snapshot of https://github.com/ory/keto.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
CI / Run lints and checks (push) Failing after 47s
CI / Run tests (push) Failing after 1s
CI / Run race tests (push) Failing after 5s
CI / Build CLI docs (push) Has been skipped
CI / Run buf actions (push) Failing after 5s
CodeQL / Analyze (go) (push) Failing after 3s
CodeQL / Analyze (javascript) (push) Failing after 2s
Docker Image Scanners / scanners (push) Failing after 3s
Format / format (push) Failing after 3s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Draft newsletter (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
Some checks failed
CI / Run lints and checks (push) Failing after 47s
CI / Run tests (push) Failing after 1s
CI / Run race tests (push) Failing after 5s
CI / Build CLI docs (push) Has been skipped
CI / Run buf actions (push) Failing after 5s
CodeQL / Analyze (go) (push) Failing after 3s
CodeQL / Analyze (javascript) (push) Failing after 2s
Docker Image Scanners / scanners (push) Failing after 3s
Format / format (push) Failing after 3s
Synchronize Issue Labels / Synchronize Issue Labels (push) Has been skipped
CI / Generate release (push) Has been skipped
CI / Draft newsletter (push) Has been skipped
CI / Pending approval Slack notification (push) Has been skipped
CI / Send newsletter (push) Has been skipped
This commit is contained in:
127
internal/expand/testhelper.go
Normal file
127
internal/expand/testhelper.go
Normal file
@@ -0,0 +1,127 @@
|
||||
// Copyright © 2023 Ory Corp
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package expand
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"slices"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/ory/keto/internal/relationtuple"
|
||||
"github.com/ory/keto/ketoapi"
|
||||
)
|
||||
|
||||
func AssertExternalTreesAreEqual(t *testing.T, expected, actual *ketoapi.Tree[*ketoapi.RelationTuple]) {
|
||||
t.Helper()
|
||||
assert.Truef(t, treesAreEqual(t, expected, actual),
|
||||
"expected:\n%+v\n\nactual:\n%+v", expected, actual)
|
||||
}
|
||||
|
||||
// TODO(hperl): Refactor to generic tree equality helper.
|
||||
func treesAreEqual(t *testing.T, expected, actual *ketoapi.Tree[*ketoapi.RelationTuple]) bool {
|
||||
if expected == nil || actual == nil {
|
||||
return expected == actual
|
||||
}
|
||||
|
||||
if expected.Type != actual.Type {
|
||||
t.Logf("expected type %q, actual type %q", expected.Type, actual.Type)
|
||||
return false
|
||||
}
|
||||
if !assert.ObjectsAreEqual(expected.Tuple.SubjectID, actual.Tuple.SubjectID) || !assert.ObjectsAreEqual(expected.Tuple.SubjectSet, actual.Tuple.SubjectSet) {
|
||||
t.Logf("expected subject: %+v %+v, actual subject: %+v %+v", expected.Tuple.SubjectID, expected.Tuple.SubjectSet, actual.Tuple.SubjectID, actual.Tuple.SubjectSet)
|
||||
return false
|
||||
}
|
||||
if len(expected.Children) != len(actual.Children) {
|
||||
t.Logf("expected len(children)=%d, actual len(children)=%d", len(expected.Children), len(actual.Children))
|
||||
return false
|
||||
}
|
||||
|
||||
// For children, we check for equality disregarding the order
|
||||
outer:
|
||||
for _, expectedChild := range expected.Children {
|
||||
for _, actualChild := range actual.Children {
|
||||
if treesAreEqual(t, expectedChild, actualChild) {
|
||||
continue outer
|
||||
}
|
||||
}
|
||||
t.Logf("expected child:\n%+v\n\nactual child:\n%+v", expectedChild, actual)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// formatTree returns a human-readable, indented representation of a tree.
|
||||
func formatTree(tree *relationtuple.Tree, indent string) string {
|
||||
if tree == nil {
|
||||
return indent + "<nil>\n"
|
||||
}
|
||||
var b strings.Builder
|
||||
fmt.Fprintf(&b, "%s(%s) %+v", indent, tree.Type, tree.Subject)
|
||||
if e := tree.Truncation; e != nil {
|
||||
fmt.Fprintf(&b, " [truncation: reason=%s cursor=%s]", e.Reason, formatExpandCursor(e.Cursor))
|
||||
}
|
||||
b.WriteByte('\n')
|
||||
for _, child := range tree.Children {
|
||||
b.WriteString(formatTree(child, indent+" "))
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
func formatExpandCursor(c *relationtuple.ExpandCursor) string {
|
||||
if c == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
var parts []string
|
||||
parts = append(parts, "kind="+string(c.Kind))
|
||||
parts = append(parts, "subject_set="+c.SubjectSet.String())
|
||||
if c.TraverseRelation != nil {
|
||||
parts = append(parts, "traverseRel="+*c.TraverseRelation)
|
||||
}
|
||||
return "{" + strings.Join(parts, " ") + "}"
|
||||
}
|
||||
|
||||
// sortTree recursively sorts the children of a tree by subject string, in-place.
|
||||
func sortTree(tree *relationtuple.Tree) {
|
||||
if tree == nil {
|
||||
return
|
||||
}
|
||||
for _, child := range tree.Children {
|
||||
sortTree(child)
|
||||
}
|
||||
if tree.Children == nil {
|
||||
return
|
||||
}
|
||||
slices.SortFunc(tree.Children, func(a, b *relationtuple.Tree) int {
|
||||
if a.Subject == nil && b.Subject == nil {
|
||||
return 0
|
||||
}
|
||||
if a.Subject == nil {
|
||||
return 1
|
||||
}
|
||||
if b.Subject == nil {
|
||||
return -1
|
||||
}
|
||||
return strings.Compare(a.Subject.String(), b.Subject.String())
|
||||
})
|
||||
}
|
||||
|
||||
// AssertInternalTreesAreEqual compares two trees for equality, ignoring child order.
|
||||
func AssertInternalTreesAreEqual(t *testing.T, expected, actual *relationtuple.Tree) bool {
|
||||
t.Helper()
|
||||
sortTree(expected)
|
||||
sortTree(actual)
|
||||
return assert.Equal(t, formatTree(expected, ""), formatTree(actual, ""))
|
||||
}
|
||||
|
||||
// RequireInternalTreesAreEqual compares two trees for equality, ignoring child order.
|
||||
func RequireInternalTreesAreEqual(t *testing.T, expected, actual *relationtuple.Tree) {
|
||||
t.Helper()
|
||||
sortTree(expected)
|
||||
sortTree(actual)
|
||||
require.Equal(t, formatTree(expected, ""), formatTree(actual, ""))
|
||||
}
|
||||
Reference in New Issue
Block a user