ysaveload_ut.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  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. std::map<ui16, ui32> map;
  114. map[(ui16)1] = 2;
  115. map[(ui16)2] = 3;
  116. map[(ui16)3] = 4;
  117. Save(&S_, map);
  118. }
  119. {
  120. TMultiMap<ui16, ui32> multimap;
  121. multimap.emplace((ui16)1, 2);
  122. multimap.emplace((ui16)2, 3);
  123. multimap.emplace((ui16)2, 4);
  124. multimap.emplace((ui16)2, 5);
  125. multimap.emplace((ui16)3, 6);
  126. Save(&S_, multimap);
  127. }
  128. {
  129. std::multimap<ui16, ui32> multimap;
  130. multimap.emplace((ui16)1, 2);
  131. multimap.emplace((ui16)2, 3);
  132. multimap.emplace((ui16)2, 4);
  133. multimap.emplace((ui16)2, 5);
  134. multimap.emplace((ui16)3, 6);
  135. Save(&S_, multimap);
  136. }
  137. {
  138. THashMap<ui16, ui32> hmap;
  139. hmap[(ui16)1] = 2;
  140. hmap[(ui16)2] = 3;
  141. hmap[(ui16)3] = 4;
  142. Save(&S_, hmap);
  143. }
  144. {
  145. std::unordered_map<ui16, ui32> umap;
  146. umap[(ui16)1] = 2;
  147. umap[(ui16)2] = 3;
  148. umap[(ui16)3] = 4;
  149. Save(&S_, umap);
  150. }
  151. {
  152. THashMultiMap<TString, int> mm;
  153. mm.insert({"one", 1});
  154. mm.insert({"two", 2});
  155. mm.insert({"two", 22});
  156. Save(&S_, mm);
  157. }
  158. {
  159. TSet<int> s;
  160. s.insert(2);
  161. s.insert(3);
  162. s.insert(4);
  163. Save(&S_, s);
  164. }
  165. {
  166. std::set<int> s;
  167. s.insert(2);
  168. s.insert(3);
  169. s.insert(4);
  170. Save(&S_, s);
  171. }
  172. {
  173. THashSet<int> hs;
  174. hs.insert(2);
  175. hs.insert(3);
  176. hs.insert(4);
  177. Save(&S_, hs);
  178. }
  179. {
  180. std::unordered_set<int> us;
  181. us.insert(2);
  182. us.insert(3);
  183. us.insert(4);
  184. Save(&S_, us);
  185. }
  186. {
  187. TSaveHelper helper;
  188. Save(&S_, helper);
  189. }
  190. {
  191. TString val("123456");
  192. Save(&S_, val);
  193. }
  194. {
  195. TBuffer buf;
  196. buf.Append("asdf", 4);
  197. Save(&S_, buf);
  198. }
  199. {
  200. TVector<const char*> vec;
  201. vec.push_back("1");
  202. vec.push_back("123");
  203. vec.push_back("4567");
  204. Save(&S_, vec);
  205. }
  206. {
  207. TDeque<ui16> deq;
  208. deq.push_back(1);
  209. deq.push_back(2);
  210. deq.push_back(4);
  211. deq.push_back(5);
  212. Save(&S_, deq);
  213. }
  214. {
  215. TMaybe<size_t> h(10);
  216. Save(&S_, h);
  217. }
  218. {
  219. TMaybe<size_t> h(20);
  220. Save(&S_, h);
  221. }
  222. {
  223. TMaybe<size_t> h;
  224. Save(&S_, h);
  225. }
  226. {
  227. TMaybe<size_t> h;
  228. Save(&S_, h);
  229. }
  230. // load part
  231. {
  232. ui8 val;
  233. Load(&S_, val);
  234. UNIT_ASSERT_EQUAL(val, 1);
  235. }
  236. {
  237. ui16 val;
  238. Load(&S_, val);
  239. UNIT_ASSERT_EQUAL(val, 2);
  240. }
  241. {
  242. ui32 val;
  243. Load(&S_, val);
  244. UNIT_ASSERT_EQUAL(val, 3);
  245. }
  246. {
  247. ui64 val;
  248. Load(&S_, val);
  249. UNIT_ASSERT_EQUAL(val, 4);
  250. }
  251. {
  252. TVector<ui16> vec;
  253. Load(&S_, vec);
  254. UNIT_ASSERT_EQUAL(vec.size(), 3);
  255. UNIT_ASSERT_EQUAL(vec[0], 1);
  256. UNIT_ASSERT_EQUAL(vec[1], 2);
  257. UNIT_ASSERT_EQUAL(vec[2], 4);
  258. }
  259. {
  260. TMap<ui16, ui32> map;
  261. Load(&S_, map);
  262. UNIT_ASSERT_EQUAL(map.size(), 3);
  263. UNIT_ASSERT_EQUAL(map[(ui16)1], 2);
  264. UNIT_ASSERT_EQUAL(map[(ui16)2], 3);
  265. UNIT_ASSERT_EQUAL(map[(ui16)3], 4);
  266. }
  267. {
  268. std::map<ui16, ui32> map;
  269. Load(&S_, map);
  270. UNIT_ASSERT_EQUAL(map.size(), 3);
  271. UNIT_ASSERT_EQUAL(map[(ui16)1], 2);
  272. UNIT_ASSERT_EQUAL(map[(ui16)2], 3);
  273. UNIT_ASSERT_EQUAL(map[(ui16)3], 4);
  274. }
  275. {
  276. TMultiMap<ui16, ui32> multimap;
  277. Load(&S_, multimap);
  278. UNIT_ASSERT_EQUAL(multimap.size(), 5);
  279. UNIT_ASSERT_EQUAL(multimap.find((ui16)1)->second, 2);
  280. UNIT_ASSERT_EQUAL(multimap.find((ui16)3)->second, 6);
  281. THashSet<ui32> values;
  282. auto range = multimap.equal_range((ui16)2);
  283. for (auto i = range.first; i != range.second; ++i) {
  284. values.insert(i->second);
  285. }
  286. UNIT_ASSERT_EQUAL(values.size(), 3);
  287. UNIT_ASSERT_EQUAL(values.contains(3), true);
  288. UNIT_ASSERT_EQUAL(values.contains(4), true);
  289. UNIT_ASSERT_EQUAL(values.contains(5), true);
  290. }
  291. {
  292. std::multimap<ui16, ui32> multimap;
  293. Load(&S_, multimap);
  294. UNIT_ASSERT_EQUAL(multimap.size(), 5);
  295. UNIT_ASSERT_EQUAL(multimap.find((ui16)1)->second, 2);
  296. UNIT_ASSERT_EQUAL(multimap.find((ui16)3)->second, 6);
  297. std::set<ui32> values;
  298. auto range = multimap.equal_range((ui16)2);
  299. for (auto i = range.first; i != range.second; ++i) {
  300. values.insert(i->second);
  301. }
  302. UNIT_ASSERT_EQUAL(values.size(), 3);
  303. UNIT_ASSERT_EQUAL(values.contains(3), true);
  304. UNIT_ASSERT_EQUAL(values.contains(4), true);
  305. UNIT_ASSERT_EQUAL(values.contains(5), true);
  306. }
  307. {
  308. THashMap<ui16, ui32> hmap;
  309. Load(&S_, hmap);
  310. UNIT_ASSERT_EQUAL(hmap.size(), 3);
  311. UNIT_ASSERT_EQUAL(hmap[(ui16)1], 2);
  312. UNIT_ASSERT_EQUAL(hmap[(ui16)2], 3);
  313. UNIT_ASSERT_EQUAL(hmap[(ui16)3], 4);
  314. }
  315. {
  316. std::unordered_map<ui16, ui32> umap;
  317. Load(&S_, umap);
  318. UNIT_ASSERT_EQUAL(umap.size(), 3);
  319. UNIT_ASSERT_EQUAL(umap[(ui16)1], 2);
  320. UNIT_ASSERT_EQUAL(umap[(ui16)2], 3);
  321. UNIT_ASSERT_EQUAL(umap[(ui16)3], 4);
  322. }
  323. {
  324. THashMultiMap<TString, int> mm;
  325. Load(&S_, mm);
  326. UNIT_ASSERT_EQUAL(mm.size(), 3);
  327. UNIT_ASSERT_EQUAL(mm.count("one"), 1);
  328. auto oneIter = mm.equal_range("one").first;
  329. UNIT_ASSERT_EQUAL(oneIter->second, 1);
  330. UNIT_ASSERT_EQUAL(mm.count("two"), 2);
  331. auto twoIter = mm.equal_range("two").first;
  332. UNIT_ASSERT_EQUAL(twoIter->second, 2);
  333. UNIT_ASSERT_EQUAL((++twoIter)->second, 22);
  334. }
  335. {
  336. TSet<int> s;
  337. Load(&S_, s);
  338. UNIT_ASSERT_EQUAL(s.size(), 3);
  339. UNIT_ASSERT_EQUAL(s.contains(2), true);
  340. UNIT_ASSERT_EQUAL(s.contains(3), true);
  341. UNIT_ASSERT_EQUAL(s.contains(4), true);
  342. }
  343. {
  344. std::set<int> s;
  345. Load(&S_, s);
  346. UNIT_ASSERT_EQUAL(s.size(), 3);
  347. UNIT_ASSERT_EQUAL(s.contains(2), true);
  348. UNIT_ASSERT_EQUAL(s.contains(3), true);
  349. UNIT_ASSERT_EQUAL(s.contains(4), true);
  350. }
  351. {
  352. THashSet<int> hs;
  353. Load(&S_, hs);
  354. UNIT_ASSERT_EQUAL(hs.size(), 3);
  355. UNIT_ASSERT_EQUAL(hs.contains(2), true);
  356. UNIT_ASSERT_EQUAL(hs.contains(3), true);
  357. UNIT_ASSERT_EQUAL(hs.contains(4), true);
  358. }
  359. {
  360. std::unordered_set<int> us;
  361. Load(&S_, us);
  362. UNIT_ASSERT_EQUAL(us.size(), 3);
  363. UNIT_ASSERT_EQUAL(us.contains(2), true);
  364. UNIT_ASSERT_EQUAL(us.contains(3), true);
  365. UNIT_ASSERT_EQUAL(us.contains(4), true);
  366. }
  367. {
  368. TSaveHelper helper;
  369. Load(&S_, helper);
  370. }
  371. {
  372. TString val;
  373. Load(&S_, val);
  374. UNIT_ASSERT_EQUAL(val, "123456");
  375. }
  376. {
  377. TBuffer buf;
  378. Load(&S_, buf);
  379. UNIT_ASSERT_EQUAL(buf.size(), 4);
  380. UNIT_ASSERT_EQUAL(memcmp(buf.data(), "asdf", 4), 0);
  381. }
  382. {
  383. TVector<const char*> vec;
  384. TMemoryPool pool(1024);
  385. Load(&S_, vec, pool);
  386. UNIT_ASSERT_EQUAL(vec.size(), 3);
  387. UNIT_ASSERT_EQUAL(vec[0], TString("1"));
  388. UNIT_ASSERT_EQUAL(vec[1], TString("123"));
  389. UNIT_ASSERT_EQUAL(vec[2], TString("4567"));
  390. }
  391. {
  392. TDeque<ui16> deq;
  393. Load(&S_, deq);
  394. UNIT_ASSERT_EQUAL(deq.size(), 4);
  395. UNIT_ASSERT_EQUAL(deq[0], 1);
  396. UNIT_ASSERT_EQUAL(deq[1], 2);
  397. UNIT_ASSERT_EQUAL(deq[2], 4);
  398. UNIT_ASSERT_EQUAL(deq[3], 5);
  399. }
  400. {
  401. TMaybe<size_t> h(5);
  402. Load(&S_, h);
  403. UNIT_ASSERT_EQUAL(*h, 10);
  404. }
  405. {
  406. TMaybe<size_t> h;
  407. Load(&S_, h);
  408. UNIT_ASSERT_EQUAL(*h, 20);
  409. }
  410. {
  411. TMaybe<size_t> h;
  412. UNIT_ASSERT(!h);
  413. Load(&S_, h);
  414. UNIT_ASSERT(!h);
  415. }
  416. {
  417. TMaybe<size_t> h(7);
  418. UNIT_ASSERT(!!h);
  419. Load(&S_, h);
  420. UNIT_ASSERT(!h);
  421. }
  422. }
  423. inline void TestSaveLoadEmptyStruct() {
  424. TBufferStream S_;
  425. TNewNewStyleEmptyHelper h;
  426. Save(&S_, h);
  427. Load(&S_, h);
  428. }
  429. void TestList() {
  430. TBufferStream s;
  431. TList<int> list = {0, 1, 10};
  432. Save(&s, list);
  433. list.clear();
  434. Load(&s, list);
  435. UNIT_ASSERT_VALUES_EQUAL(list.size(), 3);
  436. UNIT_ASSERT_VALUES_EQUAL(*std::next(list.begin(), 0), 0);
  437. UNIT_ASSERT_VALUES_EQUAL(*std::next(list.begin(), 1), 1);
  438. UNIT_ASSERT_VALUES_EQUAL(*std::next(list.begin(), 2), 10);
  439. }
  440. void TestTuple() {
  441. TBufferStream s;
  442. using TTuple = std::tuple<int, TString, unsigned int>;
  443. const TTuple toSave{-10, "qwerty", 15};
  444. Save(&s, toSave);
  445. TTuple toLoad;
  446. Load(&s, toLoad);
  447. UNIT_ASSERT_VALUES_EQUAL(std::get<0>(toLoad), std::get<0>(toSave));
  448. UNIT_ASSERT_VALUES_EQUAL(std::get<1>(toLoad), std::get<1>(toSave));
  449. UNIT_ASSERT_VALUES_EQUAL(std::get<2>(toLoad), std::get<2>(toSave));
  450. }
  451. template <class TVariant, class T>
  452. void TestVariantImpl(TVariant& v, const T& expected) {
  453. v = expected;
  454. TBufferStream s;
  455. ::Save(&s, v);
  456. ::Load(&s, v);
  457. UNIT_ASSERT_VALUES_EQUAL(std::get<T>(v), expected);
  458. }
  459. void TestVariant() {
  460. std::variant<int, bool, TString, TVector<char>> v(1);
  461. TestVariantImpl(v, 42);
  462. TestVariantImpl(v, true);
  463. TestVariantImpl(v, TString("foo"));
  464. TestVariantImpl(v, TVector<char>{'b', 'a', 'r'});
  465. v = TString("baz");
  466. TBufferStream s;
  467. ::Save(&s, v);
  468. std::variant<char, bool> v2 = false;
  469. UNIT_ASSERT_EXCEPTION(::Load(&s, v2), TLoadEOF);
  470. }
  471. template <class T>
  472. void TestOptionalImpl(const std::optional<T>& v) {
  473. std::optional<T> loaded;
  474. TBufferStream s;
  475. ::Save(&s, v);
  476. ::Load(&s, loaded);
  477. UNIT_ASSERT_VALUES_EQUAL(v.has_value(), loaded.has_value());
  478. if (v.has_value()) {
  479. UNIT_ASSERT_VALUES_EQUAL(*v, *loaded);
  480. }
  481. }
  482. void TestOptional() {
  483. TestOptionalImpl(std::optional<ui64>(42ull));
  484. TestOptionalImpl(std::optional<bool>(true));
  485. TestOptionalImpl(std::optional<TString>("abacaba"));
  486. TestOptionalImpl(std::optional<ui64>(std::nullopt));
  487. }
  488. // tests serialization of class with three public string members
  489. template <class TDerived, class TInterface = TDerived>
  490. void TestInheritClassImpl() {
  491. TBufferStream s;
  492. {
  493. TDerived v1;
  494. v1.Str1 = "One";
  495. v1.Str2 = "Two";
  496. v1.Str3 = "Three";
  497. ::Save(&s, static_cast<const TInterface&>(v1));
  498. }
  499. {
  500. TDerived v2;
  501. ::Load(&s, static_cast<TInterface&>(v2));
  502. UNIT_ASSERT_VALUES_EQUAL_C(v2.Str1, "One", TypeName<TDerived>() << " via " << TypeName<TInterface>());
  503. UNIT_ASSERT_VALUES_EQUAL_C(v2.Str2, "Two", TypeName<TDerived>() << " via " << TypeName<TInterface>());
  504. UNIT_ASSERT_VALUES_EQUAL_C(v2.Str3, "Three", TypeName<TDerived>() << " via " << TypeName<TInterface>());
  505. }
  506. }
  507. void TestInheritNonVirtualClass() {
  508. struct TBaseNonVirtual {
  509. TString Str1;
  510. Y_SAVELOAD_DEFINE(Str1);
  511. };
  512. struct TDerivedNonVirtual: TBaseNonVirtual {
  513. TString Str2;
  514. TString Str3;
  515. Y_SAVELOAD_DEFINE(TNonVirtualSaver<TBaseNonVirtual>{this}, Str2, Str3);
  516. };
  517. TestInheritClassImpl<TDerivedNonVirtual>();
  518. }
  519. void TestInheritVirtualClass() {
  520. struct IInterface {
  521. virtual void Save(IOutputStream* out) const = 0;
  522. virtual void Load(IInputStream* in) = 0;
  523. virtual ~IInterface() = default;
  524. };
  525. struct TBaseVirtual: IInterface {
  526. TString Str1;
  527. Y_SAVELOAD_DEFINE_OVERRIDE(Str1);
  528. };
  529. struct TDerivedVirtual: TBaseVirtual {
  530. TString Str2;
  531. TString Str3;
  532. Y_SAVELOAD_DEFINE_OVERRIDE(TNonVirtualSaver<TBaseVirtual>{this}, Str2, Str3);
  533. };
  534. TestInheritClassImpl<TDerivedVirtual>();
  535. TestInheritClassImpl<TDerivedVirtual, TBaseVirtual>();
  536. TestInheritClassImpl<TDerivedVirtual, IInterface>();
  537. }
  538. };
  539. UNIT_TEST_SUITE_REGISTRATION(TSaveLoadTest);