8
0

transform.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /**
  2. * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import transformations from '../../../../src/model/delta/basic-transformations';
  6. /*jshint unused: false*/
  7. import deltaTransform from '../../../../src/model/delta/transform';
  8. const transformDeltaSets = deltaTransform.transformDeltaSets;
  9. import Document from '../../../../src/model/document';
  10. import Element from '../../../../src/model/element';
  11. import Text from '../../../../src/model/text';
  12. import Position from '../../../../src/model/position';
  13. import Delta from '../../../../src/model/delta/delta';
  14. import InsertDelta from '../../../../src/model/delta/insertdelta';
  15. import RemoveDelta from '../../../../src/model/delta/removedelta';
  16. import SplitDelta from '../../../../src/model/delta/splitdelta';
  17. import NoOperation from '../../../../src/model/operation/nooperation';
  18. import MoveOperation from '../../../../src/model/operation/moveoperation';
  19. import RemoveOperation from '../../../../src/model/operation/removeoperation';
  20. import InsertOperation from '../../../../src/model/operation/insertoperation';
  21. import {
  22. expectDelta,
  23. getInsertDelta,
  24. getSplitDelta,
  25. getRemoveDelta
  26. } from '../../../../tests/model/delta/transform/_utils/utils';
  27. describe( 'transform', () => {
  28. let doc, root, gy, baseVersion;
  29. beforeEach( () => {
  30. doc = new Document();
  31. root = doc.createRoot();
  32. root.appendChildren( new Element( 'p', null, new Text( 'foobar' ) ) );
  33. gy = doc.graveyard;
  34. baseVersion = doc.version;
  35. } );
  36. describe( 'transformDeltaSets', () => {
  37. it( 'should use deltaTransform.transform', () => {
  38. sinon.spy( deltaTransform, 'transform' );
  39. const insertDelta = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'xxx' ), baseVersion );
  40. const removeDelta = getRemoveDelta( new Position( root, [ 0, 0 ] ), 2, baseVersion );
  41. transformDeltaSets( [ insertDelta ], [ removeDelta ] );
  42. expect( deltaTransform.transform.called ).to.be.true;
  43. deltaTransform.transform.restore();
  44. } );
  45. it( 'should transform two deltas', () => {
  46. const insertDelta = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'xxx' ), baseVersion );
  47. const removeDelta = getRemoveDelta( new Position( root, [ 0, 0 ] ), 2, baseVersion );
  48. const { deltasA, deltasB } = transformDeltaSets( [ insertDelta ], [ removeDelta ] );
  49. expect( deltasA.length ).to.equal( 1 );
  50. expect( deltasB.length ).to.equal( 1 );
  51. expectDelta( deltasA[ 0 ], {
  52. type: InsertDelta,
  53. operations: [
  54. {
  55. type: InsertOperation,
  56. position: new Position( root, [ 0, 2 ] ),
  57. baseVersion: 1
  58. }
  59. ]
  60. } );
  61. expectDelta( deltasB[ 0 ], {
  62. type: RemoveDelta,
  63. operations: [
  64. {
  65. type: RemoveOperation,
  66. sourcePosition: new Position( root, [ 0, 0 ] ),
  67. howMany: 2,
  68. baseVersion: 1
  69. }
  70. ]
  71. } );
  72. } );
  73. it( 'should transform two deltas - reverse', () => {
  74. const insertDelta = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'xxx' ), baseVersion );
  75. const removeDelta = getRemoveDelta( new Position( root, [ 0, 0 ] ), 2, baseVersion );
  76. const { deltasA, deltasB } = transformDeltaSets( [ removeDelta ], [ insertDelta ] );
  77. expect( deltasA.length ).to.equal( 1 );
  78. expect( deltasB.length ).to.equal( 1 );
  79. expectDelta( deltasA[ 0 ], {
  80. type: RemoveDelta,
  81. operations: [
  82. {
  83. type: RemoveOperation,
  84. sourcePosition: new Position( root, [ 0, 0 ] ),
  85. howMany: 2,
  86. baseVersion: 1
  87. }
  88. ]
  89. } );
  90. expectDelta( deltasB[ 0 ], {
  91. type: InsertDelta,
  92. operations: [
  93. {
  94. type: InsertOperation,
  95. position: new Position( root, [ 0, 2 ] ),
  96. baseVersion: 1
  97. }
  98. ]
  99. } );
  100. } );
  101. it( 'should transform two arrays of deltas', () => {
  102. const splitDelta = getSplitDelta( new Position( root, [ 0, 3 ] ), new Element( 'p' ), 3, baseVersion );
  103. const insertDeltaX = getInsertDelta( new Position( root, [ 0, 3 ] ), new Text( 'xxx' ), baseVersion + 2 );
  104. const removeDelta = getRemoveDelta( new Position( root, [ 0, 2 ] ), 2, baseVersion );
  105. const insertDeltaY = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'yyy' ), baseVersion + 1 );
  106. const { deltasA, deltasB } = transformDeltaSets( [ splitDelta, insertDeltaX ], [ removeDelta, insertDeltaY ], true );
  107. expect( deltasA.length ).to.equal( 3 );
  108. expect( deltasB.length ).to.equal( 2 );
  109. expectDelta( deltasA[ 0 ], {
  110. type: SplitDelta,
  111. operations: [
  112. {
  113. type: InsertOperation,
  114. position: new Position( root, [ 1 ] ),
  115. baseVersion: 2
  116. },
  117. {
  118. type: MoveOperation,
  119. sourcePosition: new Position( root, [ 0, 2 ] ),
  120. howMany: 5,
  121. targetPosition: new Position( root, [ 1, 0 ] ),
  122. baseVersion: 3
  123. }
  124. ]
  125. } );
  126. expectDelta( deltasA[ 1 ], {
  127. type: InsertDelta,
  128. operations: [
  129. {
  130. type: InsertOperation,
  131. position: new Position( root, [ 0, 2 ] ),
  132. baseVersion: 4
  133. }
  134. ]
  135. } );
  136. expectDelta( deltasA[ 2 ], {
  137. type: Delta,
  138. operations: [
  139. {
  140. type: NoOperation,
  141. baseVersion: 5
  142. }
  143. ]
  144. } );
  145. expectDelta( deltasB[ 0 ], {
  146. type: RemoveDelta,
  147. operations: [
  148. {
  149. type: RemoveOperation,
  150. sourcePosition: new Position( root, [ 1, 0 ] ),
  151. howMany: 1,
  152. baseVersion: 3
  153. },
  154. {
  155. type: RemoveOperation,
  156. sourcePosition: new Position( root, [ 0, 2 ] ),
  157. howMany: 1,
  158. baseVersion: 4
  159. }
  160. ]
  161. } );
  162. expectDelta( deltasB[ 1 ], {
  163. type: InsertDelta,
  164. operations: [
  165. {
  166. type: InsertOperation,
  167. position: new Position( root, [ 1, 2 ] ),
  168. baseVersion: 5
  169. }
  170. ]
  171. } );
  172. } );
  173. it( 'should transform two arrays of deltas - reverse', () => {
  174. const splitDelta = getSplitDelta( new Position( root, [ 0, 3 ] ), new Element( 'p' ), 3, baseVersion );
  175. const insertDeltaX = getInsertDelta( new Position( root, [ 0, 3 ] ), new Text( 'xxx' ), baseVersion + 2 );
  176. const removeDelta = getRemoveDelta( new Position( root, [ 0, 2 ] ), 2, baseVersion );
  177. const insertDeltaY = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'yyy' ), baseVersion + 1 );
  178. const { deltasA, deltasB } = transformDeltaSets( [ removeDelta, insertDeltaY ], [ splitDelta, insertDeltaX ], true );
  179. expect( deltasA.length ).to.equal( 2 );
  180. expect( deltasB.length ).to.equal( 3 );
  181. expectDelta( deltasA[ 0 ], {
  182. type: RemoveDelta,
  183. operations: [
  184. {
  185. type: RemoveOperation,
  186. sourcePosition: new Position( root, [ 1, 0 ] ),
  187. howMany: 1,
  188. baseVersion: 3
  189. },
  190. {
  191. type: RemoveOperation,
  192. sourcePosition: new Position( root, [ 0, 2 ] ),
  193. howMany: 1,
  194. baseVersion: 4
  195. }
  196. ]
  197. } );
  198. expectDelta( deltasA[ 1 ], {
  199. type: InsertDelta,
  200. operations: [
  201. {
  202. type: InsertOperation,
  203. position: new Position( root, [ 1, 2 ] ),
  204. baseVersion: 5
  205. }
  206. ]
  207. } );
  208. expectDelta( deltasB[ 0 ], {
  209. type: SplitDelta,
  210. operations: [
  211. {
  212. type: InsertOperation,
  213. position: new Position( root, [ 1 ] ),
  214. baseVersion: 2
  215. },
  216. {
  217. type: MoveOperation,
  218. sourcePosition: new Position( root, [ 0, 2 ] ),
  219. howMany: 5,
  220. targetPosition: new Position( root, [ 1, 0 ] ),
  221. baseVersion: 3
  222. }
  223. ]
  224. } );
  225. expectDelta( deltasB[ 1 ], {
  226. type: InsertDelta,
  227. operations: [
  228. {
  229. type: InsertOperation,
  230. position: new Position( root, [ 0, 2 ] ),
  231. baseVersion: 4
  232. }
  233. ]
  234. } );
  235. expectDelta( deltasB[ 2 ], {
  236. type: Delta,
  237. operations: [
  238. {
  239. type: NoOperation,
  240. baseVersion: 5
  241. }
  242. ]
  243. } );
  244. } );
  245. it( 'importance flag - first set is important', () => {
  246. const insertDeltaA = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'xxx' ), baseVersion );
  247. const insertDeltaB = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'yyy' ), baseVersion );
  248. let { deltasA, deltasB } = transformDeltaSets( [ insertDeltaA ], [ insertDeltaB ], true );
  249. expectDelta( deltasA[ 0 ], {
  250. type: InsertDelta,
  251. operations: [
  252. {
  253. type: InsertOperation,
  254. position: new Position( root, [ 0, 4 ] ),
  255. baseVersion: 1
  256. }
  257. ]
  258. } );
  259. expectDelta( deltasB[ 0 ], {
  260. type: InsertDelta,
  261. operations: [
  262. {
  263. type: InsertOperation,
  264. position: new Position( root, [ 0, 7 ] ),
  265. baseVersion: 1
  266. }
  267. ]
  268. } );
  269. } );
  270. it( 'importance flag - second set is important', () => {
  271. const insertDeltaA = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'xxx' ), baseVersion );
  272. const insertDeltaB = getInsertDelta( new Position( root, [ 0, 4 ] ), new Text( 'yyy' ), baseVersion );
  273. let { deltasA, deltasB } = transformDeltaSets( [ insertDeltaA ], [ insertDeltaB ], false );
  274. expectDelta( deltasA[ 0 ], {
  275. type: InsertDelta,
  276. operations: [
  277. {
  278. type: InsertOperation,
  279. position: new Position( root, [ 0, 7 ] ),
  280. baseVersion: 1
  281. }
  282. ]
  283. } );
  284. expectDelta( deltasB[ 0 ], {
  285. type: InsertDelta,
  286. operations: [
  287. {
  288. type: InsertOperation,
  289. position: new Position( root, [ 0, 4 ] ),
  290. baseVersion: 1
  291. }
  292. ]
  293. } );
  294. } );
  295. it( 'should not modify original deltas or arrays', () => {
  296. const insertDeltaA = getInsertDelta( new Position( root, [ 0, 0 ] ), new Text( 'x' ), baseVersion );
  297. const insertDeltaB = getInsertDelta( new Position( root, [ 1, 0 ] ), new Text( 'y' ), baseVersion );
  298. const originalDeltasA = [ insertDeltaA ];
  299. const originalDeltasB = [ insertDeltaB ];
  300. let { deltasA, deltasB } = transformDeltaSets( originalDeltasA, originalDeltasB, false );
  301. expect( deltasA ).to.not.equal( originalDeltasA );
  302. expect( deltasB ).to.not.equal( originalDeltasB );
  303. expect( deltasA[ 0 ] ).to.not.equal( originalDeltasA[ 0 ] );
  304. expect( deltasB[ 0 ] ).to.not.equal( originalDeltasB[ 0 ] );
  305. } );
  306. } );
  307. } );