@fluidframework/merge-tree 2.0.0-internal.8.0.0 → 2.0.0-rc.1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (481) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +0 -6
  3. package/api-extractor-esm.json +17 -0
  4. package/api-extractor-lint.json +1 -10
  5. package/api-extractor.json +0 -4
  6. package/api-report/merge-tree.api.md +4 -9
  7. package/dist/client.d.ts +0 -7
  8. package/dist/client.d.ts.map +1 -1
  9. package/dist/client.js +0 -7
  10. package/dist/client.js.map +1 -1
  11. package/dist/merge-tree-alpha.d.ts +27 -12
  12. package/dist/merge-tree-beta.d.ts +0 -16
  13. package/dist/merge-tree-public.d.ts +0 -16
  14. package/dist/merge-tree-untrimmed.d.ts +5 -29
  15. package/dist/mergeTree.d.ts +0 -17
  16. package/dist/mergeTree.d.ts.map +1 -1
  17. package/dist/mergeTree.js +0 -130
  18. package/dist/mergeTree.js.map +1 -1
  19. package/dist/ops.d.ts +1 -1
  20. package/dist/ops.js +1 -1
  21. package/dist/ops.js.map +1 -1
  22. package/dist/revertibles.d.ts +4 -4
  23. package/dist/revertibles.js +3 -3
  24. package/dist/revertibles.js.map +1 -1
  25. package/dist/test/Insertion.perf.spec.d.ts +6 -0
  26. package/dist/test/Insertion.perf.spec.d.ts.map +1 -0
  27. package/dist/test/Insertion.perf.spec.js +113 -0
  28. package/dist/test/Insertion.perf.spec.js.map +1 -0
  29. package/dist/test/PartialLengths.perf.spec.d.ts +6 -0
  30. package/dist/test/PartialLengths.perf.spec.d.ts.map +1 -0
  31. package/dist/test/PartialLengths.perf.spec.js +67 -0
  32. package/dist/test/PartialLengths.perf.spec.js.map +1 -0
  33. package/dist/test/Removal.perf.spec.d.ts +6 -0
  34. package/dist/test/Removal.perf.spec.d.ts.map +1 -0
  35. package/dist/test/Removal.perf.spec.js +166 -0
  36. package/dist/test/Removal.perf.spec.js.map +1 -0
  37. package/dist/test/Snapshot.perf.spec.d.ts +6 -0
  38. package/dist/test/Snapshot.perf.spec.d.ts.map +1 -0
  39. package/dist/test/Snapshot.perf.spec.js +33 -0
  40. package/dist/test/Snapshot.perf.spec.js.map +1 -0
  41. package/dist/test/attributionCollection.perf.spec.d.ts +6 -0
  42. package/dist/test/attributionCollection.perf.spec.d.ts.map +1 -0
  43. package/dist/test/attributionCollection.perf.spec.js +231 -0
  44. package/dist/test/attributionCollection.perf.spec.js.map +1 -0
  45. package/dist/test/attributionCollection.spec.d.ts +6 -0
  46. package/dist/test/attributionCollection.spec.d.ts.map +1 -0
  47. package/dist/test/attributionCollection.spec.js +486 -0
  48. package/dist/test/attributionCollection.spec.js.map +1 -0
  49. package/dist/test/attributionPolicy.spec.d.ts +6 -0
  50. package/dist/test/attributionPolicy.spec.d.ts.map +1 -0
  51. package/dist/test/attributionPolicy.spec.js +189 -0
  52. package/dist/test/attributionPolicy.spec.js.map +1 -0
  53. package/dist/test/beastTest.d.ts +54 -0
  54. package/dist/test/beastTest.d.ts.map +1 -0
  55. package/dist/test/beastTest.js +1333 -0
  56. package/dist/test/beastTest.js.map +1 -0
  57. package/dist/test/client.annotateMarker.spec.d.ts +6 -0
  58. package/dist/test/client.annotateMarker.spec.d.ts.map +1 -0
  59. package/dist/test/client.annotateMarker.spec.js +45 -0
  60. package/dist/test/client.annotateMarker.spec.js.map +1 -0
  61. package/dist/test/client.apis.d.ts +7 -0
  62. package/dist/test/client.apis.d.ts.map +1 -0
  63. package/dist/test/client.apis.js +72 -0
  64. package/dist/test/client.apis.js.map +1 -0
  65. package/dist/test/client.applyMsg.spec.d.ts +6 -0
  66. package/dist/test/client.applyMsg.spec.d.ts.map +1 -0
  67. package/dist/test/client.applyMsg.spec.js +500 -0
  68. package/dist/test/client.applyMsg.spec.js.map +1 -0
  69. package/dist/test/client.applyStashedOpFarm.spec.d.ts +12 -0
  70. package/dist/test/client.applyStashedOpFarm.spec.d.ts.map +1 -0
  71. package/dist/test/client.applyStashedOpFarm.spec.js +144 -0
  72. package/dist/test/client.applyStashedOpFarm.spec.js.map +1 -0
  73. package/dist/test/client.attributionFarm.spec.d.ts +7 -0
  74. package/dist/test/client.attributionFarm.spec.d.ts.map +1 -0
  75. package/dist/test/client.attributionFarm.spec.js +96 -0
  76. package/dist/test/client.attributionFarm.spec.js.map +1 -0
  77. package/dist/test/client.conflictFarm.spec.d.ts +15 -0
  78. package/dist/test/client.conflictFarm.spec.d.ts.map +1 -0
  79. package/dist/test/client.conflictFarm.spec.js +88 -0
  80. package/dist/test/client.conflictFarm.spec.js.map +1 -0
  81. package/dist/test/client.getPosition.spec.d.ts +6 -0
  82. package/dist/test/client.getPosition.spec.d.ts.map +1 -0
  83. package/dist/test/client.getPosition.spec.js +54 -0
  84. package/dist/test/client.getPosition.spec.js.map +1 -0
  85. package/dist/test/client.localReference.spec.d.ts +6 -0
  86. package/dist/test/client.localReference.spec.d.ts.map +1 -0
  87. package/dist/test/client.localReference.spec.js +439 -0
  88. package/dist/test/client.localReference.spec.js.map +1 -0
  89. package/dist/test/client.localReferenceFarm.spec.d.ts +6 -0
  90. package/dist/test/client.localReferenceFarm.spec.d.ts.map +1 -0
  91. package/dist/test/client.localReferenceFarm.spec.js +88 -0
  92. package/dist/test/client.localReferenceFarm.spec.js.map +1 -0
  93. package/dist/test/client.rebasePosition.spec.d.ts +6 -0
  94. package/dist/test/client.rebasePosition.spec.d.ts.map +1 -0
  95. package/dist/test/client.rebasePosition.spec.js +102 -0
  96. package/dist/test/client.rebasePosition.spec.js.map +1 -0
  97. package/dist/test/client.reconnectFarm.spec.d.ts +12 -0
  98. package/dist/test/client.reconnectFarm.spec.d.ts.map +1 -0
  99. package/dist/test/client.reconnectFarm.spec.js +91 -0
  100. package/dist/test/client.reconnectFarm.spec.js.map +1 -0
  101. package/dist/test/client.replay.spec.d.ts +6 -0
  102. package/dist/test/client.replay.spec.d.ts.map +1 -0
  103. package/dist/test/client.replay.spec.js +85 -0
  104. package/dist/test/client.replay.spec.js.map +1 -0
  105. package/dist/test/client.rollback.spec.d.ts +6 -0
  106. package/dist/test/client.rollback.spec.d.ts.map +1 -0
  107. package/dist/test/client.rollback.spec.js +453 -0
  108. package/dist/test/client.rollback.spec.js.map +1 -0
  109. package/dist/test/client.rollbackFarm.spec.d.ts +6 -0
  110. package/dist/test/client.rollbackFarm.spec.d.ts.map +1 -0
  111. package/dist/test/client.rollbackFarm.spec.js +48 -0
  112. package/dist/test/client.rollbackFarm.spec.js.map +1 -0
  113. package/dist/test/client.searchForMarker.spec.d.ts +6 -0
  114. package/dist/test/client.searchForMarker.spec.d.ts.map +1 -0
  115. package/dist/test/client.searchForMarker.spec.js +446 -0
  116. package/dist/test/client.searchForMarker.spec.js.map +1 -0
  117. package/dist/test/client.walkSegments.spec.d.ts +6 -0
  118. package/dist/test/client.walkSegments.spec.d.ts.map +1 -0
  119. package/dist/test/client.walkSegments.spec.js +54 -0
  120. package/dist/test/client.walkSegments.spec.js.map +1 -0
  121. package/dist/test/collections.list.spec.d.ts +6 -0
  122. package/dist/test/collections.list.spec.d.ts.map +1 -0
  123. package/dist/test/collections.list.spec.js +84 -0
  124. package/dist/test/collections.list.spec.js.map +1 -0
  125. package/dist/test/createInsertOnlyAttributionPolicy.spec.d.ts +6 -0
  126. package/dist/test/createInsertOnlyAttributionPolicy.spec.d.ts.map +1 -0
  127. package/dist/test/createInsertOnlyAttributionPolicy.spec.js +35 -0
  128. package/dist/test/createInsertOnlyAttributionPolicy.spec.js.map +1 -0
  129. package/dist/test/index.d.ts +13 -0
  130. package/dist/test/index.d.ts.map +1 -0
  131. package/dist/test/index.js +88 -0
  132. package/dist/test/index.js.map +1 -0
  133. package/dist/test/mergeTree.annotate.deltaCallback.spec.d.ts +6 -0
  134. package/dist/test/mergeTree.annotate.deltaCallback.spec.d.ts.map +1 -0
  135. package/dist/test/mergeTree.annotate.deltaCallback.spec.js +142 -0
  136. package/dist/test/mergeTree.annotate.deltaCallback.spec.js.map +1 -0
  137. package/dist/test/mergeTree.annotate.spec.d.ts +6 -0
  138. package/dist/test/mergeTree.annotate.spec.d.ts.map +1 -0
  139. package/dist/test/mergeTree.annotate.spec.js +448 -0
  140. package/dist/test/mergeTree.annotate.spec.js.map +1 -0
  141. package/dist/test/mergeTree.insert.deltaCallback.spec.d.ts +6 -0
  142. package/dist/test/mergeTree.insert.deltaCallback.spec.d.ts.map +1 -0
  143. package/dist/test/mergeTree.insert.deltaCallback.spec.js +126 -0
  144. package/dist/test/mergeTree.insert.deltaCallback.spec.js.map +1 -0
  145. package/dist/test/mergeTree.insertingWalk.spec.d.ts +6 -0
  146. package/dist/test/mergeTree.insertingWalk.spec.d.ts.map +1 -0
  147. package/dist/test/mergeTree.insertingWalk.spec.js +279 -0
  148. package/dist/test/mergeTree.insertingWalk.spec.js.map +1 -0
  149. package/dist/test/mergeTree.markRangeRemoved.deltaCallback.spec.d.ts +6 -0
  150. package/dist/test/mergeTree.markRangeRemoved.deltaCallback.spec.d.ts.map +1 -0
  151. package/dist/test/mergeTree.markRangeRemoved.deltaCallback.spec.js +178 -0
  152. package/dist/test/mergeTree.markRangeRemoved.deltaCallback.spec.js.map +1 -0
  153. package/dist/test/mergeTree.markRangeRemoved.spec.d.ts +6 -0
  154. package/dist/test/mergeTree.markRangeRemoved.spec.d.ts.map +1 -0
  155. package/dist/test/mergeTree.markRangeRemoved.spec.js +130 -0
  156. package/dist/test/mergeTree.markRangeRemoved.spec.js.map +1 -0
  157. package/dist/test/mergeTree.walk.spec.d.ts +6 -0
  158. package/dist/test/mergeTree.walk.spec.d.ts.map +1 -0
  159. package/dist/test/mergeTree.walk.spec.js +63 -0
  160. package/dist/test/mergeTree.walk.spec.js.map +1 -0
  161. package/dist/test/mergeTree.zamboni.spec.d.ts +6 -0
  162. package/dist/test/mergeTree.zamboni.spec.d.ts.map +1 -0
  163. package/dist/test/mergeTree.zamboni.spec.js +52 -0
  164. package/dist/test/mergeTree.zamboni.spec.js.map +1 -0
  165. package/dist/test/mergeTreeOperationRunner.d.ts +63 -0
  166. package/dist/test/mergeTreeOperationRunner.d.ts.map +1 -0
  167. package/dist/test/mergeTreeOperationRunner.js +245 -0
  168. package/dist/test/mergeTreeOperationRunner.js.map +1 -0
  169. package/dist/test/mergeTreeOperationRunner.spec.d.ts +6 -0
  170. package/dist/test/mergeTreeOperationRunner.spec.d.ts.map +1 -0
  171. package/dist/test/mergeTreeOperationRunner.spec.js +156 -0
  172. package/dist/test/mergeTreeOperationRunner.spec.js.map +1 -0
  173. package/dist/test/obliterate.concurrent.spec.d.ts +6 -0
  174. package/dist/test/obliterate.concurrent.spec.d.ts.map +1 -0
  175. package/dist/test/obliterate.concurrent.spec.js +1446 -0
  176. package/dist/test/obliterate.concurrent.spec.js.map +1 -0
  177. package/dist/test/obliterate.partialLength.spec.d.ts +6 -0
  178. package/dist/test/obliterate.partialLength.spec.d.ts.map +1 -0
  179. package/dist/test/obliterate.partialLength.spec.js +279 -0
  180. package/dist/test/obliterate.partialLength.spec.js.map +1 -0
  181. package/dist/test/obliterate.reconnect.spec.d.ts +6 -0
  182. package/dist/test/obliterate.reconnect.spec.d.ts.map +1 -0
  183. package/dist/test/obliterate.reconnect.spec.js +164 -0
  184. package/dist/test/obliterate.reconnect.spec.js.map +1 -0
  185. package/dist/test/obliterate.spec.d.ts +6 -0
  186. package/dist/test/obliterate.spec.d.ts.map +1 -0
  187. package/dist/test/obliterate.spec.js +162 -0
  188. package/dist/test/obliterate.spec.js.map +1 -0
  189. package/dist/test/ordinal.spec.d.ts +2 -0
  190. package/dist/test/ordinal.spec.d.ts.map +1 -0
  191. package/dist/test/ordinal.spec.js +43 -0
  192. package/dist/test/ordinal.spec.js.map +1 -0
  193. package/dist/test/partialLength.spec.d.ts +6 -0
  194. package/dist/test/partialLength.spec.d.ts.map +1 -0
  195. package/dist/test/partialLength.spec.js +282 -0
  196. package/dist/test/partialLength.spec.js.map +1 -0
  197. package/dist/test/properties.spec.d.ts +6 -0
  198. package/dist/test/properties.spec.d.ts.map +1 -0
  199. package/dist/test/properties.spec.js +55 -0
  200. package/dist/test/properties.spec.js.map +1 -0
  201. package/dist/test/reconnectHelper.d.ts +48 -0
  202. package/dist/test/reconnectHelper.d.ts.map +1 -0
  203. package/dist/test/reconnectHelper.js +86 -0
  204. package/dist/test/reconnectHelper.js.map +1 -0
  205. package/dist/test/resetPendingSegmentsToOp.spec.d.ts +6 -0
  206. package/dist/test/resetPendingSegmentsToOp.spec.d.ts.map +1 -0
  207. package/dist/test/resetPendingSegmentsToOp.spec.js +218 -0
  208. package/dist/test/resetPendingSegmentsToOp.spec.js.map +1 -0
  209. package/dist/test/revertibleFarm.spec.d.ts +6 -0
  210. package/dist/test/revertibleFarm.spec.d.ts.map +1 -0
  211. package/dist/test/revertibleFarm.spec.js +124 -0
  212. package/dist/test/revertibleFarm.spec.js.map +1 -0
  213. package/dist/test/revertibles.spec.d.ts +17 -0
  214. package/dist/test/revertibles.spec.d.ts.map +1 -0
  215. package/dist/test/revertibles.spec.js +385 -0
  216. package/dist/test/revertibles.spec.js.map +1 -0
  217. package/dist/test/segmentGroupCollection.spec.d.ts +6 -0
  218. package/dist/test/segmentGroupCollection.spec.d.ts.map +1 -0
  219. package/dist/test/segmentGroupCollection.spec.js +60 -0
  220. package/dist/test/segmentGroupCollection.spec.js.map +1 -0
  221. package/dist/test/snapshot.spec.d.ts +6 -0
  222. package/dist/test/snapshot.spec.d.ts.map +1 -0
  223. package/dist/test/snapshot.spec.js +178 -0
  224. package/dist/test/snapshot.spec.js.map +1 -0
  225. package/dist/test/snapshot.utils.d.ts +33 -0
  226. package/dist/test/snapshot.utils.d.ts.map +1 -0
  227. package/dist/test/snapshot.utils.js +109 -0
  228. package/dist/test/snapshot.utils.js.map +1 -0
  229. package/dist/test/snapshotlegacy.spec.d.ts +6 -0
  230. package/dist/test/snapshotlegacy.spec.d.ts.map +1 -0
  231. package/dist/test/snapshotlegacy.spec.js +139 -0
  232. package/dist/test/snapshotlegacy.spec.js.map +1 -0
  233. package/dist/test/sortedSegmentSet.spec.d.ts +6 -0
  234. package/dist/test/sortedSegmentSet.spec.d.ts.map +1 -0
  235. package/dist/test/sortedSegmentSet.spec.js +95 -0
  236. package/dist/test/sortedSegmentSet.spec.js.map +1 -0
  237. package/dist/test/testClient.d.ts +119 -0
  238. package/dist/test/testClient.d.ts.map +1 -0
  239. package/dist/test/testClient.js +439 -0
  240. package/dist/test/testClient.js.map +1 -0
  241. package/dist/test/testClientLogger.d.ts +44 -0
  242. package/dist/test/testClientLogger.d.ts.map +1 -0
  243. package/dist/test/testClientLogger.js +287 -0
  244. package/dist/test/testClientLogger.js.map +1 -0
  245. package/dist/test/testSerializer.d.ts +18 -0
  246. package/dist/test/testSerializer.d.ts.map +1 -0
  247. package/dist/test/testSerializer.js +33 -0
  248. package/dist/test/testSerializer.js.map +1 -0
  249. package/dist/test/testServer.d.ts +36 -0
  250. package/dist/test/testServer.d.ts.map +1 -0
  251. package/dist/test/testServer.js +138 -0
  252. package/dist/test/testServer.js.map +1 -0
  253. package/dist/test/testUtils.d.ts +69 -0
  254. package/dist/test/testUtils.d.ts.map +1 -0
  255. package/dist/test/testUtils.js +149 -0
  256. package/dist/test/testUtils.js.map +1 -0
  257. package/dist/test/text.d.ts +9 -0
  258. package/dist/test/text.d.ts.map +1 -0
  259. package/dist/test/text.js +76 -0
  260. package/dist/test/text.js.map +1 -0
  261. package/dist/test/tracking.spec.d.ts +6 -0
  262. package/dist/test/tracking.spec.d.ts.map +1 -0
  263. package/dist/test/tracking.spec.js +120 -0
  264. package/dist/test/tracking.spec.js.map +1 -0
  265. package/dist/test/wordUnitTests.d.ts +6 -0
  266. package/dist/test/wordUnitTests.d.ts.map +1 -0
  267. package/dist/test/wordUnitTests.js +172 -0
  268. package/dist/test/wordUnitTests.js.map +1 -0
  269. package/lib/{MergeTreeTextHelper.d.ts → MergeTreeTextHelper.d.mts} +3 -3
  270. package/lib/MergeTreeTextHelper.d.mts.map +1 -0
  271. package/lib/{MergeTreeTextHelper.js → MergeTreeTextHelper.mjs} +5 -10
  272. package/lib/MergeTreeTextHelper.mjs.map +1 -0
  273. package/lib/{attributionCollection.d.ts → attributionCollection.d.mts} +2 -2
  274. package/lib/attributionCollection.d.mts.map +1 -0
  275. package/lib/{attributionCollection.js → attributionCollection.mjs} +9 -14
  276. package/lib/attributionCollection.mjs.map +1 -0
  277. package/lib/{attributionPolicy.d.ts → attributionPolicy.d.mts} +2 -2
  278. package/lib/attributionPolicy.d.mts.map +1 -0
  279. package/lib/{attributionPolicy.js → attributionPolicy.mjs} +21 -27
  280. package/lib/attributionPolicy.mjs.map +1 -0
  281. package/lib/{client.d.ts → client.d.mts} +9 -16
  282. package/lib/client.d.mts.map +1 -0
  283. package/lib/{client.js → client.mjs} +101 -110
  284. package/lib/client.mjs.map +1 -0
  285. package/lib/collections/{index.d.ts → index.d.mts} +3 -3
  286. package/lib/collections/index.d.mts.map +1 -0
  287. package/lib/collections/index.mjs +7 -0
  288. package/lib/collections/index.mjs.map +1 -0
  289. package/lib/collections/{list.d.ts → list.d.mts} +1 -1
  290. package/lib/collections/list.d.mts.map +1 -0
  291. package/lib/collections/{list.js → list.mjs} +6 -11
  292. package/lib/collections/list.mjs.map +1 -0
  293. package/lib/collections/{rbTree.d.ts → rbTree.d.mts} +1 -1
  294. package/lib/collections/rbTree.d.mts.map +1 -0
  295. package/lib/collections/{rbTree.js → rbTree.mjs} +16 -20
  296. package/lib/collections/rbTree.mjs.map +1 -0
  297. package/lib/{constants.d.ts → constants.d.mts} +1 -1
  298. package/lib/constants.d.mts.map +1 -0
  299. package/lib/constants.mjs +32 -0
  300. package/lib/constants.mjs.map +1 -0
  301. package/lib/{endOfTreeSegment.d.ts → endOfTreeSegment.d.mts} +4 -4
  302. package/lib/endOfTreeSegment.d.mts.map +1 -0
  303. package/lib/{endOfTreeSegment.js → endOfTreeSegment.mjs} +13 -18
  304. package/lib/endOfTreeSegment.mjs.map +1 -0
  305. package/lib/{index.d.ts → index.d.mts} +21 -21
  306. package/lib/index.d.mts.map +1 -0
  307. package/lib/index.mjs +24 -0
  308. package/lib/index.mjs.map +1 -0
  309. package/lib/{localReference.d.ts → localReference.d.mts} +7 -7
  310. package/lib/localReference.d.mts.map +1 -0
  311. package/lib/{localReference.js → localReference.mjs} +38 -47
  312. package/lib/localReference.mjs.map +1 -0
  313. package/lib/{merge-tree-alpha.d.ts → merge-tree-alpha.d.mts} +27 -12
  314. package/lib/{merge-tree-beta.d.ts → merge-tree-beta.d.mts} +0 -16
  315. package/lib/{merge-tree-public.d.ts → merge-tree-public.d.mts} +0 -16
  316. package/lib/{merge-tree-untrimmed.d.ts → merge-tree-untrimmed.d.mts} +5 -29
  317. package/lib/{mergeTree.d.ts → mergeTree.d.mts} +12 -29
  318. package/lib/mergeTree.d.mts.map +1 -0
  319. package/lib/{mergeTree.js → mergeTree.mjs} +203 -340
  320. package/lib/mergeTree.mjs.map +1 -0
  321. package/lib/{mergeTreeDeltaCallback.d.ts → mergeTreeDeltaCallback.d.mts} +4 -8
  322. package/lib/mergeTreeDeltaCallback.d.mts.map +1 -0
  323. package/lib/{mergeTreeDeltaCallback.js → mergeTreeDeltaCallback.mjs} +2 -5
  324. package/lib/mergeTreeDeltaCallback.mjs.map +1 -0
  325. package/lib/{mergeTreeNodeWalk.d.ts → mergeTreeNodeWalk.d.mts} +2 -2
  326. package/lib/mergeTreeNodeWalk.d.mts.map +1 -0
  327. package/lib/{mergeTreeNodeWalk.js → mergeTreeNodeWalk.mjs} +14 -21
  328. package/lib/mergeTreeNodeWalk.mjs.map +1 -0
  329. package/lib/{mergeTreeNodes.d.ts → mergeTreeNodes.d.mts} +12 -12
  330. package/lib/mergeTreeNodes.d.mts.map +1 -0
  331. package/lib/{mergeTreeNodes.js → mergeTreeNodes.mjs} +60 -76
  332. package/lib/mergeTreeNodes.mjs.map +1 -0
  333. package/lib/{mergeTreeTracking.d.ts → mergeTreeTracking.d.mts} +3 -3
  334. package/lib/mergeTreeTracking.d.mts.map +1 -0
  335. package/lib/{mergeTreeTracking.js → mergeTreeTracking.mjs} +6 -13
  336. package/lib/mergeTreeTracking.mjs.map +1 -0
  337. package/lib/{opBuilder.d.ts → opBuilder.d.mts} +4 -4
  338. package/lib/opBuilder.d.mts.map +1 -0
  339. package/lib/{opBuilder.js → opBuilder.mjs} +15 -25
  340. package/lib/opBuilder.mjs.map +1 -0
  341. package/lib/{ops.d.ts → ops.d.mts} +2 -2
  342. package/lib/ops.d.mts.map +1 -0
  343. package/lib/{ops.js → ops.mjs} +5 -8
  344. package/lib/ops.mjs.map +1 -0
  345. package/lib/{ordinal.d.ts → ordinal.d.mts} +1 -1
  346. package/lib/ordinal.d.mts.map +1 -0
  347. package/lib/{ordinal.js → ordinal.mjs} +4 -9
  348. package/lib/ordinal.mjs.map +1 -0
  349. package/lib/{partialLengths.d.ts → partialLengths.d.mts} +4 -4
  350. package/lib/partialLengths.d.mts.map +1 -0
  351. package/lib/{partialLengths.js → partialLengths.mjs} +38 -46
  352. package/lib/partialLengths.mjs.map +1 -0
  353. package/lib/{properties.d.ts → properties.d.mts} +1 -1
  354. package/lib/properties.d.mts.map +1 -0
  355. package/lib/{properties.js → properties.mjs} +7 -16
  356. package/lib/properties.mjs.map +1 -0
  357. package/lib/{referencePositions.d.ts → referencePositions.d.mts} +5 -5
  358. package/lib/referencePositions.d.mts.map +1 -0
  359. package/lib/referencePositions.mjs +70 -0
  360. package/lib/referencePositions.mjs.map +1 -0
  361. package/lib/{revertibles.d.ts → revertibles.d.mts} +12 -12
  362. package/lib/revertibles.d.mts.map +1 -0
  363. package/lib/{revertibles.js → revertibles.mjs} +60 -67
  364. package/lib/revertibles.mjs.map +1 -0
  365. package/lib/{segmentGroupCollection.d.ts → segmentGroupCollection.d.mts} +2 -2
  366. package/lib/segmentGroupCollection.d.mts.map +1 -0
  367. package/lib/{segmentGroupCollection.js → segmentGroupCollection.mjs} +5 -9
  368. package/lib/segmentGroupCollection.mjs.map +1 -0
  369. package/lib/{segmentPropertiesManager.d.ts → segmentPropertiesManager.d.mts} +3 -3
  370. package/lib/segmentPropertiesManager.d.mts.map +1 -0
  371. package/lib/{segmentPropertiesManager.js → segmentPropertiesManager.mjs} +14 -20
  372. package/lib/{segmentPropertiesManager.js.map → segmentPropertiesManager.mjs.map} +1 -1
  373. package/lib/{snapshotChunks.d.ts → snapshotChunks.d.mts} +4 -4
  374. package/lib/snapshotChunks.d.mts.map +1 -0
  375. package/lib/{snapshotChunks.js → snapshotChunks.mjs} +10 -17
  376. package/lib/snapshotChunks.mjs.map +1 -0
  377. package/lib/{snapshotLoader.d.ts → snapshotLoader.d.mts} +3 -3
  378. package/lib/snapshotLoader.d.mts.map +1 -0
  379. package/lib/{snapshotLoader.js → snapshotLoader.mjs} +33 -38
  380. package/lib/snapshotLoader.mjs.map +1 -0
  381. package/lib/{snapshotV1.d.ts → snapshotV1.d.mts} +4 -4
  382. package/lib/snapshotV1.d.mts.map +1 -0
  383. package/lib/{snapshotV1.js → snapshotV1.mjs} +28 -32
  384. package/lib/snapshotV1.mjs.map +1 -0
  385. package/lib/{snapshotlegacy.d.ts → snapshotlegacy.d.mts} +3 -3
  386. package/lib/snapshotlegacy.d.mts.map +1 -0
  387. package/lib/{snapshotlegacy.js → snapshotlegacy.mjs} +21 -26
  388. package/lib/snapshotlegacy.mjs.map +1 -0
  389. package/lib/{sortedSegmentSet.d.ts → sortedSegmentSet.d.mts} +4 -4
  390. package/lib/sortedSegmentSet.d.mts.map +1 -0
  391. package/lib/{sortedSegmentSet.js → sortedSegmentSet.mjs} +3 -8
  392. package/lib/sortedSegmentSet.mjs.map +1 -0
  393. package/lib/{sortedSet.d.ts → sortedSet.d.mts} +1 -1
  394. package/lib/sortedSet.d.mts.map +1 -0
  395. package/lib/{sortedSet.js → sortedSet.mjs} +2 -6
  396. package/lib/sortedSet.mjs.map +1 -0
  397. package/lib/{textSegment.d.ts → textSegment.d.mts} +4 -4
  398. package/lib/textSegment.d.mts.map +1 -0
  399. package/lib/{textSegment.js → textSegment.mjs} +8 -12
  400. package/lib/textSegment.mjs.map +1 -0
  401. package/lib/{zamboni.d.ts → zamboni.d.mts} +3 -3
  402. package/lib/zamboni.d.mts.map +1 -0
  403. package/lib/{zamboni.js → zamboni.mjs} +22 -28
  404. package/lib/zamboni.mjs.map +1 -0
  405. package/package.json +95 -164
  406. package/src/client.ts +0 -8
  407. package/src/mergeTree.ts +0 -226
  408. package/src/ops.ts +1 -1
  409. package/src/revertibles.ts +4 -4
  410. package/lib/MergeTreeTextHelper.d.ts.map +0 -1
  411. package/lib/MergeTreeTextHelper.js.map +0 -1
  412. package/lib/attributionCollection.d.ts.map +0 -1
  413. package/lib/attributionCollection.js.map +0 -1
  414. package/lib/attributionPolicy.d.ts.map +0 -1
  415. package/lib/attributionPolicy.js.map +0 -1
  416. package/lib/client.d.ts.map +0 -1
  417. package/lib/client.js.map +0 -1
  418. package/lib/collections/index.d.ts.map +0 -1
  419. package/lib/collections/index.js +0 -14
  420. package/lib/collections/index.js.map +0 -1
  421. package/lib/collections/list.d.ts.map +0 -1
  422. package/lib/collections/list.js.map +0 -1
  423. package/lib/collections/rbTree.d.ts.map +0 -1
  424. package/lib/collections/rbTree.js.map +0 -1
  425. package/lib/constants.d.ts.map +0 -1
  426. package/lib/constants.js +0 -35
  427. package/lib/constants.js.map +0 -1
  428. package/lib/endOfTreeSegment.d.ts.map +0 -1
  429. package/lib/endOfTreeSegment.js.map +0 -1
  430. package/lib/index.d.ts.map +0 -1
  431. package/lib/index.js +0 -80
  432. package/lib/index.js.map +0 -1
  433. package/lib/localReference.d.ts.map +0 -1
  434. package/lib/localReference.js.map +0 -1
  435. package/lib/mergeTree.d.ts.map +0 -1
  436. package/lib/mergeTree.js.map +0 -1
  437. package/lib/mergeTreeDeltaCallback.d.ts.map +0 -1
  438. package/lib/mergeTreeDeltaCallback.js.map +0 -1
  439. package/lib/mergeTreeNodeWalk.d.ts.map +0 -1
  440. package/lib/mergeTreeNodeWalk.js.map +0 -1
  441. package/lib/mergeTreeNodes.d.ts.map +0 -1
  442. package/lib/mergeTreeNodes.js.map +0 -1
  443. package/lib/mergeTreeTracking.d.ts.map +0 -1
  444. package/lib/mergeTreeTracking.js.map +0 -1
  445. package/lib/opBuilder.d.ts.map +0 -1
  446. package/lib/opBuilder.js.map +0 -1
  447. package/lib/ops.d.ts.map +0 -1
  448. package/lib/ops.js.map +0 -1
  449. package/lib/ordinal.d.ts.map +0 -1
  450. package/lib/ordinal.js.map +0 -1
  451. package/lib/partialLengths.d.ts.map +0 -1
  452. package/lib/partialLengths.js.map +0 -1
  453. package/lib/properties.d.ts.map +0 -1
  454. package/lib/properties.js.map +0 -1
  455. package/lib/referencePositions.d.ts.map +0 -1
  456. package/lib/referencePositions.js +0 -80
  457. package/lib/referencePositions.js.map +0 -1
  458. package/lib/revertibles.d.ts.map +0 -1
  459. package/lib/revertibles.js.map +0 -1
  460. package/lib/segmentGroupCollection.d.ts.map +0 -1
  461. package/lib/segmentGroupCollection.js.map +0 -1
  462. package/lib/segmentPropertiesManager.d.ts.map +0 -1
  463. package/lib/snapshotChunks.d.ts.map +0 -1
  464. package/lib/snapshotChunks.js.map +0 -1
  465. package/lib/snapshotLoader.d.ts.map +0 -1
  466. package/lib/snapshotLoader.js.map +0 -1
  467. package/lib/snapshotV1.d.ts.map +0 -1
  468. package/lib/snapshotV1.js.map +0 -1
  469. package/lib/snapshotlegacy.d.ts.map +0 -1
  470. package/lib/snapshotlegacy.js.map +0 -1
  471. package/lib/sortedSegmentSet.d.ts.map +0 -1
  472. package/lib/sortedSegmentSet.js.map +0 -1
  473. package/lib/sortedSet.d.ts.map +0 -1
  474. package/lib/sortedSet.js.map +0 -1
  475. package/lib/textSegment.d.ts.map +0 -1
  476. package/lib/textSegment.js.map +0 -1
  477. package/lib/zamboni.d.ts.map +0 -1
  478. package/lib/zamboni.js.map +0 -1
  479. package/merge-tree.test-files.tar +0 -0
  480. package/src/mergeTreeExample1.pdf +0 -0
  481. package/tsconfig.esnext.json +0 -6
