#include <library/cpp/binsaver/util_stream_io.h> #include <library/cpp/binsaver/mem_io.h> #include <library/cpp/binsaver/bin_saver.h> #include <library/cpp/binsaver/ut_util/ut_util.h> #include <library/cpp/testing/unittest/registar.h> #include <util/stream/buffer.h> #include <util/generic/map.h> struct TBinarySerializable { ui32 Data = 0; }; struct TNonBinarySerializable { ui32 Data = 0; TString StrData; }; struct TCustomSerializer { ui32 Data = 0; TString StrData; SAVELOAD(StrData, Data); }; struct TCustomOuterSerializer { ui32 Data = 0; TString StrData; }; void operator&(TCustomOuterSerializer& s, IBinSaver& f); struct TCustomOuterSerializerTmpl { ui32 Data = 0; TString StrData; }; struct TCustomOuterSerializerTmplDerived: public TCustomOuterSerializerTmpl { ui32 Data = 0; TString StrData; }; struct TMoveOnlyType { ui32 Data = 0; TMoveOnlyType() = default; TMoveOnlyType(TMoveOnlyType&&) = default; bool operator==(const TMoveOnlyType& obj) const { return Data == obj.Data; } }; struct TTypeWithArray { ui32 Data = 1; TString Array[2][2]{{"test", "data"}, {"and", "more"}}; SAVELOAD(Data, Array); bool operator==(const TTypeWithArray& obj) const { return Data == obj.Data && std::equal(std::begin(Array[0]), std::end(Array[0]), obj.Array[0]) && std::equal(std::begin(Array[1]), std::end(Array[1]), obj.Array[1]); } }; template <typename T, typename = std::enable_if_t<std::is_base_of<TCustomOuterSerializerTmpl, T>::value>> int operator&(T& s, IBinSaver& f); static bool operator==(const TBlob& l, const TBlob& r) { return TStringBuf(l.AsCharPtr(), l.Size()) == TStringBuf(r.AsCharPtr(), r.Size()); } Y_UNIT_TEST_SUITE(BinSaver){ Y_UNIT_TEST(HasTrivialSerializer){ UNIT_ASSERT(!IBinSaver::HasNonTrivialSerializer<TBinarySerializable>(0u)); UNIT_ASSERT(!IBinSaver::HasNonTrivialSerializer<TNonBinarySerializable>(0u)); UNIT_ASSERT(IBinSaver::HasNonTrivialSerializer<TCustomSerializer>(0u)); UNIT_ASSERT(IBinSaver::HasNonTrivialSerializer<TCustomOuterSerializer>(0u)); UNIT_ASSERT(IBinSaver::HasNonTrivialSerializer<TCustomOuterSerializerTmpl>(0u)); UNIT_ASSERT(IBinSaver::HasNonTrivialSerializer<TCustomOuterSerializerTmplDerived>(0u)); UNIT_ASSERT(IBinSaver::HasNonTrivialSerializer<TVector<TCustomSerializer>>(0u)); } Y_UNIT_TEST(TestStroka) { TestBinSaverSerialization(TString("QWERTY")); } Y_UNIT_TEST(TestMoveOnlyType) { TestBinSaverSerializationToBuffer(TMoveOnlyType()); } Y_UNIT_TEST(TestVectorStrok) { TestBinSaverSerialization(TVector<TString>{"A", "B", "C"}); } Y_UNIT_TEST(TestCArray) { TestBinSaverSerialization(TTypeWithArray()); } Y_UNIT_TEST(TestSets) { TestBinSaverSerialization(THashSet<TString>{"A", "B", "C"}); TestBinSaverSerialization(TSet<TString>{"A", "B", "C"}); } Y_UNIT_TEST(TestMaps) { TestBinSaverSerialization(THashMap<TString, ui32>{{"A", 1}, {"B", 2}, {"C", 3}}); TestBinSaverSerialization(TMap<TString, ui32>{{"A", 1}, {"B", 2}, {"C", 3}}); } Y_UNIT_TEST(TestBlob) { TestBinSaverSerialization(TBlob::FromStringSingleThreaded("qwerty")); } Y_UNIT_TEST(TestVariant) { { using T = std::variant<TString, int>; TestBinSaverSerialization(T(TString(""))); TestBinSaverSerialization(T(0)); } { using T = std::variant<TString, int, float>; TestBinSaverSerialization(T(TString("ask"))); TestBinSaverSerialization(T(12)); TestBinSaverSerialization(T(0.64f)); } } Y_UNIT_TEST(TestPod) { struct TPod { ui32 A = 5; ui64 B = 7; bool operator==(const TPod& other) const { return A == other.A && B == other.B; } }; TestBinSaverSerialization(TPod()); TPod custom; custom.A = 25; custom.B = 37; TestBinSaverSerialization(custom); TestBinSaverSerialization(TVector<TPod>{custom}); } Y_UNIT_TEST(TestSubPod) { struct TPod { struct TSub { ui32 X = 10; bool operator==(const TSub& other) const { return X == other.X; } }; TVector<TSub> B; int operator&(IBinSaver& f) { f.Add(0, &B); return 0; } bool operator==(const TPod& other) const { return B == other.B; } }; TestBinSaverSerialization(TPod()); TPod::TSub sub; sub.X = 1; TPod custom; custom.B = {sub}; TestBinSaverSerialization(TVector<TPod>{custom}); } Y_UNIT_TEST(TestMemberAndOpIsMain) { struct TBase { TString S; virtual int operator&(IBinSaver& f) { f.Add(0, &S); return 0; } virtual ~TBase() = default; }; struct TDerived: public TBase { int A = 0; int operator&(IBinSaver& f)override { f.Add(0, static_cast<TBase*>(this)); f.Add(0, &A); return 0; } bool operator==(const TDerived& other) const { return A == other.A && S == other.S; } }; TDerived obj; obj.S = "TString"; obj.A = 42; TestBinSaverSerialization(obj); } }