key_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651
  1. // Copyright (c) 2015 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 key_test
  5. import (
  6. "encoding/json"
  7. "fmt"
  8. "strconv"
  9. "testing"
  10. . "notabug.org/themusicgod1/goarista/key"
  11. "notabug.org/themusicgod1/goarista/test"
  12. "notabug.org/themusicgod1/goarista/value"
  13. )
  14. type compareMe struct {
  15. i int
  16. }
  17. func (c compareMe) Equal(other interface{}) bool {
  18. o, ok := other.(compareMe)
  19. return ok && c == o
  20. }
  21. type customKey struct {
  22. i int
  23. }
  24. var _ value.Value = customKey{}
  25. func (c customKey) String() string {
  26. return fmt.Sprintf("customKey=%d", c.i)
  27. }
  28. func (c customKey) MarshalJSON() ([]byte, error) {
  29. return nil, nil
  30. }
  31. func (c customKey) ToBuiltin() interface{} {
  32. return c.i
  33. }
  34. func TestKeyEqual(t *testing.T) {
  35. tests := []struct {
  36. a Key
  37. b Key
  38. result bool
  39. }{{
  40. a: New("foo"),
  41. b: New("foo"),
  42. result: true,
  43. }, {
  44. a: New("foo"),
  45. b: New("bar"),
  46. result: false,
  47. }, {
  48. a: New([]interface{}{}),
  49. b: New("bar"),
  50. result: false,
  51. }, {
  52. a: New([]interface{}{}),
  53. b: New([]interface{}{}),
  54. result: true,
  55. }, {
  56. a: New([]interface{}{"a", "b"}),
  57. b: New([]interface{}{"a"}),
  58. result: false,
  59. }, {
  60. a: New([]interface{}{"a", "b"}),
  61. b: New([]interface{}{"b", "a"}),
  62. result: false,
  63. }, {
  64. a: New([]interface{}{"a", "b"}),
  65. b: New([]interface{}{"a", "b"}),
  66. result: true,
  67. }, {
  68. a: New([]interface{}{"a", map[string]interface{}{"b": "c"}}),
  69. b: New([]interface{}{"a", map[string]interface{}{"c": "b"}}),
  70. result: false,
  71. }, {
  72. a: New([]interface{}{"a", map[string]interface{}{"b": "c"}}),
  73. b: New([]interface{}{"a", map[string]interface{}{"b": "c"}}),
  74. result: true,
  75. }, {
  76. a: New(map[string]interface{}{}),
  77. b: New("bar"),
  78. result: false,
  79. }, {
  80. a: New(map[string]interface{}{}),
  81. b: New(map[string]interface{}{}),
  82. result: true,
  83. }, {
  84. a: New(map[string]interface{}{"a": 3}),
  85. b: New(map[string]interface{}{}),
  86. result: false,
  87. }, {
  88. a: New(map[string]interface{}{"a": 3}),
  89. b: New(map[string]interface{}{"b": 4}),
  90. result: false,
  91. }, {
  92. a: New(map[string]interface{}{"a": 4, "b": 5}),
  93. b: New(map[string]interface{}{"a": 4}),
  94. result: false,
  95. }, {
  96. a: New(map[string]interface{}{"a": 3}),
  97. b: New(map[string]interface{}{"a": 4}),
  98. result: false,
  99. }, {
  100. a: New(map[string]interface{}{"a": 3}),
  101. b: New(map[string]interface{}{"a": 3}),
  102. result: true,
  103. }, {
  104. a: New(map[string]interface{}{"a": map[Key]interface{}{New("b"): 3}}),
  105. b: New(map[string]interface{}{"a": map[Key]interface{}{New("b"): 4}}),
  106. result: false,
  107. }, {
  108. a: New(map[string]interface{}{"a": map[Key]interface{}{New("b"): 4, New("c"): 5}}),
  109. b: New(map[string]interface{}{"a": map[Key]interface{}{New("b"): 4}}),
  110. result: false,
  111. }, {
  112. a: New(map[string]interface{}{"a": map[Key]interface{}{New("b"): 4, New("c"): 5}}),
  113. b: New(map[string]interface{}{"a": map[Key]interface{}{New("b"): 4, New("c"): 5}}),
  114. result: true,
  115. }, {
  116. a: New(map[string]interface{}{"a": map[Key]interface{}{New("b"): 4}}),
  117. b: New(map[string]interface{}{"a": map[Key]interface{}{New("b"): 4}}),
  118. result: true,
  119. }, {
  120. a: New(map[string]interface{}{"a": compareMe{i: 3}}),
  121. b: New(map[string]interface{}{"a": compareMe{i: 3}}),
  122. result: true,
  123. }, {
  124. a: New(map[string]interface{}{"a": compareMe{i: 3}}),
  125. b: New(map[string]interface{}{"a": compareMe{i: 4}}),
  126. result: false,
  127. }, {
  128. a: New(customKey{i: 42}),
  129. b: New(customKey{i: 42}),
  130. result: true,
  131. }}
  132. for _, tcase := range tests {
  133. if tcase.a.Equal(tcase.b) != tcase.result {
  134. t.Errorf("Wrong result for case:\na: %#v\nb: %#v\nresult: %#v",
  135. tcase.a,
  136. tcase.b,
  137. tcase.result)
  138. }
  139. }
  140. if New("a").Equal(32) {
  141. t.Error("Wrong result for different types case")
  142. }
  143. }
  144. func TestGetFromMap(t *testing.T) {
  145. tests := []struct {
  146. k Key
  147. m map[Key]interface{}
  148. v interface{}
  149. found bool
  150. }{{
  151. k: New("a"),
  152. m: map[Key]interface{}{New("a"): "b"},
  153. v: "b",
  154. found: true,
  155. }, {
  156. k: New(uint32(35)),
  157. m: map[Key]interface{}{New(uint32(35)): "c"},
  158. v: "c",
  159. found: true,
  160. }, {
  161. k: New(uint32(37)),
  162. m: map[Key]interface{}{New(uint32(36)): "c"},
  163. found: false,
  164. }, {
  165. k: New(uint32(37)),
  166. m: map[Key]interface{}{},
  167. found: false,
  168. }, {
  169. k: New([]interface{}{"a", "b"}),
  170. m: map[Key]interface{}{
  171. New([]interface{}{"a", "b"}): "foo",
  172. },
  173. v: "foo",
  174. found: true,
  175. }, {
  176. k: New([]interface{}{"a", "b"}),
  177. m: map[Key]interface{}{
  178. New([]interface{}{"a", "b", "c"}): "foo",
  179. },
  180. found: false,
  181. }, {
  182. k: New([]interface{}{"a", map[string]interface{}{"b": "c"}}),
  183. m: map[Key]interface{}{
  184. New([]interface{}{"a", map[string]interface{}{"b": "c"}}): "foo",
  185. },
  186. v: "foo",
  187. found: true,
  188. }, {
  189. k: New([]interface{}{"a", map[string]interface{}{"b": "c"}}),
  190. m: map[Key]interface{}{
  191. New([]interface{}{"a", map[string]interface{}{"c": "b"}}): "foo",
  192. },
  193. found: false,
  194. }, {
  195. k: New(map[string]interface{}{"a": "b", "c": uint64(4)}),
  196. m: map[Key]interface{}{
  197. New(map[string]interface{}{"a": "b", "c": uint64(4)}): "foo",
  198. },
  199. v: "foo",
  200. found: true,
  201. }, {
  202. k: New(map[string]interface{}{"a": "b", "c": uint64(4)}),
  203. m: map[Key]interface{}{
  204. New(map[string]interface{}{"a": "b", "c": uint64(5)}): "foo",
  205. },
  206. found: false,
  207. }, {
  208. k: New(customKey{i: 42}),
  209. m: map[Key]interface{}{New(customKey{i: 42}): "c"},
  210. v: "c",
  211. found: true,
  212. }, {
  213. k: New(customKey{i: 42}),
  214. m: map[Key]interface{}{New(customKey{i: 43}): "c"},
  215. found: false,
  216. }, {
  217. k: New(map[string]interface{}{
  218. "damn": map[Key]interface{}{
  219. New(map[string]interface{}{"a": uint32(42),
  220. "b": uint32(51)}): true}}),
  221. m: map[Key]interface{}{
  222. New(map[string]interface{}{
  223. "damn": map[Key]interface{}{
  224. New(map[string]interface{}{"a": uint32(42),
  225. "b": uint32(51)}): true}}): "foo",
  226. },
  227. v: "foo",
  228. found: true,
  229. }, {
  230. k: New(map[string]interface{}{
  231. "damn": map[Key]interface{}{
  232. New(map[string]interface{}{"a": uint32(42),
  233. "b": uint32(52)}): true}}),
  234. m: map[Key]interface{}{
  235. New(map[string]interface{}{
  236. "damn": map[Key]interface{}{
  237. New(map[string]interface{}{"a": uint32(42),
  238. "b": uint32(51)}): true}}): "foo",
  239. },
  240. found: false,
  241. }, {
  242. k: New(map[string]interface{}{
  243. "nested": map[string]interface{}{
  244. "a": uint32(42), "b": uint32(51)}}),
  245. m: map[Key]interface{}{
  246. New(map[string]interface{}{
  247. "nested": map[string]interface{}{
  248. "a": uint32(42), "b": uint32(51)}}): "foo",
  249. },
  250. v: "foo",
  251. found: true,
  252. }, {
  253. k: New(map[string]interface{}{
  254. "nested": map[string]interface{}{
  255. "a": uint32(42), "b": uint32(52)}}),
  256. m: map[Key]interface{}{
  257. New(map[string]interface{}{
  258. "nested": map[string]interface{}{
  259. "a": uint32(42), "b": uint32(51)}}): "foo",
  260. },
  261. found: false,
  262. }}
  263. for _, tcase := range tests {
  264. v, ok := tcase.m[tcase.k]
  265. if tcase.found != ok {
  266. t.Errorf("Wrong retrieval result for case:\nk: %#v\nm: %#v\nv: %#v",
  267. tcase.k,
  268. tcase.m,
  269. tcase.v)
  270. } else if tcase.found && !ok {
  271. t.Errorf("Unable to retrieve value for case:\nk: %#v\nm: %#v\nv: %#v",
  272. tcase.k,
  273. tcase.m,
  274. tcase.v)
  275. } else if tcase.found && !test.DeepEqual(tcase.v, v) {
  276. t.Errorf("Wrong result for case:\nk: %#v\nm: %#v\nv: %#v",
  277. tcase.k,
  278. tcase.m,
  279. tcase.v)
  280. }
  281. }
  282. }
  283. func TestDeleteFromMap(t *testing.T) {
  284. tests := []struct {
  285. k Key
  286. m map[Key]interface{}
  287. r map[Key]interface{}
  288. }{{
  289. k: New("a"),
  290. m: map[Key]interface{}{New("a"): "b"},
  291. r: map[Key]interface{}{},
  292. }, {
  293. k: New("b"),
  294. m: map[Key]interface{}{New("a"): "b"},
  295. r: map[Key]interface{}{New("a"): "b"},
  296. }, {
  297. k: New("a"),
  298. m: map[Key]interface{}{},
  299. r: map[Key]interface{}{},
  300. }, {
  301. k: New(uint32(35)),
  302. m: map[Key]interface{}{New(uint32(35)): "c"},
  303. r: map[Key]interface{}{},
  304. }, {
  305. k: New(uint32(36)),
  306. m: map[Key]interface{}{New(uint32(35)): "c"},
  307. r: map[Key]interface{}{New(uint32(35)): "c"},
  308. }, {
  309. k: New(uint32(37)),
  310. m: map[Key]interface{}{},
  311. r: map[Key]interface{}{},
  312. }, {
  313. k: New(map[string]interface{}{"a": "b", "c": uint64(4)}),
  314. m: map[Key]interface{}{
  315. New(map[string]interface{}{"a": "b", "c": uint64(4)}): "foo",
  316. },
  317. r: map[Key]interface{}{},
  318. }, {
  319. k: New(customKey{i: 42}),
  320. m: map[Key]interface{}{New(customKey{i: 42}): "c"},
  321. r: map[Key]interface{}{},
  322. }}
  323. for _, tcase := range tests {
  324. delete(tcase.m, tcase.k)
  325. if !test.DeepEqual(tcase.m, tcase.r) {
  326. t.Errorf("Wrong result for case:\nk: %#v\nm: %#v\nr: %#v",
  327. tcase.k,
  328. tcase.m,
  329. tcase.r)
  330. }
  331. }
  332. }
  333. func TestSetToMap(t *testing.T) {
  334. tests := []struct {
  335. k Key
  336. v interface{}
  337. m map[Key]interface{}
  338. r map[Key]interface{}
  339. }{{
  340. k: New("a"),
  341. v: "c",
  342. m: map[Key]interface{}{New("a"): "b"},
  343. r: map[Key]interface{}{New("a"): "c"},
  344. }, {
  345. k: New("b"),
  346. v: uint64(56),
  347. m: map[Key]interface{}{New("a"): "b"},
  348. r: map[Key]interface{}{
  349. New("a"): "b",
  350. New("b"): uint64(56),
  351. },
  352. }, {
  353. k: New("a"),
  354. v: "foo",
  355. m: map[Key]interface{}{},
  356. r: map[Key]interface{}{New("a"): "foo"},
  357. }, {
  358. k: New(uint32(35)),
  359. v: "d",
  360. m: map[Key]interface{}{New(uint32(35)): "c"},
  361. r: map[Key]interface{}{New(uint32(35)): "d"},
  362. }, {
  363. k: New(uint32(36)),
  364. v: true,
  365. m: map[Key]interface{}{New(uint32(35)): "c"},
  366. r: map[Key]interface{}{
  367. New(uint32(35)): "c",
  368. New(uint32(36)): true,
  369. },
  370. }, {
  371. k: New(uint32(37)),
  372. v: false,
  373. m: map[Key]interface{}{New(uint32(36)): "c"},
  374. r: map[Key]interface{}{
  375. New(uint32(36)): "c",
  376. New(uint32(37)): false,
  377. },
  378. }, {
  379. k: New(uint32(37)),
  380. v: "foobar",
  381. m: map[Key]interface{}{},
  382. r: map[Key]interface{}{New(uint32(37)): "foobar"},
  383. }, {
  384. k: New(map[string]interface{}{"a": "b", "c": uint64(4)}),
  385. v: "foobar",
  386. m: map[Key]interface{}{
  387. New(map[string]interface{}{"a": "b", "c": uint64(4)}): "foo",
  388. },
  389. r: map[Key]interface{}{
  390. New(map[string]interface{}{"a": "b", "c": uint64(4)}): "foobar",
  391. },
  392. }, {
  393. k: New(map[string]interface{}{"a": "b", "c": uint64(7)}),
  394. v: "foobar",
  395. m: map[Key]interface{}{
  396. New(map[string]interface{}{"a": "b", "c": uint64(4)}): "foo",
  397. },
  398. r: map[Key]interface{}{
  399. New(map[string]interface{}{"a": "b", "c": uint64(4)}): "foo",
  400. New(map[string]interface{}{"a": "b", "c": uint64(7)}): "foobar",
  401. },
  402. }, {
  403. k: New(map[string]interface{}{"a": "b", "d": uint64(6)}),
  404. v: "barfoo",
  405. m: map[Key]interface{}{
  406. New(map[string]interface{}{"a": "b", "c": uint64(4)}): "foo",
  407. },
  408. r: map[Key]interface{}{
  409. New(map[string]interface{}{"a": "b", "c": uint64(4)}): "foo",
  410. New(map[string]interface{}{"a": "b", "d": uint64(6)}): "barfoo",
  411. },
  412. }, {
  413. k: New(customKey{i: 42}),
  414. v: "foo",
  415. m: map[Key]interface{}{},
  416. r: map[Key]interface{}{New(customKey{i: 42}): "foo"},
  417. }}
  418. for i, tcase := range tests {
  419. tcase.m[tcase.k] = tcase.v
  420. if !test.DeepEqual(tcase.m, tcase.r) {
  421. t.Errorf("Wrong result for case %d:\nk: %#v\nm: %#v\nr: %#v",
  422. i,
  423. tcase.k,
  424. tcase.m,
  425. tcase.r)
  426. }
  427. }
  428. }
  429. func TestMisc(t *testing.T) {
  430. k := New(map[string]interface{}{"foo": true})
  431. js, err := json.Marshal(k)
  432. if err != nil {
  433. t.Error("JSON encoding failed:", err)
  434. } else if expected := `{"foo":true}`; string(js) != expected {
  435. t.Errorf("Wanted JSON %q but got %q", expected, js)
  436. }
  437. expected := `key.New(map[string]interface {}{"foo":true})`
  438. gostr := fmt.Sprintf("%#v", k)
  439. if expected != gostr {
  440. t.Errorf("Wanted Go representation %q but got %q", expected, gostr)
  441. }
  442. test.ShouldPanic(t, func() { New(42) })
  443. k = New(customKey{i: 42})
  444. if expected, str := "customKey=42", k.String(); expected != str {
  445. t.Errorf("Wanted string representation %q but got %q", expected, str)
  446. }
  447. }
  448. func BenchmarkSetToMapWithStringKey(b *testing.B) {
  449. m := map[Key]interface{}{
  450. New("a"): true,
  451. New("a1"): true,
  452. New("a2"): true,
  453. New("a3"): true,
  454. New("a4"): true,
  455. New("a5"): true,
  456. New("a6"): true,
  457. New("a7"): true,
  458. New("a8"): true,
  459. New("a9"): true,
  460. New("a10"): true,
  461. New("a11"): true,
  462. New("a12"): true,
  463. New("a13"): true,
  464. New("a14"): true,
  465. New("a15"): true,
  466. New("a16"): true,
  467. New("a17"): true,
  468. New("a18"): true,
  469. }
  470. b.ReportAllocs()
  471. b.ResetTimer()
  472. for i := 0; i < b.N; i++ {
  473. m[New(strconv.Itoa(i))] = true
  474. }
  475. }
  476. func BenchmarkSetToMapWithUint64Key(b *testing.B) {
  477. m := map[Key]interface{}{
  478. New(uint64(1)): true,
  479. New(uint64(2)): true,
  480. New(uint64(3)): true,
  481. New(uint64(4)): true,
  482. New(uint64(5)): true,
  483. New(uint64(6)): true,
  484. New(uint64(7)): true,
  485. New(uint64(8)): true,
  486. New(uint64(9)): true,
  487. New(uint64(10)): true,
  488. New(uint64(11)): true,
  489. New(uint64(12)): true,
  490. New(uint64(13)): true,
  491. New(uint64(14)): true,
  492. New(uint64(15)): true,
  493. New(uint64(16)): true,
  494. New(uint64(17)): true,
  495. New(uint64(18)): true,
  496. New(uint64(19)): true,
  497. }
  498. b.ReportAllocs()
  499. b.ResetTimer()
  500. for i := 0; i < b.N; i++ {
  501. m[New(uint64(i))] = true
  502. }
  503. }
  504. func BenchmarkGetFromMapWithMapKey(b *testing.B) {
  505. m := map[Key]interface{}{
  506. New(map[string]interface{}{"a": true}): true,
  507. New(map[string]interface{}{"b": true}): true,
  508. New(map[string]interface{}{"c": true}): true,
  509. New(map[string]interface{}{"d": true}): true,
  510. New(map[string]interface{}{"e": true}): true,
  511. New(map[string]interface{}{"f": true}): true,
  512. New(map[string]interface{}{"g": true}): true,
  513. New(map[string]interface{}{"h": true}): true,
  514. New(map[string]interface{}{"i": true}): true,
  515. New(map[string]interface{}{"j": true}): true,
  516. New(map[string]interface{}{"k": true}): true,
  517. New(map[string]interface{}{"l": true}): true,
  518. New(map[string]interface{}{"m": true}): true,
  519. New(map[string]interface{}{"n": true}): true,
  520. New(map[string]interface{}{"o": true}): true,
  521. New(map[string]interface{}{"p": true}): true,
  522. New(map[string]interface{}{"q": true}): true,
  523. New(map[string]interface{}{"r": true}): true,
  524. New(map[string]interface{}{"s": true}): true,
  525. }
  526. b.ReportAllocs()
  527. b.ResetTimer()
  528. for i := 0; i < b.N; i++ {
  529. key := New(map[string]interface{}{string('a' + i%19): true})
  530. _, found := m[key]
  531. if !found {
  532. b.Fatalf("WTF: %#v", key)
  533. }
  534. }
  535. }
  536. func mkKey(i int) Key {
  537. return New(map[string]interface{}{
  538. "foo": map[string]interface{}{
  539. "aaaa1": uint32(0),
  540. "aaaa2": uint32(0),
  541. "aaaa3": uint32(i),
  542. },
  543. "bar": map[string]interface{}{
  544. "nested": uint32(42),
  545. },
  546. })
  547. }
  548. func BenchmarkBigMapWithCompositeKeys(b *testing.B) {
  549. const size = 10000
  550. m := make(map[Key]interface{}, size)
  551. for i := 0; i < size; i++ {
  552. m[mkKey(i)] = true
  553. }
  554. k := mkKey(0)
  555. submap := k.Key().(map[string]interface{})["foo"].(map[string]interface{})
  556. b.ResetTimer()
  557. for i := 0; i < b.N; i++ {
  558. submap["aaaa3"] = uint32(i)
  559. _, found := m[k]
  560. if found != (i < size) {
  561. b.Fatalf("WTF: %#v", k)
  562. }
  563. }
  564. }
  565. func BenchmarkBuiltInType(b *testing.B) {
  566. benches := []struct {
  567. val interface{}
  568. }{
  569. {
  570. val: "foo",
  571. },
  572. {
  573. val: int8(-12),
  574. },
  575. {
  576. val: int16(123),
  577. },
  578. {
  579. val: int32(123),
  580. },
  581. {
  582. val: int64(123456),
  583. },
  584. {
  585. val: uint8(12),
  586. },
  587. {
  588. val: uint16(123),
  589. },
  590. {
  591. val: uint32(123),
  592. },
  593. {
  594. val: uint64(123456),
  595. },
  596. {
  597. val: float32(123456.12),
  598. },
  599. {
  600. val: float64(123456.12),
  601. },
  602. {
  603. val: true,
  604. },
  605. }
  606. for _, bench := range benches {
  607. var k Key
  608. b.Run(fmt.Sprintf("%T", bench.val), func(b *testing.B) {
  609. b.ReportAllocs()
  610. for i := 0; i < b.N; i++ {
  611. // create the key.Key and call some function here
  612. if k = New(bench.val); k == nil {
  613. b.Fatalf("expect to get key.Key, but got nil")
  614. }
  615. if !k.Equal(New(bench.val)) {
  616. b.Fatalf("k is not equal to itself: %v", bench.val)
  617. }
  618. }
  619. })
  620. }
  621. }