//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 #include #include "serialization_test_utils.h" #include #include #include #include using testing::Eq; using bitsery::ext::CompactValue; using bitsery::ext::CompactValueAsObject; using bitsery::EndiannessType; // helper function, that gets value filled with specified number of bits template TValue getValue(bool isPositive, size_t significantBits) { TValue v = isPositive ? 0 : -1; if (significantBits == 0) return v; using TUnsigned = typename std::make_unsigned::type; TUnsigned mask = {}; mask = ~mask; // invert shiftByBits auto shiftBy = bitsery::details::BitsSize::value - significantBits; mask >>= shiftBy; //cast to unsigned when applying mask return (TUnsigned)v ^ mask; } // helper function, that serialize and return deserialized value template std::pair serializeAndGetDeserialized(TValue data) { TSerContext ctx; TValue res{}; ctx.createSerializer().template ext(data, CompactValue{}); ctx.createDeserializer().template ext(res, CompactValue{}); return {res, ctx.getBufferSize()}; } struct LittleEndianConfig: public bitsery::DefaultConfig { static constexpr EndiannessType NetworkEndianness = EndiannessType::LittleEndian; }; struct BigEndianConfig: public bitsery::DefaultConfig { static constexpr EndiannessType NetworkEndianness = EndiannessType::BigEndian; }; 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, TC >; TYPED_TEST_CASE(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_CASE(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{}; auto& ser = ctx.createSerializer(); ser.ext(data, CompactValueAsObject{}); auto& des = ctx.createDeserializer(); des.ext(res, CompactValueAsObject{}); auto& rd = bitsery::AdapterAccess::getReader(des); EXPECT_THAT(data, ::testing::Ne(res)); EXPECT_THAT(rd.error(), Eq(bitsery::ReaderError::DataOverflow)); }