Adding upstream version 3.10.8.
Signed-off-by: Daniel Baumann <daniel@debian.org>
This commit is contained in:
parent
37e9b6d587
commit
03bfe4079e
356 changed files with 28857 additions and 0 deletions
626
tree/tests/generic/unify_test.go
Normal file
626
tree/tests/generic/unify_test.go
Normal file
|
@ -0,0 +1,626 @@
|
|||
// Copyright Earl Warren <contact@earl-warren.org>
|
||||
// Copyright Loïc Dachary <loic@dachary.org>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package generic
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"testing"
|
||||
|
||||
"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 TestUnifyPathSimpleRemap(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, testCase := range []struct {
|
||||
path string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
path: "",
|
||||
expected: []string{},
|
||||
},
|
||||
{
|
||||
path: "/O-A",
|
||||
expected: []string{"/O-A:O-A=content O-A => /D-A:D-A=content O-A"},
|
||||
},
|
||||
{
|
||||
path: "/O-A/O-B",
|
||||
expected: []string{"/O-A:O-A=content O-A => /D-A:D-A=content O-A", "/O-A/O-B:O-B=content O-B => /D-A/D-B:D-B=content O-B"},
|
||||
},
|
||||
{
|
||||
path: "/O-A/O-B/O-C",
|
||||
expected: []string{"/O-A:O-A=content O-A => /D-A:D-A=content O-A", "/O-A/O-B:O-B=content O-B => /D-A/D-B:D-B=content O-B", "/O-A/O-B/O-C:O-C=content O-C => /D-A/D-B/D-C:D-C=content O-C"},
|
||||
},
|
||||
} {
|
||||
t.Run(" "+testCase.path, func(t *testing.T) {
|
||||
originTree := NewMemoryTree(ctx, "O")
|
||||
testTreeBuild(t, originTree, 2)
|
||||
destinationTree := NewMemoryTree(ctx, "D")
|
||||
|
||||
collected := make([]string, 0, 10)
|
||||
p := generic.NewPathFromString(testCase.path)
|
||||
upsert := func(ctx context.Context, origin generic.NodeInterface, originPath path.Path, destination generic.NodeInterface, destinationPath path.Path) {
|
||||
fmt.Printf("origin %v destination %v\n", origin, destination)
|
||||
originPath = originPath.Append(origin)
|
||||
destinationPath = destinationPath.Append(destination)
|
||||
collected = append(collected, originPath.String()+":"+origin.String()+" => "+destinationPath.String()+":"+destination.String())
|
||||
}
|
||||
generic.TreeUnifyPath(ctx, originTree, p, destinationTree, generic.NewUnifyOptions(destinationTree).SetUpsert(upsert))
|
||||
assert.EqualValues(t, testCase.expected, collected)
|
||||
collected = make([]string, 0, 10)
|
||||
generic.TreeUnifyPath(ctx, originTree, p, destinationTree, generic.NewUnifyOptions(destinationTree).SetUpsert(upsert))
|
||||
assert.EqualValues(t, testCase.expected, collected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnifyPathSimpleNoRemap(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, testCase := range []struct {
|
||||
noremap bool
|
||||
path string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
noremap: false,
|
||||
path: "/O-A/O-B",
|
||||
expected: []string{"/O-A:O-A=content O-A => /D-A:D-A=content O-A", "/O-A/O-B:O-B=content O-B => /D-A/D-B:D-B=content O-B"},
|
||||
},
|
||||
{
|
||||
noremap: true,
|
||||
path: "/O-A/O-B",
|
||||
expected: []string{"/O-A:O-A=content O-A => /O-A:O-A=content O-A", "/O-A/O-B:O-B=content O-B => /O-A/O-B:O-B=content O-B"},
|
||||
},
|
||||
} {
|
||||
t.Run(fmt.Sprintf("noremap=%v,path=%s", testCase.noremap, testCase.path), func(t *testing.T) {
|
||||
originName := "O"
|
||||
originTree := NewMemoryTree(ctx, originName)
|
||||
testTreeBuild(t, originTree, 2)
|
||||
var destinationName string
|
||||
if testCase.noremap {
|
||||
destinationName = originName
|
||||
} else {
|
||||
destinationName = "D"
|
||||
}
|
||||
destinationTree := NewMemoryTree(ctx, destinationName)
|
||||
|
||||
collected := make([]string, 0, 10)
|
||||
p := generic.NewPathFromString(testCase.path)
|
||||
upsert := func(ctx context.Context, origin generic.NodeInterface, originPath path.Path, destination generic.NodeInterface, destinationPath path.Path) {
|
||||
fmt.Printf("origin %v destination %v\n", origin, destination)
|
||||
originPath = originPath.Append(origin)
|
||||
destinationPath = destinationPath.Append(destination)
|
||||
collected = append(collected, originPath.String()+":"+origin.String()+" => "+destinationPath.String()+":"+destination.String())
|
||||
}
|
||||
generic.TreeUnifyPath(ctx, originTree, p, destinationTree, generic.NewUnifyOptions(destinationTree).SetUpsert(upsert).SetNoRemap(testCase.noremap))
|
||||
assert.EqualValues(t, testCase.expected, collected)
|
||||
collected = make([]string, 0, 10)
|
||||
generic.TreeUnifyPath(ctx, originTree, p, destinationTree, generic.NewUnifyOptions(destinationTree).SetUpsert(upsert).SetNoRemap(testCase.noremap))
|
||||
assert.EqualValues(t, testCase.expected, collected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnifyPathRelative(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, testCase := range []struct {
|
||||
start string
|
||||
destination string
|
||||
expected []string
|
||||
}{
|
||||
{
|
||||
start: "/O-A/O-B",
|
||||
destination: "O-C",
|
||||
expected: []string{"cd: /O-A/O-B:O-B=content O-B => /D-A/D-B:D-B=content O-B", "unify: /O-A/O-B:O-B=content O-B => /D-A/D-B:D-B=content O-B", "unify: /O-A/O-B/O-C:O-C=content O-C => /D-A/D-B/D-C:D-C=content O-C"},
|
||||
},
|
||||
{
|
||||
start: "/O-A/O-B",
|
||||
destination: ".",
|
||||
expected: []string{"cd: /O-A/O-B:O-B=content O-B => /D-A/D-B:D-B=content O-B", "unify: /O-A/O-B:O-B=content O-B => /D-A/D-B:D-B=content O-B"},
|
||||
},
|
||||
{
|
||||
start: "/O-A/O-B",
|
||||
destination: "../O-F/O-G",
|
||||
expected: []string{"cd: /O-A/O-B:O-B=content O-B => /D-A/D-B:D-B=content O-B", "unify: /O-A:O-A=content O-A => /D-A:D-A=content O-A", "unify: /O-A/O-F:O-F=content O-F => /D-A/D-C:D-C=content O-F", "unify: /O-A/O-F/O-G:O-G=content O-G => /D-A/D-C/D-D:D-D=content O-G"},
|
||||
},
|
||||
{
|
||||
start: "/O-A/O-B/O-C",
|
||||
destination: "../O-E",
|
||||
expected: []string{"cd: /O-A/O-B/O-C:O-C=content O-C => /D-A/D-B/D-C:D-C=content O-C", "unify: /O-A/O-B:O-B=content O-B => /D-A/D-B:D-B=content O-B", "unify: /O-A/O-B/O-E:O-E=content O-E => /D-A/D-B/D-D:D-D=content O-E"},
|
||||
},
|
||||
} {
|
||||
t.Run(" "+testCase.start+" => "+testCase.destination, func(t *testing.T) {
|
||||
originTree := NewMemoryTree(ctx, "O")
|
||||
testTreeBuild(t, originTree, 2)
|
||||
destinationTree := NewMemoryTree(ctx, "D")
|
||||
|
||||
var collected []string
|
||||
start := generic.NewPathFromString(testCase.start)
|
||||
collect := func(prefix string, origin, destination generic.NodeInterface) {
|
||||
originPath := origin.GetCurrentPath().String()
|
||||
destinationPath := destination.GetCurrentPath().String()
|
||||
collected = append(collected, prefix+originPath+":"+origin.GetSelf().String()+" => "+destinationPath+":"+destination.GetSelf().String())
|
||||
}
|
||||
//
|
||||
// Unify testCase.start
|
||||
//
|
||||
upsert := func(ctx context.Context, origin generic.NodeInterface, originParent path.Path, destination generic.NodeInterface, destinationParent path.Path) {
|
||||
collect("unify: ", origin, destination)
|
||||
}
|
||||
generic.TreeUnifyPath(ctx, originTree, start, destinationTree, generic.NewUnifyOptions(destinationTree).SetUpsert(upsert))
|
||||
//
|
||||
// Beginning from testCase.start, unify testCase.destination
|
||||
//
|
||||
cd := func(ctx context.Context, origin, destination generic.NodeInterface) {
|
||||
collect("cd: ", origin, destination)
|
||||
path := generic.NewPathFromString(testCase.destination)
|
||||
originParent := origin.GetParent().GetCurrentPath()
|
||||
destinationParent := destination.GetParent().GetCurrentPath()
|
||||
generic.NodeUnifyPath(ctx, origin.GetSelf(), originParent, path, destinationParent, generic.NewUnifyOptions(destinationTree).SetUpsert(upsert))
|
||||
}
|
||||
//
|
||||
//
|
||||
//
|
||||
collected = make([]string, 0, 10)
|
||||
generic.TreeParallelApply(ctx, originTree, start, destinationTree, generic.NewParallelApplyOptions(cd))
|
||||
assert.EqualValues(t, testCase.expected, collected)
|
||||
//
|
||||
// Do it twice to verify it is idempotent
|
||||
//
|
||||
collected = make([]string, 0, 10)
|
||||
generic.TreeParallelApply(ctx, originTree, start, destinationTree, generic.NewParallelApplyOptions(cd))
|
||||
assert.EqualValues(t, testCase.expected, collected)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnifyPathScenario(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
//
|
||||
// build and populate a tree
|
||||
//
|
||||
originTree := NewMemoryTree(ctx, "O")
|
||||
testTreeBuild(t, originTree, 2)
|
||||
|
||||
//
|
||||
// build an empty tree
|
||||
//
|
||||
destinationTree := NewMemoryTree(ctx, "D")
|
||||
|
||||
//
|
||||
// accumulate the call results for verification
|
||||
//
|
||||
var collected []string
|
||||
upsert := func(ctx context.Context, origin generic.NodeInterface, originPath path.Path, destination generic.NodeInterface, destinationPath path.Path) {
|
||||
originPath = originPath.Append(origin)
|
||||
destinationPath = destinationPath.Append(destination)
|
||||
what := originPath.String() + ":" + origin.String() + " => " + destinationPath.String() + ":" + destination.String()
|
||||
fmt.Printf("unify: %T => %T | %s\n", origin, destination, what)
|
||||
collected = append(collected, what)
|
||||
}
|
||||
|
||||
assertTree := func(tree generic.TreeInterface, expected []string) {
|
||||
collected := make([]string, 0, 10)
|
||||
tree.Walk(ctx, generic.NewWalkOptions(func(ctx context.Context, path path.Path, node generic.NodeInterface) {
|
||||
if node.GetKind() == kind.KindRoot {
|
||||
return
|
||||
}
|
||||
path = path.Append(node)
|
||||
collected = append(collected, path.String()+":"+node.String())
|
||||
}))
|
||||
sort.Strings(collected)
|
||||
assert.EqualValues(t, expected, collected)
|
||||
}
|
||||
|
||||
//
|
||||
// unify the originTree with the destinationTree on the specified path
|
||||
//
|
||||
fullPath := generic.NewPathFromString("/O-A/O-B/O-C")
|
||||
collected = make([]string, 0, 10)
|
||||
generic.TreeUnifyPath(ctx, originTree, fullPath, destinationTree, generic.NewUnifyOptions(destinationTree).SetUpsert(upsert))
|
||||
sort.Strings(collected)
|
||||
assert.EqualValues(t, []string{"/O-A/O-B/O-C:O-C=content O-C => /D-A/D-B/D-C:D-C=content O-C", "/O-A/O-B:O-B=content O-B => /D-A/D-B:D-B=content O-B", "/O-A:O-A=content O-A => /D-A:D-A=content O-A"}, collected)
|
||||
assertTree(destinationTree, []string{"/D-A/D-B/D-C:D-C=content O-C", "/D-A/D-B:D-B=content O-B", "/D-A:D-A=content O-A"})
|
||||
|
||||
//
|
||||
// Add a node unrelated to the unification path
|
||||
//
|
||||
var unrelatedOriginPath path.Path
|
||||
{
|
||||
originTree.Apply(ctx, generic.NewPathFromString("/O-A/O-B"), generic.NewApplyOptions(func(ctx context.Context, parent, path path.Path, node generic.NodeInterface) {
|
||||
assert.EqualValues(t, parent.Length()+1, node.GetCurrentPath().Length())
|
||||
unrelated := node.CreateChild(ctx)
|
||||
unrelated.Upsert(ctx)
|
||||
memory.SetContent(unrelated, "content "+unrelated.GetID().String())
|
||||
unrelated.Upsert(ctx)
|
||||
unrelatedOriginPath = unrelated.GetCurrentPath()
|
||||
assert.EqualValues(t, "/O-A/O-B/O-N", (unrelatedOriginPath.PathString().Join()))
|
||||
}))
|
||||
}
|
||||
|
||||
//
|
||||
// Replace the content of the last node
|
||||
//
|
||||
lastContent := "LAST"
|
||||
{
|
||||
lastPath := generic.NewPathFromString("/O-A/O-B/O-C")
|
||||
originTree.Apply(ctx, lastPath, generic.NewApplyOptions(func(ctx context.Context, parent, path path.Path, node generic.NodeInterface) {
|
||||
memory.SetContent(node, lastContent)
|
||||
}))
|
||||
collected = make([]string, 0, 10)
|
||||
generic.TreeUnifyPath(ctx, originTree, lastPath, destinationTree, generic.NewUnifyOptions(destinationTree).SetUpsert(upsert))
|
||||
sort.Strings(collected)
|
||||
assert.EqualValues(t, []string{"/O-A/O-B/O-C:O-C=LAST => /D-A/D-B/D-C:D-C=LAST", "/O-A/O-B:O-B=content O-B => /D-A/D-B:D-B=content O-B", "/O-A:O-A=content O-A => /D-A:D-A=content O-A"}, collected)
|
||||
assertTree(destinationTree, []string{"/D-A/D-B/D-C:D-C=LAST", "/D-A/D-B:D-B=content O-B", "/D-A:D-A=content O-A"})
|
||||
}
|
||||
//
|
||||
// Replace the content of the first node
|
||||
//
|
||||
firstContent := "FIRST"
|
||||
{
|
||||
firstPath := generic.NewPathFromString("/O-A")
|
||||
originTree.Apply(ctx, firstPath, generic.NewApplyOptions(func(ctx context.Context, parent, path path.Path, node generic.NodeInterface) {
|
||||
memory.SetContent(node, firstContent)
|
||||
}))
|
||||
collected = make([]string, 0, 10)
|
||||
generic.TreeUnifyPath(ctx, originTree, firstPath, destinationTree, generic.NewUnifyOptions(destinationTree).SetUpsert(upsert))
|
||||
sort.Strings(collected)
|
||||
assert.EqualValues(t, []string{"/O-A:O-A=" + firstContent + " => /D-A:D-A=" + firstContent}, collected)
|
||||
assertTree(destinationTree, []string{"/D-A/D-B/D-C:D-C=LAST", "/D-A/D-B:D-B=content O-B", "/D-A:D-A=FIRST"})
|
||||
}
|
||||
//
|
||||
// Replace the content of the second node
|
||||
//
|
||||
secondContent := "SECOND"
|
||||
{
|
||||
secondPath := generic.NewPathFromString("/O-A/O-B")
|
||||
originTree.Apply(ctx, secondPath, generic.NewApplyOptions(func(ctx context.Context, parent, path path.Path, node generic.NodeInterface) {
|
||||
memory.SetContent(node, secondContent)
|
||||
}))
|
||||
collected = make([]string, 0, 10)
|
||||
generic.TreeUnifyPath(ctx, originTree, secondPath, destinationTree, generic.NewUnifyOptions(destinationTree).SetUpsert(upsert))
|
||||
assert.EqualValues(t, []string{"/O-A:O-A=" + firstContent + " => /D-A:D-A=" + firstContent, "/O-A/O-B:O-B=" + secondContent + " => /D-A/D-B:D-B=" + secondContent}, collected)
|
||||
sort.Strings(collected)
|
||||
assertTree(destinationTree, []string{"/D-A/D-B/D-C:D-C=LAST", "/D-A/D-B:D-B=SECOND", "/D-A:D-A=FIRST"})
|
||||
}
|
||||
//
|
||||
// verify the node unrelated to the unification is still there
|
||||
//
|
||||
{
|
||||
var found bool
|
||||
originTree.Apply(ctx, unrelatedOriginPath, generic.NewApplyOptions(func(ctx context.Context, parent, path path.Path, node generic.NodeInterface) {
|
||||
found = true
|
||||
}))
|
||||
assert.True(t, found)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnifyMirror(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
//
|
||||
// build and populate a tree
|
||||
//
|
||||
originTree := NewMemoryTree(ctx, "O")
|
||||
log := originTree.GetLogger()
|
||||
testTreeBuild(t, originTree, 2)
|
||||
|
||||
//
|
||||
// build an empty tree
|
||||
//
|
||||
destinationTree := NewMemoryTree(ctx, "D")
|
||||
|
||||
upsert := func(ctx context.Context, origin generic.NodeInterface, originPath path.Path, destination generic.NodeInterface, destinationPath path.Path) {
|
||||
assert.NotNil(t, origin.GetDriver().(*memory.Driver))
|
||||
assert.NotNil(t, destination.GetDriver().(*memory.Driver))
|
||||
originPath = originPath.Append(origin)
|
||||
destinationPath = destinationPath.Append(destination)
|
||||
what := fmt.Sprintf("%s:%s => %s:%s", originPath, origin.GetSelf(), destinationPath, destination.GetSelf())
|
||||
log.Trace("mirror upsert: %T => %T | %s", origin, destination, what)
|
||||
}
|
||||
delete := func(ctx context.Context, destination generic.NodeInterface, destinationPath path.Path) {
|
||||
assert.NotNil(t, destination.GetDriver().(*memory.Driver))
|
||||
destinationPath = destinationPath.Append(destination)
|
||||
log.Trace("mirror delete: %T | %s:%s", destination, destinationPath, destination)
|
||||
}
|
||||
|
||||
var sameTree func(origin, destination generic.NodeInterface) bool
|
||||
sameTree = func(origin, destination generic.NodeInterface) bool {
|
||||
what := origin.GetCurrentPath().String() + ":" + origin.GetSelf().String() + " => " + destination.GetCurrentPath().String() + ":" + destination.GetSelf().String()
|
||||
log.Trace("sameTree: %T => %T | %s", origin.GetSelf(), destination.GetSelf(), what)
|
||||
if origin.GetMappedID() != destination.GetID() {
|
||||
log.Trace("sameTree: different: %s != %s", origin.GetMappedID(), destination.GetID())
|
||||
return false
|
||||
}
|
||||
originChildren := origin.GetChildren()
|
||||
destinationChildren := destination.GetChildren()
|
||||
if len(originChildren) != len(destinationChildren) {
|
||||
log.Trace("sameTree: different: length %v != %v", len(originChildren), len(destinationChildren))
|
||||
return false
|
||||
}
|
||||
|
||||
for _, originChild := range originChildren {
|
||||
destinationChild := destination.GetChild(originChild.GetMappedID())
|
||||
if destinationChild == generic.NilNode {
|
||||
log.Trace("sameTree: different: %s not found", originChild.GetMappedID())
|
||||
return false
|
||||
}
|
||||
if !sameTree(originChild, destinationChild) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
//
|
||||
// unify the originTree with the destinationTree
|
||||
//
|
||||
assert.False(t, sameTree(originTree.GetRoot(), destinationTree.GetRoot()))
|
||||
generic.TreeUnify(ctx, originTree, destinationTree, generic.NewUnifyOptions(destinationTree).SetUpsert(upsert).SetDelete(delete))
|
||||
assert.True(t, sameTree(originTree.GetRoot(), destinationTree.GetRoot()))
|
||||
generic.TreeUnify(ctx, originTree, destinationTree, generic.NewUnifyOptions(destinationTree).SetUpsert(upsert).SetDelete(delete))
|
||||
assert.True(t, sameTree(originTree.GetRoot(), destinationTree.GetRoot()))
|
||||
|
||||
{
|
||||
addNode := func(tree generic.TreeInterface, pathString string) {
|
||||
tree.Apply(ctx, generic.NewPathFromString(pathString), generic.NewApplyOptions(func(ctx context.Context, parent, path path.Path, node generic.NodeInterface) {
|
||||
new := node.CreateChild(ctx)
|
||||
new.Upsert(ctx)
|
||||
memory.SetContent(new, "content "+new.GetID().String())
|
||||
new.Upsert(ctx)
|
||||
log.Trace("add: %s", parent.ReadableString())
|
||||
log.Trace("add: %s", node.GetCurrentPath().ReadableString())
|
||||
log.Trace("add: %s", new.GetCurrentPath().ReadableString())
|
||||
}))
|
||||
}
|
||||
|
||||
for _, testCase := range []struct {
|
||||
existingPath string
|
||||
newPath string
|
||||
}{
|
||||
{
|
||||
existingPath: "/O-A/O-B",
|
||||
newPath: "/D-A/D-B/D-N",
|
||||
},
|
||||
{
|
||||
existingPath: "/O-A",
|
||||
newPath: "/D-A/D-O",
|
||||
},
|
||||
{
|
||||
existingPath: "/O-A/O-J/O-K",
|
||||
newPath: "/D-A/D-J/D-K/D-P",
|
||||
},
|
||||
} {
|
||||
t.Run("add"+testCase.newPath, func(t *testing.T) {
|
||||
destinationPath := generic.NewPathFromString(testCase.newPath)
|
||||
addNode(originTree, testCase.existingPath)
|
||||
assert.False(t, sameTree(originTree.GetRoot(), destinationTree.GetRoot()))
|
||||
assert.False(t, destinationTree.Exists(ctx, destinationPath), destinationPath.String())
|
||||
generic.TreeUnify(ctx, originTree, destinationTree, generic.NewUnifyOptions(destinationTree).SetUpsert(upsert).SetDelete(delete))
|
||||
assert.True(t, destinationTree.Exists(ctx, destinationPath), destinationPath.String())
|
||||
assert.True(t, sameTree(originTree.GetRoot(), destinationTree.GetRoot()))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
deleteNode := func(tree generic.TreeInterface, toDelete path.Path) {
|
||||
tree.Apply(ctx, toDelete, generic.NewApplyOptions(func(ctx context.Context, parent, path path.Path, node generic.NodeInterface) {
|
||||
node.Delete(ctx)
|
||||
}))
|
||||
}
|
||||
|
||||
for _, testCase := range []struct {
|
||||
originPath string
|
||||
destinationPath string
|
||||
}{
|
||||
{
|
||||
originPath: "/O-A/O-F",
|
||||
destinationPath: "/D-A/D-F",
|
||||
},
|
||||
} {
|
||||
t.Run("delete"+testCase.originPath, func(t *testing.T) {
|
||||
originPath := generic.NewPathFromString(testCase.originPath)
|
||||
destinationPath := generic.NewPathFromString(testCase.destinationPath)
|
||||
assert.True(t, originTree.Exists(ctx, originPath))
|
||||
assert.True(t, destinationTree.Exists(ctx, destinationPath), destinationPath.String())
|
||||
deleteNode(originTree, originPath)
|
||||
assert.False(t, originTree.Exists(ctx, originPath))
|
||||
generic.TreeUnify(ctx, originTree, destinationTree, generic.NewUnifyOptions(destinationTree).SetUpsert(upsert).SetDelete(delete))
|
||||
assert.False(t, destinationTree.Exists(ctx, destinationPath), destinationPath.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeParallelApplyFound(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, testCase := range []struct {
|
||||
start string
|
||||
destination string
|
||||
expected []string
|
||||
expectedRemapped string
|
||||
}{
|
||||
{
|
||||
start: "/O-A/O-B",
|
||||
destination: "O-C",
|
||||
expected: []string{"/O-A/O-B => /D-A/D-B", "/O-A/O-B/O-C => /D-A/D-B/D-C"},
|
||||
expectedRemapped: "/D-A/D-B/D-C",
|
||||
},
|
||||
{
|
||||
start: "/O-A/O-B/O-D",
|
||||
destination: ".",
|
||||
expected: []string{"/O-A/O-B/O-D => /D-A/D-B/D-D"},
|
||||
expectedRemapped: "/D-A/D-B/D-D",
|
||||
},
|
||||
{
|
||||
start: ".",
|
||||
destination: ".",
|
||||
expected: []string{" => "},
|
||||
expectedRemapped: "",
|
||||
},
|
||||
{
|
||||
start: "/O-A/O-B/O-C",
|
||||
destination: "../O-D",
|
||||
expected: []string{"/O-A/O-B => /D-A/D-B", "/O-A/O-B/O-D => /D-A/D-B/D-D"},
|
||||
expectedRemapped: "/D-A/D-B/D-D",
|
||||
},
|
||||
{
|
||||
start: "/",
|
||||
destination: ".",
|
||||
expected: []string{" => "},
|
||||
expectedRemapped: "",
|
||||
},
|
||||
} {
|
||||
t.Run(" "+testCase.start+" => "+testCase.destination, func(t *testing.T) {
|
||||
originTree := NewMemoryTree(ctx, "O")
|
||||
testTreeBuild(t, originTree, 2)
|
||||
destinationTree := NewMemoryTree(ctx, "D")
|
||||
|
||||
//
|
||||
// Mirror two trees
|
||||
//
|
||||
generic.TreeMirror(ctx, originTree, destinationTree, generic.NewPathFromString("/"), generic.NewMirrorOptions())
|
||||
//
|
||||
// collect all nodes traversed by the apply function along testCase.destination
|
||||
//
|
||||
collected := make([]string, 0, 10)
|
||||
collect := func(ctx context.Context, origin, destination generic.NodeInterface) {
|
||||
collected = append(collected, fmt.Sprintf("%s => %s", origin.GetCurrentPath().String(), destination.GetCurrentPath().String()))
|
||||
}
|
||||
//
|
||||
// get to testCase.start and from there run the apply function to reach testCase.destination
|
||||
//
|
||||
nodeApply := func(ctx context.Context, origin, destination generic.NodeInterface) {
|
||||
assert.True(t, generic.NodeParallelApply(ctx, origin, generic.NewPathFromString(testCase.destination), destination, generic.NewParallelApplyOptions(collect).SetWhere(generic.ApplyEachNode)))
|
||||
}
|
||||
assert.True(t, generic.TreeParallelApply(ctx, originTree, generic.NewPathFromString(testCase.start), destinationTree, generic.NewParallelApplyOptions(nodeApply)))
|
||||
assert.EqualValues(t, testCase.expected, collected)
|
||||
|
||||
//
|
||||
// test TreePathRemap
|
||||
//
|
||||
remappedPath := generic.TreePathRemap(ctx, originTree, generic.NewPathFromString(filepath.Join(testCase.start, testCase.destination)), destinationTree)
|
||||
assert.EqualValues(t, testCase.expectedRemapped, remappedPath.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeParallelApplyNoRemap(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, testCase := range []struct {
|
||||
noremap bool
|
||||
start string
|
||||
expected []string
|
||||
expectedRemapped string
|
||||
}{
|
||||
{
|
||||
noremap: false,
|
||||
start: "/O-A/O-B",
|
||||
expected: []string{" => ", "/O-A => /D-A", "/O-A/O-B => /D-A/D-B"},
|
||||
expectedRemapped: "/D-A/D-B",
|
||||
},
|
||||
{
|
||||
noremap: true,
|
||||
start: "/O-A/O-B",
|
||||
expected: []string{" => ", "/O-A => /O-A", "/O-A/O-B => /O-A/O-B"},
|
||||
expectedRemapped: "/O-A/O-B",
|
||||
},
|
||||
} {
|
||||
t.Run(fmt.Sprintf("noremap=%v,start=%s", testCase.noremap, testCase.start), func(t *testing.T) {
|
||||
originName := "O"
|
||||
originTree := NewMemoryTree(ctx, originName)
|
||||
testTreeBuild(t, originTree, 2)
|
||||
var destinationName string
|
||||
if testCase.noremap {
|
||||
destinationName = originName
|
||||
} else {
|
||||
destinationName = "D"
|
||||
}
|
||||
destinationTree := NewMemoryTree(ctx, destinationName)
|
||||
|
||||
//
|
||||
// Mirror two trees
|
||||
//
|
||||
generic.TreeMirror(ctx, originTree, destinationTree, generic.NewPathFromString("/"), generic.NewMirrorOptions())
|
||||
//
|
||||
// collect all nodes traversed by the apply function along testCase.destination
|
||||
//
|
||||
collected := make([]string, 0, 10)
|
||||
collect := func(ctx context.Context, origin, destination generic.NodeInterface) {
|
||||
collected = append(collected, fmt.Sprintf("%s => %s", origin.GetCurrentPath(), destination.GetCurrentPath()))
|
||||
}
|
||||
//
|
||||
// get to testCase.start and from there run the apply function to reach testCase.destination
|
||||
//
|
||||
assert.True(t, generic.TreeParallelApply(ctx, originTree, generic.NewPathFromString(testCase.start), destinationTree, generic.NewParallelApplyOptions(collect).SetWhere(generic.ApplyEachNode).SetNoRemap(testCase.noremap)))
|
||||
assert.EqualValues(t, testCase.expected, collected)
|
||||
|
||||
//
|
||||
// test TreePathRemap
|
||||
//
|
||||
remappedPath := generic.TreePathRemap(ctx, originTree, generic.NewPathFromString(testCase.start), destinationTree)
|
||||
assert.EqualValues(t, testCase.expectedRemapped, remappedPath.String())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNodeParallelApplyNotFound(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
for _, testCase := range []struct {
|
||||
start string
|
||||
destination string
|
||||
}{
|
||||
{
|
||||
start: "/O-A",
|
||||
destination: "O-B/???",
|
||||
},
|
||||
{
|
||||
start: "/O-A/O-B",
|
||||
destination: "???",
|
||||
},
|
||||
{
|
||||
start: "/O-A/O-B",
|
||||
destination: "../???",
|
||||
},
|
||||
} {
|
||||
t.Run(" "+testCase.start+" => "+testCase.destination, func(t *testing.T) {
|
||||
originTree := NewMemoryTree(ctx, "O")
|
||||
testTreeBuild(t, originTree, 2)
|
||||
destinationTree := NewMemoryTree(ctx, "D")
|
||||
|
||||
//
|
||||
// Mirror two trees
|
||||
//
|
||||
generic.TreeMirror(ctx, originTree, destinationTree, generic.NewPathFromString("/"), generic.NewMirrorOptions())
|
||||
//
|
||||
// get to testCase.start and from there run the apply function to reach testCase.destination
|
||||
//
|
||||
var called bool
|
||||
nodeApply := func(ctx context.Context, origin, destination generic.NodeInterface) {
|
||||
called = true
|
||||
found := generic.NodeParallelApply(ctx, origin, generic.NewPathFromString(testCase.destination), destination, generic.NewParallelApplyOptions(nil))
|
||||
assert.False(t, found)
|
||||
}
|
||||
assert.True(t, generic.TreeParallelApply(ctx, originTree, generic.NewPathFromString(testCase.start), destinationTree, generic.NewParallelApplyOptions(nodeApply)))
|
||||
assert.True(t, called)
|
||||
})
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue