transform.js 63 KB

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