github.com/philpearl/plenc@v0.0.15/plenccodec/map_test.go (about) 1 package plenccodec_test 2 3 import ( 4 "reflect" 5 "testing" 6 7 "github.com/google/go-cmp/cmp" 8 fuzz "github.com/google/gofuzz" 9 "github.com/philpearl/plenc" 10 ) 11 12 func TestMap(t *testing.T) { 13 one := 1 14 two := 2 15 16 type mk struct { 17 A int `plenc:"1"` 18 B int `plenc:"2"` 19 } 20 21 type thing struct { 22 M map[string]string `plenc:"1"` 23 I int `plenc:"2"` 24 } 25 26 tests := []struct { 27 name string 28 data interface{} 29 }{ 30 { 31 name: "string,string", 32 data: map[string]string{ 33 "hat": "hut", 34 "it": "sit", 35 }, 36 }, 37 { 38 name: "string,string empty", 39 data: map[string]string{}, 40 }, 41 { 42 name: "string,string empty strings", 43 data: map[string]string{ 44 "hat": "", 45 "it": "", 46 "": "elephant", 47 }, 48 }, 49 { 50 name: "string,int", 51 data: map[string]int{ 52 "hat": 0, 53 "it": 32, 54 }, 55 }, 56 { 57 name: "string,*int", 58 data: map[string]*int{ 59 "hat": nil, 60 "it": &one, 61 }, 62 }, 63 { 64 name: "string,*int", 65 data: map[string]*int{ 66 "hat": nil, 67 "it": &one, 68 "at": &two, 69 }, 70 }, 71 { 72 name: "string,*int just nil", 73 data: map[string]*int{ 74 "hat": nil, 75 }, 76 }, 77 { 78 name: "float,*int", 79 data: map[float32]*int{ 80 0: nil, 81 1.001: &one, 82 }, 83 }, 84 { 85 name: "struct,*int", 86 data: map[mk]*int{ 87 {A: 1, B: 7}: nil, 88 {A: 1, B: 3}: &one, 89 }, 90 }, 91 { 92 name: "nil map", 93 data: map[string]string(nil), 94 }, 95 { 96 name: "map in struct nil", 97 data: thing{}, 98 }, 99 { 100 name: "map in struct empty", 101 data: thing{M: map[string]string{}}, 102 }, 103 { 104 name: "map in struct", 105 data: thing{ 106 M: map[string]string{"A": "B"}, 107 }, 108 }, 109 { 110 name: "map in struct with following", 111 data: thing{ 112 M: map[string]string{"A": "B"}, 113 I: 100, 114 }, 115 }, 116 } 117 118 for _, test := range tests { 119 t.Run(test.name, func(t *testing.T) { 120 data, err := plenc.Marshal(nil, test.data) 121 if err != nil { 122 t.Fatal(err) 123 } 124 125 mv := reflect.New(reflect.TypeOf(test.data)) 126 if err := plenc.Unmarshal(data, mv.Interface()); err != nil { 127 t.Fatal(err) 128 } 129 130 if diff := cmp.Diff(test.data, mv.Elem().Interface()); diff != "" { 131 t.Fatalf("result differs: %s", diff) 132 } 133 }) 134 } 135 } 136 137 func TestMapZero(t *testing.T) { 138 // This matches the behaviour of the standard json package, but is different 139 // to unmarshalling into a struct where the struct is always zeroed first 140 m := map[string]string{"hat": "pineapple"} 141 n := map[string]string{"cheese": "monkey"} 142 data, err := plenc.Marshal(nil, n) 143 if err != nil { 144 t.Fatal(err) 145 } 146 if err := plenc.Unmarshal(data, &m); err != nil { 147 t.Fatal(err) 148 } 149 if diff := cmp.Diff(map[string]string{ 150 "hat": "pineapple", 151 "cheese": "monkey", 152 }, m); diff != "" { 153 t.Fatal(diff) 154 } 155 } 156 157 func TestMapFuzz(t *testing.T) { 158 fz := fuzz.New() 159 160 for i := 0; i < 100; i++ { 161 var in, out map[string]string 162 fz.Fuzz(&in) 163 164 data, err := plenc.Marshal(nil, in) 165 if err != nil { 166 t.Fatal(err) 167 } 168 169 if err := plenc.Unmarshal(data, &out); err != nil { 170 t.Fatal(err) 171 } 172 173 if diff := cmp.Diff(in, out); diff != "" { 174 t.Fatalf("result differs (%d): %s", i, diff) 175 } 176 } 177 } 178 179 func BenchmarkMap(b *testing.B) { 180 m := map[string]string{ 181 "AAA": "AAA", 182 "AAA1": "AAA", 183 "AAA2": "AAA", 184 "AAA3": "AAA", 185 "AAA4": "AAA", 186 "AAA5": "AAA", 187 "AAA6": "AAA", 188 "AAA7": "AAA", 189 } 190 191 b.ResetTimer() 192 b.ReportAllocs() 193 var data []byte 194 var o map[string]string 195 for i := 0; i < b.N; i++ { 196 var err error 197 data, err = plenc.Marshal(data[:0], m) 198 if err != nil { 199 b.Fatal(err) 200 } 201 for k := range o { 202 delete(o, k) 203 } 204 if err := plenc.Unmarshal(data, &o); err != nil { 205 b.Fatal(err) 206 } 207 } 208 }