1
0
Fork 0
golang-forgejo-f3-gof3/tree/tests/generic/memory_test.go
Daniel Baumann 03bfe4079e
Adding upstream version 3.10.8.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-05-18 09:37:23 +02:00

193 lines
5.5 KiB
Go

// Copyright Earl Warren <contact@earl-warren.org>
// Copyright Loïc Dachary <loic@dachary.org>
// SPDX-License-Identifier: MIT
package generic
import (
"context"
"sort"
"testing"
"code.forgejo.org/f3/gof3/v3/id"
"code.forgejo.org/f3/gof3/v3/kind"
"code.forgejo.org/f3/gof3/v3/path"
"code.forgejo.org/f3/gof3/v3/tree/generic"
"code.forgejo.org/f3/gof3/v3/tree/memory"
"github.com/stretchr/testify/assert"
)
func NewMemoryTree(ctx context.Context, name string) generic.TreeInterface {
return generic.GetFactory("memory")(ctx, memory.NewOptions(memory.NewIDAllocatorGenerator(name)))
}
func TestMemoryTreeIDAllocator(t *testing.T) {
ctx := context.Background()
name := "T"
id := "THEID"
for _, testCase := range []struct {
idAllocator memory.IDAllocatorInterface
setID bool
expectedID string
}{
{
idAllocator: memory.NewIDAllocatorGenerator(name),
setID: false,
expectedID: name + "-A",
},
{
idAllocator: memory.NewIDAllocatorNull(),
setID: true,
expectedID: id,
},
} {
t.Run(testCase.expectedID, func(t *testing.T) {
tree := generic.GetFactory("memory")(ctx, memory.NewOptions(testCase.idAllocator))
node := tree.GetRoot().CreateChild(ctx)
f := memory.NewFormat("")
if testCase.setID {
f.SetID(id)
}
node.FromFormat(f)
node.Upsert(ctx)
assert.EqualValues(t, testCase.expectedID, node.GetID())
})
}
}
func testTreeBuild(t *testing.T, tree generic.TreeInterface, maxDepth int) {
ctx := context.Background()
insert := func(tree generic.TreeInterface, parent generic.NodeInterface) generic.NodeInterface {
node := parent.CreateChild(ctx)
node.Upsert(ctx)
memory.SetContent(node, "content "+node.GetID().String())
node.Upsert(ctx)
return node
}
var populate func(depth int, tree generic.TreeInterface, parent generic.NodeInterface)
populate = func(depth int, tree generic.TreeInterface, parent generic.NodeInterface) {
if depth >= maxDepth {
return
}
depth++
for i := 1; i <= 3; i++ {
node := insert(tree, parent)
populate(depth, tree, node)
}
}
populate(0, tree, insert(tree, tree.GetRoot()))
}
func TestMemoryTreeBuild(t *testing.T) {
ctx := context.Background()
verify := func(tree generic.TreeInterface, expected []string) {
collected := make([]string, 0, 10)
collect := func(ctx context.Context, p path.Path, node generic.NodeInterface) {
if node.GetKind() == kind.KindRoot {
return
}
p = p.Append(node)
collected = append(collected, p.String()+":"+memory.GetContent(node))
}
tree.WalkAndGet(ctx, generic.NewWalkOptions(collect))
sort.Strings(expected)
sort.Strings(collected)
assert.EqualValues(t, expected, collected)
}
for _, testCase := range []struct {
name string
build func(tree generic.TreeInterface)
operations func(tree generic.TreeInterface)
expected []string
}{
{
name: "full tree",
build: func(tree generic.TreeInterface) { testTreeBuild(t, tree, 2) },
operations: func(tree generic.TreeInterface) {},
expected: []string{"/T-A/T-B/T-C:content T-C", "/T-A/T-B/T-D:content T-D", "/T-A/T-B/T-E:content T-E", "/T-A/T-B:content T-B", "/T-A/T-F/T-G:content T-G", "/T-A/T-F/T-H:content T-H", "/T-A/T-F/T-I:content T-I", "/T-A/T-F:content T-F", "/T-A/T-J/T-K:content T-K", "/T-A/T-J/T-L:content T-L", "/T-A/T-J/T-M:content T-M", "/T-A/T-J:content T-J", "/T-A:content T-A"},
},
{
name: "scenario 1",
build: func(tree generic.TreeInterface) { testTreeBuild(t, tree, 2) },
operations: func(tree generic.TreeInterface) {
root := tree.GetRoot()
id0 := id.NewNodeID("T-A")
root.List(ctx)
zero := root.GetChild(id0)
assert.False(t, generic.NilNode == zero)
assert.True(t, zero == zero.Get(ctx))
id1 := id.NewNodeID("T-B")
zero.List(ctx)
one := zero.GetChild(id1)
assert.False(t, generic.NilNode == one)
one.Get(ctx)
memory.SetContent(one, "other one")
one.Upsert(ctx)
id2 := id.NewNodeID("T-F")
two := zero.GetChild(id2)
two.Delete(ctx)
two.Delete(ctx)
assert.True(t, generic.NilNode == zero.GetChild(id2))
},
expected: []string{"/T-A/T-B/T-C:content T-C", "/T-A/T-B/T-D:content T-D", "/T-A/T-B/T-E:content T-E", "/T-A/T-B:other one", "/T-A/T-J/T-K:content T-K", "/T-A/T-J/T-L:content T-L", "/T-A/T-J/T-M:content T-M", "/T-A/T-J:content T-J", "/T-A:content T-A"},
},
{
name: "scenario 2",
build: func(tree generic.TreeInterface) { testTreeBuild(t, tree, 0) },
operations: func(tree generic.TreeInterface) {
root := tree.GetRoot()
id0 := id.NewNodeID("T-A")
root.List(ctx)
zero := root.GetChild(id0)
assert.False(t, generic.NilNode == zero)
zero.Get(ctx)
one := zero.CreateChild(ctx)
one.Upsert(ctx)
memory.SetContent(one, "ONE")
one.Upsert(ctx)
two := one.CreateChild(ctx)
two.Upsert(ctx)
memory.SetContent(two, "SOMETHING")
two.Upsert(ctx)
memory.SetContent(two, "ONE/TWO")
two.Upsert(ctx)
one.DeleteChild(two.GetID())
two.Get(ctx)
three := two.CreateChild(ctx)
three.Upsert(ctx)
memory.SetContent(three, "ONE/THREE")
three.Upsert(ctx)
three.Delete(ctx)
},
expected: []string{"/T-A/T-B/T-C:ONE/TWO", "/T-A/T-B:ONE", "/T-A:content T-A"},
},
} {
t.Run(testCase.name, func(t *testing.T) {
tree := NewMemoryTree(ctx, "T")
tree.Trace("========== BUILD")
testCase.build(tree)
tree.Trace("========== OPERATIONS")
testCase.operations(tree)
verify(tree, testCase.expected)
tree.Trace("========== VERIFY RELOAD")
tree.Clear(ctx)
verify(tree, testCase.expected)
})
}
}