From d043d58ab6b635e0301be88a03dd5fd7632408be Mon Sep 17 00:00:00 2001 From: Jeounghui Date: Tue, 30 Jan 2024 16:06:10 +0900 Subject: [PATCH 1/6] Add merge concurrency test --- test/integration/tree_concurrency_test.go | 48 ++++++++++++++++++++++- test/integration/tree_test.go | 4 +- 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/test/integration/tree_concurrency_test.go b/test/integration/tree_concurrency_test.go index b62e41706..2fda715b5 100644 --- a/test/integration/tree_concurrency_test.go +++ b/test/integration/tree_concurrency_test.go @@ -30,6 +30,24 @@ import ( "github.com/yorkie-team/yorkie/test/helper" ) +func parseSimpleXML(s string) []string { + res := []string{} + for i := 0; i < len(s); i++ { + now := `` + if s[i] == '<' { + for i < len(s) && s[i] != '>' { + now += string(s[i]) + i++ + } + now += string(s[i]) + } else { + now += string(s[i]) + } + res = append(res, now) + } + return res +} + type testResult struct { flag bool resultDesc string @@ -77,6 +95,20 @@ func makeTwoRanges(from1, mid1, to1 int, from2, mid2, to2 int, desc string) twoR return twoRangesType{[2]rangeWithMiddleType{range0, range1}, desc} } +func getMergeRange(xml string, interval rangeType) rangeType { + content := parseSimpleXML(xml) + st, ed := -1, -1 + for i := interval.from + 1; i <= interval.to; i++ { + if st == -1 && len(content[i]) >= 2 && content[i][0] == '<' && content[i][1] == '/' { + st = i - 1 + } + if len(content[i]) >= 2 && content[i][0] == '<' && content[i][1] != '/' { + ed = i + } + } + return rangeType{st, ed} +} + type styleOpCode int type editOpCode int @@ -89,6 +121,7 @@ const ( const ( EditUndefined editOpCode = iota EditUpdate + MergeUpdate ) type operationInterface interface { @@ -138,7 +171,15 @@ func (op editOperationType) run(t *testing.T, doc *document.Document, user int, from, to := interval.from, interval.to assert.NoError(t, doc.Update(func(root *json.Object, p *presence.Presence) error { - root.GetTree("t").Edit(from, to, op.content, op.splitLevel) + if op.op == EditUpdate { + root.GetTree("t").Edit(from, to, op.content, op.splitLevel) + } else if op.op == MergeUpdate { + mergeInterval := getMergeRange(root.GetTree("t").ToXML(), interval) + from, to = mergeInterval.from, mergeInterval.to + if from != -1 && to != -1 && from < to { + root.GetTree("t").Edit(mergeInterval.from, mergeInterval.to, op.content, op.splitLevel) + } + } return nil })) } @@ -247,6 +288,7 @@ func TestTreeConcurrencyEditEdit(t *testing.T) { editOperationType{RangeBack, EditUpdate, elementNode1, 0, `insertElementBack`}, editOperationType{RangeAll, EditUpdate, elementNode1, 0, `replaceElement`}, editOperationType{RangeAll, EditUpdate, nil, 0, `delete`}, + editOperationType{RangeAll, MergeUpdate, nil, 0, `merge`}, } editOperations2 := []operationInterface{ @@ -259,6 +301,7 @@ func TestTreeConcurrencyEditEdit(t *testing.T) { editOperationType{RangeBack, EditUpdate, elementNode2, 0, `insertElementBack`}, editOperationType{RangeAll, EditUpdate, elementNode2, 0, `replaceElement`}, editOperationType{RangeAll, EditUpdate, nil, 0, `delete`}, + editOperationType{RangeAll, MergeUpdate, nil, 0, `merge`}, } RunTestTreeConcurrency("concurrently-edit-edit-test", t, initialState, initialXML, ranges, editOperations1, editOperations2) @@ -326,6 +369,8 @@ func TestTreeConcurrencyEditStyle(t *testing.T) { ranges := []twoRangesType{ // equal:

b

-

b

makeTwoRanges(3, 3, 6, 3, -1, 6, `equal`), + // equal multiple:

a

b

c

-

a

b

c

+ makeTwoRanges(0, 3, 9, 0, 3, 9, `equal multiple`), // A contains B:

a

b

c

-

b

makeTwoRanges(0, 3, 9, 3, -1, 6, `A contains B`), // B contains A:

b

-

a

b

c

@@ -344,6 +389,7 @@ func TestTreeConcurrencyEditStyle(t *testing.T) { editOperationType{RangeBack, EditUpdate, content, 0, `insertBack`}, editOperationType{RangeAll, EditUpdate, nil, 0, `delete`}, editOperationType{RangeAll, EditUpdate, content, 0, `replace`}, + editOperationType{RangeAll, MergeUpdate, nil, 0, `merge`}, } styleOperations := []operationInterface{ diff --git a/test/integration/tree_test.go b/test/integration/tree_test.go index 38df94629..5afb68c8d 100644 --- a/test/integration/tree_test.go +++ b/test/integration/tree_test.go @@ -1343,7 +1343,7 @@ func TestTree(t *testing.T) { assert.Equal(t, "

a

b

", d1.Root().GetTree("t").ToXML()) }) - t.Run("contained-split-and-split-at-diffrent-positions-on-the-same-node", func(t *testing.T) { + t.Run("contained-split-and-split-at-different-positions-on-the-same-node", func(t *testing.T) { ctx := context.Background() d1 := document.New(helper.TestDocKey(t)) assert.NoError(t, c1.Attach(ctx, d1)) @@ -2623,7 +2623,7 @@ func TestTree(t *testing.T) { assert.Equal(t, "

a

b

", d1.Root().GetTree("t").ToXML()) }) - t.Run("side-by-side-split-and-delete", func(t *testing.T) { + t.Run("side-by-side-split-and-merge", func(t *testing.T) { ctx := context.Background() d1 := document.New(helper.TestDocKey(t)) assert.NoError(t, c1.Attach(ctx, d1)) From 7e167cf1dc4441d942e87702cf45d688f8293ea5 Mon Sep 17 00:00:00 2001 From: Jeounghui Date: Wed, 31 Jan 2024 15:02:45 +0900 Subject: [PATCH 2/6] Add split edit test, split style test --- test/integration/tree_concurrency_test.go | 81 +++++++++++++++++++++-- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/test/integration/tree_concurrency_test.go b/test/integration/tree_concurrency_test.go index 2fda715b5..540344642 100644 --- a/test/integration/tree_concurrency_test.go +++ b/test/integration/tree_concurrency_test.go @@ -61,6 +61,8 @@ const ( RangeMiddle RangeBack RangeAll + RangeOneQuarter + RangeThreeQuarter ) type rangeType struct { @@ -77,14 +79,22 @@ type twoRangesType struct { } func getRange(ranges twoRangesType, selector rangeSelector, user int) rangeType { + interval := ranges.ranges[user] + from, mid, to := interval.from, interval.mid, interval.to if selector == RangeFront { - return rangeType{ranges.ranges[user].from, ranges.ranges[user].from} + return rangeType{from, from} } else if selector == RangeMiddle { - return rangeType{ranges.ranges[user].mid, ranges.ranges[user].mid} + return rangeType{mid, mid} } else if selector == RangeBack { - return rangeType{ranges.ranges[user].to, ranges.ranges[user].to} + return rangeType{to, to} } else if selector == RangeAll { - return rangeType{ranges.ranges[user].from, ranges.ranges[user].to} + return rangeType{from, to} + } else if selector == RangeOneQuarter { + pos := (from + mid) / 2 + return rangeType{pos, pos} + } else if selector == RangeThreeQuarter { + pos := (mid + to) / 2 + return rangeType{pos, pos} } return rangeType{-1, -1} } @@ -122,6 +132,7 @@ const ( EditUndefined editOpCode = iota EditUpdate MergeUpdate + SplitUpdate ) type operationInterface interface { @@ -179,6 +190,10 @@ func (op editOperationType) run(t *testing.T, doc *document.Document, user int, if from != -1 && to != -1 && from < to { root.GetTree("t").Edit(mergeInterval.from, mergeInterval.to, op.content, op.splitLevel) } + } else if op.op == SplitUpdate { + assert.NotEqual(t, 0, op.splitLevel) + assert.Equal(t, from, to) + root.GetTree("t").Edit(from, to, op.content, op.splitLevel) } return nil })) @@ -307,6 +322,64 @@ func TestTreeConcurrencyEditEdit(t *testing.T) { RunTestTreeConcurrency("concurrently-edit-edit-test", t, initialState, initialXML, ranges, editOperations1, editOperations2) } +func TestTreeConcurrencySplitEdit(t *testing.T) { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 + //

a b c d

e f g h

i j k l

+ + initialState := json.TreeNode{ + Type: "root", + Children: []json.TreeNode{ + {Type: "p", Children: []json.TreeNode{ + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "abcd"}}}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "efgh"}}}, + }}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "ijkl"}}}, + }, + } + initialXML := `

abcd

efgh

ijkl

` + + content := &json.TreeNode{Type: "i", Children: []json.TreeNode{}} + + ranges := []twoRangesType{ + // equal:

ab'cd

+ makeTwoRanges(1, 4, 7, 2, 4, 6, `equal`), + // A contains B:

ab'cd

- bc + makeTwoRanges(1, 4, 7, 3, 4, 5, `A contains B`), + // B contains A:

ab'cd

-

abcd

efgh

+ makeTwoRanges(1, 4, 7, 1, 7, 13, `B contains A`), + // left node(text):

ab'cd

- ab + makeTwoRanges(1, 4, 7, 2, 3, 4, `left node(text)`), + // right node(text):

ab'cd

- cd + makeTwoRanges(1, 4, 7, 4, 5, 6, `right node(text)`), + // left node(element):

abcd

'

efgh

-

abcd

+ makeTwoRanges(1, 7, 13, 1, 4, 7, `left node(element)`), + // right node(element):

abcd

'

efgh

-

efgh

+ makeTwoRanges(1, 7, 13, 7, 10, 13, `right node(element)`), + // A -> B:

ab'cd

-

efgh

+ makeTwoRanges(1, 4, 7, 7, 10, 13, `A -> B`), + // B -> A:

ef'gh

-

abcd

+ makeTwoRanges(7, 10, 13, 1, 4, 7, `B -> A`), + } + + splitOperations := []operationInterface{ + editOperationType{RangeMiddle, SplitUpdate, nil, 1, `split-1`}, + editOperationType{RangeMiddle, SplitUpdate, nil, 1, `split-2`}, + } + + editOperations := []operationInterface{ + editOperationType{RangeFront, EditUpdate, content, 0, `insertFront`}, + editOperationType{RangeMiddle, EditUpdate, content, 0, `insertMiddle`}, + editOperationType{RangeBack, EditUpdate, content, 0, `insertBack`}, + editOperationType{RangeAll, EditUpdate, content, 0, "replace"}, + editOperationType{RangeAll, EditUpdate, nil, 0, `delete`}, + editOperationType{RangeAll, MergeUpdate, nil, 0, `merge`}, + styleOperationType{RangeAll, StyleSet, "bold", "aa", `style`}, + styleOperationType{RangeAll, StyleRemove, "bold", "", `remove-style`}, + } + + RunTestTreeConcurrency("concurrently-split-edit-test", t, initialState, initialXML, ranges, splitOperations, editOperations) +} + func TestTreeConcurrencyStyleStyle(t *testing.T) { // 0 1 2 3 4 5 6 7 8 9 //

a

b

c

From dae401caed537900f80f2d34d12acb5cb8334054 Mon Sep 17 00:00:00 2001 From: Jeounghui Date: Wed, 31 Jan 2024 15:17:14 +0900 Subject: [PATCH 3/6] Fix style test to recognize remove style error --- test/integration/tree_concurrency_test.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/test/integration/tree_concurrency_test.go b/test/integration/tree_concurrency_test.go index 540344642..04735b279 100644 --- a/test/integration/tree_concurrency_test.go +++ b/test/integration/tree_concurrency_test.go @@ -330,13 +330,13 @@ func TestTreeConcurrencySplitEdit(t *testing.T) { Type: "root", Children: []json.TreeNode{ {Type: "p", Children: []json.TreeNode{ - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "abcd"}}}, - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "efgh"}}}, - }}, - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "ijkl"}}}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "abcd"}}, Attributes: map[string]string{"italic": "true"}}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "efgh"}}, Attributes: map[string]string{"italic": "true"}}, + }, Attributes: map[string]string{"italic": "true"}}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "ijkl"}}, Attributes: map[string]string{"italic": "true"}}, }, } - initialXML := `

abcd

efgh

ijkl

` + initialXML := `

abcd

efgh

ijkl

` content := &json.TreeNode{Type: "i", Children: []json.TreeNode{}} @@ -374,7 +374,7 @@ func TestTreeConcurrencySplitEdit(t *testing.T) { editOperationType{RangeAll, EditUpdate, nil, 0, `delete`}, editOperationType{RangeAll, MergeUpdate, nil, 0, `merge`}, styleOperationType{RangeAll, StyleSet, "bold", "aa", `style`}, - styleOperationType{RangeAll, StyleRemove, "bold", "", `remove-style`}, + styleOperationType{RangeAll, StyleRemove, "italic", "", `remove-style`}, } RunTestTreeConcurrency("concurrently-split-edit-test", t, initialState, initialXML, ranges, splitOperations, editOperations) @@ -430,12 +430,12 @@ func TestTreeConcurrencyEditStyle(t *testing.T) { initialState := json.TreeNode{ Type: "root", Children: []json.TreeNode{ - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "a"}}}, - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "b"}}}, - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "c"}}}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "a"}}, Attributes: map[string]string{"color": "red"}}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "b"}}, Attributes: map[string]string{"color": "red"}}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "c"}}, Attributes: map[string]string{"color": "red"}}, }, } - initialXML := `

a

b

c

` + initialXML := `

a

b

c

` content := &json.TreeNode{Type: "p", Attributes: map[string]string{"italic": "true"}, Children: []json.TreeNode{{Type: "text", Value: `d`}}} @@ -466,7 +466,7 @@ func TestTreeConcurrencyEditStyle(t *testing.T) { } styleOperations := []operationInterface{ - styleOperationType{RangeAll, StyleRemove, "bold", "", `remove-bold`}, + styleOperationType{RangeAll, StyleRemove, "color", "", `remove-bold`}, styleOperationType{RangeAll, StyleSet, "bold", "aa", `set-bold-aa`}, } From 0774d372d08709de2bfd80ab7f60f2a439334979 Mon Sep 17 00:00:00 2001 From: Jeounghui Date: Wed, 31 Jan 2024 15:57:37 +0900 Subject: [PATCH 4/6] Add split split test for splitLevel = 1 --- test/integration/tree_concurrency_test.go | 47 ++++++++++++++++++++++- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/test/integration/tree_concurrency_test.go b/test/integration/tree_concurrency_test.go index 04735b279..e43d75702 100644 --- a/test/integration/tree_concurrency_test.go +++ b/test/integration/tree_concurrency_test.go @@ -90,7 +90,7 @@ func getRange(ranges twoRangesType, selector rangeSelector, user int) rangeType } else if selector == RangeAll { return rangeType{from, to} } else if selector == RangeOneQuarter { - pos := (from + mid) / 2 + pos := (from + mid + 1) / 2 return rangeType{pos, pos} } else if selector == RangeThreeQuarter { pos := (mid + to) / 2 @@ -322,6 +322,50 @@ func TestTreeConcurrencyEditEdit(t *testing.T) { RunTestTreeConcurrency("concurrently-edit-edit-test", t, initialState, initialXML, ranges, editOperations1, editOperations2) } +// TODO(justiceHui): add split test for splitLevel > 1 +func TestTreeConcurrencySplitSplit(t *testing.T) { + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + //

a b c d

e f g h

i j k l

+ + initialState := json.TreeNode{ + Type: "root", + Children: []json.TreeNode{ + { + Type: "p", Children: []json.TreeNode{ + {Type: "p", Children: []json.TreeNode{ + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "abcd"}}}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "efgh"}}}, + }}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "ijkl"}}}, + }, + }, + }, + } + initialXML := `

abcd

efgh

ijkl

` + + ranges := []twoRangesType{ + // equal-single-element:

abcd

+ makeTwoRanges(2, 5, 8, 2, 5, 8, `equal-single`), + // equal-multiple-element:

abcd

efgh

+ makeTwoRanges(2, 8, 14, 2, 8, 14, `equal-multiple`), + // A contains B same level:

abcd

efgh

-

efgh

+ makeTwoRanges(2, 8, 14, 8, 11, 14, `A contains B same level`), + // A contains B multiple level:

abcd

efgh

ijkl

-

efgh

+ makeTwoRanges(1, 15, 21, 8, 11, 14, `A contains B multiple level`), + // side by side + makeTwoRanges(2, 5, 8, 8, 11, 14, `B is next to A`), + } + + splitOperations := []operationInterface{ + editOperationType{RangeFront, SplitUpdate, nil, 1, `split-front-1`}, + editOperationType{RangeOneQuarter, SplitUpdate, nil, 1, `split-one-quarter-1`}, + editOperationType{RangeThreeQuarter, SplitUpdate, nil, 1, `split-three-quarter-1`}, + editOperationType{RangeBack, SplitUpdate, nil, 1, `split-back-1`}, + } + + RunTestTreeConcurrency("concurrently-split-split-test", t, initialState, initialXML, ranges, splitOperations, splitOperations) +} + func TestTreeConcurrencySplitEdit(t *testing.T) { // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 //

a b c d

e f g h

i j k l

@@ -363,7 +407,6 @@ func TestTreeConcurrencySplitEdit(t *testing.T) { splitOperations := []operationInterface{ editOperationType{RangeMiddle, SplitUpdate, nil, 1, `split-1`}, - editOperationType{RangeMiddle, SplitUpdate, nil, 1, `split-2`}, } editOperations := []operationInterface{ From fb9c6c4bee00995688b4499d4af56c97c8fc681e Mon Sep 17 00:00:00 2001 From: Jeounghui Date: Wed, 31 Jan 2024 16:16:48 +0900 Subject: [PATCH 5/6] Add split edit test for splitLevel = 2 --- test/integration/tree_concurrency_test.go | 53 ++++++++++++----------- 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/test/integration/tree_concurrency_test.go b/test/integration/tree_concurrency_test.go index e43d75702..9a921a009 100644 --- a/test/integration/tree_concurrency_test.go +++ b/test/integration/tree_concurrency_test.go @@ -324,21 +324,19 @@ func TestTreeConcurrencyEditEdit(t *testing.T) { // TODO(justiceHui): add split test for splitLevel > 1 func TestTreeConcurrencySplitSplit(t *testing.T) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 //

a b c d

e f g h

i j k l

initialState := json.TreeNode{ Type: "root", Children: []json.TreeNode{ - { - Type: "p", Children: []json.TreeNode{ - {Type: "p", Children: []json.TreeNode{ - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "abcd"}}}, - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "efgh"}}}, - }}, - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "ijkl"}}}, - }, - }, + {Type: "p", Children: []json.TreeNode{ + {Type: "p", Children: []json.TreeNode{ + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "abcd"}}}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "efgh"}}}, + }}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "ijkl"}}}, + }}, }, } initialXML := `

abcd

efgh

ijkl

` @@ -367,46 +365,49 @@ func TestTreeConcurrencySplitSplit(t *testing.T) { } func TestTreeConcurrencySplitEdit(t *testing.T) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 - //

