github.com/aristanetworks/goarista@v0.0.0-20240514173732-cca2755bbd44/key/stringify_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
     6  
     7  import (
     8  	"fmt"
     9  	"math"
    10  	"testing"
    11  )
    12  
    13  func TestStringify(t *testing.T) {
    14  	testcases := []struct {
    15  		name   string
    16  		input  interface{}
    17  		output string // or expected panic error message.
    18  	}{{
    19  		name:   "nil",
    20  		input:  nil,
    21  		output: "<nil>",
    22  	}, {
    23  		name:   "struct{}",
    24  		input:  struct{}{},
    25  		output: "Unable to stringify type struct {}: struct {}{}",
    26  	}, {
    27  		name:   "string",
    28  		input:  "foobar",
    29  		output: "foobar",
    30  	}, {
    31  		name:   "valid non-ASCII UTF-8 string",
    32  		input:  "日本語",
    33  		output: "日本語",
    34  	}, {
    35  		name:   "invalid UTF-8 string 1",
    36  		input:  string([]byte{0xef, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe}),
    37  		output: "77++vr6+vg==",
    38  	}, {
    39  		name:   "invalid UTF-8 string 2",
    40  		input:  string([]byte{0xef, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x23}),
    41  		output: "77++vr6+viM=",
    42  	}, {
    43  		name:   "invalid UTF-8 string 3",
    44  		input:  string([]byte{0xef, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe, 0x23, 0x24}),
    45  		output: "77++vr6+viMk",
    46  	}, {
    47  		name:   "uint8",
    48  		input:  uint8(43),
    49  		output: "43",
    50  	}, {
    51  		name:   "uint16",
    52  		input:  uint16(43),
    53  		output: "43",
    54  	}, {
    55  		name:   "uint32",
    56  		input:  uint32(43),
    57  		output: "43",
    58  	}, {
    59  		name:   "uint64",
    60  		input:  uint64(43),
    61  		output: "43",
    62  	}, {
    63  		name:   "max uint64",
    64  		input:  uint64(math.MaxUint64),
    65  		output: "18446744073709551615",
    66  	}, {
    67  		name:   "int8",
    68  		input:  int8(-32),
    69  		output: "-32",
    70  	}, {
    71  		name:   "int16",
    72  		input:  int16(-32),
    73  		output: "-32",
    74  	}, {
    75  		name:   "int32",
    76  		input:  int32(-32),
    77  		output: "-32",
    78  	}, {
    79  		name:   "int64",
    80  		input:  int64(-32),
    81  		output: "-32",
    82  	}, {
    83  		name:   "true",
    84  		input:  true,
    85  		output: "true",
    86  	}, {
    87  		name:   "false",
    88  		input:  false,
    89  		output: "false",
    90  	}, {
    91  		name:   "float32",
    92  		input:  float32(2.345),
    93  		output: "f1075188859",
    94  	}, {
    95  		name:   "float64",
    96  		input:  float64(-34.6543),
    97  		output: "f-4593298060402564373",
    98  	}, {
    99  		name: "map[string]interface{}",
   100  		input: map[string]interface{}{
   101  			"b": uint32(43),
   102  			"a": "foobar",
   103  			"ex": map[string]interface{}{
   104  				"d": "barfoo",
   105  				"c": uint32(45),
   106  			},
   107  		},
   108  		output: "foobar_43_45_barfoo",
   109  	}, {
   110  		name: "nil inside map[string]interface{}",
   111  		input: map[string]interface{}{
   112  			"n": nil,
   113  		},
   114  		output: "<nil>",
   115  	}, {
   116  		name: "[]interface{}",
   117  		input: []interface{}{
   118  			uint32(42),
   119  			true,
   120  			"foo", NewMap(
   121  				New("a"), "b",
   122  				New("b"), "c"),
   123  		},
   124  		output: "42,true,foo,a=b_b=c",
   125  	}, {
   126  		name:   "pointer",
   127  		input:  NewPointer(Path{New("foo"), New("bar")}),
   128  		output: "{/foo/bar}",
   129  	}, {
   130  		name:   "[]byte",
   131  		input:  []byte{0x1},
   132  		output: "AQ==",
   133  	}, {
   134  		name:   "map with []byte",
   135  		input:  map[string]interface{}{"key1": []byte{0x1}, "key2": uint32(42)},
   136  		output: "AQ==_42",
   137  	}}
   138  
   139  	for _, tcase := range testcases {
   140  		// Pardon the contraption used to catch panic's in error cases.
   141  		func() {
   142  			defer func() {
   143  				if e := recover(); e != nil {
   144  					if tcase.output != e.(error).Error() {
   145  						t.Errorf("Test %s: Error returned: %q but wanted %q",
   146  							tcase.name, e, tcase.output)
   147  					}
   148  				}
   149  			}()
   150  
   151  			result := stringify(tcase.input)
   152  			if tcase.output != result {
   153  				t.Errorf("Test %s: Result is different\nReceived: %s\nExpected: %s",
   154  					tcase.name, result, tcase.output)
   155  			}
   156  			keyString := StringKey(New(tcase.input))
   157  			if tcase.output != keyString {
   158  				t.Errorf("Test %s: KeyString result is different\nReceived: %s\nExpected: %s",
   159  					tcase.name, keyString, tcase.output)
   160  			}
   161  		}()
   162  	}
   163  }
   164  
   165  var benchcases = []Key{
   166  	New(nil),
   167  	New("foobar"),
   168  	New(string([]byte{0xef, 0xbf, 0xbe, 0xbe, 0xbe, 0xbe, 0xbe})),
   169  	New(uint64(123456)),
   170  	New(int8(-32)),
   171  	New(true),
   172  	New(float32(2.345)),
   173  	New(float64(-34.6543)),
   174  	New(map[string]interface{}{
   175  		"b": uint32(43),
   176  		"a": "foobar",
   177  		"ex": map[string]interface{}{
   178  			"d": "barfoo",
   179  			"c": uint32(45),
   180  		},
   181  	}),
   182  	New([]interface{}{
   183  		uint32(42),
   184  		true,
   185  		"foo", NewMap(
   186  			New("a"), "b",
   187  			New("b"), "c"),
   188  	}),
   189  	New(NewPointer(Path{New("foo"), New("bar")})),
   190  }
   191  
   192  var str string
   193  
   194  func BenchmarkStringification(b *testing.B) {
   195  	for _, k := range benchcases {
   196  		b.Run(fmt.Sprintf("SI_%T", k.Key()), func(b *testing.B) {
   197  			b.ReportAllocs()
   198  			for i := 0; i < b.N; i++ {
   199  				str, _ = StringifyInterface(k.Key())
   200  			}
   201  		})
   202  		b.Run(fmt.Sprintf("SK_%T", k.Key()), func(b *testing.B) {
   203  			b.ReportAllocs()
   204  			for i := 0; i < b.N; i++ {
   205  				str = StringKey(k)
   206  			}
   207  		})
   208  	}
   209  }