GenericStreamTests.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <Tests/GenericStreamMock.h>
  9. #include <AzCore/UnitTest/TestTypes.h>
  10. #include <AZTestShared/Utils/Utils.h>
  11. class GenericStreamTest
  12. : public UnitTest::LeakDetectionFixture
  13. {
  14. public:
  15. void SetUp() override
  16. {
  17. using ::testing::_;
  18. using ::testing::NiceMock;
  19. using ::testing::Return;
  20. UnitTest::LeakDetectionFixture::SetUp();
  21. // Route our mocked WriteFromStream back to the base class implementation for test validation
  22. ON_CALL(m_mockGenericStream, WriteFromStream(_, _))
  23. .WillByDefault([this](AZ::IO::SizeType bytes, AZ::IO::GenericStream* inputStream)
  24. {
  25. return m_mockGenericStream.BaseWriteFromStream(bytes, inputStream);
  26. });
  27. }
  28. void TearDown() override
  29. {
  30. UnitTest::LeakDetectionFixture::TearDown();
  31. }
  32. void CreateTestData(AZStd::vector<AZ::u8>& inBuffer, size_t numBytes)
  33. {
  34. inBuffer.resize(numBytes);
  35. // Fill the buffer with a repeating pattern of 00->FF, FF->00, 00->FF, etc.
  36. // We flip the pattern ordering to ensure that our buffer copies don't keep copying the first set of bytes.
  37. for (size_t offset = 0; offset < numBytes; offset++)
  38. {
  39. inBuffer[offset] = (offset >> 8) & 0x01 ? ~(offset & 0xFF) : (offset & 0xFF);
  40. }
  41. }
  42. void TestGenericStreamWriteFromStream(size_t numBytesToWrite)
  43. {
  44. using ::testing::_;
  45. // Create an inputStream filled with a repeating pattern of 00-FF, FF-00, 00-FF, etc...
  46. AZStd::vector<AZ::u8> inBuffer(numBytesToWrite);
  47. CreateTestData(inBuffer, numBytesToWrite);
  48. AZ::IO::MemoryStream inputStream(inBuffer.data(), inBuffer.size());
  49. // We will use mockGenericStream as our output stream for testing, but we'll reroute the Write() call into an
  50. // output memoryStream to help us easily validate that the GenericStream WriteFromStream implementation works correctly.
  51. AZStd::vector<AZ::u8> outBuffer(numBytesToWrite);
  52. AZ::IO::MemoryStream outputStream(outBuffer.data(), outBuffer.size(), 0);;
  53. // Reroute the mock stream to our output MemoryStream for writing.
  54. ON_CALL(m_mockGenericStream, Write(_, _))
  55. .WillByDefault([&outputStream](AZ::IO::SizeType bytes, const void* buffer)
  56. {
  57. return outputStream.Write(bytes, buffer);
  58. });
  59. // Verify that the default implementation of WriteFromStream works correctly.
  60. m_mockGenericStream.WriteFromStream(numBytesToWrite, &inputStream);
  61. EXPECT_EQ(inBuffer, outBuffer);
  62. }
  63. void TestMemoryStreamWriteFromStream(size_t numBytesToWrite)
  64. {
  65. using ::testing::_;
  66. // Create an inputStream filled with a repeating pattern of 00-FF, FF-00, 00-FF, etc...
  67. AZStd::vector<AZ::u8> inBuffer(numBytesToWrite);
  68. CreateTestData(inBuffer, numBytesToWrite);
  69. AZ::IO::MemoryStream inputStream(inBuffer.data(), inBuffer.size());
  70. // Create an output MemoryStream to write into
  71. AZStd::vector<AZ::u8> outBuffer(numBytesToWrite);
  72. AZ::IO::MemoryStream outputStream(outBuffer.data(), outBuffer.size(), 0);;
  73. // Verify that the MemoryStream implementation of WriteFromStream works correctly.
  74. outputStream.WriteFromStream(numBytesToWrite, &inputStream);
  75. EXPECT_EQ(inBuffer, outBuffer);
  76. }
  77. protected:
  78. ::testing::NiceMock<GenericStreamMock> m_mockGenericStream;
  79. };
  80. TEST_F(GenericStreamTest, WriteFromStream_LessBytesThanTempBuffer_CopyIsSuccessful)
  81. {
  82. // Test WriteFromStream with a buffer size that's smaller than the copy buffer and not a power of two
  83. // just to help catch any possible errors.
  84. TestGenericStreamWriteFromStream(AZ::IO::GenericStream::StreamToStreamCopyBufferSize / 3);
  85. }
  86. TEST_F(GenericStreamTest, WriteFromStream_SameByteSizeAsTempBuffer_CopyIsSuccessful)
  87. {
  88. // Test WriteFromStream with a buffer size exactly equal to the copy buffer
  89. TestGenericStreamWriteFromStream(AZ::IO::GenericStream::StreamToStreamCopyBufferSize);
  90. }
  91. TEST_F(GenericStreamTest, WriteFromStream_MoreBytesThanTempBuffer_CopyIsSuccessful)
  92. {
  93. // Test WriteFromStream with a buffer size that's larger than the copy buffer and not a power of two
  94. // just to help catch any possible errors.
  95. TestGenericStreamWriteFromStream(aznumeric_cast<size_t>(AZ::IO::GenericStream::StreamToStreamCopyBufferSize * 2.6f));
  96. }
  97. TEST_F(GenericStreamTest, MemoryStreamWriteFromStream_LessBytesThanTempBuffer_CopyIsSuccessful)
  98. {
  99. // Test WriteFromStream with a buffer size that's smaller than the GenericStream copy buffer and not a power of two
  100. // just to help catch any possible errors.
  101. TestMemoryStreamWriteFromStream(AZ::IO::GenericStream::StreamToStreamCopyBufferSize / 3);
  102. }
  103. TEST_F(GenericStreamTest, MemoryStreamWriteFromStream_SameByteSizeAsTempBuffer_CopyIsSuccessful)
  104. {
  105. // Test WriteFromStream with a buffer size exactly equal to the GenericStream copy buffer
  106. TestMemoryStreamWriteFromStream(AZ::IO::GenericStream::StreamToStreamCopyBufferSize);
  107. }
  108. TEST_F(GenericStreamTest, MemoryStreamWriteFromStream_MoreBytesThanTempBuffer_CopyIsSuccessful)
  109. {
  110. // Test WriteFromStream with a buffer size that's larger than the GenericStream copy buffer and not a power of two
  111. // just to help catch any possible errors.
  112. TestMemoryStreamWriteFromStream(aznumeric_cast<size_t>(AZ::IO::GenericStream::StreamToStreamCopyBufferSize * 2.6f));
  113. }
  114. namespace AZ::IO::Test
  115. {
  116. class ByteContainerStreamTest
  117. : public UnitTest::LeakDetectionFixture
  118. {
  119. };
  120. TEST_F(ByteContainerStreamTest, IsDefaultConstructible)
  121. {
  122. using ContainerType = AZStd::vector<AZStd::byte>;
  123. AZ::IO::ByteContainerStream<ContainerType> byteContainerStream;
  124. EXPECT_FALSE(byteContainerStream.IsOpen());
  125. }
  126. TEST_F(ByteContainerStreamTest, CanBeOpened_PostConstruction)
  127. {
  128. using ContainerType = AZStd::vector<AZStd::byte>;
  129. AZ::IO::ByteContainerStream<ContainerType> byteContainerStream;
  130. EXPECT_FALSE(byteContainerStream.IsOpen());
  131. ContainerType byteBuffer;
  132. EXPECT_TRUE(byteContainerStream.Open(byteBuffer));
  133. ASSERT_TRUE(byteContainerStream.IsOpen());
  134. EXPECT_EQ(0, byteContainerStream.GetCurPos());
  135. }
  136. TEST_F(ByteContainerStreamTest, Open_OnAlreadyOpenStream_Fails)
  137. {
  138. using ContainerType = AZStd::vector<AZStd::byte>;
  139. ContainerType byteBuffer;
  140. AZ::IO::ByteContainerStream byteContainerStream(&byteBuffer);
  141. ASSERT_TRUE(byteContainerStream.IsOpen());
  142. ContainerType secondBuffer;
  143. AZ_TEST_START_TRACE_SUPPRESSION;
  144. EXPECT_FALSE(byteContainerStream.Open(secondBuffer));
  145. AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
  146. }
  147. TEST_F(ByteContainerStreamTest, Cannot_PerformStreamModificationOperations_OnClosedStream)
  148. {
  149. using ContainerType = AZStd::vector<AZStd::byte>;
  150. ContainerType byteBuffer;
  151. AZ::IO::ByteContainerStream byteContainerStream(&byteBuffer);
  152. EXPECT_TRUE(byteContainerStream.IsOpen());
  153. constexpr AZStd::string_view testString("Hello World");
  154. EXPECT_EQ(testString.size(), byteContainerStream.Write(testString.size(), testString.data()));
  155. EXPECT_EQ(testString.size(), byteContainerStream.GetCurPos());
  156. EXPECT_EQ(testString.size(), byteContainerStream.GetLength());
  157. // Seek back to the beginning of the stream
  158. byteContainerStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN);
  159. AZStd::string outputString;
  160. auto ReadByteContainerStream = [expectedSize = testString.size(),
  161. &byteContainerStream](char* buffer, size_t size)
  162. {
  163. AZ::IO::SizeType readSize = byteContainerStream.Read(size, buffer);
  164. EXPECT_EQ(expectedSize, readSize);
  165. return readSize;
  166. };
  167. outputString.resize_and_overwrite(testString.size(), ReadByteContainerStream);
  168. // Close the stream and retry the above operations
  169. byteContainerStream.Close();
  170. ASSERT_FALSE(byteContainerStream.IsOpen());
  171. AZ_TEST_START_TRACE_SUPPRESSION;
  172. EXPECT_EQ(0, byteContainerStream.Write(testString.size(), testString.data()));
  173. EXPECT_EQ(0, byteContainerStream.GetCurPos());
  174. EXPECT_EQ(0, byteContainerStream.GetLength());
  175. AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
  176. AZ_TEST_START_TRACE_SUPPRESSION;
  177. // This seek should do nothing, but output an AZ_Error
  178. byteContainerStream.Seek(0, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN);
  179. AZ_TEST_STOP_TRACE_SUPPRESSION(1);
  180. auto ReadByteContainerStreamOnClosed = [&byteContainerStream](char* buffer, size_t size)
  181. {
  182. AZ_TEST_START_TRACE_SUPPRESSION;
  183. AZ::IO::SizeType readSize = byteContainerStream.Read(size, buffer);
  184. AZ_TEST_STOP_TRACE_SUPPRESSION_NO_COUNT;
  185. EXPECT_EQ(0, readSize);
  186. return readSize;
  187. };
  188. outputString.clear();
  189. outputString.resize_and_overwrite(testString.size(), ReadByteContainerStreamOnClosed);
  190. // Now re-open the stream and validate that seeking/reading and writing works again
  191. EXPECT_TRUE(byteContainerStream.ReOpen());
  192. ASSERT_TRUE(byteContainerStream.IsOpen());
  193. AZ::IO::SizeType seekPos = byteContainerStream.GetLength();
  194. EXPECT_EQ(seekPos, byteContainerStream.GetLength());
  195. // Seek to the end of the stream
  196. byteContainerStream.Seek(seekPos, AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN);
  197. EXPECT_EQ(seekPos, byteContainerStream.GetCurPos());
  198. // Yes, "byte" was on purpose
  199. constexpr AZStd::string_view secondString("Goodbyte World");
  200. EXPECT_EQ(secondString.size(), byteContainerStream.Write(secondString.size(), secondString.data()));
  201. EXPECT_EQ(testString.size() + secondString.size(), byteContainerStream.GetCurPos());
  202. EXPECT_EQ(testString.size() + secondString.size(), byteContainerStream.GetLength());
  203. // Seek to beginning of the second string
  204. byteContainerStream.Seek(testString.size(), AZ::IO::GenericStream::SeekMode::ST_SEEK_BEGIN);
  205. auto ReadByteContainerStreamOnReopened = [expectedSize = secondString.size(),
  206. &byteContainerStream](char* buffer, size_t size)
  207. {
  208. AZ::IO::SizeType readSize = byteContainerStream.Read(size, buffer);
  209. EXPECT_EQ(expectedSize, readSize);
  210. return readSize;
  211. };
  212. outputString.clear();
  213. outputString.resize_and_overwrite(secondString.size(), ReadByteContainerStreamOnReopened);
  214. }
  215. }