//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" using bitsery::ext::BaseClass; using bitsery::ext::VirtualBaseClass; using bitsery::ext::InheritanceContext; using bitsery::ext::PointerLinkingContext; using bitsery::ext::PolymorphicContext; using bitsery::ext::StandardRTTI; using bitsery::ext::PointerType; using bitsery::ext::StdSmartPtr; using bitsery::ext::PointerObserver; using testing::Eq; using testing::Ne; struct Base { uint8_t x{}; virtual ~Base() = default; }; template void serialize(S& s, Base& o) { s.value1b(o.x); } struct Derived : virtual Base { uint8_t y{}; Derived() = default; Derived(uint8_t x_, uint8_t y_) { x = x_; y = y_; } }; template void serialize(S& s, Derived& o) { s.ext(o, VirtualBaseClass{}); s.value1b(o.y); } struct MoreDerived : Derived { int8_t z{}; MoreDerived() = default; MoreDerived(uint8_t x_, uint8_t y_, uint8_t z_) : Derived(x_, y_) { z = z_; } }; template void serialize(S& s, MoreDerived& o) { s.ext(o, BaseClass{}); s.value1b(o.z); } //define relationships between base class and derived classes for runtime polymorphism namespace bitsery { namespace ext { template<> struct PolymorphicBaseClass : PolymorphicDerivedClasses { }; template<> struct PolymorphicBaseClass : PolymorphicDerivedClasses { }; } } template class SerializeExtensionStdSmartPtrNonPolymorphicType : public testing::Test { public: template using TPtr = typename T::template TData; using TExt = typename T::TExt; using TContext = std::tuple; using SerContext = BasicSerializationContext; //this is useful for PolymorphicContext to bind classes to serializer/deserializer using TSerializer = typename SerContext::TSerializer; using TDeserializer = typename SerContext::TDeserializer; TContext plctx{}; SerContext sctx{}; typename SerContext::TSerializer& createSerializer() { return sctx.createSerializer(plctx); } typename SerContext::TDeserializer& createDeserializer() { return sctx.createDeserializer(plctx); } bool isPointerContextValid() { return std::get<0>(plctx).isValid(); } virtual void TearDown() override { EXPECT_TRUE(isPointerContextValid()); } }; template class SerializeExtensionStdSmartPtrPolymorphicType : public testing::Test { public: template using TPtr = typename T::template TData; using TExt = typename T::TExt; using TContext = std::tuple>; using SerContext = BasicSerializationContext; //this is useful for PolymorphicContext to bind classes to serializer/deserializer using TSerializer = typename SerContext::TSerializer; using TDeserializer = typename SerContext::TDeserializer; TContext plctx{}; SerContext sctx{}; typename SerContext::TSerializer& createSerializer() { auto& res = sctx.createSerializer(plctx); std::get<2>(plctx).clear(); //bind serializer with classes std::get<2>(plctx).template registerBasesList( bitsery::ext::PolymorphicClassesList{}); return res; } typename SerContext::TDeserializer& createDeserializer() { auto& res = sctx.createDeserializer(plctx); std::get<2>(plctx).clear(); //bind deserializer with classes std::get<2>(plctx).template registerBasesList( bitsery::ext::PolymorphicClassesList{}); return res; } bool isPointerContextValid() { return std::get<0>(plctx).isValid(); } virtual void TearDown() override { EXPECT_TRUE(isPointerContextValid()); } }; struct UniquePtrTest { template using TData = std::unique_ptr; using TExt = StdSmartPtr; }; struct SharedPtrTest { template using TData = std::shared_ptr; using TExt = StdSmartPtr; }; using TestingWithNonPolymorphicTypes = ::testing::Types< UniquePtrTest, SharedPtrTest>; TYPED_TEST_CASE(SerializeExtensionStdSmartPtrNonPolymorphicType, TestingWithNonPolymorphicTypes); using TestingWithPolymorphicTypes = ::testing::Types< UniquePtrTest, SharedPtrTest>; TYPED_TEST_CASE(SerializeExtensionStdSmartPtrPolymorphicType, TestingWithPolymorphicTypes); TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data0Result0) { using Ptr = typename TestFixture::template TPtr; using Ext = typename TestFixture::TExt; Ptr data{}; this->createSerializer().ext(data, Ext{}); Ptr res{}; this->createDeserializer().ext(res, Ext{}); EXPECT_THAT(data.get(), ::testing::IsNull()); EXPECT_THAT(res.get(), ::testing::IsNull()); } TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data0Result1) { using Ptr = typename TestFixture::template TPtr; using Ext = typename TestFixture::TExt; Ptr data{}; this->createSerializer().ext(data, Ext{}); Ptr res{new MyStruct1{}}; this->createDeserializer().ext(res, Ext{}); EXPECT_THAT(data.get(), ::testing::IsNull()); EXPECT_THAT(res.get(), ::testing::IsNull()); } TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data1Result0) { using Ptr = typename TestFixture::template TPtr; using Ext = typename TestFixture::TExt; Ptr data{new MyStruct1{3, 78}}; this->createSerializer().ext(data, Ext{}); Ptr res{}; this->createDeserializer().ext(res, Ext{}); EXPECT_THAT(data.get(), ::testing::NotNull()); EXPECT_THAT(res.get(), ::testing::NotNull()); EXPECT_THAT(res->i1, Eq(data->i1)); EXPECT_THAT(res->i2, Eq(data->i2)); } TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, Data1Result1) { using Ptr = typename TestFixture::template TPtr; using Ext = typename TestFixture::TExt; Ptr data{new MyStruct1{3, 78}}; this->createSerializer().ext(data, Ext{}); Ptr res{new MyStruct1{}}; this->createDeserializer().ext(res, Ext{}); EXPECT_THAT(data.get(), ::testing::NotNull()); EXPECT_THAT(res.get(), ::testing::NotNull()); EXPECT_THAT(res->i1, Eq(data->i1)); EXPECT_THAT(res->i2, Eq(data->i2)); } TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, CanUseLambdaOverload) { using Ptr = typename TestFixture::template TPtr; using Ext = typename TestFixture::TExt; Ptr data{new MyStruct1{3, 78}}; auto& ser = this->createSerializer(); ser.ext(data, Ext{}, [](decltype(ser)& ser, MyStruct1& o) { //serialize only one field ser.value4b(o.i1); }); Ptr res{new MyStruct1{97, 12}}; auto& des = this->createDeserializer(); des.ext(res, Ext{}, [](decltype(des)& des, MyStruct1& o) { des.value4b(o.i1); }); EXPECT_THAT(res->i1, Eq(data->i1)); EXPECT_THAT(res->i2, Ne(data->i2)); } TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, CanUseValueOverload) { using Ptr = typename TestFixture::template TPtr; using Ext = typename TestFixture::TExt; Ptr data{new uint16_t{3}}; this->createSerializer().ext2b(data, Ext{}); Ptr res{}; this->createDeserializer().ext2b(res, Ext{}); EXPECT_THAT(*res, Eq(*data)); } TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, FirstPtrThenPointerObserver) { using Ptr = typename TestFixture::template TPtr; using Ext = typename TestFixture::TExt; Ptr data{new uint16_t{3}}; uint16_t* dataObs = data.get(); auto& ser = this->createSerializer(); ser.ext2b(data, Ext{}); ser.ext2b(dataObs, PointerObserver{}); Ptr res{}; uint16_t* resObs = nullptr; auto& des = this->createDeserializer(); des.ext2b(res, Ext{}); des.ext2b(resObs, PointerObserver{}); EXPECT_THAT(resObs, Eq(res.get())); } TYPED_TEST(SerializeExtensionStdSmartPtrNonPolymorphicType, FirstPointerObserverThenPtr) { using Ptr = typename TestFixture::template TPtr; using Ext = typename TestFixture::TExt; Ptr data{new uint16_t{3}}; uint16_t* dataObs = data.get(); auto& ser = this->createSerializer(); ser.ext2b(dataObs, PointerObserver{}); ser.ext2b(data, Ext{}); Ptr res{}; uint16_t* resObs = nullptr; auto& des = this->createDeserializer(); des.ext2b(resObs, PointerObserver{}); des.ext2b(res, Ext{}); EXPECT_THAT(resObs, Eq(res.get())); } TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, Data0Result0) { using Ptr = typename TestFixture::template TPtr; using Ext = typename TestFixture::TExt; Ptr baseData{}; this->createSerializer().ext(baseData, Ext{}); Ptr baseRes{}; this->createDeserializer().ext(baseRes, Ext{}); EXPECT_THAT(baseRes.get(), ::testing::IsNull()); EXPECT_THAT(baseData.get(), ::testing::IsNull()); } TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, Data0Result1) { using Ptr = typename TestFixture::template TPtr; using Ext = typename TestFixture::TExt; Ptr baseData{}; this->createSerializer().ext(baseData, Ext{}); Ptr baseRes{new Derived{}}; this->createDeserializer().ext(baseRes, Ext{}); EXPECT_THAT(baseRes.get(), ::testing::IsNull()); EXPECT_THAT(baseData.get(), ::testing::IsNull()); } TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, Data1Result0) { using Ptr = typename TestFixture::template TPtr; using Ext = typename TestFixture::TExt; Ptr baseData{new Derived{3, 78}}; this->createSerializer().ext(baseData, Ext{}); Ptr baseRes{}; this->createDeserializer().ext(baseRes, Ext{}); auto* data = dynamic_cast(baseData.get()); auto* res = dynamic_cast(baseRes.get()); EXPECT_THAT(data, ::testing::NotNull()); EXPECT_THAT(res, ::testing::NotNull()); EXPECT_THAT(res->x, Eq(data->x)); EXPECT_THAT(res->y, Eq(data->y)); } TYPED_TEST(SerializeExtensionStdSmartPtrPolymorphicType, DataAndResultWithDifferentRuntimeTypes) { using Ptr = typename TestFixture::template TPtr; using Ext = typename TestFixture::TExt; Ptr baseData{new Derived{3, 78}}; this->createSerializer().ext(baseData, Ext{}); Ptr baseRes{new Base{}}; this->createDeserializer().ext(baseRes, Ext{}); auto* data = dynamic_cast(baseData.get()); auto* res = dynamic_cast(baseRes.get()); EXPECT_THAT(data, ::testing::NotNull()); EXPECT_THAT(res, ::testing::NotNull()); EXPECT_THAT(res->x, Eq(data->x)); EXPECT_THAT(res->y, Eq(data->y)); } class SerializeExtensionStdSmartSharedPtr : public testing::Test { public: using TContext = std::tuple>; using SerContext = BasicSerializationContext; //this is useful for PolymorphicContext to bind classes to serializer/deserializer using TSerializer = typename SerContext::TSerializer; using TDeserializer = typename SerContext::TDeserializer; TContext plctx{}; SerContext sctx{}; typename SerContext::TSerializer& createSerializer() { auto& res = sctx.createSerializer(plctx); std::get<2>(plctx).clear(); //bind serializer with classes std::get<2>(plctx).registerBasesList(bitsery::ext::PolymorphicClassesList{}); return res; } typename SerContext::TDeserializer& createDeserializer() { auto& res = sctx.createDeserializer(plctx); std::get<2>(plctx).clear(); //bind deserializer with classes std::get<2>(plctx).registerBasesList(bitsery::ext::PolymorphicClassesList{}); return res; } size_t getBufferSize() const { return sctx.getBufferSize(); } bool isPointerContextValid() { return std::get<0>(plctx).isValid(); } void clearSharedState() { return std::get<0>(plctx).clearSharedState(); } }; TEST_F(SerializeExtensionStdSmartSharedPtr, SameSharedObjectIsSerializedOnce) { std::shared_ptr baseData1{new Derived{3, 78}}; std::shared_ptr baseData2{baseData1}; auto& ser = createSerializer(); ser.ext(baseData1, StdSmartPtr{}); ser.ext(baseData1, StdSmartPtr{}); createDeserializer(); //1b linking context (for 1st time) //1b dynamic type info //2b Derived object //1b linking context (for 2nd time) EXPECT_THAT(getBufferSize(), Eq(5)); EXPECT_TRUE(isPointerContextValid()); } TEST_F(SerializeExtensionStdSmartSharedPtr, PointerLinkingContextCorrectlyClearSharedState) { std::shared_ptr baseData1{new Derived{3, 78}}; auto& ser = createSerializer(); ser.ext(baseData1, StdSmartPtr{}); std::shared_ptr baseRes1{}; auto& des = createDeserializer(); des.ext(baseRes1, StdSmartPtr{}); EXPECT_THAT(baseRes1.use_count(), Eq(2)); clearSharedState(); EXPECT_THAT(baseRes1.use_count(), Eq(1)); EXPECT_TRUE(isPointerContextValid()); } TEST_F(SerializeExtensionStdSmartSharedPtr, CorrectlyManagesSameSharedObject) { std::shared_ptr baseData1{new Derived{3, 78}}; std::shared_ptr baseData2{new Derived{55, 11}}; std::shared_ptr baseData21{baseData2}; auto& ser = createSerializer(); ser.ext(baseData1, StdSmartPtr{}); ser.ext(baseData2, StdSmartPtr{}); ser.ext(baseData21, StdSmartPtr{}); std::shared_ptr baseRes1{}; std::shared_ptr baseRes2{}; std::shared_ptr baseRes21{}; auto& des = createDeserializer(); des.ext(baseRes1, StdSmartPtr{}); des.ext(baseRes2, StdSmartPtr{}); des.ext(baseRes21, StdSmartPtr{}); auto* data = dynamic_cast(baseRes1.get()); EXPECT_THAT(data, ::testing::NotNull()); clearSharedState(); EXPECT_THAT(baseRes1.use_count(), Eq(1)); EXPECT_THAT(baseRes2.use_count(), Eq(2)); EXPECT_THAT(baseRes21.use_count(), Eq(2)); baseRes2.reset(); EXPECT_THAT(baseRes21.use_count(), Eq(1)); EXPECT_TRUE(isPointerContextValid()); } TEST_F(SerializeExtensionStdSmartSharedPtr, FirstSharedThenWeakPtr) { std::shared_ptr baseData1{new Derived{3, 78}}; std::weak_ptr baseData11{baseData1}; std::weak_ptr baseData12{baseData11}; auto& ser = createSerializer(); ser.ext(baseData1, StdSmartPtr{}); ser.ext(baseData11, StdSmartPtr{}); ser.ext(baseData12, StdSmartPtr{}); std::shared_ptr baseRes1{}; std::weak_ptr baseRes11{}; std::weak_ptr baseRes12{}; auto& des = createDeserializer(); des.ext(baseRes1, StdSmartPtr{}); des.ext(baseRes11, StdSmartPtr{}); des.ext(baseRes12, StdSmartPtr{}); auto* data = dynamic_cast(baseRes1.get()); EXPECT_THAT(data, ::testing::NotNull()); clearSharedState(); EXPECT_THAT(baseRes1.use_count(), Eq(1)); EXPECT_THAT(baseRes11.use_count(), Eq(1)); EXPECT_THAT(baseRes12.use_count(), Eq(1)); baseRes1.reset(); EXPECT_THAT(baseRes11.use_count(), Eq(0)); EXPECT_TRUE(isPointerContextValid()); } TEST_F(SerializeExtensionStdSmartSharedPtr, FirstWeakThenSharedPtr) { std::shared_ptr baseData1{new MyStruct1{3, 78}}; std::weak_ptr baseData11{baseData1}; std::weak_ptr baseData2{}; auto& ser = createSerializer(); ser.ext(baseData2, StdSmartPtr{}); ser.ext(baseData11, StdSmartPtr{}); ser.ext(baseData1, StdSmartPtr{}); std::shared_ptr baseRes1{}; std::weak_ptr baseRes11{}; std::weak_ptr baseRes2{}; auto& des = createDeserializer(); des.ext(baseRes2, StdSmartPtr{}); des.ext(baseRes11, StdSmartPtr{}); des.ext(baseRes1, StdSmartPtr{}); clearSharedState(); EXPECT_THAT(*baseData1, Eq(*baseRes1)); EXPECT_THAT(baseRes1.use_count(), Eq(1)); EXPECT_THAT(baseRes2.use_count(), Eq(0)); EXPECT_THAT(baseRes11.use_count(), Eq(1)); baseRes1.reset(); EXPECT_THAT(baseRes11.use_count(), Eq(0)); EXPECT_TRUE(isPointerContextValid()); } TEST_F(SerializeExtensionStdSmartSharedPtr, WeakPtrFirstPolymorphicData0Result1) { std::shared_ptr baseData1{}; std::weak_ptr baseData2{}; auto& ser = createSerializer(); ser.ext(baseData2, StdSmartPtr{}); ser.ext(baseData1, StdSmartPtr{}); std::shared_ptr baseRes1{new Base{}}; std::weak_ptr baseRes2{baseRes1}; auto& des = createDeserializer(); des.ext(baseRes2, StdSmartPtr{}); des.ext(baseRes1, StdSmartPtr{}); clearSharedState(); EXPECT_THAT(baseRes1.use_count(), Eq(0)); EXPECT_THAT(baseRes2.use_count(), Eq(0)); baseRes1.reset(); EXPECT_TRUE(isPointerContextValid()); } TEST_F(SerializeExtensionStdSmartSharedPtr, WeakPtrFirstNonPolymorphicData0Result1) { std::shared_ptr baseData1{}; std::weak_ptr baseData2{}; auto& ser = createSerializer(); ser.ext(baseData2, StdSmartPtr{}); ser.ext(baseData1, StdSmartPtr{}); std::shared_ptr baseRes1{new MyStruct2{MyStruct2::MyEnum::V4, {1, 87}}}; std::weak_ptr baseRes2{baseRes1}; auto& des = createDeserializer(); des.ext(baseRes2, StdSmartPtr{}); des.ext(baseRes1, StdSmartPtr{}); clearSharedState(); EXPECT_THAT(baseRes1.use_count(), Eq(0)); EXPECT_THAT(baseRes2.use_count(), Eq(0)); baseRes1.reset(); EXPECT_TRUE(isPointerContextValid()); } TEST_F(SerializeExtensionStdSmartSharedPtr, FewPtrsAreEmpty) { std::shared_ptr baseData1{new Derived{3, 78}}; std::shared_ptr baseData2{}; std::weak_ptr baseData3{}; std::weak_ptr baseData11{baseData1}; auto& ser = createSerializer(); ser.ext(baseData1, StdSmartPtr{}); ser.ext(baseData2, StdSmartPtr{}); ser.ext(baseData3, StdSmartPtr{}); ser.ext(baseData11, StdSmartPtr{}); std::shared_ptr baseRes1{}; std::shared_ptr baseRes2{new Derived{3, 78}}; std::weak_ptr baseRes3{baseRes2}; std::weak_ptr baseRes11{}; auto& des = createDeserializer(); des.ext(baseRes1, StdSmartPtr{}); des.ext(baseRes2, StdSmartPtr{}); des.ext(baseRes3, StdSmartPtr{}); des.ext(baseRes11, StdSmartPtr{}); clearSharedState(); EXPECT_THAT(baseRes1.use_count(), Eq(1)); EXPECT_THAT(baseRes2.use_count(), Eq(0)); EXPECT_THAT(baseRes3.use_count(), Eq(0)); EXPECT_THAT(baseRes11.use_count(), Eq(1)); baseRes1.reset(); EXPECT_THAT(baseRes11.use_count(), Eq(0)); EXPECT_TRUE(isPointerContextValid()); } TEST_F(SerializeExtensionStdSmartSharedPtr, WhenResultObjectExistsSameType) { std::shared_ptr baseData1{new Derived{3, 78}}; auto& ser = createSerializer(); ser.ext(baseData1, StdSmartPtr{}); std::shared_ptr baseRes1{new Derived{0, 0}}; auto& des = createDeserializer(); des.ext(baseRes1, StdSmartPtr{}); clearSharedState(); EXPECT_THAT(baseRes1.use_count(), Eq(1)); EXPECT_THAT(baseRes1->x, Eq(baseData1->x)); EXPECT_TRUE(isPointerContextValid()); } TEST_F(SerializeExtensionStdSmartSharedPtr, WhenResultObjectExistsDifferentType) { std::shared_ptr baseData1{new Derived{3, 78}}; auto& ser = createSerializer(); ser.ext(baseData1, StdSmartPtr{}); std::shared_ptr baseRes1{new Base{}}; auto& des = createDeserializer(); des.ext(baseRes1, StdSmartPtr{}); clearSharedState(); EXPECT_THAT(baseRes1.use_count(), Eq(1)); EXPECT_THAT(baseRes1->x, Eq(baseData1->x)); EXPECT_THAT(dynamic_cast(baseRes1.get()), ::testing::NotNull()); EXPECT_TRUE(isPointerContextValid()); } TEST_F(SerializeExtensionStdSmartSharedPtr, WhenOnlyWeakPtrIsSerializedThenPointerCointextIsInvalid) { std::shared_ptr tmp{new Derived{3, 78}}; std::weak_ptr baseData1{tmp}; auto& ser = createSerializer(); ser.ext(baseData1, StdSmartPtr{}); EXPECT_FALSE(isPointerContextValid()); } TEST_F(SerializeExtensionStdSmartSharedPtr, WhenOnlyWeakPtrIsDeserializedThenPointerCointextIsInvalid) { std::shared_ptr baseData1{new Derived{3, 78}}; auto& ser = createSerializer(); ser.ext(baseData1, StdSmartPtr{}); std::weak_ptr baseRes1{}; auto& des = createDeserializer(); des.ext(baseRes1, StdSmartPtr{}); EXPECT_FALSE(isPointerContextValid()); EXPECT_THAT(baseRes1.use_count(), Eq(1)); clearSharedState(); EXPECT_THAT(baseRes1.use_count(), Eq(0)); } struct TestSharedFromThis : public std::enable_shared_from_this { float x{}; explicit TestSharedFromThis() : std::enable_shared_from_this() {} template void serialize(S& s) { s.value4b(x); } }; TEST_F(SerializeExtensionStdSmartSharedPtr, EnableSharedFromThis) { std::shared_ptr dataPtr(new TestSharedFromThis{}); std::shared_ptr resPtr{}; createSerializer().ext(dataPtr, StdSmartPtr{}); createDeserializer().ext(resPtr, StdSmartPtr{}); clearSharedState(); auto resPtr2 = resPtr->shared_from_this(); EXPECT_THAT(resPtr->x, Eq(dataPtr->x)); EXPECT_THAT(resPtr2.use_count(), Eq(2)); } struct CustomDeleter { void operator()(Base* p) { delete p; } }; class SerializeExtensionStdSmartUniquePtr : public SerializeExtensionStdSmartSharedPtr { }; TEST_F(SerializeExtensionStdSmartUniquePtr, WithCustomDeleter) { std::unique_ptr dataPtr(new Derived{87, 7}); std::unique_ptr resPtr{}; createSerializer().ext(dataPtr, StdSmartPtr{}); createDeserializer().ext(resPtr, StdSmartPtr{}); clearSharedState(); EXPECT_THAT(resPtr->x, Eq(dataPtr->x)); EXPECT_THAT(dynamic_cast(resPtr.get()), ::testing::NotNull()); }