@@ -0,0 +1,1446 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const assert_1 = require("assert");
8
+ const telemetry_utils_1 = require("@fluidframework/telemetry-utils");
9
+ const partialLengths_1 = require("../partialLengths");
10
+ const mergeTree_1 = require("../mergeTree");
11
+ const reconnectHelper_1 = require("./reconnectHelper");
12
+ /**
13
+ * Some tests contain ASCII diagrams of the trees to make it easier to reason about
14
+ * structure. The format of these diagrams is this:
15
+ * - segments are separated by `-`.
16
+ * - removed ranges are surrounded by `[` ... `]`
17
+ * - obliterated ranges are surrounded by `(` ... `)`
18
+ *
19
+ * In cases where these ranges are ambiguous, there are additional diagrams
20
+ * containing `v` and `-`, with the `v` denoting the start and end of the range
21
+ *
22
+ * E.g.
23
+ *
24
+ * ```
25
+ * v---v
26
+ * [ABC]
27
+ * ```
28
+ *
29
+ * This diagram describes a single segment, `ABC`, that has been removed.
30
+ *
31
+ *
32
+ * ```
33
+ * v-----v
34
+ * v---v
35
+ * [[ABC]]
36
+ * ```
37
+ *
38
+ * This diagram describes a single segment, `ABC`, that has been concurrently
39
+ * removed by two clients.
40
+ */
41
+ for (const incremental of [true, false]) {
42
+ describe(`obliterate partial lengths incremental = ${incremental}`, () => {
43
+ beforeEach(() => {
44
+ partialLengths_1.PartialSequenceLengths.options.verifier = partialLengths_1.verify;
45
+ partialLengths_1.PartialSequenceLengths.options.verifyExpected = partialLengths_1.verifyExpected;
46
+ mergeTree_1.MergeTree.options.incrementalUpdate = incremental;
47
+ });
48
+ afterEach(() => {
49
+ partialLengths_1.PartialSequenceLengths.options.verifier = undefined;
50
+ partialLengths_1.PartialSequenceLengths.options.verifyExpected = undefined;
51
+ mergeTree_1.MergeTree.options.incrementalUpdate = true;
52
+ });
53
+ it("length of children does not differ from parent when overlapping remove+obliterate", () => {
54
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
55
+ // ABCDEFGH
56
+ // I-[J]-(KLM-[ABC]-D-123456-E-[FG]-H)
57
+ helper.insertText("A", 0, "ABCDEFGH");
58
+ helper.processAllOps();
59
+ helper.removeRange("C", 0, 3);
60
+ helper.insertText("C", 1, "123456");
61
+ helper.removeRange("A", 5, 7);
62
+ helper.insertText("A", 0, "IJKLM");
63
+ helper.obliterateRange("A", 2, 11);
64
+ helper.removeRange("A", 1, 2);
65
+ helper.processAllOps();
66
+ assert_1.strict.equal(helper.clients.A.getText(), "I");
67
+ helper.logger.validate();
68
+ });
69
+ it("deletes concurrent insert that occurs after obliterate", () => {
70
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
71
+ helper.insertText("B", 0, "ABCD");
72
+ helper.processAllOps();
73
+ helper.obliterateRange("B", 0, 4);
74
+ helper.insertText("C", 2, "X");
75
+ helper.processAllOps();
76
+ assert_1.strict.equal(helper.clients.A.getText(), "");
77
+ assert_1.strict.equal(helper.clients.C.getText(), "");
78
+ helper.logger.validate();
79
+ });
80
+ it("deletes concurrent insert that occurs before obliterate", () => {
81
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
82
+ helper.insertText("B", 0, "ABCD");
83
+ helper.processAllOps();
84
+ helper.insertText("C", 2, "X");
85
+ helper.obliterateRange("B", 0, 4);
86
+ helper.processAllOps();
87
+ assert_1.strict.equal(helper.clients.A.getText(), "");
88
+ assert_1.strict.equal(helper.clients.C.getText(), "");
89
+ helper.logger.validate();
90
+ });
91
+ it("does not delete unacked segment at start of string", () => {
92
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
93
+ helper.insertText("C", 0, "ABC");
94
+ helper.obliterateRange("C", 2, 3);
95
+ helper.insertText("B", 0, "X");
96
+ helper.processAllOps();
97
+ assert_1.strict.equal(helper.clients.A.getText(), "XAB");
98
+ assert_1.strict.equal(helper.clients.B.getText(), "XAB");
99
+ assert_1.strict.equal(helper.clients.C.getText(), "XAB");
100
+ helper.logger.validate();
101
+ });
102
+ it("throws when local obliterate has range end outside length of local string", () => {
103
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
104
+ helper.insertText("B", 0, "A");
105
+ helper.insertText("C", 0, "B");
106
+ try {
107
+ helper.obliterateRange("C", 0, 2);
108
+ assert_1.strict.fail("should not be possible to obliterate outside local range");
109
+ }
110
+ catch (e) {
111
+ (0, assert_1.strict)(e instanceof telemetry_utils_1.LoggingError);
112
+ assert_1.strict.equal(e.message, "RangeOutOfBounds");
113
+ }
114
+ });
115
+ it("does not delete when obliterate immediately after insert", () => {
116
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
117
+ helper.insertText("C", 0, "A");
118
+ helper.obliterateRange("C", 0, 1);
119
+ helper.insertText("B", 0, "W");
120
+ helper.insertText("C", 0, "D");
121
+ helper.obliterateRange("C", 0, 1);
122
+ helper.processAllOps();
123
+ assert_1.strict.equal(helper.clients.A.getText(), "W");
124
+ assert_1.strict.equal(helper.clients.B.getText(), "W");
125
+ assert_1.strict.equal(helper.clients.C.getText(), "W");
126
+ helper.logger.validate();
127
+ });
128
+ it("does not delete remote insert when between local insert+obliterate", () => {
129
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
130
+ helper.insertText("C", 0, "A");
131
+ helper.insertText("B", 0, "X");
132
+ helper.obliterateRange("C", 0, 1);
133
+ helper.insertText("C", 0, "B");
134
+ helper.obliterateRange("C", 0, 1);
135
+ helper.processAllOps();
136
+ assert_1.strict.equal(helper.clients.A.getText(), "X");
137
+ assert_1.strict.equal(helper.clients.B.getText(), "X");
138
+ assert_1.strict.equal(helper.clients.C.getText(), "X");
139
+ helper.logger.validate();
140
+ });
141
+ it("does not delete remote insert when between local insert+obliterate", () => {
142
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
143
+ helper.insertText("C", 0, "A");
144
+ helper.obliterateRange("C", 0, 1);
145
+ helper.insertText("B", 0, "B");
146
+ helper.insertText("C", 0, "X");
147
+ helper.obliterateRange("B", 0, 1);
148
+ helper.processAllOps();
149
+ assert_1.strict.equal(helper.clients.A.getText(), "X");
150
+ assert_1.strict.equal(helper.clients.B.getText(), "X");
151
+ assert_1.strict.equal(helper.clients.C.getText(), "X");
152
+ helper.logger.validate();
153
+ });
154
+ it("does not delete remote insert when in middle of segment", () => {
155
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
156
+ helper.insertText("C", 0, "ABC");
157
+ helper.obliterateRange("C", 2, 3);
158
+ helper.obliterateRange("C", 0, 1);
159
+ helper.insertText("B", 0, "X");
160
+ helper.processAllOps();
161
+ assert_1.strict.equal(helper.clients.A.getText(), "XB");
162
+ assert_1.strict.equal(helper.clients.B.getText(), "XB");
163
+ assert_1.strict.equal(helper.clients.C.getText(), "XB");
164
+ helper.logger.validate();
165
+ });
166
+ it("deletes segment inserted into locally obliterated segment", () => {
167
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
168
+ helper.insertText("C", 0, "A");
169
+ helper.insertText("B", 0, "X");
170
+ helper.insertText("C", 0, "B");
171
+ helper.obliterateRange("C", 0, 2);
172
+ helper.processAllOps();
173
+ assert_1.strict.equal(helper.clients.A.getText(), "");
174
+ assert_1.strict.equal(helper.clients.B.getText(), "");
175
+ assert_1.strict.equal(helper.clients.C.getText(), "");
176
+ helper.logger.validate();
177
+ });
178
+ it("updates lengths after obliterated insertion", () => {
179
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
180
+ helper.insertText("C", 0, "A");
181
+ helper.insertText("B", 0, "X");
182
+ helper.insertText("C", 0, "N");
183
+ helper.obliterateRange("C", 0, 2);
184
+ helper.insertText("B", 1, "B");
185
+ helper.processAllOps();
186
+ assert_1.strict.equal(helper.clients.A.getText(), "");
187
+ assert_1.strict.equal(helper.clients.B.getText(), "");
188
+ assert_1.strict.equal(helper.clients.C.getText(), "");
189
+ assert_1.strict.equal(helper.clients.A.getLength(), 0);
190
+ assert_1.strict.equal(helper.clients.B.getLength(), 0);
191
+ assert_1.strict.equal(helper.clients.C.getLength(), 0);
192
+ helper.logger.validate();
193
+ });
194
+ it("updates lengths when insertion causes tree to split", () => {
195
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
196
+ helper.insertText("A", 0, "0");
197
+ helper.insertText("C", 0, "123");
198
+ helper.insertText("B", 0, "BB");
199
+ helper.insertText("C", 0, "GGG");
200
+ helper.obliterateRange("C", 2, 5);
201
+ helper.insertText("B", 1, "A");
202
+ helper.processAllOps();
203
+ assert_1.strict.equal(helper.clients.A.getText().length, helper.clients.A.getLength());
204
+ assert_1.strict.equal(helper.clients.B.getText().length, helper.clients.B.getLength());
205
+ assert_1.strict.equal(helper.clients.C.getText().length, helper.clients.C.getLength());
206
+ assert_1.strict.equal(helper.clients.A.getText(), "GG30");
207
+ helper.logger.validate();
208
+ });
209
+ it("length of node split by insertion does not count remotely obliterated segments", () => {
210
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
211
+ helper.insertText("A", 0, "1");
212
+ helper.insertText("A", 0, "2");
213
+ helper.insertText("C", 0, "XXXX");
214
+ helper.insertText("B", 0, "ABC");
215
+ helper.insertText("C", 0, "GGG");
216
+ helper.obliterateRange("C", 2, 6);
217
+ helper.insertText("C", 1, "D");
218
+ helper.processAllOps();
219
+ assert_1.strict.equal(helper.clients.A.getText(), "GDGX21");
220
+ assert_1.strict.equal(helper.clients.C.getText(), "GDGX21");
221
+ helper.logger.validate();
222
+ });
223
+ it("length of node split by obliterate does not count remotely obliterated segments", () => {
224
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
225
+ helper.insertText("A", 0, "1");
226
+ helper.insertText("A", 0, "2");
227
+ helper.insertText("C", 0, "XXXX");
228
+ helper.insertText("B", 0, "A");
229
+ helper.insertText("C", 0, "GGG");
230
+ helper.obliterateRange("C", 2, 6);
231
+ helper.insertText("C", 1, "C");
232
+ helper.insertText("B", 1, "D");
233
+ helper.processAllOps();
234
+ assert_1.strict.equal(helper.clients.A.getText(), "GCGX21");
235
+ assert_1.strict.equal(helper.clients.B.getText(), "GCGX21");
236
+ helper.logger.validate();
237
+ });
238
+ it("counts remotely but not concurrently inserted segments for length when tree is split", () => {
239
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
240
+ // a-b-c-d-e-123
241
+ // (a-b)-c-d-e-1-[2]-3
242
+ helper.insertText("B", 0, "123");
243
+ helper.insertText("C", 0, "e");
244
+ helper.insertText("C", 0, "d");
245
+ helper.insertText("C", 0, "c");
246
+ helper.insertText("C", 0, "b");
247
+ helper.insertText("C", 0, "a");
248
+ helper.processAllOps();
249
+ helper.obliterateRange("B", 0, 2);
250
+ helper.removeRange("B", 4, 5);
251
+ helper.processAllOps();
252
+ assert_1.strict.equal(helper.clients.A.getText(), "cde13");
253
+ assert_1.strict.equal(helper.clients.C.getText(), "cde13");
254
+ helper.logger.validate();
255
+ });
256
+ it("does obliterate X for all clients", () => {
257
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
258
+ helper.insertText("B", 0, "DE");
259
+ helper.obliterateRange("B", 0, 1);
260
+ helper.insertText("A", 0, "X");
261
+ helper.insertText("B", 0, "ABC");
262
+ helper.obliterateRange("B", 2, 4);
263
+ helper.processAllOps();
264
+ assert_1.strict.equal(helper.clients.A.getText(), "AB");
265
+ assert_1.strict.equal(helper.clients.C.getText(), "AB");
266
+ helper.logger.validate();
267
+ });
268
+ it("does not include remote but unacked segments in partial len calculation", () => {
269
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
270
+ // 89-4567-123-X
271
+ // 8-(9-4-w-567-1)-23-Y-X
272
+ helper.insertText("A", 0, "X");
273
+ helper.insertText("C", 0, "123");
274
+ helper.insertText("C", 0, "4567");
275
+ helper.insertText("B", 0, "89");
276
+ helper.processAllOps();
277
+ helper.obliterateRange("C", 1, 7);
278
+ helper.insertText("A", 3, "w");
279
+ helper.insertText("C", 3, "Y");
280
+ helper.processAllOps();
281
+ assert_1.strict.equal(helper.clients.A.getText(), "823YX");
282
+ assert_1.strict.equal(helper.clients.B.getText(), "823YX");
283
+ helper.logger.validate();
284
+ });
285
+ it("correctly accounts for overlapping obliterate", () => {
286
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
287
+ helper.insertText("B", 0, "AB");
288
+ helper.processAllOps();
289
+ helper.obliterateRange("C", 0, 1);
290
+ helper.obliterateRange("B", 0, 1);
291
+ helper.processAllOps();
292
+ assert_1.strict.equal(helper.clients.A.getText(), "B");
293
+ assert_1.strict.equal(helper.clients.B.getText(), "B");
294
+ assert_1.strict.equal(helper.clients.C.getText(), "B");
295
+ helper.logger.validate();
296
+ });
297
+ it("correctly accounts for overlapping obliterate and remove", () => {
298
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
299
+ helper.insertText("B", 0, "AB");
300
+ helper.processAllOps();
301
+ helper.removeRange("C", 0, 1);
302
+ helper.obliterateRange("B", 0, 1);
303
+ helper.processAllOps();
304
+ assert_1.strict.equal(helper.clients.A.getText(), "B");
305
+ assert_1.strict.equal(helper.clients.B.getText(), "B");
306
+ assert_1.strict.equal(helper.clients.C.getText(), "B");
307
+ helper.logger.validate();
308
+ });
309
+ it("clones movedClientIds array during insert", () => {
310
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
311
+ // the bug found here:
312
+ // the X was skipped over by client `A` because it had already been
313
+ // deleted, so its length at refSeq was 0
314
+ //
315
+ // this was due to the movedClientIds array not being properly cloned
316
+ // when marking obliterated during insert
317
+ helper.insertText("C", 0, "ABCD");
318
+ helper.processAllOps();
319
+ helper.insertText("B", 2, "X");
320
+ helper.obliterateRange("A", 1, 3);
321
+ helper.obliterateRange("B", 1, 4);
322
+ helper.processAllOps();
323
+ assert_1.strict.equal(helper.clients.A.getText(), "AD");
324
+ assert_1.strict.equal(helper.clients.B.getText(), "AD");
325
+ assert_1.strict.equal(helper.clients.C.getText(), "AD");
326
+ helper.logger.validate();
327
+ });
328
+ it("client partial lens consider overlapping obliterates", () => {
329
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
330
+ helper.insertText("A", 0, "123");
331
+ helper.insertText("A", 0, "ABCDEF");
332
+ helper.processAllOps();
333
+ helper.obliterateRange("B", 2, 3);
334
+ helper.obliterateRange("C", 1, 4);
335
+ helper.obliterateRange("C", 4, 5);
336
+ helper.processAllOps();
337
+ assert_1.strict.equal(helper.clients.A.getText(), "AEF13");
338
+ assert_1.strict.equal(helper.clients.B.getText(), "AEF13");
339
+ assert_1.strict.equal(helper.clients.C.getText(), "AEF13");
340
+ helper.logger.validate();
341
+ });
342
+ it("client partial lens consider overlapping obliterates", () => {
343
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
344
+ helper.insertText("C", 0, "X");
345
+ helper.insertText("C", 0, "ABCDEFG");
346
+ helper.processAllOps();
347
+ helper.obliterateRange("B", 2, 3);
348
+ helper.obliterateRange("C", 1, 4);
349
+ helper.obliterateRange("C", 2, 3);
350
+ helper.processAllOps();
351
+ assert_1.strict.equal(helper.clients.A.getText(), "AEGX");
352
+ assert_1.strict.equal(helper.clients.C.getText(), "AEGX");
353
+ helper.logger.validate();
354
+ });
355
+ it("tracks obliterate refSeq when acking op for partial len calculation", () => {
356
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
357
+ // v-----------------------v
358
+ // v--v
359
+ // v--v
360
+ // 6-(345-AB-(CD)-E-(FG)-HI-1)-2
361
+ helper.insertText("A", 0, "12");
362
+ helper.insertText("B", 0, "ABCDEFGHI");
363
+ helper.insertText("A", 0, "345");
364
+ helper.obliterateRange("A", 0, 4);
365
+ helper.obliterateRange("B", 2, 4);
366
+ helper.insertText("A", 0, "6");
367
+ helper.obliterateRange("B", 3, 5);
368
+ helper.processAllOps();
369
+ assert_1.strict.equal(helper.clients.A.getText(), "62");
370
+ assert_1.strict.equal(helper.clients.B.getText(), "62");
371
+ helper.logger.validate();
372
+ });
373
+ it("does not have negative len when segment obliterated before insert", () => {
374
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
375
+ // 1234567-D-C-AB
376
+ // 12-([3-X-45]-67)-D-C-AB
377
+ helper.insertText("A", 0, "AB");
378
+ helper.insertText("A", 0, "C");
379
+ helper.insertText("A", 0, "D");
380
+ helper.insertText("A", 0, "1234567");
381
+ helper.processAllOps();
382
+ helper.logger.validate();
383
+ helper.obliterateRange("A", 2, 7);
384
+ helper.removeRange("A", 2, 5);
385
+ helper.insertText("C", 3, "X");
386
+ helper.processAllOps();
387
+ assert_1.strict.equal(helper.clients.A.getText(), "12B");
388
+ assert_1.strict.equal(helper.clients.B.getText(), "12B");
389
+ assert_1.strict.equal(helper.clients.C.getText(), "12B");
390
+ helper.logger.validate();
391
+ });
392
+ it("does not have negative len when segment obliterated before insert", () => {
393
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
394
+ // ABCDE-1-[2]-3
395
+ // (A-XX-B)-(CD)-E-1-3
396
+ helper.insertText("B", 0, "123");
397
+ helper.insertText("C", 0, "ABCDE");
398
+ helper.removeRange("B", 1, 2);
399
+ helper.processAllOps();
400
+ helper.logger.validate();
401
+ helper.obliterateRange("C", 0, 2);
402
+ helper.obliterateRange("C", 0, 2);
403
+ helper.insertText("B", 1, "XX");
404
+ helper.processAllOps();
405
+ assert_1.strict.equal(helper.clients.A.getText(), "E13");
406
+ assert_1.strict.equal(helper.clients.B.getText(), "E13");
407
+ assert_1.strict.equal(helper.clients.C.getText(), "E13");
408
+ helper.logger.validate();
409
+ });
410
+ it("deletes segments between two obliterates with different seq", () => {
411
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
412
+ // 90-8-1234-(5)-67-D-C-B-A
413
+ // 9-(EFG-[0-8-1234-(5)-67)]-D-C-B-A
414
+ helper.insertText("A", 0, "A");
415
+ helper.insertText("C", 0, "B");
416
+ helper.insertText("C", 0, "C");
417
+ helper.insertText("C", 0, "D");
418
+ helper.insertText("B", 0, "1234567");
419
+ helper.obliterateRange("B", 4, 5);
420
+ helper.insertText("A", 0, "8");
421
+ helper.insertText("A", 0, "90");
422
+ helper.processAllOps();
423
+ helper.removeRange("C", 1, 9);
424
+ helper.insertText("A", 1, "EFG");
425
+ helper.obliterateRange("A", 1, 11);
426
+ helper.processAllOps();
427
+ assert_1.strict.equal(helper.clients.A.getText(), "9DCBA");
428
+ helper.logger.validate();
429
+ });
430
+ it("deletes inserted segment when obliterate of different seq in-between", () => {
431
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
432
+ helper.insertText("A", 0, "AB");
433
+ helper.insertText("B", 0, "E");
434
+ helper.obliterateRange("A", 0, 1);
435
+ helper.insertText("A", 1, "12");
436
+ helper.insertText("A", 0, "CD");
437
+ helper.obliterateRange("A", 1, 4);
438
+ helper.processAllOps();
439
+ assert_1.strict.equal(helper.clients.A.getText(), "C2");
440
+ assert_1.strict.equal(helper.clients.B.getText(), "C2");
441
+ assert_1.strict.equal(helper.clients.C.getText(), "C2");
442
+ helper.logger.validate();
443
+ });
444
+ it("deletes inserted segment when obliterate of different seq in-between", () => {
445
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
446
+ helper.insertText("A", 0, "ABC");
447
+ helper.obliterateRange("A", 1, 2);
448
+ helper.processAllOps();
449
+ helper.insertText("A", 1, "D");
450
+ helper.obliterateRange("C", 0, 2);
451
+ helper.processAllOps();
452
+ assert_1.strict.equal(helper.clients.A.getText(), "");
453
+ assert_1.strict.equal(helper.clients.B.getText(), "");
454
+ assert_1.strict.equal(helper.clients.C.getText(), "");
455
+ helper.logger.validate();
456
+ });
457
+ it("deletes inserted segment when obliterate of different seq in-between", () => {
458
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
459
+ helper.insertText("A", 0, "ABC");
460
+ helper.obliterateRange("A", 1, 2);
461
+ helper.processAllOps();
462
+ helper.insertText("A", 1, "D");
463
+ helper.obliterateRange("C", 0, 2);
464
+ helper.processAllOps();
465
+ assert_1.strict.equal(helper.clients.A.getText(), "");
466
+ assert_1.strict.equal(helper.clients.B.getText(), "");
467
+ assert_1.strict.equal(helper.clients.C.getText(), "");
468
+ helper.logger.validate();
469
+ });
470
+ it("considers obliterated local segments as remotely obliterate", () => {
471
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
472
+ // G-(H-F-I-C)-J-DE-A-(B)
473
+ // G-J-(H-F-I-CD)-E
474
+ helper.insertText("A", 0, "AB");
475
+ helper.obliterateRange("A", 1, 2);
476
+ helper.insertText("C", 0, "CDE");
477
+ helper.insertText("B", 0, "F");
478
+ helper.insertText("C", 0, "GH");
479
+ helper.obliterateRange("C", 1, 3);
480
+ helper.insertText("B", 1, "I");
481
+ helper.insertText("C", 1, "J");
482
+ helper.processAllOps();
483
+ assert_1.strict.equal(helper.clients.A.getText(), "GJDEA");
484
+ assert_1.strict.equal(helper.clients.B.getText(), "GJDEA");
485
+ helper.logger.validate();
486
+ });
487
+ it("traverses hier block in obliterated when len at ref seq is >0 and len at len seq == 0", () => {
488
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
489
+ helper.insertText("A", 0, "AB");
490
+ helper.insertText("A", 2, "CD");
491
+ helper.removeRange("A", 1, 3);
492
+ helper.insertText("C", 0, "12345");
493
+ helper.insertText("B", 0, "EFG");
494
+ helper.insertText("B", 1, "HIJKL");
495
+ helper.processAllOps();
496
+ helper.logger.validate();
497
+ helper.obliterateRange("A", 6, 12);
498
+ helper.removeRange("A", 5, 7);
499
+ helper.obliterateRange("C", 7, 9);
500
+ helper.processAllOps();
501
+ assert_1.strict.equal(helper.clients.A.getText(), helper.clients.D.getText());
502
+ assert_1.strict.equal(helper.clients.B.getText(), "EHIJKAD");
503
+ helper.logger.validate();
504
+ });
505
+ it("traverses hier block in obliterate when len at ref seq is >0 and len at len seq == 0", () => {
506
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
507
+ // [E]-FGH-12-[A]-[B]-CD
508
+ // 3-4-F-[G-(H-1)-2]-CD
509
+ helper.insertText("B", 0, "ABCD");
510
+ helper.removeRange("B", 0, 1);
511
+ helper.insertText("C", 0, "12");
512
+ helper.insertText("A", 0, "EFGH");
513
+ helper.removeRange("B", 1, 2);
514
+ helper.removeRange("A", 0, 1);
515
+ helper.processAllOps();
516
+ helper.logger.validate();
517
+ helper.removeRange("A", 1, 5);
518
+ helper.obliterateRange("B", 2, 4);
519
+ helper.insertText("A", 0, "3");
520
+ helper.insertText("A", 0, "4");
521
+ helper.processAllOps();
522
+ assert_1.strict.equal(helper.clients.A.getText(), "43FBD");
523
+ assert_1.strict.equal(helper.clients.B.getText(), "43FBD");
524
+ helper.logger.validate();
525
+ });
526
+ it("ignores segments where movedSeq < seq for partial len calculations", () => {
527
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
528
+ helper.insertText("B", 0, "ABC");
529
+ helper.insertText("A", 0, "DEF");
530
+ helper.removeRange("A", 1, 2);
531
+ helper.insertText("B", 0, "123456");
532
+ helper.obliterateRange("B", 2, 7);
533
+ helper.insertText("A", 1, "Y");
534
+ helper.processAllOps();
535
+ helper.logger.validate();
536
+ helper.insertText("B", 4, "X");
537
+ helper.processAllOps();
538
+ assert_1.strict.equal(helper.clients.A.getText(), "12BCX");
539
+ assert_1.strict.equal(helper.clients.B.getText(), "12BCX");
540
+ assert_1.strict.equal(helper.clients.C.getText(), "12BCX");
541
+ helper.logger.validate();
542
+ });
543
+ it("accounts for overlapping obliterates from same client", () => {
544
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
545
+ helper.insertText("A", 0, "AB");
546
+ helper.processAllOps();
547
+ helper.logger.validate();
548
+ helper.obliterateRange("B", 0, 1);
549
+ helper.obliterateRange("B", 0, 1);
550
+ helper.removeRange("A", 0, 1);
551
+ helper.processAllOps();
552
+ assert_1.strict.equal(helper.clients.A.getText(), "");
553
+ assert_1.strict.equal(helper.clients.B.getText(), "");
554
+ assert_1.strict.equal(helper.clients.C.getText(), "");
555
+ helper.logger.validate();
556
+ });
557
+ it("accounts for concurrently obliterated segments from the perspective of the inserting client for partial lengths", () => {
558
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
559
+ helper.insertText("B", 0, "A");
560
+ helper.insertText("C", 0, "B");
561
+ helper.insertText("C", 0, "C");
562
+ helper.insertText("A", 0, "1234");
563
+ helper.processAllOps();
564
+ helper.obliterateRange("C", 1, 3);
565
+ helper.insertText("A", 2, "D");
566
+ helper.insertText("A", 4, "E");
567
+ helper.processAllOps();
568
+ assert_1.strict.equal(helper.clients.A.getText(), "1E4CBA");
569
+ assert_1.strict.equal(helper.clients.B.getText(), "1E4CBA");
570
+ helper.logger.validate();
571
+ });
572
+ it("traverses segments when there is a local obliterate", () => {
573
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
574
+ helper.insertText("A", 0, "AB");
575
+ helper.obliterateRange("A", 0, 1);
576
+ helper.insertText("C", 0, "12");
577
+ helper.processAllOps();
578
+ helper.logger.validate();
579
+ helper.insertText("C", 2, "C");
580
+ helper.obliterateRange("A", 0, 3);
581
+ helper.processAllOps();
582
+ assert_1.strict.equal(helper.clients.A.getText(), "");
583
+ helper.logger.validate();
584
+ });
585
+ it("keeps track of all obliterates on a segment", () => {
586
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
587
+ // B-A
588
+ // (B-C-(A))
589
+ helper.insertText("C", 0, "A");
590
+ helper.insertText("B", 0, "B");
591
+ helper.processAllOps();
592
+ helper.logger.validate();
593
+ helper.obliterateRange("B", 1, 2);
594
+ // bug here: because segment A has already been obliterated, we wouldn't
595
+ // mark it obliterated by this op as well, meaning that segments in
596
+ // this range would look to the right and not find a matching move seq
597
+ helper.obliterateRange("A", 0, 2);
598
+ helper.insertText("B", 1, "C");
599
+ helper.processAllOps();
600
+ assert_1.strict.equal(helper.clients.A.getText(), "");
601
+ assert_1.strict.equal(helper.clients.B.getText(), "");
602
+ assert_1.strict.equal(helper.clients.C.getText(), "");
603
+ assert_1.strict.equal(helper.clients.D.getText(), "");
604
+ helper.logger.validate();
605
+ });
606
+ it("many overlapping obliterates", () => {
607
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
608
+ // EF-ABCD
609
+ // (1)-2-((E)-F-A)-B-(C)-D
610
+ helper.insertText("C", 0, "ABCD");
611
+ helper.insertText("B", 0, "EF");
612
+ helper.processAllOps();
613
+ helper.logger.validate();
614
+ helper.obliterateRange("B", 0, 3);
615
+ helper.insertText("A", 0, "12");
616
+ helper.removeRange("C", 0, 1);
617
+ helper.obliterateRange("A", 0, 1);
618
+ helper.obliterateRange("B", 1, 2);
619
+ helper.processAllOps();
620
+ assert_1.strict.equal(helper.clients.A.getText(), "2BD");
621
+ helper.logger.validate();
622
+ });
623
+ it("overlapping obliterates at start", () => {
624
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
625
+ // 12345-B-A
626
+ // ((1-C-2)-3)-4-D-5-B-A
627
+ helper.insertText("C", 0, "A");
628
+ helper.insertText("B", 0, "B");
629
+ helper.insertText("A", 0, "12345");
630
+ helper.processAllOps();
631
+ helper.logger.validate();
632
+ helper.obliterateRange("A", 0, 2);
633
+ helper.insertText("C", 1, "C");
634
+ helper.obliterateRange("C", 0, 4);
635
+ helper.insertText("C", 1, "D");
636
+ helper.processAllOps();
637
+ helper.logger.validate();
638
+ });
639
+ it("partial lengths updated when local insert is acked", () => {
640
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
641
+ // A-BCDEF
642
+ // (A-B-G-C)-D-I-E-H-F
643
+ helper.insertText("A", 0, "A");
644
+ helper.insertText("A", 1, "BCDEF");
645
+ helper.processAllOps();
646
+ helper.logger.validate();
647
+ helper.obliterateRange("C", 0, 3);
648
+ helper.insertText("A", 2, "G");
649
+ helper.insertText("B", 5, "H");
650
+ helper.insertText("C", 1, "I");
651
+ helper.processAllOps();
652
+ assert_1.strict.equal(helper.clients.A.getText(), "DIEHF");
653
+ assert_1.strict.equal(helper.clients.B.getText(), "DIEHF");
654
+ assert_1.strict.equal(helper.clients.C.getText(), "DIEHF");
655
+ assert_1.strict.equal(helper.clients.D.getText(), "DIEHF");
656
+ helper.logger.validate();
657
+ });
658
+ it("two local obliterates get different seq numbers after ack", () => {
659
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
660
+ // C-AB
661
+ // (C-A)-D-(B)
662
+ helper.insertText("C", 0, "AB");
663
+ helper.insertText("A", 0, "C");
664
+ helper.processAllOps();
665
+ helper.logger.validate();
666
+ // bug here: when the op is acked by client C, it would incorrectly give
667
+ // segment B the same movedSeq despite coming from a different op
668
+ helper.obliterateRange("C", 0, 2);
669
+ helper.insertText("B", 2, "D");
670
+ helper.obliterateRange("C", 0, 1);
671
+ helper.processAllOps();
672
+ assert_1.strict.equal(helper.clients.A.getText(), "D");
673
+ assert_1.strict.equal(helper.clients.C.getText(), "D");
674
+ helper.logger.validate();
675
+ });
676
+ it("acks remote segment obliterated by local op", () => {
677
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
678
+ // (D-C-A)-B
679
+ // (D-C-A)-B-E
680
+ helper.insertText("B", 0, "AB");
681
+ helper.insertText("A", 0, "C");
682
+ helper.insertText("B", 0, "D");
683
+ // bug here: when the op is acked by client B, it wouldn't correctly
684
+ // visit the segment "C", leaving the obliterate unacked
685
+ helper.obliterateRange("B", 0, 2);
686
+ helper.processAllOps();
687
+ helper.logger.validate();
688
+ helper.insertText("C", 1, "E");
689
+ helper.processAllOps();
690
+ assert_1.strict.equal(helper.clients.A.getText(), "BE");
691
+ assert_1.strict.equal(helper.clients.B.getText(), "BE");
692
+ helper.logger.validate();
693
+ });
694
+ it("skips segments obliterated before refSeq when traversing for insertion", () => {
695
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
696
+ // CDE-(A)-B
697
+ // C-(DE-F-(A)-B)
698
+ helper.insertText("A", 0, "AB");
699
+ helper.obliterateRange("A", 0, 1);
700
+ helper.insertText("A", 0, "CDE");
701
+ helper.processAllOps();
702
+ helper.logger.validate();
703
+ helper.obliterateRange("A", 1, 4);
704
+ // bug here: when traversing to see if segment should be obliterated after
705
+ // insertion, traversal would stop at segment A because it was obliterated
706
+ // before the refSeq, which made it appear as an un-deleted segment
707
+ helper.insertText("B", 3, "F");
708
+ helper.processAllOps();
709
+ assert_1.strict.equal(helper.clients.A.getText(), "C");
710
+ assert_1.strict.equal(helper.clients.B.getText(), "C");
711
+ assert_1.strict.equal(helper.clients.C.getText(), "C");
712
+ helper.logger.validate();
713
+ });
714
+ it("applies correct movedSeq when right segment has multiple movedSeqs", () => {
715
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
716
+ // AB
717
+ // (A-C-D-(B))
718
+ helper.insertText("B", 0, "AB");
719
+ helper.processAllOps();
720
+ helper.logger.validate();
721
+ helper.obliterateRange("A", 1, 2);
722
+ helper.obliterateRange("B", 0, 2);
723
+ // bug here: for client B, segment B had multiple movedSeqs, and when
724
+ // traversal went to the right and found a matching movedSeq in the movedSeqs
725
+ // array, it selected the lowest seq in the array, which differed from
726
+ // the correct and matching movedSeq
727
+ helper.insertText("A", 1, "C");
728
+ helper.insertText("A", 2, "D");
729
+ helper.processAllOps();
730
+ assert_1.strict.equal(helper.clients.A.getText(), "");
731
+ assert_1.strict.equal(helper.clients.B.getText(), "");
732
+ assert_1.strict.equal(helper.clients.C.getText(), "");
733
+ helper.logger.validate();
734
+ });
735
+ it("takes the correct moved client id when multiple clientIds for right segment", () => {
736
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
737
+ // AB
738
+ // (A-C-D-(B))
739
+ helper.insertText("A", 0, "AB");
740
+ helper.processAllOps();
741
+ helper.logger.validate();
742
+ helper.obliterateRange("A", 1, 2);
743
+ // bug here: we would incorrectly take the client id of the first element
744
+ // in the movedClientIds array because we did not take into account the
745
+ // length of _both_ the local and non-local movedSeqs arrays
746
+ helper.insertText("A", 1, "C");
747
+ helper.obliterateRange("C", 0, 2);
748
+ helper.insertText("A", 2, "D");
749
+ helper.processAllOps();
750
+ assert_1.strict.equal(helper.clients.A.getText(), "");
751
+ assert_1.strict.equal(helper.clients.B.getText(), "");
752
+ assert_1.strict.equal(helper.clients.C.getText(), "");
753
+ helper.logger.validate();
754
+ });
755
+ it("selects clientId if 0", () => {
756
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
757
+ // AB
758
+ // (A-D-E-(C)-B)
759
+ helper.insertText("B", 0, "AB");
760
+ helper.processAllOps();
761
+ helper.logger.validate();
762
+ // bug here: client id was 0, and the check we used was !clientId, rather
763
+ // than clientId !== undefined
764
+ helper.insertText("A", 1, "C");
765
+ helper.obliterateRange("B", 0, 2);
766
+ helper.obliterateRange("A", 1, 2);
767
+ helper.insertText("A", 1, "D");
768
+ helper.insertText("A", 2, "E");
769
+ helper.processAllOps();
770
+ assert_1.strict.equal(helper.clients.A.getText(), "");
771
+ assert_1.strict.equal(helper.clients.B.getText(), "");
772
+ assert_1.strict.equal(helper.clients.C.getText(), "");
773
+ helper.logger.validate();
774
+ });
775
+ it("obliterates unacked segment inside non-leaf-segment", () => {
776
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
777
+ // FGHIJ-E-12345678-D-C-A-K-B
778
+ // FGHIJ-E-12345-(6-[7-L-8-D]-C)-A-K-B
779
+ helper.insertText("A", 0, "AB");
780
+ helper.insertText("A", 0, "C");
781
+ helper.insertText("C", 0, "D");
782
+ helper.insertText("B", 0, "12345678");
783
+ helper.insertText("B", 0, "E");
784
+ helper.insertText("C", 0, "FGHIJ");
785
+ helper.insertText("A", 2, "K");
786
+ helper.processAllOps();
787
+ helper.logger.validate();
788
+ helper.removeRange("A", 12, 15);
789
+ // bug here: when traversing for obliterate, we visit unacked segments
790
+ // within the range, considering their length 0 but still marking them
791
+ // obliterated. if the segment was inside a hiernode whose length was
792
+ // also 0, we would incorrectly skip over the entire hier node, rather
793
+ // than visiting the children segments
794
+ helper.obliterateRange("A", 11, 13);
795
+ helper.insertText("B", 13, "L");
796
+ helper.processAllOps();
797
+ assert_1.strict.equal(helper.clients.A.getText(), "FGHIJE12345AKB");
798
+ assert_1.strict.equal(helper.clients.B.getText(), "FGHIJE12345AKB");
799
+ assert_1.strict.equal(helper.clients.C.getText(), "FGHIJE12345AKB");
800
+ helper.logger.validate();
801
+ });
802
+ it("tracks length at seq of lower move/remove seq when overlapping", () => {
803
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
804
+ // H-FG-A-CDE-B
805
+ // (H-F-[G-A)-C-I-D]-E-B
806
+ helper.insertText("C", 0, "AB");
807
+ helper.insertText("C", 1, "CDE");
808
+ helper.insertText("B", 0, "FG");
809
+ helper.insertText("A", 0, "H");
810
+ helper.processAllOps();
811
+ helper.logger.validate();
812
+ helper.obliterateRange("A", 0, 4);
813
+ helper.removeRange("B", 2, 6);
814
+ // bug here: this insert triggers a new chunk to be created. when the
815
+ // partial lengths of the new chunk were calculated, it incorrectly
816
+ // used the removedSeq instead of the moveSeq, despite the latter having
817
+ // occurred prior to the remove
818
+ helper.insertText("A", 1, "I");
819
+ helper.processAllOps();
820
+ assert_1.strict.equal(helper.clients.A.getText(), "IEB");
821
+ assert_1.strict.equal(helper.clients.B.getText(), "IEB");
822
+ assert_1.strict.equal(helper.clients.C.getText(), "IEB");
823
+ helper.logger.validate();
824
+ });
825
+ it("segment obliterated on insert overlaps with local obliterate", () => {
826
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
827
+ // AB
828
+ // ((A-C)-B)
829
+ helper.insertText("B", 0, "AB");
830
+ helper.processAllOps();
831
+ helper.logger.validate();
832
+ helper.insertText("B", 1, "C");
833
+ helper.obliterateRange("B", 0, 2);
834
+ helper.obliterateRange("A", 0, 2);
835
+ helper.processAllOps();
836
+ assert_1.strict.equal(helper.clients.A.getText(), "");
837
+ helper.logger.validate();
838
+ });
839
+ it("obliterates entire string when concurrent inserts inside range", () => {
840
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
841
+ // GT
842
+ // (G-O-S-Y-T)
843
+ helper.insertText("B", 0, "GT");
844
+ helper.processAllOps();
845
+ helper.logger.validate();
846
+ helper.obliterateRange("B", 0, 2);
847
+ helper.insertText("C", 1, "OY");
848
+ helper.insertText("C", 2, "S");
849
+ helper.processAllOps();
850
+ assert_1.strict.equal(helper.clients.A.getText(), "");
851
+ helper.logger.validate();
852
+ });
853
+ it("obliterate ack traverses over non-obliterated remove", () => {
854
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
855
+ // ABCDEFGH-1
856
+ // ABCDE-(F-[G]-2-H)-1
857
+ // ABCDE-(F-[G]-2-H)-1-3
858
+ helper.insertText("A", 0, "1");
859
+ helper.insertText("C", 0, "ABCDEFGH");
860
+ helper.processAllOps();
861
+ helper.logger.validate();
862
+ helper.removeRange("C", 6, 7);
863
+ helper.insertText("A", 7, "2");
864
+ // obliterate at seq 5 isn't getting acked because it stops traversal
865
+ // at the removed segment, which doesn't have move info
866
+ helper.obliterateRange("C", 5, 7);
867
+ helper.processAllOps();
868
+ helper.logger.validate();
869
+ helper.insertText("A", 6, "3");
870
+ helper.processAllOps();
871
+ assert_1.strict.equal(helper.clients.A.getText(), "ABCDE13");
872
+ assert_1.strict.equal(helper.clients.C.getText(), "ABCDE13");
873
+ helper.logger.validate();
874
+ });
875
+ it("overlapping remove and obliterate when remove happens last", () => {
876
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
877
+ // FGH-E-D-BC-A
878
+ // ([F]-G)-H-E-D-B-I-C-A
879
+ helper.insertText("A", 0, "A");
880
+ helper.insertText("B", 0, "BC");
881
+ helper.insertText("C", 0, "D");
882
+ helper.insertText("B", 0, "E");
883
+ helper.insertText("B", 0, "FGH");
884
+ helper.processAllOps();
885
+ helper.logger.validate();
886
+ helper.obliterateRange("C", 0, 2);
887
+ helper.removeRange("A", 0, 1);
888
+ helper.insertText("A", 5, "I");
889
+ helper.processAllOps();
890
+ assert_1.strict.equal(helper.clients.A.getText(), "HEDBICA");
891
+ assert_1.strict.equal(helper.clients.B.getText(), "HEDBICA");
892
+ assert_1.strict.equal(helper.clients.C.getText(), "HEDBICA");
893
+ assert_1.strict.equal(helper.clients.D.getText(), "HEDBICA");
894
+ helper.logger.validate();
895
+ });
896
+ it("overlapping remove and obliterate when remove happens last _and_ partial length already exists", () => {
897
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
898
+ // FGH-CDE-B-A
899
+ // [F-(GH)-C]-D-Z-E-B-A
900
+ helper.insertText("B", 0, "A");
901
+ helper.insertText("B", 0, "B");
902
+ helper.insertText("B", 0, "CDE");
903
+ helper.insertText("C", 0, "FGH");
904
+ helper.processAllOps();
905
+ helper.logger.validate();
906
+ helper.obliterateRange("C", 1, 2);
907
+ helper.removeRange("A", 0, 4);
908
+ helper.insertText("A", 1, "Z");
909
+ helper.processAllOps();
910
+ assert_1.strict.equal(helper.clients.A.getText(), "DZEBA");
911
+ helper.logger.validate();
912
+ });
913
+ it("overlapping obliterate and remove when obliterate is larger than remove and happened last", () => {
914
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
915
+ // H-CDEFG-B-A
916
+ // (H-C-[D]-E)-F-Z-G-B-A
917
+ helper.insertText("B", 0, "A");
918
+ helper.insertText("C", 0, "B");
919
+ helper.insertText("A", 0, "CDEFG");
920
+ helper.insertText("A", 0, "H");
921
+ helper.processAllOps();
922
+ helper.logger.validate();
923
+ helper.removeRange("A", 2, 3);
924
+ helper.obliterateRange("C", 0, 4);
925
+ helper.insertText("C", 1, "Z");
926
+ helper.processAllOps();
927
+ assert_1.strict.equal(helper.clients.A.getText(), "FZGBA");
928
+ helper.logger.validate();
929
+ });
930
+ it("wasMovedOnInsert remains after leaf node is split", () => {
931
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
932
+ // CD-B-A
933
+ // I-(C-(G)H-E)-F-D-B-A
934
+ helper.insertText("C", 0, "A");
935
+ helper.insertText("B", 0, "B");
936
+ helper.insertText("B", 0, "CD");
937
+ helper.processAllOps();
938
+ helper.logger.validate();
939
+ helper.insertText("B", 1, "EF");
940
+ helper.obliterateRange("B", 0, 2);
941
+ helper.insertText("A", 1, "GH");
942
+ helper.obliterateRange("A", 1, 2);
943
+ helper.insertText("B", 0, "I");
944
+ helper.processAllOps();
945
+ assert_1.strict.equal(helper.clients.A.getText(), "IFDBA");
946
+ helper.logger.validate();
947
+ });
948
+ it("overlapping obliterates, segment is obliterated on insert and by local client", () => {
949
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
950
+ // DEFG-BC-A
951
+ // v-----------v
952
+ // v-----v
953
+ // (D-(E-H-F)-G)-B-I-C-A
954
+ helper.insertText("B", 0, "A");
955
+ helper.insertText("C", 0, "BC");
956
+ helper.insertText("B", 0, "DEFG");
957
+ helper.processAllOps();
958
+ helper.logger.validate();
959
+ helper.obliterateRange("B", 1, 3);
960
+ helper.insertText("A", 2, "H");
961
+ helper.obliterateRange("A", 0, 5);
962
+ helper.insertText("A", 1, "I");
963
+ helper.processAllOps();
964
+ assert_1.strict.equal(helper.clients.A.getText(), "BICA");
965
+ helper.logger.validate();
966
+ });
967
+ it("overlapping obliterates and remove", () => {
968
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
969
+ // FGHIJKL-BCDE-A
970
+ // (FGHI-[JK-(L-B)-C]-D)-E-M-A
971
+ helper.insertText("C", 0, "A");
972
+ helper.insertText("B", 0, "BCDE");
973
+ helper.insertText("A", 0, "FGHIJKL");
974
+ helper.processAllOps();
975
+ helper.logger.validate();
976
+ helper.removeRange("B", 4, 9);
977
+ helper.obliterateRange("A", 6, 8);
978
+ helper.obliterateRange("C", 0, 10);
979
+ helper.insertText("C", 1, "M");
980
+ helper.processAllOps();
981
+ assert_1.strict.equal(helper.clients.A.getText(), "EMA");
982
+ helper.logger.validate();
983
+ });
984
+ it("does not mark obliterated on insert for non-acked obliterates", () => {
985
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
986
+ // CDE-B-A
987
+ // I-((C-F)-G-D)-H-E-B-A
988
+ helper.insertText("B", 0, "A");
989
+ helper.insertText("A", 0, "B");
990
+ helper.insertText("C", 0, "CDE");
991
+ helper.processAllOps();
992
+ helper.logger.validate();
993
+ helper.insertText("A", 1, "FG");
994
+ helper.obliterateRange("A", 0, 2);
995
+ helper.insertText("A", 2, "H");
996
+ helper.obliterateRange("C", 0, 2);
997
+ helper.insertText("C", 0, "I");
998
+ helper.processAllOps();
999
+ assert_1.strict.equal(helper.clients.A.getText(), "IHEBA");
1000
+ helper.logger.validate();
1001
+ });
1002
+ it("partial len isLocal when seq is -1 but moveSeq > -1", () => {
1003
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1004
+ // CDEFG-AB
1005
+ // C-((D-I-E)-F)-G-A-H-B
1006
+ helper.insertText("A", 0, "AB");
1007
+ helper.insertText("B", 0, "CDEFG");
1008
+ helper.processAllOps();
1009
+ helper.logger.validate();
1010
+ helper.obliterateRange("C", 1, 4);
1011
+ helper.obliterateRange("B", 1, 3);
1012
+ helper.insertText("B", 4, "H");
1013
+ helper.insertText("A", 2, "I");
1014
+ helper.processAllOps();
1015
+ assert_1.strict.equal(helper.clients.A.getText(), "CGAHB");
1016
+ helper.logger.validate();
1017
+ });
1018
+ it("obliterated on insert by overlapping obliterates", () => {
1019
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1020
+ // B-DEFG-C-A
1021
+ // ((B-D-H-E)-F-I-G-C)-A
1022
+ helper.insertText("C", 0, "A");
1023
+ helper.insertText("A", 0, "BC");
1024
+ helper.insertText("A", 1, "DEFG");
1025
+ helper.processAllOps();
1026
+ helper.logger.validate();
1027
+ helper.obliterateRange("B", 0, 6);
1028
+ helper.obliterateRange("A", 0, 3);
1029
+ helper.insertText("C", 2, "H");
1030
+ helper.insertText("A", 1, "I");
1031
+ helper.processAllOps();
1032
+ assert_1.strict.equal(helper.clients.A.getText(), "A");
1033
+ helper.logger.validate();
1034
+ });
1035
+ it("overlapping obliterates", () => {
1036
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1037
+ // ABCDEF
1038
+ // v-------------v
1039
+ // v-----------v
1040
+ // v-------v
1041
+ // I-((AB-(C-G)-H-D)-E)-F
1042
+ helper.insertText("A", 0, "ABCDEF");
1043
+ helper.processAllOps();
1044
+ helper.logger.validate();
1045
+ helper.obliterateRange("B", 0, 4);
1046
+ helper.obliterateRange("C", 2, 5);
1047
+ helper.insertText("A", 3, "GH");
1048
+ helper.insertText("C", 0, "I");
1049
+ helper.obliterateRange("A", 0, 4);
1050
+ helper.processAllOps();
1051
+ assert_1.strict.equal(helper.clients.A.getText(), "IF");
1052
+ helper.logger.validate();
1053
+ });
1054
+ it("overlapping obliterates", () => {
1055
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1056
+ // CDEF-AB
1057
+ // v-------------------v
1058
+ // v---------v
1059
+ // v-v
1060
+ // ((C-(G)-H-D)-E-I-F-A)-B
1061
+ helper.insertText("B", 0, "AB");
1062
+ helper.insertText("C", 0, "CDEF");
1063
+ helper.processAllOps();
1064
+ helper.logger.validate();
1065
+ helper.obliterateRange("B", 0, 5);
1066
+ helper.obliterateRange("C", 0, 2);
1067
+ helper.insertText("A", 1, "GH");
1068
+ helper.insertText("C", 1, "I");
1069
+ helper.obliterateRange("A", 1, 2);
1070
+ helper.processAllOps();
1071
+ assert_1.strict.equal(helper.clients.A.getText(), "B");
1072
+ helper.logger.validate();
1073
+ });
1074
+ it("overlapping remove and obliterate, local obliterate does not have a remote obliterated len", () => {
1075
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1076
+ // v-v------v-v
1077
+ // G-(H-[F]-E)-D-[A]-B-I-C
1078
+ helper.insertText("A", 0, "ABC");
1079
+ helper.insertText("B", 0, "D");
1080
+ helper.insertText("B", 0, "E");
1081
+ helper.insertText("A", 0, "F");
1082
+ helper.removeRange("A", 0, 2);
1083
+ helper.insertText("B", 0, "GH");
1084
+ helper.insertText("A", 1, "I");
1085
+ helper.obliterateRange("B", 1, 3);
1086
+ helper.processAllOps();
1087
+ assert_1.strict.equal(helper.clients.A.getText(), "GDBIC");
1088
+ helper.logger.validate();
1089
+ });
1090
+ it("triple overlapping obliterate and overlapping remove", () => {
1091
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1092
+ // I-H-BCDEFG-A
1093
+ // v------------v
1094
+ // v-------v
1095
+ // v-v
1096
+ // v-------------------------v
1097
+ // [[I]-H-BCD-(E-(F-(J)-G))-A]
1098
+ helper.insertText("C", 0, "A");
1099
+ helper.insertText("B", 0, "BCDEFG");
1100
+ helper.insertText("B", 0, "H");
1101
+ helper.insertText("B", 0, "I");
1102
+ helper.processAllOps();
1103
+ helper.logger.validate();
1104
+ helper.obliterateRange("B", 6, 8);
1105
+ helper.obliterateRange("A", 5, 8);
1106
+ helper.removeRange("C", 0, 1);
1107
+ helper.insertText("C", 6, "J");
1108
+ helper.obliterateRange("C", 6, 7);
1109
+ helper.removeRange("A", 0, 6);
1110
+ helper.processAllOps();
1111
+ assert_1.strict.equal(helper.clients.A.getText(), "");
1112
+ assert_1.strict.equal(helper.clients.C.getText(), "");
1113
+ helper.logger.validate();
1114
+ });
1115
+ it("triple overlapping obliterate with one being local", () => {
1116
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1117
+ // CDEFG-B-A
1118
+ // v--------v
1119
+ // v--------v
1120
+ // v------v
1121
+ // J-(CD-((E-H)-F))-I-G-B-A
1122
+ helper.insertText("C", 0, "A");
1123
+ helper.insertText("B", 0, "B");
1124
+ helper.insertText("C", 0, "CDEFG");
1125
+ helper.processAllOps();
1126
+ helper.logger.validate();
1127
+ helper.obliterateRange("A", 2, 4);
1128
+ helper.insertText("C", 3, "H");
1129
+ helper.obliterateRange("C", 0, 4);
1130
+ helper.insertText("C", 1, "I");
1131
+ helper.insertText("B", 0, "J");
1132
+ helper.obliterateRange("B", 3, 5);
1133
+ helper.processAllOps();
1134
+ assert_1.strict.equal(helper.clients.C.getText(), "JIGBA");
1135
+ helper.logger.validate();
1136
+ });
1137
+ it("obliterate ack traversal is not stopped by moved segment", () => {
1138
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1139
+ // ABCD
1140
+ // (A-(B)-E-C)-D-F
1141
+ helper.insertText("B", 0, "ABCD");
1142
+ helper.processAllOps();
1143
+ helper.logger.validate();
1144
+ helper.obliterateRange("A", 1, 2);
1145
+ helper.insertText("C", 2, "E");
1146
+ helper.obliterateRange("A", 0, 2);
1147
+ helper.processAllOps();
1148
+ helper.logger.validate();
1149
+ helper.insertText("C", 1, "F");
1150
+ helper.processAllOps();
1151
+ assert_1.strict.equal(helper.clients.A.getText(), "DF");
1152
+ assert_1.strict.equal(helper.clients.C.getText(), "DF");
1153
+ helper.logger.validate();
1154
+ });
1155
+ it("updates partial lengths for segments when doing obliterate ack traversal", () => {
1156
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1157
+ // O-JKLMN-FGHI-E-CD-AB
1158
+ // v-v---v-----v
1159
+ // (P-O-JKLMN-FG-[H]-Q-[I-E-C]-D-A)-B
1160
+ // (P-O-JKLMN-FG-[H]-Q-[I-E-C]-D-A)-B-R
1161
+ // problematic segment: H-Q-I-E
1162
+ helper.insertText("B", 0, "AB");
1163
+ helper.insertText("A", 0, "CD");
1164
+ helper.insertText("A", 0, "E");
1165
+ helper.insertText("A", 0, "FGHI");
1166
+ helper.insertText("C", 0, "JKLMN");
1167
+ helper.insertText("B", 0, "O");
1168
+ helper.processAllOps();
1169
+ helper.logger.validate();
1170
+ helper.insertText("A", 0, "P");
1171
+ helper.insertText("B", 9, "Q");
1172
+ helper.removeRange("A", 9, 13);
1173
+ helper.obliterateRange("A", 0, 11);
1174
+ helper.processAllOps();
1175
+ helper.logger.validate();
1176
+ helper.insertText("B", 1, "R");
1177
+ helper.processAllOps();
1178
+ assert_1.strict.equal(helper.clients.A.getText(), "BR");
1179
+ helper.logger.validate();
1180
+ });
1181
+ // fails only for incremental
1182
+ it("combines remote obliterated length ", () => {
1183
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1184
+ // R-XYZ12-STUVW-LMNOP-DEFGHIJK-A-34567890-Q-BC
1185
+ // v---------------v------------v------v--------v------------v
1186
+ // [R-XYZ12-STUVW-L]-abcdefghij-[MNOP-D]-klmnop-[EFGHIJK-A-34]-5-(6-x-7)-890-Q-BC
1187
+ // v--------v
1188
+ // v--------v
1189
+ // a-T-b-S-c-[def]-ghij-k-Q-l-R-mno-[p-5-8-[9]-0-Q-B]-C
1190
+ // v--------v
1191
+ // v--------v
1192
+ // segment is R-mno-[p-5-8-[9]-0-Q-B]-C
1193
+ // v-------------------------------v
1194
+ // v--------v
1195
+ // v------------v
1196
+ // R-mno-[p-[EFGHIJK-A-34]-5-(6-x-7)-8-[9]-0-Q-B]-C
1197
+ helper.insertText("A", 0, "ABC");
1198
+ helper.insertText("C", 0, "DEFGHIJK");
1199
+ helper.insertText("C", 0, "LMNOP");
1200
+ helper.insertText("A", 1, "Q");
1201
+ helper.insertText("B", 0, "RSTUVW");
1202
+ helper.insertText("B", 1, "XYZ12");
1203
+ helper.insertText("A", 1, "34567890");
1204
+ helper.processAllOps();
1205
+ helper.logger.validate();
1206
+ helper.insertText("C", 29, "x");
1207
+ helper.removeRange("B", 0, 27);
1208
+ helper.insertText("A", 12, "abcdefghij");
1209
+ helper.obliterateRange("A", 38, 40);
1210
+ helper.insertText("C", 17, "klmnop");
1211
+ helper.processAllOps();
1212
+ assert_1.strict.equal(helper.clients.A.getText(), "abcdefghijklmnop5890QBC");
1213
+ helper.logger.validate();
1214
+ helper.removeRange("B", 3, 6);
1215
+ helper.insertText("C", 11, "Q");
1216
+ helper.insertText("B", 9, "R");
1217
+ helper.insertText("B", 2, "S");
1218
+ helper.removeRange("C", 19, 23);
1219
+ helper.obliterateRange("B", 14, 18);
1220
+ helper.insertText("B", 1, "T");
1221
+ helper.processAllOps();
1222
+ assert_1.strict.equal(helper.clients.A.getText(), "aTbScghijkQlRmnoC");
1223
+ helper.logger.validate();
1224
+ });
1225
+ it("three obliterates on same segment", () => {
1226
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1227
+ // A
1228
+ // (C-B-D-((A)))
1229
+ helper.insertText("B", 0, "A");
1230
+ helper.processAllOps();
1231
+ helper.logger.validate();
1232
+ helper.obliterateRange("B", 0, 1);
1233
+ helper.obliterateRange("A", 0, 1);
1234
+ helper.insertText("A", 0, "B");
1235
+ helper.insertText("C", 0, "C");
1236
+ helper.insertText("A", 1, "D");
1237
+ helper.obliterateRange("C", 0, 2);
1238
+ helper.processAllOps();
1239
+ helper.logger.validate();
1240
+ });
1241
+ describe("incremental partial length updates", () => {
1242
+ it("obliterates concurrently inserted segment", () => {
1243
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1244
+ // (C-B-A)
1245
+ helper.insertText("A", 0, "A");
1246
+ helper.insertText("B", 0, "B");
1247
+ helper.insertText("A", 0, "C");
1248
+ helper.obliterateRange("A", 0, 2);
1249
+ helper.processAllOps();
1250
+ assert_1.strict.equal(helper.clients.A.getText(), "");
1251
+ helper.logger.validate();
1252
+ });
1253
+ it("obliterates 2 concurrently inserted segments", () => {
1254
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1255
+ // (C-B-D-A)
1256
+ helper.insertText("B", 0, "A");
1257
+ helper.insertText("A", 0, "B");
1258
+ helper.insertText("B", 0, "C");
1259
+ helper.obliterateRange("B", 0, 2);
1260
+ helper.insertText("A", 1, "D");
1261
+ helper.processAllOps();
1262
+ assert_1.strict.equal(helper.clients.A.getText(), "");
1263
+ helper.logger.validate();
1264
+ });
1265
+ it("obliterates 4 concurrently inserted segments", () => {
1266
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1267
+ // I-F-(G-D-H-E-C-A)-B
1268
+ helper.insertText("B", 0, "AB");
1269
+ helper.insertText("B", 0, "C");
1270
+ helper.insertText("A", 0, "DE");
1271
+ helper.insertText("B", 0, "FG");
1272
+ helper.obliterateRange("B", 1, 4);
1273
+ helper.insertText("A", 1, "H");
1274
+ helper.insertText("B", 0, "I");
1275
+ helper.processAllOps();
1276
+ assert_1.strict.equal(helper.clients.A.getText(), "IFB");
1277
+ helper.logger.validate();
1278
+ });
1279
+ it("obliterates 3 concurrently inserted segments", () => {
1280
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1281
+ // I-G-(H-D-F-E-B)-C-A
1282
+ helper.insertText("B", 0, "A");
1283
+ helper.insertText("B", 0, "BC");
1284
+ helper.insertText("A", 0, "DE");
1285
+ helper.insertText("A", 1, "F");
1286
+ helper.insertText("B", 0, "GH");
1287
+ helper.obliterateRange("B", 1, 3);
1288
+ helper.insertText("B", 0, "I");
1289
+ helper.processAllOps();
1290
+ assert_1.strict.equal(helper.clients.A.getText(), "IGCA");
1291
+ helper.logger.validate();
1292
+ });
1293
+ it("overlapping remove + obliterate, remove happened first", () => {
1294
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1295
+ // D-EFG-B-H-C-A
1296
+ // I-D-([E]-F)-G-B-H-C-A
1297
+ helper.insertText("A", 0, "A");
1298
+ helper.insertText("B", 0, "BC");
1299
+ helper.insertText("C", 0, "DEFG");
1300
+ helper.insertText("B", 1, "H");
1301
+ helper.processAllOps();
1302
+ helper.logger.validate();
1303
+ helper.removeRange("B", 1, 2);
1304
+ helper.obliterateRange("A", 1, 3);
1305
+ helper.insertText("A", 0, "I");
1306
+ helper.processAllOps();
1307
+ assert_1.strict.equal(helper.clients.A.getText(), "IDGBHCA");
1308
+ helper.logger.validate();
1309
+ });
1310
+ it("overlapping remove + obliterate, remove happened last", () => {
1311
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1312
+ // DEFGH-C-B-A
1313
+ // [D]-[E-(F)-G]-H-C-B-A
1314
+ helper.insertText("C", 0, "A");
1315
+ helper.insertText("B", 0, "B");
1316
+ helper.insertText("A", 0, "C");
1317
+ helper.insertText("B", 0, "DEFGH");
1318
+ helper.processAllOps();
1319
+ helper.logger.validate();
1320
+ helper.obliterateRange("C", 2, 3);
1321
+ helper.removeRange("A", 1, 4);
1322
+ helper.removeRange("A", 0, 1);
1323
+ helper.processAllOps();
1324
+ assert_1.strict.equal(helper.clients.A.getText(), "HCBA");
1325
+ helper.logger.validate();
1326
+ });
1327
+ it("segment inside locally obliterated segment group is split", () => {
1328
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1329
+ // CDEF-AB
1330
+ // [C]-DE-(F-(G)-H-A)-B
1331
+ // [C]-DE-(F-(G)-H-A)-(B)
1332
+ helper.insertText("B", 0, "AB");
1333
+ helper.insertText("B", 0, "CDEF");
1334
+ helper.processAllOps();
1335
+ helper.logger.validate();
1336
+ helper.removeRange("C", 0, 1);
1337
+ helper.insertText("C", 3, "GH");
1338
+ helper.obliterateRange("C", 3, 4);
1339
+ helper.obliterateRange("A", 3, 5);
1340
+ helper.processAllOps();
1341
+ helper.logger.validate();
1342
+ helper.obliterateRange("B", 2, 3);
1343
+ helper.processAllOps();
1344
+ assert_1.strict.equal(helper.clients.A.getText(), "DE");
1345
+ helper.logger.validate();
1346
+ });
1347
+ it("continues traversal past locally removed segment inserted before first obliterate", () => {
1348
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1349
+ // ABC
1350
+ // (E-D-(A)-[B]-C)
1351
+ helper.insertText("A", 0, "ABC");
1352
+ helper.processAllOps();
1353
+ helper.logger.validate();
1354
+ helper.obliterateRange("C", 0, 1);
1355
+ helper.insertText("B", 0, "D");
1356
+ helper.removeRange("C", 0, 1);
1357
+ helper.insertText("C", 0, "E");
1358
+ helper.obliterateRange("C", 0, 2);
1359
+ helper.processAllOps();
1360
+ assert_1.strict.equal(helper.clients.A.getText(), "");
1361
+ helper.logger.validate();
1362
+ });
1363
+ it("keeps track of remote obliterated length when hier node contains hier nodes", () => {
1364
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1365
+ // LMNO-HIJ-E-K-FG-D-C-AB
1366
+ // lmnopq-L-[M]-NO-H-ghijk-I-(J-E-K-FG-D-C-A-a)-bc-ef-d-B
1367
+ // v--------------------------------------v
1368
+ // v-------------------v
1369
+ // r-l-x-mn-[opq-L-[M]-NO-H-gh-s]-t-(u-i-[j]-k-I-(J-E-K-FG-D-C-A-a)-b-v-c-e)-f-d-B
1370
+ // bad segment: (I-(J-E-K-FG-D-C-A-a)-b-v-c-e)-f-d-B
1371
+ helper.insertText("B", 0, "AB");
1372
+ helper.insertText("C", 0, "C");
1373
+ helper.insertText("A", 0, "D");
1374
+ helper.insertText("B", 0, "EFG");
1375
+ helper.insertText("C", 0, "HIJ");
1376
+ helper.insertText("B", 1, "K");
1377
+ helper.insertText("B", 0, "LMNO");
1378
+ helper.processAllOps();
1379
+ helper.logger.validate();
1380
+ helper.removeRange("A", 1, 2);
1381
+ helper.insertText("A", 13, "abcd");
1382
+ helper.obliterateRange("A", 5, 14);
1383
+ helper.insertText("A", 7, "ef"); // seq: 11, len: 7
1384
+ helper.insertText("B", 5, "ghijk");
1385
+ helper.insertText("C", 0, "lmnopq"); // seq: 13, len: 7
1386
+ helper.processAllOps();
1387
+ assert_1.strict.equal(helper.clients.A.getText(), "lmnopqLNOHghijkIbcefdB");
1388
+ helper.logger.validate();
1389
+ helper.insertText("A", 0, "r");
1390
+ helper.insertText("B", 12, "stu");
1391
+ helper.insertText("A", 18, "v"); // seq: 16, len: 8
1392
+ helper.obliterateRange("B", 14, 22); // seq: 17, len: 3
1393
+ helper.removeRange("B", 3, 13); // seq: 18, len: 3
1394
+ helper.removeRange("A", 14, 15); // seq: 19, len: 3
1395
+ helper.insertText("B", 1, "x");
1396
+ helper.processAllOps();
1397
+ assert_1.strict.equal(helper.clients.A.getText(), "rlxmntfdB");
1398
+ helper.logger.validate();
1399
+ });
1400
+ it("combines remote obliterated length for parent node of tree with depth >=3", () => {
1401
+ const helper = new reconnectHelper_1.ReconnectTestHelper();
1402
+ // VWXYZ0-(K)-[L]-M-[N]-O-EFGHIJ-[A]-B-P-TU-QRS-CD
1403
+ // v-v------v------------v
1404
+ // v--------------------v
1405
+ // v----v---------v-v-----v-----v------------------------------v-v
1406
+ // V-c-W-[XYZ0]-(K)-[L]-[M]-[N]-[O-EFG]-[H]-a-[b-[IJ-[A]-B-P-T]-U-Q]-[R]-S-C-d-f-e-D
1407
+ // v-v------v-v---v-----------v
1408
+ // v-------------------------v
1409
+ // v------v---------v-v-----v---v---v--v-----------------------------------v-v
1410
+ // v---------v
1411
+ // j-i-(V-c-W-[XY)-Z0]-(K)-[L]-[M]-[N]-[O-E]-h-[FG]-[H]-a-[b-[I]-g-[J-[A]-B-P-T]-U-Q]-[R]-S-C-d-f-e-D
1412
+ // problem segment: j-i-(V-c-W-[XY)-Z0]-(K)-[L]-[M]-[N]-[O-E]-h-[FG]-[H]-a-[b]
1413
+ // specifically: j-(V-c-W
1414
+ helper.insertText("C", 0, "ABCD");
1415
+ helper.removeRange("C", 0, 1);
1416
+ helper.insertText("B", 0, "EFGHIJ");
1417
+ helper.insertText("A", 0, "KLMNO");
1418
+ helper.obliterateRange("A", 0, 1);
1419
+ helper.removeRange("A", 0, 1);
1420
+ helper.insertText("C", 1, "PQRS");
1421
+ helper.insertText("C", 2, "TU");
1422
+ helper.removeRange("A", 1, 2);
1423
+ helper.insertText("A", 0, "VWXYZ0"); // seq: 10, len: 2
1424
+ helper.processAllOps();
1425
+ assert_1.strict.equal(helper.clients.A.getText(), "VWXYZ0MOEFGHIJBPTUQRSCD");
1426
+ helper.logger.validate();
1427
+ helper.insertText("C", 12, "ab");
1428
+ helper.removeRange("B", 11, 17);
1429
+ helper.removeRange("C", 13, 21);
1430
+ helper.insertText("B", 1, "c"); // seq: 14, len: 3
1431
+ helper.insertText("C", 16, "de");
1432
+ helper.insertText("C", 17, "f");
1433
+ helper.removeRange("B", 3, 15);
1434
+ helper.insertText("A", 13, "g");
1435
+ helper.insertText("A", 9, "h");
1436
+ helper.obliterateRange("C", 0, 4); // seq: 20, len: 0
1437
+ helper.insertText("C", 0, "i");
1438
+ helper.insertText("A", 0, "j"); // seq: 22, len: 1
1439
+ helper.processAllOps();
1440
+ assert_1.strict.equal(helper.clients.A.getText(), "jihagSCdfeD");
1441
+ helper.logger.validate();
1442
+ });
1443
+ });
1444
+ });
1445
+ }
1446
+ //# sourceMappingURL=obliterate.concurrent.spec.js.map