testDuplicate.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. #include "testBase.h"
  2. static void testDuplicateEdgeCases(void)
  3. {
  4. // 复制 NULL
  5. TEST_ASSERT_NULL_MESSAGE(RyanJsonDuplicate(NULL), "Duplicate(NULL) 应返回 NULL");
  6. // 深拷贝验证
  7. // 创建一个嵌套 Object: root -> child -> val
  8. RyanJson_t root = RyanJsonCreateObject();
  9. RyanJson_t child = RyanJsonCreateObject();
  10. RyanJsonAddIntToObject(child, "val", 100);
  11. RyanJsonAddItemToObject(root, "child", child);
  12. // 复制整个树
  13. RyanJson_t rootCopy = RyanJsonDuplicate(root);
  14. TEST_ASSERT_NOT_NULL(rootCopy);
  15. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(root, rootCopy), "复制后内容应一致");
  16. // 修改副本的深层值
  17. RyanJson_t childCopy = RyanJsonGetObjectToKey(rootCopy, "child");
  18. RyanJsonChangeIntValue(RyanJsonGetObjectToKey(childCopy, "val"), 200);
  19. // 验证:原件应保持 100,副本为 200
  20. TEST_ASSERT_EQUAL_INT_MESSAGE(100, RyanJsonGetIntValue(RyanJsonGetObjectToKey(root, "child", "val")), "修改副本不应影响原件");
  21. TEST_ASSERT_EQUAL_INT_MESSAGE(200, RyanJsonGetIntValue(RyanJsonGetObjectToKey(rootCopy, "child", "val")), "副本修改失效");
  22. RyanJsonDelete(root);
  23. RyanJsonDelete(rootCopy);
  24. }
  25. static void testDuplicateEmptyAndSpecial(void)
  26. {
  27. // 复制空 Object 和空 Array
  28. RyanJson_t emptyObj = RyanJsonCreateObject();
  29. RyanJson_t dupEmptyObj = RyanJsonDuplicate(emptyObj);
  30. TEST_ASSERT_NOT_NULL(dupEmptyObj);
  31. TEST_ASSERT_TRUE(RyanJsonIsObject(dupEmptyObj));
  32. TEST_ASSERT_EQUAL_INT(0, RyanJsonGetSize(dupEmptyObj));
  33. RyanJsonDelete(emptyObj);
  34. RyanJsonDelete(dupEmptyObj);
  35. RyanJson_t emptyArr = RyanJsonCreateArray();
  36. RyanJson_t dupEmptyArr = RyanJsonDuplicate(emptyArr);
  37. TEST_ASSERT_NOT_NULL(dupEmptyArr);
  38. TEST_ASSERT_TRUE(RyanJsonIsArray(dupEmptyArr));
  39. TEST_ASSERT_EQUAL_INT(0, RyanJsonGetSize(dupEmptyArr));
  40. RyanJsonDelete(emptyArr);
  41. RyanJsonDelete(dupEmptyArr);
  42. // 复制包含特殊值的 Object
  43. RyanJson_t specialObj = RyanJsonCreateObject();
  44. RyanJsonAddNullToObject(specialObj, "null");
  45. RyanJsonAddBoolToObject(specialObj, "true", RyanJsonTrue);
  46. RyanJsonAddBoolToObject(specialObj, "false", RyanJsonFalse);
  47. RyanJsonAddStringToObject(specialObj, "emptyStr", "");
  48. RyanJson_t dupSpecial = RyanJsonDuplicate(specialObj);
  49. TEST_ASSERT_TRUE(RyanJsonCompare(specialObj, dupSpecial));
  50. RyanJsonDelete(specialObj);
  51. RyanJsonDelete(dupSpecial);
  52. }
  53. static void testDuplicateFullScenarios(void)
  54. {
  55. RyanJson_t json, dupItem, jsonRoot = NULL;
  56. char jsonstr[] = "{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,\"boolFalse\":false,\"null\":null,\"item\":"
  57. "{\"inter\":16,\"double\":16."
  58. "89,\"string\":\"hello\","
  59. "\"boolTrue\":true,\"boolFalse\":false,\"null\":null},\"arrayInt\":[16,16,16,16,16],\"arrayDouble\":[16.89,16.89,"
  60. "16.89,16.89,16.89],"
  61. "\"arrayString\":[\"hello\",\"hello\","
  62. "\"hello\",\"hello\",\"hello\"],\"array\":[16,16.89,\"hello\",true,false,null],\"arrayItem\":[{\"inter\":16,"
  63. "\"double\":16.89,\"string\":"
  64. "\"hello\",\"boolTrue\":true,"
  65. "\"boolFalse\":false,\"null\":null},{\"inter\":16,\"double\":16.89,\"string\":\"hello\",\"boolTrue\":true,"
  66. "\"boolFalse\":false,\"null\":null}]}";
  67. /**
  68. * @brief 普通类型复制测试
  69. */
  70. json = RyanJsonParse(jsonstr);
  71. TEST_ASSERT_NOT_NULL_MESSAGE(json, "解析 Json 失败");
  72. dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "inter"));
  73. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(dupItem, RyanJsonGetObjectToKey(json, "inter")), "普通类型复制后比较失败");
  74. RyanJsonDelete(dupItem);
  75. dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "inter"));
  76. TEST_ASSERT_FALSE_MESSAGE(RyanJsonAddItemToObject(json, "test", dupItem), "AddItemToObject 不应接受标量 item");
  77. dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "inter"));
  78. TEST_ASSERT_FALSE_MESSAGE(RyanJsonAddItemToObject(json, "test", dupItem), "AddItemToObject 不应接受标量 item");
  79. RyanJsonDelete(json);
  80. /**
  81. * @brief Object 类型复制测试
  82. */
  83. json = RyanJsonParse(jsonstr);
  84. TEST_ASSERT_NOT_NULL_MESSAGE(json, "重新解析 Json 失败");
  85. dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item"));
  86. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(dupItem, RyanJsonGetObjectToKey(json, "item")), "Object 类型复制后比较失败");
  87. RyanJsonDelete(dupItem);
  88. dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item"));
  89. RyanJsonAddItemToObject(json, "test", dupItem);
  90. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "item")),
  91. "Object 类型复制并添加后比较失败");
  92. RyanJsonDelete(RyanJsonDetachByKey(json, "test"));
  93. dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "item"));
  94. RyanJsonAddItemToObject(json, "test", dupItem);
  95. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "item")),
  96. "Object 类型复制并添加后删除再添加比较失败");
  97. RyanJsonDelete(json);
  98. /**
  99. * @brief Array 类型复制测试
  100. */
  101. json = RyanJsonParse(jsonstr);
  102. TEST_ASSERT_NOT_NULL_MESSAGE(json, "重新解析 Json 失败 (Array 测试)");
  103. dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "arrayItem"));
  104. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(dupItem, RyanJsonGetObjectToKey(json, "arrayItem")), "Array 类型复制后比较失败");
  105. RyanJsonDelete(dupItem);
  106. dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "arrayItem"));
  107. RyanJsonAddItemToObject(json, "test", dupItem);
  108. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "arrayItem")),
  109. "Array 类型复制并添加后比较失败");
  110. RyanJsonDelete(RyanJsonDetachByKey(json, "test"));
  111. dupItem = RyanJsonDuplicate(RyanJsonGetObjectToKey(json, "arrayItem"));
  112. RyanJsonAddItemToObject(json, "test", dupItem);
  113. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(RyanJsonGetObjectToKey(json, "test"), RyanJsonGetObjectToKey(json, "arrayItem")),
  114. "Array 类型复制并添加后删除再添加比较失败");
  115. RyanJsonDelete(json);
  116. /**
  117. * @brief 循环压力与内存泄漏测试
  118. */
  119. json = RyanJsonParse(jsonstr);
  120. jsonRoot = RyanJsonCreateObject();
  121. RyanJsonAddBoolToObject(jsonRoot, "arrayItem", RyanJsonTrue);
  122. int32_t initialUse = vallocGetUse();
  123. for (uint8_t i = 0; i < 10; i++)
  124. {
  125. dupItem = RyanJsonParse(jsonstr);
  126. TEST_ASSERT_NOT_NULL_MESSAGE(dupItem, "循环中解析失败");
  127. RyanJsonReplaceByKey(jsonRoot, "arrayItem", RyanJsonDuplicate(dupItem));
  128. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(RyanJsonGetObjectToKey(jsonRoot, "arrayItem"), dupItem), "循环中替换并比较失败");
  129. RyanJsonReplaceByKey(json, "arrayItem", RyanJsonDuplicate(RyanJsonGetObjectByKey(dupItem, "item")));
  130. TEST_ASSERT_TRUE_MESSAGE(
  131. RyanJsonCompare(RyanJsonGetObjectToKey(json, "arrayItem"), RyanJsonGetObjectByKey(dupItem, "item")),
  132. "循环中嵌套替换并比较失败");
  133. RyanJsonDelete(dupItem);
  134. if (i > 0) { TEST_ASSERT_EQUAL_INT_MESSAGE(initialUse, vallocGetUse(), "内存泄漏检测失败"); }
  135. initialUse = vallocGetUse();
  136. }
  137. RyanJsonDelete(json);
  138. RyanJsonDelete(jsonRoot);
  139. }
  140. static void testDuplicateMassiveStress(void)
  141. {
  142. // 压力测试:大 Array 复制
  143. int32_t bigSize = 2000;
  144. RyanJson_t bigArr = RyanJsonCreateArray();
  145. for (int32_t i = 0; i < bigSize; i++)
  146. {
  147. RyanJsonAddIntToArray(bigArr, i);
  148. }
  149. RyanJson_t dupBigArr = RyanJsonDuplicate(bigArr);
  150. TEST_ASSERT_EQUAL_INT(bigSize, RyanJsonGetArraySize(dupBigArr));
  151. #if true == RyanJsonDefaultAddAtHead
  152. TEST_ASSERT_EQUAL_INT(0, RyanJsonGetIntValue(RyanJsonGetObjectByIndex(dupBigArr, bigSize - 1)));
  153. #else
  154. TEST_ASSERT_EQUAL_INT(bigSize - 1, RyanJsonGetIntValue(RyanJsonGetObjectByIndex(dupBigArr, bigSize - 1)));
  155. #endif
  156. RyanJsonDelete(bigArr);
  157. RyanJsonDelete(dupBigArr);
  158. }
  159. static void testDuplicateCrossContainerMoveIsolationChain(void)
  160. {
  161. // 复杂链路:
  162. // Parse -> Duplicate(work) -> DetachByKey/DetachByIndex -> Change -> Insert/AddItemToObject
  163. // -> ReplaceByKey -> Compare(期望文档) -> 校验 original 隔离性。
  164. // 目标:
  165. // - 验证副本上的跨容器迁移不会污染原树;
  166. // - 验证“分离+改写+重挂载”后结构可稳定收敛到期望文档;
  167. // - 验证复杂链路后依旧可 Print/Parse 往返。
  168. const char *source =
  169. "{\"left\":{\"node\":{\"v\":1},\"keep\":2},\"right\":[{\"id\":\"a\"},{\"id\":\"b\"}],\"map\":{},\"meta\":{\"ver\":1}}";
  170. const char *expectText = "{\"left\":{\"keep\":\"k\",\"fromRight\":{\"id\":\"b\"}},\"right\":[{\"id\":\"a\"}],\"map\":{\"node2\":{"
  171. "\"v\":9}},\"meta\":{\"ver\":2}}";
  172. RyanJson_t original = RyanJsonParse(source);
  173. TEST_ASSERT_NOT_NULL_MESSAGE(original, "Duplicate 迁移样本解析失败");
  174. RyanJson_t work = RyanJsonDuplicate(original);
  175. TEST_ASSERT_NOT_NULL_MESSAGE(work, "Duplicate 迁移样本拷贝失败");
  176. RyanJson_t left = RyanJsonGetObjectToKey(work, "left");
  177. RyanJson_t right = RyanJsonGetObjectToKey(work, "right");
  178. RyanJson_t map = RyanJsonGetObjectToKey(work, "map");
  179. RyanJson_t meta = RyanJsonGetObjectToKey(work, "meta");
  180. TEST_ASSERT_NOT_NULL(left);
  181. TEST_ASSERT_NOT_NULL(right);
  182. TEST_ASSERT_NOT_NULL(map);
  183. TEST_ASSERT_NOT_NULL(meta);
  184. RyanJson_t movedNode = RyanJsonDetachByKey(left, "node");
  185. TEST_ASSERT_NOT_NULL_MESSAGE(movedNode, "分离 left.node 失败");
  186. TEST_ASSERT_TRUE(RyanJsonIsDetachedItem(movedNode));
  187. TEST_ASSERT_TRUE(RyanJsonChangeIntValue(RyanJsonGetObjectToKey(movedNode, "v"), 9));
  188. TEST_ASSERT_TRUE(RyanJsonChangeKey(movedNode, "node2"));
  189. TEST_ASSERT_TRUE_MESSAGE(RyanJsonInsert(map, 0, movedNode), "插入 map.node2 失败");
  190. RyanJson_t movedRight = RyanJsonDetachByIndex(right, 1);
  191. TEST_ASSERT_NOT_NULL_MESSAGE(movedRight, "分离 right[1] 失败");
  192. TEST_ASSERT_TRUE_MESSAGE(RyanJsonAddItemToObject(left, "fromRight", movedRight), "将分离 ArrayObject 挂载到 left.fromRight 失败");
  193. TEST_ASSERT_TRUE_MESSAGE(RyanJsonReplaceByKey(left, "keep", RyanJsonCreateString("keep", "k")), "替换 left.keep 失败");
  194. TEST_ASSERT_TRUE_MESSAGE(RyanJsonReplaceByKey(meta, "ver", RyanJsonCreateInt("ver", 2)), "替换 meta.ver 失败");
  195. RyanJson_t expect = RyanJsonParse(expectText);
  196. TEST_ASSERT_NOT_NULL(expect);
  197. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(work, expect), "副本迁移链路结果与期望文档不一致");
  198. // 原树隔离性校验:不应受到 work 上的链路变更影响。
  199. TEST_ASSERT_TRUE(RyanJsonHasObjectToKey(original, "left", "node", "v"));
  200. TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(RyanJsonGetObjectToKey(original, "left", "node", "v")));
  201. TEST_ASSERT_EQUAL_INT(2, RyanJsonGetIntValue(RyanJsonGetObjectToKey(original, "left", "keep")));
  202. TEST_ASSERT_EQUAL_UINT32(2U, RyanJsonGetArraySize(RyanJsonGetObjectToKey(original, "right")));
  203. TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(RyanJsonGetObjectToKey(original, "meta", "ver")));
  204. TEST_ASSERT_FALSE_MESSAGE(RyanJsonCompare(original, work), "修改后的副本不应与原树相等");
  205. char *printed = RyanJsonPrint(work, 192, RyanJsonFalse, NULL);
  206. TEST_ASSERT_NOT_NULL(printed);
  207. RyanJson_t roundtrip = RyanJsonParse(printed);
  208. TEST_ASSERT_NOT_NULL(roundtrip);
  209. TEST_ASSERT_TRUE(RyanJsonCompare(work, roundtrip));
  210. RyanJsonDelete(roundtrip);
  211. RyanJsonFree(printed);
  212. RyanJsonDelete(expect);
  213. RyanJsonDelete(work);
  214. RyanJsonDelete(original);
  215. }
  216. static void testDuplicateDetachedNodeDualAttachWithoutAlias(void)
  217. {
  218. // 复杂链路:
  219. // Parse -> DetachByKey -> Duplicate(detached) -> Change 两份副本不同值/不同 key
  220. // -> Insert(Object) 双挂载 -> Compare(期望文档)。
  221. // 目标:
  222. // - 验证 detached 节点可被 Duplicate;
  223. // - 验证 duplicate 后两份节点无别名,可独立修改;
  224. // - 验证双挂载后的结构和值符合预期。
  225. const char *source = "{\"obj\":{\"a\":{\"v\":1}},\"meta\":0}";
  226. const char *expectText = "{\"obj\":{\"a2\":{\"v\":2},\"a3\":{\"v\":3}},\"meta\":0}";
  227. RyanJson_t root = RyanJsonParse(source);
  228. TEST_ASSERT_NOT_NULL_MESSAGE(root, "detached duplicate 样本解析失败");
  229. RyanJson_t obj = RyanJsonGetObjectToKey(root, "obj");
  230. TEST_ASSERT_NOT_NULL(obj);
  231. RyanJson_t detached = RyanJsonDetachByKey(obj, "a");
  232. TEST_ASSERT_NOT_NULL_MESSAGE(detached, "分离 obj.a 失败");
  233. TEST_ASSERT_TRUE(RyanJsonIsDetachedItem(detached));
  234. RyanJson_t detachedCopy = RyanJsonDuplicate(detached);
  235. TEST_ASSERT_NOT_NULL_MESSAGE(detachedCopy, "Duplicate(detached) 失败");
  236. TEST_ASSERT_TRUE(RyanJsonChangeKey(detached, "a2"));
  237. TEST_ASSERT_TRUE(RyanJsonChangeIntValue(RyanJsonGetObjectToKey(detached, "v"), 2));
  238. TEST_ASSERT_TRUE(RyanJsonChangeKey(detachedCopy, "a3"));
  239. TEST_ASSERT_TRUE(RyanJsonChangeIntValue(RyanJsonGetObjectToKey(detachedCopy, "v"), 3));
  240. TEST_ASSERT_TRUE_MESSAGE(RyanJsonInsert(obj, 0, detached), "插入 obj.a2 失败");
  241. TEST_ASSERT_TRUE_MESSAGE(RyanJsonInsert(obj, 1, detachedCopy), "插入 obj.a3 失败");
  242. TEST_ASSERT_NULL(RyanJsonGetObjectToKey(obj, "a"));
  243. TEST_ASSERT_EQUAL_INT(2, RyanJsonGetIntValue(RyanJsonGetObjectToKey(obj, "a2", "v")));
  244. TEST_ASSERT_EQUAL_INT(3, RyanJsonGetIntValue(RyanJsonGetObjectToKey(obj, "a3", "v")));
  245. RyanJson_t expect = RyanJsonParse(expectText);
  246. TEST_ASSERT_NOT_NULL(expect);
  247. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(root, expect), "detached duplicate 双挂载结果与期望文档不一致");
  248. char *printed = RyanJsonPrint(root, 128, RyanJsonFalse, NULL);
  249. TEST_ASSERT_NOT_NULL(printed);
  250. RyanJson_t roundtrip = RyanJsonParse(printed);
  251. TEST_ASSERT_NOT_NULL(roundtrip);
  252. TEST_ASSERT_TRUE(RyanJsonCompare(root, roundtrip));
  253. RyanJsonDelete(roundtrip);
  254. RyanJsonFree(printed);
  255. RyanJsonDelete(expect);
  256. RyanJsonDelete(root);
  257. }
  258. static void testDuplicateOomRecoveryAndSourceImmutability(void)
  259. {
  260. // 复杂链路:
  261. // Parse -> Duplicate(OOM失败) -> 恢复 hooks -> Duplicate(成功) -> 修改副本
  262. // -> 校验原树不变。
  263. // 目标:
  264. // - 验证 Duplicate 失败不会破坏源树;
  265. // - 验证 OOM 恢复后 Duplicate 能继续成功;
  266. // - 验证副本修改与原树隔离。
  267. const char *source = "{\"cfg\":{\"mode\":\"a\",\"retry\":1},\"arr\":[1,2]}";
  268. RyanJson_t root = RyanJsonParse(source);
  269. TEST_ASSERT_NOT_NULL_MESSAGE(root, "OOM duplicate 样本解析失败");
  270. RyanJson_t baseline = RyanJsonDuplicate(root);
  271. TEST_ASSERT_NOT_NULL_MESSAGE(baseline, "OOM duplicate 基线快照失败");
  272. UNITY_TEST_OOM_BEGIN(0);
  273. RyanJson_t dupFail = RyanJsonDuplicate(root);
  274. UNITY_TEST_OOM_END();
  275. TEST_ASSERT_NULL_MESSAGE(dupFail, "OOM 注入下 Duplicate 应失败");
  276. TEST_ASSERT_TRUE_MESSAGE(RyanJsonCompare(root, baseline), "Duplicate 失败后源树语义不应改变");
  277. RyanJson_t dupOk = RyanJsonDuplicate(root);
  278. TEST_ASSERT_NOT_NULL_MESSAGE(dupOk, "恢复 hooks 后 Duplicate 应成功");
  279. TEST_ASSERT_TRUE(RyanJsonChangeStringValue(RyanJsonGetObjectToKey(dupOk, "cfg", "mode"), "b"));
  280. TEST_ASSERT_TRUE(RyanJsonChangeIntValue(RyanJsonGetObjectToKey(dupOk, "cfg", "retry"), 9));
  281. TEST_ASSERT_TRUE(RyanJsonReplaceByIndex(RyanJsonGetObjectToKey(dupOk, "arr"), 1, RyanJsonCreateInt(NULL, 7)));
  282. TEST_ASSERT_EQUAL_STRING("a", RyanJsonGetStringValue(RyanJsonGetObjectToKey(root, "cfg", "mode")));
  283. TEST_ASSERT_EQUAL_INT(1, RyanJsonGetIntValue(RyanJsonGetObjectToKey(root, "cfg", "retry")));
  284. TEST_ASSERT_EQUAL_INT(2, RyanJsonGetIntValue(RyanJsonGetObjectToIndex(RyanJsonGetObjectToKey(root, "arr"), 1)));
  285. TEST_ASSERT_FALSE_MESSAGE(RyanJsonCompare(root, dupOk), "修改后的副本不应与原树相等");
  286. RyanJsonDelete(dupOk);
  287. RyanJsonDelete(baseline);
  288. RyanJsonDelete(root);
  289. }
  290. void testDuplicateRunner(void)
  291. {
  292. UnitySetTestFile(__FILE__);
  293. RUN_TEST(testDuplicateEdgeCases);
  294. RUN_TEST(testDuplicateEmptyAndSpecial);
  295. RUN_TEST(testDuplicateFullScenarios);
  296. RUN_TEST(testDuplicateMassiveStress);
  297. RUN_TEST(testDuplicateCrossContainerMoveIsolationChain);
  298. RUN_TEST(testDuplicateDetachedNodeDualAttachWithoutAlias);
  299. RUN_TEST(testDuplicateOomRecoveryAndSourceImmutability);
  300. }