// 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 #include #include "serialization_test_utils.h" #include using testing::ContainerEq; using testing::Eq; /* * overload to get container of types */ template Container getFilledContainer() { return { 1, 2, 3, 4, 5, 78, 456, 8, 54 }; } template<> std::vector getFilledContainer>() { return { { 0, 1 }, { 2, 3 }, { 4, 5 }, { 6, 7 }, { 8, 9 }, { 11, 34 }, { 5134, 1532 } }; } template<> std::list getFilledContainer>() { return { { MyStruct2::V1, { 0, 1 } }, { MyStruct2::V3, { -45, 45 } } }; } struct EmptyFtor { template void operator()(S&, T&) { } }; /* * start testing session */ template class SerializeContainerDynamicSizeArthmeticTypes : public testing::Test { public: using TContainer = T; using TValue = typename T::value_type; const TContainer src = getFilledContainer(); TContainer res{}; size_t getExpectedBufSize(const SerializationContext& ctx) const { auto size = bitsery::traits::ContainerTraits::size(src); return ctx.containerSizeSerializedBytesCount(size) + size * sizeof(TValue); } }; // std::forward_list is not supported, because it doesn't have size() method using SequenceContainersWithArthmeticTypes = ::testing::Types, std::list, std::forward_list, std::deque>; TYPED_TEST_SUITE(SerializeContainerDynamicSizeArthmeticTypes, SequenceContainersWithArthmeticTypes, ); TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, Values) { SerializationContext ctx{}; using TValue = typename TestFixture::TValue; ctx.createSerializer().container(this->src, 1000); ctx.createDeserializer().container(this->res, 1000); EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx))); EXPECT_THAT(this->res, ContainerEq(this->src)); } TYPED_TEST(SerializeContainerDynamicSizeArthmeticTypes, CustomFunctionIncrements) { SerializationContext ctx{}; using TValue = typename TestFixture::TValue; auto& ser = ctx.createSerializer(); ser.container(this->src, 1000, [](decltype(ser)& ser, TValue& v) { ser.template value(v); }); auto& des = ctx.createDeserializer(); des.container(this->res, 1000, [](decltype(des)& des, TValue& v) { des.template value(v); // increment by 1 after reading v++; }); // decrement result by 1, before comparing for eq for (auto& v : this->res) v = static_cast(v - 1); EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx))); EXPECT_THAT(this->res, ContainerEq(this->src)); } template class SerializeContainerDynamicSizeCompositeTypes : public testing::Test { public: using TContainer = T; using TValue = typename T::value_type; const TContainer src = getFilledContainer(); TContainer res{}; size_t getExpectedBufSize(const SerializationContext& ctx) const { return ctx.containerSizeSerializedBytesCount(src.size()) + src.size() * TValue::SIZE; } }; using SerializeContainerDynamicSizeWithCompositeTypes = ::testing::Types, std::list>; TYPED_TEST_SUITE(SerializeContainerDynamicSizeCompositeTypes, SerializeContainerDynamicSizeWithCompositeTypes, ); TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes, DefaultSerializeFunction) { SerializationContext ctx{}; ctx.createSerializer().container(this->src, 1000); ctx.createDeserializer().container(this->res, 1000); EXPECT_THAT(ctx.getBufferSize(), Eq(this->getExpectedBufSize(ctx))); EXPECT_THAT(this->res, ContainerEq(this->src)); } TYPED_TEST(SerializeContainerDynamicSizeCompositeTypes, CustomFunctionThatDoNothing) { SerializationContext ctx{}; ctx.createSerializer().container(this->src, 1000, EmptyFtor{}); ctx.createDeserializer().container(this->res, 1000, EmptyFtor{}); EXPECT_THAT(ctx.getBufferSize(), Eq(ctx.containerSizeSerializedBytesCount(this->src.size()))); } template class SerializeContainerFixedSizeArithmeticTypes : public testing::Test { public: using TContainer = T; size_t getContainerSize() { T tmp{}; return static_cast(std::distance(std::begin(tmp), std::end(tmp))); } }; using StaticContainersWithIntegralTypes = ::testing::Types, int16_t[4]>; TYPED_TEST_SUITE(SerializeContainerFixedSizeArithmeticTypes, StaticContainersWithIntegralTypes, ); TYPED_TEST(SerializeContainerFixedSizeArithmeticTypes, ArithmeticValues) { using Container = typename TestFixture::TContainer; Container src{ 5, 9, 15, -459 }; Container res{}; SerializationContext ctx; ctx.createSerializer().container<2>(src); ctx.createDeserializer().container<2>(res); EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * 2)); EXPECT_THAT(res, ContainerEq(src)); } template class SerializeContainerFixedSizeCompositeTypes : public SerializeContainerFixedSizeArithmeticTypes {}; using StaticContainersWithCompositeTypes = ::testing::Types, MyStruct1[4]>; TYPED_TEST_SUITE(SerializeContainerFixedSizeCompositeTypes, StaticContainersWithCompositeTypes, ); TYPED_TEST(SerializeContainerFixedSizeCompositeTypes, DefaultSerializationFunction) { using Container = typename TestFixture::TContainer; Container src{ MyStruct1{ 0, 1 }, MyStruct1{ 8, 9 }, MyStruct1{ 11, 34 }, MyStruct1{ 5134, 1532 } }; Container res{}; SerializationContext ctx{}; ctx.createSerializer().container(src); ctx.createDeserializer().container(res); EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * MyStruct1::SIZE)); EXPECT_THAT(res, ContainerEq(src)); } TYPED_TEST(SerializeContainerFixedSizeCompositeTypes, CustomFunctionThatSerializesAnEmptyByteEveryElement) { using Container = typename TestFixture::TContainer; Container src{ MyStruct1{ 0, 1 }, MyStruct1{ 2, 3 }, MyStruct1{ 4, 5 }, MyStruct1{ 5134, 1532 } }; Container res{}; using TValue = decltype(*std::begin(res)); SerializationContext ctx{}; auto& ser = ctx.createSerializer(); ser.container(src, [](decltype(ser)& ser, TValue& v) { char tmp{}; ser.object(v); ser.value1b(tmp); }); auto& des = ctx.createDeserializer(); des.container(res, [](decltype(des)& des, TValue& v) { char tmp{}; des.object(v); des.value1b(tmp); }); EXPECT_THAT(ctx.getBufferSize(), Eq(this->getContainerSize() * (MyStruct1::SIZE + sizeof(char)))); EXPECT_THAT(res, ContainerEq(src)); } class SerializeContainer : public ::testing::TestWithParam {}; TEST_P(SerializeContainer, SizeHasVariableLength) { SerializationContext ctx{}; std::vector src(GetParam()); std::vector res{}; ctx.createSerializer().container( src, std::numeric_limits::max(), EmptyFtor{}); ctx.createDeserializer().container( res, std::numeric_limits::max(), EmptyFtor{}); EXPECT_THAT(res.size(), Eq(src.size())); EXPECT_THAT(ctx.getBufferSize(), Eq(ctx.containerSizeSerializedBytesCount(src.size()))); } INSTANTIATE_TEST_SUITE_P(LargeContainerSize, SerializeContainer, ::testing::Values(0x01, 0x80, 0x4000));