mkql_join_dict_ut.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. #include "mkql_computation_node_ut.h"
  2. namespace NKikimr {
  3. namespace NMiniKQL {
  4. Y_UNIT_TEST_SUITE(TMiniKQLJoinDictNodeTest) {
  5. Y_UNIT_TEST_LLVM(TestInner) {
  6. for (ui32 pass = 0; pass < 1; ++pass) {
  7. TSetup<LLVM> setup;
  8. TProgramBuilder& pb = *setup.PgmBuilder;
  9. const auto key1 = pb.NewDataLiteral<ui32>(1);
  10. const auto key2 = pb.NewDataLiteral<ui32>(2);
  11. const auto key3 = pb.NewDataLiteral<ui32>(2);
  12. const auto key4 = pb.NewDataLiteral<ui32>(3);
  13. const auto payload1 = pb.NewDataLiteral<NUdf::EDataSlot::String>("A");
  14. const auto payload2 = pb.NewDataLiteral<NUdf::EDataSlot::String>("B");
  15. const auto payload3 = pb.NewDataLiteral<NUdf::EDataSlot::String>("C");
  16. const auto payload4 = pb.NewDataLiteral<NUdf::EDataSlot::String>("X");
  17. const auto payload5 = pb.NewDataLiteral<NUdf::EDataSlot::String>("Y");
  18. const auto payload6 = pb.NewDataLiteral<NUdf::EDataSlot::String>("Z");
  19. const auto structType = pb.NewStructType({
  20. {"Key", pb.NewDataType(NUdf::TDataType<ui32>::Id)},
  21. {"Payload", pb.NewDataType(NUdf::TDataType<char*>::Id)}
  22. });
  23. const auto list1 = pb.NewList(structType, {
  24. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key1), "Payload", payload1),
  25. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key2), "Payload", payload2),
  26. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key3), "Payload", payload3)
  27. });
  28. const auto dict1 = pb.ToSortedDict(list1, true,
  29. [&](TRuntimeNode item) {
  30. return pb.Member(item, "Key");
  31. },
  32. [&](TRuntimeNode item) {
  33. return pb.Member(item, "Payload");
  34. });
  35. const auto list2 = pb.NewList(structType, {
  36. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key2), "Payload", payload4),
  37. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key3), "Payload", payload5),
  38. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key4), "Payload", payload6)
  39. });
  40. const auto dict2 = pb.ToSortedDict(list2, true,
  41. [&](TRuntimeNode item) {
  42. return pb.Member(item, "Key");
  43. },
  44. [&](TRuntimeNode item) {
  45. return pb.Member(item, "Payload");
  46. });
  47. const auto pgmReturn = pb.JoinDict(dict1, true, dict2, true, EJoinKind::Inner);
  48. const auto graph = setup.BuildGraph(pgmReturn);
  49. const auto iterator = graph->GetValue().GetListIterator();
  50. NUdf::TUnboxedValue tuple;
  51. UNIT_ASSERT(iterator.Next(tuple));
  52. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "B");
  53. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "X");
  54. UNIT_ASSERT(iterator.Next(tuple));
  55. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "B");
  56. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "Y");
  57. UNIT_ASSERT(iterator.Next(tuple));
  58. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "C");
  59. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "X");
  60. UNIT_ASSERT(iterator.Next(tuple));
  61. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "C");
  62. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "Y");
  63. UNIT_ASSERT(!iterator.Next(tuple));
  64. UNIT_ASSERT(!iterator.Next(tuple));
  65. }
  66. }
  67. Y_UNIT_TEST_LLVM(TestLeft) {
  68. for (ui32 pass = 0; pass < 1; ++pass) {
  69. TSetup<LLVM> setup;
  70. TProgramBuilder& pb = *setup.PgmBuilder;
  71. const auto key1 = pb.NewDataLiteral<ui32>(1);
  72. const auto key2 = pb.NewDataLiteral<ui32>(2);
  73. const auto key3 = pb.NewDataLiteral<ui32>(2);
  74. const auto key4 = pb.NewDataLiteral<ui32>(3);
  75. const auto payload1 = pb.NewDataLiteral<NUdf::EDataSlot::String>("A");
  76. const auto payload2 = pb.NewDataLiteral<NUdf::EDataSlot::String>("B");
  77. const auto payload3 = pb.NewDataLiteral<NUdf::EDataSlot::String>("C");
  78. const auto payload4 = pb.NewDataLiteral<NUdf::EDataSlot::String>("X");
  79. const auto payload5 = pb.NewDataLiteral<NUdf::EDataSlot::String>("Y");
  80. const auto payload6 = pb.NewDataLiteral<NUdf::EDataSlot::String>("Z");
  81. const auto structType = pb.NewStructType({
  82. {"Key", pb.NewDataType(NUdf::TDataType<ui32>::Id)},
  83. {"Payload", pb.NewDataType(NUdf::TDataType<char*>::Id)}
  84. });
  85. const auto list1 = pb.NewList(structType, {
  86. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key1), "Payload", payload1),
  87. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key2), "Payload", payload2),
  88. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key3), "Payload", payload3)
  89. });
  90. const auto dict1 = pb.ToSortedDict(list1, true,
  91. [&](TRuntimeNode item) {
  92. return pb.Member(item, "Key");
  93. },
  94. [&](TRuntimeNode item) {
  95. return pb.Member(item, "Payload");
  96. });
  97. const auto list2 = pb.NewList(structType, {
  98. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key2), "Payload", payload4),
  99. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key3), "Payload", payload5),
  100. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key4), "Payload", payload6)
  101. });
  102. const auto dict2 = pb.ToSortedDict(list2, true,
  103. [&](TRuntimeNode item) {
  104. return pb.Member(item, "Key");
  105. },
  106. [&](TRuntimeNode item) {
  107. return pb.Member(item, "Payload");
  108. });
  109. const auto pgmReturn = pb.JoinDict(dict1, true, dict2, true, EJoinKind::Left);
  110. const auto graph = setup.BuildGraph(pgmReturn);
  111. const auto iterator = graph->GetValue().GetListIterator();
  112. NUdf::TUnboxedValue tuple;
  113. UNIT_ASSERT(iterator.Next(tuple));
  114. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "A");
  115. UNIT_ASSERT(!tuple.GetElement(1));
  116. UNIT_ASSERT(iterator.Next(tuple));
  117. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "B");
  118. UNIT_ASSERT(tuple.GetElement(1));
  119. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "X");
  120. UNIT_ASSERT(iterator.Next(tuple));
  121. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "B");
  122. UNIT_ASSERT(tuple.GetElement(1));
  123. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "Y");
  124. UNIT_ASSERT(iterator.Next(tuple));
  125. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "C");
  126. UNIT_ASSERT(tuple.GetElement(1));
  127. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "X");
  128. UNIT_ASSERT(iterator.Next(tuple));
  129. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "C");
  130. UNIT_ASSERT(tuple.GetElement(1));
  131. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "Y");
  132. UNIT_ASSERT(!iterator.Next(tuple));
  133. UNIT_ASSERT(!iterator.Next(tuple));
  134. }
  135. }
  136. Y_UNIT_TEST_LLVM(TestRight) {
  137. for (ui32 pass = 0; pass < 1; ++pass) {
  138. TSetup<LLVM> setup;
  139. TProgramBuilder& pb = *setup.PgmBuilder;
  140. const auto key1 = pb.NewDataLiteral<ui32>(1);
  141. const auto key2 = pb.NewDataLiteral<ui32>(2);
  142. const auto key3 = pb.NewDataLiteral<ui32>(2);
  143. const auto key4 = pb.NewDataLiteral<ui32>(3);
  144. const auto payload1 = pb.NewDataLiteral<NUdf::EDataSlot::String>("A");
  145. const auto payload2 = pb.NewDataLiteral<NUdf::EDataSlot::String>("B");
  146. const auto payload3 = pb.NewDataLiteral<NUdf::EDataSlot::String>("C");
  147. const auto payload4 = pb.NewDataLiteral<NUdf::EDataSlot::String>("X");
  148. const auto payload5 = pb.NewDataLiteral<NUdf::EDataSlot::String>("Y");
  149. const auto payload6 = pb.NewDataLiteral<NUdf::EDataSlot::String>("Z");
  150. const auto structType = pb.NewStructType({
  151. {"Key", pb.NewDataType(NUdf::TDataType<ui32>::Id)},
  152. {"Payload", pb.NewDataType(NUdf::TDataType<char*>::Id)}
  153. });
  154. const auto list1 = pb.NewList(structType, {
  155. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key1), "Payload", payload1),
  156. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key2), "Payload", payload2),
  157. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key3), "Payload", payload3)
  158. });
  159. const auto dict1 = pb.ToSortedDict(list1, true,
  160. [&](TRuntimeNode item) {
  161. return pb.Member(item, "Key");
  162. },
  163. [&](TRuntimeNode item) {
  164. return pb.Member(item, "Payload");
  165. });
  166. const auto list2 = pb.NewList(structType, {
  167. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key2), "Payload", payload4),
  168. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key3), "Payload", payload5),
  169. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key4), "Payload", payload6)
  170. });
  171. const auto dict2 = pb.ToSortedDict(list2, true,
  172. [&](TRuntimeNode item) {
  173. return pb.Member(item, "Key");
  174. },
  175. [&](TRuntimeNode item) {
  176. return pb.Member(item, "Payload");
  177. });
  178. const auto pgmReturn = pb.JoinDict(dict1, true, dict2, true, EJoinKind::Right);
  179. const auto graph = setup.BuildGraph(pgmReturn);
  180. const auto iterator = graph->GetValue().GetListIterator();
  181. NUdf::TUnboxedValue tuple;
  182. UNIT_ASSERT(iterator.Next(tuple));
  183. UNIT_ASSERT(tuple.GetElement(0));
  184. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "B");
  185. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "X");
  186. UNIT_ASSERT(iterator.Next(tuple));
  187. UNIT_ASSERT(tuple.GetElement(0));
  188. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "B");
  189. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "Y");
  190. UNIT_ASSERT(iterator.Next(tuple));
  191. UNIT_ASSERT(tuple.GetElement(0));
  192. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "C");
  193. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "X");
  194. UNIT_ASSERT(iterator.Next(tuple));
  195. UNIT_ASSERT(tuple.GetElement(0));
  196. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "C");
  197. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "Y");
  198. UNIT_ASSERT(iterator.Next(tuple));
  199. UNIT_ASSERT(!tuple.GetElement(0));
  200. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "Z");
  201. UNIT_ASSERT(!iterator.Next(tuple));
  202. UNIT_ASSERT(!iterator.Next(tuple));
  203. }
  204. }
  205. Y_UNIT_TEST_LLVM(TestFull) {
  206. TSetup<LLVM> setup;
  207. TProgramBuilder& pb = *setup.PgmBuilder;
  208. const auto key1 = pb.NewDataLiteral<ui32>(1);
  209. const auto key2 = pb.NewDataLiteral<ui32>(2);
  210. const auto key3 = pb.NewDataLiteral<ui32>(2);
  211. const auto key4 = pb.NewDataLiteral<ui32>(3);
  212. const auto payload1 = pb.NewDataLiteral<NUdf::EDataSlot::String>("A");
  213. const auto payload2 = pb.NewDataLiteral<NUdf::EDataSlot::String>("B");
  214. const auto payload3 = pb.NewDataLiteral<NUdf::EDataSlot::String>("C");
  215. const auto payload4 = pb.NewDataLiteral<NUdf::EDataSlot::String>("X");
  216. const auto payload5 = pb.NewDataLiteral<NUdf::EDataSlot::String>("Y");
  217. const auto payload6 = pb.NewDataLiteral<NUdf::EDataSlot::String>("Z");
  218. const auto structType = pb.NewStructType({
  219. {"Key", pb.NewDataType(NUdf::TDataType<ui32>::Id)},
  220. {"Payload", pb.NewDataType(NUdf::TDataType<char*>::Id)}
  221. });
  222. const auto list1 = pb.NewList(structType, {
  223. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key1), "Payload", payload1),
  224. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key2), "Payload", payload2),
  225. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key3), "Payload", payload3)
  226. });
  227. const auto dict1 = pb.ToSortedDict(list1, true,
  228. [&](TRuntimeNode item) {
  229. return pb.Member(item, "Key");
  230. },
  231. [&](TRuntimeNode item) {
  232. return pb.Member(item, "Payload");
  233. });
  234. const auto list2 = pb.NewList(structType, {
  235. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key2), "Payload", payload4),
  236. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key3), "Payload", payload5),
  237. pb.AddMember(pb.AddMember(pb.NewEmptyStruct(), "Key", key4), "Payload", payload6)
  238. });
  239. const auto dict2 = pb.ToSortedDict(list2, true,
  240. [&](TRuntimeNode item) {
  241. return pb.Member(item, "Key");
  242. },
  243. [&](TRuntimeNode item) {
  244. return pb.Member(item, "Payload");
  245. });
  246. const auto pgmReturn = pb.JoinDict(dict1, true, dict2, true, EJoinKind::Full);
  247. const auto graph = setup.BuildGraph(pgmReturn);
  248. const auto iterator = graph->GetValue().GetListIterator();
  249. NUdf::TUnboxedValue tuple;
  250. UNIT_ASSERT(iterator.Next(tuple));
  251. UNIT_ASSERT(tuple.GetElement(0));
  252. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "A");
  253. UNIT_ASSERT(!tuple.GetElement(1));
  254. UNIT_ASSERT(iterator.Next(tuple));
  255. UNIT_ASSERT(tuple.GetElement(0));
  256. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "B");
  257. UNIT_ASSERT(tuple.GetElement(1));
  258. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "X");
  259. UNIT_ASSERT(iterator.Next(tuple));
  260. UNIT_ASSERT(tuple.GetElement(0));
  261. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "B");
  262. UNIT_ASSERT(tuple.GetElement(1));
  263. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "Y");
  264. UNIT_ASSERT(iterator.Next(tuple));
  265. UNIT_ASSERT(tuple.GetElement(0));
  266. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "C");
  267. UNIT_ASSERT(tuple.GetElement(1));
  268. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "X");
  269. UNIT_ASSERT(iterator.Next(tuple));
  270. UNIT_ASSERT(tuple.GetElement(0));
  271. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(0), "C");
  272. UNIT_ASSERT(tuple.GetElement(1));
  273. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "Y");
  274. UNIT_ASSERT(iterator.Next(tuple));
  275. UNIT_ASSERT(!tuple.GetElement(0));
  276. UNIT_ASSERT(tuple.GetElement(1));
  277. UNBOXED_VALUE_STR_EQUAL(tuple.GetElement(1), "Z");
  278. UNIT_ASSERT(!iterator.Next(tuple));
  279. UNIT_ASSERT(!iterator.Next(tuple));
  280. }
  281. Y_UNIT_TEST_LLVM(TestInnerFlat) {
  282. TSetup<LLVM> setup;
  283. TProgramBuilder& pb = *setup.PgmBuilder;
  284. const auto key1 = pb.NewDataLiteral<ui32>(1U);
  285. const auto key2 = pb.NewDataLiteral<ui32>(2U);
  286. const auto key3 = pb.NewDataLiteral<ui32>(3U);
  287. const auto key4 = pb.NewDataLiteral<ui32>(4U);
  288. const auto key5 = pb.NewDataLiteral<ui32>(5U);
  289. const auto payload1 = pb.NewDataLiteral<NUdf::EDataSlot::String>("A");
  290. const auto payload2 = pb.NewDataLiteral<NUdf::EDataSlot::String>("B");
  291. const auto payload3 = pb.NewDataLiteral<NUdf::EDataSlot::String>("C");
  292. const auto payload4 = pb.NewDataLiteral<NUdf::EDataSlot::String>("D");
  293. const auto payload5 = pb.NewDataLiteral<NUdf::EDataSlot::String>("E");
  294. const auto payload6 = pb.NewDataLiteral<NUdf::EDataSlot::String>("F");
  295. const auto payload7 = pb.NewDataLiteral<NUdf::EDataSlot::String>("G");
  296. const auto payload8 = pb.NewDataLiteral<NUdf::EDataSlot::String>("H");
  297. const auto structType = pb.NewStructType({
  298. {"Key", pb.NewDataType(NUdf::TDataType<ui32>::Id)},
  299. {"Payload", pb.NewDataType(NUdf::TDataType<char*>::Id)}
  300. });
  301. const auto list1 = pb.NewList(structType, {
  302. pb.NewStruct(structType, {{"Key", key1}, {"Payload", payload1}}),
  303. pb.NewStruct(structType, {{"Key", key2}, {"Payload", payload2}}),
  304. pb.NewStruct(structType, {{"Key", key3}, {"Payload", payload3}}),
  305. pb.NewStruct(structType, {{"Key", key4}, {"Payload", payload4}})
  306. });
  307. const auto list2 = pb.NewList(structType, {
  308. pb.NewStruct(structType, {{"Key", key2}, {"Payload", payload8}}),
  309. pb.NewStruct(structType, {{"Key", key3}, {"Payload", payload7}}),
  310. pb.NewStruct(structType, {{"Key", key4}, {"Payload", payload6}}),
  311. pb.NewStruct(structType, {{"Key", key5}, {"Payload", payload5}})
  312. });
  313. const auto listList = pb.NewList(pb.NewListType(structType), {list1, list2});
  314. const auto pgmReturn = pb.FlatMap(listList,
  315. [&](TRuntimeNode left) {
  316. const auto dict1 = pb.ToSortedDict(left, false,
  317. [&](TRuntimeNode item) {
  318. return pb.Member(item, "Key");
  319. },
  320. [&](TRuntimeNode item) {
  321. return pb.Member(item, "Payload");
  322. }, false, 0);
  323. return pb.FlatMap(listList,
  324. [&](TRuntimeNode right) {
  325. const auto dict2 = pb.ToSortedDict(right, false,
  326. [&](TRuntimeNode item) {
  327. return pb.Member(item, "Key");
  328. },
  329. [&](TRuntimeNode item) {
  330. return pb.Member(item, "Payload");
  331. }, false, 0);
  332. return pb.JoinDict(dict1, false, dict2, false, EJoinKind::Inner);
  333. });
  334. });
  335. const auto graph = setup.BuildGraph(pgmReturn);
  336. const auto list = graph->GetValue();
  337. UNIT_ASSERT_VALUES_EQUAL(list.GetListLength(), 14U);
  338. const auto iterator = list.GetListIterator();
  339. NUdf::TUnboxedValue item;
  340. UNIT_ASSERT(iterator.Next(item));
  341. UNBOXED_VALUE_STR_EQUAL(item.GetElement(0), "A");
  342. UNBOXED_VALUE_STR_EQUAL(item.GetElement(1), "A");
  343. UNIT_ASSERT(iterator.Next(item));
  344. UNBOXED_VALUE_STR_EQUAL(item.GetElement(0), "B");
  345. UNBOXED_VALUE_STR_EQUAL(item.GetElement(1), "B");
  346. UNIT_ASSERT(iterator.Next(item));
  347. UNBOXED_VALUE_STR_EQUAL(item.GetElement(0), "C");
  348. UNBOXED_VALUE_STR_EQUAL(item.GetElement(1), "C");
  349. UNIT_ASSERT(iterator.Next(item));
  350. UNBOXED_VALUE_STR_EQUAL(item.GetElement(0), "D");
  351. UNBOXED_VALUE_STR_EQUAL(item.GetElement(1), "D");
  352. UNIT_ASSERT(iterator.Next(item));
  353. UNBOXED_VALUE_STR_EQUAL(item.GetElement(0), "B");
  354. UNBOXED_VALUE_STR_EQUAL(item.GetElement(1), "H");
  355. UNIT_ASSERT(iterator.Next(item));
  356. UNBOXED_VALUE_STR_EQUAL(item.GetElement(0), "C");
  357. UNBOXED_VALUE_STR_EQUAL(item.GetElement(1), "G");
  358. UNIT_ASSERT(iterator.Next(item));
  359. UNBOXED_VALUE_STR_EQUAL(item.GetElement(0), "D");
  360. UNBOXED_VALUE_STR_EQUAL(item.GetElement(1), "F");
  361. UNIT_ASSERT(iterator.Next(item));
  362. UNBOXED_VALUE_STR_EQUAL(item.GetElement(0), "H");
  363. UNBOXED_VALUE_STR_EQUAL(item.GetElement(1), "B");
  364. UNIT_ASSERT(iterator.Next(item));
  365. UNBOXED_VALUE_STR_EQUAL(item.GetElement(0), "G");
  366. UNBOXED_VALUE_STR_EQUAL(item.GetElement(1), "C");
  367. UNIT_ASSERT(iterator.Next(item));
  368. UNBOXED_VALUE_STR_EQUAL(item.GetElement(0), "F");
  369. UNBOXED_VALUE_STR_EQUAL(item.GetElement(1), "D");
  370. UNIT_ASSERT(iterator.Next(item));
  371. UNBOXED_VALUE_STR_EQUAL(item.GetElement(0), "H");
  372. UNBOXED_VALUE_STR_EQUAL(item.GetElement(1), "H");
  373. UNIT_ASSERT(iterator.Next(item));
  374. UNBOXED_VALUE_STR_EQUAL(item.GetElement(0), "G");
  375. UNBOXED_VALUE_STR_EQUAL(item.GetElement(1), "G");
  376. UNIT_ASSERT(iterator.Next(item));
  377. UNBOXED_VALUE_STR_EQUAL(item.GetElement(0), "F");
  378. UNBOXED_VALUE_STR_EQUAL(item.GetElement(1), "F");
  379. UNIT_ASSERT(iterator.Next(item));
  380. UNBOXED_VALUE_STR_EQUAL(item.GetElement(0), "E");
  381. UNBOXED_VALUE_STR_EQUAL(item.GetElement(1), "E");
  382. UNIT_ASSERT(!iterator.Next(item));
  383. UNIT_ASSERT(!iterator.Next(item));
  384. }
  385. }
  386. }
  387. }