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  }