aboutsummaryrefslogtreecommitdiffstats
path: root/util/ysaveload_ut.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/ysaveload_ut.cpp
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/ysaveload_ut.cpp')
-rw-r--r--util/ysaveload_ut.cpp487
1 files changed, 487 insertions, 0 deletions
diff --git a/util/ysaveload_ut.cpp b/util/ysaveload_ut.cpp
new file mode 100644
index 0000000000..723c68f391
--- /dev/null
+++ b/util/ysaveload_ut.cpp
@@ -0,0 +1,487 @@
+#include "ysaveload.h"
+
+#include <library/cpp/testing/unittest/registar.h>
+
+#include <util/memory/pool.h>
+#include <util/stream/buffer.h>
+#include <util/memory/blob.h>
+#include <util/generic/list.h>
+#include <util/generic/map.h>
+#include <util/generic/set.h>
+#include <util/generic/hash.h>
+#include <util/generic/deque.h>
+#include <util/generic/string.h>
+#include <util/generic/vector.h>
+#include <util/generic/buffer.h>
+#include <util/generic/hash_set.h>
+#include <util/generic/maybe.h>
+#include <util/generic/variant.h>
+
+static inline char* AllocateFromPool(TMemoryPool& pool, size_t len) {
+ return (char*)pool.Allocate(len);
+}
+
+class TSaveLoadTest: public TTestBase {
+ UNIT_TEST_SUITE(TSaveLoadTest);
+ UNIT_TEST(TestSaveLoad)
+ UNIT_TEST(TestNewStyle)
+ UNIT_TEST(TestNewNewStyle)
+ UNIT_TEST(TestList)
+ UNIT_TEST(TestTuple)
+ UNIT_TEST(TestVariant)
+ UNIT_TEST(TestInheritNonVirtualClass)
+ UNIT_TEST(TestInheritVirtualClass)
+ UNIT_TEST_SUITE_END();
+
+ struct TSaveHelper {
+ inline void Save(IOutputStream* o) const {
+ o->Write("qwerty", 7);
+ }
+
+ inline void Load(IInputStream* i) {
+ char buf[7];
+
+ UNIT_ASSERT_EQUAL(i->Load(buf, 7), 7);
+ UNIT_ASSERT_EQUAL(strcmp(buf, "qwerty"), 0);
+ }
+ };
+
+ struct TNewStyleSaveHelper {
+ template <class S>
+ inline void SaveLoad(S* s) {
+ ::SaveLoad(s, Str);
+ }
+
+ TString Str;
+ };
+
+ struct TNewNewStyleHelper {
+ TString Str;
+ ui32 Int;
+
+ Y_SAVELOAD_DEFINE(Str, Int)
+ };
+
+private:
+ inline void TestNewNewStyle() {
+ TString ss;
+
+ {
+ TNewNewStyleHelper h;
+
+ h.Str = "qw";
+ h.Int = 42;
+
+ TStringOutput so(ss);
+
+ ::Save(&so, h);
+ }
+
+ {
+ TNewNewStyleHelper h;
+
+ TStringInput si(ss);
+ ::Load(&si, h);
+
+ UNIT_ASSERT_EQUAL(h.Str, "qw");
+ UNIT_ASSERT_EQUAL(h.Int, 42);
+ }
+ }
+
+ inline void TestNewStyle() {
+ TString ss;
+
+ {
+ TNewStyleSaveHelper sh;
+ sh.Str = "qwerty";
+ TStringOutput so(ss);
+ SaveLoad(&so, sh);
+ }
+
+ {
+ TNewStyleSaveHelper sh;
+ TStringInput si(ss);
+ SaveLoad(&si, sh);
+
+ UNIT_ASSERT_EQUAL(sh.Str, "qwerty");
+ }
+ }
+
+ inline void TestSaveLoad() {
+ TBufferStream S_;
+
+ //save part
+ {
+ Save(&S_, (ui8)1);
+ Save(&S_, (ui16)2);
+ Save(&S_, (ui32)3);
+ Save(&S_, (ui64)4);
+ }
+
+ {
+ TVector<ui16> vec;
+
+ vec.push_back((ui16)1);
+ vec.push_back((ui16)2);
+ vec.push_back((ui16)4);
+
+ Save(&S_, vec);
+ }
+
+ {
+ TMap<ui16, ui32> map;
+
+ map[(ui16)1] = 2;
+ map[(ui16)2] = 3;
+ map[(ui16)3] = 4;
+
+ Save(&S_, map);
+ }
+
+ {
+ TMultiMap<ui16, ui32> multimap;
+
+ multimap.emplace((ui16)1, 2);
+ multimap.emplace((ui16)2, 3);
+ multimap.emplace((ui16)2, 4);
+ multimap.emplace((ui16)2, 5);
+ multimap.emplace((ui16)3, 6);
+
+ Save(&S_, multimap);
+ }
+
+ {
+ TSaveHelper helper;
+
+ Save(&S_, helper);
+ }
+
+ {
+ TString val("123456");
+
+ Save(&S_, val);
+ }
+
+ {
+ TBuffer buf;
+
+ buf.Append("asdf", 4);
+ Save(&S_, buf);
+ }
+
+ {
+ TVector<const char*> vec;
+
+ vec.push_back("1");
+ vec.push_back("123");
+ vec.push_back("4567");
+
+ Save(&S_, vec);
+ }
+
+ {
+ TDeque<ui16> deq;
+
+ deq.push_back(1);
+ deq.push_back(2);
+ deq.push_back(4);
+ deq.push_back(5);
+
+ Save(&S_, deq);
+ }
+
+ {
+ TMaybe<size_t> h(10);
+ Save(&S_, h);
+ }
+
+ {
+ TMaybe<size_t> h(20);
+ Save(&S_, h);
+ }
+
+ {
+ TMaybe<size_t> h;
+ Save(&S_, h);
+ }
+
+ {
+ TMaybe<size_t> h;
+ Save(&S_, h);
+ }
+
+ {
+ THashMultiMap<TString, int> mm;
+
+ mm.insert({"one", 1});
+ mm.insert({"two", 2});
+ mm.insert({"two", 22});
+
+ Save(&S_, mm);
+ }
+
+ //load part
+ {
+ ui8 val;
+
+ Load(&S_, val);
+ UNIT_ASSERT_EQUAL(val, 1);
+ }
+
+ {
+ ui16 val;
+
+ Load(&S_, val);
+ UNIT_ASSERT_EQUAL(val, 2);
+ }
+
+ {
+ ui32 val;
+
+ Load(&S_, val);
+ UNIT_ASSERT_EQUAL(val, 3);
+ }
+
+ {
+ ui64 val;
+
+ Load(&S_, val);
+ UNIT_ASSERT_EQUAL(val, 4);
+ }
+
+ {
+ TVector<ui16> vec;
+
+ Load(&S_, vec);
+ UNIT_ASSERT_EQUAL(vec.size(), 3);
+ UNIT_ASSERT_EQUAL(vec[0], 1);
+ UNIT_ASSERT_EQUAL(vec[1], 2);
+ UNIT_ASSERT_EQUAL(vec[2], 4);
+ }
+
+ {
+ TMap<ui16, ui32> map;
+
+ Load(&S_, map);
+ UNIT_ASSERT_EQUAL(map.size(), 3);
+ UNIT_ASSERT_EQUAL(map[(ui16)1], 2);
+ UNIT_ASSERT_EQUAL(map[(ui16)2], 3);
+ UNIT_ASSERT_EQUAL(map[(ui16)3], 4);
+ }
+
+ {
+ TMultiMap<ui16, ui32> multimap;
+
+ Load(&S_, multimap);
+ UNIT_ASSERT_EQUAL(multimap.size(), 5);
+ UNIT_ASSERT_EQUAL(multimap.find((ui16)1)->second, 2);
+ UNIT_ASSERT_EQUAL(multimap.find((ui16)3)->second, 6);
+
+ THashSet<ui32> values;
+ auto range = multimap.equal_range((ui16)2);
+ for (auto i = range.first; i != range.second; ++i) {
+ values.insert(i->second);
+ }
+
+ UNIT_ASSERT_EQUAL(values.size(), 3);
+ UNIT_ASSERT_EQUAL(values.contains(3), true);
+ UNIT_ASSERT_EQUAL(values.contains(4), true);
+ UNIT_ASSERT_EQUAL(values.contains(5), true);
+ }
+
+ {
+ TSaveHelper helper;
+
+ Load(&S_, helper);
+ }
+
+ {
+ TString val;
+
+ Load(&S_, val);
+ UNIT_ASSERT_EQUAL(val, "123456");
+ }
+
+ {
+ TBuffer buf;
+
+ Load(&S_, buf);
+ UNIT_ASSERT_EQUAL(buf.size(), 4);
+ UNIT_ASSERT_EQUAL(memcmp(buf.data(), "asdf", 4), 0);
+ }
+
+ {
+ TVector<const char*> vec;
+ TMemoryPool pool(1024);
+
+ Load(&S_, vec, pool);
+
+ UNIT_ASSERT_EQUAL(vec.size(), 3);
+ UNIT_ASSERT_EQUAL(vec[0], TString("1"));
+ UNIT_ASSERT_EQUAL(vec[1], TString("123"));
+ UNIT_ASSERT_EQUAL(vec[2], TString("4567"));
+ }
+
+ {
+ TDeque<ui16> deq;
+
+ Load(&S_, deq);
+
+ UNIT_ASSERT_EQUAL(deq.size(), 4);
+ UNIT_ASSERT_EQUAL(deq[0], 1);
+ UNIT_ASSERT_EQUAL(deq[1], 2);
+ UNIT_ASSERT_EQUAL(deq[2], 4);
+ UNIT_ASSERT_EQUAL(deq[3], 5);
+ }
+
+ {
+ TMaybe<size_t> h(5);
+ Load(&S_, h);
+ UNIT_ASSERT_EQUAL(*h, 10);
+ }
+
+ {
+ TMaybe<size_t> h;
+ Load(&S_, h);
+ UNIT_ASSERT_EQUAL(*h, 20);
+ }
+
+ {
+ TMaybe<size_t> h;
+ UNIT_ASSERT(!h);
+ Load(&S_, h);
+ UNIT_ASSERT(!h);
+ }
+
+ {
+ TMaybe<size_t> h(7);
+ UNIT_ASSERT(!!h);
+ Load(&S_, h);
+ UNIT_ASSERT(!h);
+ }
+
+ {
+ THashMultiMap<TString, int> mm;
+
+ Load(&S_, mm);
+
+ UNIT_ASSERT_EQUAL(mm.size(), 3);
+ UNIT_ASSERT_EQUAL(mm.count("one"), 1);
+ auto oneIter = mm.equal_range("one").first;
+ UNIT_ASSERT_EQUAL(oneIter->second, 1);
+ UNIT_ASSERT_EQUAL(mm.count("two"), 2);
+ auto twoIter = mm.equal_range("two").first;
+ UNIT_ASSERT_EQUAL(twoIter->second, 2);
+ UNIT_ASSERT_EQUAL((++twoIter)->second, 22);
+ }
+ }
+
+ void TestList() {
+ TBufferStream s;
+
+ TList<int> list = {0, 1, 10};
+ Save(&s, list);
+
+ list.clear();
+ Load(&s, list);
+
+ UNIT_ASSERT_VALUES_EQUAL(list.size(), 3);
+ UNIT_ASSERT_VALUES_EQUAL(*std::next(list.begin(), 0), 0);
+ UNIT_ASSERT_VALUES_EQUAL(*std::next(list.begin(), 1), 1);
+ UNIT_ASSERT_VALUES_EQUAL(*std::next(list.begin(), 2), 10);
+ }
+
+ void TestTuple() {
+ TBufferStream s;
+
+ using TTuple = std::tuple<int, TString, unsigned int>;
+ const TTuple toSave{-10, "qwerty", 15};
+ Save(&s, toSave);
+
+ TTuple toLoad;
+ Load(&s, toLoad);
+
+ UNIT_ASSERT_VALUES_EQUAL(std::get<0>(toLoad), std::get<0>(toSave));
+ UNIT_ASSERT_VALUES_EQUAL(std::get<1>(toLoad), std::get<1>(toSave));
+ UNIT_ASSERT_VALUES_EQUAL(std::get<2>(toLoad), std::get<2>(toSave));
+ }
+
+ template <class TVariant, class T>
+ void TestVariantImpl(TVariant& v, const T& expected) {
+ v = expected;
+
+ TBufferStream s;
+ ::Save(&s, v);
+ ::Load(&s, v);
+ UNIT_ASSERT_VALUES_EQUAL(std::get<T>(v), expected);
+ }
+
+ void TestVariant() {
+ std::variant<int, bool, TString, TVector<char>> v(1);
+ TestVariantImpl(v, 42);
+ TestVariantImpl(v, true);
+ TestVariantImpl(v, TString("foo"));
+ TestVariantImpl(v, TVector<char>{'b', 'a', 'r'});
+
+ v = TString("baz");
+ TBufferStream s;
+ ::Save(&s, v);
+
+ std::variant<char, bool> v2 = false;
+ UNIT_ASSERT_EXCEPTION(::Load(&s, v2), TLoadEOF);
+ }
+
+ // tests serialization of class with three public string members
+ template <class TDerived, class TInterface = TDerived>
+ void TestInheritClassImpl() {
+ TBufferStream s;
+ {
+ TDerived v1;
+ v1.Str1 = "One";
+ v1.Str2 = "Two";
+ v1.Str3 = "Three";
+ ::Save(&s, static_cast<const TInterface&>(v1));
+ }
+ {
+ TDerived v2;
+ ::Load(&s, static_cast<TInterface&>(v2));
+ UNIT_ASSERT_VALUES_EQUAL_C(v2.Str1, "One", TypeName<TDerived>() << " via " << TypeName<TInterface>());
+ UNIT_ASSERT_VALUES_EQUAL_C(v2.Str2, "Two", TypeName<TDerived>() << " via " << TypeName<TInterface>());
+ UNIT_ASSERT_VALUES_EQUAL_C(v2.Str3, "Three", TypeName<TDerived>() << " via " << TypeName<TInterface>());
+ }
+ }
+
+ void TestInheritNonVirtualClass() {
+ struct TBaseNonVirtual {
+ TString Str1;
+ Y_SAVELOAD_DEFINE(Str1);
+ };
+ struct TDerivedNonVirtual: TBaseNonVirtual {
+ TString Str2;
+ TString Str3;
+ Y_SAVELOAD_DEFINE(TNonVirtualSaver<TBaseNonVirtual>{this}, Str2, Str3);
+ };
+ TestInheritClassImpl<TDerivedNonVirtual>();
+ }
+
+ void TestInheritVirtualClass() {
+ struct IInterface {
+ virtual void Save(IOutputStream* out) const = 0;
+ virtual void Load(IInputStream* in) = 0;
+ };
+ struct TBaseVirtual: IInterface {
+ TString Str1;
+ Y_SAVELOAD_DEFINE_OVERRIDE(Str1);
+ };
+ struct TDerivedVirtual: TBaseVirtual {
+ TString Str2;
+ TString Str3;
+ Y_SAVELOAD_DEFINE_OVERRIDE(TNonVirtualSaver<TBaseVirtual>{this}, Str2, Str3);
+ };
+ TestInheritClassImpl<TDerivedVirtual>();
+ TestInheritClassImpl<TDerivedVirtual, TBaseVirtual>();
+ TestInheritClassImpl<TDerivedVirtual, IInterface>();
+ }
+};
+
+UNIT_TEST_SUITE_REGISTRATION(TSaveLoadTest);