ysaveload_ut.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  1. #include "ysaveload.h"
  2. #include <library/cpp/testing/unittest/registar.h>
  3. #include <util/memory/pool.h>
  4. #include <util/stream/buffer.h>
  5. #include <util/memory/blob.h>
  6. #include <util/generic/list.h>
  7. #include <util/generic/map.h>
  8. #include <util/generic/hash_multi_map.h>
  9. #include <util/generic/deque.h>
  10. #include <util/generic/string.h>
  11. #include <util/generic/vector.h>
  12. #include <util/generic/buffer.h>
  13. #include <util/generic/hash_set.h>
  14. #include <util/generic/maybe.h>
  15. static inline char* AllocateFromPool(TMemoryPool& pool, size_t len) {
  16. return (char*)pool.Allocate(len);
  17. }
  18. class TSaveLoadTest: public TTestBase {
  19. UNIT_TEST_SUITE(TSaveLoadTest);
  20. UNIT_TEST(TestSaveLoad)
  21. UNIT_TEST(TestSaveLoadEmptyStruct)
  22. UNIT_TEST(TestNewStyle)
  23. UNIT_TEST(TestNewNewStyle)
  24. UNIT_TEST(TestList)
  25. UNIT_TEST(TestTuple)
  26. UNIT_TEST(TestVariant)
  27. UNIT_TEST(TestOptional)
  28. UNIT_TEST(TestInheritNonVirtualClass)
  29. UNIT_TEST(TestInheritVirtualClass)
  30. UNIT_TEST_SUITE_END();
  31. struct TSaveHelper {
  32. inline void Save(IOutputStream* o) const {
  33. o->Write("qwerty", 7);
  34. }
  35. inline void Load(IInputStream* i) {
  36. char buf[7];
  37. UNIT_ASSERT_EQUAL(i->Load(buf, 7), 7);
  38. UNIT_ASSERT_EQUAL(strcmp(buf, "qwerty"), 0);
  39. }
  40. };
  41. struct TNewStyleSaveHelper {
  42. template <class S>
  43. inline void SaveLoad(S* s) {
  44. ::SaveLoad(s, Str);
  45. }
  46. TString Str;
  47. };
  48. struct TNewNewStyleHelper {
  49. TString Str;
  50. ui32 Int;
  51. Y_SAVELOAD_DEFINE(Str, Int);
  52. };
  53. struct TNewNewStyleEmptyHelper {
  54. Y_SAVELOAD_DEFINE();
  55. };
  56. private:
  57. inline void TestNewNewStyle() {
  58. TString ss;
  59. {
  60. TNewNewStyleHelper h;
  61. h.Str = "qw";
  62. h.Int = 42;
  63. TStringOutput so(ss);
  64. ::Save(&so, h);
  65. }
  66. {
  67. TNewNewStyleHelper h;
  68. TStringInput si(ss);
  69. ::Load(&si, h);
  70. UNIT_ASSERT_EQUAL(h.Str, "qw");
  71. UNIT_ASSERT_EQUAL(h.Int, 42);
  72. }
  73. }
  74. inline void TestNewStyle() {
  75. TString ss;
  76. {
  77. TNewStyleSaveHelper sh;
  78. sh.Str = "qwerty";
  79. TStringOutput so(ss);
  80. SaveLoad(&so, sh);
  81. }
  82. {
  83. TNewStyleSaveHelper sh;
  84. TStringInput si(ss);
  85. SaveLoad(&si, sh);
  86. UNIT_ASSERT_EQUAL(sh.Str, "qwerty");
  87. }
  88. }
  89. inline void TestSaveLoad() {
  90. TBufferStream S_;
  91. //save part
  92. {
  93. Save(&S_, (ui8)1);
  94. Save(&S_, (ui16)2);
  95. Save(&S_, (ui32)3);
  96. Save(&S_, (ui64)4);
  97. }
  98. {
  99. TVector<ui16> vec;
  100. vec.push_back((ui16)1);
  101. vec.push_back((ui16)2);
  102. vec.push_back((ui16)4);
  103. Save(&S_, vec);
  104. }
  105. {
  106. TMap<ui16, ui32> map;
  107. map[(ui16)1] = 2;
  108. map[(ui16)2] = 3;
  109. map[(ui16)3] = 4;
  110. Save(&S_, map);
  111. }
  112. {
  113. TMultiMap<ui16, ui32> multimap;
  114. multimap.emplace((ui16)1, 2);
  115. multimap.emplace((ui16)2, 3);
  116. multimap.emplace((ui16)2, 4);
  117. multimap.emplace((ui16)2, 5);
  118. multimap.emplace((ui16)3, 6);
  119. Save(&S_, multimap);
  120. }
  121. {
  122. TSaveHelper helper;
  123. Save(&S_, helper);
  124. }
  125. {
  126. TString val("123456");
  127. Save(&S_, val);
  128. }
  129. {
  130. TBuffer buf;
  131. buf.Append("asdf", 4);
  132. Save(&S_, buf);
  133. }
  134. {
  135. TVector<const char*> vec;
  136. vec.push_back("1");
  137. vec.push_back("123");
  138. vec.push_back("4567");
  139. Save(&S_, vec);
  140. }
  141. {
  142. TDeque<ui16> deq;
  143. deq.push_back(1);
  144. deq.push_back(2);
  145. deq.push_back(4);
  146. deq.push_back(5);
  147. Save(&S_, deq);
  148. }
  149. {
  150. TMaybe<size_t> h(10);
  151. Save(&S_, h);
  152. }
  153. {
  154. TMaybe<size_t> h(20);
  155. Save(&S_, h);
  156. }
  157. {
  158. TMaybe<size_t> h;
  159. Save(&S_, h);
  160. }
  161. {
  162. TMaybe<size_t> h;
  163. Save(&S_, h);
  164. }
  165. {
  166. THashMultiMap<TString, int> mm;
  167. mm.insert({"one", 1});
  168. mm.insert({"two", 2});
  169. mm.insert({"two", 22});
  170. Save(&S_, mm);
  171. }
  172. //load part
  173. {
  174. ui8 val;
  175. Load(&S_, val);
  176. UNIT_ASSERT_EQUAL(val, 1);
  177. }
  178. {
  179. ui16 val;
  180. Load(&S_, val);
  181. UNIT_ASSERT_EQUAL(val, 2);
  182. }
  183. {
  184. ui32 val;
  185. Load(&S_, val);
  186. UNIT_ASSERT_EQUAL(val, 3);
  187. }
  188. {
  189. ui64 val;
  190. Load(&S_, val);
  191. UNIT_ASSERT_EQUAL(val, 4);
  192. }
  193. {
  194. TVector<ui16> vec;
  195. Load(&S_, vec);
  196. UNIT_ASSERT_EQUAL(vec.size(), 3);
  197. UNIT_ASSERT_EQUAL(vec[0], 1);
  198. UNIT_ASSERT_EQUAL(vec[1], 2);
  199. UNIT_ASSERT_EQUAL(vec[2], 4);
  200. }
  201. {
  202. TMap<ui16, ui32> map;
  203. Load(&S_, map);
  204. UNIT_ASSERT_EQUAL(map.size(), 3);
  205. UNIT_ASSERT_EQUAL(map[(ui16)1], 2);
  206. UNIT_ASSERT_EQUAL(map[(ui16)2], 3);
  207. UNIT_ASSERT_EQUAL(map[(ui16)3], 4);
  208. }
  209. {
  210. TMultiMap<ui16, ui32> multimap;
  211. Load(&S_, multimap);
  212. UNIT_ASSERT_EQUAL(multimap.size(), 5);
  213. UNIT_ASSERT_EQUAL(multimap.find((ui16)1)->second, 2);
  214. UNIT_ASSERT_EQUAL(multimap.find((ui16)3)->second, 6);
  215. THashSet<ui32> values;
  216. auto range = multimap.equal_range((ui16)2);
  217. for (auto i = range.first; i != range.second; ++i) {
  218. values.insert(i->second);
  219. }
  220. UNIT_ASSERT_EQUAL(values.size(), 3);
  221. UNIT_ASSERT_EQUAL(values.contains(3), true);
  222. UNIT_ASSERT_EQUAL(values.contains(4), true);
  223. UNIT_ASSERT_EQUAL(values.contains(5), true);
  224. }
  225. {
  226. TSaveHelper helper;
  227. Load(&S_, helper);
  228. }
  229. {
  230. TString val;
  231. Load(&S_, val);
  232. UNIT_ASSERT_EQUAL(val, "123456");
  233. }
  234. {
  235. TBuffer buf;
  236. Load(&S_, buf);
  237. UNIT_ASSERT_EQUAL(buf.size(), 4);
  238. UNIT_ASSERT_EQUAL(memcmp(buf.data(), "asdf", 4), 0);
  239. }
  240. {
  241. TVector<const char*> vec;
  242. TMemoryPool pool(1024);
  243. Load(&S_, vec, pool);
  244. UNIT_ASSERT_EQUAL(vec.size(), 3);
  245. UNIT_ASSERT_EQUAL(vec[0], TString("1"));
  246. UNIT_ASSERT_EQUAL(vec[1], TString("123"));
  247. UNIT_ASSERT_EQUAL(vec[2], TString("4567"));
  248. }
  249. {
  250. TDeque<ui16> deq;
  251. Load(&S_, deq);
  252. UNIT_ASSERT_EQUAL(deq.size(), 4);
  253. UNIT_ASSERT_EQUAL(deq[0], 1);
  254. UNIT_ASSERT_EQUAL(deq[1], 2);
  255. UNIT_ASSERT_EQUAL(deq[2], 4);
  256. UNIT_ASSERT_EQUAL(deq[3], 5);
  257. }
  258. {
  259. TMaybe<size_t> h(5);
  260. Load(&S_, h);
  261. UNIT_ASSERT_EQUAL(*h, 10);
  262. }
  263. {
  264. TMaybe<size_t> h;
  265. Load(&S_, h);
  266. UNIT_ASSERT_EQUAL(*h, 20);
  267. }
  268. {
  269. TMaybe<size_t> h;
  270. UNIT_ASSERT(!h);
  271. Load(&S_, h);
  272. UNIT_ASSERT(!h);
  273. }
  274. {
  275. TMaybe<size_t> h(7);
  276. UNIT_ASSERT(!!h);
  277. Load(&S_, h);
  278. UNIT_ASSERT(!h);
  279. }
  280. {
  281. THashMultiMap<TString, int> mm;
  282. Load(&S_, mm);
  283. UNIT_ASSERT_EQUAL(mm.size(), 3);
  284. UNIT_ASSERT_EQUAL(mm.count("one"), 1);
  285. auto oneIter = mm.equal_range("one").first;
  286. UNIT_ASSERT_EQUAL(oneIter->second, 1);
  287. UNIT_ASSERT_EQUAL(mm.count("two"), 2);
  288. auto twoIter = mm.equal_range("two").first;
  289. UNIT_ASSERT_EQUAL(twoIter->second, 2);
  290. UNIT_ASSERT_EQUAL((++twoIter)->second, 22);
  291. }
  292. }
  293. inline void TestSaveLoadEmptyStruct() {
  294. TBufferStream S_;
  295. TNewNewStyleEmptyHelper h;
  296. Save(&S_, h);
  297. Load(&S_, h);
  298. }
  299. void TestList() {
  300. TBufferStream s;
  301. TList<int> list = {0, 1, 10};
  302. Save(&s, list);
  303. list.clear();
  304. Load(&s, list);
  305. UNIT_ASSERT_VALUES_EQUAL(list.size(), 3);
  306. UNIT_ASSERT_VALUES_EQUAL(*std::next(list.begin(), 0), 0);
  307. UNIT_ASSERT_VALUES_EQUAL(*std::next(list.begin(), 1), 1);
  308. UNIT_ASSERT_VALUES_EQUAL(*std::next(list.begin(), 2), 10);
  309. }
  310. void TestTuple() {
  311. TBufferStream s;
  312. using TTuple = std::tuple<int, TString, unsigned int>;
  313. const TTuple toSave{-10, "qwerty", 15};
  314. Save(&s, toSave);
  315. TTuple toLoad;
  316. Load(&s, toLoad);
  317. UNIT_ASSERT_VALUES_EQUAL(std::get<0>(toLoad), std::get<0>(toSave));
  318. UNIT_ASSERT_VALUES_EQUAL(std::get<1>(toLoad), std::get<1>(toSave));
  319. UNIT_ASSERT_VALUES_EQUAL(std::get<2>(toLoad), std::get<2>(toSave));
  320. }
  321. template <class TVariant, class T>
  322. void TestVariantImpl(TVariant& v, const T& expected) {
  323. v = expected;
  324. TBufferStream s;
  325. ::Save(&s, v);
  326. ::Load(&s, v);
  327. UNIT_ASSERT_VALUES_EQUAL(std::get<T>(v), expected);
  328. }
  329. void TestVariant() {
  330. std::variant<int, bool, TString, TVector<char>> v(1);
  331. TestVariantImpl(v, 42);
  332. TestVariantImpl(v, true);
  333. TestVariantImpl(v, TString("foo"));
  334. TestVariantImpl(v, TVector<char>{'b', 'a', 'r'});
  335. v = TString("baz");
  336. TBufferStream s;
  337. ::Save(&s, v);
  338. std::variant<char, bool> v2 = false;
  339. UNIT_ASSERT_EXCEPTION(::Load(&s, v2), TLoadEOF);
  340. }
  341. template <class T>
  342. void TestOptionalImpl(const std::optional<T>& v) {
  343. std::optional<T> loaded;
  344. TBufferStream s;
  345. ::Save(&s, v);
  346. ::Load(&s, loaded);
  347. UNIT_ASSERT_VALUES_EQUAL(v.has_value(), loaded.has_value());
  348. if (v.has_value()) {
  349. UNIT_ASSERT_VALUES_EQUAL(*v, *loaded);
  350. }
  351. }
  352. void TestOptional() {
  353. TestOptionalImpl(std::optional<ui64>(42ull));
  354. TestOptionalImpl(std::optional<bool>(true));
  355. TestOptionalImpl(std::optional<TString>("abacaba"));
  356. TestOptionalImpl(std::optional<ui64>(std::nullopt));
  357. }
  358. // tests serialization of class with three public string members
  359. template <class TDerived, class TInterface = TDerived>
  360. void TestInheritClassImpl() {
  361. TBufferStream s;
  362. {
  363. TDerived v1;
  364. v1.Str1 = "One";
  365. v1.Str2 = "Two";
  366. v1.Str3 = "Three";
  367. ::Save(&s, static_cast<const TInterface&>(v1));
  368. }
  369. {
  370. TDerived v2;
  371. ::Load(&s, static_cast<TInterface&>(v2));
  372. UNIT_ASSERT_VALUES_EQUAL_C(v2.Str1, "One", TypeName<TDerived>() << " via " << TypeName<TInterface>());
  373. UNIT_ASSERT_VALUES_EQUAL_C(v2.Str2, "Two", TypeName<TDerived>() << " via " << TypeName<TInterface>());
  374. UNIT_ASSERT_VALUES_EQUAL_C(v2.Str3, "Three", TypeName<TDerived>() << " via " << TypeName<TInterface>());
  375. }
  376. }
  377. void TestInheritNonVirtualClass() {
  378. struct TBaseNonVirtual {
  379. TString Str1;
  380. Y_SAVELOAD_DEFINE(Str1);
  381. };
  382. struct TDerivedNonVirtual: TBaseNonVirtual {
  383. TString Str2;
  384. TString Str3;
  385. Y_SAVELOAD_DEFINE(TNonVirtualSaver<TBaseNonVirtual>{this}, Str2, Str3);
  386. };
  387. TestInheritClassImpl<TDerivedNonVirtual>();
  388. }
  389. void TestInheritVirtualClass() {
  390. struct IInterface {
  391. virtual void Save(IOutputStream* out) const = 0;
  392. virtual void Load(IInputStream* in) = 0;
  393. };
  394. struct TBaseVirtual: IInterface {
  395. TString Str1;
  396. Y_SAVELOAD_DEFINE_OVERRIDE(Str1);
  397. };
  398. struct TDerivedVirtual: TBaseVirtual {
  399. TString Str2;
  400. TString Str3;
  401. Y_SAVELOAD_DEFINE_OVERRIDE(TNonVirtualSaver<TBaseVirtual>{this}, Str2, Str3);
  402. };
  403. TestInheritClassImpl<TDerivedVirtual>();
  404. TestInheritClassImpl<TDerivedVirtual, TBaseVirtual>();
  405. TestInheritClassImpl<TDerivedVirtual, IInterface>();
  406. }
  407. };
  408. UNIT_TEST_SUITE_REGISTRATION(TSaveLoadTest);