Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Move ToXML from RHT to TreeNode #863

Merged
merged 2 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions pkg/document/crdt/rht.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,28 +198,3 @@ func (rht *RHT) Marshal() string {

return sb.String()
}

// ToXML returns the XML representation of this hashtable.
func (rht *RHT) ToXML() string {
members := rht.Elements()

size := len(members)

// Extract and sort the keys
keys := make([]string, 0, size)
for k := range members {
keys = append(keys, k)
}
sort.Strings(keys)

sb := strings.Builder{}
for idx, k := range keys {
if idx > 0 {
sb.WriteString(" ")
}
value := members[k]
sb.WriteString(fmt.Sprintf(`%s="%s"`, k, EscapeString(value)))
}

return sb.String()
}
43 changes: 0 additions & 43 deletions pkg/document/crdt/rht_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,48 +51,6 @@ func TestRHT_Marshal(t *testing.T) {
}
}

func TestRHT_ToXML(t *testing.T) {
tests := []struct {
desc string
insertKey string
insertVal string
expectStr string
}{
{
desc: `1. empty hash table`,
insertKey: ``,
insertVal: ``,
expectStr: ``,
},
{
desc: `2. only one element`,
insertKey: "hello\\\\\\t",
insertVal: "world\"\f\b",
expectStr: `hello\\\t="world\"\f\b"`,
},
{
desc: `3. non-empty hash table`,
insertKey: "hi",
insertVal: `test\r`,
expectStr: `hello\\\t="world\"\f\b" hi="test\\r"`,
},
}

root := helper.TestRoot()
ctx := helper.TextChangeContext(root)

rht := crdt.NewRHT()

for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
if len(tt.insertKey) > 0 {
rht.Set(tt.insertKey, tt.insertVal, ctx.IssueTimeTicket())
}
assert.Equal(t, tt.expectStr, rht.ToXML())
})
}
}

func TestRHT_Set(t *testing.T) {
key1, val1 := `key1`, `value1`
key2, val2 := `key2`, `value2`
Expand Down Expand Up @@ -236,7 +194,6 @@ func TestRHT_Remove(t *testing.T) {
removedElement := rht.Remove(key, ctx.IssueTimeTicket())
assert.Equal(t, tt.deleteVal[i], removedElement)
}
assert.Equal(t, tt.expectXML, rht.ToXML())
assert.Equal(t, tt.expectJSON, rht.Marshal())
assert.Equal(t, tt.expectSize, rht.Len())
assert.Equal(t, tt.expectSize, len(rht.Nodes()))
Expand Down
37 changes: 31 additions & 6 deletions pkg/document/crdt/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"errors"
"fmt"
"slices"
"sort"
"strconv"
"strings"
"unicode/utf16"
Expand Down Expand Up @@ -184,8 +185,27 @@ func (n *TreeNode) Attributes() string {
if n.Attrs == nil || n.Attrs.Len() == 0 {
return ""
}
members := n.Attrs.Elements()

return " " + n.Attrs.ToXML()
size := len(members)

// Extract and sort the keys
keys := make([]string, 0, size)
for k := range members {
keys = append(keys, k)
}
sort.Strings(keys)

sb := strings.Builder{}
for idx, k := range keys {
if idx > 0 {
sb.WriteString(" ")
}
value := members[k]
sb.WriteString(fmt.Sprintf(`%s="%s"`, k, EscapeString(value)))
}

return " " + sb.String()
}

// Append appends the given node to the end of the children.
Expand Down Expand Up @@ -395,6 +415,15 @@ func (n *TreeNode) InsertAfter(content *TreeNode, children *TreeNode) error {
return n.Index.InsertAfter(content.Index, children.Index)
}

// SetAttr sets the attribute of the node.
func (n *TreeNode) SetAttr(k string, v string, ticket *time.Ticket) {
if n.Attrs == nil {
n.Attrs = NewRHT()
}

n.Attrs.Set(k, v, ticket)
}

// Tree represents the tree of CRDT. It has doubly linked list structure and
// index tree structure.
type Tree struct {
Expand Down Expand Up @@ -901,12 +930,8 @@ func (t *Tree) Style(
createdAtMapByActor[actorIDHex] = createdAt
}

if node.Attrs == nil {
node.Attrs = NewRHT()
}

for key, value := range attributes {
node.Attrs.Set(key, value, editedAt)
node.SetAttr(key, value, editedAt)
}
}
})
Expand Down
17 changes: 17 additions & 0 deletions pkg/document/crdt/tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,23 @@ func TestTreeNode(t *testing.T) {
assert.NoError(t, err)
helper.AssertEqualTreeNode(t, tree.Root(), clone)
})

t.Run("ToXML test", func(t *testing.T) {
node := crdt.NewTreeNode(dummyTreeNodeID, "text", nil, "hello")
assert.Equal(t, "hello", crdt.ToXML(node))

para := crdt.NewTreeNode(dummyTreeNodeID, "p", nil)
assert.NoError(t, para.Append(node))
assert.Equal(t, "<p>hello</p>", crdt.ToXML(para))

elemWithAttrs := crdt.NewTreeNode(dummyTreeNodeID, "p", nil)
assert.NoError(t, elemWithAttrs.Append(node))
elemWithAttrs.SetAttr("e", "\"true\"", time.MaxTicket)
assert.Equal(t, `<p e="\"true\"">hello</p>`, crdt.ToXML(elemWithAttrs))

elemWithAttrs.SetAttr("b", "t", time.MaxTicket)
assert.Equal(t, `<p b="t" e="\"true\"">hello</p>`, crdt.ToXML(elemWithAttrs))
})
}

func TestTreeEdit(t *testing.T) {
Expand Down
Loading