mirror of
https://github.com/DarkStore-3DS/Project_CTR.git
synced 2026-07-03 08:49:03 +00:00
2645 lines
89 KiB
C++
2645 lines
89 KiB
C++
#include "io_ConcatenatedStream_TestClass.h"
|
|
|
|
#include <fmt/core.h>
|
|
#include "StreamTestUtil.h"
|
|
|
|
#include <tc.h>
|
|
#include <tc/io/IOUtil.h>
|
|
|
|
void io_ConcatenatedStream_TestClass::runAllTests(void)
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] START\n");
|
|
test_DefaultConstructor();
|
|
test_CreateConstructor_ThrowsOnBadInput();
|
|
test_CreateConstructor_SetsCorrectStreamState();
|
|
test_setLength_ThrowsOnUse();
|
|
test_read_ThrowsOnUnsupported();
|
|
test_write_ThrowsOnUnsupported();
|
|
test_seek_ThrowsOnUnsupported();
|
|
test_seek_SeeksToBeginOnNegativeSeek();
|
|
test_seek_SeeksToEndOnTooLargeSeek();
|
|
test_seek_CanFindCorrectStreamForSeek();
|
|
test_read_CanReadFromSingleStream();
|
|
test_read_CanReadFromMultipleStreamWithSeekSupport();
|
|
test_read_CanReadFromMultipleStreamWithNoSeekSupport();
|
|
test_read_ReadFromMultiStream_NoSeekSupport_ThrowsOnSeekRequired();
|
|
test_write_CanWriteFromSingleStream();
|
|
test_write_CanWriteFromMultipleStreamWithSeekSupport();
|
|
test_write_CanWriteFromMultipleStreamWithNoSeekSupport();
|
|
test_write_WriteFromMultiStream_NoSeekSupport_ThrowsOnSeekRequired();
|
|
test_MoveOperator_MoveDisposedToDisposed();
|
|
test_MoveOperator_MoveInitializedToDisposed();
|
|
test_MoveOperator_MoveDisposedToInitialized();
|
|
test_MoveOperator_MoveInitializedToInitialized();
|
|
test_MoveConstructor_MoveDisposed();
|
|
test_MoveConstructor_MoveInitialized();
|
|
fmt::print("[tc::io::ConcatenatedStream] END\n");
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_DefaultConstructor()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_DefaultConstructor : ");
|
|
try
|
|
{
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream();
|
|
|
|
// test state of stream
|
|
StreamTestUtil::constructor_TestHelper(stream, 0, 0, false, false, false);
|
|
|
|
try
|
|
{
|
|
stream.read(nullptr, 0);
|
|
throw tc::Exception(".read() failed to throw tc::ObjectDisposedException when class was not initilaized.");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
try
|
|
{
|
|
stream.write(nullptr, 0);
|
|
throw tc::Exception(".write() failed to throw tc::ObjectDisposedException when class was not initilaized.");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
try
|
|
{
|
|
stream.seek(0, tc::io::SeekOrigin::Begin);
|
|
throw tc::Exception(".seek() failed to throw tc::ObjectDisposedException when class was not initilaized.");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
try
|
|
{
|
|
stream.setLength(0);
|
|
throw tc::Exception(".setLength() failed to throw tc::ObjectDisposedException when class was not initilaized.");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
try
|
|
{
|
|
stream.flush();
|
|
throw tc::Exception(".flush() failed to throw tc::ObjectDisposedException when class was not initilaized.");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_CreateConstructor_ThrowsOnBadInput()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_CreateConstructor_ThrowsOnBadInput : ");
|
|
try
|
|
{
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
throw tc::Exception(".ctor() did not throw tc::NotSupportedException where there were no input streams");
|
|
}
|
|
catch (tc::NotSupportedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
nullptr,
|
|
nullptr,
|
|
nullptr
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
throw tc::Exception(".ctor() did not throw tc::NotSupportedException where there were null input streams");
|
|
}
|
|
catch (tc::NotSupportedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x0)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x0)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x0))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
throw tc::Exception(".ctor() did not throw tc::NotSupportedException where there total length of input streams was 0.");
|
|
}
|
|
catch (tc::NotSupportedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, true, true, false, false)), // canRead=false, canWrite=true, canSeek=true, ...
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, false, true, false, false)), // canRead=true, canWrite=false, canSeek=true, ...
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)) // canRead=true, canWrite=true, canSeek=true, ...
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
throw tc::Exception(".ctor() did not throw tc::NotSupportedException where the input streams did not all support atleast either read or write.");
|
|
}
|
|
catch (tc::NotSupportedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_CreateConstructor_SetsCorrectStreamState()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_CreateConstructor_SetsCorrectStreamState : ");
|
|
try
|
|
{
|
|
// test 1) (all input streams, length=0x100, canRead=true, canWrite=false, canSeek=false)
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, false, false, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, false, false, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, false, false, false, false))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
StreamTestUtil::constructor_TestHelper(stream, 0x300, 0, true, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("Test 1 Failed: {}", e.error()));
|
|
}
|
|
|
|
// test 2) (all input streams, length=0x100, canRead=true, canWrite=mixed, canSeek=false)
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, false, false, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, false, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, false, false, false, false))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
StreamTestUtil::constructor_TestHelper(stream, 0x300, 0, true, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("Test 2 Failed: {}", e.error()));
|
|
}
|
|
|
|
// test 3) (all input streams, length=0x100, canRead=true, canWrite=true, canSeek=false)
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, false, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, false, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, false, false, false))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
StreamTestUtil::constructor_TestHelper(stream, 0x300, 0, true, true, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("Test 3 Failed: {}", e.error()));
|
|
}
|
|
|
|
// test 4) (all input streams, length=0x100, canRead=true, canWrite=true, canSeek=mixed)
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, false, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, false, false, false))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
StreamTestUtil::constructor_TestHelper(stream, 0x300, 0, true, true, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("Test 4 Failed: {}", e.error()));
|
|
}
|
|
|
|
// test 5) (all input streams, length=0x100, canRead=true, canWrite=true, canSeek=true)
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
StreamTestUtil::constructor_TestHelper(stream, 0x300, 0, true, true, true);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("Test 5 Failed: {}", e.error()));
|
|
}
|
|
|
|
// test 6) (all input streams, length=0x100, canRead=mixed, canWrite=true, canSeek=true)
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
StreamTestUtil::constructor_TestHelper(stream, 0x300, 0, false, true, true);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("Test 6 Failed: {}", e.error()));
|
|
}
|
|
|
|
// test 7) (all input streams, length=0x100, canRead=false, canWrite=true, canSeek=true)
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, true, true, false, false))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
StreamTestUtil::constructor_TestHelper(stream, 0x300, 0, false, true, true);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("Test 7 Failed: {}", e.error()));
|
|
}
|
|
|
|
// test 8) (all input streams, length=0x100, canRead=false, canWrite=true, canSeek=mixed)
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, true, false, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, true, true, false, false))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
StreamTestUtil::constructor_TestHelper(stream, 0x300, 0, false, true, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("Test 8 Failed: {}", e.error()));
|
|
}
|
|
|
|
// test 9) (all input streams, length=0x100, canRead=false, canWrite=true, canSeek=false)
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, true, false, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, true, false, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, true, false, false, false))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
StreamTestUtil::constructor_TestHelper(stream, 0x300, 0, false, true, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("Test 9 Failed: {}", e.error()));
|
|
}
|
|
|
|
// test 10) (all input streams, length=0x100, canRead=true, canWrite=true, canSeek=true) & one empty stream with only read
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x000, true, false, false, false, false)), // this should be skipped because it has no size
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
StreamTestUtil::constructor_TestHelper(stream, 0x300, 0, true, true, true);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("Test 10 Failed: {}", e.error()));
|
|
}
|
|
|
|
// test 11) (all input streams, length=0x100, canRead=true, canWrite=true, canSeek=true) & one populated stream with only no read/write
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, false, false, false, false)), // this should be skipped because it cannot be read or written too
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
StreamTestUtil::constructor_TestHelper(stream, 0x300, 0, true, true, true);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("Test 11 Failed: {}", e.error()));
|
|
}
|
|
|
|
// test 12) (all input streams, length=0x100, canRead=true, canWrite=true, canSeek=true) & one nullptr stream
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
nullptr, // this should be skipped because it is null
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
StreamTestUtil::constructor_TestHelper(stream, 0x300, 0, true, true, true);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("Test 12 Failed: {}", e.error()));
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_setLength_ThrowsOnUse()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_setLength_ThrowsOnUse : ");
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
try
|
|
{
|
|
stream.setLength(0);
|
|
throw tc::Exception(".setLength() did not throw tc::NotImplementedException when called from an initalized class.");
|
|
}
|
|
catch (const tc::NotImplementedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_read_ThrowsOnUnsupported()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_read_ThrowsOnUnsupported : ");
|
|
try
|
|
{
|
|
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, false, true, true, false, false))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
try
|
|
{
|
|
stream.read(nullptr, 0);
|
|
throw tc::Exception(".read() did not throw tc::NotSupportedException when canRead() == false.");
|
|
}
|
|
catch (const tc::NotSupportedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_write_ThrowsOnUnsupported()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_write_ThrowsOnUnsupported : ");
|
|
try
|
|
{
|
|
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, false, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, false, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, false, true, false, false))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
try
|
|
{
|
|
stream.write(nullptr, 0);
|
|
throw tc::Exception(".write() did not throw tc::NotSupportedException when canWrite() == false.");
|
|
}
|
|
catch (const tc::NotSupportedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_seek_ThrowsOnUnsupported()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_seek_ThrowsOnUnsupported : ");
|
|
try
|
|
{
|
|
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, false, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, false, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, false, false, false))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
try
|
|
{
|
|
stream.seek(0, tc::io::SeekOrigin::Begin);
|
|
throw tc::Exception(".seek() did not throw tc::NotSupportedException when canSeek() == false.");
|
|
}
|
|
catch (const tc::NotSupportedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_seek_SeeksToBeginOnNegativeSeek()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_seek_SeeksToBeginOnNegativeSeek : ");
|
|
try
|
|
{
|
|
class ValidateSeekParamDummyStream : public StreamTestUtil::DummyStreamBase
|
|
{
|
|
public:
|
|
ValidateSeekParamDummyStream(int64_t seek_offset, tc::io::SeekOrigin seek_origin) :
|
|
DummyStreamBase(0x100, true, true, true, false, false),
|
|
mExpectedSeekOffset(seek_offset),
|
|
mExpectedSeekOrigin(seek_origin)
|
|
{}
|
|
|
|
int64_t seek(int64_t offset, tc::io::SeekOrigin origin)
|
|
{
|
|
if (offset != mExpectedSeekOffset)
|
|
{
|
|
throw tc::Exception(fmt::format("offset passed to seek() was 0x{:x} (expected 0x{:x}", offset, mExpectedSeekOffset));
|
|
}
|
|
|
|
if (origin != mExpectedSeekOrigin)
|
|
{
|
|
std::string origin_str;
|
|
switch (origin)
|
|
{
|
|
case tc::io::SeekOrigin::Begin:
|
|
origin_str = "SeekOrigin::Begin";
|
|
break;
|
|
case tc::io::SeekOrigin::Current:
|
|
origin_str = "SeekOrigin::Current";
|
|
break;
|
|
case tc::io::SeekOrigin::End:
|
|
origin_str = "SeekOrigin::End";
|
|
break;
|
|
}
|
|
|
|
std::string expected_origin_str;
|
|
switch (mExpectedSeekOrigin)
|
|
{
|
|
case tc::io::SeekOrigin::Begin:
|
|
expected_origin_str = "SeekOrigin::Begin";
|
|
break;
|
|
case tc::io::SeekOrigin::Current:
|
|
expected_origin_str = "SeekOrigin::Current";
|
|
break;
|
|
case tc::io::SeekOrigin::End:
|
|
expected_origin_str = "SeekOrigin::End";
|
|
break;
|
|
}
|
|
|
|
throw tc::Exception(fmt::format("origin passed to seek() was {:s} (expected {:s}", origin_str, expected_origin_str));
|
|
}
|
|
|
|
return DummyStreamBase::seek(offset, origin);
|
|
}
|
|
private:
|
|
int64_t mExpectedSeekOffset;
|
|
tc::io::SeekOrigin mExpectedSeekOrigin;
|
|
};
|
|
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<ValidateSeekParamDummyStream>(ValidateSeekParamDummyStream(0, tc::io::SeekOrigin::Begin)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
struct Test {
|
|
int64_t seek_pos, exp_seek_res;
|
|
};
|
|
|
|
std::vector<Test> tests {
|
|
{0x0, 0x0},
|
|
{-1, 0x0},
|
|
{-2, 0x0},
|
|
{-3, 0x0},
|
|
{-10, 0x0},
|
|
{-1000, 0x0},
|
|
{-20000, 0x0},
|
|
};
|
|
|
|
for (auto test = tests.begin(); test != tests.end(); test++)
|
|
{
|
|
int64_t seek_res = stream.seek(test->seek_pos, tc::io::SeekOrigin::Begin);
|
|
if (seek_res != test->exp_seek_res)
|
|
{
|
|
throw tc::Exception(fmt::format(".seek({}, tc::io::SeekOrigin::Begin) returned {} (expected {})", test->seek_pos, seek_res, test->exp_seek_res));
|
|
}
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_seek_SeeksToEndOnTooLargeSeek()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_seek_SeeksToEndOnTooLargeSeek : ");
|
|
try
|
|
{
|
|
class ValidateSeekParamDummyStream : public StreamTestUtil::DummyStreamBase
|
|
{
|
|
public:
|
|
ValidateSeekParamDummyStream(int64_t seek_offset, tc::io::SeekOrigin seek_origin) :
|
|
DummyStreamBase(0x100, true, true, true, false, false),
|
|
mExpectedSeekOffset(seek_offset),
|
|
mExpectedSeekOrigin(seek_origin)
|
|
{}
|
|
|
|
int64_t seek(int64_t offset, tc::io::SeekOrigin origin)
|
|
{
|
|
if (offset != mExpectedSeekOffset)
|
|
{
|
|
throw tc::Exception(fmt::format("offset passed to seek() was 0x{:x} (expected 0x{:x}", offset, mExpectedSeekOffset));
|
|
}
|
|
|
|
if (origin != mExpectedSeekOrigin)
|
|
{
|
|
std::string origin_str;
|
|
switch (origin)
|
|
{
|
|
case tc::io::SeekOrigin::Begin:
|
|
origin_str = "SeekOrigin::Begin";
|
|
break;
|
|
case tc::io::SeekOrigin::Current:
|
|
origin_str = "SeekOrigin::Current";
|
|
break;
|
|
case tc::io::SeekOrigin::End:
|
|
origin_str = "SeekOrigin::End";
|
|
break;
|
|
}
|
|
|
|
std::string expected_origin_str;
|
|
switch (mExpectedSeekOrigin)
|
|
{
|
|
case tc::io::SeekOrigin::Begin:
|
|
expected_origin_str = "SeekOrigin::Begin";
|
|
break;
|
|
case tc::io::SeekOrigin::Current:
|
|
expected_origin_str = "SeekOrigin::Current";
|
|
break;
|
|
case tc::io::SeekOrigin::End:
|
|
expected_origin_str = "SeekOrigin::End";
|
|
break;
|
|
}
|
|
|
|
throw tc::Exception(fmt::format("origin passed to seek() was {:s} (expected {:s}", origin_str, expected_origin_str));
|
|
}
|
|
|
|
return DummyStreamBase::seek(offset, origin);
|
|
}
|
|
private:
|
|
int64_t mExpectedSeekOffset;
|
|
tc::io::SeekOrigin mExpectedSeekOrigin;
|
|
};
|
|
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<ValidateSeekParamDummyStream>(ValidateSeekParamDummyStream(0, tc::io::SeekOrigin::End))
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
struct Test {
|
|
int64_t seek_pos, exp_seek_res;
|
|
};
|
|
|
|
std::vector<Test> tests {
|
|
{0x300, 0x300},
|
|
{0x301, 0x300},
|
|
{0x302, 0x300},
|
|
{0x310, 0x300},
|
|
{0x400, 0x300},
|
|
{0x1000, 0x300},
|
|
{0x20000, 0x300},
|
|
};
|
|
|
|
for (auto test = tests.begin(); test != tests.end(); test++)
|
|
{
|
|
int64_t seek_res = stream.seek(test->seek_pos, tc::io::SeekOrigin::Begin);
|
|
if (seek_res != test->exp_seek_res)
|
|
{
|
|
throw tc::Exception(fmt::format(".seek({}, tc::io::SeekOrigin::Begin) returned {} (expected {})", test->seek_pos, seek_res, test->exp_seek_res));
|
|
}
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_seek_CanFindCorrectStreamForSeek()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_seek_CanFindCorrectStreamForSeek : ");
|
|
try
|
|
{
|
|
struct SeekReport
|
|
{
|
|
int64_t seek_pos;
|
|
size_t stream_id;
|
|
};
|
|
|
|
class ReportsSeekPosParamDummyStream : public StreamTestUtil::DummyStreamBase
|
|
{
|
|
public:
|
|
ReportsSeekPosParamDummyStream(SeekReport& seek_resport, size_t stream_id) :
|
|
DummyStreamBase(0x100, true, true, true, false, false),
|
|
mSeekReport(seek_resport),
|
|
mStreamId(stream_id)
|
|
{}
|
|
|
|
int64_t seek(int64_t offset, tc::io::SeekOrigin origin)
|
|
{
|
|
mSeekReport.seek_pos = DummyStreamBase::seek(offset, origin);
|
|
mSeekReport.stream_id = mStreamId;
|
|
|
|
return mSeekReport.seek_pos;
|
|
}
|
|
private:
|
|
SeekReport& mSeekReport;
|
|
size_t mStreamId;
|
|
};
|
|
|
|
SeekReport seek_report;
|
|
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<ReportsSeekPosParamDummyStream>(ReportsSeekPosParamDummyStream(seek_report, 0)), // 0x000 - 0x0ff
|
|
std::make_shared<ReportsSeekPosParamDummyStream>(ReportsSeekPosParamDummyStream(seek_report, 1)), // 0x100 - 0x1ff
|
|
std::make_shared<ReportsSeekPosParamDummyStream>(ReportsSeekPosParamDummyStream(seek_report, 2)), // 0x200 - 0x2ff
|
|
std::make_shared<ReportsSeekPosParamDummyStream>(ReportsSeekPosParamDummyStream(seek_report, 3)), // 0x300 - 0x3ff
|
|
std::make_shared<ReportsSeekPosParamDummyStream>(ReportsSeekPosParamDummyStream(seek_report, 4)), // 0x400 - 0x4ff
|
|
std::make_shared<ReportsSeekPosParamDummyStream>(ReportsSeekPosParamDummyStream(seek_report, 5)), // 0x500 - 0x5ff
|
|
std::make_shared<ReportsSeekPosParamDummyStream>(ReportsSeekPosParamDummyStream(seek_report, 6)), // 0x600 - 0x6ff
|
|
std::make_shared<ReportsSeekPosParamDummyStream>(ReportsSeekPosParamDummyStream(seek_report, 7)), // 0x700 - 0x7ff
|
|
};
|
|
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
struct Test {
|
|
int64_t seek_pos;
|
|
int64_t exp_seek_res;
|
|
SeekReport exp_seek_report;
|
|
};
|
|
|
|
std::vector<Test> tests {
|
|
{0x0, 0x0, {0x0, 0}},
|
|
{0x20, 0x20, {0x20, 0}},
|
|
{0xff, 0xff, {0xff, 0}},
|
|
{0x100, 0x100, {0x0, 1}},
|
|
{0x101, 0x101, {0x1, 1}},
|
|
{0x1ff, 0x1ff, {0xff, 1}},
|
|
{0x200, 0x200, {0x0, 2}},
|
|
{0x600, 0x600, {0x0, 6}},
|
|
{0x378, 0x378, {0x78, 3}},
|
|
{0x7ff, 0x7ff, {0xff, 7}},
|
|
{0x8, 0x8, {0x8, 0}},
|
|
// prior of stream case
|
|
{-1, 0x0, {0x0, 0}},
|
|
{-120, 0x0, {0x0, 0}},
|
|
// end of stream case
|
|
{0x800, 0x800, {0x100, 7}},
|
|
{0x1000, 0x800, {0x100, 7}},
|
|
};
|
|
|
|
for (auto test = tests.begin(); test != tests.end(); test++)
|
|
{
|
|
int64_t seek_res = stream.seek(test->seek_pos, tc::io::SeekOrigin::Begin);
|
|
if (seek_res != test->exp_seek_res)
|
|
{
|
|
throw tc::Exception(fmt::format(".seek({}) returned {} (expected {})", test->seek_pos, seek_res, test->exp_seek_res));
|
|
}
|
|
|
|
if (seek_report.seek_pos != test->exp_seek_report.seek_pos || seek_report.stream_id != test->exp_seek_report.stream_id)
|
|
{
|
|
throw tc::Exception(fmt::format(".seek({}) triggered .seek({}) in stream {} (expected .seek({}) in stream {})", test->seek_pos, test->exp_seek_report.seek_pos, test->exp_seek_report.stream_id, seek_report.seek_pos, seek_report.stream_id));
|
|
}
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_read_CanReadFromSingleStream()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_read_CanReadFromSingleStream : ");
|
|
|
|
class ReportDummyStream : public StreamTestUtil::DummyStreamBase
|
|
{
|
|
public:
|
|
struct SeekReport
|
|
{
|
|
int64_t seek_offset;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const SeekReport& other) const
|
|
{
|
|
return seek_offset == other.seek_offset \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
struct ReadReport
|
|
{
|
|
const byte_t* read_ptr;
|
|
size_t read_count;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const ReadReport& other) const
|
|
{
|
|
return read_ptr == other.read_ptr \
|
|
&& read_count == other.read_count \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
ReportDummyStream(std::vector<ReadReport>& read_report, std::vector<SeekReport>& seek_report, size_t stream_id) :
|
|
DummyStreamBase(0x100, true, true, true, false, false),
|
|
mReadReport(read_report),
|
|
mSeekReport(seek_report),
|
|
mStreamId(stream_id)
|
|
{}
|
|
|
|
size_t read(byte_t* ptr, size_t count)
|
|
{
|
|
mReadReport.push_back({ptr, count, mStreamId});
|
|
|
|
size_t readable_count = tc::io::IOUtil::getReadableCount(DummyStreamBase::length(), DummyStreamBase::position(), count);
|
|
|
|
// update stream position
|
|
DummyStreamBase::seek(int64_t(readable_count), tc::io::SeekOrigin::Current);
|
|
|
|
return readable_count;
|
|
}
|
|
|
|
int64_t seek(int64_t offset, tc::io::SeekOrigin origin)
|
|
{
|
|
SeekReport seek_report = {DummyStreamBase::seek(offset, origin), mStreamId};
|
|
|
|
mSeekReport.push_back(seek_report);
|
|
|
|
return seek_report.seek_offset;
|
|
}
|
|
private:
|
|
std::vector<ReadReport>& mReadReport;
|
|
std::vector<SeekReport>& mSeekReport;
|
|
size_t mStreamId;
|
|
};
|
|
|
|
try
|
|
{
|
|
// declare report logs
|
|
std::vector<ReportDummyStream::ReadReport> read_report;
|
|
std::vector<ReportDummyStream::SeekReport> seek_report;
|
|
|
|
// create stream list with links to report logs
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 0)), // 0x000 - 0x0ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 1)), // 0x100 - 0x1ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 2)), // 0x200 - 0x2ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 3)), // 0x300 - 0x3ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 4)), // 0x400 - 0x4ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 5)), // 0x500 - 0x5ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 6)), // 0x600 - 0x6ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 7)), // 0x700 - 0x7ff
|
|
};
|
|
|
|
// create concatenated stream
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
// define test
|
|
struct Test {
|
|
// test name
|
|
std::string test_name;
|
|
|
|
// these seeks are done then seek log is cleared
|
|
std::vector<int64_t> unlogged_seeks;
|
|
|
|
// these seeks are done before reading but will be logged
|
|
std::vector<int64_t> logged_seeks;
|
|
|
|
// read param
|
|
byte_t* read_ptr;
|
|
size_t read_count;
|
|
|
|
// expected log reports
|
|
std::vector<ReportDummyStream::ReadReport> exp_read_report;
|
|
std::vector<ReportDummyStream::SeekReport> exp_seek_report;
|
|
};
|
|
|
|
// create tests
|
|
std::vector<Test> tests {
|
|
{"ReadFromBeginning", {0}, {}, (byte_t*)0x1000, 0x30, {{(byte_t*)0x1000, 0x30, 0}}, {}},
|
|
{"ContinueReadingFromBeginning", {}, {}, (byte_t*)0x1000, 0x30, {{(byte_t*)0x1000, 0x30, 0}}, {}},
|
|
{"ReadFromSomewhereElseInExistingStream", {0xe0}, {}, (byte_t*)0x1000, 0x20, {{(byte_t*)0x1000, 0x20, 0}}, {}},
|
|
};
|
|
|
|
// run tests
|
|
for (auto test = tests.begin(); test != tests.end(); test++)
|
|
{
|
|
for (auto itr = test->unlogged_seeks.begin(); itr != test->unlogged_seeks.end(); itr++)
|
|
{
|
|
stream.seek(*itr, tc::io::SeekOrigin::Begin);
|
|
}
|
|
|
|
read_report.clear();
|
|
seek_report.clear();
|
|
|
|
for (auto itr = test->logged_seeks.begin(); itr != test->logged_seeks.end(); itr++)
|
|
{
|
|
stream.seek(*itr, tc::io::SeekOrigin::Begin);
|
|
}
|
|
|
|
stream.read(test->read_ptr, test->read_count);
|
|
|
|
if (read_report != test->exp_read_report)
|
|
{
|
|
throw tc::Exception(fmt::format("Test \"{}\" Failed: .read() issued to base streams were not as expected", test->test_name));
|
|
}
|
|
|
|
if (seek_report != test->exp_seek_report)
|
|
{
|
|
throw tc::Exception(fmt::format("Test \"{}\" Failed: .seek() issued to base streams were not as expected", test->test_name));
|
|
}
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_read_CanReadFromMultipleStreamWithSeekSupport()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_read_CanReadFromMultipleStreamWithSeekSupport : ");
|
|
|
|
class ReportDummyStream : public StreamTestUtil::DummyStreamBase
|
|
{
|
|
public:
|
|
struct SeekReport
|
|
{
|
|
int64_t seek_offset;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const SeekReport& other) const
|
|
{
|
|
return seek_offset == other.seek_offset \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
struct ReadReport
|
|
{
|
|
const byte_t* read_ptr;
|
|
size_t read_count;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const ReadReport& other) const
|
|
{
|
|
return read_ptr == other.read_ptr \
|
|
&& read_count == other.read_count \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
ReportDummyStream(std::vector<ReadReport>& read_report, std::vector<SeekReport>& seek_report, size_t stream_id) :
|
|
DummyStreamBase(0x100, true, true, true, false, false),
|
|
mReadReport(read_report),
|
|
mSeekReport(seek_report),
|
|
mStreamId(stream_id)
|
|
{}
|
|
|
|
size_t read(byte_t* ptr, size_t count)
|
|
{
|
|
mReadReport.push_back({ptr, count, mStreamId});
|
|
|
|
size_t readable_count = tc::io::IOUtil::getReadableCount(DummyStreamBase::length(), DummyStreamBase::position(), count);
|
|
|
|
// update stream position
|
|
DummyStreamBase::seek(int64_t(readable_count), tc::io::SeekOrigin::Current);
|
|
|
|
return readable_count;
|
|
}
|
|
|
|
int64_t seek(int64_t offset, tc::io::SeekOrigin origin)
|
|
{
|
|
SeekReport seek_report = {DummyStreamBase::seek(offset, origin), mStreamId};
|
|
|
|
mSeekReport.push_back(seek_report);
|
|
|
|
return seek_report.seek_offset;
|
|
}
|
|
private:
|
|
std::vector<ReadReport>& mReadReport;
|
|
std::vector<SeekReport>& mSeekReport;
|
|
size_t mStreamId;
|
|
};
|
|
|
|
try
|
|
{
|
|
// declare report logs
|
|
std::vector<ReportDummyStream::ReadReport> read_report;
|
|
std::vector<ReportDummyStream::SeekReport> seek_report;
|
|
|
|
// create stream list with links to report logs
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 0)), // 0x000 - 0x0ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 1)), // 0x100 - 0x1ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 2)), // 0x200 - 0x2ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 3)), // 0x300 - 0x3ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 4)), // 0x400 - 0x4ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 5)), // 0x500 - 0x5ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 6)), // 0x600 - 0x6ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 7)), // 0x700 - 0x7ff
|
|
};
|
|
|
|
// create concatenated stream
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
// define test
|
|
struct Test {
|
|
// test name
|
|
std::string test_name;
|
|
|
|
// these seeks are done then seek log is cleared
|
|
std::vector<int64_t> unlogged_seeks;
|
|
|
|
// these seeks are done before reading but will be logged
|
|
std::vector<int64_t> logged_seeks;
|
|
|
|
// read param
|
|
byte_t* read_ptr;
|
|
size_t read_count;
|
|
|
|
// expected log reports
|
|
std::vector<ReportDummyStream::ReadReport> exp_read_report;
|
|
std::vector<ReportDummyStream::SeekReport> exp_seek_report;
|
|
};
|
|
|
|
// create tests
|
|
std::vector<Test> tests {
|
|
{"ReadAllOfStream 0-7 (stream 0x0 positions)", {0x000, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x000}, {}, (byte_t*)0x1000, 0x800, {{(byte_t*)0x1000, 0x100, 0}, {(byte_t*)0x1100, 0x100, 1}, {(byte_t*)0x1200, 0x100, 2}, {(byte_t*)0x1300, 0x100, 3}, {(byte_t*)0x1400, 0x100, 4}, {(byte_t*)0x1500, 0x100, 5}, {(byte_t*)0x1600, 0x100, 6}, {(byte_t*)0x1700, 0x100, 7}}, {}},
|
|
{"ReadAllOfStream 0-7 (stream 0x80 positions)", {0x080, 0x180, 0x280, 0x380, 0x480, 0x580, 0x680, 0x780, 0x000}, {}, (byte_t*)0x1000, 0x800, {{(byte_t*)0x1000, 0x100, 0}, {(byte_t*)0x1100, 0x100, 1}, {(byte_t*)0x1200, 0x100, 2}, {(byte_t*)0x1300, 0x100, 3}, {(byte_t*)0x1400, 0x100, 4}, {(byte_t*)0x1500, 0x100, 5}, {(byte_t*)0x1600, 0x100, 6}, {(byte_t*)0x1700, 0x100, 7}}, {{0x0, 1}, {0x0, 2}, {0x0, 3}, {0x0, 4}, {0x0, 5}, {0x0, 6}, {0x0, 7}}},
|
|
{"ReadAllOfStream 0-7 (stream 0x00 or 0x80 positions)", {0x080, 0x100, 0x280, 0x300, 0x480, 0x500, 0x680, 0x700, 0x000}, {}, (byte_t*)0x1000, 0x800, {{(byte_t*)0x1000, 0x100, 0}, {(byte_t*)0x1100, 0x100, 1}, {(byte_t*)0x1200, 0x100, 2}, {(byte_t*)0x1300, 0x100, 3}, {(byte_t*)0x1400, 0x100, 4}, {(byte_t*)0x1500, 0x100, 5}, {(byte_t*)0x1600, 0x100, 6}, {(byte_t*)0x1700, 0x100, 7}}, {{0x0, 2}, {0x0, 4}, {0x0, 6}}},
|
|
{"ReadAllOfStream 3-6 (stream 0x0 positions)", {0x000, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x300}, {}, (byte_t*)0x1000, 0x400, {{(byte_t*)0x1000, 0x100, 3}, {(byte_t*)0x1100, 0x100, 4}, {(byte_t*)0x1200, 0x100, 5}, {(byte_t*)0x1300, 0x100, 6}}, {}},
|
|
{"ReadAllOfStream 3-6 (stream 0x80 positions)", {0x080, 0x180, 0x280, 0x380, 0x480, 0x580, 0x680, 0x780, 0x300}, {}, (byte_t*)0x1000, 0x400, {{(byte_t*)0x1000, 0x100, 3}, {(byte_t*)0x1100, 0x100, 4}, {(byte_t*)0x1200, 0x100, 5}, {(byte_t*)0x1300, 0x100, 6}}, {{0x0, 4}, {0x0, 5}, {0x0, 6}}},
|
|
{"ReadStream (partial)3,4-5,(partial)6 (stream 0x0 positions)", {0x000, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x350}, {}, (byte_t*)0x1000, 0x300, {{(byte_t*)0x1000, 0xB0, 3}, {(byte_t*)0x10B0, 0x100, 4}, {(byte_t*)0x11B0, 0x100, 5}, {(byte_t*)0x12B0, 0x50, 6}}, {}},
|
|
{"ReadStream (partial)3,4-5,(partial)6 (stream 0x80 positions)", {0x080, 0x180, 0x280, 0x380, 0x480, 0x580, 0x680, 0x780, 0x350}, {}, (byte_t*)0x1000, 0x300, {{(byte_t*)0x1000, 0xB0, 3}, {(byte_t*)0x10B0, 0x100, 4}, {(byte_t*)0x11B0, 0x100, 5}, {(byte_t*)0x12B0, 0x50, 6}}, {{0x0, 4}, {0x0, 5}, {0x0, 6}}},
|
|
};
|
|
|
|
// run tests
|
|
for (auto test = tests.begin(); test != tests.end(); test++)
|
|
{
|
|
for (auto itr = test->unlogged_seeks.begin(); itr != test->unlogged_seeks.end(); itr++)
|
|
{
|
|
stream.seek(*itr, tc::io::SeekOrigin::Begin);
|
|
}
|
|
|
|
read_report.clear();
|
|
seek_report.clear();
|
|
|
|
for (auto itr = test->logged_seeks.begin(); itr != test->logged_seeks.end(); itr++)
|
|
{
|
|
stream.seek(*itr, tc::io::SeekOrigin::Begin);
|
|
}
|
|
|
|
stream.read(test->read_ptr, test->read_count);
|
|
|
|
if (read_report != test->exp_read_report)
|
|
{
|
|
throw tc::Exception(fmt::format("Test \"{}\" Failed: .read() issued to base streams were not as expected", test->test_name));
|
|
}
|
|
|
|
if (seek_report != test->exp_seek_report)
|
|
{
|
|
throw tc::Exception(fmt::format("Test \"{}\" Failed: .seek() issued to base streams were not as expected", test->test_name));
|
|
}
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_read_CanReadFromMultipleStreamWithNoSeekSupport()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_read_CanReadFromMultipleStreamWithNoSeekSupport : ");
|
|
|
|
class ReportDummyStream : public StreamTestUtil::DummyStreamBase
|
|
{
|
|
public:
|
|
struct SeekReport
|
|
{
|
|
int64_t seek_offset;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const SeekReport& other) const
|
|
{
|
|
return seek_offset == other.seek_offset \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
struct ReadReport
|
|
{
|
|
const byte_t* read_ptr;
|
|
size_t read_count;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const ReadReport& other) const
|
|
{
|
|
return read_ptr == other.read_ptr \
|
|
&& read_count == other.read_count \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
ReportDummyStream(std::vector<ReadReport>& read_report, std::vector<SeekReport>& seek_report, size_t stream_id) :
|
|
DummyStreamBase(0x100, true, true, false, false, false),
|
|
mReadReport(read_report),
|
|
mSeekReport(seek_report),
|
|
mStreamId(stream_id)
|
|
{}
|
|
|
|
size_t read(byte_t* ptr, size_t count)
|
|
{
|
|
mReadReport.push_back({ptr, count, mStreamId});
|
|
|
|
size_t readable_count = tc::io::IOUtil::getReadableCount(DummyStreamBase::length(), DummyStreamBase::position(), count);
|
|
|
|
// update stream position
|
|
DummyStreamBase::seek(int64_t(readable_count), tc::io::SeekOrigin::Current);
|
|
|
|
return readable_count;
|
|
}
|
|
|
|
int64_t seek(int64_t offset, tc::io::SeekOrigin origin)
|
|
{
|
|
SeekReport seek_report = {DummyStreamBase::seek(offset, origin), mStreamId};
|
|
|
|
mSeekReport.push_back(seek_report);
|
|
|
|
return seek_report.seek_offset;
|
|
}
|
|
private:
|
|
std::vector<ReadReport>& mReadReport;
|
|
std::vector<SeekReport>& mSeekReport;
|
|
size_t mStreamId;
|
|
};
|
|
|
|
try
|
|
{
|
|
// declare report logs
|
|
std::vector<ReportDummyStream::ReadReport> read_report;
|
|
std::vector<ReportDummyStream::SeekReport> seek_report;
|
|
|
|
// create stream list with links to report logs
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 0)), // 0x000 - 0x0ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 1)), // 0x100 - 0x1ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 2)), // 0x200 - 0x2ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 3)), // 0x300 - 0x3ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 4)), // 0x400 - 0x4ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 5)), // 0x500 - 0x5ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 6)), // 0x600 - 0x6ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 7)), // 0x700 - 0x7ff
|
|
};
|
|
|
|
// create concatenated stream
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
// define test
|
|
struct Test {
|
|
// test name
|
|
std::string test_name;
|
|
|
|
// these seeks are done then seek log is cleared
|
|
std::vector<int64_t> unlogged_seeks;
|
|
|
|
// these seeks are done before reading but will be logged
|
|
std::vector<int64_t> logged_seeks;
|
|
|
|
// read param
|
|
byte_t* read_ptr;
|
|
size_t read_count;
|
|
|
|
// expected log reports
|
|
std::vector<ReportDummyStream::ReadReport> exp_read_report;
|
|
std::vector<ReportDummyStream::SeekReport> exp_seek_report;
|
|
};
|
|
|
|
// create tests
|
|
std::vector<Test> tests {
|
|
{"ReadStream (partial)0", {}, {}, (byte_t*)0x1000, 0xA0, {{(byte_t*)0x1000, 0xA0, 0}}, {}},
|
|
{"ReadStream (partial)0,1-4", {}, {}, (byte_t*)0x1000, 0x460, {{(byte_t*)0x1000, 0x60, 0}, {(byte_t*)0x1060, 0x100, 1}, {(byte_t*)0x1160, 0x100, 2}, {(byte_t*)0x1260, 0x100, 3}, {(byte_t*)0x1360, 0x100, 4}}, {}},
|
|
{"ReadStream 5-7", {}, {}, (byte_t*)0x1000, 0x300, {{(byte_t*)0x1000, 0x100, 5}, {(byte_t*)0x1100, 0x100, 6}, {(byte_t*)0x1200, 0x100, 7}}, {}},
|
|
};
|
|
|
|
// run tests
|
|
for (auto test = tests.begin(); test != tests.end(); test++)
|
|
{
|
|
for (auto itr = test->unlogged_seeks.begin(); itr != test->unlogged_seeks.end(); itr++)
|
|
{
|
|
stream.seek(*itr, tc::io::SeekOrigin::Begin);
|
|
}
|
|
|
|
read_report.clear();
|
|
seek_report.clear();
|
|
|
|
for (auto itr = test->logged_seeks.begin(); itr != test->logged_seeks.end(); itr++)
|
|
{
|
|
stream.seek(*itr, tc::io::SeekOrigin::Begin);
|
|
}
|
|
|
|
stream.read(test->read_ptr, test->read_count);
|
|
|
|
if (read_report != test->exp_read_report)
|
|
{
|
|
fmt::print("\n");
|
|
fmt::print("ReadLog:\n");
|
|
for (auto itr = read_report.begin(); itr != read_report.end(); itr++)
|
|
{
|
|
fmt::print("ReadReport (ptr: 0x{:x}, count: 0x{:x}, stream: {:d})\n", (size_t)itr->read_ptr, itr->read_count, itr->stream_id);
|
|
}
|
|
fmt::print("ExpReadLog:\n");
|
|
for (auto itr = test->exp_read_report.begin(); itr != test->exp_read_report.end(); itr++)
|
|
{
|
|
fmt::print("ReadReport (ptr: 0x{:x}, count: 0x{:x}, stream: {:d})\n", (size_t)itr->read_ptr, itr->read_count, itr->stream_id);
|
|
}
|
|
throw tc::Exception(fmt::format("Test \"{}\" Failed: .read() issued to base streams were not as expected", test->test_name));
|
|
}
|
|
|
|
if (seek_report != test->exp_seek_report)
|
|
{
|
|
throw tc::Exception(fmt::format("Test \"{}\" Failed: .seek() issued to base streams were not as expected", test->test_name));
|
|
}
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_read_ReadFromMultiStream_NoSeekSupport_ThrowsOnSeekRequired()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_read_ReadFromMultiStream_NoSeekSupport_ThrowsOnSeekRequired : ");
|
|
|
|
class ReportDummyStream : public StreamTestUtil::DummyStreamBase
|
|
{
|
|
public:
|
|
struct SeekReport
|
|
{
|
|
int64_t seek_offset;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const SeekReport& other) const
|
|
{
|
|
return seek_offset == other.seek_offset \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
struct ReadReport
|
|
{
|
|
const byte_t* read_ptr;
|
|
size_t read_count;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const ReadReport& other) const
|
|
{
|
|
return read_ptr == other.read_ptr \
|
|
&& read_count == other.read_count \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
ReportDummyStream(std::vector<ReadReport>& read_report, std::vector<SeekReport>& seek_report, size_t stream_id) :
|
|
DummyStreamBase(0x100, 0x80, true, true, false, false, false), // the initial position is 0x80
|
|
mReadReport(read_report),
|
|
mSeekReport(seek_report),
|
|
mStreamId(stream_id)
|
|
{}
|
|
|
|
size_t read(byte_t* ptr, size_t count)
|
|
{
|
|
mReadReport.push_back({ptr, count, mStreamId});
|
|
|
|
size_t readable_count = tc::io::IOUtil::getReadableCount(DummyStreamBase::length(), DummyStreamBase::position(), count);
|
|
|
|
// update stream position
|
|
DummyStreamBase::seek(int64_t(readable_count), tc::io::SeekOrigin::Current);
|
|
|
|
return readable_count;
|
|
}
|
|
|
|
int64_t seek(int64_t offset, tc::io::SeekOrigin origin)
|
|
{
|
|
SeekReport seek_report = {DummyStreamBase::seek(offset, origin), mStreamId};
|
|
|
|
mSeekReport.push_back(seek_report);
|
|
|
|
return seek_report.seek_offset;
|
|
}
|
|
private:
|
|
std::vector<ReadReport>& mReadReport;
|
|
std::vector<SeekReport>& mSeekReport;
|
|
size_t mStreamId;
|
|
};
|
|
|
|
try
|
|
{
|
|
// declare report logs
|
|
std::vector<ReportDummyStream::ReadReport> read_report;
|
|
std::vector<ReportDummyStream::SeekReport> seek_report;
|
|
|
|
// create stream list with links to report logs
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 0)), // 0x000 - 0x0ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 1)), // 0x100 - 0x1ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 2)), // 0x200 - 0x2ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 3)), // 0x300 - 0x3ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 4)), // 0x400 - 0x4ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 5)), // 0x500 - 0x5ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 6)), // 0x600 - 0x6ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(read_report, seek_report, 7)), // 0x700 - 0x7ff
|
|
};
|
|
|
|
// create concatenated stream
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
try
|
|
{
|
|
stream.read((byte_t*)0x1000, 0x200);
|
|
throw tc::Exception(".read() did not throw tc::io::IOException where stream required seeking to begining but did not support seeking.");
|
|
}
|
|
catch (const tc::io::IOException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_write_CanWriteFromSingleStream()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_write_CanWriteFromSingleStream : ");
|
|
|
|
class ReportDummyStream : public StreamTestUtil::DummyStreamBase
|
|
{
|
|
public:
|
|
struct SeekReport
|
|
{
|
|
int64_t seek_offset;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const SeekReport& other) const
|
|
{
|
|
return seek_offset == other.seek_offset \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
struct WriteReport
|
|
{
|
|
const byte_t* write_ptr;
|
|
size_t write_count;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const WriteReport& other) const
|
|
{
|
|
return write_ptr == other.write_ptr \
|
|
&& write_count == other.write_count \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
ReportDummyStream(std::vector<WriteReport>& write_report, std::vector<SeekReport>& seek_report, size_t stream_id) :
|
|
DummyStreamBase(0x100, true, true, true, false, false),
|
|
mWriteReport(write_report),
|
|
mSeekReport(seek_report),
|
|
mStreamId(stream_id)
|
|
{}
|
|
|
|
size_t write(const byte_t* ptr, size_t count)
|
|
{
|
|
mWriteReport.push_back({ptr, count, mStreamId});
|
|
|
|
size_t writable_count = tc::io::IOUtil::getWritableCount(DummyStreamBase::length(), DummyStreamBase::position(), count);
|
|
|
|
// update stream position
|
|
DummyStreamBase::seek(int64_t(writable_count), tc::io::SeekOrigin::Current);
|
|
|
|
return writable_count;
|
|
}
|
|
|
|
int64_t seek(int64_t offset, tc::io::SeekOrigin origin)
|
|
{
|
|
SeekReport seek_report = {DummyStreamBase::seek(offset, origin), mStreamId};
|
|
|
|
mSeekReport.push_back(seek_report);
|
|
|
|
return seek_report.seek_offset;
|
|
}
|
|
private:
|
|
std::vector<WriteReport>& mWriteReport;
|
|
std::vector<SeekReport>& mSeekReport;
|
|
size_t mStreamId;
|
|
};
|
|
|
|
try
|
|
{
|
|
// declare report logs
|
|
std::vector<ReportDummyStream::WriteReport> write_report;
|
|
std::vector<ReportDummyStream::SeekReport> seek_report;
|
|
|
|
// create stream list with links to report logs
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 0)), // 0x000 - 0x0ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 1)), // 0x100 - 0x1ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 2)), // 0x200 - 0x2ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 3)), // 0x300 - 0x3ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 4)), // 0x400 - 0x4ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 5)), // 0x500 - 0x5ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 6)), // 0x600 - 0x6ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 7)), // 0x700 - 0x7ff
|
|
};
|
|
|
|
// create concatenated stream
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
// define test
|
|
struct Test {
|
|
// test name
|
|
std::string test_name;
|
|
|
|
// these seeks are done then seek log is cleared
|
|
std::vector<int64_t> unlogged_seeks;
|
|
|
|
// these seeks are done before writing but will be logged
|
|
std::vector<int64_t> logged_seeks;
|
|
|
|
// write param
|
|
byte_t* write_ptr;
|
|
size_t write_count;
|
|
|
|
// expected log reports
|
|
std::vector<ReportDummyStream::WriteReport> exp_write_report;
|
|
std::vector<ReportDummyStream::SeekReport> exp_seek_report;
|
|
};
|
|
|
|
// create tests
|
|
std::vector<Test> tests {
|
|
{"WriteFromBeginning", {0}, {}, (byte_t*)0x1000, 0x30, {{(byte_t*)0x1000, 0x30, 0}}, {}},
|
|
{"ContinueWritingFromBeginning", {}, {}, (byte_t*)0x1000, 0x30, {{(byte_t*)0x1000, 0x30, 0}}, {}},
|
|
{"WriteFromSomewhereElseInExistingStream", {0xe0}, {}, (byte_t*)0x1000, 0x20, {{(byte_t*)0x1000, 0x20, 0}}, {}},
|
|
};
|
|
|
|
// run tests
|
|
for (auto test = tests.begin(); test != tests.end(); test++)
|
|
{
|
|
for (auto itr = test->unlogged_seeks.begin(); itr != test->unlogged_seeks.end(); itr++)
|
|
{
|
|
stream.seek(*itr, tc::io::SeekOrigin::Begin);
|
|
}
|
|
|
|
write_report.clear();
|
|
seek_report.clear();
|
|
|
|
for (auto itr = test->logged_seeks.begin(); itr != test->logged_seeks.end(); itr++)
|
|
{
|
|
stream.seek(*itr, tc::io::SeekOrigin::Begin);
|
|
}
|
|
|
|
stream.write(test->write_ptr, test->write_count);
|
|
|
|
if (write_report != test->exp_write_report)
|
|
{
|
|
throw tc::Exception(fmt::format("Test \"{}\" Failed: .write() issued to base streams were not as expected", test->test_name));
|
|
}
|
|
|
|
if (seek_report != test->exp_seek_report)
|
|
{
|
|
throw tc::Exception(fmt::format("Test \"{}\" Failed: .seek() issued to base streams were not as expected", test->test_name));
|
|
}
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_write_CanWriteFromMultipleStreamWithSeekSupport()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_write_CanWriteFromMultipleStreamWithSeekSupport : ");
|
|
|
|
class ReportDummyStream : public StreamTestUtil::DummyStreamBase
|
|
{
|
|
public:
|
|
struct SeekReport
|
|
{
|
|
int64_t seek_offset;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const SeekReport& other) const
|
|
{
|
|
return seek_offset == other.seek_offset \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
struct WriteReport
|
|
{
|
|
const byte_t* write_ptr;
|
|
size_t write_count;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const WriteReport& other) const
|
|
{
|
|
return write_ptr == other.write_ptr \
|
|
&& write_count == other.write_count \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
ReportDummyStream(std::vector<WriteReport>& write_report, std::vector<SeekReport>& seek_report, size_t stream_id) :
|
|
DummyStreamBase(0x100, true, true, true, false, false),
|
|
mWriteReport(write_report),
|
|
mSeekReport(seek_report),
|
|
mStreamId(stream_id)
|
|
{}
|
|
|
|
size_t write(const byte_t* ptr, size_t count)
|
|
{
|
|
mWriteReport.push_back({ptr, count, mStreamId});
|
|
|
|
size_t writable_count = tc::io::IOUtil::getWritableCount(DummyStreamBase::length(), DummyStreamBase::position(), count);
|
|
|
|
// update stream position
|
|
DummyStreamBase::seek(int64_t(writable_count), tc::io::SeekOrigin::Current);
|
|
|
|
return writable_count;
|
|
}
|
|
|
|
int64_t seek(int64_t offset, tc::io::SeekOrigin origin)
|
|
{
|
|
SeekReport seek_report = {DummyStreamBase::seek(offset, origin), mStreamId};
|
|
|
|
mSeekReport.push_back(seek_report);
|
|
|
|
return seek_report.seek_offset;
|
|
}
|
|
private:
|
|
std::vector<WriteReport>& mWriteReport;
|
|
std::vector<SeekReport>& mSeekReport;
|
|
size_t mStreamId;
|
|
};
|
|
|
|
try
|
|
{
|
|
// declare report logs
|
|
std::vector<ReportDummyStream::WriteReport> write_report;
|
|
std::vector<ReportDummyStream::SeekReport> seek_report;
|
|
|
|
// create stream list with links to report logs
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 0)), // 0x000 - 0x0ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 1)), // 0x100 - 0x1ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 2)), // 0x200 - 0x2ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 3)), // 0x300 - 0x3ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 4)), // 0x400 - 0x4ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 5)), // 0x500 - 0x5ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 6)), // 0x600 - 0x6ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 7)), // 0x700 - 0x7ff
|
|
};
|
|
|
|
// create concatenated stream
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
// define test
|
|
struct Test {
|
|
// test name
|
|
std::string test_name;
|
|
|
|
// these seeks are done then seek log is cleared
|
|
std::vector<int64_t> unlogged_seeks;
|
|
|
|
// these seeks are done before writeing but will be logged
|
|
std::vector<int64_t> logged_seeks;
|
|
|
|
// write param
|
|
byte_t* write_ptr;
|
|
size_t write_count;
|
|
|
|
// expected log reports
|
|
std::vector<ReportDummyStream::WriteReport> exp_write_report;
|
|
std::vector<ReportDummyStream::SeekReport> exp_seek_report;
|
|
};
|
|
|
|
// create tests
|
|
std::vector<Test> tests {
|
|
{"WriteAllOfStream 0-7 (stream 0x0 positions)", {0x000, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x000}, {}, (byte_t*)0x1000, 0x800, {{(byte_t*)0x1000, 0x100, 0}, {(byte_t*)0x1100, 0x100, 1}, {(byte_t*)0x1200, 0x100, 2}, {(byte_t*)0x1300, 0x100, 3}, {(byte_t*)0x1400, 0x100, 4}, {(byte_t*)0x1500, 0x100, 5}, {(byte_t*)0x1600, 0x100, 6}, {(byte_t*)0x1700, 0x100, 7}}, {}},
|
|
{"WriteAllOfStream 0-7 (stream 0x80 positions)", {0x080, 0x180, 0x280, 0x380, 0x480, 0x580, 0x680, 0x780, 0x000}, {}, (byte_t*)0x1000, 0x800, {{(byte_t*)0x1000, 0x100, 0}, {(byte_t*)0x1100, 0x100, 1}, {(byte_t*)0x1200, 0x100, 2}, {(byte_t*)0x1300, 0x100, 3}, {(byte_t*)0x1400, 0x100, 4}, {(byte_t*)0x1500, 0x100, 5}, {(byte_t*)0x1600, 0x100, 6}, {(byte_t*)0x1700, 0x100, 7}}, {{0x0, 1}, {0x0, 2}, {0x0, 3}, {0x0, 4}, {0x0, 5}, {0x0, 6}, {0x0, 7}}},
|
|
{"WriteAllOfStream 0-7 (stream 0x00 or 0x80 positions)", {0x080, 0x100, 0x280, 0x300, 0x480, 0x500, 0x680, 0x700, 0x000}, {}, (byte_t*)0x1000, 0x800, {{(byte_t*)0x1000, 0x100, 0}, {(byte_t*)0x1100, 0x100, 1}, {(byte_t*)0x1200, 0x100, 2}, {(byte_t*)0x1300, 0x100, 3}, {(byte_t*)0x1400, 0x100, 4}, {(byte_t*)0x1500, 0x100, 5}, {(byte_t*)0x1600, 0x100, 6}, {(byte_t*)0x1700, 0x100, 7}}, {{0x0, 2}, {0x0, 4}, {0x0, 6}}},
|
|
{"WriteAllOfStream 3-6 (stream 0x0 positions)", {0x000, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x300}, {}, (byte_t*)0x1000, 0x400, {{(byte_t*)0x1000, 0x100, 3}, {(byte_t*)0x1100, 0x100, 4}, {(byte_t*)0x1200, 0x100, 5}, {(byte_t*)0x1300, 0x100, 6}}, {}},
|
|
{"WriteAllOfStream 3-6 (stream 0x80 positions)", {0x080, 0x180, 0x280, 0x380, 0x480, 0x580, 0x680, 0x780, 0x300}, {}, (byte_t*)0x1000, 0x400, {{(byte_t*)0x1000, 0x100, 3}, {(byte_t*)0x1100, 0x100, 4}, {(byte_t*)0x1200, 0x100, 5}, {(byte_t*)0x1300, 0x100, 6}}, {{0x0, 4}, {0x0, 5}, {0x0, 6}}},
|
|
{"WriteStream (partial)3,4-5,(partial)6 (stream 0x0 positions)", {0x000, 0x100, 0x200, 0x300, 0x400, 0x500, 0x600, 0x700, 0x350}, {}, (byte_t*)0x1000, 0x300, {{(byte_t*)0x1000, 0xB0, 3}, {(byte_t*)0x10B0, 0x100, 4}, {(byte_t*)0x11B0, 0x100, 5}, {(byte_t*)0x12B0, 0x50, 6}}, {}},
|
|
{"WriteStream (partial)3,4-5,(partial)6 (stream 0x80 positions)", {0x080, 0x180, 0x280, 0x380, 0x480, 0x580, 0x680, 0x780, 0x350}, {}, (byte_t*)0x1000, 0x300, {{(byte_t*)0x1000, 0xB0, 3}, {(byte_t*)0x10B0, 0x100, 4}, {(byte_t*)0x11B0, 0x100, 5}, {(byte_t*)0x12B0, 0x50, 6}}, {{0x0, 4}, {0x0, 5}, {0x0, 6}}},
|
|
};
|
|
|
|
// run tests
|
|
for (auto test = tests.begin(); test != tests.end(); test++)
|
|
{
|
|
for (auto itr = test->unlogged_seeks.begin(); itr != test->unlogged_seeks.end(); itr++)
|
|
{
|
|
stream.seek(*itr, tc::io::SeekOrigin::Begin);
|
|
}
|
|
|
|
write_report.clear();
|
|
seek_report.clear();
|
|
|
|
for (auto itr = test->logged_seeks.begin(); itr != test->logged_seeks.end(); itr++)
|
|
{
|
|
stream.seek(*itr, tc::io::SeekOrigin::Begin);
|
|
}
|
|
|
|
stream.write(test->write_ptr, test->write_count);
|
|
|
|
if (write_report != test->exp_write_report)
|
|
{
|
|
throw tc::Exception(fmt::format("Test \"{}\" Failed: .write() issued to base streams were not as expected", test->test_name));
|
|
}
|
|
|
|
if (seek_report != test->exp_seek_report)
|
|
{
|
|
throw tc::Exception(fmt::format("Test \"{}\" Failed: .seek() issued to base streams were not as expected", test->test_name));
|
|
}
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_write_CanWriteFromMultipleStreamWithNoSeekSupport()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_write_CanWriteFromMultipleStreamWithNoSeekSupport : ");
|
|
|
|
class ReportDummyStream : public StreamTestUtil::DummyStreamBase
|
|
{
|
|
public:
|
|
struct SeekReport
|
|
{
|
|
int64_t seek_offset;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const SeekReport& other) const
|
|
{
|
|
return seek_offset == other.seek_offset \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
struct WriteReport
|
|
{
|
|
const byte_t* write_ptr;
|
|
size_t write_count;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const WriteReport& other) const
|
|
{
|
|
return write_ptr == other.write_ptr \
|
|
&& write_count == other.write_count \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
ReportDummyStream(std::vector<WriteReport>& write_report, std::vector<SeekReport>& seek_report, size_t stream_id) :
|
|
DummyStreamBase(0x100, true, true, false, false, false),
|
|
mWriteReport(write_report),
|
|
mSeekReport(seek_report),
|
|
mStreamId(stream_id)
|
|
{}
|
|
|
|
size_t write(const byte_t* ptr, size_t count)
|
|
{
|
|
mWriteReport.push_back({ptr, count, mStreamId});
|
|
|
|
size_t writable_count = tc::io::IOUtil::getWritableCount(DummyStreamBase::length(), DummyStreamBase::position(), count);
|
|
|
|
// update stream position
|
|
DummyStreamBase::seek(int64_t(writable_count), tc::io::SeekOrigin::Current);
|
|
|
|
return writable_count;
|
|
}
|
|
|
|
int64_t seek(int64_t offset, tc::io::SeekOrigin origin)
|
|
{
|
|
SeekReport seek_report = {DummyStreamBase::seek(offset, origin), mStreamId};
|
|
|
|
mSeekReport.push_back(seek_report);
|
|
|
|
return seek_report.seek_offset;
|
|
}
|
|
private:
|
|
std::vector<WriteReport>& mWriteReport;
|
|
std::vector<SeekReport>& mSeekReport;
|
|
size_t mStreamId;
|
|
};
|
|
|
|
try
|
|
{
|
|
// declare report logs
|
|
std::vector<ReportDummyStream::WriteReport> write_report;
|
|
std::vector<ReportDummyStream::SeekReport> seek_report;
|
|
|
|
// create stream list with links to report logs
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 0)), // 0x000 - 0x0ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 1)), // 0x100 - 0x1ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 2)), // 0x200 - 0x2ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 3)), // 0x300 - 0x3ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 4)), // 0x400 - 0x4ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 5)), // 0x500 - 0x5ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 6)), // 0x600 - 0x6ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 7)), // 0x700 - 0x7ff
|
|
};
|
|
|
|
// create concatenated stream
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
// define test
|
|
struct Test {
|
|
// test name
|
|
std::string test_name;
|
|
|
|
// these seeks are done then seek log is cleared
|
|
std::vector<int64_t> unlogged_seeks;
|
|
|
|
// these seeks are done before writeing but will be logged
|
|
std::vector<int64_t> logged_seeks;
|
|
|
|
// write param
|
|
byte_t* write_ptr;
|
|
size_t write_count;
|
|
|
|
// expected log reports
|
|
std::vector<ReportDummyStream::WriteReport> exp_write_report;
|
|
std::vector<ReportDummyStream::SeekReport> exp_seek_report;
|
|
};
|
|
|
|
// create tests
|
|
std::vector<Test> tests {
|
|
{"WriteStream (partial)0", {}, {}, (byte_t*)0x1000, 0xA0, {{(byte_t*)0x1000, 0xA0, 0}}, {}},
|
|
{"WriteStream (partial)0,1-4", {}, {}, (byte_t*)0x1000, 0x460, {{(byte_t*)0x1000, 0x60, 0}, {(byte_t*)0x1060, 0x100, 1}, {(byte_t*)0x1160, 0x100, 2}, {(byte_t*)0x1260, 0x100, 3}, {(byte_t*)0x1360, 0x100, 4}}, {}},
|
|
{"WriteStream 5-7", {}, {}, (byte_t*)0x1000, 0x300, {{(byte_t*)0x1000, 0x100, 5}, {(byte_t*)0x1100, 0x100, 6}, {(byte_t*)0x1200, 0x100, 7}}, {}},
|
|
};
|
|
|
|
// run tests
|
|
for (auto test = tests.begin(); test != tests.end(); test++)
|
|
{
|
|
for (auto itr = test->unlogged_seeks.begin(); itr != test->unlogged_seeks.end(); itr++)
|
|
{
|
|
stream.seek(*itr, tc::io::SeekOrigin::Begin);
|
|
}
|
|
|
|
write_report.clear();
|
|
seek_report.clear();
|
|
|
|
for (auto itr = test->logged_seeks.begin(); itr != test->logged_seeks.end(); itr++)
|
|
{
|
|
stream.seek(*itr, tc::io::SeekOrigin::Begin);
|
|
}
|
|
|
|
stream.write(test->write_ptr, test->write_count);
|
|
|
|
if (write_report != test->exp_write_report)
|
|
{
|
|
fmt::print("\n");
|
|
fmt::print("WriteLog:\n");
|
|
for (auto itr = write_report.begin(); itr != write_report.end(); itr++)
|
|
{
|
|
fmt::print("WriteReport (ptr: 0x{:x}, count: 0x{:x}, stream: {:d})\n", (size_t)itr->write_ptr, itr->write_count, itr->stream_id);
|
|
}
|
|
fmt::print("ExpWriteLog:\n");
|
|
for (auto itr = test->exp_write_report.begin(); itr != test->exp_write_report.end(); itr++)
|
|
{
|
|
fmt::print("WriteReport (ptr: 0x{:x}, count: 0x{:x}, stream: {:d})\n", (size_t)itr->write_ptr, itr->write_count, itr->stream_id);
|
|
}
|
|
throw tc::Exception(fmt::format("Test \"{}\" Failed: .write() issued to base streams were not as expected", test->test_name));
|
|
}
|
|
|
|
if (seek_report != test->exp_seek_report)
|
|
{
|
|
throw tc::Exception(fmt::format("Test \"{}\" Failed: .seek() issued to base streams were not as expected", test->test_name));
|
|
}
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_write_WriteFromMultiStream_NoSeekSupport_ThrowsOnSeekRequired()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_write_WriteFromMultiStream_NoSeekSupport_ThrowsOnSeekRequired : ");
|
|
|
|
class ReportDummyStream : public StreamTestUtil::DummyStreamBase
|
|
{
|
|
public:
|
|
struct SeekReport
|
|
{
|
|
int64_t seek_offset;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const SeekReport& other) const
|
|
{
|
|
return seek_offset == other.seek_offset \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
struct WriteReport
|
|
{
|
|
const byte_t* write_ptr;
|
|
size_t write_count;
|
|
size_t stream_id;
|
|
|
|
bool operator==(const WriteReport& other) const
|
|
{
|
|
return write_ptr == other.write_ptr \
|
|
&& write_count == other.write_count \
|
|
&& stream_id == other.stream_id;
|
|
}
|
|
};
|
|
|
|
ReportDummyStream(std::vector<WriteReport>& write_report, std::vector<SeekReport>& seek_report, size_t stream_id) :
|
|
DummyStreamBase(0x100, 0x80, true, true, false, false, false), // the initial position is 0x80
|
|
mWriteReport(write_report),
|
|
mSeekReport(seek_report),
|
|
mStreamId(stream_id)
|
|
{}
|
|
|
|
size_t write(const byte_t* ptr, size_t count)
|
|
{
|
|
mWriteReport.push_back({ptr, count, mStreamId});
|
|
|
|
size_t writable_count = tc::io::IOUtil::getWritableCount(DummyStreamBase::length(), DummyStreamBase::position(), count);
|
|
|
|
// update stream position
|
|
DummyStreamBase::seek(int64_t(writable_count), tc::io::SeekOrigin::Current);
|
|
|
|
return writable_count;
|
|
}
|
|
|
|
int64_t seek(int64_t offset, tc::io::SeekOrigin origin)
|
|
{
|
|
SeekReport seek_report = {DummyStreamBase::seek(offset, origin), mStreamId};
|
|
|
|
mSeekReport.push_back(seek_report);
|
|
|
|
return seek_report.seek_offset;
|
|
}
|
|
private:
|
|
std::vector<WriteReport>& mWriteReport;
|
|
std::vector<SeekReport>& mSeekReport;
|
|
size_t mStreamId;
|
|
};
|
|
|
|
try
|
|
{
|
|
// declare report logs
|
|
std::vector<ReportDummyStream::WriteReport> write_report;
|
|
std::vector<ReportDummyStream::SeekReport> seek_report;
|
|
|
|
// create stream list with links to report logs
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 0)), // 0x000 - 0x0ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 1)), // 0x100 - 0x1ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 2)), // 0x200 - 0x2ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 3)), // 0x300 - 0x3ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 4)), // 0x400 - 0x4ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 5)), // 0x500 - 0x5ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 6)), // 0x600 - 0x6ff
|
|
std::make_shared<ReportDummyStream>(ReportDummyStream(write_report, seek_report, 7)), // 0x700 - 0x7ff
|
|
};
|
|
|
|
// create concatenated stream
|
|
tc::io::ConcatenatedStream stream = tc::io::ConcatenatedStream(streams);
|
|
|
|
try
|
|
{
|
|
stream.write((byte_t*)0x1000, 0x200);
|
|
throw tc::Exception(".write() did not throw tc::io::IOException where stream required seeking to begining but did not support seeking.");
|
|
}
|
|
catch (const tc::io::IOException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_MoveOperator_MoveDisposedToDisposed()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_MoveOperator_MoveDisposedToDisposed : ");
|
|
try
|
|
{
|
|
// create streams a and b (both disposed)
|
|
tc::io::ConcatenatedStream stream_a;
|
|
tc::io::ConcatenatedStream stream_b;
|
|
|
|
// ensure stream a had valid properties to begin with
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_a, 0x0, 0x0, false, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_a had wrong properies after default .ctor() ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_a.seek(0, tc::io::SeekOrigin::Current);
|
|
throw tc::Exception("stream_a was disposed upon construction, but failed throw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
// ensure stream b had valid properties to begin with
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_b, 0x0, 0x0, false, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_b had wrong properies after default .ctor() ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_b.seek(0, tc::io::SeekOrigin::Current);
|
|
throw tc::Exception("stream_b was disposed upon construction, but failed throw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
// move stream_a to stream_b
|
|
stream_b = std::move(stream_a);
|
|
|
|
// ensure stream a had valid properties after being moved from
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_a, 0x0, 0x0, false, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_a had wrong properies after it was move assigned to stream_b ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_a.seek(0, tc::io::SeekOrigin::Current);
|
|
throw tc::Exception("stream_a was disposed upon being move assigned to stream_b, but failed throw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
// ensure stream b had valid properties after being moved to
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_b, 0x0, 0x0, false, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_b has wrong properties after being move assigned from stream_a ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_b.seek(0, tc::io::SeekOrigin::Current);
|
|
throw tc::Exception("stream_b was disposed upon move assignment from stream_a, but failed throw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_MoveOperator_MoveInitializedToDisposed()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_MoveOperator_MoveInitializedToDisposed : ");
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false))
|
|
};
|
|
|
|
// create streams a and b
|
|
tc::io::ConcatenatedStream stream_a(streams);
|
|
tc::io::ConcatenatedStream stream_b;
|
|
|
|
// ensure stream a had valid properties to begin with
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_a, 0x300, 0x0, true, true, true);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_a had wrong properies after create .ctor() ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_a.seek(0, tc::io::SeekOrigin::Current);
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
throw tc::Exception("stream_a was initialized upon construction, but threw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
|
|
// ensure stream b had valid properties to begin with
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_b, 0x0, 0x0, false, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_b had wrong properies after default .ctor() ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_b.seek(0, tc::io::SeekOrigin::Current);
|
|
throw tc::Exception("stream_b was disposed upon construction, but failed throw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
// move stream_a to stream_b
|
|
stream_b = std::move(stream_a);
|
|
|
|
// ensure stream a had valid properties after being moved from
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_a, 0x0, 0x0, false, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_a had wrong properies after it was move assigned to stream_b ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_a.seek(0, tc::io::SeekOrigin::Current);
|
|
throw tc::Exception("stream_a was disposed upon being move assigned to stream_b, but failed throw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
// ensure stream b had valid properties after being moved to
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_b, 0x300, 0x0, true, true, true);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_b has wrong properties after being move assigned from stream_a ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_b.seek(0, tc::io::SeekOrigin::Current);
|
|
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
throw tc::Exception("stream_b was initialized upon move assignment from stream_a, but threw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_MoveOperator_MoveDisposedToInitialized()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_MoveOperator_MoveDisposedToInitialized : ");
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false))
|
|
};
|
|
|
|
// create streams a and b
|
|
tc::io::ConcatenatedStream stream_a;
|
|
tc::io::ConcatenatedStream stream_b(streams);
|
|
|
|
// ensure stream b had valid properties to begin with
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_a, 0x0, 0x0, false, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_a had wrong properies after default .ctor() ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_a.seek(0, tc::io::SeekOrigin::Current);
|
|
throw tc::Exception("stream_a was disposed upon construction, but failed throw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
// ensure stream a had valid properties to begin with
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_b, 0x300, 0x0, true, true, true);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_b had wrong properies after create .ctor() ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_b.seek(0, tc::io::SeekOrigin::Current);
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
throw tc::Exception("stream_b was initialized upon construction, but threw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
|
|
// move stream_a to stream_b
|
|
stream_b = std::move(stream_a);
|
|
|
|
// ensure stream a had valid properties after being moved from
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_a, 0x0, 0x0, false, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_a had wrong properies after it was move assigned to stream_b ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_a.seek(0, tc::io::SeekOrigin::Current);
|
|
throw tc::Exception("stream_a was disposed upon being move assigned to stream_b, but failed throw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
// ensure stream b had valid properties after being moved to
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_b, 0x0, 0x0, false, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_b has wrong properties after being move assigned from stream_a ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_b.seek(0, tc::io::SeekOrigin::Current);
|
|
throw tc::Exception("stream_b was disposed upon move assignment from stream_a, but failed throw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_MoveOperator_MoveInitializedToInitialized()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_MoveOperator_MoveInitializedToInitialized : ");
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams_a {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false))
|
|
};
|
|
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams_b {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x200, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x200, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x200, true, true, true, false, false))
|
|
};
|
|
|
|
// create streams a and b
|
|
tc::io::ConcatenatedStream stream_a(streams_a);
|
|
tc::io::ConcatenatedStream stream_b(streams_b);
|
|
|
|
// ensure stream a had valid properties to begin with
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_a, 0x300, 0x0, true, true, true);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_a had wrong properies after create .ctor() ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_a.seek(0, tc::io::SeekOrigin::Current);
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
throw tc::Exception("stream_a was initialized upon construction, but threw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
|
|
// ensure stream a had valid properties to begin with
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_b, 0x600, 0x0, true, true, true);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_b had wrong properies after create .ctor() ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_b.seek(0, tc::io::SeekOrigin::Current);
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
throw tc::Exception("stream_b was initialized upon construction, but threw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
|
|
// move stream_a to stream_b
|
|
stream_b = std::move(stream_a);
|
|
|
|
// ensure stream a had valid properties after being moved from
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_a, 0x0, 0x0, false, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_a had wrong properies after it was move assigned to stream_b ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_a.seek(0, tc::io::SeekOrigin::Current);
|
|
throw tc::Exception("stream_a was disposed upon being move assigned to stream_b, but failed throw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
// ensure stream b had valid properties after being moved to
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_b, 0x300, 0x0, true, true, true);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_b has wrong properties after being move assigned from stream_a ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_b.seek(0, tc::io::SeekOrigin::Current);
|
|
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
throw tc::Exception("stream_b was initialized upon move assignment from stream_a, but threw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_MoveConstructor_MoveDisposed()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_MoveConstructor_MoveDisposed : ");
|
|
try
|
|
{
|
|
// create stream a
|
|
tc::io::ConcatenatedStream stream_a;
|
|
|
|
// ensure stream a had valid properties to begin with
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_a, 0x0, 0x0, false, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_a had wrong properies after default .ctor() ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_a.seek(0, tc::io::SeekOrigin::Current);
|
|
throw tc::Exception("stream_a was disposed upon construction, but failed throw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
// move stream_a to stream_b
|
|
tc::io::ConcatenatedStream stream_b(std::move(stream_a));
|
|
|
|
// ensure stream a had valid properties after being moved from
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_a, 0x0, 0x0, false, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_a had wrong properies after it was move assigned to stream_b ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_a.seek(0, tc::io::SeekOrigin::Current);
|
|
throw tc::Exception("stream_a was disposed upon being move assigned to stream_b, but failed throw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
// ensure stream b had valid properties after being moved to
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_b, 0x0, 0x0, false, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_b has wrong properties after being move assigned from stream_a ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_b.seek(0, tc::io::SeekOrigin::Current);
|
|
throw tc::Exception("stream_b was disposed upon move assignment from stream_a, but failed throw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
}
|
|
|
|
void io_ConcatenatedStream_TestClass::test_MoveConstructor_MoveInitialized()
|
|
{
|
|
fmt::print("[tc::io::ConcatenatedStream] test_MoveConstructor_MoveInitialized : ");
|
|
try
|
|
{
|
|
std::vector<std::shared_ptr<tc::io::IStream>> streams {
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false)),
|
|
std::make_shared<StreamTestUtil::DummyStreamBase>(StreamTestUtil::DummyStreamBase(0x100, true, true, true, false, false))
|
|
};
|
|
|
|
// create stream a
|
|
tc::io::ConcatenatedStream stream_a(streams);
|
|
|
|
// ensure stream a had valid properties to begin with
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_a, 0x300, 0x0, true, true, true);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_a had wrong properies after create .ctor() ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_a.seek(0, tc::io::SeekOrigin::Current);
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
throw tc::Exception("stream_a was initialized upon construction, but threw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
|
|
// move stream_a to stream_b
|
|
tc::io::ConcatenatedStream stream_b(std::move(stream_a));
|
|
|
|
// ensure stream a had valid properties after being moved from
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_a, 0x0, 0x0, false, false, false);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_a had wrong properies after it was move assigned to stream_b ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_a.seek(0, tc::io::SeekOrigin::Current);
|
|
throw tc::Exception("stream_a was disposed upon being move assigned to stream_b, but failed throw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
// ensure stream b had valid properties after being moved to
|
|
try
|
|
{
|
|
StreamTestUtil::constructor_TestHelper(stream_b, 0x300, 0x0, true, true, true);
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
throw tc::Exception(fmt::format("stream_b has wrong properties after being move assigned from stream_a ({})", e.error()));
|
|
}
|
|
try
|
|
{
|
|
stream_b.seek(0, tc::io::SeekOrigin::Current);
|
|
|
|
}
|
|
catch (const tc::ObjectDisposedException&)
|
|
{
|
|
throw tc::Exception("stream_b was initialized upon move assignment from stream_a, but threw tc::ObjectDisposedException when seek() was called");
|
|
}
|
|
|
|
fmt::print("PASS\n");
|
|
}
|
|
catch (const tc::Exception& e)
|
|
{
|
|
fmt::print("FAIL ({:s})\n", e.error());
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
fmt::print("FAIL (unhandled exception) ({})\n", e.what());
|
|
}
|
|
} |