history.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /**
  2. * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import History from '/ckeditor5/engine/model/history.js';
  6. import Delta from '/ckeditor5/engine/model/delta/delta.js';
  7. import Operation from '/ckeditor5/engine/model/operation/operation.js';
  8. describe( 'History', () => {
  9. let history;
  10. beforeEach( () => {
  11. history = new History();
  12. } );
  13. describe( 'constructor', () => {
  14. it( 'should create an empty History instance', () => {
  15. expect( Array.from( history.getDeltas() ).length ).to.equal( 0 );
  16. } );
  17. } );
  18. describe( 'addDelta', () => {
  19. it( 'should save delta in the history', () => {
  20. let delta = new Delta();
  21. delta.addOperation( new Operation( 0 ) );
  22. history.addDelta( delta );
  23. const deltas = Array.from( history.getDeltas() );
  24. expect( deltas.length ).to.equal( 1 );
  25. expect( deltas[ 0 ] ).to.equal( delta );
  26. } );
  27. it( 'should save each delta only once', () => {
  28. let delta = new Delta();
  29. delta.addOperation( new Operation( 0 ) );
  30. history.addDelta( delta );
  31. history.addDelta( delta );
  32. const deltas = Array.from( history.getDeltas() );
  33. expect( deltas.length ).to.equal( 1 );
  34. expect( deltas[ 0 ] ).to.equal( delta );
  35. } );
  36. it( 'should save multiple deltas and keep their order', () => {
  37. let deltas = getDeltaSet();
  38. for ( let delta of deltas ) {
  39. history.addDelta( delta );
  40. }
  41. const historyDeltas = Array.from( history.getDeltas() );
  42. expect( historyDeltas ).to.deep.equal( deltas );
  43. } );
  44. it( 'should skip deltas that does not have operations', () => {
  45. let delta = new Delta();
  46. history.addDelta( delta );
  47. expect( Array.from( history.getDeltas() ).length ).to.equal( 0 );
  48. } );
  49. } );
  50. describe( 'getDelta', () => {
  51. it( 'should return array with one delta with given base version', () => {
  52. let delta = getDelta( 0 );
  53. history.addDelta( delta );
  54. const historyDelta = history.getDelta( 0 );
  55. expect( historyDelta ).to.deep.equal( [ delta ] );
  56. } );
  57. it( 'should return array with all updated deltas of delta with given base version', () => {
  58. let delta = getDelta( 0 );
  59. history.addDelta( delta );
  60. let deltas = getDeltaSet();
  61. history.updateDelta( 0, deltas );
  62. const historyDelta = history.getDelta( 0 );
  63. expect( historyDelta ).to.deep.equal( deltas );
  64. } );
  65. it( 'should return null if delta has not been found in history', () => {
  66. expect( history.getDelta( -1 ) ).to.be.null;
  67. expect( history.getDelta( 2 ) ).to.be.null;
  68. expect( history.getDelta( 20 ) ).to.be.null;
  69. } );
  70. it( 'should return null if delta has been removed by removeDelta', () => {
  71. let delta = getDelta( 0 );
  72. history.addDelta( delta );
  73. history.removeDelta( 0 );
  74. expect( history.getDelta( 0 ) ).to.be.null;
  75. } );
  76. } );
  77. describe( 'getDeltas', () => {
  78. let deltas;
  79. beforeEach( () => {
  80. deltas = getDeltaSet();
  81. for ( let delta of deltas ) {
  82. history.addDelta( delta );
  83. }
  84. } );
  85. it( 'should return only history deltas from given base version', () => {
  86. const historyDeltas = Array.from( history.getDeltas( 3 ) );
  87. expect( historyDeltas ).to.deep.equal( deltas.slice( 1 ) );
  88. } );
  89. it( 'should return only history deltas to given base version', () => {
  90. const historyDeltas = Array.from( history.getDeltas( 3, 6 ) );
  91. expect( historyDeltas ).to.deep.equal( deltas.slice( 1, 2 ) );
  92. } );
  93. it( 'should return empty (finished) iterator if given history point is too high or negative', () => {
  94. expect( Array.from( history.getDeltas( 20 ) ).length ).to.equal( 0 );
  95. expect( Array.from( history.getDeltas( -1 ) ).length ).to.equal( 0 );
  96. } );
  97. it( 'should throw if given history point is "inside" delta', () => {
  98. expect( () => {
  99. Array.from( history.getDeltas( 2 ) );
  100. } ).to.throwCKEditorError( /model-history-wrong-version/ );
  101. } );
  102. } );
  103. describe( 'updateDelta', () => {
  104. it( 'should substitute delta from history by given deltas', () => {
  105. history.addDelta( getDelta( 0 ) );
  106. const deltas = getDeltaSet();
  107. history.updateDelta( 0, deltas );
  108. const historyDeltas = Array.from( history.getDeltas() );
  109. expect( historyDeltas ).to.deep.equal( deltas );
  110. } );
  111. it( 'should substitute all updated deltas by new deltas', () => {
  112. history.addDelta( getDelta( 0 ) );
  113. // Change original single delta to three deltas generated by `getDeltaSet`.
  114. // All those deltas should now be seen under base version 0.
  115. history.updateDelta( 0, getDeltaSet() );
  116. const deltas = getDeltaSet();
  117. // Change all three deltas from base version 0 to new set of deltas.
  118. history.updateDelta( 0, deltas );
  119. const historyDeltas = Array.from( history.getDeltas() );
  120. expect( historyDeltas ).to.deep.equal( deltas );
  121. } );
  122. it( 'should do nothing if deltas for given base version has not been found in history', () => {
  123. history.addDelta( getDelta( 0 ) );
  124. history.removeDelta( 0 );
  125. const deltas = getDeltaSet();
  126. history.updateDelta( 0, deltas );
  127. expect( Array.from( history.getDeltas() ).length ).to.equal( 0 );
  128. } );
  129. } );
  130. describe( 'removeDelta', () => {
  131. it( 'should remove deltas that do not have graveyard related operations', () => {
  132. for ( let delta of getDeltaSet() ) {
  133. history.addDelta( delta );
  134. }
  135. history.removeDelta( 3 );
  136. const deltas = Array.from( history.getDeltas() );
  137. expect( deltas.length ).to.equal( 2 );
  138. } );
  139. it( 'should remove multiple updated deltas', () => {
  140. let delta = getDelta( 0 );
  141. history.addDelta( delta );
  142. let updatedDeltas = getDeltaSet( 0 );
  143. history.updateDelta( 0, updatedDeltas );
  144. history.removeDelta( 0 );
  145. const deltas = Array.from( history.getDeltas() );
  146. expect( deltas.length ).to.equal( 0 );
  147. } );
  148. it( 'should do nothing if deltas for given base version has not been found in history', () => {
  149. const deltas = getDeltaSet();
  150. for ( let delta of deltas ) {
  151. history.addDelta( delta );
  152. }
  153. history.removeDelta( 12 );
  154. expect( Array.from( history.getDeltas() ) ).to.deep.equal( deltas );
  155. } );
  156. } );
  157. } );
  158. function getDeltaSet() {
  159. const deltas = [];
  160. deltas.push( getDelta( 0 ) );
  161. deltas.push( getDelta( 3 ) );
  162. deltas.push( getDelta( 6 ) );
  163. return deltas;
  164. }
  165. function getDelta( baseVersion ) {
  166. const delta = new Delta();
  167. for ( let i = 0; i < 3; i++ ) {
  168. delta.addOperation( new Operation( i + baseVersion ) );
  169. }
  170. return delta;
  171. }