path_test.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  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. "fmt"
  7. "testing"
  8. "notabug.org/themusicgod1/goarista/key"
  9. "notabug.org/themusicgod1/goarista/value"
  10. )
  11. func TestNew(t *testing.T) {
  12. tcases := []struct {
  13. in []interface{}
  14. out key.Path
  15. }{
  16. {
  17. in: nil,
  18. out: key.Path{},
  19. }, {
  20. in: []interface{}{},
  21. out: key.Path{},
  22. }, {
  23. in: []interface{}{"foo", key.New("bar"), true},
  24. out: key.Path{key.New("foo"), key.New("bar"), key.New(true)},
  25. }, {
  26. in: []interface{}{int8(5), int16(5), int32(5), int64(5)},
  27. out: key.Path{key.New(int8(5)), key.New(int16(5)), key.New(int32(5)),
  28. key.New(int64(5))},
  29. }, {
  30. in: []interface{}{uint8(5), uint16(5), uint32(5), uint64(5)},
  31. out: key.Path{key.New(uint8(5)), key.New(uint16(5)), key.New(uint32(5)),
  32. key.New(uint64(5))},
  33. }, {
  34. in: []interface{}{float32(5), float64(5)},
  35. out: key.Path{key.New(float32(5)), key.New(float64(5))},
  36. }, {
  37. in: []interface{}{customKey{i: &a}, map[string]interface{}{}},
  38. out: key.Path{key.New(customKey{i: &a}), key.New(map[string]interface{}{})},
  39. },
  40. }
  41. for i, tcase := range tcases {
  42. if p := New(tcase.in...); !Equal(p, tcase.out) {
  43. t.Fatalf("Test %d failed: %#v != %#v", i, p, tcase.out)
  44. }
  45. }
  46. }
  47. func TestClone(t *testing.T) {
  48. if !Equal(Clone(key.Path{}), key.Path{}) {
  49. t.Error("Clone(key.Path{}) != key.Path{}")
  50. }
  51. a := key.Path{key.New("foo"), key.New("bar")}
  52. b, c := Clone(a), Clone(a)
  53. b[1] = key.New("baz")
  54. if Equal(a, b) || !Equal(a, c) {
  55. t.Error("Clone is not making a copied path")
  56. }
  57. }
  58. func TestAppend(t *testing.T) {
  59. tcases := []struct {
  60. a key.Path
  61. b []interface{}
  62. result key.Path
  63. }{
  64. {
  65. a: key.Path{},
  66. b: []interface{}{},
  67. result: key.Path{},
  68. }, {
  69. a: key.Path{key.New("foo")},
  70. b: []interface{}{},
  71. result: key.Path{key.New("foo")},
  72. }, {
  73. a: key.Path{},
  74. b: []interface{}{"foo", key.New("bar")},
  75. result: key.Path{key.New("foo"), key.New("bar")},
  76. }, {
  77. a: key.Path{key.New("foo")},
  78. b: []interface{}{int64(0), key.New("bar")},
  79. result: key.Path{key.New("foo"), key.New(int64(0)), key.New("bar")},
  80. },
  81. }
  82. for i, tcase := range tcases {
  83. if p := Append(tcase.a, tcase.b...); !Equal(p, tcase.result) {
  84. t.Fatalf("Test %d failed: %#v != %#v", i, p, tcase.result)
  85. }
  86. }
  87. }
  88. func TestJoin(t *testing.T) {
  89. tcases := []struct {
  90. paths []key.Path
  91. result key.Path
  92. }{
  93. {
  94. paths: nil,
  95. result: nil,
  96. }, {
  97. paths: []key.Path{},
  98. result: nil,
  99. }, {
  100. paths: []key.Path{key.Path{}},
  101. result: nil,
  102. }, {
  103. paths: []key.Path{key.Path{key.New(true)}, key.Path{}},
  104. result: key.Path{key.New(true)},
  105. }, {
  106. paths: []key.Path{key.Path{}, key.Path{key.New(true)}},
  107. result: key.Path{key.New(true)},
  108. }, {
  109. paths: []key.Path{key.Path{key.New("foo")}, key.Path{key.New("bar")}},
  110. result: key.Path{key.New("foo"), key.New("bar")},
  111. }, {
  112. paths: []key.Path{key.Path{key.New("bar")}, key.Path{key.New("foo")}},
  113. result: key.Path{key.New("bar"), key.New("foo")},
  114. }, {
  115. paths: []key.Path{
  116. key.Path{key.New(uint32(0)), key.New(uint64(0))},
  117. key.Path{key.New(int8(0))},
  118. key.Path{key.New(int16(0)), key.New(int32(0))},
  119. key.Path{key.New(int64(0)), key.New(uint8(0)), key.New(uint16(0))},
  120. },
  121. result: key.Path{
  122. key.New(uint32(0)), key.New(uint64(0)),
  123. key.New(int8(0)), key.New(int16(0)),
  124. key.New(int32(0)), key.New(int64(0)),
  125. key.New(uint8(0)), key.New(uint16(0)),
  126. },
  127. },
  128. }
  129. for i, tcase := range tcases {
  130. if p := Join(tcase.paths...); !Equal(p, tcase.result) {
  131. t.Fatalf("Test %d failed: %#v != %#v", i, p, tcase.result)
  132. }
  133. }
  134. }
  135. func TestParent(t *testing.T) {
  136. if Parent(key.Path{}) != nil {
  137. t.Fatal("Parent of empty key.Path should be nil")
  138. }
  139. tcases := []struct {
  140. in key.Path
  141. out key.Path
  142. }{
  143. {
  144. in: key.Path{key.New("foo")},
  145. out: key.Path{},
  146. }, {
  147. in: key.Path{key.New("foo"), key.New("bar")},
  148. out: key.Path{key.New("foo")},
  149. }, {
  150. in: key.Path{key.New("foo"), key.New("bar"), key.New("baz")},
  151. out: key.Path{key.New("foo"), key.New("bar")},
  152. },
  153. }
  154. for _, tcase := range tcases {
  155. if !Equal(Parent(tcase.in), tcase.out) {
  156. t.Fatalf("Parent of %#v != %#v", tcase.in, tcase.out)
  157. }
  158. }
  159. }
  160. func TestBase(t *testing.T) {
  161. if Base(key.Path{}) != nil {
  162. t.Fatal("Base of empty key.Path should be nil")
  163. }
  164. tcases := []struct {
  165. in key.Path
  166. out key.Key
  167. }{
  168. {
  169. in: key.Path{key.New("foo")},
  170. out: key.New("foo"),
  171. }, {
  172. in: key.Path{key.New("foo"), key.New("bar")},
  173. out: key.New("bar"),
  174. },
  175. }
  176. for _, tcase := range tcases {
  177. if !Base(tcase.in).Equal(tcase.out) {
  178. t.Fatalf("Base of %#v != %#v", tcase.in, tcase.out)
  179. }
  180. }
  181. }
  182. type customKey struct {
  183. i *int
  184. }
  185. func (c customKey) String() string {
  186. return fmt.Sprintf("customKey=%d", *c.i)
  187. }
  188. func (c customKey) MarshalJSON() ([]byte, error) {
  189. return nil, nil
  190. }
  191. func (c customKey) ToBuiltin() interface{} {
  192. return nil
  193. }
  194. func (c customKey) Equal(other interface{}) bool {
  195. o, ok := other.(customKey)
  196. return ok && *c.i == *o.i
  197. }
  198. var (
  199. _ value.Value = customKey{}
  200. _ key.Comparable = customKey{}
  201. a = 1
  202. b = 1
  203. )
  204. func TestEqual(t *testing.T) {
  205. tcases := []struct {
  206. a key.Path
  207. b key.Path
  208. result bool
  209. }{
  210. {
  211. a: nil,
  212. b: nil,
  213. result: true,
  214. }, {
  215. a: nil,
  216. b: key.Path{},
  217. result: true,
  218. }, {
  219. a: key.Path{},
  220. b: nil,
  221. result: true,
  222. }, {
  223. a: key.Path{},
  224. b: key.Path{},
  225. result: true,
  226. }, {
  227. a: key.Path{},
  228. b: key.Path{key.New("")},
  229. result: false,
  230. }, {
  231. a: key.Path{Wildcard},
  232. b: key.Path{key.New("foo")},
  233. result: false,
  234. }, {
  235. a: key.Path{Wildcard},
  236. b: key.Path{Wildcard},
  237. result: true,
  238. }, {
  239. a: key.Path{key.New("foo")},
  240. b: key.Path{key.New("foo")},
  241. result: true,
  242. }, {
  243. a: key.Path{key.New(true)},
  244. b: key.Path{key.New(false)},
  245. result: false,
  246. }, {
  247. a: key.Path{key.New(int32(5))},
  248. b: key.Path{key.New(int64(5))},
  249. result: false,
  250. }, {
  251. a: key.Path{key.New("foo")},
  252. b: key.Path{key.New("foo"), key.New("bar")},
  253. result: false,
  254. }, {
  255. a: key.Path{key.New("foo"), key.New("bar")},
  256. b: key.Path{key.New("foo")},
  257. result: false,
  258. }, {
  259. a: key.Path{key.New(uint8(0)), key.New(int8(0))},
  260. b: key.Path{key.New(int8(0)), key.New(uint8(0))},
  261. result: false,
  262. },
  263. // Ensure that we check deep equality.
  264. {
  265. a: key.Path{key.New(map[string]interface{}{})},
  266. b: key.Path{key.New(map[string]interface{}{})},
  267. result: true,
  268. }, {
  269. a: key.Path{key.New(customKey{i: &a})},
  270. b: key.Path{key.New(customKey{i: &b})},
  271. result: true,
  272. },
  273. }
  274. for i, tcase := range tcases {
  275. if result := Equal(tcase.a, tcase.b); result != tcase.result {
  276. t.Fatalf("Test %d failed: a: %#v; b: %#v, result: %t",
  277. i, tcase.a, tcase.b, tcase.result)
  278. }
  279. }
  280. }
  281. func TestMatch(t *testing.T) {
  282. tcases := []struct {
  283. a key.Path
  284. b key.Path
  285. result bool
  286. }{
  287. {
  288. a: nil,
  289. b: nil,
  290. result: true,
  291. }, {
  292. a: nil,
  293. b: key.Path{},
  294. result: true,
  295. }, {
  296. a: key.Path{},
  297. b: nil,
  298. result: true,
  299. }, {
  300. a: key.Path{},
  301. b: key.Path{},
  302. result: true,
  303. }, {
  304. a: key.Path{},
  305. b: key.Path{key.New("foo")},
  306. result: false,
  307. }, {
  308. a: key.Path{Wildcard},
  309. b: key.Path{key.New("foo")},
  310. result: true,
  311. }, {
  312. a: key.Path{key.New("foo")},
  313. b: key.Path{Wildcard},
  314. result: false,
  315. }, {
  316. a: key.Path{Wildcard},
  317. b: key.Path{key.New("foo"), key.New("bar")},
  318. result: false,
  319. }, {
  320. a: key.Path{Wildcard, Wildcard},
  321. b: key.Path{key.New(int64(0))},
  322. result: false,
  323. }, {
  324. a: key.Path{Wildcard, Wildcard},
  325. b: key.Path{key.New(int64(0)), key.New(int32(0))},
  326. result: true,
  327. }, {
  328. a: key.Path{Wildcard, key.New(false)},
  329. b: key.Path{key.New(true), Wildcard},
  330. result: false,
  331. },
  332. }
  333. for i, tcase := range tcases {
  334. if result := Match(tcase.a, tcase.b); result != tcase.result {
  335. t.Fatalf("Test %d failed: a: %#v; b: %#v, result: %t",
  336. i, tcase.a, tcase.b, tcase.result)
  337. }
  338. }
  339. }
  340. func TestHasElement(t *testing.T) {
  341. tcases := []struct {
  342. a key.Path
  343. b key.Key
  344. result bool
  345. }{
  346. {
  347. a: nil,
  348. b: nil,
  349. result: false,
  350. }, {
  351. a: nil,
  352. b: key.New("foo"),
  353. result: false,
  354. }, {
  355. a: key.Path{},
  356. b: nil,
  357. result: false,
  358. }, {
  359. a: key.Path{key.New("foo")},
  360. b: nil,
  361. result: false,
  362. }, {
  363. a: key.Path{key.New("foo")},
  364. b: key.New("foo"),
  365. result: true,
  366. }, {
  367. a: key.Path{key.New(true)},
  368. b: key.New("true"),
  369. result: false,
  370. }, {
  371. a: key.Path{key.New("foo"), key.New("bar")},
  372. b: key.New("bar"),
  373. result: true,
  374. }, {
  375. a: key.Path{key.New(map[string]interface{}{})},
  376. b: key.New(map[string]interface{}{}),
  377. result: true,
  378. }, {
  379. a: key.Path{key.New(map[string]interface{}{"foo": "a"})},
  380. b: key.New(map[string]interface{}{"bar": "a"}),
  381. result: false,
  382. },
  383. }
  384. for i, tcase := range tcases {
  385. if result := HasElement(tcase.a, tcase.b); result != tcase.result {
  386. t.Errorf("Test %d failed: a: %#v; b: %#v, result: %t, expected: %t",
  387. i, tcase.a, tcase.b, result, tcase.result)
  388. }
  389. }
  390. }
  391. func TestHasPrefix(t *testing.T) {
  392. tcases := []struct {
  393. a key.Path
  394. b key.Path
  395. result bool
  396. }{
  397. {
  398. a: nil,
  399. b: nil,
  400. result: true,
  401. }, {
  402. a: nil,
  403. b: key.Path{},
  404. result: true,
  405. }, {
  406. a: key.Path{},
  407. b: nil,
  408. result: true,
  409. }, {
  410. a: key.Path{},
  411. b: key.Path{},
  412. result: true,
  413. }, {
  414. a: key.Path{},
  415. b: key.Path{key.New("foo")},
  416. result: false,
  417. }, {
  418. a: key.Path{key.New("foo")},
  419. b: key.Path{},
  420. result: true,
  421. }, {
  422. a: key.Path{key.New(true)},
  423. b: key.Path{key.New(false)},
  424. result: false,
  425. }, {
  426. a: key.Path{key.New("foo"), key.New("bar")},
  427. b: key.Path{key.New("bar"), key.New("foo")},
  428. result: false,
  429. }, {
  430. a: key.Path{key.New(int8(0)), key.New(uint8(0))},
  431. b: key.Path{key.New(uint8(0)), key.New(uint8(0))},
  432. result: false,
  433. }, {
  434. a: key.Path{key.New(true), key.New(true)},
  435. b: key.Path{key.New(true), key.New(true), key.New(true)},
  436. result: false,
  437. }, {
  438. a: key.Path{key.New(true), key.New(true), key.New(true)},
  439. b: key.Path{key.New(true), key.New(true)},
  440. result: true,
  441. }, {
  442. a: key.Path{Wildcard, key.New(int32(0)), Wildcard},
  443. b: key.Path{key.New(int64(0)), Wildcard},
  444. result: false,
  445. },
  446. }
  447. for i, tcase := range tcases {
  448. if result := HasPrefix(tcase.a, tcase.b); result != tcase.result {
  449. t.Fatalf("Test %d failed: a: %#v; b: %#v, result: %t",
  450. i, tcase.a, tcase.b, tcase.result)
  451. }
  452. }
  453. }
  454. func TestMatchPrefix(t *testing.T) {
  455. tcases := []struct {
  456. a key.Path
  457. b key.Path
  458. result bool
  459. }{
  460. {
  461. a: nil,
  462. b: nil,
  463. result: true,
  464. }, {
  465. a: nil,
  466. b: key.Path{},
  467. result: true,
  468. }, {
  469. a: key.Path{},
  470. b: nil,
  471. result: true,
  472. }, {
  473. a: key.Path{},
  474. b: key.Path{},
  475. result: true,
  476. }, {
  477. a: key.Path{},
  478. b: key.Path{key.New("foo")},
  479. result: false,
  480. }, {
  481. a: key.Path{key.New("foo")},
  482. b: key.Path{},
  483. result: true,
  484. }, {
  485. a: key.Path{key.New("foo")},
  486. b: key.Path{Wildcard},
  487. result: false,
  488. }, {
  489. a: key.Path{Wildcard},
  490. b: key.Path{key.New("foo")},
  491. result: true,
  492. }, {
  493. a: key.Path{Wildcard},
  494. b: key.Path{key.New("foo"), key.New("bar")},
  495. result: false,
  496. }, {
  497. a: key.Path{Wildcard, key.New(true)},
  498. b: key.Path{key.New(false), Wildcard},
  499. result: false,
  500. }, {
  501. a: key.Path{Wildcard, key.New(int32(0)), key.New(int16(0))},
  502. b: key.Path{key.New(int64(0)), key.New(int32(0))},
  503. result: true,
  504. },
  505. }
  506. for i, tcase := range tcases {
  507. if result := MatchPrefix(tcase.a, tcase.b); result != tcase.result {
  508. t.Fatalf("Test %d failed: a: %#v; b: %#v, result: %t",
  509. i, tcase.a, tcase.b, tcase.result)
  510. }
  511. }
  512. }
  513. func TestFromString(t *testing.T) {
  514. tcases := []struct {
  515. in string
  516. out key.Path
  517. }{
  518. {
  519. in: "",
  520. out: key.Path{},
  521. }, {
  522. in: "/",
  523. out: key.Path{},
  524. }, {
  525. in: "//",
  526. out: key.Path{key.New(""), key.New("")},
  527. }, {
  528. in: "foo",
  529. out: key.Path{key.New("foo")},
  530. }, {
  531. in: "/foo",
  532. out: key.Path{key.New("foo")},
  533. }, {
  534. in: "foo/bar",
  535. out: key.Path{key.New("foo"), key.New("bar")},
  536. }, {
  537. in: "/foo/bar",
  538. out: key.Path{key.New("foo"), key.New("bar")},
  539. }, {
  540. in: "foo/bar/baz",
  541. out: key.Path{key.New("foo"), key.New("bar"), key.New("baz")},
  542. }, {
  543. in: "/foo/bar/baz",
  544. out: key.Path{key.New("foo"), key.New("bar"), key.New("baz")},
  545. }, {
  546. in: "0/123/456/789",
  547. out: key.Path{key.New("0"), key.New("123"), key.New("456"), key.New("789")},
  548. }, {
  549. in: "/0/123/456/789",
  550. out: key.Path{key.New("0"), key.New("123"), key.New("456"), key.New("789")},
  551. }, {
  552. in: "`~!@#$%^&*()_+{}\\/|[];':\"<>?,./",
  553. out: key.Path{key.New("`~!@#$%^&*()_+{}\\"), key.New("|[];':\"<>?,."), key.New("")},
  554. }, {
  555. in: "/`~!@#$%^&*()_+{}\\/|[];':\"<>?,./",
  556. out: key.Path{key.New("`~!@#$%^&*()_+{}\\"), key.New("|[];':\"<>?,."), key.New("")},
  557. },
  558. }
  559. for i, tcase := range tcases {
  560. if p := FromString(tcase.in); !Equal(p, tcase.out) {
  561. t.Fatalf("Test %d failed: %#v != %#v", i, p, tcase.out)
  562. }
  563. }
  564. }
  565. func TestString(t *testing.T) {
  566. tcases := []struct {
  567. in key.Path
  568. out string
  569. }{
  570. {
  571. in: key.Path{},
  572. out: "/",
  573. }, {
  574. in: key.Path{key.New("")},
  575. out: "/",
  576. }, {
  577. in: key.Path{key.New("foo")},
  578. out: "/foo",
  579. }, {
  580. in: key.Path{key.New("foo"), key.New("bar")},
  581. out: "/foo/bar",
  582. }, {
  583. in: key.Path{key.New("/foo"), key.New("bar")},
  584. out: "//foo/bar",
  585. }, {
  586. in: key.Path{key.New("foo"), key.New("bar/")},
  587. out: "/foo/bar/",
  588. }, {
  589. in: key.Path{key.New(""), key.New("foo"), key.New("bar")},
  590. out: "//foo/bar",
  591. }, {
  592. in: key.Path{key.New("foo"), key.New("bar"), key.New("")},
  593. out: "/foo/bar/",
  594. }, {
  595. in: key.Path{key.New("/"), key.New("foo"), key.New("bar")},
  596. out: "///foo/bar",
  597. }, {
  598. in: key.Path{key.New("foo"), key.New("bar"), key.New("/")},
  599. out: "/foo/bar//",
  600. },
  601. }
  602. for i, tcase := range tcases {
  603. if s := tcase.in.String(); s != tcase.out {
  604. t.Fatalf("Test %d failed: %s != %s", i, s, tcase.out)
  605. }
  606. }
  607. }
  608. func BenchmarkJoin(b *testing.B) {
  609. generate := func(n int) []key.Path {
  610. paths := make([]key.Path, 0, n)
  611. for i := 0; i < n; i++ {
  612. paths = append(paths, key.Path{key.New("foo")})
  613. }
  614. return paths
  615. }
  616. benchmarks := map[string][]key.Path{
  617. "10 key.Paths": generate(10),
  618. "100 key.Paths": generate(100),
  619. "1000 key.Paths": generate(1000),
  620. "10000 key.Paths": generate(10000),
  621. }
  622. for name, benchmark := range benchmarks {
  623. b.Run(name, func(b *testing.B) {
  624. for i := 0; i < b.N; i++ {
  625. Join(benchmark...)
  626. }
  627. })
  628. }
  629. }
  630. func BenchmarkHasElement(b *testing.B) {
  631. element := key.New("waldo")
  632. generate := func(n, loc int) key.Path {
  633. path := make(key.Path, n)
  634. for i := 0; i < n; i++ {
  635. if i == loc {
  636. path[i] = element
  637. } else {
  638. path[i] = key.New(int8(0))
  639. }
  640. }
  641. return path
  642. }
  643. benchmarks := map[string]key.Path{
  644. "10 Elements Index 0": generate(10, 0),
  645. "10 Elements Index 4": generate(10, 4),
  646. "10 Elements Index 9": generate(10, 9),
  647. "100 Elements Index 0": generate(100, 0),
  648. "100 Elements Index 49": generate(100, 49),
  649. "100 Elements Index 99": generate(100, 99),
  650. "1000 Elements Index 0": generate(1000, 0),
  651. "1000 Elements Index 499": generate(1000, 499),
  652. "1000 Elements Index 999": generate(1000, 999),
  653. }
  654. for name, benchmark := range benchmarks {
  655. b.Run(name, func(b *testing.B) {
  656. for i := 0; i < b.N; i++ {
  657. HasElement(benchmark, element)
  658. }
  659. })
  660. }
  661. }