//MIT License // //Copyright (c) 2019 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 #include #include #include "serialization_test_utils.h" using testing::ContainerEq; using testing::Eq; //forward declare, for testing with std::unordered_map class HasherForNonDefaultConstructible; class NonDefaultConstructible { int32_t i{0}; friend class HasherForNonDefaultConstructible; friend class bitsery::Access; NonDefaultConstructible() = default; template void serialize(S& s) { s.value4b(i); } public: explicit NonDefaultConstructible(int32_t v):i{v} {} bool operator == (const NonDefaultConstructible& other) const { return i == other.i; } bool operator < (const NonDefaultConstructible& other) const { return i < other.i; } }; class HasherForNonDefaultConstructible { public: size_t operator()(const NonDefaultConstructible& o) const { return std::hash()(o.i); } }; TEST(DeserializeNonDefaultConstructible, Container) { SerializationContext ctx{}; std::vector data{}; data.emplace_back(1); data.emplace_back(2); data.emplace_back(3); std::vector res{}; ctx.createSerializer().container(data, 10); ctx.createDeserializer().container(res, 10); EXPECT_THAT(res, ContainerEq(data)); } //this test is here, because when object is not constructible we cannot simple "resize" container TEST(DeserializeNonDefaultConstructible, ResultContainerShouldShrink) { SerializationContext ctx{}; std::vector data{}; data.emplace_back(1); std::vector res{}; res.emplace_back(2); res.emplace_back(3); res.emplace_back(4); ctx.createSerializer().container(data, 10); ctx.createDeserializer().container(res, 10); EXPECT_THAT(res, ContainerEq(data)); } TEST(DeserializeNonDefaultConstructible, ResultStdForwardListShouldShrink) { // forward list doesn't have .erase function, bet has erase_after // in this case, if new size is 0 it must call clear, so we need to check two cases { // 1) when result should have more than 0 elements SerializationContext ctx{}; std::forward_list data{}; data.push_front(NonDefaultConstructible{1}); std::forward_list res{}; res.push_front(NonDefaultConstructible{21}); res.push_front(NonDefaultConstructible{14}); ctx.createSerializer().container(data, 10); ctx.createDeserializer().container(res, 10); auto resIt = res.begin(); for (auto it = data.begin(); it != data.end(); ++it, ++resIt) { EXPECT_THAT(*resIt, Eq(*it)); } EXPECT_THAT(resIt, Eq(res.end())); } { // 1) when result should have 0 elements SerializationContext ctx{}; std::forward_list data{}; std::forward_list res{}; res.push_front(NonDefaultConstructible{1}); res.push_front(NonDefaultConstructible{14}); ctx.createSerializer().container(data, 10); ctx.createDeserializer().container(res, 10); EXPECT_THAT(res.begin(), Eq(res.end())); } { // also check if correctly expands if source is bigger than destination SerializationContext ctx{}; std::forward_list data{}; data.push_front(NonDefaultConstructible{1}); data.push_front(NonDefaultConstructible{14}); std::forward_list res{}; ctx.createSerializer().container(data, 10); ctx.createDeserializer().container(res, 10); auto resIt = res.begin(); for (auto it = data.begin(); it != data.end(); ++it, ++resIt) { EXPECT_THAT(*resIt, Eq(*it)); } EXPECT_THAT(resIt, Eq(res.end())); } } TEST(DeserializeNonDefaultConstructible, StdSet) { SerializationContext ctx{}; std::set data; data.insert(NonDefaultConstructible{1}); data.insert(NonDefaultConstructible{2}); std::set res{}; data.insert(NonDefaultConstructible{3}); ctx.createSerializer().ext(data, bitsery::ext::StdSet{10}); ctx.createDeserializer().ext(res, bitsery::ext::StdSet{10}); EXPECT_THAT(res, ContainerEq(data)); } TEST(DeserializeNonDefaultConstructible, StdMap) { SerializationContext ctx{}; std::unordered_map data; data.emplace(NonDefaultConstructible{2}, NonDefaultConstructible{3}); std::unordered_map res{}; data.emplace(NonDefaultConstructible{2}, NonDefaultConstructible{3}); data.emplace(NonDefaultConstructible{4}, NonDefaultConstructible{4}); auto& ser = ctx.createSerializer(); ser.ext(data, bitsery::ext::StdMap{10},[](decltype(ser)& ser, NonDefaultConstructible& key, NonDefaultConstructible& value) { ser.object(key); ser.object(value); }); auto& des = ctx.createDeserializer(); des.ext(res, bitsery::ext::StdMap{10},[](decltype(des)& des, NonDefaultConstructible& key, NonDefaultConstructible& value) { des.object(key); des.object(value); }); EXPECT_THAT(res, ContainerEq(data)); } struct NonPolymorphicPointers { NonDefaultConstructible* pp; std::unique_ptr up; std::shared_ptr sp; std::weak_ptr wp; }; template void serialize(S& s, NonPolymorphicPointers& o) { s.ext(o.pp, bitsery::ext::PointerOwner{}); s.ext(o.up, bitsery::ext::StdSmartPtr{}); s.ext(o.sp, bitsery::ext::StdSmartPtr{}); s.ext(o.wp, bitsery::ext::StdSmartPtr{}); } TEST(DeserializeNonDefaultConstructible, NonPolymorphicPointerAndSmartPointer) { using SerContext = BasicSerializationContext; SerContext ctx{}; NonPolymorphicPointers data{}; data.pp = new NonDefaultConstructible{3}; data.up = std::unique_ptr(new NonDefaultConstructible{54}); data.sp = std::shared_ptr(new NonDefaultConstructible{-481}); data.wp = data.sp; NonPolymorphicPointers res{}; bitsery::ext::PointerLinkingContext plctx1{}; ctx.createSerializer(plctx1).object(data); ctx.createDeserializer(plctx1).object(res); EXPECT_THAT(*res.pp, Eq(*data.pp)); delete res.pp; delete data.pp; EXPECT_THAT(*res.up, Eq(*data.up)); EXPECT_THAT(*res.sp, Eq(*data.sp)); EXPECT_THAT(*(res.wp.lock()), Eq(*(data.wp.lock()))); } class PolymorphicNDCBase { public: virtual ~PolymorphicNDCBase() = 0; template void serialize(S& ) {} }; PolymorphicNDCBase::~PolymorphicNDCBase() = default; class PolymorphicNDC1:public PolymorphicNDCBase { int8_t i{}; friend class bitsery::Access; template void serialize(S& s) { s.value1b(i); } public: PolymorphicNDC1() = default; PolymorphicNDC1(int8_t v):i{v} {} bool operator == (const PolymorphicNDC1& other) const { return i == other.i; } }; class PolymorphicNDC2:public PolymorphicNDCBase { uint16_t ui{}; friend class bitsery::Access; template void serialize(S& s) { s.value2b(ui); } public: PolymorphicNDC2() = default; PolymorphicNDC2(uint16_t v):ui{v} {} bool operator == (const PolymorphicNDC2& other) const { return ui == other.ui; } }; namespace bitsery { namespace ext { template<> struct PolymorphicBaseClass : PolymorphicDerivedClasses { }; } } struct PolymorphicPointers { PolymorphicNDCBase* pp; std::unique_ptr up; std::shared_ptr sp; std::weak_ptr wp; }; template void serialize(S& s, PolymorphicPointers& o) { s.ext(o.pp, bitsery::ext::PointerOwner{}); s.ext(o.up, bitsery::ext::StdSmartPtr{}); s.ext(o.sp, bitsery::ext::StdSmartPtr{}); s.ext(o.wp, bitsery::ext::StdSmartPtr{}); } TEST(DeserializeNonDefaultConstructible, PolymorphicPointerAndSmartPointer) { using TContext = std::tuple>; using SerContext = BasicSerializationContext; SerContext ctx{}; PolymorphicPointers data{}; data.pp = new PolymorphicNDC1{-4}; data.up = std::unique_ptr(new PolymorphicNDC2{54}); data.sp = std::shared_ptr(new PolymorphicNDC1{15}); data.wp = data.sp; PolymorphicPointers res{}; TContext serCtx{}; TContext desCtx{}; std::get<1>(serCtx).registerBasesList(bitsery::ext::PolymorphicClassesList{}); std::get<1>(desCtx).registerBasesList(bitsery::ext::PolymorphicClassesList{}); ctx.createSerializer(serCtx).object(data); ctx.createDeserializer(desCtx).object(res); auto respp = dynamic_cast(res.pp); auto resup = dynamic_cast(res.up.get()); auto ressp = dynamic_cast(res.sp.get()); auto reswp = dynamic_cast(res.wp.lock().get()); auto datapp = dynamic_cast(data.pp); auto dataup = dynamic_cast(data.up.get()); auto datasp = dynamic_cast(data.sp.get()); auto datawp = dynamic_cast(data.wp.lock().get()); EXPECT_THAT(respp, ::testing::Ne(nullptr)); EXPECT_THAT(resup, ::testing::Ne(nullptr)); EXPECT_THAT(ressp, ::testing::Ne(nullptr)); EXPECT_THAT(reswp, ::testing::Ne(nullptr)); EXPECT_THAT(*respp, Eq(*datapp)); delete res.pp; delete data.pp; EXPECT_THAT(*resup, Eq(*dataup)); EXPECT_THAT(*ressp, Eq(*datasp)); EXPECT_THAT(*reswp, Eq(*datawp)); std::get<0>(serCtx).clearSharedState(); std::get<0>(desCtx).clearSharedState(); }