Просмотр исходного кода

Don't error when rewinding and insert op which is beyond the length of the document.

ShareJS will accept an op where p > content.length when applied,
and it applies as though p == content.length. However, the op is
passed to us with the original p > content.length. Detect if that
is the case with this op, and shift p back appropriately to match
ShareJS if so.
James Allen 11 лет назад
Родитель
Сommit
23dfe68cb8

+ 15 - 2
services/track-changes/app/coffee/DiffGenerator.coffee

@@ -5,6 +5,8 @@ ConsistencyError = (message) ->
 	return error
 ConsistencyError.prototype.__proto__ = Error.prototype
 
+logger = require "logger-sharelatex"
+
 module.exports = DiffGenerator =
 	ConsistencyError: ConsistencyError
 
@@ -15,13 +17,24 @@ module.exports = DiffGenerator =
 
 	rewindOp: (content, op) ->
 		if op.i?
-			textToBeRemoved = content.slice(op.p, op.p + op.i.length)
+			# ShareJS will accept an op where p > content.length when applied,
+			# and it applies as though p == content.length. However, the op is
+			# passed to us with the original p > content.length. Detect if that
+			# is the case with this op, and shift p back appropriately to match
+			# ShareJS if so.
+			p = op.p
+			max_p = content.length - op.i.length
+			if p > max_p
+				logger.warn {max_p, p}, "truncating position to content length"
+				p = max_p
+
+			textToBeRemoved = content.slice(p, p + op.i.length)
 			if op.i != textToBeRemoved
 				throw new ConsistencyError(
 					"Inserted content, '#{op.i}', does not match text to be removed, '#{textToBeRemoved}'"
 				)
 
-			return content.slice(0, op.p) + content.slice(op.p + op.i.length)
+			return content.slice(0, p) + content.slice(p + op.i.length)
 
 		else if op.d?
 			return content.slice(0, op.p) + op.d + content.slice(op.p)

+ 8 - 1
services/track-changes/test/unit/coffee/DiffGenerator/DiffGeneratorTests.coffee

@@ -7,7 +7,8 @@ SandboxedModule = require('sandboxed-module')
 
 describe "DiffGenerator", ->
 	beforeEach ->
-		@DiffGenerator = SandboxedModule.require modulePath
+		@DiffGenerator = SandboxedModule.require modulePath, requires:
+			"logger-sharelatex": { warn: sinon.stub() }
 		@ts = Date.now()
 		@user_id = "mock-user-id"
 		@user_id_2 = "mock-user-id-2"
@@ -34,6 +35,12 @@ describe "DiffGenerator", ->
 				expect( () =>
 					@DiffGenerator.rewindOp content, { p: 6, i: "foo" }
 				).to.throw(@DiffGenerator.ConsistencyError)
+		
+		describe "with an update which is beyond the length of the content", ->
+			it "should undo the insert as if it were at the end of the content", ->
+				content = "foobar"
+				rewoundContent = @DiffGenerator.rewindOp content, { p: 4, i: "bar" }
+				rewoundContent.should.equal "foo"
 
 	describe "rewindUpdate", ->
 		it "should rewind ops in reverse", ->