DiffGeneratorTests.coffee 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. sinon = require('sinon')
  2. chai = require('chai')
  3. should = chai.should()
  4. expect = chai.expect
  5. modulePath = "../../../../app/js/DiffGenerator.js"
  6. SandboxedModule = require('sandboxed-module')
  7. describe "DiffGenerator", ->
  8. beforeEach ->
  9. @DiffGenerator = SandboxedModule.require modulePath
  10. @ts = Date.now()
  11. @user_id = "mock-user-id"
  12. @meta = {
  13. start_ts: @ts, end_ts: @ts, user_id: @user_id
  14. }
  15. describe "rewindUpdate", ->
  16. describe "rewinding an insert", ->
  17. it "should undo the insert", ->
  18. content = "hello world"
  19. update =
  20. op: { p: 6, i: "wo" }
  21. rewoundContent = @DiffGenerator.rewindUpdate content, update
  22. rewoundContent.should.equal "hello rld"
  23. describe "rewinding a delete", ->
  24. it "should undo the delete", ->
  25. content = "hello rld"
  26. update =
  27. op: { p: 6, d: "wo" }
  28. rewoundContent = @DiffGenerator.rewindUpdate content, update
  29. rewoundContent.should.equal "hello world"
  30. describe "with an inconsistent update", ->
  31. it "should throw an error", ->
  32. content = "hello world"
  33. update =
  34. op: { p: 6, i: "foo" }
  35. expect( () =>
  36. @DiffGenerator.rewindUpdate content, update
  37. ).to.throw(@DiffGenerator.ConsistencyError)
  38. describe "rewindUpdates", ->
  39. it "should rewind updates in reverse", ->
  40. content = "aaabbbccc"
  41. updates = [
  42. { op: { p: 3, i: "bbb" } },
  43. { op: { p: 6, i: "ccc" } }
  44. ]
  45. rewoundContent = @DiffGenerator.rewindUpdates content, updates
  46. rewoundContent.should.equal "aaa"
  47. describe "applyUpdateToDiff", ->
  48. describe "an insert", ->
  49. it "should insert into the middle of (u)nchanged text", ->
  50. diff = @DiffGenerator.applyUpdateToDiff(
  51. [ { u: "foobar" } ],
  52. { op: { p: 3, i: "baz" }, meta: @meta }
  53. )
  54. expect(diff).to.deep.equal([
  55. { u: "foo" }
  56. { i: "baz", meta: @meta }
  57. { u: "bar" }
  58. ])
  59. it "should insert into the start of (u)changed text", ->
  60. diff = @DiffGenerator.applyUpdateToDiff(
  61. [ { u: "foobar" } ],
  62. { op: { p: 0, i: "baz" }, meta: @meta }
  63. )
  64. expect(diff).to.deep.equal([
  65. { i: "baz", meta: @meta }
  66. { u: "foobar" }
  67. ])
  68. it "should insert into the end of (u)changed text", ->
  69. diff = @DiffGenerator.applyUpdateToDiff(
  70. [ { u: "foobar" } ],
  71. { op: { p: 6, i: "baz" }, meta: @meta }
  72. )
  73. expect(diff).to.deep.equal([
  74. { u: "foobar" }
  75. { i: "baz", meta: @meta }
  76. ])
  77. it "should insert into the middle of (i)inserted text", ->
  78. diff = @DiffGenerator.applyUpdateToDiff(
  79. [ { i: "foobar", meta: @meta } ],
  80. { op: { p: 3, i: "baz" }, meta: @meta }
  81. )
  82. expect(diff).to.deep.equal([
  83. { i: "foo", meta: @meta }
  84. { i: "baz", meta: @meta }
  85. { i: "bar", meta: @meta }
  86. ])
  87. it "should not count deletes in the running length total", ->
  88. diff = @DiffGenerator.applyUpdateToDiff(
  89. [
  90. { d: "deleted", meta: @meta }
  91. { u: "foobar" }
  92. ],
  93. { op: { p: 3, i: "baz" }, meta: @meta }
  94. )
  95. expect(diff).to.deep.equal([
  96. { d: "deleted", meta: @meta }
  97. { u: "foo" }
  98. { i: "baz", meta: @meta }
  99. { u: "bar" }
  100. ])
  101. describe "a delete", ->
  102. describe "deleting unchanged text", ->
  103. it "should delete from the middle of (u)nchanged text", ->
  104. diff = @DiffGenerator.applyUpdateToDiff(
  105. [ { u: "foobazbar" } ],
  106. { op: { p: 3, d: "baz" }, meta: @meta }
  107. )
  108. expect(diff).to.deep.equal([
  109. { u: "foo" }
  110. { d: "baz", meta: @meta }
  111. { u: "bar" }
  112. ])
  113. it "should delete from the start of (u)nchanged text", ->
  114. diff = @DiffGenerator.applyUpdateToDiff(
  115. [ { u: "foobazbar" } ],
  116. { op: { p: 0, d: "foo" }, meta: @meta }
  117. )
  118. expect(diff).to.deep.equal([
  119. { d: "foo", meta: @meta }
  120. { u: "bazbar" }
  121. ])
  122. it "should delete from the end of (u)nchanged text", ->
  123. diff = @DiffGenerator.applyUpdateToDiff(
  124. [ { u: "foobazbar" } ],
  125. { op: { p: 6, d: "bar" }, meta: @meta }
  126. )
  127. expect(diff).to.deep.equal([
  128. { u: "foobaz" }
  129. { d: "bar", meta: @meta }
  130. ])
  131. it "should delete across multiple (u)changed text parts", ->
  132. diff = @DiffGenerator.applyUpdateToDiff(
  133. [ { u: "foo" }, { u: "baz" }, { u: "bar" } ],
  134. { op: { p: 2, d: "obazb" }, meta: @meta }
  135. )
  136. expect(diff).to.deep.equal([
  137. { u: "fo" }
  138. { d: "o", meta: @meta }
  139. { d: "baz", meta: @meta }
  140. { d: "b", meta: @meta }
  141. { u: "ar" }
  142. ])
  143. describe "deleting inserts", ->
  144. it "should delete from the middle of (i)nserted text", ->
  145. diff = @DiffGenerator.applyUpdateToDiff(
  146. [ { i: "foobazbar", meta: @meta } ],
  147. { op: { p: 3, d: "baz" }, meta: @meta }
  148. )
  149. expect(diff).to.deep.equal([
  150. { i: "foo", meta: @meta }
  151. { i: "bar", meta: @meta }
  152. ])
  153. it "should delete from the start of (u)nchanged text", ->
  154. diff = @DiffGenerator.applyUpdateToDiff(
  155. [ { i: "foobazbar", meta: @meta } ],
  156. { op: { p: 0, d: "foo" }, meta: @meta }
  157. )
  158. expect(diff).to.deep.equal([
  159. { i: "bazbar", meta: @meta }
  160. ])
  161. it "should delete from the end of (u)nchanged text", ->
  162. diff = @DiffGenerator.applyUpdateToDiff(
  163. [ { i: "foobazbar", meta: @meta } ],
  164. { op: { p: 6, d: "bar" }, meta: @meta }
  165. )
  166. expect(diff).to.deep.equal([
  167. { i: "foobaz", meta: @meta }
  168. ])
  169. it "should delete across multiple (u)changed and (i)nserted text parts", ->
  170. diff = @DiffGenerator.applyUpdateToDiff(
  171. [ { u: "foo" }, { i: "baz", meta: @meta }, { u: "bar" } ],
  172. { op: { p: 2, d: "obazb" }, meta: @meta }
  173. )
  174. expect(diff).to.deep.equal([
  175. { u: "fo" }
  176. { d: "o", meta: @meta }
  177. { d: "b", meta: @meta }
  178. { u: "ar" }
  179. ])
  180. describe "deleting over existing deletes", ->
  181. it "should delete across multiple (u)changed and (d)deleted text parts", ->
  182. diff = @DiffGenerator.applyUpdateToDiff(
  183. [ { u: "foo" }, { d: "baz", meta: @meta }, { u: "bar" } ],
  184. { op: { p: 2, d: "ob" }, meta: @meta }
  185. )
  186. expect(diff).to.deep.equal([
  187. { u: "fo" }
  188. { d: "o", meta: @meta }
  189. { d: "baz", meta: @meta }
  190. { d: "b", meta: @meta }
  191. { u: "ar" }
  192. ])
  193. describe "deleting when the text doesn't match", ->
  194. it "should throw an error when deleting from the middle of (u)nchanged text", ->
  195. expect(
  196. () => @DiffGenerator.applyUpdateToDiff(
  197. [ { u: "foobazbar" } ],
  198. { op: { p: 3, d: "xxx" }, meta: @meta }
  199. )
  200. ).to.throw(@DiffGenerator.ConsistencyError)
  201. it "should throw an error when deleting from the start of (u)nchanged text", ->
  202. expect(
  203. () => @DiffGenerator.applyUpdateToDiff(
  204. [ { u: "foobazbar" } ],
  205. { op: { p: 0, d: "xxx" }, meta: @meta }
  206. )
  207. ).to.throw(@DiffGenerator.ConsistencyError)
  208. it "should throw an error when deleting from the end of (u)nchanged text", ->
  209. expect(
  210. () => @DiffGenerator.applyUpdateToDiff(
  211. [ { u: "foobazbar" } ],
  212. { op: { p: 6, d: "xxx" }, meta: @meta }
  213. )
  214. ).to.throw(@DiffGenerator.ConsistencyError)