// MIT License // // Copyright (c) 2017 Mindaugas Vinkelis // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. #include "serialization_test_utils.h" #include #include #include #include #include using bitsery::EndiannessType; using bitsery::ext::CompactValue; using bitsery::ext::CompactValueAsObject; using testing::Eq; // helper function, that gets value filled with specified number of bits template TValue getValue(bool isPositive, size_t significantBits) { TValue v = isPositive ? 0 : static_cast(-1); if (significantBits == 0) return v; using TUnsigned = typename std::make_unsigned::type; TUnsigned mask = {}; mask = static_cast(~mask); // invert shiftByBits auto shiftBy = bitsery::details::BitsSize::value - significantBits; mask = static_cast(mask >> shiftBy); // cast to unsigned when applying mask return v ^ static_cast(mask); } // helper function, that serialize and return deserialized value template std::pair serializeAndGetDeserialized(TValue data) { Buffer buf{}; bitsery::Serializer> ser{ buf }; ser.template ext(data, CompactValue{}); bitsery::Deserializer> des{ buf.begin(), ser.adapter().writtenBytesCount() }; TValue res; des.template ext(res, CompactValue{}); return { res, ser.adapter().writtenBytesCount() }; } struct LittleEndianConfig { static constexpr EndiannessType Endianness = EndiannessType::LittleEndian; static constexpr bool CheckDataErrors = true; static constexpr bool CheckAdapterErrors = true; }; struct BigEndianConfig { static constexpr EndiannessType Endianness = EndiannessType::BigEndian; static constexpr bool CheckDataErrors = true; static constexpr bool CheckAdapterErrors = true; }; template struct TC { static_assert(isPositiveNr || std::is_signed::value, ""); using Value = TValue; using Config = TConfig; bool isPositive = isPositiveNr; }; template class SerializeExtensionCompactValueCorrectness : public testing::Test { public: using TestCase = T; }; using AllValueSizesTestCases = ::testing::Types, TC, TC, TC, TC, TC, TC, TC, TC, TC, TC, TC, TC, TC, TC, TC, TC, TC, TC, TC, TC, TC, TC, TC>; TYPED_TEST_SUITE(SerializeExtensionCompactValueCorrectness, AllValueSizesTestCases, ); TYPED_TEST(SerializeExtensionCompactValueCorrectness, TestDifferentSizeValues) { using TCase = typename TestFixture::TestCase; using TValue = typename TCase::Value; TCase tc{}; for (auto i = 0u; i < bitsery::details::BitsSize::value + 1; ++i) { auto data = getValue(tc.isPositive, i); auto res = serializeAndGetDeserialized(data); EXPECT_THAT(res.first, Eq(data)); } } // this stucture will contain test data and result, as type paramters template struct SizeTC { static_assert(isPositiveNr || std::is_signed::value, ""); static_assert(bitsery::details::BitsSize::value >= significantBits, ""); using Value = TValue; bool isPositive = isPositiveNr; size_t fillBits = significantBits; size_t bytesCount = resultBytes; }; template class SerializeExtensionCompactValueRequiredBytes : public testing::Test { public: using TestCase = T; }; using RequiredBytesTestCases = ::testing::Types< // 1 byte always writes to 1 byte SizeTC, SizeTC, SizeTC, SizeTC, // 2 byte, +1 byte after 15 significant bits SizeTC, SizeTC, SizeTC, SizeTC, // 2 byte, +1 byte after 15-1 significant bits (1 bit for sign) SizeTC, SizeTC, SizeTC, SizeTC, // 4 byte, +1 byte after 29 significant bits SizeTC, SizeTC, SizeTC, SizeTC, SizeTC, // 4 byte SizeTC, SizeTC, SizeTC, SizeTC, SizeTC, // 8 byte, +1 byte after 57 significant bits, or +2 byte when all bits are // significant SizeTC, SizeTC, SizeTC, SizeTC, SizeTC, SizeTC, SizeTC, SizeTC, // 8 byte, SizeTC, SizeTC, SizeTC, SizeTC, SizeTC, SizeTC, SizeTC, SizeTC>; TYPED_TEST_SUITE(SerializeExtensionCompactValueRequiredBytes, RequiredBytesTestCases, ); TYPED_TEST(SerializeExtensionCompactValueRequiredBytes, Test) { using TCase = typename TestFixture::TestCase; using TValue = typename TCase::Value; TCase tc{}; TValue data = getValue(tc.isPositive, tc.fillBits); auto res = serializeAndGetDeserialized(data); EXPECT_THAT(res.first, Eq(data)); EXPECT_THAT(res.second, tc.bytesCount); } enum b1En : uint8_t { A, B, C, D = 54, E }; enum class b8En : int64_t { A = -874987489, B, C = 0, D, E = 489748978, F, G }; TEST(SerializeExtensionCompactValueEnum, TestEnums) { auto d1 = b1En::E; auto d2 = b8En::B; auto d3 = b8En::F; EXPECT_THAT(serializeAndGetDeserialized(d1).first, Eq(d1)); EXPECT_THAT(serializeAndGetDeserialized(d2).first, Eq(d2)); EXPECT_THAT(serializeAndGetDeserialized(d3).first, Eq(d3)); } TEST(SerializeExtensionCompactValueAsObjectDeserializeOverflow, TestEnums) { SerializationContext ctx; auto data = getValue(true, 17); uint16_t res{}; ctx.createSerializer().ext(data, CompactValueAsObject{}); ctx.createDeserializer().ext(res, CompactValueAsObject{}); EXPECT_THAT(data, ::testing::Ne(res)); EXPECT_THAT(ctx.des->adapter().error(), Eq(bitsery::ReaderError::InvalidData)); }