diff --git a/src/CBot/CBotFileUtils.cpp b/src/CBot/CBotFileUtils.cpp index cdbc62af..cebe9acb 100644 --- a/src/CBot/CBotFileUtils.cpp +++ b/src/CBot/CBotFileUtils.cpp @@ -59,7 +59,7 @@ static bool ReadBinary(std::istream &istr, T &value) while (true) // unsigned LEB128 { if (!istr.read(reinterpret_cast(&chr), 1)) return false; - if (shift < sizeof(T) * 8 - 1) + if (shift < sizeof(T) * 8) value |= static_cast(chr & 0x7F) << shift; shift += 7; if ((chr & 0x80) == 0) break; diff --git a/test/unit/CBot/CBotFileUtils_test.cpp b/test/unit/CBot/CBotFileUtils_test.cpp new file mode 100644 index 00000000..8f35118c --- /dev/null +++ b/test/unit/CBot/CBotFileUtils_test.cpp @@ -0,0 +1,285 @@ +#include "CBot/CBotFileUtils.h" + +#include + +namespace +{ +std::string createTestStringWithAllPossibleCharacters() +{ + std::string testString; + for (char c = std::numeric_limits::min(); ; ++c) + { + testString.push_back(c); + if (c == std::numeric_limits::max()) break; + } + return testString; +} +} + +namespace CBot +{ + +struct CBotFileUtilsTest : public testing::Test +{ + std::stringstream stream; +}; + +struct CBotFileUtilsReadWriteByteTest : public CBotFileUtilsTest, public testing::WithParamInterface +{ +}; + +TEST_P(CBotFileUtilsReadWriteByteTest, ReadByteValueShouldMatchWrittenValue) +{ + char expectedValue{GetParam()}; + ASSERT_TRUE(WriteByte(stream, expectedValue)); + char value{1}; + ASSERT_TRUE(ReadByte(stream, value)); + ASSERT_EQ(expectedValue, value); +} + +INSTANTIATE_TEST_SUITE_P( + CBotIoReadWriteTest, + CBotFileUtilsReadWriteByteTest, + testing::Values( + '\0', + static_cast(42), + std::numeric_limits::min(), + std::numeric_limits::max())); + +struct CBotFileUtilsReadWriteWordTest : public CBotFileUtilsTest, public testing::WithParamInterface +{ +}; + +TEST_P(CBotFileUtilsReadWriteWordTest, ReadWordValueShouldMatchWrittenValue) +{ + unsigned short expectedValue{GetParam()}; + ASSERT_TRUE(WriteWord(stream, expectedValue)); + unsigned short value{1}; + ASSERT_TRUE(ReadWord(stream, value)); + ASSERT_EQ(expectedValue, value); +} + +INSTANTIATE_TEST_SUITE_P( + CBotIoReadWriteTest, + CBotFileUtilsReadWriteWordTest, + testing::Values( + static_cast(0), + static_cast(42), + std::numeric_limits::min(), + std::numeric_limits::max() / 2, + std::numeric_limits::max())); + +struct CBotFileUtilsReadWriteShortTest : public CBotFileUtilsTest, public testing::WithParamInterface +{ +}; + +TEST_P(CBotFileUtilsReadWriteShortTest, ReadShortValueShouldMatchWrittenValue) +{ + short expectedValue{GetParam()}; + ASSERT_TRUE(WriteShort(stream, expectedValue)); + short value{1}; + ASSERT_TRUE(ReadShort(stream, value)); + ASSERT_EQ(expectedValue, value); +} + +INSTANTIATE_TEST_SUITE_P( + CBotIoReadWriteTest, + CBotFileUtilsReadWriteShortTest, + testing::Values( + static_cast(-7), + static_cast(-1), + static_cast(0), + static_cast(42), + std::numeric_limits::min(), + std::numeric_limits::min() / 2, + std::numeric_limits::max() / 2, + std::numeric_limits::max())); + +struct CBotFileUtilsReadWriteUInt32Test : public CBotFileUtilsTest, public testing::WithParamInterface +{ +}; + +TEST_P(CBotFileUtilsReadWriteUInt32Test, ReadUInt32ValueShouldMatchWrittenValue) +{ + uint32_t expectedValue{GetParam()}; + ASSERT_TRUE(WriteUInt32(stream, expectedValue)); + uint32_t value{1}; + ASSERT_TRUE(ReadUInt32(stream, value)); + ASSERT_EQ(expectedValue, value); +} + +INSTANTIATE_TEST_SUITE_P( + CBotIoReadWriteTest, + CBotFileUtilsReadWriteUInt32Test, + testing::Values( + static_cast(0), + static_cast(42), + std::numeric_limits::max() / 2, + std::numeric_limits::max())); + +struct CBotFileUtilsReadWriteIntTest : public CBotFileUtilsTest, public testing::WithParamInterface +{ +}; + +TEST_P(CBotFileUtilsReadWriteIntTest, ReadIntValueShouldMatchWrittenValue) +{ + int expectedValue{GetParam()}; + ASSERT_TRUE(WriteInt(stream, expectedValue)); + int value{1}; + ASSERT_TRUE(ReadInt(stream, value)); + ASSERT_EQ(expectedValue, value); +} + +INSTANTIATE_TEST_SUITE_P( + CBotIoReadWriteTest, + CBotFileUtilsReadWriteIntTest, + testing::Values( + static_cast(7), + static_cast(-1), + static_cast(0), + static_cast(42), + std::numeric_limits::min(), + std::numeric_limits::min() / 2, + std::numeric_limits::max() / 2, + std::numeric_limits::max())); + +struct CBotFileUtilsReadWriteLongTest : public CBotFileUtilsTest, public testing::WithParamInterface +{ +}; + +TEST_P(CBotFileUtilsReadWriteLongTest, ReadLongValueShouldMatchWrittenValue) +{ + long value{1}; + long expectedValue{GetParam()}; + ASSERT_TRUE(WriteLong(stream, expectedValue)); + ASSERT_TRUE(ReadLong(stream, value)); + ASSERT_EQ(expectedValue, value); +} + +TEST_P(CBotFileUtilsReadWriteLongTest, ReadLongValueShouldMatchWrittenValueWithPadding) +{ + constexpr int padding = 10; + long expectedValue{GetParam()}; + ASSERT_TRUE(WriteLong(stream, expectedValue, padding)); + long value{1}; + ASSERT_TRUE(ReadLong(stream, value)); + ASSERT_EQ(expectedValue, value); +} + +TEST_P(CBotFileUtilsReadWriteLongTest, ReadLongValueShouldMatchWrittenValueWithPaddingAndMultipleValues) +{ + constexpr int padding = 10; + long value{1}; + long expectedValue{GetParam()}; + int anotherValue{1}; + int anotherExpectedValue{2}; + ASSERT_TRUE(WriteLong(stream, expectedValue, padding)); + ASSERT_TRUE(WriteInt(stream, anotherExpectedValue)); + ASSERT_TRUE(ReadLong(stream, value)); + ASSERT_TRUE(ReadInt(stream, anotherValue)); + ASSERT_EQ(expectedValue, value); + ASSERT_EQ(anotherExpectedValue, anotherValue); +} + +INSTANTIATE_TEST_SUITE_P( + CBotIoReadWriteTest, + CBotFileUtilsReadWriteLongTest, + testing::Values( + static_cast(7), + static_cast(-1), + static_cast(0), + static_cast(42), + std::numeric_limits::min(), + std::numeric_limits::min() / 2, + std::numeric_limits::max() / 2, + std::numeric_limits::max())); + +struct CBotFileUtilsReadWriteFloatTest : public CBotFileUtilsTest, public testing::WithParamInterface +{ +}; + +TEST_P(CBotFileUtilsReadWriteFloatTest, ReadFloatValueShouldMatchWrittenValue) +{ + float expectedValue{GetParam()}; + ASSERT_TRUE(WriteFloat(stream, expectedValue)); + float value{1.0f}; + ASSERT_TRUE(ReadFloat(stream, value)); + ASSERT_EQ(expectedValue, value); +} + +INSTANTIATE_TEST_SUITE_P( + CBotIoReadWriteTest, + CBotFileUtilsReadWriteFloatTest, + testing::Values( + 7.0f, + -1.0f, + 0.0f, + 42.0f, + 3.14f, + -2.73f, + std::numeric_limits::min(), + std::numeric_limits::min() / 2.0f, + std::numeric_limits::max() / 2.0f, + std::numeric_limits::max())); + +struct CBotFileUtilsReadWriteDoubleTest : public CBotFileUtilsTest, public testing::WithParamInterface +{ +}; + +TEST_P(CBotFileUtilsReadWriteDoubleTest, ReadDoubleValueShouldMatchWrittenValue) +{ + double expectedValue{GetParam()}; + ASSERT_TRUE(WriteDouble(stream, expectedValue)); + double value{1.0}; + ASSERT_TRUE(ReadDouble(stream, value)); + ASSERT_EQ(expectedValue, value); +} + +INSTANTIATE_TEST_SUITE_P( + CBotIoReadWriteTest, + CBotFileUtilsReadWriteDoubleTest, + testing::Values( + 7.0, + -1.0, + 0.0, + 42.0, + 3.14, + -2.73, + std::numeric_limits::min(), + std::numeric_limits::min() / 2.0, + std::numeric_limits::max() / 2.0, + std::numeric_limits::max())); + +struct CBotFileUtilsReadWriteStringTest : public CBotFileUtilsTest, public testing::WithParamInterface +{ +}; + +TEST_P(CBotFileUtilsReadWriteStringTest, ReadStringValueShouldMatchWrittenValue) +{ + std::string expectedValue{GetParam()}; + ASSERT_TRUE(WriteString(stream, expectedValue)); + std::string value{"test"}; + ASSERT_TRUE(ReadString(stream, value)); + ASSERT_EQ(expectedValue, value); +} + +INSTANTIATE_TEST_SUITE_P( + CBotIoReadWriteTest, + CBotFileUtilsReadWriteStringTest, + testing::Values( + "", + "123", + "abc", + createTestStringWithAllPossibleCharacters())); + +TEST_F(CBotFileUtilsTest, ReadStreamShouldMatchWrittenStream) +{ + std::string expectedValue{"Lorem ipsum dolor sit amet"}; + std::stringstream initialStream{expectedValue}; + ASSERT_TRUE(WriteStream(stream, initialStream)); + std::stringstream newStream{}; + ASSERT_TRUE(ReadStream(stream, newStream)); + ASSERT_EQ(expectedValue, newStream.str()); +} + +} diff --git a/test/unit/CBot/CBot_test.cpp b/test/unit/CBot/CBot_test.cpp index 3d1ee516..7da15f69 100644 --- a/test/unit/CBot/CBot_test.cpp +++ b/test/unit/CBot/CBot_test.cpp @@ -320,200 +320,6 @@ protected: } }; -TEST_F(CBotUT, TestSaveStateIOFunctions) -{ - std::stringstream sstr(""); - std::string teststring; - - for (char c = std::numeric_limits::min() ;; ++c) - { - teststring.push_back(c); - if ( c == std::numeric_limits::max() ) break; - } - - auto CallWriteFunctions = [&sstr, &teststring]() -> bool - { - if (!WriteWord(sstr, static_cast(0))) return false; - if (!WriteWord(sstr, std::numeric_limits::max() / 2)) return false; - if (!WriteWord(sstr, std::numeric_limits::max())) return false; - - if (!WriteByte(sstr, std::numeric_limits::min())) return false; - if (!WriteByte(sstr, std::numeric_limits::max())) return false; - - if (!WriteShort(sstr, std::numeric_limits::min())) return false; - if (!WriteShort(sstr, std::numeric_limits::min() / 2)) return false; - if (!WriteShort(sstr, -1)) return false; - if (!WriteShort(sstr, 0)) return false; - if (!WriteShort(sstr, std::numeric_limits::max() / 2)) return false; - if (!WriteShort(sstr, std::numeric_limits::max())) return false; - - if (!WriteUInt32(sstr, static_cast(0))) return false; - if (!WriteUInt32(sstr, std::numeric_limits::max() / 2)) return false; - if (!WriteUInt32(sstr, std::numeric_limits::max())) return false; - - if (!WriteInt(sstr, std::numeric_limits::min())) return false; - if (!WriteInt(sstr, std::numeric_limits::min() / 2)) return false; - if (!WriteInt(sstr, -1)) return false; - if (!WriteInt(sstr, 0)) return false; - if (!WriteInt(sstr, std::numeric_limits::max() / 2)) return false; - if (!WriteInt(sstr, std::numeric_limits::max())) return false; - - if (!WriteLong(sstr, std::numeric_limits::min())) return false; - if (!WriteLong(sstr, std::numeric_limits::min() / 2L)) return false; - if (!WriteLong(sstr, -1L)) return false; - if (!WriteLong(sstr, 0L)) return false; - if (!WriteLong(sstr, std::numeric_limits::max() / 2L)) return false; - if (!WriteLong(sstr, std::numeric_limits::max())) return false; - - // test with padding bytes (not currently used anywhere) - if (!WriteLong(sstr, 1234567890L, 10)) return false; - - if (!WriteFloat(sstr, std::numeric_limits::min())) return false; - if (!WriteFloat(sstr, 0.0f)) return false; - if (!WriteFloat(sstr, std::numeric_limits::max())) return false; - - if (!WriteDouble(sstr, std::numeric_limits::min())) return false; - if (!WriteDouble(sstr, 0.0)) return false; - if (!WriteDouble(sstr, std::numeric_limits::max())) return false; - - if (!WriteString(sstr, "")) return false; - if (!WriteString(sstr, teststring)) return false; - return true; - }; - - if ( !CallWriteFunctions() ) - { - ADD_FAILURE() << "failed in CallWriteFunctions()" << std::endl; - return; - } - - std::stringstream savestream(""); - - if ( !WriteStream(savestream, sstr) ) - { - ADD_FAILURE() << "CBot::WriteStream() failed" << std::endl; - return; - } - - std::stringstream newstream(""); - - if ( !ReadStream(savestream, newstream) ) - { - ADD_FAILURE() << "CBot:ReadStream() failed" << std::endl; - return; - } - - auto CallReadFunctions = [&teststring, &newstream]() -> bool - { - unsigned short w = 1; - if (!ReadWord(newstream, w)) return false; - if (w != static_cast(0)) return false; - if (!ReadWord(newstream, w)) return false; - if (w != std::numeric_limits::max() / 2) return false; - - if (!ReadWord(newstream, w)) return false; - if (w != std::numeric_limits::max()) return false; - - char c = 1; - if (!ReadByte(newstream, c)) return false; - if (c != std::numeric_limits::min()) return false; - if (!ReadByte(newstream, c)) return false; - if (c != std::numeric_limits::max()) return false; - - short s = 1; - if (!ReadShort(newstream, s)) return false; - if (s != std::numeric_limits::min()) return false; - if (!ReadShort(newstream, s)) return false; - if (s != std::numeric_limits::min() / 2) return false; - - if (!ReadShort(newstream, s)) return false; - if (s != -1) return false; - if (!ReadShort(newstream, s)) return false; - if (s != 0) return false; - - if (!ReadShort(newstream, s)) return false; - if (s != std::numeric_limits::max() / 2) return false; - if (!ReadShort(newstream, s)) return false; - if (s != std::numeric_limits::max()) return false; - - uint32_t u = 1; - if (!ReadUInt32(newstream, u)) return false; - if (u != static_cast(0)) return false; - if (!ReadUInt32(newstream, u)) return false; - if (u != std::numeric_limits::max() / 2) return false; - - if (!ReadUInt32(newstream, u)) return false; - if (u != std::numeric_limits::max()) return false; - - int i = 1; - if (!ReadInt(newstream, i)) return false; - if (i != std::numeric_limits::min()) return false; - if (!ReadInt(newstream, i)) return false; - if (i != std::numeric_limits::min() / 2) return false; - - if (!ReadInt(newstream, i)) return false; - if (i != -1) return false; - if (!ReadInt(newstream, i)) return false; - if (i != 0) return false; - - if (!ReadInt(newstream, i)) return false; - if (i != std::numeric_limits::max() / 2) return false; - if (!ReadInt(newstream, i)) return false; - if (i != std::numeric_limits::max()) return false; - - long l = 1L; - if (!ReadLong(newstream, l)) return false; - if (l != std::numeric_limits::min()) return false; - if (!ReadLong(newstream, l)) return false; - if (l != std::numeric_limits::min() / 2L) return false; - - if (!ReadLong(newstream, l)) return false; - if (l != -1L) return false; - if (!ReadLong(newstream, l)) return false; - if (l != 0L) return false; - - if (!ReadLong(newstream, l)) return false; - if (l != std::numeric_limits::max() / 2L) return false; - if (!ReadLong(newstream, l)) return false; - if (l != std::numeric_limits::max()) return false; - - if (!ReadLong(newstream, l)) return false; - if (l != 1234567890L) return false; - - float f = 1.0f; - if (!ReadFloat(newstream, f)) return false; - if (f != std::numeric_limits::min()) return false; - if (!ReadFloat(newstream, f)) return false; - if (f != 0.0f) return false; - - if (!ReadFloat(newstream, f)) return false; - if (f != std::numeric_limits::max()) return false; - - double d = 1.0; - if (!ReadDouble(newstream, d)) return false; - if (d != std::numeric_limits::min()) return false; - if (!ReadDouble(newstream, d)) return false; - if (d != 0.0) return false; - - if (!ReadDouble(newstream, d)) return false; - if (d != std::numeric_limits::max()) return false; - - std::string newstring = "should be empty string after next read"; - if (!ReadString(newstream, newstring)) return false; - if (newstring != "") return false; - - if (!ReadString(newstream, newstring)) return false; - if (newstring != teststring) return false; - return true; - }; - - if ( !CallReadFunctions() ) - { - ADD_FAILURE() << "failed in CallReadFunctions()" << std::endl; - return; - } -} - TEST_F(CBotUT, EmptyTest) { ExecuteTest( diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index b549229e..8eb7d7a5 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -11,8 +11,9 @@ add_definitions(-DGTEST_HAS_TR1_TUPLE=0) add_executable(colobot_ut main.cpp app/app_test.cpp - CBot/CBotToken_test.cpp CBot/CBot_test.cpp + CBot/CBotFileUtils_test.cpp + CBot/CBotToken_test.cpp common/config_file_test.cpp common/timeutils_test.cpp graphics/engine/lightman_test.cpp