Add more delta tests

This commit is contained in:
Jonatan Kłosko 2021-01-21 00:11:18 +01:00
parent ba6506a55e
commit e875da348e
6 changed files with 207 additions and 122 deletions

View file

@ -5,7 +5,7 @@
"scripts": {
"deploy": "NODE_ENV=production webpack --mode production",
"watch": "webpack --mode development --watch",
"format": "prettier --trailing-comma es5 --write {js,css}/**/*.{js,json,css,scss,md}",
"format": "prettier --trailing-comma es5 --write {js,test,css}/**/*.{js,json,css,scss,md}",
"test": "jest --watch"
},
"dependencies": {

View file

@ -1,40 +1,40 @@
import Delta from '../../js/lib/delta';
import Delta from "../../js/lib/delta";
describe('Delta', () => {
describe('compose', () => {
it('insert with insert', () => {
const a = new Delta().insert('A');
const b = new Delta().insert('B');
const expected = new Delta().insert('B').insert('A');
describe("Delta", () => {
describe("compose", () => {
test("insert with insert", () => {
const a = new Delta().insert("A");
const b = new Delta().insert("B");
const expected = new Delta().insert("B").insert("A");
expect(a.compose(b)).toEqual(expected);
});
it('insert with retain', () => {
const a = new Delta().insert('A');
test("insert with retain", () => {
const a = new Delta().insert("A");
const b = new Delta().retain(1);
const expected = new Delta().insert('A');
const expected = new Delta().insert("A");
expect(a.compose(b)).toEqual(expected);
});
it('insert with delete', () => {
const a = new Delta().insert('A');
test("insert with delete", () => {
const a = new Delta().insert("A");
const b = new Delta().delete(1);
const expected = new Delta();
expect(a.compose(b)).toEqual(expected);
});
it('retain with insert', () => {
test("retain with insert", () => {
const a = new Delta().retain(1);
const b = new Delta().insert('B');
const expected = new Delta().insert('B');
const b = new Delta().insert("B");
const expected = new Delta().insert("B");
expect(a.compose(b)).toEqual(expected);
});
it('retain with retain', () => {
test("retain with retain", () => {
const a = new Delta().retain(1);
const b = new Delta().retain(1);
const expected = new Delta();
@ -42,7 +42,7 @@ describe('Delta', () => {
expect(a.compose(b)).toEqual(expected);
});
it('retain with delete', () => {
test("retain with delete", () => {
const a = new Delta().retain(1);
const b = new Delta().delete(1);
const expected = new Delta().delete(1);
@ -50,15 +50,15 @@ describe('Delta', () => {
expect(a.compose(b)).toEqual(expected);
});
it('delete with insert', () => {
test("delete with insert", () => {
const a = new Delta().delete(1);
const b = new Delta().insert('B');
const expected = new Delta().insert('B').delete(1);
const b = new Delta().insert("B");
const expected = new Delta().insert("B").delete(1);
expect(a.compose(b)).toEqual(expected);
});
it('delete with retain', () => {
test("delete with retain", () => {
const a = new Delta().delete(1);
const b = new Delta().retain(1);
const expected = new Delta().delete(1);
@ -66,7 +66,7 @@ describe('Delta', () => {
expect(a.compose(b)).toEqual(expected);
});
it('delete with delete', () => {
test("delete with delete", () => {
const a = new Delta().delete(1);
const b = new Delta().delete(1);
const expected = new Delta().delete(2);
@ -74,181 +74,182 @@ describe('Delta', () => {
expect(a.compose(b)).toEqual(expected);
});
it('insert in the middle of a text', () => {
const a = new Delta().insert('Hello');
const b = new Delta().retain(3).insert('X');
const expected = new Delta().insert('HelXlo');
test("insert in the middle of a text", () => {
const a = new Delta().insert("Hello");
const b = new Delta().retain(3).insert("X");
const expected = new Delta().insert("HelXlo");
expect(a.compose(b)).toEqual(expected);
});
it('insert and delete with different ordering', () => {
const a = new Delta().insert('Hello');
const b = new Delta().insert('Hello');
test("insert and delete with different ordering", () => {
const a = new Delta().insert("Hello");
const b = new Delta().insert("Hello");
const insertFirst = new Delta()
.retain(3)
.insert('X')
.delete(1);
const insertFirst = new Delta().retain(3).insert("X").delete(1);
const deleteFirst = new Delta()
.retain(3)
.delete(1)
.insert('X');
const deleteFirst = new Delta().retain(3).delete(1).insert("X");
const expected = new Delta().insert('HelXo');
const expected = new Delta().insert("HelXo");
expect(a.compose(insertFirst)).toEqual(expected);
expect(b.compose(deleteFirst)).toEqual(expected);
});
it('retain then insert with delete entire text', () => {
const a = new Delta().retain(4).insert('Hello');
test("retain then insert with delete entire text", () => {
const a = new Delta().retain(4).insert("Hello");
const b = new Delta().delete(9);
const expected = new Delta().delete(4);
expect(a.compose(b)).toEqual(expected);
});
it('retain more than the length of text', () => {
const a = new Delta().insert('Hello');
test("retain more than the length of text", () => {
const a = new Delta().insert("Hello");
const b = new Delta().retain(10);
const expected = new Delta().insert('Hello');
const expected = new Delta().insert("Hello");
expect(a.compose(b)).toEqual(expected);
});
});
describe('transform', () => {
it('insert against insert', () => {
const a = new Delta().insert('A');
const b = new Delta().insert('B');
const bPrimeAssumingAFirst = new Delta().retain(1).insert('B');
const bPrimeAssumingBFirst = new Delta().insert('B');
describe("transform", () => {
test("insert against insert", () => {
const a = new Delta().insert("A");
const b = new Delta().insert("B");
const bPrimeAssumingAFirst = new Delta().retain(1).insert("B");
const bPrimeAssumingBFirst = new Delta().insert("B");
expect(a.transform(b, "left")).toEqual(bPrimeAssumingAFirst);
expect(a.transform(b, "right")).toEqual(bPrimeAssumingBFirst);
});
it('retain against insert', () => {
const a = new Delta().insert('A');
const b = new Delta().retain(1).insert('B');
const bPrime = new Delta().retain(2).insert('B');
test("retain against insert", () => {
const a = new Delta().insert("A");
// Add insert, so that trailing retain is not trimmed (same in other places)
const b = new Delta().retain(1).insert("B");
const bPrime = new Delta().retain(2).insert("B");
expect(a.transform(b, "right")).toEqual(bPrime);
});
it('delete against insert', () => {
const a = new Delta().insert('A');
test("delete against insert", () => {
const a = new Delta().insert("A");
const b = new Delta().delete(1);
const bPrime = new Delta().retain(1).delete(1);
expect(a.transform(b, "right")).toEqual(bPrime);
});
it('insert against delete', () => {
test("insert against delete", () => {
const a = new Delta().delete(1);
const b = new Delta().insert('B');
const bPrime = new Delta().insert('B');
const b = new Delta().insert("B");
const bPrime = new Delta().insert("B");
expect(a.transform(b, "right")).toEqual(bPrime);
});
it('retain against delete', () => {
test("retain against delete", () => {
const a = new Delta().delete(1);
const b = new Delta().retain(1);
const bPrime = new Delta();
const b = new Delta().retain(1).insert("B");
const bPrime = new Delta().insert("B");
expect(a.transform(b, "right")).toEqual(bPrime);
});
it('delete against delete', () => {
test("delete against delete", () => {
const a = new Delta().delete(1);
const b = new Delta().delete(1);
const bPrime = new Delta();
expect(a.transform(b, "right")).toEqual(bPrime);
});
it('insert against retain', () => {
const a = new Delta().retain(1).insert('A');
const b = new Delta().insert('B');
const bPrime = new Delta().insert('B');
test("insert against retain", () => {
const a = new Delta().retain(1).insert("A");
const b = new Delta().insert("B");
const bPrime = new Delta().insert("B");
expect(a.transform(b, "right")).toEqual(bPrime);
});
it('retain against retain', () => {
const a = new Delta().retain(1).insert('A');
const b = new Delta().retain(1).insert('B');
const bPrime = new Delta().retain(1).insert('B')
test("retain against retain", () => {
const a = new Delta().retain(1).insert("A");
const b = new Delta().retain(1).insert("B");
const bPrime = new Delta().retain(1).insert("B");
expect(a.transform(b, "right")).toEqual(bPrime);
});
it('delete against retain', () => {
test("delete against retain", () => {
const a = new Delta().retain(1);
const b = new Delta().delete(1);
const bPrime = new Delta().delete(1);
expect(a.transform(b, "right")).toEqual(bPrime);
});
it('alternating edits', () => {
const a = new Delta()
.retain(2)
.insert('si')
.delete(5);
test("multiple edits", () => {
const a = new Delta().retain(2).insert("aa").delete(5);
const b = new Delta()
.retain(1)
.insert('e')
.insert("b")
.delete(5)
.retain(1)
.insert('ow');
.insert("bb");
const bPrimeAssumingBFirst = new Delta()
.retain(1)
.insert('e')
.insert("b")
.delete(1)
.retain(2)
.insert('ow');
.insert("bb");
const aPrimeAssumingBFirst = new Delta()
.retain(2)
.insert('si')
.delete(1);
const aPrimeAssumingBFirst = new Delta().retain(2).insert("aa").delete(1);
expect(a.transform(b, "right")).toEqual(bPrimeAssumingBFirst);
expect(b.transform(a, "left")).toEqual(aPrimeAssumingBFirst);
});
it('conflicting appends', () => {
const a = new Delta().retain(3).insert('aa');
const b = new Delta().retain(3).insert('bb');
const bPrimeAssumingBFirst = new Delta().retain(3).insert('bb');
const aPrimeAssumingBFirst = new Delta().retain(5).insert('aa');
test("conflicting appends", () => {
const a = new Delta().retain(3).insert("aa");
const b = new Delta().retain(3).insert("bb");
const bPrimeAssumingBFirst = new Delta().retain(3).insert("bb");
const aPrimeAssumingBFirst = new Delta().retain(5).insert("aa");
expect(a.transform(b, "right")).toEqual(bPrimeAssumingBFirst);
expect(b.transform(a, "left")).toEqual(aPrimeAssumingBFirst);
});
it('prepend and append', () => {
const a = new Delta().insert('aa');
const b = new Delta().retain(3).insert('bb');
const bPrime = new Delta().retain(5).insert('bb');
const aPrime = new Delta().insert('aa');
test("prepend and append", () => {
const a = new Delta().insert("aa");
const b = new Delta().retain(3).insert("bb");
const bPrime = new Delta().retain(5).insert("bb");
const aPrime = new Delta().insert("aa");
expect(a.transform(b, "right")).toEqual(bPrime);
expect(b.transform(a, "left")).toEqual(aPrime);
});
it('trailing deletes with differing lengths', () => {
test("trailing deletes with differing lengths", () => {
const a = new Delta().retain(2).delete(1);
const b = new Delta().delete(3);
const bPrime = new Delta().delete(2);
const aPrime = new Delta();
expect(a.transform(b, "right")).toEqual(bPrime);
expect(b.transform(a, "left")).toEqual(aPrime);
});
it('immutability', () => {
const a = new Delta().insert('A');
const b = new Delta().insert('B');
const bPrime = new Delta().retain(1).insert('B');
test("immutability", () => {
const a = new Delta().insert("A");
const b = new Delta().insert("B");
const bPrime = new Delta().retain(1).insert("B");
expect(a.transform(b, "left")).toEqual(bPrime);
expect(a).toEqual(new Delta().insert('A'));
expect(b).toEqual(new Delta().insert('B'));
expect(a).toEqual(new Delta().insert("A"));
expect(b).toEqual(new Delta().insert("B"));
});
});
});

View file

@ -19,5 +19,4 @@
"telemetry": {:hex, :telemetry, "0.4.2", "2808c992455e08d6177322f14d3bdb6b625fbcfd233a73505870d8738a2f4599", [:rebar3], [], "hexpm", "2d1419bd9dda6a206d7b5852179511722e2b18812310d304620c7bd92a13fcef"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.0", "da9d49ee7e6bb1c259d36ce6539cd45ae14d81247a2b0c90edf55e2b50507f7b", [:mix], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5cfe67ad464b243835512aa44321cee91faed6ea868d7fb761d7016e02915c3d"},
"telemetry_poller": {:hex, :telemetry_poller, "0.5.1", "21071cc2e536810bac5628b935521ff3e28f0303e770951158c73eaaa01e962a", [:rebar3], [{:telemetry, "~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4cab72069210bc6e7a080cec9afffad1b33370149ed5d379b81c7c5f0c663fd4"},
"text_delta": {:hex, :text_delta, "1.4.0", "ce55cd209d058b14dd15e5c22c5a55f8ca7d1c405e400f4e0e82654ec434d2cf", [:mix], [], "hexpm", "49f94d382c6baf08ae388f5e58901fa0f601154eaa67defae0c22af9f14c8668"},
}

View file

@ -13,17 +13,17 @@ defmodule LiveBook.Delta.TransformationText do
Delta.new()
|> Delta.insert("B")
b_prime_assuming_a_a =
b_prime_assuming_a_first =
Delta.new()
|> Delta.retain(1)
|> Delta.insert("B")
b_prime_assuming_b_a =
b_prime_assuming_b_first =
Delta.new()
|> Delta.insert("B")
assert Delta.transform(a, b, :left) == b_prime_assuming_a_a
assert Delta.transform(a, b, :right) == b_prime_assuming_b_a
assert Delta.transform(a, b, :left) == b_prime_assuming_a_first
assert Delta.transform(a, b, :right) == b_prime_assuming_b_first
end
test "retain against insert" do
@ -34,6 +34,7 @@ defmodule LiveBook.Delta.TransformationText do
b =
Delta.new()
|> Delta.retain(1)
# Add insert, so that trailing retain is not trimmed (same in other places)
|> Delta.insert("B")
b_prime =
@ -85,8 +86,12 @@ defmodule LiveBook.Delta.TransformationText do
b =
Delta.new()
|> Delta.retain(1)
|> Delta.insert("B")
b_prime =
Delta.new()
|> Delta.insert("B")
b_prime = Delta.new()
assert Delta.transform(a, b, :right) == b_prime
end
@ -100,6 +105,7 @@ defmodule LiveBook.Delta.TransformationText do
|> Delta.delete(1)
b_prime = Delta.new()
assert Delta.transform(a, b, :right) == b_prime
end
@ -107,7 +113,6 @@ defmodule LiveBook.Delta.TransformationText do
a =
Delta.new()
|> Delta.retain(1)
# Add insert, so that trailing retain is not trimmed
|> Delta.insert("A")
b =
@ -156,33 +161,41 @@ defmodule LiveBook.Delta.TransformationText do
assert Delta.transform(a, b, :right) == b_prime
end
test "alternating edits" do
test "multiple edits" do
a =
Delta.new()
# Move 2 positions
|> Delta.retain(2)
|> Delta.insert("si")
# Insert a word
|> Delta.insert("aa")
# Delete a word
|> Delta.delete(5)
b =
Delta.new()
# Move 1 position
|> Delta.retain(1)
|> Delta.insert("e")
# Insert a word
|> Delta.insert("b")
# Delete a word
|> Delta.delete(5)
# Move 1 position
|> Delta.retain(1)
|> Delta.insert("ow")
# Insert another word
|> Delta.insert("bb")
b_prime_assuming_b_first =
Delta.new()
|> Delta.retain(1)
|> Delta.insert("e")
|> Delta.insert("b")
|> Delta.delete(1)
|> Delta.retain(2)
|> Delta.insert("ow")
|> Delta.insert("bb")
a_prime_assuming_b_first =
Delta.new()
|> Delta.retain(2)
|> Delta.insert("si")
|> Delta.insert("aa")
|> Delta.delete(1)
assert Delta.transform(a, b, :right) == b_prime_assuming_b_first
@ -224,20 +237,20 @@ defmodule LiveBook.Delta.TransformationText do
|> Delta.retain(3)
|> Delta.insert("bb")
b_prime =
b_prime_assuming_b_first =
Delta.new()
|> Delta.retain(5)
|> Delta.insert("bb")
a_prime =
a_prime_assuming_b_first =
Delta.new()
|> Delta.insert("aa")
assert Delta.transform(a, b, :right) == b_prime
assert Delta.transform(b, a, :left) == a_prime
assert Delta.transform(a, b, :right) == b_prime_assuming_b_first
assert Delta.transform(b, a, :left) == a_prime_assuming_b_first
end
test "trailing deletes with differing lengths" do
test "trailing deletes with different lengths" do
a =
Delta.new()
|> Delta.retain(2)

View file

@ -0,0 +1,72 @@
defmodule LiveBook.DeltaTest do
use ExUnit.Case, async: true
alias LiveBook.Delta
alias LiveBook.Delta.Operation
doctest Delta
describe "append/2" do
test "ignores empty operations" do
assert Delta.append(Delta.new(), {:insert, ""}) == %Delta{ops: []}
assert Delta.append(Delta.new(), {:retain, 0}) == %Delta{ops: []}
assert Delta.append(Delta.new(), {:delete, 0}) == %Delta{ops: []}
end
test "given empty delta just appends the operation" do
delta = Delta.new()
op = Operation.insert("cats")
assert Delta.append(delta, op) == %Delta{ops: [insert: "cats"]}
end
test "merges consecutive inserts" do
delta = Delta.new() |> Delta.insert("cats")
op = Operation.insert(" rule")
assert Delta.append(delta, op) == %Delta{ops: [insert: "cats rule"]}
end
test "merges consecutive retains" do
delta = Delta.new() |> Delta.retain(2)
op = Operation.retain(2)
assert Delta.append(delta, op) == %Delta{ops: [retain: 4]}
end
test "merges consecutive delete" do
delta = Delta.new() |> Delta.delete(2)
op = Operation.delete(2)
assert Delta.append(delta, op) == %Delta{ops: [delete: 4]}
end
test "given insert appended after delete, swaps the operations" do
delta = Delta.new() |> Delta.delete(2)
op = Operation.insert("cats")
assert Delta.append(delta, op) == %Delta{ops: [insert: "cats", delete: 2]}
end
end
describe "apply_to_string/2" do
test "prepend" do
string = "cats"
delta = Delta.new() |> Delta.insert("fat ")
assert Delta.apply_to_string(delta, string) == "fat cats"
end
test "insert in the middle" do
string = "cats"
delta = Delta.new() |> Delta.retain(3) |> Delta.insert("'")
assert Delta.apply_to_string(delta, string) == "cat's"
end
test "delete" do
string = "cats"
delta = Delta.new() |> Delta.retain(1) |> Delta.delete(2)
assert Delta.apply_to_string(delta, string) == "cs"
end
test "replace" do
string = "cats"
delta = Delta.new() |> Delta.retain(1) |> Delta.delete(2) |> Delta.insert("ar")
assert Delta.apply_to_string(delta, string) == "cars"
end
end
end

View file

@ -1 +1 @@
ExUnit.start(assert_receive_timeout: 500)
ExUnit.start(assert_receive_timeout: 1000)