RangesManagerTests.coffee 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. sinon = require('sinon')
  2. chai = require('chai')
  3. should = chai.should()
  4. expect = chai.expect
  5. modulePath = "../../../../app/js/RangesManager.js"
  6. SandboxedModule = require('sandboxed-module')
  7. describe "RangesManager", ->
  8. beforeEach ->
  9. @RangesManager = SandboxedModule.require modulePath,
  10. requires:
  11. "logger-sharelatex": @logger = { error: sinon.stub(), log: sinon.stub(), warn: sinon.stub() }
  12. @doc_id = "doc-id-123"
  13. @project_id = "project-id-123"
  14. @user_id = "user-id-123"
  15. @callback = sinon.stub()
  16. describe "applyUpdate", ->
  17. beforeEach ->
  18. @updates = [{
  19. meta:
  20. user_id: @user_id
  21. op: [{
  22. i: "two "
  23. p: 4
  24. }]
  25. }]
  26. @entries = {
  27. comments: [{
  28. op:
  29. c: "three "
  30. p: 4
  31. metadata:
  32. user_id: @user_id
  33. }]
  34. changes: [{
  35. op:
  36. i: "five"
  37. p: 15
  38. metadata:
  39. user_id: @user_id
  40. }]
  41. }
  42. @newDocLines = ["one two three four five"] # old is "one three four five"
  43. describe "successfully", ->
  44. beforeEach ->
  45. @RangesManager.applyUpdate @project_id, @doc_id, @entries, @updates, @newDocLines, @callback
  46. it "should return the modified the comments and changes", ->
  47. @callback.called.should.equal true
  48. [error, entries] = @callback.args[0]
  49. expect(error).to.be.null
  50. entries.comments[0].op.should.deep.equal {
  51. c: "three "
  52. p: 8
  53. }
  54. entries.changes[0].op.should.deep.equal {
  55. i: "five"
  56. p: 19
  57. }
  58. describe "with empty comments", ->
  59. beforeEach ->
  60. @entries.comments = []
  61. @RangesManager.applyUpdate @project_id, @doc_id, @entries, @updates, @newDocLines, @callback
  62. it "should return an object with no comments", ->
  63. # Save space in redis and don't store just {}
  64. @callback.called.should.equal true
  65. [error, entries] = @callback.args[0]
  66. expect(error).to.be.null
  67. expect(entries.comments).to.be.undefined
  68. describe "with empty changes", ->
  69. beforeEach ->
  70. @entries.changes = []
  71. @RangesManager.applyUpdate @project_id, @doc_id, @entries, @updates, @newDocLines, @callback
  72. it "should return an object with no changes", ->
  73. # Save space in redis and don't store just {}
  74. @callback.called.should.equal true
  75. [error, entries] = @callback.args[0]
  76. expect(error).to.be.null
  77. expect(entries.changes).to.be.undefined
  78. describe "with too many comments", ->
  79. beforeEach ->
  80. @RangesManager.MAX_COMMENTS = 2
  81. @updates = [{
  82. meta:
  83. user_id: @user_id
  84. op: [{
  85. c: "one"
  86. p: 0
  87. t: "thread-id-1"
  88. }]
  89. }]
  90. @entries = {
  91. comments: [{
  92. op:
  93. c: "three "
  94. p: 4
  95. t: "thread-id-2"
  96. metadata:
  97. user_id: @user_id
  98. }, {
  99. op:
  100. c: "four "
  101. p: 10
  102. t: "thread-id-3"
  103. metadata:
  104. user_id: @user_id
  105. }]
  106. changes: []
  107. }
  108. @RangesManager.applyUpdate @project_id, @doc_id, @entries, @updates, @newDocLines, @callback
  109. it "should return an error", ->
  110. @callback.called.should.equal true
  111. [error, entries] = @callback.args[0]
  112. expect(error).to.not.be.null
  113. expect(error.message).to.equal("too many comments or tracked changes")
  114. describe "with too many changes", ->
  115. beforeEach ->
  116. @RangesManager.MAX_CHANGES = 2
  117. @updates = [{
  118. meta:
  119. user_id: @user_id
  120. tc: "track-changes-id-yes"
  121. op: [{
  122. i: "one "
  123. p: 0
  124. }]
  125. }]
  126. @entries = {
  127. changes: [{
  128. op:
  129. i: "three"
  130. p: 4
  131. metadata:
  132. user_id: @user_id
  133. }, {
  134. op:
  135. i: "four"
  136. p: 10
  137. metadata:
  138. user_id: @user_id
  139. }]
  140. comments: []
  141. }
  142. @newDocLines = ["one two three four"]
  143. @RangesManager.applyUpdate @project_id, @doc_id, @entries, @updates, @newDocLines, @callback
  144. it "should return an error", ->
  145. # Save space in redis and don't store just {}
  146. @callback.called.should.equal true
  147. [error, entries] = @callback.args[0]
  148. expect(error).to.not.be.null
  149. expect(error.message).to.equal("too many comments or tracked changes")
  150. describe "inconsistent changes", ->
  151. beforeEach ->
  152. @updates = [{
  153. meta:
  154. user_id: @user_id
  155. op: [{
  156. c: "doesn't match"
  157. p: 0
  158. }]
  159. }]
  160. @RangesManager.applyUpdate @project_id, @doc_id, @entries, @updates, @newDocLines, @callback
  161. it "should return an error", ->
  162. # Save space in redis and don't store just {}
  163. @callback.called.should.equal true
  164. [error, entries] = @callback.args[0]
  165. expect(error).to.not.be.null
  166. expect(error.message).to.equal("Change ({\"op\":{\"i\":\"five\",\"p\":15},\"metadata\":{\"user_id\":\"user-id-123\"}}) doesn't match text (\"our \")")
  167. describe "acceptChanges", ->
  168. beforeEach ->
  169. @RangesManager = SandboxedModule.require modulePath,
  170. requires:
  171. "logger-sharelatex": @logger = { error: sinon.stub(), log: sinon.stub(), warn: sinon.stub() }
  172. "./RangesTracker":@RangesTracker = SandboxedModule.require "../../../../app/js/RangesTracker.js"
  173. @ranges = {
  174. comments: []
  175. changes: [{
  176. id: "a1"
  177. op:
  178. i: "lorem"
  179. p: 0
  180. }, {
  181. id: "a2"
  182. op:
  183. i: "ipsum"
  184. p: 10
  185. }, {
  186. id: "a3"
  187. op:
  188. i: "dolor"
  189. p: 20
  190. }, {
  191. id: "a4"
  192. op:
  193. i: "sit"
  194. p: 30
  195. }, {
  196. id: "a5"
  197. op:
  198. i: "amet"
  199. p: 40
  200. }]
  201. }
  202. @removeChangeIdsSpy = sinon.spy @RangesTracker.prototype, "removeChangeIds"
  203. describe "successfully with a single change", ->
  204. beforeEach (done) ->
  205. @change_ids = [ @ranges.changes[1].id ]
  206. @RangesManager.acceptChanges @change_ids, @ranges, (err, ranges) =>
  207. @rangesResponse = ranges
  208. done()
  209. it "should log the call with the correct number of changes", ->
  210. @logger.log
  211. .calledWith("accepting 1 changes in ranges")
  212. .should.equal true
  213. it "should delegate the change removal to the ranges tracker", ->
  214. @removeChangeIdsSpy
  215. .calledWith(@change_ids)
  216. .should.equal true
  217. it "should remove the change", ->
  218. expect(@rangesResponse.changes
  219. .find((change) => change.id == @ranges.changes[1].id))
  220. .to.be.undefined
  221. it "should return the original number of changes minus 1", ->
  222. @rangesResponse.changes.length
  223. .should.equal @ranges.changes.length - 1
  224. it "should not touch other changes", ->
  225. for i in [ 0, 2, 3, 4]
  226. expect(@rangesResponse.changes
  227. .find((change) => change.id == @ranges.changes[i].id))
  228. .to.deep.equal @ranges.changes[i]
  229. describe "successfully with multiple changes", ->
  230. beforeEach (done) ->
  231. @change_ids = [ @ranges.changes[1].id, @ranges.changes[3].id, @ranges.changes[4].id ]
  232. @RangesManager.acceptChanges @change_ids, @ranges, (err, ranges) =>
  233. @rangesResponse = ranges
  234. done()
  235. it "should log the call with the correct number of changes", ->
  236. @logger.log
  237. .calledWith("accepting #{ @change_ids.length } changes in ranges")
  238. .should.equal true
  239. it "should delegate the change removal to the ranges tracker", ->
  240. @removeChangeIdsSpy
  241. .calledWith(@change_ids)
  242. .should.equal true
  243. it "should remove the changes", ->
  244. for i in [ 1, 3, 4]
  245. expect(@rangesResponse.changes
  246. .find((change) => change.id == @ranges.changes[1].id))
  247. .to.be.undefined
  248. it "should return the original number of changes minus the number of accepted changes", ->
  249. @rangesResponse.changes.length
  250. .should.equal @ranges.changes.length - 3
  251. it "should not touch other changes", ->
  252. for i in [ 0, 2 ]
  253. expect(@rangesResponse.changes
  254. .find((change) => change.id == @ranges.changes[i].id))
  255. .to.deep.equal @ranges.changes[i]