map_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. // Copyright (c) 2017 Arista Networks, Inc.
  2. // Use of this source code is governed by the Apache License 2.0
  3. // that can be found in the COPYING file.
  4. package path
  5. import (
  6. "errors"
  7. "fmt"
  8. "testing"
  9. "notabug.org/themusicgod1/goarista/key"
  10. "notabug.org/themusicgod1/goarista/test"
  11. )
  12. func accumulator(counter map[int]int) VisitorFunc {
  13. return func(val interface{}) error {
  14. counter[val.(int)]++
  15. return nil
  16. }
  17. }
  18. func TestMapVisit(t *testing.T) {
  19. m := Map{}
  20. m.Set(key.Path{key.New("foo"), key.New("bar"), key.New("baz")}, 1)
  21. m.Set(key.Path{Wildcard, key.New("bar"), key.New("baz")}, 2)
  22. m.Set(key.Path{Wildcard, Wildcard, key.New("baz")}, 3)
  23. m.Set(key.Path{Wildcard, Wildcard, Wildcard}, 4)
  24. m.Set(key.Path{key.New("foo"), Wildcard, Wildcard}, 5)
  25. m.Set(key.Path{key.New("foo"), key.New("bar"), Wildcard}, 6)
  26. m.Set(key.Path{key.New("foo"), Wildcard, key.New("baz")}, 7)
  27. m.Set(key.Path{Wildcard, key.New("bar"), Wildcard}, 8)
  28. m.Set(key.Path{}, 10)
  29. m.Set(key.Path{Wildcard}, 20)
  30. m.Set(key.Path{key.New("foo")}, 21)
  31. m.Set(key.Path{key.New("zap"), key.New("zip")}, 30)
  32. m.Set(key.Path{key.New("zap"), key.New("zip")}, 31)
  33. m.Set(key.Path{key.New("zip"), Wildcard}, 40)
  34. m.Set(key.Path{key.New("zip"), Wildcard}, 41)
  35. testCases := []struct {
  36. path key.Path
  37. expected map[int]int
  38. }{{
  39. path: key.Path{key.New("foo"), key.New("bar"), key.New("baz")},
  40. expected: map[int]int{1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1},
  41. }, {
  42. path: key.Path{key.New("qux"), key.New("bar"), key.New("baz")},
  43. expected: map[int]int{2: 1, 3: 1, 4: 1, 8: 1},
  44. }, {
  45. path: key.Path{key.New("foo"), key.New("qux"), key.New("baz")},
  46. expected: map[int]int{3: 1, 4: 1, 5: 1, 7: 1},
  47. }, {
  48. path: key.Path{key.New("foo"), key.New("bar"), key.New("qux")},
  49. expected: map[int]int{4: 1, 5: 1, 6: 1, 8: 1},
  50. }, {
  51. path: key.Path{},
  52. expected: map[int]int{10: 1},
  53. }, {
  54. path: key.Path{key.New("foo")},
  55. expected: map[int]int{20: 1, 21: 1},
  56. }, {
  57. path: key.Path{key.New("foo"), key.New("bar")},
  58. expected: map[int]int{},
  59. }, {
  60. path: key.Path{key.New("zap"), key.New("zip")},
  61. expected: map[int]int{31: 1},
  62. }, {
  63. path: key.Path{key.New("zip"), key.New("zap")},
  64. expected: map[int]int{41: 1},
  65. }}
  66. for _, tc := range testCases {
  67. result := make(map[int]int, len(tc.expected))
  68. m.Visit(tc.path, accumulator(result))
  69. if diff := test.Diff(tc.expected, result); diff != "" {
  70. t.Errorf("Test case %v: %s", tc.path, diff)
  71. }
  72. }
  73. }
  74. func TestMapVisitError(t *testing.T) {
  75. m := Map{}
  76. m.Set(key.Path{key.New("foo"), key.New("bar")}, 1)
  77. m.Set(key.Path{Wildcard, key.New("bar")}, 2)
  78. errTest := errors.New("Test")
  79. err := m.Visit(key.Path{key.New("foo"), key.New("bar")},
  80. func(v interface{}) error { return errTest })
  81. if err != errTest {
  82. t.Errorf("Unexpected error. Expected: %v, Got: %v", errTest, err)
  83. }
  84. err = m.VisitPrefixes(key.Path{key.New("foo"), key.New("bar"), key.New("baz")},
  85. func(v interface{}) error { return errTest })
  86. if err != errTest {
  87. t.Errorf("Unexpected error. Expected: %v, Got: %v", errTest, err)
  88. }
  89. }
  90. func TestMapGet(t *testing.T) {
  91. m := Map{}
  92. m.Set(key.Path{}, 0)
  93. m.Set(key.Path{key.New("foo"), key.New("bar")}, 1)
  94. m.Set(key.Path{key.New("foo"), Wildcard}, 2)
  95. m.Set(key.Path{Wildcard, key.New("bar")}, 3)
  96. m.Set(key.Path{key.New("zap"), key.New("zip")}, 4)
  97. m.Set(key.Path{key.New("baz"), key.New("qux")}, nil)
  98. testCases := []struct {
  99. path key.Path
  100. v interface{}
  101. ok bool
  102. }{{
  103. path: key.Path{},
  104. v: 0,
  105. ok: true,
  106. }, {
  107. path: key.Path{key.New("foo"), key.New("bar")},
  108. v: 1,
  109. ok: true,
  110. }, {
  111. path: key.Path{key.New("foo"), Wildcard},
  112. v: 2,
  113. ok: true,
  114. }, {
  115. path: key.Path{Wildcard, key.New("bar")},
  116. v: 3,
  117. ok: true,
  118. }, {
  119. path: key.Path{key.New("baz"), key.New("qux")},
  120. v: nil,
  121. ok: true,
  122. }, {
  123. path: key.Path{key.New("bar"), key.New("foo")},
  124. v: nil,
  125. }, {
  126. path: key.Path{key.New("zap"), Wildcard},
  127. v: nil,
  128. }}
  129. for _, tc := range testCases {
  130. v, ok := m.Get(tc.path)
  131. if v != tc.v || ok != tc.ok {
  132. t.Errorf("Test case %v: Expected (v: %v, ok: %t), Got (v: %v, ok: %t)",
  133. tc.path, tc.v, tc.ok, v, ok)
  134. }
  135. }
  136. }
  137. func countNodes(m *Map) int {
  138. if m == nil {
  139. return 0
  140. }
  141. count := 1
  142. count += countNodes(m.wildcard)
  143. for _, child := range m.children {
  144. count += countNodes(child)
  145. }
  146. return count
  147. }
  148. func TestMapDelete(t *testing.T) {
  149. m := Map{}
  150. m.Set(key.Path{}, 0)
  151. m.Set(key.Path{Wildcard}, 1)
  152. m.Set(key.Path{key.New("foo"), key.New("bar")}, 2)
  153. m.Set(key.Path{key.New("foo"), Wildcard}, 3)
  154. n := countNodes(&m)
  155. if n != 5 {
  156. t.Errorf("Initial count wrong. Expected: 5, Got: %d", n)
  157. }
  158. testCases := []struct {
  159. del key.Path // key.Path to delete
  160. expected bool // expected return value of Delete
  161. visit key.Path // key.Path to Visit
  162. before map[int]int // Expected to find items before deletion
  163. after map[int]int // Expected to find items after deletion
  164. count int // Count of nodes
  165. }{{
  166. del: key.Path{key.New("zap")}, // A no-op Delete
  167. expected: false,
  168. visit: key.Path{key.New("foo"), key.New("bar")},
  169. before: map[int]int{2: 1, 3: 1},
  170. after: map[int]int{2: 1, 3: 1},
  171. count: 5,
  172. }, {
  173. del: key.Path{key.New("foo"), key.New("bar")},
  174. expected: true,
  175. visit: key.Path{key.New("foo"), key.New("bar")},
  176. before: map[int]int{2: 1, 3: 1},
  177. after: map[int]int{3: 1},
  178. count: 4,
  179. }, {
  180. del: key.Path{Wildcard},
  181. expected: true,
  182. visit: key.Path{key.New("foo")},
  183. before: map[int]int{1: 1},
  184. after: map[int]int{},
  185. count: 3,
  186. }, {
  187. del: key.Path{Wildcard},
  188. expected: false,
  189. visit: key.Path{key.New("foo")},
  190. before: map[int]int{},
  191. after: map[int]int{},
  192. count: 3,
  193. }, {
  194. del: key.Path{key.New("foo"), Wildcard},
  195. expected: true,
  196. visit: key.Path{key.New("foo"), key.New("bar")},
  197. before: map[int]int{3: 1},
  198. after: map[int]int{},
  199. count: 1, // Should have deleted "foo" and "bar" nodes
  200. }, {
  201. del: key.Path{},
  202. expected: true,
  203. visit: key.Path{},
  204. before: map[int]int{0: 1},
  205. after: map[int]int{},
  206. count: 1, // Root node can't be deleted
  207. }}
  208. for i, tc := range testCases {
  209. beforeResult := make(map[int]int, len(tc.before))
  210. m.Visit(tc.visit, accumulator(beforeResult))
  211. if diff := test.Diff(tc.before, beforeResult); diff != "" {
  212. t.Errorf("Test case %d (%v): %s", i, tc.del, diff)
  213. }
  214. if got := m.Delete(tc.del); got != tc.expected {
  215. t.Errorf("Test case %d (%v): Unexpected return. Expected %t, Got: %t",
  216. i, tc.del, tc.expected, got)
  217. }
  218. afterResult := make(map[int]int, len(tc.after))
  219. m.Visit(tc.visit, accumulator(afterResult))
  220. if diff := test.Diff(tc.after, afterResult); diff != "" {
  221. t.Errorf("Test case %d (%v): %s", i, tc.del, diff)
  222. }
  223. }
  224. }
  225. func TestMapVisitPrefixes(t *testing.T) {
  226. m := Map{}
  227. m.Set(key.Path{}, 0)
  228. m.Set(key.Path{key.New("foo")}, 1)
  229. m.Set(key.Path{key.New("foo"), key.New("bar")}, 2)
  230. m.Set(key.Path{key.New("foo"), key.New("bar"), key.New("baz")}, 3)
  231. m.Set(key.Path{key.New("foo"), key.New("bar"), key.New("baz"), key.New("quux")}, 4)
  232. m.Set(key.Path{key.New("quux"), key.New("bar")}, 5)
  233. m.Set(key.Path{key.New("foo"), key.New("quux")}, 6)
  234. m.Set(key.Path{Wildcard}, 7)
  235. m.Set(key.Path{key.New("foo"), Wildcard}, 8)
  236. m.Set(key.Path{Wildcard, key.New("bar")}, 9)
  237. m.Set(key.Path{Wildcard, key.New("quux")}, 10)
  238. m.Set(key.Path{key.New("quux"), key.New("quux"), key.New("quux"), key.New("quux")}, 11)
  239. testCases := []struct {
  240. path key.Path
  241. expected map[int]int
  242. }{{
  243. path: key.Path{key.New("foo"), key.New("bar"), key.New("baz")},
  244. expected: map[int]int{0: 1, 1: 1, 2: 1, 3: 1, 7: 1, 8: 1, 9: 1},
  245. }, {
  246. path: key.Path{key.New("zip"), key.New("zap")},
  247. expected: map[int]int{0: 1, 7: 1},
  248. }, {
  249. path: key.Path{key.New("foo"), key.New("zap")},
  250. expected: map[int]int{0: 1, 1: 1, 8: 1, 7: 1},
  251. }, {
  252. path: key.Path{key.New("quux"), key.New("quux"), key.New("quux")},
  253. expected: map[int]int{0: 1, 7: 1, 10: 1},
  254. }}
  255. for _, tc := range testCases {
  256. result := make(map[int]int, len(tc.expected))
  257. m.VisitPrefixes(tc.path, accumulator(result))
  258. if diff := test.Diff(tc.expected, result); diff != "" {
  259. t.Errorf("Test case %v: %s", tc.path, diff)
  260. }
  261. }
  262. }
  263. func TestMapVisitPrefixed(t *testing.T) {
  264. m := Map{}
  265. m.Set(key.Path{}, 0)
  266. m.Set(key.Path{key.New("qux")}, 1)
  267. m.Set(key.Path{key.New("foo")}, 2)
  268. m.Set(key.Path{key.New("foo"), key.New("qux")}, 3)
  269. m.Set(key.Path{key.New("foo"), key.New("bar")}, 4)
  270. m.Set(key.Path{Wildcard, key.New("bar")}, 5)
  271. m.Set(key.Path{key.New("foo"), Wildcard}, 6)
  272. m.Set(key.Path{key.New("qux"), key.New("foo"), key.New("bar")}, 7)
  273. testCases := []struct {
  274. in key.Path
  275. out map[int]int
  276. }{{
  277. in: key.Path{},
  278. out: map[int]int{0: 1, 1: 1, 2: 1, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1},
  279. }, {
  280. in: key.Path{key.New("qux")},
  281. out: map[int]int{1: 1, 5: 1, 7: 1},
  282. }, {
  283. in: key.Path{key.New("foo")},
  284. out: map[int]int{2: 1, 3: 1, 4: 1, 5: 1, 6: 1},
  285. }, {
  286. in: key.Path{key.New("foo"), key.New("qux")},
  287. out: map[int]int{3: 1, 6: 1},
  288. }, {
  289. in: key.Path{key.New("foo"), key.New("bar")},
  290. out: map[int]int{4: 1, 5: 1, 6: 1},
  291. }, {
  292. in: key.Path{key.New(int64(0))},
  293. out: map[int]int{5: 1},
  294. }, {
  295. in: key.Path{Wildcard},
  296. out: map[int]int{5: 1},
  297. }, {
  298. in: key.Path{Wildcard, Wildcard},
  299. out: map[int]int{},
  300. }}
  301. for _, tc := range testCases {
  302. out := make(map[int]int, len(tc.out))
  303. m.VisitPrefixed(tc.in, accumulator(out))
  304. if diff := test.Diff(tc.out, out); diff != "" {
  305. t.Errorf("Test case %v: %s", tc.out, diff)
  306. }
  307. }
  308. }
  309. func TestMapString(t *testing.T) {
  310. m := Map{}
  311. m.Set(key.Path{}, 0)
  312. m.Set(key.Path{key.New("foo"), key.New("bar")}, 1)
  313. m.Set(key.Path{key.New("foo"), key.New("quux")}, 2)
  314. m.Set(key.Path{key.New("foo"), Wildcard}, 3)
  315. expected := `Val: 0
  316. Child "foo":
  317. Child "*":
  318. Val: 3
  319. Child "bar":
  320. Val: 1
  321. Child "quux":
  322. Val: 2
  323. `
  324. got := fmt.Sprint(&m)
  325. if expected != got {
  326. t.Errorf("Unexpected string. Expected:\n\n%s\n\nGot:\n\n%s", expected, got)
  327. }
  328. }
  329. func genWords(count, wordLength int) key.Path {
  330. chars := []byte("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
  331. if count+wordLength > len(chars) {
  332. panic("need more chars")
  333. }
  334. result := make(key.Path, count)
  335. for i := 0; i < count; i++ {
  336. result[i] = key.New(string(chars[i : i+wordLength]))
  337. }
  338. return result
  339. }
  340. func benchmarkPathMap(pathLength, pathDepth int, b *testing.B) {
  341. // Push pathDepth paths, each of length pathLength
  342. path := genWords(pathLength, 10)
  343. words := genWords(pathDepth, 10)
  344. m := &Map{}
  345. for _, element := range path {
  346. m.children = map[key.Key]*Map{}
  347. for _, word := range words {
  348. m.children[word] = &Map{}
  349. }
  350. m = m.children[element]
  351. }
  352. b.ResetTimer()
  353. for i := 0; i < b.N; i++ {
  354. m.Visit(path, func(v interface{}) error { return nil })
  355. }
  356. }
  357. func BenchmarkPathMap1x25(b *testing.B) { benchmarkPathMap(1, 25, b) }
  358. func BenchmarkPathMap10x50(b *testing.B) { benchmarkPathMap(10, 25, b) }
  359. func BenchmarkPathMap20x50(b *testing.B) { benchmarkPathMap(20, 25, b) }