560305f601
- uses newer version of go-ethereum required for go1.11
686 lines
16 KiB
Go
686 lines
16 KiB
Go
// 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)
|
|
}
|
|
})
|
|
}
|
|
}
|