ipld-eth-server/vendor/github.com/aristanetworks/goarista/path/path_test.go

686 lines
16 KiB
Go
Raw Normal View History

// Copyright (c) 2017 Arista Networks, Inc.
// Use of this source code is governed by the Apache License 2.0
// that can be found in the COPYING file.
package path
import (
"fmt"
"testing"
"github.com/aristanetworks/goarista/key"
"github.com/aristanetworks/goarista/value"
)
func TestNew(t *testing.T) {
tcases := []struct {
in []interface{}
out key.Path
}{
{
in: nil,
out: key.Path{},
}, {
in: []interface{}{},
out: key.Path{},
}, {
in: []interface{}{"foo", key.New("bar"), true},
out: key.Path{key.New("foo"), key.New("bar"), key.New(true)},
}, {
in: []interface{}{int8(5), int16(5), int32(5), int64(5)},
out: key.Path{key.New(int8(5)), key.New(int16(5)), key.New(int32(5)),
key.New(int64(5))},
}, {
in: []interface{}{uint8(5), uint16(5), uint32(5), uint64(5)},
out: key.Path{key.New(uint8(5)), key.New(uint16(5)), key.New(uint32(5)),
key.New(uint64(5))},
}, {
in: []interface{}{float32(5), float64(5)},
out: key.Path{key.New(float32(5)), key.New(float64(5))},
}, {
in: []interface{}{customKey{i: &a}, map[string]interface{}{}},
out: key.Path{key.New(customKey{i: &a}), key.New(map[string]interface{}{})},
},
}
for i, tcase := range tcases {
if p := New(tcase.in...); !Equal(p, tcase.out) {
t.Fatalf("Test %d failed: %#v != %#v", i, p, tcase.out)
}
}
}
func TestClone(t *testing.T) {
if !Equal(Clone(key.Path{}), key.Path{}) {
t.Error("Clone(key.Path{}) != key.Path{}")
}
a := key.Path{key.New("foo"), key.New("bar")}
b, c := Clone(a), Clone(a)
b[1] = key.New("baz")
if Equal(a, b) || !Equal(a, c) {
t.Error("Clone is not making a copied path")
}
}
func TestAppend(t *testing.T) {
tcases := []struct {
a key.Path
b []interface{}
result key.Path
}{
{
a: key.Path{},
b: []interface{}{},
result: key.Path{},
}, {
a: key.Path{key.New("foo")},
b: []interface{}{},
result: key.Path{key.New("foo")},
}, {
a: key.Path{},
b: []interface{}{"foo", key.New("bar")},
result: key.Path{key.New("foo"), key.New("bar")},
}, {
a: key.Path{key.New("foo")},
b: []interface{}{int64(0), key.New("bar")},
result: key.Path{key.New("foo"), key.New(int64(0)), key.New("bar")},
},
}
for i, tcase := range tcases {
if p := Append(tcase.a, tcase.b...); !Equal(p, tcase.result) {
t.Fatalf("Test %d failed: %#v != %#v", i, p, tcase.result)
}
}
}
func TestJoin(t *testing.T) {
tcases := []struct {
paths []key.Path
result key.Path
}{
{
paths: nil,
result: nil,
}, {
paths: []key.Path{},
result: nil,
}, {
paths: []key.Path{key.Path{}},
result: nil,
}, {
paths: []key.Path{key.Path{key.New(true)}, key.Path{}},
result: key.Path{key.New(true)},
}, {
paths: []key.Path{key.Path{}, key.Path{key.New(true)}},
result: key.Path{key.New(true)},
}, {
paths: []key.Path{key.Path{key.New("foo")}, key.Path{key.New("bar")}},
result: key.Path{key.New("foo"), key.New("bar")},
}, {
paths: []key.Path{key.Path{key.New("bar")}, key.Path{key.New("foo")}},
result: key.Path{key.New("bar"), key.New("foo")},
}, {
paths: []key.Path{
key.Path{key.New(uint32(0)), key.New(uint64(0))},
key.Path{key.New(int8(0))},
key.Path{key.New(int16(0)), key.New(int32(0))},
key.Path{key.New(int64(0)), key.New(uint8(0)), key.New(uint16(0))},
},
result: key.Path{
key.New(uint32(0)), key.New(uint64(0)),
key.New(int8(0)), key.New(int16(0)),
key.New(int32(0)), key.New(int64(0)),
key.New(uint8(0)), key.New(uint16(0)),
},
},
}
for i, tcase := range tcases {
if p := Join(tcase.paths...); !Equal(p, tcase.result) {
t.Fatalf("Test %d failed: %#v != %#v", i, p, tcase.result)
}
}
}
func TestParent(t *testing.T) {
if Parent(key.Path{}) != nil {
t.Fatal("Parent of empty key.Path should be nil")
}
tcases := []struct {
in key.Path
out key.Path
}{
{
in: key.Path{key.New("foo")},
out: key.Path{},
}, {
in: key.Path{key.New("foo"), key.New("bar")},
out: key.Path{key.New("foo")},
}, {
in: key.Path{key.New("foo"), key.New("bar"), key.New("baz")},
out: key.Path{key.New("foo"), key.New("bar")},
},
}
for _, tcase := range tcases {
if !Equal(Parent(tcase.in), tcase.out) {
t.Fatalf("Parent of %#v != %#v", tcase.in, tcase.out)
}
}
}
func TestBase(t *testing.T) {
if Base(key.Path{}) != nil {
t.Fatal("Base of empty key.Path should be nil")
}
tcases := []struct {
in key.Path
out key.Key
}{
{
in: key.Path{key.New("foo")},
out: key.New("foo"),
}, {
in: key.Path{key.New("foo"), key.New("bar")},
out: key.New("bar"),
},
}
for _, tcase := range tcases {
if !Base(tcase.in).Equal(tcase.out) {
t.Fatalf("Base of %#v != %#v", tcase.in, tcase.out)
}
}
}
type customKey struct {
i *int
}
func (c customKey) String() string {
return fmt.Sprintf("customKey=%d", *c.i)
}
func (c customKey) MarshalJSON() ([]byte, error) {
return nil, nil
}
func (c customKey) ToBuiltin() interface{} {
return nil
}
func (c customKey) Equal(other interface{}) bool {
o, ok := other.(customKey)
return ok && *c.i == *o.i
}
var (
_ value.Value = customKey{}
_ key.Comparable = customKey{}
a = 1
b = 1
)
func TestEqual(t *testing.T) {
tcases := []struct {
a key.Path
b key.Path
result bool
}{
{
a: nil,
b: nil,
result: true,
}, {
a: nil,
b: key.Path{},
result: true,
}, {
a: key.Path{},
b: nil,
result: true,
}, {
a: key.Path{},
b: key.Path{},
result: true,
}, {
a: key.Path{},
b: key.Path{key.New("")},
result: false,
}, {
a: key.Path{Wildcard},
b: key.Path{key.New("foo")},
result: false,
}, {
a: key.Path{Wildcard},
b: key.Path{Wildcard},
result: true,
}, {
a: key.Path{key.New("foo")},
b: key.Path{key.New("foo")},
result: true,
}, {
a: key.Path{key.New(true)},
b: key.Path{key.New(false)},
result: false,
}, {
a: key.Path{key.New(int32(5))},
b: key.Path{key.New(int64(5))},
result: false,
}, {
a: key.Path{key.New("foo")},
b: key.Path{key.New("foo"), key.New("bar")},
result: false,
}, {
a: key.Path{key.New("foo"), key.New("bar")},
b: key.Path{key.New("foo")},
result: false,
}, {
a: key.Path{key.New(uint8(0)), key.New(int8(0))},
b: key.Path{key.New(int8(0)), key.New(uint8(0))},
result: false,
},
// Ensure that we check deep equality.
{
a: key.Path{key.New(map[string]interface{}{})},
b: key.Path{key.New(map[string]interface{}{})},
result: true,
}, {
a: key.Path{key.New(customKey{i: &a})},
b: key.Path{key.New(customKey{i: &b})},
result: true,
},
}
for i, tcase := range tcases {
if result := Equal(tcase.a, tcase.b); result != tcase.result {
t.Fatalf("Test %d failed: a: %#v; b: %#v, result: %t",
i, tcase.a, tcase.b, tcase.result)
}
}
}
func TestMatch(t *testing.T) {
tcases := []struct {
a key.Path
b key.Path
result bool
}{
{
a: nil,
b: nil,
result: true,
}, {
a: nil,
b: key.Path{},
result: true,
}, {
a: key.Path{},
b: nil,
result: true,
}, {
a: key.Path{},
b: key.Path{},
result: true,
}, {
a: key.Path{},
b: key.Path{key.New("foo")},
result: false,
}, {
a: key.Path{Wildcard},
b: key.Path{key.New("foo")},
result: true,
}, {
a: key.Path{key.New("foo")},
b: key.Path{Wildcard},
result: false,
}, {
a: key.Path{Wildcard},
b: key.Path{key.New("foo"), key.New("bar")},
result: false,
}, {
a: key.Path{Wildcard, Wildcard},
b: key.Path{key.New(int64(0))},
result: false,
}, {
a: key.Path{Wildcard, Wildcard},
b: key.Path{key.New(int64(0)), key.New(int32(0))},
result: true,
}, {
a: key.Path{Wildcard, key.New(false)},
b: key.Path{key.New(true), Wildcard},
result: false,
},
}
for i, tcase := range tcases {
if result := Match(tcase.a, tcase.b); result != tcase.result {
t.Fatalf("Test %d failed: a: %#v; b: %#v, result: %t",
i, tcase.a, tcase.b, tcase.result)
}
}
}
func TestHasElement(t *testing.T) {
tcases := []struct {
a key.Path
b key.Key
result bool
}{
{
a: nil,
b: nil,
result: false,
}, {
a: nil,
b: key.New("foo"),
result: false,
}, {
a: key.Path{},
b: nil,
result: false,
}, {
a: key.Path{key.New("foo")},
b: nil,
result: false,
}, {
a: key.Path{key.New("foo")},
b: key.New("foo"),
result: true,
}, {
a: key.Path{key.New(true)},
b: key.New("true"),
result: false,
}, {
a: key.Path{key.New("foo"), key.New("bar")},
b: key.New("bar"),
result: true,
}, {
a: key.Path{key.New(map[string]interface{}{})},
b: key.New(map[string]interface{}{}),
result: true,
}, {
a: key.Path{key.New(map[string]interface{}{"foo": "a"})},
b: key.New(map[string]interface{}{"bar": "a"}),
result: false,
},
}
for i, tcase := range tcases {
if result := HasElement(tcase.a, tcase.b); result != tcase.result {
t.Errorf("Test %d failed: a: %#v; b: %#v, result: %t, expected: %t",
i, tcase.a, tcase.b, result, tcase.result)
}
}
}
func TestHasPrefix(t *testing.T) {
tcases := []struct {
a key.Path
b key.Path
result bool
}{
{
a: nil,
b: nil,
result: true,
}, {
a: nil,
b: key.Path{},
result: true,
}, {
a: key.Path{},
b: nil,
result: true,
}, {
a: key.Path{},
b: key.Path{},
result: true,
}, {
a: key.Path{},
b: key.Path{key.New("foo")},
result: false,
}, {
a: key.Path{key.New("foo")},
b: key.Path{},
result: true,
}, {
a: key.Path{key.New(true)},
b: key.Path{key.New(false)},
result: false,
}, {
a: key.Path{key.New("foo"), key.New("bar")},
b: key.Path{key.New("bar"), key.New("foo")},
result: false,
}, {
a: key.Path{key.New(int8(0)), key.New(uint8(0))},
b: key.Path{key.New(uint8(0)), key.New(uint8(0))},
result: false,
}, {
a: key.Path{key.New(true), key.New(true)},
b: key.Path{key.New(true), key.New(true), key.New(true)},
result: false,
}, {
a: key.Path{key.New(true), key.New(true), key.New(true)},
b: key.Path{key.New(true), key.New(true)},
result: true,
}, {
a: key.Path{Wildcard, key.New(int32(0)), Wildcard},
b: key.Path{key.New(int64(0)), Wildcard},
result: false,
},
}
for i, tcase := range tcases {
if result := HasPrefix(tcase.a, tcase.b); result != tcase.result {
t.Fatalf("Test %d failed: a: %#v; b: %#v, result: %t",
i, tcase.a, tcase.b, tcase.result)
}
}
}
func TestMatchPrefix(t *testing.T) {
tcases := []struct {
a key.Path
b key.Path
result bool
}{
{
a: nil,
b: nil,
result: true,
}, {
a: nil,
b: key.Path{},
result: true,
}, {
a: key.Path{},
b: nil,
result: true,
}, {
a: key.Path{},
b: key.Path{},
result: true,
}, {
a: key.Path{},
b: key.Path{key.New("foo")},
result: false,
}, {
a: key.Path{key.New("foo")},
b: key.Path{},
result: true,
}, {
a: key.Path{key.New("foo")},
b: key.Path{Wildcard},
result: false,
}, {
a: key.Path{Wildcard},
b: key.Path{key.New("foo")},
result: true,
}, {
a: key.Path{Wildcard},
b: key.Path{key.New("foo"), key.New("bar")},
result: false,
}, {
a: key.Path{Wildcard, key.New(true)},
b: key.Path{key.New(false), Wildcard},
result: false,
}, {
a: key.Path{Wildcard, key.New(int32(0)), key.New(int16(0))},
b: key.Path{key.New(int64(0)), key.New(int32(0))},
result: true,
},
}
for i, tcase := range tcases {
if result := MatchPrefix(tcase.a, tcase.b); result != tcase.result {
t.Fatalf("Test %d failed: a: %#v; b: %#v, result: %t",
i, tcase.a, tcase.b, tcase.result)
}
}
}
func TestFromString(t *testing.T) {
tcases := []struct {
in string
out key.Path
}{
{
in: "",
out: key.Path{},
}, {
in: "/",
out: key.Path{},
}, {
in: "//",
out: key.Path{key.New(""), key.New("")},
}, {
in: "foo",
out: key.Path{key.New("foo")},
}, {
in: "/foo",
out: key.Path{key.New("foo")},
}, {
in: "foo/bar",
out: key.Path{key.New("foo"), key.New("bar")},
}, {
in: "/foo/bar",
out: key.Path{key.New("foo"), key.New("bar")},
}, {
in: "foo/bar/baz",
out: key.Path{key.New("foo"), key.New("bar"), key.New("baz")},
}, {
in: "/foo/bar/baz",
out: key.Path{key.New("foo"), key.New("bar"), key.New("baz")},
}, {
in: "0/123/456/789",
out: key.Path{key.New("0"), key.New("123"), key.New("456"), key.New("789")},
}, {
in: "/0/123/456/789",
out: key.Path{key.New("0"), key.New("123"), key.New("456"), key.New("789")},
}, {
in: "`~!@#$%^&*()_+{}\\/|[];':\"<>?,./",
out: key.Path{key.New("`~!@#$%^&*()_+{}\\"), key.New("|[];':\"<>?,."), key.New("")},
}, {
in: "/`~!@#$%^&*()_+{}\\/|[];':\"<>?,./",
out: key.Path{key.New("`~!@#$%^&*()_+{}\\"), key.New("|[];':\"<>?,."), key.New("")},
},
}
for i, tcase := range tcases {
if p := FromString(tcase.in); !Equal(p, tcase.out) {
t.Fatalf("Test %d failed: %#v != %#v", i, p, tcase.out)
}
}
}
func TestString(t *testing.T) {
tcases := []struct {
in key.Path
out string
}{
{
in: key.Path{},
out: "/",
}, {
in: key.Path{key.New("")},
out: "/",
}, {
in: key.Path{key.New("foo")},
out: "/foo",
}, {
in: key.Path{key.New("foo"), key.New("bar")},
out: "/foo/bar",
}, {
in: key.Path{key.New("/foo"), key.New("bar")},
out: "//foo/bar",
}, {
in: key.Path{key.New("foo"), key.New("bar/")},
out: "/foo/bar/",
}, {
in: key.Path{key.New(""), key.New("foo"), key.New("bar")},
out: "//foo/bar",
}, {
in: key.Path{key.New("foo"), key.New("bar"), key.New("")},
out: "/foo/bar/",
}, {
in: key.Path{key.New("/"), key.New("foo"), key.New("bar")},
out: "///foo/bar",
}, {
in: key.Path{key.New("foo"), key.New("bar"), key.New("/")},
out: "/foo/bar//",
},
}
for i, tcase := range tcases {
if s := tcase.in.String(); s != tcase.out {
t.Fatalf("Test %d failed: %s != %s", i, s, tcase.out)
}
}
}
func BenchmarkJoin(b *testing.B) {
generate := func(n int) []key.Path {
paths := make([]key.Path, 0, n)
for i := 0; i < n; i++ {
paths = append(paths, key.Path{key.New("foo")})
}
return paths
}
benchmarks := map[string][]key.Path{
"10 key.Paths": generate(10),
"100 key.Paths": generate(100),
"1000 key.Paths": generate(1000),
"10000 key.Paths": generate(10000),
}
for name, benchmark := range benchmarks {
b.Run(name, func(b *testing.B) {
for i := 0; i < b.N; i++ {
Join(benchmark...)
}
})
}
}
func BenchmarkHasElement(b *testing.B) {
element := key.New("waldo")
generate := func(n, loc int) key.Path {
path := make(key.Path, n)
for i := 0; i < n; i++ {
if i == loc {
path[i] = element
} else {
path[i] = key.New(int8(0))
}
}
return path
}
benchmarks := map[string]key.Path{
"10 Elements Index 0": generate(10, 0),
"10 Elements Index 4": generate(10, 4),
"10 Elements Index 9": generate(10, 9),
"100 Elements Index 0": generate(100, 0),
"100 Elements Index 49": generate(100, 49),
"100 Elements Index 99": generate(100, 99),
"1000 Elements Index 0": generate(1000, 0),
"1000 Elements Index 499": generate(1000, 499),
"1000 Elements Index 999": generate(1000, 999),
}
for name, benchmark := range benchmarks {
b.Run(name, func(b *testing.B) {
for i := 0; i < b.N; i++ {
HasElement(benchmark, element)
}
})
}
}