ipld-eth-server/vendor/github.com/aristanetworks/goarista/path/map_test.go
Matt K 293dd2e848 Add vendor dir (#16) (#4)
* Add vendor dir so builds dont require dep

* Pin specific version go-eth version
2018-01-29 13:44:18 -06:00

340 lines
9.3 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 (
"errors"
"fmt"
"testing"
"github.com/aristanetworks/goarista/key"
"github.com/aristanetworks/goarista/pathmap"
"github.com/aristanetworks/goarista/test"
)
func accumulator(counter map[int]int) pathmap.VisitorFunc {
return func(val interface{}) error {
counter[val.(int)]++
return nil
}
}
func TestVisit(t *testing.T) {
m := NewMap()
m.Set(Path{key.New("foo"), key.New("bar"), key.New("baz")}, 1)
m.Set(Path{key.New("*"), key.New("bar"), key.New("baz")}, 2)
m.Set(Path{key.New("*"), key.New("*"), key.New("baz")}, 3)
m.Set(Path{key.New("*"), key.New("*"), key.New("*")}, 4)
m.Set(Path{key.New("foo"), key.New("*"), key.New("*")}, 5)
m.Set(Path{key.New("foo"), key.New("bar"), key.New("*")}, 6)
m.Set(Path{key.New("foo"), key.New("*"), key.New("baz")}, 7)
m.Set(Path{key.New("*"), key.New("bar"), key.New("*")}, 8)
m.Set(Path{}, 10)
m.Set(Path{key.New("*")}, 20)
m.Set(Path{key.New("foo")}, 21)
m.Set(Path{key.New("zap"), key.New("zip")}, 30)
m.Set(Path{key.New("zap"), key.New("zip")}, 31)
m.Set(Path{key.New("zip"), key.New("*")}, 40)
m.Set(Path{key.New("zip"), key.New("*")}, 41)
testCases := []struct {
path Path
expected map[int]int
}{{
path: Path{key.New("foo"), key.New("bar"), key.New("baz")},
expected: map[int]int{1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1},
}, {
path: Path{key.New("qux"), key.New("bar"), key.New("baz")},
expected: map[int]int{2: 1, 3: 1, 4: 1, 8: 1},
}, {
path: Path{key.New("foo"), key.New("qux"), key.New("baz")},
expected: map[int]int{3: 1, 4: 1, 5: 1, 7: 1},
}, {
path: Path{key.New("foo"), key.New("bar"), key.New("qux")},
expected: map[int]int{4: 1, 5: 1, 6: 1, 8: 1},
}, {
path: Path{},
expected: map[int]int{10: 1},
}, {
path: Path{key.New("foo")},
expected: map[int]int{20: 1, 21: 1},
}, {
path: Path{key.New("foo"), key.New("bar")},
expected: map[int]int{},
}, {
path: Path{key.New("zap"), key.New("zip")},
expected: map[int]int{31: 1},
}, {
path: Path{key.New("zip"), key.New("zap")},
expected: map[int]int{41: 1},
}}
for _, tc := range testCases {
result := make(map[int]int, len(tc.expected))
m.Visit(tc.path, accumulator(result))
if diff := test.Diff(tc.expected, result); diff != "" {
t.Errorf("Test case %v: %s", tc.path, diff)
}
}
}
func TestVisitError(t *testing.T) {
m := NewMap()
m.Set(Path{key.New("foo"), key.New("bar")}, 1)
m.Set(Path{key.New("*"), key.New("bar")}, 2)
errTest := errors.New("Test")
err := m.Visit(Path{key.New("foo"), key.New("bar")},
func(v interface{}) error { return errTest })
if err != errTest {
t.Errorf("Unexpected error. Expected: %v, Got: %v", errTest, err)
}
err = m.VisitPrefix(Path{key.New("foo"), key.New("bar"), key.New("baz")},
func(v interface{}) error { return errTest })
if err != errTest {
t.Errorf("Unexpected error. Expected: %v, Got: %v", errTest, err)
}
}
func TestGet(t *testing.T) {
m := NewMap()
m.Set(Path{}, 0)
m.Set(Path{key.New("foo"), key.New("bar")}, 1)
m.Set(Path{key.New("foo"), key.New("*")}, 2)
m.Set(Path{key.New("*"), key.New("bar")}, 3)
m.Set(Path{key.New("zap"), key.New("zip")}, 4)
testCases := []struct {
path Path
expected interface{}
}{{
path: Path{},
expected: 0,
}, {
path: Path{key.New("foo"), key.New("bar")},
expected: 1,
}, {
path: Path{key.New("foo"), key.New("*")},
expected: 2,
}, {
path: Path{key.New("*"), key.New("bar")},
expected: 3,
}, {
path: Path{key.New("bar"), key.New("foo")},
expected: nil,
}, {
path: Path{key.New("zap"), key.New("*")},
expected: nil,
}}
for _, tc := range testCases {
got := m.Get(tc.path)
if got != tc.expected {
t.Errorf("Test case %v: Expected %v, Got %v",
tc.path, tc.expected, got)
}
}
}
func countNodes(n *node) int {
if n == nil {
return 0
}
count := 1
count += countNodes(n.wildcard)
for _, child := range n.children {
count += countNodes(child)
}
return count
}
func TestDelete(t *testing.T) {
m := NewMap()
m.Set(Path{}, 0)
m.Set(Path{key.New("*")}, 1)
m.Set(Path{key.New("foo"), key.New("bar")}, 2)
m.Set(Path{key.New("foo"), key.New("*")}, 3)
n := countNodes(m.(*node))
if n != 5 {
t.Errorf("Initial count wrong. Expected: 5, Got: %d", n)
}
testCases := []struct {
del Path // Path to delete
expected bool // expected return value of Delete
visit Path // Path to Visit
before map[int]int // Expected to find items before deletion
after map[int]int // Expected to find items after deletion
count int // Count of nodes
}{{
del: Path{key.New("zap")}, // A no-op Delete
expected: false,
visit: Path{key.New("foo"), key.New("bar")},
before: map[int]int{2: 1, 3: 1},
after: map[int]int{2: 1, 3: 1},
count: 5,
}, {
del: Path{key.New("foo"), key.New("bar")},
expected: true,
visit: Path{key.New("foo"), key.New("bar")},
before: map[int]int{2: 1, 3: 1},
after: map[int]int{3: 1},
count: 4,
}, {
del: Path{key.New("*")},
expected: true,
visit: Path{key.New("foo")},
before: map[int]int{1: 1},
after: map[int]int{},
count: 3,
}, {
del: Path{key.New("*")},
expected: false,
visit: Path{key.New("foo")},
before: map[int]int{},
after: map[int]int{},
count: 3,
}, {
del: Path{key.New("foo"), key.New("*")},
expected: true,
visit: Path{key.New("foo"), key.New("bar")},
before: map[int]int{3: 1},
after: map[int]int{},
count: 1, // Should have deleted "foo" and "bar" nodes
}, {
del: Path{},
expected: true,
visit: Path{},
before: map[int]int{0: 1},
after: map[int]int{},
count: 1, // Root node can't be deleted
}}
for i, tc := range testCases {
beforeResult := make(map[int]int, len(tc.before))
m.Visit(tc.visit, accumulator(beforeResult))
if diff := test.Diff(tc.before, beforeResult); diff != "" {
t.Errorf("Test case %d (%v): %s", i, tc.del, diff)
}
if got := m.Delete(tc.del); got != tc.expected {
t.Errorf("Test case %d (%v): Unexpected return. Expected %t, Got: %t",
i, tc.del, tc.expected, got)
}
afterResult := make(map[int]int, len(tc.after))
m.Visit(tc.visit, accumulator(afterResult))
if diff := test.Diff(tc.after, afterResult); diff != "" {
t.Errorf("Test case %d (%v): %s", i, tc.del, diff)
}
}
}
func TestVisitPrefix(t *testing.T) {
m := NewMap()
m.Set(Path{}, 0)
m.Set(Path{key.New("foo")}, 1)
m.Set(Path{key.New("foo"), key.New("bar")}, 2)
m.Set(Path{key.New("foo"), key.New("bar"), key.New("baz")}, 3)
m.Set(Path{key.New("foo"), key.New("bar"), key.New("baz"), key.New("quux")}, 4)
m.Set(Path{key.New("quux"), key.New("bar")}, 5)
m.Set(Path{key.New("foo"), key.New("quux")}, 6)
m.Set(Path{key.New("*")}, 7)
m.Set(Path{key.New("foo"), key.New("*")}, 8)
m.Set(Path{key.New("*"), key.New("bar")}, 9)
m.Set(Path{key.New("*"), key.New("quux")}, 10)
m.Set(Path{key.New("quux"), key.New("quux"), key.New("quux"), key.New("quux")}, 11)
testCases := []struct {
path Path
expected map[int]int
}{{
path: Path{key.New("foo"), key.New("bar"), key.New("baz")},
expected: map[int]int{0: 1, 1: 1, 2: 1, 3: 1, 7: 1, 8: 1, 9: 1},
}, {
path: Path{key.New("zip"), key.New("zap")},
expected: map[int]int{0: 1, 7: 1},
}, {
path: Path{key.New("foo"), key.New("zap")},
expected: map[int]int{0: 1, 1: 1, 8: 1, 7: 1},
}, {
path: Path{key.New("quux"), key.New("quux"), key.New("quux")},
expected: map[int]int{0: 1, 7: 1, 10: 1},
}}
for _, tc := range testCases {
result := make(map[int]int, len(tc.expected))
m.VisitPrefix(tc.path, accumulator(result))
if diff := test.Diff(tc.expected, result); diff != "" {
t.Errorf("Test case %v: %s", tc.path, diff)
}
}
}
func TestString(t *testing.T) {
m := NewMap()
m.Set(Path{}, 0)
m.Set(Path{key.New("foo"), key.New("bar")}, 1)
m.Set(Path{key.New("foo"), key.New("quux")}, 2)
m.Set(Path{key.New("foo"), key.New("*")}, 3)
expected := `Val: 0
Child "foo":
Child "*":
Val: 3
Child "bar":
Val: 1
Child "quux":
Val: 2
`
got := fmt.Sprint(m)
if expected != got {
t.Errorf("Unexpected string. Expected:\n\n%s\n\nGot:\n\n%s", expected, got)
}
}
func genWords(count, wordLength int) Path {
chars := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
if count+wordLength > len(chars) {
panic("need more chars")
}
result := make(Path, count)
for i := 0; i < count; i++ {
result[i] = key.New(string(chars[i : i+wordLength]))
}
return result
}
func benchmarkPathMap(pathLength, pathDepth int, b *testing.B) {
m := NewMap()
// Push pathDepth paths, each of length pathLength
path := genWords(pathLength, 10)
words := genWords(pathDepth, 10)
n := m.(*node)
for _, element := range path {
n.children = map[key.Key]*node{}
for _, word := range words {
n.children[word] = &node{}
}
n = n.children[element]
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
m.Visit(path, func(v interface{}) error { return nil })
}
}
func BenchmarkPathMap1x25(b *testing.B) { benchmarkPathMap(1, 25, b) }
func BenchmarkPathMap10x50(b *testing.B) { benchmarkPathMap(10, 25, b) }
func BenchmarkPathMap20x50(b *testing.B) { benchmarkPathMap(20, 25, b) }