fastdiff.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /**
  2. * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md.
  4. */
  5. import fastDiff from '../src/fastdiff';
  6. import diff from '../src/diff';
  7. import diffToChanges from '../src/difftochanges';
  8. describe( 'fastDiff', () => {
  9. it( 'should diff identical texts', () => {
  10. expectDiff( '123', '123', [] );
  11. } );
  12. describe( 'insertion', () => {
  13. it( 'should diff if old text is empty', () => {
  14. expectDiff( '', '123', [ { index: 0, type: 'insert', values: [ '1', '2', '3' ] } ] );
  15. } );
  16. it( 'should diff insertion on the beginning', () => {
  17. expectDiff( '123', 'abc123', [ { index: 0, type: 'insert', values: [ 'a', 'b', 'c' ] } ] );
  18. } );
  19. it( 'should diff insertion on the beginning (repetitive substring)', () => {
  20. // Do not check compatibility with 'diffToChanges' as it generates:
  21. // [ { index: 0, type: 'insert', values: [ 'a', 'b' ] }, { index: 5, type: 'insert', values: [ 'c', '1', '2', '3' ] } ]
  22. expectDiff( '123', 'ab123c123', [ { index: 0, type: 'insert', values: [ 'a', 'b', '1', '2', '3', 'c' ] } ], false );
  23. } );
  24. it( 'should diff insertion on the end', () => {
  25. expectDiff( '123', '123abc', [ { index: 3, type: 'insert', values: [ 'a', 'b', 'c' ] } ] );
  26. } );
  27. it( 'should diff insertion on the end (repetitive substring)', () => {
  28. expectDiff( '123', '123ab123c', [ { index: 3, type: 'insert', values: [ 'a', 'b', '1', '2', '3', 'c' ] } ] );
  29. } );
  30. it( 'should diff insertion in the middle', () => {
  31. expectDiff( '123', '12abc3', [ { index: 2, type: 'insert', values: [ 'a', 'b', 'c' ] } ] );
  32. } );
  33. it( 'should diff insertion in the middle (repetitive substring)', () => {
  34. // Do not check compatibility with 'diffToChanges' as it generates:
  35. // [ { index: 2, type: 'insert', values: [ 'a', 'b', '1', '2' ] }, { index: 7, type: 'insert', values: [ 'c', '3' ] } ]
  36. expectDiff( '123', '12ab123c3', [ { index: 2, type: 'insert', values: [ 'a', 'b', '1', '2', '3', 'c' ] } ], false );
  37. } );
  38. it( 'should diff insertion of duplicated content', () => {
  39. expectDiff( '123', '123123', [ { index: 3, type: 'insert', values: [ '1', '2', '3' ] } ] );
  40. } );
  41. it( 'should diff insertion of partially duplicated content', () => {
  42. expectDiff( '123', '12323', [ { index: 3, type: 'insert', values: [ '2', '3' ] } ] );
  43. } );
  44. it( 'should diff insertion on both boundaries', () => {
  45. // Do not check compatibility with 'diffToChanges' as it generates:
  46. // [ { index: 2, type: 'insert', values: [ 'a', 'b' ] }, { index: 5, type: 'insert', values: [ 'c' ] } ]
  47. expectDiff( '123', 'ab123c', [
  48. { index: 0, type: 'insert', values: [ 'a', 'b', '1', '2', '3', 'c' ] },
  49. { index: 6, type: 'delete', howMany: 3 }
  50. ], false );
  51. } );
  52. } );
  53. describe( 'deletion', () => {
  54. it( 'should diff if new text is empty', () => {
  55. expectDiff( '123', '', [ { index: 0, type: 'delete', howMany: 3 } ] );
  56. } );
  57. it( 'should diff deletion on the beginning', () => {
  58. expectDiff( 'abc123', '123', [ { index: 0, type: 'delete', howMany: 3 } ] );
  59. } );
  60. it( 'should diff deletion on the beginning (repetitive substring)', () => {
  61. // Do not check compatibility with 'diffToChanges' as it generates:
  62. // [ { index: 0, type: 'delete', howMany: 2 }, { index: 3, type: 'delete', howMany: 4 } ]
  63. expectDiff( 'ab123c123', '123', [ { index: 0, type: 'delete', howMany: 6 } ], false );
  64. } );
  65. it( 'should diff deletion on the end', () => {
  66. expectDiff( '123abc', '123', [ { index: 3, type: 'delete', howMany: 3 } ] );
  67. } );
  68. it( 'should diff deletion on the end (repetitive substring)', () => {
  69. expectDiff( '123ab123c', '123', [ { index: 3, type: 'delete', howMany: 6 } ] );
  70. } );
  71. it( 'should diff deletion in the middle', () => {
  72. expectDiff( '12abc3', '123', [ { index: 2, type: 'delete', howMany: 3 } ] );
  73. } );
  74. it( 'should diff deletion in the middle (repetitive substring)', () => {
  75. // Do not check compatibility with 'diffToChanges' as it generates:
  76. // [ { index: 2, type: 'delete', howMany: 4 }, { index: 3, type: 'delete', howMany: 2 } ]
  77. expectDiff( '12ab123c3', '123', [ { index: 2, type: 'delete', howMany: 6 } ], false );
  78. } );
  79. it( 'should diff deletion on both boundaries', () => {
  80. // Do not check compatibility with 'diffToChanges' as it generates:
  81. // [ { index: 0, type: 'delete', howMany: 1 }, { index: 3, type: 'delete', howMany: 2 } ]
  82. expectDiff( '12abc3', '2ab', [
  83. { index: 0, type: 'insert', values: [ '2', 'a', 'b' ] },
  84. { index: 3, type: 'delete', howMany: 6 }
  85. ], false );
  86. } );
  87. it( 'should diff deletion of duplicated content', () => {
  88. expectDiff( '123123', '123', [ { index: 3, type: 'delete', howMany: 3 } ] );
  89. } );
  90. it( 'should diff deletion of partially duplicated content', () => {
  91. expectDiff( '12323', '123', [ { index: 3, type: 'delete', howMany: 2 } ] );
  92. } );
  93. it( 'should diff deletion of partially duplicated content 2', () => {
  94. // Do not check compatibility with 'diffToChanges' as it generates:
  95. // [ { index: 1, type: 'delete', howMany: 2 }, { index: 2, type: 'delete', howMany: 1 } ]
  96. expectDiff( '11233', '13', [ { index: 1, type: 'delete', howMany: 3 } ], false );
  97. } );
  98. } );
  99. describe( 'replacement', () => {
  100. it( 'should diff replacement of entire text', () => {
  101. // Do not check compatibility with 'diffToChanges' as it has changes in reveres order ('delete', 'insert') here.
  102. expectDiff( '12345', 'abcd', [
  103. { index: 0, type: 'insert', values: [ 'a', 'b', 'c', 'd' ] },
  104. { index: 4, type: 'delete', howMany: 5 }
  105. ], false );
  106. } );
  107. it( 'should diff replacement on the beginning', () => {
  108. expectDiff( '12345', 'abcd345', [
  109. { index: 0, type: 'insert', values: [ 'a', 'b', 'c', 'd' ] },
  110. { index: 4, type: 'delete', howMany: 2 }
  111. ] );
  112. } );
  113. it( 'should diff replacement on the beginning (repetitive substring)', () => {
  114. // Do not check compatibility with 'diffToChanges' as it has changes in reveres order ('delete', 'insert') here.
  115. expectDiff( '12345', '345345', [
  116. { index: 0, type: 'insert', values: [ '3', '4', '5' ] },
  117. { index: 3, type: 'delete', howMany: 2 }
  118. ], false );
  119. } );
  120. it( 'should diff replacement on the end', () => {
  121. // Do not check compatibility with 'diffToChanges' as it has changes in reveres order ('delete', 'insert') here.
  122. expectDiff( '12345', '12ab', [
  123. { index: 2, type: 'insert', values: [ 'a', 'b' ] },
  124. { index: 4, type: 'delete', howMany: 3 }
  125. ], false );
  126. } );
  127. it( 'should diff replacement on the end (repetitive substring)', () => {
  128. // Do not check compatibility with 'diffToChanges' as it generates:
  129. // [ { index: 3, type: 'insert', values: [ '1', '2', '3' ] }, { index: 7, type: 'delete', howMany: 1 } ]
  130. expectDiff( '12345', '1231234', [
  131. { index: 3, type: 'insert', values: [ '1', '2', '3', '4' ] },
  132. { index: 7, type: 'delete', howMany: 2 }
  133. ], false );
  134. } );
  135. it( 'should diff insertion of duplicated content', () => {
  136. expectDiff( '1234', '123123', [
  137. { index: 3, type: 'insert', values: [ '1', '2', '3' ] },
  138. { index: 6, type: 'delete', howMany: 1 }
  139. ], false );
  140. } );
  141. it( 'should diff insertion of duplicated content', () => {
  142. expectDiff( '1234', '13424', [
  143. { index: 1, type: 'insert', values: [ '3', '4', '2' ] },
  144. { index: 4, type: 'delete', howMany: 2 }
  145. ], false );
  146. } );
  147. it( 'should diff replacement in the middle', () => {
  148. expectDiff( '12345', '12ab5', [
  149. { index: 2, type: 'insert', values: [ 'a', 'b' ] },
  150. { index: 4, type: 'delete', howMany: 2 }
  151. ] );
  152. } );
  153. it( 'should diff replacement in the middle (repetitive substring)', () => {
  154. // Do not check compatibility with 'diffToChanges' as it generates:
  155. // [ { index: 2, type: 'insert', values: [ '1', '2' ] }, { index: 7, type: 'insert', values: [ '5' ] } ]
  156. expectDiff( '12345', '12123455', [
  157. { index: 2, type: 'insert', values: [ '1', '2', '3', '4', '5' ] },
  158. { index: 7, type: 'delete', howMany: 2 }
  159. ], false );
  160. } );
  161. it( 'should diff replacement of duplicated content', () => {
  162. // Do not check compatibility with 'diffToChanges' as it has changes in reveres order ('delete', 'insert') here.
  163. expectDiff( '123123', '123333', [
  164. { index: 3, type: 'insert', values: '33'.split( '' ) },
  165. { index: 5, type: 'delete', howMany: 2 }
  166. ], false );
  167. } );
  168. } );
  169. } );
  170. function expectDiff( oldText, newText, expected, checkDiffToChangesCompatibility = true ) {
  171. const result = fastDiff( oldText, newText );
  172. expect( result ).to.deep.equals( expected );
  173. if ( checkDiffToChangesCompatibility ) {
  174. expect( result ).to.deep.equals( diffToChanges( diff( oldText, newText ), newText ), 'diffToChanges compatibility' );
  175. }
  176. }