overleaf/services/web/public/coffee/tests/unit/UndoManagerTests.coffee

456 lines
13 KiB
CoffeeScript
Raw Normal View History

2014-02-12 05:23:40 -05:00
define [
"undo/UndoManager"
], (UndoManager) ->
describe "UndoManager", ->
beforeEach ->
@undoManager = new UndoManager()
describe "Regression Tests", ->
describe "block commenting", ->
it "should convert correctly", ->
lines = ["a", "a", "a", "a"]
simpleDeltas = [
deltas: [
{ insert: "%", position: 0 }
{ insert: "%", position: 3 }
{ insert: "%", position: 6 }
{ insert: "%", position: 9 }
]
group: "doc"
]
aceDeltas = @undoManager._simpleDeltaSetsToAceDeltaSets(simpleDeltas, lines)
expectedAceDeltas = [
deltas: [{
action: "insertText"
text: "%"
range:
start: column: 0, row: 0
end: column: 1, row: 0
}, {
action: "insertText"
text: "%"
range:
start: column: 0, row: 1
end: column: 1, row: 1
}, {
action: "insertText"
text: "%"
range:
start: column: 0, row: 2
end: column: 1, row: 2
}, {
action: "insertText"
text: "%"
range:
start: column: 0, row: 3
end: column: 1, row: 3
}]
group: "doc"
]
console.log aceDeltas, expectedAceDeltas
aceDeltas.should.deep.equal expectedAceDeltas
describe "_shiftLocalChangeToTopOfUndoStack", ->
describe "with no local undos", ->
beforeEach ->
@undoManager.undoStack = [
{ deltaSets: [], remote: true }
{ deltaSets: [], remote: true }
]
@return = @undoManager._shiftLocalChangeToTopOfUndoStack()
it "should return false", ->
@return.should.equal false
describe "with a local undo that can be shifted to the top", ->
beforeEach ->
@undoManager.undoStack = [
{ deltaSets: [deltas: [{ position: 0, insert: "banana"}], group: "doc"], remote: true }
{ deltaSets: [deltas: [{ position: 5, insert: "baz" }], group: "doc"], remote: false }
{ deltaSets: [deltas: [{ position: 20, insert: "bar" }], group: "doc"], remote: true }
{ deltaSets: [deltas: [{ position: 10, insert: "foo" }], group: "doc"], remote: true }
]
@return = @undoManager._shiftLocalChangeToTopOfUndoStack()
it "should bring the local change to the top of the stack", ->
@expected = [
{ deltaSets: [deltas: [{ position: 0, insert: "banana"}], group: "doc"], remote: true }
{ deltaSets: [deltas: [{ position: 17, insert: "bar" }], group: "doc"], remote: true }
{ deltaSets: [deltas: [{ position: 7, insert: "foo" }], group: "doc"], remote: true }
{ deltaSets: [deltas: [{ position: 5, insert: "baz" }], group: "doc"], remote: false }
]
@undoManager.undoStack.should.deep.equal @expected
it "should return true", ->
@return.should.equal true
describe "with a local undo that cannot be brought all the way to the top", ->
beforeEach ->
@undoManager.undoStack = [
{ deltaSets: [deltas: [{ position: 0, insert: "banana"}], group: "doc"], remote: true }
{ deltaSets: [deltas: [{ position: 5, insert: "baz" }], group: "doc"], remote: false }
{ deltaSets: [deltas: [{ position: 20, insert: "bar" }], group: "doc"], remote: true }
{ deltaSets: [deltas: [{ position: 6, insert: "foo" }], group: "doc"], remote: true }
]
@return = @undoManager._shiftLocalChangeToTopOfUndoStack()
it "should bring the change as far up the stack as possible", ->
@expected = [
{ deltaSets: [deltas: [{ position: 0, insert: "banana"}], group: "doc"], remote: true }
{ deltaSets: [deltas: [{ position: 17, insert: "bar" }], group: "doc"], remote: true }
{ deltaSets: [deltas: [{ position: 5, insert: "baz" }], group: "doc"], remote: false }
{ deltaSets: [deltas: [{ position: 6, insert: "foo" }], group: "doc"], remote: true }
]
@undoManager.undoStack.should.deep.equal @expected
it "should return true", ->
@return.should.equal true
describe "_aceDeltaToSimpleDelta", ->
beforeEach ->
@docLines = [
"one",
"two",
"three",
"four"
]
describe "insertText", ->
it "should convert correctly", ->
@aceDelta =
action: "insertText"
range:
start:
row: 2
column: 2
end:
row: 2
column: 5
text: "foo"
@simpleDelta = @undoManager._aceDeltaToSimpleDelta(@aceDelta, @docLines)
@simpleDelta.should.deep.equal
insert: "foo"
position: 10
describe "insertLines", ->
it "should convert correctly", ->
@aceDelta =
action: "insertLines"
lines: [
"two and half"
"two and three quarters"
]
range:
start:
row: 2
column: 0
end:
row: 4
column: 0
@simpleDelta = @undoManager._aceDeltaToSimpleDelta(@aceDelta, @docLines)
@simpleDelta.should.deep.equal
insert: "two and half\ntwo and three quarters\n"
position: 8
describe "removeText", ->
it "should convert correctly", ->
@aceDelta =
action: "removeLines"
range:
start:
row: 1
column: 0
end:
row: 3
column: 0
lines: [
"two",
"three"
]
@simpleDelta = @undoManager._aceDeltaToSimpleDelta(@aceDelta, @docLines)
@simpleDelta.should.deep.equal
remove: "two\nthree\n"
position: 4
describe "_simpleDeltaToAceDelta", ->
describe "insert", ->
beforeEach ->
@docLines = [
"one",
"two"
"three"
]
describe "with leading and trailing partial lines", ->
it "should return insertText and insertLines ace updates", ->
@simpleDelta =
position: 7
insert: "after\ntwo and a half\nbefore"
@aceDeltas = @undoManager._simpleDeltaToAceDeltas(@simpleDelta, @docLines)
@expected = [{
text: "after"
range:
start: row: 1, column: 3
end: row:1, column: 8
action: "insertText"
}, {
text: "\n"
range:
start: row: 1, column: 8
end: row:2, column: 0
action: "insertText"
}, {
lines: [ "two and a half" ]
range:
start: row: 2, column:0
end: row:3, column: 0
action: "insertLines"
}, {
text: "before"
range:
start: row: 3, column:0
end: row: 3, column: 6
action: "insertText"
}]
@aceDeltas.should.deep.equal @expected
describe "remove", ->
beforeEach ->
@docLines = [
"one",
"two"
"three"
]
describe "with leading and trailing partial lines", ->
it "should return insertText and insertLines ace updates", ->
@simpleDelta =
position: 2
remove: "e\ntwo\nth"
@aceDeltas = @undoManager._simpleDeltaToAceDeltas(@simpleDelta, @docLines)
@expected = [{
text: "th"
range:
start: row: 2, column:0
end: row: 2, column: 2
action: "removeText"
}, {
lines: [ "two" ]
range:
start: row: 1, column:0
end: row:2, column: 0
action: "removeLines"
}, {
text: "\n"
range:
start: row: 0, column: 3
end: row:1, column: 0
action: "removeText"
}, {
text: "e"
range:
start: row: 0, column: 2
end: row: 0, column: 3
action: "removeText"
}]
@aceDeltas.should.deep.equal @expected
describe "_concatSimpleDeltas", ->
it "should concat adjacent simple deltas", ->
@result = @undoManager._concatSimpleDeltas [{
insert: "foo"
position: 5
}, {
insert: "bar"
position: 8
}, {
insert: "baz"
position: 11
}, {
insert: "one"
position: 20
}, {
insert: "two"
position: 23
}, {
remove: "three"
position: 26
}]
@result.should.deep.equal [{
insert: "foobarbaz"
position: 5
}, {
insert: "onetwo"
position: 20
}, {
remove: "three"
position: 26
}]
it "should concat removes", ->
@result = @undoManager._concatSimpleDeltas [{
remove: "foo"
position: 5
}, {
remove: "bar"
position: 5
}, {
remove: "baz"
position: 5
}]
@result.should.deep.equal [{
remove: "foobarbaz"
position: 5
}]
describe "_swapSimpleDeltaOrder", ->
describe "insert - insert", ->
describe "when the first delta is before the second", ->
beforeEach ->
# result: "**fooba"
[@newFirstDelta, @newSecondDelta] = @undoManager._swapSimpleDeltaOrder(
{ insert: "foo", position: 2 }
{ insert: "ba", position: 5 }
)
it "should remove the length of the first insert from the second position", ->
@newFirstDelta.should.deep.equal position: 2, insert: "ba"
@newSecondDelta.should.deep.equal position: 2, insert: "foo"
describe "when the second delta is inserted into the first", ->
beforeEach ->
# result "**fobao*"
@result = @undoManager._swapSimpleDeltaOrder(
{ insert: "foo", position: 2 }
{ insert: "ba", position: 4 }
)
it "should return null", ->
(@result?).should.equal false
describe "when the second delta is before the first", ->
beforeEach ->
# result: "**bafoo"
[@newFirstDelta, @newSecondDelta] = @undoManager._swapSimpleDeltaOrder(
{ insert: "foo", position: 2 }
{ insert: "ba", position: 2 }
)
it "should add the length of the second delta on to the first position", ->
@newFirstDelta.should.deep.equal insert: "ba", position: 2
@newSecondDelta.should.deep.equal insert: "foo", position: 4
describe "remove - remove", ->
describe "when the first delta is before the second", ->
beforeEach ->
# start "**fooba*
[@newFirstDelta, @newSecondDelta] = @undoManager._swapSimpleDeltaOrder(
{ remove: "foo", position: 2 }
{ remove: "ba", position: 2 }
)
it "should add the length of the first remove onto the second position", ->
@newFirstDelta.should.deep.equal position: 5, remove: "ba"
@newSecondDelta.should.deep.equal position: 2, remove: "foo"
describe "when the first and second delta overlap", ->
beforeEach ->
# start "**bfooa*
@result = @undoManager._swapSimpleDeltaOrder(
{ remove: "foo", position: 3 }
{ remove: "ba", position: 2 }
)
it "should return null", ->
(@result?).should.equal false
describe "when the second delta is before the first", ->
beforeEach ->
# start "**bafoo*
[@newFirstDelta, @newSecondDelta] = @undoManager._swapSimpleDeltaOrder(
{ remove: "foo", position: 4 }
{ remove: "ba", position: 2 }
)
it "should remove the length of the second delta from the first position", ->
@newFirstDelta.should.deep.equal position: 2, remove: "ba"
@newSecondDelta.should.deep.equal position: 2, remove: "foo"
describe "insert - remove", ->
describe "when the first delta is before the second", ->
beforeEach ->
# "**ba" -> "**fooba" -> "**foo"
[@newFirstDelta, @newSecondDelta] = @undoManager._swapSimpleDeltaOrder(
{ insert: "foo", position: 2 }
{ remove: "ba", position: 5 }
)
it "should remove the length of the first delta from the second position", ->
@newFirstDelta.should.deep.equal position: 2, remove: "ba"
@newSecondDelta.should.deep.equal position: 2, insert: "foo"
describe "when the deltas overlap", ->
beforeEach ->
# "**ba" -> "**bfooa" -> "**ooa"
@result = @undoManager._swapSimpleDeltaOrder(
{ insert: "foo", position: 3 }
{ remove: "bf", position: 2 }
)
it "should return null", ->
(@result?).should.equal false
describe "when the second delta is before the first", ->
beforeEach ->
# "**ba" -> "**bafoo" -> "**foo"
[@newFirstDelta, @newSecondDelta] = @undoManager._swapSimpleDeltaOrder(
{ insert: "foo", position: 4 }
{ remove: "ba", position: 2 }
)
it "should remove the length of the second delta from the first position", ->
@newFirstDelta.should.deep.equal position: 2, remove: "ba"
@newSecondDelta.should.deep.equal position: 2, insert: "foo"
describe "remove - insert", ->
describe "when the first delta is before the second", ->
beforeEach ->
# "**foo" -> "**" -> "**ba"
[@newFirstDelta, @newSecondDelta] = @undoManager._swapSimpleDeltaOrder(
{ remove: "foo", position: 2 }
{ insert: "ba", position: 2 }
)
it "should add the length of the first delta to the second position", ->
@newFirstDelta.should.deep.equal position: 5, insert: "ba"
@newSecondDelta.should.deep.equal position: 2, remove: "foo"
# I don't think the deltas can overlap in this case!
describe "when the first delta is after the second", ->
beforeEach ->
# "**foo" -> "**" -> "*ba*"
[@newFirstDelta, @newSecondDelta] = @undoManager._swapSimpleDeltaOrder(
{ remove: "foo", position: 2 }
{ insert: "ba", position: 1 }
)
it "should add the length of the second delta on to the first position", ->
@newFirstDelta.should.deep.equal position: 1, insert: "ba"
@newSecondDelta.should.deep.equal position: 4, remove: "foo"