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