transform.js 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356
  1. /**
  2. * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. /* bender-tags: treemodel, operation */
  6. 'use strict';
  7. import RootElement from '/ckeditor5/core/treemodel/rootelement.js';
  8. import Node from '/ckeditor5/core/treemodel/node.js';
  9. import Position from '/ckeditor5/core/treemodel/position.js';
  10. import Range from '/ckeditor5/core/treemodel/range.js';
  11. import Attribute from '/ckeditor5/core/treemodel/attribute.js';
  12. import transform from '/ckeditor5/core/treemodel/operation/transform.js';
  13. import InsertOperation from '/ckeditor5/core/treemodel/operation/insertoperation.js';
  14. import AttributeOperation from '/ckeditor5/core/treemodel/operation/attributeoperation.js';
  15. import MoveOperation from '/ckeditor5/core/treemodel/operation/moveoperation.js';
  16. import NoOperation from '/ckeditor5/core/treemodel/operation/nooperation.js';
  17. describe( 'transform', () => {
  18. let root, op, nodeA, nodeB, expected, baseVersion;
  19. beforeEach( () => {
  20. root = new RootElement( null );
  21. nodeA = new Node();
  22. nodeB = new Node();
  23. baseVersion = 0;
  24. } );
  25. function expectOperation( op, params ) {
  26. for ( let i in params ) {
  27. if ( params.hasOwnProperty( i ) ) {
  28. if ( i == 'type' ) {
  29. expect( op ).to.be.instanceof( params[ i ] );
  30. }
  31. else if ( params[ i ] instanceof Array ) {
  32. expect( op[ i ].length ).to.equal( params[ i ].length );
  33. for ( let j = 0; j < params[ i ].length; j++ ) {
  34. expect( op[ i ][ j ] ).to.equal( params[ i ][ j ] );
  35. }
  36. } else if ( params[ i ] instanceof Position || params[ i ] instanceof Range ) {
  37. expect( op[ i ].isEqual( params[ i ] ) ).to.be.true;
  38. } else {
  39. expect( op[ i ] ).to.equal( params[ i ] );
  40. }
  41. }
  42. }
  43. }
  44. describe( 'InsertOperation', () => {
  45. let nodeC, nodeD, position;
  46. beforeEach( () => {
  47. nodeC = new Node();
  48. nodeD = new Node();
  49. position = new Position( root, [ 0, 2, 1 ] );
  50. op = new InsertOperation( position, [ nodeA, nodeB ], baseVersion );
  51. expected = {
  52. type: InsertOperation,
  53. position: Position.createFromPosition( position ),
  54. baseVersion: baseVersion + 1
  55. };
  56. } );
  57. describe( 'by InsertOperation', () => {
  58. it( 'target at different position: no position update', () => {
  59. let transformBy = new InsertOperation(
  60. new Position( root, [ 1, 3, 2 ] ),
  61. [ nodeC, nodeD ],
  62. baseVersion
  63. );
  64. let transOp = transform( op, transformBy );
  65. expect( transOp.length ).to.equal( 1 );
  66. expectOperation( transOp[ 0 ], expected );
  67. } );
  68. it( 'target at offset before: increment offset', () => {
  69. let transformBy = new InsertOperation(
  70. new Position( root, [ 0, 2, 0 ] ),
  71. [ nodeC, nodeD ],
  72. baseVersion
  73. );
  74. let transOp = transform( op, transformBy );
  75. expected.position.offset += 2;
  76. expect( transOp.length ).to.equal( 1 );
  77. expectOperation( transOp[ 0 ], expected );
  78. } );
  79. it( 'target at same offset and is important: increment offset', () => {
  80. let transformBy = new InsertOperation(
  81. new Position( root, [ 0, 2, 1 ] ),
  82. [ nodeC, nodeD ],
  83. baseVersion
  84. );
  85. let transOp = transform( op, transformBy );
  86. expected.position.offset += 2;
  87. expect( transOp.length ).to.equal( 1 );
  88. expectOperation( transOp[ 0 ], expected );
  89. } );
  90. it( 'target at same offset and is less important: no position update', () => {
  91. let transformBy = new InsertOperation(
  92. new Position( root, [ 0, 2, 1 ] ),
  93. [ nodeC, nodeD ],
  94. baseVersion
  95. );
  96. let transOp = transform( transformBy, true );
  97. expect( transOp.length ).to.equal( 1 );
  98. expectOperation( transOp[ 0 ], expected );
  99. } );
  100. it( 'target at offset after: no position update', () => {
  101. let transformBy = new InsertOperation(
  102. new Position( root, [ 0, 2, 2 ] ),
  103. [ nodeC, nodeD ],
  104. baseVersion
  105. );
  106. let transOp = transform( op, transformBy );
  107. expect( transOp.length ).to.equal( 1 );
  108. expectOperation( transOp[ 0 ], expected );
  109. } );
  110. it( 'target before node from path: increment index on path', () => {
  111. let transformBy = new InsertOperation(
  112. new Position( root, [ 0, 1 ] ),
  113. [ nodeC, nodeD ],
  114. baseVersion
  115. );
  116. let transOp = transform( op, transformBy );
  117. expected.position.path[ 1 ] += 2;
  118. expect( transOp.length ).to.equal( 1 );
  119. expectOperation( transOp[ 0 ], expected );
  120. } );
  121. it( 'target after node from path: no position update', () => {
  122. let transformBy = new InsertOperation(
  123. new Position( root, [ 0, 6 ] ),
  124. [ nodeC, nodeD ],
  125. baseVersion
  126. );
  127. let transOp = transform( op, transformBy );
  128. expect( transOp.length ).to.equal( 1 );
  129. expectOperation( transOp[ 0 ], expected );
  130. } );
  131. } );
  132. describe( 'by AttributeOperation', () => {
  133. it( 'no position update', () => {
  134. let transformBy = new AttributeOperation(
  135. Range.createFromPositionAndShift( position, 2 ),
  136. null,
  137. new Attribute( 'foo', 'bar' ),
  138. baseVersion
  139. );
  140. let transOp = transform( op, transformBy );
  141. expect( transOp.length ).to.equal( 1 );
  142. expectOperation( transOp[ 0 ], expected );
  143. } );
  144. } );
  145. describe( 'by MoveOperation', () => {
  146. it( 'range and target are different than insert position: no position update', () => {
  147. let transformBy = new MoveOperation(
  148. new Position( root, [ 1, 3, 2 ] ),
  149. 2,
  150. new Position( root, [ 2, 1 ] ),
  151. baseVersion
  152. );
  153. let transOp = transform( op, transformBy );
  154. expect( transOp.length ).to.equal( 1 );
  155. expectOperation( transOp[ 0 ], expected );
  156. } );
  157. it( 'range offset is before insert position offset: decrement offset', () => {
  158. let transformBy = new MoveOperation(
  159. new Position( root, [ 0, 2, 0 ] ),
  160. 1,
  161. new Position( root, [ 1, 1 ] ),
  162. baseVersion
  163. );
  164. let transOp = transform( op, transformBy );
  165. expected.position.offset--;
  166. expect( transOp.length ).to.equal( 1 );
  167. expectOperation( transOp[ 0 ], expected );
  168. } );
  169. it( 'range offset is after insert position offset: no position update', () => {
  170. let transformBy = new MoveOperation(
  171. new Position( root, [ 0, 2, 4 ] ),
  172. 1,
  173. new Position( root, [ 1, 1 ] ),
  174. baseVersion
  175. );
  176. let transOp = transform( op, transformBy );
  177. expect( transOp.length ).to.equal( 1 );
  178. expectOperation( transOp[ 0 ], expected );
  179. } );
  180. it( 'target offset before insert position offset: increment offset', () => {
  181. let transformBy = new MoveOperation(
  182. new Position( root, [ 1, 1 ] ),
  183. 2,
  184. new Position( root, [ 0, 2, 0 ] ),
  185. baseVersion
  186. );
  187. let transOp = transform( op, transformBy );
  188. expected.position.offset += 2;
  189. expect( transOp.length ).to.equal( 1 );
  190. expectOperation( transOp[ 0 ], expected );
  191. } );
  192. it( 'target offset after insert position offset: no position update', () => {
  193. let transformBy = new MoveOperation(
  194. new Position( root, [ 1, 1 ] ),
  195. 2,
  196. new Position( root, [ 0, 2, 4 ] ),
  197. baseVersion
  198. );
  199. let transOp = transform( op, transformBy );
  200. expect( transOp.length ).to.equal( 1 );
  201. expectOperation( transOp[ 0 ], expected );
  202. } );
  203. it( 'target offset same as insert position offset and is important: increment offset', () => {
  204. let transformBy = new MoveOperation(
  205. new Position( root, [ 1, 1 ] ),
  206. 2,
  207. new Position( root, [ 0, 2, 1 ] ),
  208. baseVersion
  209. );
  210. let transOp = transform( op, transformBy );
  211. expected.position.offset += 2;
  212. expect( transOp.length ).to.equal( 1 );
  213. expectOperation( transOp[ 0 ], expected );
  214. } );
  215. it( 'target offset same as insert position offset and is less important: no position update', () => {
  216. let transformBy = new MoveOperation(
  217. new Position( root, [ 1, 1 ] ),
  218. 2,
  219. new Position( root, [ 0, 2, 1 ] ),
  220. baseVersion
  221. );
  222. let transOp = transform( op, transformBy, true );
  223. expect( transOp.length ).to.equal( 1 );
  224. expectOperation( transOp[ 0 ], expected );
  225. } );
  226. it( 'range is before node from insert position path: decrement index on path', () => {
  227. let transformBy = new MoveOperation(
  228. new Position( root, [ 0, 0 ] ),
  229. 2,
  230. new Position( root, [ 1, 0 ] ),
  231. baseVersion
  232. );
  233. let transOp = transform( op, transformBy );
  234. expected.position.path[ 1 ] -= 2;
  235. expect( transOp.length ).to.equal( 1 );
  236. expectOperation( transOp[ 0 ], expected );
  237. } );
  238. it( 'range is after node from insert position path: no position update', () => {
  239. let transformBy = new MoveOperation(
  240. new Position( root, [ 0, 4 ] ),
  241. 2,
  242. new Position( root, [ 1, 0 ] ),
  243. baseVersion
  244. );
  245. let transOp = transform( op, transformBy );
  246. expect( transOp.length ).to.equal( 1 );
  247. expectOperation( transOp[ 0 ], expected );
  248. } );
  249. it( 'target before node from insert position path: increment index on path', () => {
  250. let transformBy = new MoveOperation(
  251. new Position( root, [ 1, 0 ] ),
  252. 2,
  253. new Position( root, [ 0, 0 ] ),
  254. baseVersion
  255. );
  256. let transOp = transform( op, transformBy );
  257. expected.position.path[ 1 ] += 2;
  258. expect( transOp.length ).to.equal( 1 );
  259. expectOperation( transOp[ 0 ], expected );
  260. } );
  261. it( 'target after node from insert position path: no position update', () => {
  262. let transformBy = new MoveOperation(
  263. new Position( root, [ 1, 0 ] ),
  264. 2,
  265. new Position( root, [ 0, 4 ] ),
  266. baseVersion
  267. );
  268. let transOp = transform( op, transformBy );
  269. expect( transOp.length ).to.equal( 1 );
  270. expectOperation( transOp[ 0 ], expected );
  271. } );
  272. it( 'range has node that contains insert position: update position', () => {
  273. let transformBy = new MoveOperation(
  274. new Position( root, [ 0, 1 ] ),
  275. 2,
  276. new Position( root, [ 1, 1 ] ),
  277. baseVersion
  278. );
  279. let transOp = transform( op, transformBy );
  280. expected.position.path = [ 1, 2, 1 ];
  281. expect( transOp.length ).to.equal( 1 );
  282. expectOperation( transOp[ 0 ], expected );
  283. } );
  284. it( 'range contains insert position (on same level): set position offset to range start', () => {
  285. let transformBy = new MoveOperation(
  286. new Position( root, [ 0, 2, 0 ] ),
  287. 3,
  288. new Position( root, [ 1, 0 ] ),
  289. baseVersion
  290. );
  291. let transOp = transform( op, transformBy );
  292. expected.position.offset = 0;
  293. expect( transOp.length ).to.equal( 1 );
  294. expectOperation( transOp[ 0 ], expected );
  295. } );
  296. } );
  297. describe( 'by NoOperation', () => {
  298. it( 'no operation update', () => {
  299. let transformBy = new NoOperation( baseVersion );
  300. let transOp = transform( op, transformBy );
  301. expect( transOp.length ).to.equal( 1 );
  302. expectOperation( transOp[ 0 ], expected );
  303. } );
  304. } );
  305. } );
  306. describe( 'AttributeOperation', () => {
  307. let start, end, range, oldAttr, newAttr, anotherOldAttr, anotherNewAttr;
  308. beforeEach( () => {
  309. oldAttr = new Attribute( 'foo', 'abc' );
  310. newAttr = new Attribute( 'foo', 'bar' );
  311. anotherOldAttr = new Attribute( oldAttr.key, 'another' );
  312. anotherNewAttr = new Attribute( oldAttr.key, 'anothernew' );
  313. expected = {
  314. type: AttributeOperation,
  315. oldAttr: oldAttr,
  316. newAttr: newAttr,
  317. baseVersion: baseVersion + 1
  318. };
  319. } );
  320. describe( 'with multi-level range', () => {
  321. beforeEach( () => {
  322. start = new Position( root, [ 1, 2 ] );
  323. end = new Position( root, [ 2, 2, 4 ] );
  324. range = new Range( start, end );
  325. op = new AttributeOperation( range, oldAttr, newAttr, baseVersion );
  326. expected.range = new Range( start, end );
  327. } );
  328. describe( 'by InsertOperation', () => {
  329. it( 'target at different position: no operation update', () => {
  330. let transformBy = new InsertOperation(
  331. new Position( root, [ 3, 3, 2 ] ),
  332. [ nodeA, nodeB ],
  333. baseVersion
  334. );
  335. let transOp = transform( op, transformBy );
  336. expect( transOp.length ).to.equal( 1 );
  337. expectOperation( transOp[ 0 ], expected );
  338. } );
  339. it( 'target at offset before: increment offset', () => {
  340. let transformBy = new InsertOperation(
  341. new Position( root, [ 1, 1 ] ),
  342. [ nodeA, nodeB ],
  343. baseVersion
  344. );
  345. let transOp = transform( op, transformBy );
  346. expected.range.start.offset += 2;
  347. expect( transOp.length ).to.equal( 1 );
  348. expectOperation( transOp[ 0 ], expected );
  349. } );
  350. it( 'target at same offset: increment offset', () => {
  351. let transformBy = new InsertOperation(
  352. new Position( root, [ 1, 2 ] ),
  353. [ nodeA, nodeB ],
  354. baseVersion
  355. );
  356. let transOp = transform( op, transformBy );
  357. expected.range.start.offset += 2;
  358. expect( transOp.length ).to.equal( 1 );
  359. expectOperation( transOp[ 0 ], expected );
  360. } );
  361. it( 'target at offset after: no operation update', () => {
  362. let transformBy = new InsertOperation(
  363. new Position( root, [ 3, 2 ] ),
  364. [ nodeA, nodeB ],
  365. baseVersion
  366. );
  367. let transOp = transform( op, transformBy );
  368. expect( transOp.length ).to.equal( 1 );
  369. expectOperation( transOp[ 0 ], expected );
  370. } );
  371. it( 'target before node from path: increment index on path', () => {
  372. let transformBy = new InsertOperation(
  373. new Position( root, [ 0 ] ),
  374. [ nodeA, nodeB ],
  375. baseVersion
  376. );
  377. let transOp = transform( op, transformBy );
  378. expected.range.start.path[ 0 ] += 2;
  379. expected.range.end.path[ 0 ] += 2;
  380. expect( transOp.length ).to.equal( 1 );
  381. expectOperation( transOp[ 0 ], expected );
  382. } );
  383. it( 'target after node from path: no position change', () => {
  384. let transformBy = new InsertOperation(
  385. new Position( root, [ 2, 6 ] ),
  386. [ nodeA, nodeB ],
  387. baseVersion
  388. );
  389. let transOp = transform( op, transformBy );
  390. expect( transOp.length ).to.equal( 1 );
  391. expectOperation( transOp[ 0 ], expected );
  392. } );
  393. it( 'target inside change range: split into two operations', () => {
  394. let transformBy = new InsertOperation(
  395. new Position( root, [ 1, 3, 1 ] ),
  396. [ nodeA, nodeB ],
  397. baseVersion
  398. );
  399. let transOp = transform( op, transformBy );
  400. expect( transOp.length ).to.equal( 2 );
  401. expected.range.start.path = [ 1, 3, 3 ];
  402. expectOperation( transOp[ 0 ], expected );
  403. expected.range.start = op.range.start;
  404. expected.range.end.path = [ 1, 3, 1 ];
  405. expected.baseVersion++;
  406. expectOperation( transOp[ 1 ], expected );
  407. } );
  408. } );
  409. describe( 'by AttributeOperation', () => {
  410. it( 'attributes have different key: no operation update', () => {
  411. let transformBy = new AttributeOperation(
  412. Range.createFromRange( range ),
  413. new Attribute( 'abc', true ),
  414. new Attribute( 'abc', false ),
  415. baseVersion
  416. );
  417. let transOp = transform( op, transformBy );
  418. expect( transOp.length ).to.equal( 1 );
  419. expectOperation( transOp[ 0 ], expected );
  420. } );
  421. it( 'attributes set same value: no operation update', () => {
  422. let transformBy = new AttributeOperation(
  423. Range.createFromRange( range ),
  424. oldAttr,
  425. newAttr,
  426. baseVersion
  427. );
  428. let transOp = transform( op, transformBy );
  429. expect( transOp.length ).to.equal( 1 );
  430. expectOperation( transOp[ 0 ], expected );
  431. } );
  432. it( 'both operations removes attribute: no operation update', () => {
  433. op.newAttr = null;
  434. let transformBy = new AttributeOperation(
  435. new Range( new Position( root, [ 1, 1, 4 ] ), new Position( root, [ 3 ] ) ),
  436. anotherOldAttr,
  437. null,
  438. baseVersion
  439. );
  440. let transOp = transform( op, transformBy, true );
  441. expected.newAttr = null;
  442. expect( transOp.length ).to.equal( 1 );
  443. expectOperation( transOp[ 0 ], expected );
  444. } );
  445. describe( 'that is less important and', () => {
  446. it( 'range does not intersect original range: no operation update', () => {
  447. let transformBy = new AttributeOperation(
  448. new Range( new Position( root, [ 3, 0 ] ), new Position( root, [ 4 ] ) ),
  449. anotherOldAttr,
  450. null,
  451. baseVersion
  452. );
  453. let transOp = transform( op, transformBy, true );
  454. expect( transOp.length ).to.equal( 1 );
  455. expectOperation( transOp[ 0 ], expected );
  456. } );
  457. it( 'range contains original range: update oldAttr', () => {
  458. let transformBy = new AttributeOperation(
  459. new Range( new Position( root, [ 1, 1, 4 ] ), new Position( root, [ 3 ] ) ),
  460. anotherOldAttr,
  461. null,
  462. baseVersion
  463. );
  464. let transOp = transform( op, transformBy, true );
  465. expected.oldAttr = anotherOldAttr;
  466. expect( transOp.length ).to.equal( 1 );
  467. expectOperation( transOp[ 0 ], expected );
  468. } );
  469. // [ original range < ] range transformed by >
  470. it( 'range intersects on left: split into two operations, update oldAttr', () => {
  471. // Get more test cases and better code coverage
  472. op.newAttr = null;
  473. let transformBy = new AttributeOperation(
  474. new Range( new Position( root, [ 1, 4, 2 ] ), new Position( root, [ 3 ] ) ),
  475. anotherOldAttr,
  476. // Get more test cases and better code coverage
  477. anotherNewAttr,
  478. baseVersion
  479. );
  480. let transOp = transform( op, transformBy, true );
  481. expect( transOp.length ).to.equal( 2 );
  482. expected.newAttr = null;
  483. expected.range.end.path = [ 1, 4, 2 ];
  484. expectOperation( transOp[ 0 ], expected );
  485. expected.range.start.path = [ 1, 4, 2 ];
  486. expected.range.end = op.range.end;
  487. expected.oldAttr = anotherOldAttr;
  488. expected.baseVersion++;
  489. expectOperation( transOp[ 1 ], expected );
  490. } );
  491. // [ range transformed by < ] original range >
  492. it( 'range intersects on right: split into two operations, update oldAttr', () => {
  493. let transformBy = new AttributeOperation(
  494. new Range( new Position( root, [ 1 ] ), new Position( root, [ 2, 1 ] ) ),
  495. anotherOldAttr,
  496. null,
  497. baseVersion
  498. );
  499. let transOp = transform( op, transformBy, true );
  500. expect( transOp.length ).to.equal( 2 );
  501. expected.range.start.path = [ 2, 1 ];
  502. expectOperation( transOp[ 0 ], expected );
  503. expected.range.start = op.range.start;
  504. expected.range.end.path = [ 2, 1 ];
  505. expected.oldAttr = anotherOldAttr;
  506. expected.baseVersion++;
  507. expectOperation( transOp[ 1 ], expected );
  508. } );
  509. it( 'range is inside original range: split into three operations, update oldAttr', () => {
  510. let transformBy = new AttributeOperation(
  511. new Range( new Position( root, [ 1, 4, 1 ] ), new Position( root, [ 2, 1 ] ) ),
  512. anotherOldAttr,
  513. null,
  514. baseVersion
  515. );
  516. let transOp = transform( op, transformBy, true );
  517. expect( transOp.length ).to.equal( 3 );
  518. expected.range.end.path = [ 1, 4, 1 ];
  519. expectOperation( transOp[ 0 ], expected );
  520. expected.range.start.path = [ 2, 1 ];
  521. expected.range.end = op.range.end;
  522. expected.baseVersion++;
  523. expectOperation( transOp[ 1 ], expected );
  524. expected.range.start.path = [ 1, 4, 1 ];
  525. expected.range.end.path = [ 2, 1 ];
  526. expected.oldAttr = anotherOldAttr;
  527. expected.baseVersion++;
  528. expectOperation( transOp[ 2 ], expected );
  529. } );
  530. } );
  531. describe( 'that is more important and', () => {
  532. it( 'range does not intersect original range: no operation update', () => {
  533. let transformBy = new AttributeOperation(
  534. new Range( new Position( root, [ 3, 0 ] ), new Position( root, [ 4 ] ) ),
  535. oldAttr,
  536. null,
  537. baseVersion
  538. );
  539. let transOp = transform( op, transformBy );
  540. expect( transOp.length ).to.equal( 1 );
  541. expectOperation( transOp[ 0 ], expected );
  542. } );
  543. it( 'range contains original range: convert to NoOperation', () => {
  544. let transformBy = new AttributeOperation(
  545. new Range( new Position( root, [ 1, 1, 4 ] ), new Position( root, [ 3 ] ) ),
  546. oldAttr,
  547. null,
  548. baseVersion
  549. );
  550. let transOp = transform( op, transformBy );
  551. expect( transOp.length ).to.equal( 1 );
  552. expectOperation( transOp[ 0 ], {
  553. type: NoOperation,
  554. baseVersion: baseVersion + 1
  555. } );
  556. } );
  557. // [ original range < ] range transformed by >
  558. it( 'range intersects on left: shrink original range', () => {
  559. let transformBy = new AttributeOperation(
  560. new Range( new Position( root, [ 1, 4, 2 ] ), new Position( root, [ 3 ] ) ),
  561. oldAttr,
  562. null,
  563. baseVersion
  564. );
  565. let transOp = transform( op, transformBy );
  566. expected.range.end.path = [ 1, 4, 2 ];
  567. expect( transOp.length ).to.equal( 1 );
  568. expectOperation( transOp[ 0 ], expected );
  569. } );
  570. // [ range transformed by < ] original range >
  571. it( 'range intersects on right: shrink original range', () => {
  572. let transformBy = new AttributeOperation(
  573. new Range( new Position( root, [ 1 ] ), new Position( root, [ 2, 1 ] ) ),
  574. oldAttr,
  575. null,
  576. baseVersion
  577. );
  578. let transOp = transform( op, transformBy );
  579. expected.range.start.path = [ 2, 1 ];
  580. expect( transOp.length ).to.equal( 1 );
  581. expectOperation( transOp[ 0 ], expected );
  582. } );
  583. it( 'range is inside original range: split into two operations', () => {
  584. let transformBy = new AttributeOperation(
  585. new Range( new Position( root, [ 1, 4, 1 ] ), new Position( root, [ 2, 1 ] ) ),
  586. oldAttr,
  587. null,
  588. baseVersion
  589. );
  590. let transOp = transform( op, transformBy );
  591. expect( transOp.length ).to.equal( 2 );
  592. expected.range.end.path = [ 1, 4, 1 ];
  593. expectOperation( transOp[ 0 ], expected );
  594. expected.range.start.path = [ 2, 1 ];
  595. expected.range.end = op.range.end;
  596. expected.baseVersion++;
  597. expectOperation( transOp[ 1 ], expected );
  598. } );
  599. } );
  600. } );
  601. describe( 'by MoveOperation', () => {
  602. it( 'range and target are different than change range: no operation update', () => {
  603. let transformBy = new MoveOperation(
  604. new Position( root, [ 1, 1, 2 ] ),
  605. 2,
  606. new Position( root, [ 3, 4 ] ),
  607. baseVersion
  608. );
  609. let transOp = transform( op, transformBy );
  610. expect( transOp.length ).to.equal( 1 );
  611. expectOperation( transOp[ 0 ], expected );
  612. } );
  613. it( 'range offset is before change range start offset: decrement offset', () => {
  614. let transformBy = new MoveOperation(
  615. new Position( root, [ 1, 0 ] ),
  616. 2,
  617. new Position( root, [ 3, 4, 1 ] ),
  618. baseVersion
  619. );
  620. let transOp = transform( op, transformBy );
  621. expected.range.start.offset -= 2;
  622. expect( transOp.length ).to.equal( 1 );
  623. expectOperation( transOp[ 0 ], expected );
  624. } );
  625. it( 'target offset is before change range start offset: increment offset', () => {
  626. let transformBy = new MoveOperation(
  627. new Position( root, [ 3, 4, 1 ] ),
  628. 2,
  629. new Position( root, [ 1, 0 ] ),
  630. baseVersion
  631. );
  632. let transOp = transform( op, transformBy );
  633. expected.range.start.offset += 2;
  634. expect( transOp.length ).to.equal( 1 );
  635. expectOperation( transOp[ 0 ], expected );
  636. } );
  637. it( 'range is before node from path to change range: decrement index on path', () => {
  638. let transformBy = new MoveOperation(
  639. new Position( root, [ 0 ] ),
  640. 1,
  641. new Position( root, [ 2, 4, 1 ] ),
  642. baseVersion
  643. );
  644. let transOp = transform( op, transformBy );
  645. expected.range.start.path[ 0 ]--;
  646. expected.range.end.path[ 0 ]--;
  647. expect( transOp.length ).to.equal( 1 );
  648. expectOperation( transOp[ 0 ], expected );
  649. } );
  650. it( 'range is after node from path to change range: no position change', () => {
  651. let transformBy = new MoveOperation(
  652. new Position( root, [ 3 ] ),
  653. 2,
  654. new Position( root, [ 0, 1 ] ),
  655. baseVersion
  656. );
  657. let transOp = transform( op, transformBy );
  658. expect( transOp.length ).to.equal( 1 );
  659. expectOperation( transOp[ 0 ], expected );
  660. } );
  661. it( 'target before node from path to change range: increment index on path', () => {
  662. let transformBy = new MoveOperation(
  663. new Position( root, [ 3, 4, 1 ] ),
  664. 2,
  665. new Position( root, [ 1, 0 ] ),
  666. baseVersion
  667. );
  668. let transOp = transform( op, transformBy );
  669. expected.range.start.path[ 1 ] += 2;
  670. expect( transOp.length ).to.equal( 1 );
  671. expectOperation( transOp[ 0 ], expected );
  672. } );
  673. it( 'target after node from path to change range: no position change', () => {
  674. let transformBy = new MoveOperation(
  675. new Position( root, [ 3, 4, 1 ] ),
  676. 2,
  677. new Position( root, [ 3 ] ),
  678. baseVersion
  679. );
  680. let transOp = transform( op, transformBy );
  681. expect( transOp.length ).to.equal( 1 );
  682. expectOperation( transOp[ 0 ], expected );
  683. } );
  684. it( 'range intersects on left with change range: split into two operations', () => {
  685. let transformBy = new MoveOperation(
  686. new Position( root, [ 2, 1 ] ),
  687. 3,
  688. new Position( root, [ 4 ] ),
  689. baseVersion
  690. );
  691. let transOp = transform( op, transformBy );
  692. expect( transOp.length ).to.equal( 2 );
  693. expected.range.end.path = [ 2, 1 ];
  694. expectOperation( transOp[ 0 ], expected );
  695. expected.range.start.path = [ 4 ];
  696. expected.range.end.path = [ 5, 4 ];
  697. expected.baseVersion++;
  698. expectOperation( transOp[ 1 ], expected );
  699. } );
  700. it( 'range intersects on right with change range: split into two operation', () => {
  701. let transformBy = new MoveOperation(
  702. new Position( root, [ 1, 1 ] ),
  703. 3,
  704. new Position( root, [ 0, 0 ] ),
  705. baseVersion
  706. );
  707. let transOp = transform( op, transformBy );
  708. expect( transOp.length ).to.equal( 2 );
  709. expected.range.start.path = [ 1, 1 ];
  710. expectOperation( transOp[ 0 ], expected );
  711. expected.range.start.path = [ 0, 1 ];
  712. expected.range.end.path = [ 0, 3 ];
  713. expected.baseVersion++;
  714. expectOperation( transOp[ 1 ], expected );
  715. } );
  716. it( 'range contains change range: update change range', () => {
  717. let transformBy = new MoveOperation(
  718. new Position( root, [ 1 ] ),
  719. 2,
  720. new Position( root, [ 3, 4, 1 ] ),
  721. baseVersion
  722. );
  723. let transOp = transform( op, transformBy );
  724. expected.range.start.path = [ 1, 4, 1, 2 ];
  725. expected.range.end.path = [ 1, 4, 2, 2, 4 ];
  726. expect( transOp.length ).to.equal( 1 );
  727. expectOperation( transOp[ 0 ], expected );
  728. } );
  729. it( 'range is inside change range: split into two operations', () => {
  730. let transformBy = new MoveOperation(
  731. new Position( root, [ 1, 4 ] ),
  732. 2,
  733. new Position( root, [ 3, 2 ] ),
  734. baseVersion
  735. );
  736. let transOp = transform( op, transformBy );
  737. expect( transOp.length ).to.equal( 2 );
  738. expectOperation( transOp[ 0 ], expected );
  739. expected.range.start.path = [ 3, 2 ];
  740. expected.range.end.path = [ 3, 4 ];
  741. expected.baseVersion++;
  742. expectOperation( transOp[ 1 ], expected );
  743. } );
  744. it( 'target inside change range: split into two operations', () => {
  745. let transformBy = new MoveOperation(
  746. new Position( root, [ 3, 4, 1 ] ),
  747. 2,
  748. new Position( root, [ 1, 4 ] ),
  749. baseVersion
  750. );
  751. let transOp = transform( op, transformBy );
  752. expect( transOp.length ).to.equal( 2 );
  753. expected.range.start.path = [ 1, 6 ];
  754. expectOperation( transOp[ 0 ], expected );
  755. expected.range.start = op.range.start;
  756. expected.range.end.path = [ 1, 4 ];
  757. expected.baseVersion++;
  758. expectOperation( transOp[ 1 ], expected );
  759. } );
  760. it( 'range intersects change range and target inside change range: split into three operations', () => {
  761. let transformBy = new MoveOperation(
  762. new Position( root, [ 1, 1 ] ),
  763. 3,
  764. new Position( root, [ 2 ] ),
  765. baseVersion
  766. );
  767. let transOp = transform( op, transformBy );
  768. expect( transOp.length ).to.equal( 3 );
  769. expected.range.start.path = [ 5 ];
  770. expected.range.end.path = [ 5, 2, 4 ];
  771. expectOperation( transOp[ 0 ], expected );
  772. expected.range.start.path = [ 1, 1 ];
  773. expected.range.end.path = [ 2 ];
  774. expected.baseVersion++;
  775. expectOperation( transOp[ 1 ], expected );
  776. expected.range.start.path = [ 3 ];
  777. expected.range.end.path = [ 5 ];
  778. expected.baseVersion++;
  779. expectOperation( transOp[ 2 ], expected );
  780. } );
  781. } );
  782. describe( 'by NoOperation', () => {
  783. it( 'no operation update', () => {
  784. let transformBy = new NoOperation( baseVersion );
  785. let transOp = transform( op, transformBy );
  786. expect( transOp.length ).to.equal( 1 );
  787. expectOperation( transOp[ 0 ], expected );
  788. } );
  789. } );
  790. } );
  791. // Some extra cases for a AttributeOperation that operates on single tree level range.
  792. // This means that the change range start and end differs only on offset value.
  793. // This test suite also have some modifications to the original operation
  794. // to get more test cases covered and better code coverage.
  795. describe( 'with single-level range', () => {
  796. beforeEach( () => {
  797. start = new Position( root, [ 0, 2, 1 ] );
  798. end = new Position( root, [ 0, 2, 4 ] );
  799. range = new Range( start, end );
  800. op = new AttributeOperation( range, oldAttr, newAttr, baseVersion );
  801. expected.range = new Range( start, end );
  802. } );
  803. describe( 'by InsertOperation', () => {
  804. it( 'target at offset before: increment offset', () => {
  805. let transformBy = new InsertOperation(
  806. new Position( root, [ 0, 2, 0 ] ),
  807. [ nodeA, nodeB ],
  808. baseVersion
  809. );
  810. let transOp = transform( op, transformBy );
  811. expected.range.start.offset += 2;
  812. expected.range.end.offset += 2;
  813. expect( transOp.length ).to.equal( 1 );
  814. expectOperation( transOp[ 0 ], expected );
  815. } );
  816. it( 'target at same offset: increment offset', () => {
  817. let transformBy = new InsertOperation(
  818. new Position( root, [ 0, 2, 1 ] ),
  819. [ nodeA, nodeB ],
  820. baseVersion
  821. );
  822. let transOp = transform( op, transformBy );
  823. expected.range.start.offset += 2;
  824. expected.range.end.offset += 2;
  825. expect( transOp.length ).to.equal( 1 );
  826. expectOperation( transOp[ 0 ], expected );
  827. } );
  828. } );
  829. describe( 'by MoveOperation', () => {
  830. it( 'range offset is before change range start offset: decrement offset', () => {
  831. let transformBy = new MoveOperation(
  832. new Position( root, [ 0, 2, 0 ] ),
  833. 1,
  834. new Position( root, [ 2, 4, 1 ] ),
  835. baseVersion
  836. );
  837. let transOp = transform( op, transformBy );
  838. expected.range.start.offset--;
  839. expected.range.end.offset--;
  840. expect( transOp.length ).to.equal( 1 );
  841. expectOperation( transOp[ 0 ], expected );
  842. } );
  843. it( 'target offset is before change range start offset: increment offset', () => {
  844. let transformBy = new MoveOperation(
  845. new Position( root, [ 2, 4, 1 ] ),
  846. 2,
  847. new Position( root, [ 0, 2, 0 ] ),
  848. baseVersion
  849. );
  850. let transOp = transform( op, transformBy );
  851. expected.range.start.offset += 2;
  852. expected.range.end.offset += 2;
  853. expect( transOp.length ).to.equal( 1 );
  854. expectOperation( transOp[ 0 ], expected );
  855. } );
  856. it( 'range intersects on left with change range: split into two operations', () => {
  857. let transformBy = new MoveOperation(
  858. new Position( root, [ 0, 2, 2 ] ),
  859. 4,
  860. new Position( root, [ 2, 4, 1 ] ),
  861. baseVersion
  862. );
  863. let transOp = transform( op, transformBy );
  864. expect( transOp.length ).to.equal( 2 );
  865. expected.range.end.offset -= 2;
  866. expectOperation( transOp[ 0 ], expected );
  867. expected.range.start.path = [ 2, 4, 1 ];
  868. expected.range.end.path = [ 2, 4, 3 ];
  869. expected.baseVersion++;
  870. expectOperation( transOp[ 1 ], expected );
  871. } );
  872. it( 'range intersects on right with change range: split into two operation', () => {
  873. let transformBy = new MoveOperation(
  874. new Position( root, [ 0, 2, 0 ] ),
  875. 2,
  876. new Position( root, [ 2, 4, 1 ] ),
  877. baseVersion
  878. );
  879. let transOp = transform( op, transformBy );
  880. expect( transOp.length ).to.equal( 2 );
  881. expected.range.start.offset -= 1;
  882. expected.range.end.offset -= 2;
  883. expectOperation( transOp[ 0 ], expected );
  884. expected.range.start.path = [ 2, 4, 2 ];
  885. expected.range.end.path = [ 2, 4, 3 ];
  886. expected.baseVersion++;
  887. expectOperation( transOp[ 1 ], expected );
  888. } );
  889. it( 'range contains change range: update change range', () => {
  890. let transformBy = new MoveOperation(
  891. new Position( root, [ 0, 1 ] ),
  892. 3,
  893. new Position( root, [ 2, 4, 1 ] ),
  894. baseVersion
  895. );
  896. let transOp = transform( op, transformBy );
  897. expected.range.start.path = [ 2, 4, 2, 1 ];
  898. expected.range.end.path = [ 2, 4, 2, 4 ];
  899. expect( transOp.length ).to.equal( 1 );
  900. expectOperation( transOp[ 0 ], expected );
  901. } );
  902. it( 'range is inside change range: split into two operations', () => {
  903. let transformBy = new MoveOperation(
  904. new Position( root, [ 0, 2, 2 ] ),
  905. 1,
  906. new Position( root, [ 2, 4, 1 ] ),
  907. baseVersion
  908. );
  909. let transOp = transform( op, transformBy );
  910. expect( transOp.length ).to.equal( 2 );
  911. expected.range.end.offset--;
  912. expectOperation( transOp[ 0 ], expected );
  913. expected.range.start.path = [ 2, 4, 1 ];
  914. expected.range.end.path = [ 2, 4, 2 ];
  915. expected.baseVersion++;
  916. expectOperation( transOp[ 1 ], expected );
  917. } );
  918. it( 'range is same as change range: update change range', () => {
  919. let transformBy = new MoveOperation(
  920. new Position( root, [ 0, 2, 1 ] ),
  921. 3,
  922. new Position( root, [ 2, 4, 1 ] ),
  923. baseVersion
  924. );
  925. let transOp = transform( op, transformBy );
  926. expected.range.start.path = [ 2, 4, 1 ];
  927. expected.range.end.path = [ 2, 4, 4 ];
  928. expect( transOp.length ).to.equal( 1 );
  929. expectOperation( transOp[ 0 ], expected );
  930. } );
  931. it( 'target inside change range: split into two operations', () => {
  932. let transformBy = new MoveOperation(
  933. new Position( root, [ 2, 4, 1 ] ),
  934. 2,
  935. new Position( root, [ 0, 2, 2 ] ),
  936. baseVersion
  937. );
  938. let transOp = transform( op, transformBy );
  939. expect( transOp.length ).to.equal( 2 );
  940. expected.range.start.offset = 4;
  941. expected.range.end.offset = 6;
  942. expectOperation( transOp[ 0 ], expected );
  943. expected.range.start.offset = op.range.start.offset;
  944. expected.range.end.offset = 2;
  945. expected.baseVersion++;
  946. expectOperation( transOp[ 1 ], expected );
  947. } );
  948. it( 'range intersects change range and target inside change range: split into three operations', () => {
  949. let transformBy = new MoveOperation(
  950. new Position( root, [ 0, 2, 0 ] ),
  951. 2,
  952. new Position( root, [ 0, 2, 3 ] ),
  953. baseVersion
  954. );
  955. let transOp = transform( op, transformBy );
  956. expect( transOp.length ).to.equal( 3 );
  957. expected.range.start.offset = 3;
  958. expected.range.end.offset = 4;
  959. expectOperation( transOp[ 0 ], expected );
  960. expected.range.start.offset = 0;
  961. expected.range.end.offset = 1;
  962. expected.baseVersion++;
  963. expectOperation( transOp[ 1 ], expected );
  964. expected.range.start.offset = 2;
  965. expected.range.end.offset = 3;
  966. expected.baseVersion++;
  967. expectOperation( transOp[ 2 ], expected );
  968. } );
  969. } );
  970. } );
  971. } );
  972. describe( 'MoveOperation', () => {
  973. let sourcePosition, targetPosition, rangeEnd, howMany;
  974. beforeEach( () => {
  975. sourcePosition = new Position( root, [ 2, 2, 4 ] );
  976. targetPosition = new Position( root, [ 3, 3, 3 ] );
  977. howMany = 2;
  978. rangeEnd = Position.createFromPosition( sourcePosition );
  979. rangeEnd.offset += howMany;
  980. op = new MoveOperation( sourcePosition, howMany, targetPosition, baseVersion );
  981. expected = {
  982. type: MoveOperation,
  983. sourcePosition: Position.createFromPosition( sourcePosition ),
  984. targetPosition: Position.createFromPosition( targetPosition ),
  985. howMany: howMany,
  986. baseVersion: baseVersion + 1
  987. };
  988. } );
  989. describe( 'by InsertOperation', () => {
  990. it( 'target at different position than move range and target: no operation update', () => {
  991. let transformBy = new InsertOperation(
  992. new Position( root, [ 1, 3, 2 ] ),
  993. [ nodeA, nodeB ],
  994. baseVersion
  995. );
  996. let transOp = transform( op, transformBy );
  997. expect( transOp.length ).to.equal( 1 );
  998. expectOperation( transOp[ 0 ], expected );
  999. } );
  1000. it( 'target inside node from move range: no operation update', () => {
  1001. let transformBy = new InsertOperation(
  1002. new Position( root, [ 2, 2, 3, 1 ] ),
  1003. [ nodeA, nodeB ],
  1004. baseVersion
  1005. );
  1006. let transOp = transform( op, transformBy );
  1007. expect( transOp.length ).to.equal( 1 );
  1008. expectOperation( transOp[ 0 ], expected );
  1009. } );
  1010. it( 'target at offset before range offset: increment range offset', () => {
  1011. let transformBy = new InsertOperation(
  1012. new Position( root, [ 2, 2, 0 ] ),
  1013. [ nodeA, nodeB ],
  1014. baseVersion
  1015. );
  1016. let transOp = transform( op, transformBy );
  1017. expected.sourcePosition.offset += 2;
  1018. expect( transOp.length ).to.equal( 1 );
  1019. expectOperation( transOp[ 0 ], expected );
  1020. } );
  1021. it( 'target at offset after range offset: no operation update', () => {
  1022. let transformBy = new InsertOperation(
  1023. new Position( root, [ 2, 2, 6 ] ),
  1024. [ nodeA, nodeB ],
  1025. baseVersion
  1026. );
  1027. let transOp = transform( op, transformBy );
  1028. expect( transOp.length ).to.equal( 1 );
  1029. expectOperation( transOp[ 0 ], expected );
  1030. } );
  1031. it( 'target before node from range start path: increment index on range start path', () => {
  1032. let transformBy = new InsertOperation(
  1033. new Position( root, [ 2, 0 ] ),
  1034. [ nodeA, nodeB ],
  1035. baseVersion
  1036. );
  1037. let transOp = transform( op, transformBy );
  1038. expected.sourcePosition.path[ 1 ] += 2;
  1039. expect( transOp.length ).to.equal( 1 );
  1040. expectOperation( transOp[ 0 ], expected );
  1041. } );
  1042. it( 'target after node from range start path: no operation update', () => {
  1043. let transformBy = new InsertOperation(
  1044. new Position( root, [ 2, 3 ] ),
  1045. [ nodeA, nodeB ],
  1046. baseVersion
  1047. );
  1048. let transOp = transform( op, transformBy );
  1049. expect( transOp.length ).to.equal( 1 );
  1050. expectOperation( transOp[ 0 ], expected );
  1051. } );
  1052. it( 'target offset before move target offset: increment target offset', () => {
  1053. let transformBy = new InsertOperation(
  1054. new Position( root, [ 3, 3, 2 ] ),
  1055. [ nodeA, nodeB ],
  1056. baseVersion
  1057. );
  1058. let transOp = transform( op, transformBy );
  1059. expected.targetPosition.offset += 2;
  1060. expect( transOp.length ).to.equal( 1 );
  1061. expectOperation( transOp[ 0 ], expected );
  1062. } );
  1063. it( 'target offset after move target offset: no operation update', () => {
  1064. let transformBy = new InsertOperation(
  1065. new Position( root, [ 3, 3, 4 ] ),
  1066. [ nodeA, nodeB ],
  1067. baseVersion
  1068. );
  1069. let transOp = transform( op, transformBy );
  1070. expect( transOp.length ).to.equal( 1 );
  1071. expectOperation( transOp[ 0 ], expected );
  1072. } );
  1073. it( 'target before node from move target position path: increment index on move target position path', () => {
  1074. let transformBy = new InsertOperation(
  1075. new Position( root, [ 3, 0 ] ),
  1076. [ nodeA, nodeB ],
  1077. baseVersion
  1078. );
  1079. let transOp = transform( op, transformBy );
  1080. expected.targetPosition.path[ 1 ] += 2;
  1081. expect( transOp.length ).to.equal( 1 );
  1082. expectOperation( transOp[ 0 ], expected );
  1083. } );
  1084. it( 'target after node from move target position path: no operation update', () => {
  1085. let transformBy = new InsertOperation(
  1086. new Position( root, [ 3, 6 ] ),
  1087. [ nodeA, nodeB ],
  1088. baseVersion
  1089. );
  1090. let transOp = transform( op, transformBy );
  1091. expect( transOp.length ).to.equal( 1 );
  1092. expectOperation( transOp[ 0 ], expected );
  1093. } );
  1094. it( 'target offset same as move target offset and is important: increment target offset', () => {
  1095. let transformBy = new InsertOperation(
  1096. new Position( root, [ 3, 3, 3 ] ),
  1097. [ nodeA, nodeB ],
  1098. baseVersion
  1099. );
  1100. let transOp = transform( op, transformBy );
  1101. expected.targetPosition.offset += 2;
  1102. expect( transOp.length ).to.equal( 1 );
  1103. expectOperation( transOp[ 0 ], expected );
  1104. } );
  1105. it( 'target offset same as move target offset and is less important: no operation update', () => {
  1106. let transformBy = new InsertOperation(
  1107. new Position( root, [ 3, 3, 3 ] ),
  1108. [ nodeA, nodeB ],
  1109. baseVersion
  1110. );
  1111. let transOp = transform( op, transformBy, true );
  1112. expect( transOp.length ).to.equal( 1 );
  1113. expectOperation( transOp[ 0 ], expected );
  1114. } );
  1115. it( 'target offset same as move target offset and is important: increment target offset', () => {
  1116. let transformBy = new InsertOperation(
  1117. new Position( root, [ 3, 3 ] ),
  1118. [ nodeA, nodeB ],
  1119. baseVersion
  1120. );
  1121. let transOp = transform( op, transformBy );
  1122. expected.targetPosition.path[ 1 ] += 2;
  1123. expect( transOp.length ).to.equal( 1 );
  1124. expectOperation( transOp[ 0 ], expected );
  1125. } );
  1126. it( 'target inside move range: split into two operations', () => {
  1127. let transformBy = new InsertOperation(
  1128. new Position( root, [ 2, 2, 5 ] ),
  1129. [ nodeA, nodeB ],
  1130. baseVersion
  1131. );
  1132. let transOp = transform( op, transformBy );
  1133. expect( transOp.length ).to.equal( 2 );
  1134. expected.sourcePosition.path = [ 2, 2, 7 ];
  1135. expected.howMany = 1;
  1136. expectOperation( transOp[ 0 ], expected );
  1137. expected.sourcePosition.path = [ 2, 2, 4 ];
  1138. expected.howMany = 1;
  1139. expected.baseVersion++;
  1140. expectOperation( transOp[ 1 ], expected );
  1141. } );
  1142. } );
  1143. describe( 'by AttributeOperation', () => {
  1144. it( 'no operation update', () => {
  1145. let transformBy = new AttributeOperation(
  1146. new Range( sourcePosition, rangeEnd ),
  1147. new Attribute( 'abc', true ),
  1148. new Attribute( 'abc', false ),
  1149. baseVersion
  1150. );
  1151. let transOp = transform( op, transformBy );
  1152. expect( transOp.length ).to.equal( 1 );
  1153. expectOperation( transOp[ 0 ], expected );
  1154. } );
  1155. } );
  1156. describe( 'by MoveOperation', () => {
  1157. it( 'range and target different than transforming range and target: no operation update', () => {
  1158. let transformBy = new MoveOperation(
  1159. new Position( root, [ 1, 2 ] ),
  1160. 3,
  1161. new Position( root, [ 4, 1, 0 ] ),
  1162. baseVersion
  1163. );
  1164. let transOp = transform( op, transformBy );
  1165. expect( transOp.length ).to.equal( 1 );
  1166. expectOperation( transOp[ 0 ], expected );
  1167. } );
  1168. it( 'target offset before transforming range start offset: increment range offset', () => {
  1169. let transformBy = new MoveOperation(
  1170. new Position( root, [ 4, 1, 0 ] ),
  1171. 2,
  1172. new Position( root, [ 2, 2, 0 ] ),
  1173. baseVersion
  1174. );
  1175. let transOp = transform( op, transformBy );
  1176. expected.sourcePosition.offset += 2;
  1177. expect( transOp.length ).to.equal( 1 );
  1178. expectOperation( transOp[ 0 ], expected );
  1179. } );
  1180. it( 'target offset after transforming range start offset: no operation update', () => {
  1181. let transformBy = new MoveOperation(
  1182. new Position( root, [ 4, 1, 0 ] ),
  1183. 2,
  1184. new Position( root, [ 2, 2, 7 ] ),
  1185. baseVersion
  1186. );
  1187. let transOp = transform( op, transformBy );
  1188. expect( transOp.length ).to.equal( 1 );
  1189. expectOperation( transOp[ 0 ], expected );
  1190. } );
  1191. it( 'range start offset before transforming range start offset: decrement range offset', () => {
  1192. let transformBy = new MoveOperation(
  1193. new Position( root, [ 2, 2, 0 ] ),
  1194. 2,
  1195. new Position( root, [ 4, 1, 0 ] ),
  1196. baseVersion
  1197. );
  1198. let transOp = transform( op, transformBy );
  1199. expected.sourcePosition.offset -= 2;
  1200. expect( transOp.length ).to.equal( 1 );
  1201. expectOperation( transOp[ 0 ], expected );
  1202. } );
  1203. it( 'range start offset after transforming range start offset: no operation update', () => {
  1204. let transformBy = new MoveOperation(
  1205. new Position( root, [ 2, 2, 9 ] ),
  1206. 2,
  1207. new Position( root, [ 4, 1, 0 ] ),
  1208. baseVersion
  1209. );
  1210. let transOp = transform( op, transformBy, true );
  1211. expect( transOp.length ).to.equal( 1 );
  1212. expectOperation( transOp[ 0 ], expected );
  1213. } );
  1214. it( 'target before node from transforming range start path: increment index on range start path', () => {
  1215. let transformBy = new MoveOperation(
  1216. new Position( root, [ 4, 1, 0 ] ),
  1217. 2,
  1218. new Position( root, [ 2, 1 ] ),
  1219. baseVersion
  1220. );
  1221. let transOp = transform( op, transformBy );
  1222. expected.sourcePosition.path[ 1 ] += 2;
  1223. expect( transOp.length ).to.equal( 1 );
  1224. expectOperation( transOp[ 0 ], expected );
  1225. } );
  1226. it( 'target after node from transforming range start path: no operation update', () => {
  1227. let transformBy = new MoveOperation(
  1228. new Position( root, [ 4, 1, 0 ] ),
  1229. 2,
  1230. new Position( root, [ 2, 5 ] ),
  1231. baseVersion
  1232. );
  1233. let transOp = transform( op, transformBy );
  1234. expect( transOp.length ).to.equal( 1 );
  1235. expectOperation( transOp[ 0 ], expected );
  1236. } );
  1237. it( 'range before node from transforming range start path: decrement index on range start path', () => {
  1238. let transformBy = new MoveOperation(
  1239. new Position( root, [ 2, 0 ] ),
  1240. 2,
  1241. new Position( root, [ 4, 1, 0 ] ),
  1242. baseVersion
  1243. );
  1244. let transOp = transform( op, transformBy );
  1245. expected.sourcePosition.path[ 1 ] -= 2;
  1246. expect( transOp.length ).to.equal( 1 );
  1247. expectOperation( transOp[ 0 ], expected );
  1248. } );
  1249. it( 'range after node from transforming range start path: no operation update', () => {
  1250. let transformBy = new MoveOperation(
  1251. new Position( root, [ 2, 3 ] ),
  1252. 2,
  1253. new Position( root, [ 4, 1, 0 ] ),
  1254. baseVersion
  1255. );
  1256. let transOp = transform( op, transformBy );
  1257. expect( transOp.length ).to.equal( 1 );
  1258. expectOperation( transOp[ 0 ], expected );
  1259. } );
  1260. it( 'target offset before transforming target offset: increment target offset', () => {
  1261. let transformBy = new MoveOperation(
  1262. new Position( root, [ 4, 1, 0 ] ),
  1263. 2,
  1264. new Position( root, [ 3, 3, 0 ] ),
  1265. baseVersion
  1266. );
  1267. let transOp = transform( op, transformBy );
  1268. expected.targetPosition.offset += 2;
  1269. expect( transOp.length ).to.equal( 1 );
  1270. expectOperation( transOp[ 0 ], expected );
  1271. } );
  1272. it( 'target offset after transforming target offset: no operation update', () => {
  1273. let transformBy = new MoveOperation(
  1274. new Position( root, [ 4, 1, 0 ] ),
  1275. 2,
  1276. new Position( root, [ 3, 3, 5 ] ),
  1277. baseVersion
  1278. );
  1279. let transOp = transform( op, transformBy );
  1280. expect( transOp.length ).to.equal( 1 );
  1281. expectOperation( transOp[ 0 ], expected );
  1282. } );
  1283. it( 'range offset before transforming target offset: decrement target offset', () => {
  1284. let transformBy = new MoveOperation(
  1285. new Position( root, [ 3, 3, 0 ] ),
  1286. 2,
  1287. new Position( root, [ 4, 1, 0 ] ),
  1288. baseVersion
  1289. );
  1290. let transOp = transform( op, transformBy );
  1291. expected.targetPosition.offset -= 2;
  1292. expect( transOp.length ).to.equal( 1 );
  1293. expectOperation( transOp[ 0 ], expected );
  1294. } );
  1295. it( 'range offset after transforming target offset: no operation update', () => {
  1296. let transformBy = new MoveOperation(
  1297. new Position( root, [ 3, 3, 5 ] ),
  1298. 2,
  1299. new Position( root, [ 4, 1, 0 ] ),
  1300. baseVersion
  1301. );
  1302. let transOp = transform( op, transformBy );
  1303. expect( transOp.length ).to.equal( 1 );
  1304. expectOperation( transOp[ 0 ], expected );
  1305. } );
  1306. it( 'target before node from transforming target path: increment index on target path', () => {
  1307. let transformBy = new MoveOperation(
  1308. new Position( root, [ 4, 1, 0 ] ),
  1309. 2,
  1310. new Position( root, [ 3, 1 ] ),
  1311. baseVersion
  1312. );
  1313. let transOp = transform( op, transformBy );
  1314. expected.targetPosition.path[ 1 ] += 2;
  1315. expect( transOp.length ).to.equal( 1 );
  1316. expectOperation( transOp[ 0 ], expected );
  1317. } );
  1318. it( 'target after node from transforming target path: no operation update', () => {
  1319. let transformBy = new MoveOperation(
  1320. new Position( root, [ 4, 1, 0 ] ),
  1321. 2,
  1322. new Position( root, [ 3, 5 ] ),
  1323. baseVersion
  1324. );
  1325. let transOp = transform( op, transformBy );
  1326. expect( transOp.length ).to.equal( 1 );
  1327. expectOperation( transOp[ 0 ], expected );
  1328. } );
  1329. it( 'range before node from transforming target path: decrement index on target path', () => {
  1330. let transformBy = new MoveOperation(
  1331. new Position( root, [ 3, 0 ] ),
  1332. 2,
  1333. new Position( root, [ 4, 1, 0 ] ),
  1334. baseVersion
  1335. );
  1336. let transOp = transform( op, transformBy );
  1337. expected.targetPosition.path[ 1 ] -= 2;
  1338. expect( transOp.length ).to.equal( 1 );
  1339. expectOperation( transOp[ 0 ], expected );
  1340. } );
  1341. it( 'range after node from transforming target path: no operation update', () => {
  1342. let transformBy = new MoveOperation(
  1343. new Position( root, [ 3, 5 ] ),
  1344. 2,
  1345. new Position( root, [ 4, 1, 0 ] ),
  1346. baseVersion
  1347. );
  1348. let transOp = transform( op, transformBy );
  1349. expect( transOp.length ).to.equal( 1 );
  1350. expectOperation( transOp[ 0 ], expected );
  1351. } );
  1352. it( 'target inside transforming move range: split into two operations', () => {
  1353. let transformBy = new MoveOperation(
  1354. new Position( root, [ 4, 1, 0 ] ),
  1355. 2,
  1356. new Position( root, [ 2, 2, 5 ] ),
  1357. baseVersion
  1358. );
  1359. let transOp = transform( op, transformBy );
  1360. expect( transOp.length ).to.equal( 2 );
  1361. expected.howMany = 1;
  1362. expected.sourcePosition.offset = 7;
  1363. expectOperation( transOp[ 0 ], expected );
  1364. expected.sourcePosition.offset = 4;
  1365. expected.baseVersion++;
  1366. expectOperation( transOp[ 1 ], expected );
  1367. } );
  1368. it( 'target inside a node from transforming range: no operation update', () => {
  1369. let transformBy = new MoveOperation(
  1370. new Position( root, [ 4, 1, 0 ] ),
  1371. 2,
  1372. new Position( root, [ 2, 2, 5, 1 ] ),
  1373. baseVersion
  1374. );
  1375. let transOp = transform( op, transformBy );
  1376. expect( transOp.length ).to.equal( 1 );
  1377. expectOperation( transOp[ 0 ], expected );
  1378. } );
  1379. it( 'range has node that contains transforming range: update range path', () => {
  1380. let transformBy = new MoveOperation(
  1381. new Position( root, [ 2, 1 ] ),
  1382. 3,
  1383. new Position( root, [ 4, 2 ] ),
  1384. baseVersion
  1385. );
  1386. let transOp = transform( op, transformBy );
  1387. expected.sourcePosition.path = [ 4, 3, 4 ];
  1388. expect( transOp.length ).to.equal( 1 );
  1389. expectOperation( transOp[ 0 ], expected );
  1390. } );
  1391. it( 'range has node that contains transforming target: update target path', () => {
  1392. let transformBy = new MoveOperation(
  1393. new Position( root, [ 3, 2 ] ),
  1394. 3,
  1395. new Position( root, [ 0, 1 ] ),
  1396. baseVersion
  1397. );
  1398. let transOp = transform( op, transformBy );
  1399. expected.targetPosition.path = [ 0, 2, 3 ];
  1400. expect( transOp.length ).to.equal( 1 );
  1401. expectOperation( transOp[ 0 ], expected );
  1402. } );
  1403. it( 'target inside a node from transforming range and vice versa: reverse transform-by operation', () => {
  1404. let transformBy = new MoveOperation(
  1405. new Position( root, [ 3, 2 ] ),
  1406. 3,
  1407. new Position( root, [ 2, 2, 5, 0 ] ),
  1408. baseVersion
  1409. );
  1410. let transOp = transform( op, transformBy );
  1411. let reversed = transformBy.getReversed();
  1412. expected.sourcePosition = reversed.sourcePosition;
  1413. expected.targetPosition = reversed.targetPosition;
  1414. expected.howMany = reversed.howMany;
  1415. expect( transOp.length ).to.equal( 1 );
  1416. expectOperation( transOp[ 0 ], expected );
  1417. } );
  1418. it( 'range is same as transforming range and is important: convert to NoOperation', () => {
  1419. let transformBy = new MoveOperation(
  1420. op.sourcePosition,
  1421. op.howMany,
  1422. new Position( root, [ 4, 1, 0 ] ),
  1423. baseVersion
  1424. );
  1425. let transOp = transform( op, transformBy );
  1426. expect( transOp.length ).to.equal( 1 );
  1427. expectOperation( transOp[ 0 ], {
  1428. type: NoOperation,
  1429. baseVersion: baseVersion + 1
  1430. } );
  1431. } );
  1432. it( 'range is same as transforming range and is less important: update range path', () => {
  1433. let transformBy = new MoveOperation(
  1434. op.sourcePosition,
  1435. op.howMany,
  1436. new Position( root, [ 4, 1, 0 ] ),
  1437. baseVersion
  1438. );
  1439. let transOp = transform( op, transformBy, true );
  1440. expected.sourcePosition.path = [ 4, 1, 0 ];
  1441. expect( transOp.length ).to.equal( 1 );
  1442. expectOperation( transOp[ 0 ], expected );
  1443. } );
  1444. it( 'range contains transforming range and is important: convert to NoOperation', () => {
  1445. let transformBy = new MoveOperation(
  1446. new Position( root, [ 2, 2, 3 ] ),
  1447. 4,
  1448. new Position( root, [ 4, 1, 0 ] ),
  1449. baseVersion
  1450. );
  1451. let transOp = transform( op, transformBy );
  1452. expect( transOp.length ).to.equal( 1 );
  1453. expectOperation( transOp[ 0 ], {
  1454. type: NoOperation,
  1455. baseVersion: baseVersion + 1
  1456. } );
  1457. } );
  1458. it( 'range contains transforming range and is less important: update range path', () => {
  1459. let transformBy = new MoveOperation(
  1460. new Position( root, [ 2, 2, 3 ] ),
  1461. 4,
  1462. new Position( root, [ 4, 1, 0 ] ),
  1463. baseVersion
  1464. );
  1465. let transOp = transform( op, transformBy, true );
  1466. expected.sourcePosition.path = [ 4, 1, 1 ];
  1467. expect( transOp.length ).to.equal( 1 );
  1468. expectOperation( transOp[ 0 ], expected );
  1469. } );
  1470. it( 'range contains transforming range and target and is important: update range path and target', () => {
  1471. op.targetPosition.path = [ 2, 2, 7 ];
  1472. let transformBy = new MoveOperation(
  1473. new Position( root, [ 2, 2, 3 ] ),
  1474. 5,
  1475. new Position( root, [ 4, 1, 0 ] ),
  1476. baseVersion
  1477. );
  1478. let transOp = transform( op, transformBy );
  1479. expect( transOp.length ).to.equal( 1 );
  1480. expected.sourcePosition.path = [ 4, 1, 1 ];
  1481. expected.targetPosition.path = [ 4, 1, 4 ];
  1482. expectOperation( transOp[ 0 ], expected );
  1483. } );
  1484. it( 'range contains transforming range and target and is less important: update range path and target', () => {
  1485. op.targetPosition.path = [ 2, 2, 7 ];
  1486. let transformBy = new MoveOperation(
  1487. new Position( root, [ 2, 2, 3 ] ),
  1488. 5,
  1489. new Position( root, [ 4, 1, 0 ] ),
  1490. baseVersion
  1491. );
  1492. let transOp = transform( op, transformBy, true );
  1493. expect( transOp.length ).to.equal( 1 );
  1494. expected.sourcePosition.path = [ 4, 1, 1 ];
  1495. expected.targetPosition.path = [ 4, 1, 4 ];
  1496. expectOperation( transOp[ 0 ], expected );
  1497. } );
  1498. it( 'range intersects on left side of transforming range and is important: shrink range', () => {
  1499. let transformBy = new MoveOperation(
  1500. new Position( root, [ 2, 2, 3 ] ),
  1501. 2,
  1502. new Position( root, [ 4, 1, 0 ] ),
  1503. baseVersion
  1504. );
  1505. let transOp = transform( op, transformBy );
  1506. expected.sourcePosition.path = [ 2, 2, 3 ];
  1507. expected.howMany = 1;
  1508. expect( transOp.length ).to.equal( 1 );
  1509. expectOperation( transOp[ 0 ], expected );
  1510. } );
  1511. it( 'range intersects on left side of transforming range and is less important: split into two operations', () => {
  1512. // Get more test cases and better code coverage
  1513. let otherRoot = new RootElement( null );
  1514. let transformBy = new MoveOperation(
  1515. new Position( root, [ 2, 2, 3 ] ),
  1516. 2,
  1517. new Position( otherRoot, [ 4, 1, 0 ] ),
  1518. baseVersion
  1519. );
  1520. let transOp = transform( op, transformBy, true );
  1521. expect( transOp.length ).to.equal( 2 );
  1522. expected.sourcePosition.path = [ 2, 2, 3 ];
  1523. expected.howMany = 1;
  1524. expectOperation( transOp[ 0 ], expected );
  1525. expected.sourcePosition = new Position( otherRoot, [ 4, 1, 1 ] );
  1526. expected.baseVersion++;
  1527. expectOperation( transOp[ 1 ], expected );
  1528. } );
  1529. it( 'range intersects on right side of transforming range and is important: shrink range', () => {
  1530. let transformBy = new MoveOperation(
  1531. new Position( root, [ 2, 2, 5 ] ),
  1532. 2,
  1533. new Position( root, [ 4, 1, 0 ] ),
  1534. baseVersion
  1535. );
  1536. let transOp = transform( op, transformBy );
  1537. expected.howMany = 1;
  1538. expect( transOp.length ).to.equal( 1 );
  1539. expectOperation( transOp[ 0 ], expected );
  1540. } );
  1541. it( 'range intersects on right side of transforming range and is less important: split into two operations', () => {
  1542. let transformBy = new MoveOperation(
  1543. new Position( root, [ 2, 2, 5 ] ),
  1544. 2,
  1545. new Position( root, [ 4, 1, 0 ] ),
  1546. baseVersion
  1547. );
  1548. let transOp = transform( op, transformBy, true );
  1549. expect( transOp.length ).to.equal( 2 );
  1550. expected.sourcePosition.path = [ 4, 1, 0 ];
  1551. expected.howMany = 1;
  1552. expectOperation( transOp[ 0 ], expected );
  1553. expected.sourcePosition.path = op.sourcePosition.path;
  1554. expected.baseVersion++;
  1555. expectOperation( transOp[ 1 ], expected );
  1556. } );
  1557. it( 'range intersects on left side, target inside transforming range and is important: split into two operations', () => {
  1558. op.howMany = 4;
  1559. let transformBy = new MoveOperation(
  1560. new Position( root, [ 2, 2, 3 ] ),
  1561. 2,
  1562. new Position( root, [ 2, 2, 6 ] ),
  1563. baseVersion
  1564. );
  1565. let transOp = transform( op, transformBy );
  1566. expect( transOp.length ).to.equal( 2 );
  1567. expected.sourcePosition.path = [ 2, 2, 6 ];
  1568. expected.howMany = 2;
  1569. expectOperation( transOp[ 0 ], expected );
  1570. expected.sourcePosition.path = [ 2, 2, 3 ];
  1571. expected.howMany = 1;
  1572. expected.baseVersion++;
  1573. expectOperation( transOp[ 1 ], expected );
  1574. } );
  1575. it( 'range intersects on left side, target inside transforming range and is less important: split into three operations', () => {
  1576. op.howMany = 4;
  1577. let transformBy = new MoveOperation(
  1578. new Position( root, [ 2, 2, 3 ] ),
  1579. 2,
  1580. new Position( root, [ 2, 2, 6 ] ),
  1581. baseVersion
  1582. );
  1583. let transOp = transform( op, transformBy, true );
  1584. expect( transOp.length ).to.equal( 3 );
  1585. expected.sourcePosition.path = [ 2, 2, 6 ];
  1586. expected.howMany = 2;
  1587. expectOperation( transOp[ 0 ], expected );
  1588. expected.sourcePosition.path = [ 2, 2, 3 ];
  1589. expected.howMany = 1;
  1590. expected.baseVersion++;
  1591. expectOperation( transOp[ 1 ], expected );
  1592. expected.sourcePosition.path = [ 2, 2, 5 ];
  1593. expected.howMany = 1;
  1594. expected.baseVersion++;
  1595. expectOperation( transOp[ 2 ], expected );
  1596. } );
  1597. it( 'range intersects on right side, target inside transforming range and is important: split into two operations', () => {
  1598. op.howMany = 4;
  1599. let transformBy = new MoveOperation(
  1600. new Position( root, [ 2, 2, 7 ] ),
  1601. 2,
  1602. new Position( root, [ 2, 2, 5 ] ),
  1603. baseVersion
  1604. );
  1605. let transOp = transform( op, transformBy );
  1606. expect( transOp.length ).to.equal( 2 );
  1607. expected.sourcePosition.path = [ 2, 2, 7 ];
  1608. expected.howMany = 2;
  1609. expectOperation( transOp[ 0 ], expected );
  1610. expected.sourcePosition.path = [ 2, 2, 4 ];
  1611. expected.howMany = 1;
  1612. expected.baseVersion++;
  1613. expectOperation( transOp[ 1 ], expected );
  1614. } );
  1615. it( 'range intersects on right side, target inside transforming range and is less important: split into three operations', () => {
  1616. op.howMany = 4;
  1617. let transformBy = new MoveOperation(
  1618. new Position( root, [ 2, 2, 7 ] ),
  1619. 2,
  1620. new Position( root, [ 2, 2, 5 ] ),
  1621. baseVersion
  1622. );
  1623. let transOp = transform( op, transformBy, true );
  1624. expect( transOp.length ).to.equal( 3 );
  1625. expected.sourcePosition.path = [ 2, 2, 5 ];
  1626. expected.howMany = 1;
  1627. expectOperation( transOp[ 0 ], expected );
  1628. expected.sourcePosition.path = [ 2, 2, 7 ];
  1629. expected.howMany = 2;
  1630. expected.baseVersion++;
  1631. expectOperation( transOp[ 1 ], expected );
  1632. expected.sourcePosition.path = [ 2, 2, 4 ];
  1633. expected.howMany = 1;
  1634. expected.baseVersion++;
  1635. expectOperation( transOp[ 2 ], expected );
  1636. } );
  1637. it( 'range inside transforming range and is important: split into two operations', () => {
  1638. op.howMany = 4;
  1639. let transformBy = new MoveOperation(
  1640. new Position( root, [ 2, 2, 5 ] ),
  1641. 2,
  1642. new Position( root, [ 4, 1, 0 ] ),
  1643. baseVersion
  1644. );
  1645. let transOp = transform( op, transformBy );
  1646. expect( transOp.length ).to.equal( 2 );
  1647. expected.sourcePosition.path = [ 2, 2, 5 ];
  1648. expected.howMany = 1;
  1649. expectOperation( transOp[ 0 ], expected );
  1650. expected.sourcePosition.path = [ 2, 2, 4 ];
  1651. expected.baseVersion++;
  1652. expectOperation( transOp[ 1 ], expected );
  1653. } );
  1654. it( 'range inside transforming range and is less important: split into three operations', () => {
  1655. op.howMany = 4;
  1656. let transformBy = new MoveOperation(
  1657. new Position( root, [ 2, 2, 5 ] ),
  1658. 2,
  1659. new Position( root, [ 4, 1, 0 ] ),
  1660. baseVersion
  1661. );
  1662. let transOp = transform( op, transformBy, true );
  1663. expect( transOp.length ).to.equal( 3 );
  1664. expected.sourcePosition.path = [ 2, 2, 5 ];
  1665. expected.howMany = 1;
  1666. expectOperation( transOp[ 0 ], expected );
  1667. expected.sourcePosition.path = [ 4, 1, 0 ];
  1668. expected.howMany = 2;
  1669. expected.baseVersion++;
  1670. expectOperation( transOp[ 1 ], expected );
  1671. expected.sourcePosition.path = [ 2, 2, 4 ];
  1672. expected.howMany = 1;
  1673. expected.baseVersion++;
  1674. expectOperation( transOp[ 2 ], expected );
  1675. } );
  1676. it( 'range and target inside transforming range and is important: no operation update', () => {
  1677. op.howMany = 6;
  1678. let transformBy = new MoveOperation(
  1679. new Position( root, [ 2, 2, 5 ] ),
  1680. 2,
  1681. new Position( root, [ 2, 2, 9 ] ),
  1682. baseVersion
  1683. );
  1684. let transOp = transform( op, transformBy );
  1685. expect( transOp.length ).to.equal( 1 );
  1686. expected.howMany = 6;
  1687. expectOperation( transOp[ 0 ], expected );
  1688. } );
  1689. it( 'range and target inside transforming range and is less important: no operation update', () => {
  1690. op.howMany = 6;
  1691. let transformBy = new MoveOperation(
  1692. new Position( root, [ 2, 2, 5 ] ),
  1693. 2,
  1694. new Position( root, [ 2, 2, 9 ] ),
  1695. baseVersion
  1696. );
  1697. let transOp = transform( op, transformBy, true );
  1698. expect( transOp.length ).to.equal( 1 );
  1699. expected.howMany = 6;
  1700. expectOperation( transOp[ 0 ], expected );
  1701. } );
  1702. } );
  1703. describe( 'by NoOperation', () => {
  1704. it( 'no operation update', () => {
  1705. let transformBy = new NoOperation( baseVersion );
  1706. let transOp = transform( op, transformBy );
  1707. expect( transOp.length ).to.equal( 1 );
  1708. expectOperation( transOp[ 0 ], expected );
  1709. } );
  1710. } );
  1711. } );
  1712. describe( 'NoOperation', () => {
  1713. beforeEach( () => {
  1714. op = new NoOperation( baseVersion );
  1715. expected = {
  1716. type: NoOperation,
  1717. baseVersion: baseVersion + 1
  1718. };
  1719. } );
  1720. describe( 'by InsertOperation', () => {
  1721. it( 'no operation update', () => {
  1722. let transformBy = new InsertOperation(
  1723. new Position( root, [ 0 ] ),
  1724. 'a',
  1725. baseVersion
  1726. );
  1727. let transOp = transform( op, transformBy );
  1728. expect( transOp.length ).to.equal( 1 );
  1729. expectOperation( transOp[ 0 ], expected );
  1730. } );
  1731. } );
  1732. describe( 'by AttributeOperation', () => {
  1733. it( 'no operation update', () => {
  1734. let transformBy = new AttributeOperation(
  1735. new Range(
  1736. new Position( root, [ 0 ] ),
  1737. new Position( root, [ 1 ] )
  1738. ),
  1739. new Attribute( 'foo', 'bar' ),
  1740. new Attribute( 'foo', 'xyz' ),
  1741. baseVersion
  1742. );
  1743. let transOp = transform( op, transformBy );
  1744. expect( transOp.length ).to.equal( 1 );
  1745. expectOperation( transOp[ 0 ], expected );
  1746. } );
  1747. } );
  1748. describe( 'by MoveOperation', () => {
  1749. it( 'no operation update', () => {
  1750. let transformBy = new MoveOperation(
  1751. new Position( root, [ 0 ] ),
  1752. 2,
  1753. new Position( root, [ 1 ] ),
  1754. baseVersion
  1755. );
  1756. let transOp = transform( op, transformBy );
  1757. expect( transOp.length ).to.equal( 1 );
  1758. expectOperation( transOp[ 0 ], expected );
  1759. } );
  1760. } );
  1761. describe( 'by NoOperation', () => {
  1762. it( 'no operation update', () => {
  1763. let transformBy = new NoOperation( baseVersion );
  1764. let transOp = transform( op, transformBy );
  1765. expect( transOp.length ).to.equal( 1 );
  1766. expectOperation( transOp[ 0 ], expected );
  1767. } );
  1768. } );
  1769. } );
  1770. } );