a b c d

e f g h

i j k l

+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + //

a b c d

e f g h

i j k l

initialState := json.TreeNode{ Type: "root", Children: []json.TreeNode{ {Type: "p", Children: []json.TreeNode{ - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "abcd"}}, Attributes: map[string]string{"italic": "true"}}, - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "efgh"}}, Attributes: map[string]string{"italic": "true"}}, - }, Attributes: map[string]string{"italic": "true"}}, - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "ijkl"}}, Attributes: map[string]string{"italic": "true"}}, + {Type: "p", Children: []json.TreeNode{ + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "abcd"}}, Attributes: map[string]string{"italic": "true"}}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "efgh"}}, Attributes: map[string]string{"italic": "true"}}, + }, Attributes: map[string]string{"italic": "true"}}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "ijkl"}}, Attributes: map[string]string{"italic": "true"}}, + }}, }, } - initialXML := `

abcd

efgh

ijkl

` + initialXML := `

abcd

efgh

ijkl

` content := &json.TreeNode{Type: "i", Children: []json.TreeNode{}} ranges := []twoRangesType{ // equal:

ab'cd

- makeTwoRanges(1, 4, 7, 2, 4, 6, `equal`), + makeTwoRanges(2, 5, 8, 2, 5, 8, `equal`), // A contains B:

ab'cd

- bc - makeTwoRanges(1, 4, 7, 3, 4, 5, `A contains B`), + makeTwoRanges(2, 5, 8, 4, 5, 6, `A contains B`), // B contains A:

ab'cd

-

abcd

efgh

- makeTwoRanges(1, 4, 7, 1, 7, 13, `B contains A`), + makeTwoRanges(2, 5, 8, 2, 8, 14, `B contains A`), // left node(text):

ab'cd

- ab - makeTwoRanges(1, 4, 7, 2, 3, 4, `left node(text)`), + makeTwoRanges(2, 5, 8, 3, 4, 5, `left node(text)`), // right node(text):

ab'cd

- cd - makeTwoRanges(1, 4, 7, 4, 5, 6, `right node(text)`), + makeTwoRanges(2, 5, 8, 5, 6, 7, `right node(text)`), // left node(element):

abcd

'

efgh

-

abcd

- makeTwoRanges(1, 7, 13, 1, 4, 7, `left node(element)`), + makeTwoRanges(2, 8, 14, 2, 5, 8, `left node(element)`), // right node(element):

abcd

'

efgh

-

efgh

- makeTwoRanges(1, 7, 13, 7, 10, 13, `right node(element)`), + makeTwoRanges(2, 8, 14, 8, 11, 14, `right node(element)`), // A -> B:

ab'cd

-

efgh

- makeTwoRanges(1, 4, 7, 7, 10, 13, `A -> B`), + makeTwoRanges(2, 5, 8, 8, 11, 14, `A -> B`), // B -> A:

ef'gh

-

abcd

- makeTwoRanges(7, 10, 13, 1, 4, 7, `B -> A`), + makeTwoRanges(8, 11, 14, 2, 5, 8, `B -> A`), } splitOperations := []operationInterface{ editOperationType{RangeMiddle, SplitUpdate, nil, 1, `split-1`}, + editOperationType{RangeMiddle, SplitUpdate, nil, 2, `split-2`}, } editOperations := []operationInterface{ From 13914477380e3fcf42519412b2dc043f463e62f0 Mon Sep 17 00:00:00 2001 From: Jeounghui Date: Wed, 31 Jan 2024 16:36:00 +0900 Subject: [PATCH 6/6] Add split split test for splitLevel = 2 --- test/integration/tree_concurrency_test.go | 29 +++++++++++++---------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/test/integration/tree_concurrency_test.go b/test/integration/tree_concurrency_test.go index 9a921a009..09c0a55b5 100644 --- a/test/integration/tree_concurrency_test.go +++ b/test/integration/tree_concurrency_test.go @@ -322,36 +322,37 @@ func TestTreeConcurrencyEditEdit(t *testing.T) { RunTestTreeConcurrency("concurrently-edit-edit-test", t, initialState, initialXML, ranges, editOperations1, editOperations2) } -// TODO(justiceHui): add split test for splitLevel > 1 func TestTreeConcurrencySplitSplit(t *testing.T) { - // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 - //

a b c d

e f g h

i j k l

+ // 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 + //

a b c d

e f g h

i j k l

initialState := json.TreeNode{ Type: "root", Children: []json.TreeNode{ {Type: "p", Children: []json.TreeNode{ {Type: "p", Children: []json.TreeNode{ - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "abcd"}}}, - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "efgh"}}}, + {Type: "p", Children: []json.TreeNode{ + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "abcd"}}}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "efgh"}}}, + }}, + {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "ijkl"}}}, }}, - {Type: "p", Children: []json.TreeNode{{Type: "text", Value: "ijkl"}}}, }}, }, } - initialXML := `

abcd

efgh

ijkl

` + initialXML := `

abcd

efgh

ijkl

` ranges := []twoRangesType{ // equal-single-element:

abcd

- makeTwoRanges(2, 5, 8, 2, 5, 8, `equal-single`), + makeTwoRanges(3, 6, 9, 3, 6, 9, `equal-single`), // equal-multiple-element:

abcd

efgh

- makeTwoRanges(2, 8, 14, 2, 8, 14, `equal-multiple`), + makeTwoRanges(3, 9, 15, 3, 9, 15, `equal-multiple`), // A contains B same level:

abcd

efgh

-

efgh

- makeTwoRanges(2, 8, 14, 8, 11, 14, `A contains B same level`), + makeTwoRanges(3, 9, 15, 9, 12, 15, `A contains B same level`), // A contains B multiple level:

abcd

efgh

ijkl

-

efgh

- makeTwoRanges(1, 15, 21, 8, 11, 14, `A contains B multiple level`), + makeTwoRanges(2, 16, 22, 9, 12, 15, `A contains B multiple level`), // side by side - makeTwoRanges(2, 5, 8, 8, 11, 14, `B is next to A`), + makeTwoRanges(3, 6, 9, 9, 12, 15, `B is next to A`), } splitOperations := []operationInterface{ @@ -359,6 +360,10 @@ func TestTreeConcurrencySplitSplit(t *testing.T) { editOperationType{RangeOneQuarter, SplitUpdate, nil, 1, `split-one-quarter-1`}, editOperationType{RangeThreeQuarter, SplitUpdate, nil, 1, `split-three-quarter-1`}, editOperationType{RangeBack, SplitUpdate, nil, 1, `split-back-1`}, + editOperationType{RangeFront, SplitUpdate, nil, 2, `split-front-2`}, + editOperationType{RangeOneQuarter, SplitUpdate, nil, 2, `split-one-quarter-2`}, + editOperationType{RangeThreeQuarter, SplitUpdate, nil, 2, `split-three-quarter-2`}, + editOperationType{RangeBack, SplitUpdate, nil, 2, `split-back-2`}, } RunTestTreeConcurrency("concurrently-split-split-test", t, initialState, initialXML, ranges, splitOperations, splitOperations)