github.com/urso/go-structform@v0.0.2/gotype/unfold_test.go (about) 1 package gotype 2 3 import ( 4 "bytes" 5 "fmt" 6 "testing" 7 8 "github.com/urso/go-structform/json" 9 ) 10 11 var unfoldSamples = []struct { 12 json string 13 input interface{} 14 value interface{} 15 }{ 16 17 // primitives 18 {`null`, nil, new(interface{})}, 19 {`""`, nil, new(string)}, 20 {`true`, true, new(bool)}, 21 {`true`, true, new(interface{})}, 22 {`false`, false, new(bool)}, 23 {`false`, false, new(interface{})}, 24 {`null`, nil, new(*int)}, 25 {`10`, int8(10), new(int8)}, 26 {`10`, int8(10), new(int)}, 27 {`10`, int8(10), new(*int8)}, 28 {`10`, int8(10), new(*int)}, 29 {`10`, int8(10), new(interface{})}, 30 {`10`, int32(10), new(int64)}, 31 {`10`, int32(10), new(int16)}, 32 {`10`, int32(10), new(interface{})}, 33 {`10`, int(10), new(int)}, 34 {`10`, int(10), new(uint)}, 35 {`10`, uint(10), new(uint)}, 36 {`10`, uint(10), new(uint16)}, 37 {`10`, uint(10), new(interface{})}, 38 {`10`, uint8(10), new(int)}, 39 {`10`, uint16(10), new(uint64)}, 40 {`10`, uint32(10), new(uint8)}, 41 {`12340`, uint16(12340), new(uint16)}, 42 {`12340`, uint16(12340), new(interface{})}, 43 {`1234567`, uint32(1234567), new(uint32)}, 44 {`1234567`, uint32(1234567), new(int64)}, 45 {`12345678190`, uint64(12345678190), new(uint64)}, 46 {`12345678190`, uint64(12345678190), new(int64)}, 47 {`-10`, int8(-10), new(int)}, 48 {`-10`, int8(-10), new(int8)}, 49 {`-10`, int8(-10), new(int32)}, 50 {`-10`, int8(-10), new(int64)}, 51 {`-10`, int8(-10), new(interface{})}, 52 {`3.14`, float32(3.14), new(float32)}, 53 {`3.14`, float32(3.14), new(interface{})}, 54 {`3.14`, float64(3.14), new(float32)}, 55 {`3.14`, float64(3.14), new(float64)}, 56 {`3.14`, float64(3.14), new(interface{})}, 57 {`"test"`, "test", new(string)}, 58 {`"test"`, "test", new(interface{})}, 59 {`"test with \" being escaped"`, "test with \" being escaped", new(string)}, 60 {`"test with \" being escaped"`, "test with \" being escaped", new(interface{})}, 61 62 // arrays 63 {`[]`, []uint8{}, new(interface{})}, 64 {`[]`, []uint8{}, new([]uint8)}, 65 {`[]`, []interface{}{}, new([]interface{})}, 66 // {`[]`, []interface{}{}, &[]struct{ A string }{}}, 67 {`[1,2,3]`, []uint8{1, 2, 3}, new(interface{})}, 68 {`[1,2,3]`, []uint8{1, 2, 3}, &[]uint8{0, 0, 0}}, 69 {`[1,2,3]`, []uint8{1, 2, 3}, &[]uint8{0, 0, 0, 4}}, 70 {`[1,2,3]`, []uint8{1, 2, 3}, &[]uint8{}}, 71 {`[1,2,3]`, []interface{}{1, 2, 3}, &[]uint8{}}, 72 {`[1,2,3]`, []interface{}{1, 2, 3}, new([]uint8)}, 73 {`[1,2,3]`, []int{1, 2, 3}, &[]interface{}{}}, 74 {`[1,2,3]`, []int{1, 2, 3}, &[]interface{}{nil, nil, nil, 4}}, 75 {`[1]`, []uint8{1}, &[]uint8{0, 2, 3}}, 76 {`[1,2]`, []uint8{1, 2}, &[]uint8{0, 0, 3}}, 77 {`[1,2]`, []interface{}{1, 2}, &[]uint{0, 0, 3}}, 78 {`[1,2]`, []interface{}{1, 2}, &[]interface{}{0, 0, 3}}, 79 {`["a","b"]`, []string{"a", "b"}, &[]interface{}{}}, 80 {`["a","b"]`, []string{"a", "b"}, &[]interface{}{nil, nil}}, 81 {`["a","b"]`, []string{"a", "b"}, &[]string{}}, 82 {`["a","b"]`, []string{"a", "b"}, new([]string)}, 83 {`[null,true,false,123,3.14,"test"]`, 84 []interface{}{nil, true, false, 123, 3.14, "test"}, 85 new(interface{})}, 86 {`[null,true,false,123,3.14,"test"]`, 87 []interface{}{nil, true, false, 123, 3.14, "test"}, 88 &[]interface{}{}}, 89 {`[1,2,3]`, []int{1, 2, 3}, &[]*int{}}, 90 {`[1,null,3]`, []interface{}{1, nil, 3}, &[]*int{}}, 91 92 // nested arrays 93 {`[[]]`, []interface{}{[]uint{}}, new(interface{})}, 94 {`[]`, []interface{}{}, &[]interface{}{[]interface{}{1}}}, 95 {`[]`, []interface{}{}, &[][]int{}}, 96 {`[]`, []interface{}{}, &[][]int{{1}}}, 97 {`[[1]]`, []interface{}{[]interface{}{1}}, &[][]int{}}, 98 {`[[1,2,3],[4,5,6]]`, 99 []interface{}{[]interface{}{1, 2, 3}, []interface{}{4, 5, 6}}, 100 new(interface{})}, 101 {`[[1],[4]]`, 102 []interface{}{[]interface{}{1}, []interface{}{4}}, 103 &[]interface{}{[]interface{}{0, 2, 3}}}, 104 {`[[1],[4],[6]]`, 105 []interface{}{[]interface{}{1}, []interface{}{4}, []interface{}{6}}, 106 &[]interface{}{ 107 []interface{}{0, 2, 3}, 108 []interface{}{0, 5}, 109 }}, 110 {`[[1],[4],[6]]`, 111 []interface{}{[]interface{}{1}, []interface{}{4}, []interface{}{6}}, 112 &[][]int{ 113 {0, 2, 3}, 114 {0, 5}, 115 }, 116 }, 117 118 // maps 119 {`{}`, map[string]interface{}{}, new(interface{})}, 120 {`{}`, map[string]interface{}{}, &map[string]interface{}{}}, 121 {`{"a":1}`, map[string]int{"a": 1}, new(interface{})}, 122 {`{"a":1}`, map[string]int{"a": 1}, &map[string]interface{}{}}, 123 {`{"a":1}`, map[string]int{"a": 1}, &map[string]interface{}{"a": 2}}, 124 {`{"a":1}`, map[string]int{"a": 1}, &map[string]int{}}, 125 {`{"a":1}`, map[string]int{"a": 1}, &map[string]int{"a": 2}}, 126 {`{"a":1}`, struct{ A int }{1}, &map[string]interface{}{}}, 127 {`{"a":1}`, struct{ A int }{1}, &map[string]int{}}, 128 {`{"a":1,"b":"b","c":true}`, 129 map[string]interface{}{"a": 1, "b": "b", "c": true}, 130 new(interface{}), 131 }, 132 133 // nested maps 134 {`{"a":{}}`, map[string]interface{}{"a": map[string]interface{}{}}, new(interface{})}, 135 {`{"a":{}}`, 136 map[string]interface{}{"a": map[string]interface{}{}}, 137 &map[string]interface{}{}}, 138 {`{"a":{}}`, 139 map[string]interface{}{"a": map[string]interface{}{}}, 140 &map[string]interface{}{"a": nil}}, 141 {`{"a":{}}`, 142 map[string]interface{}{"a": map[string]interface{}{}}, 143 &map[string]map[string]string{"a": nil}}, 144 {`{"0":{"a":1,"b":2,"c":3},"1":{"e":5,"f":6}}`, 145 map[string]map[string]int{ 146 "0": {"a": 1, "b": 2, "c": 3}, 147 "1": {"e": 5, "f": 6}, 148 }, 149 new(interface{})}, 150 {`{"0":{"a":1,"b":2,"c":3},"1":{"e":5,"f":6}}`, 151 map[string]map[string]int{ 152 "0": {"a": 1, "b": 2, "c": 3}, 153 "1": {"e": 5, "f": 6}, 154 }, 155 &map[string]interface{}{}}, 156 {`{"0":{"a":1,"b":2,"c":3},"1":{"e":5,"f":6}}`, 157 map[string]map[string]int{ 158 "0": {"a": 1, "b": 2, "c": 3}, 159 "1": {"e": 5, "f": 6}, 160 }, 161 &map[string]map[string]int64{}}, 162 {`{"0":{"a":1}}`, 163 map[string]map[string]int{ 164 "0": {"a": 1}, 165 }, 166 &map[string]interface{}{ 167 "0": map[string]int{"b": 2, "c": 3}, 168 }}, 169 {`{"0":{"a":1},"1":{"e":5}}`, 170 map[string]map[string]int{ 171 "0": {"a": 1}, 172 "1": {"e": 5}, 173 }, 174 &map[string]interface{}{ 175 "0": map[string]int{"b": 2, "c": 3}, 176 "1": map[string]interface{}{"f": 6, "e": 0}, 177 }}, 178 {`{"0":{"a":1},"1":{"e":5}}`, 179 map[string]map[string]int{ 180 "0": {"a": 1}, 181 "1": {"e": 5}, 182 }, 183 &map[string]map[string]uint{ 184 "0": {"b": 2, "c": 3}, 185 "1": {"f": 6, "e": 0}, 186 }}, 187 188 // map in array 189 {`[{}]`, []interface{}{map[string]interface{}{}}, new(interface{})}, 190 {`[{}]`, []interface{}{map[string]interface{}{}}, &[]map[string]int{}}, 191 {`[{"a":1}]`, []map[string]int{{"a": 1}}, new(interface{})}, 192 {`[{"a":1}]`, []map[string]int{{"a": 1}}, &[]interface{}{}}, 193 {`[{"a":1}]`, []map[string]int{{"a": 1}}, &[]map[string]interface{}{}}, 194 {`[{"a":1}]`, []map[string]int{{"a": 1}}, &[]map[string]interface{}{{"a": 2}}}, 195 {`[{"a":1,"b":2}]`, []map[string]int{{"a": 1}}, &[]map[string]int{{"b": 2}}}, 196 {`[{"a":1},{"b":2}]`, []map[string]int{{"a": 1}, {"b": 2}}, &[]map[string]int{}}, 197 {`[{"a":1},{"b":"b"},{"c":true}]`, 198 []map[string]interface{}{{"a": 1}, {"b": "b"}, {"c": true}}, 199 new(interface{})}, 200 201 // array in map 202 {`{"a": []}`, map[string]interface{}{"a": []int{}}, new(interface{})}, 203 {`{"a":[1,2],"b":[3]}`, map[string][]int{"a": {1, 2}, "b": {3}}, new(interface{})}, 204 {`{"a":[1,2],"b":[3]}`, map[string][]int{"a": {1, 2}, "b": {3}}, 205 &map[string][]int{}}, 206 {`{"a":[1,2],"b":[3,4,5]}`, map[string][]int{"a": {1, 2}, "b": {3, 4, 5}}, 207 &map[string][]int{"a": {0, 2}, "b": {0}}}, 208 209 // struct 210 {`{"a":1}`, map[string]int{"a": 1}, &struct{ A int }{}}, 211 {`{"a":1}`, map[string]int{"a": 1}, &struct{ A *int }{}}, 212 {`{"a": 1, "c": 2}`, map[string]int{"a": 1}, &struct{ A, b, C int }{b: 1, C: 2}}, 213 {`{"a": {"c": 2}, "b": 1}`, 214 map[string]interface{}{"a": map[string]int{"c": 2}}, 215 &struct { 216 A struct{ C int } 217 B int 218 }{B: 1}, 219 }, 220 {`{"a": 1}`, 221 map[string]interface{}{"a": 1}, 222 &struct { 223 S struct { 224 A int 225 } `struct:",inline"` 226 }{}, 227 }, 228 {`{"a":{"b":{"c":1}}}`, 229 map[string]interface{}{ 230 "a": map[string]interface{}{ 231 "b": map[string]int{ 232 "c": 1, 233 }, 234 }, 235 }, 236 &struct{ A struct{ B struct{ C int } } }{}, 237 }, 238 } 239 240 func TestFoldUnfoldConsistent(t *testing.T) { 241 tests := unfoldSamples 242 for i, test := range tests { 243 t.Logf("run test (%v): %v (%T -> %T)", i, test.json, test.input, test.value) 244 245 u, err := NewUnfolder(test.value) 246 if err != nil { 247 t.Errorf("NewUnfolder failed with: %v", err) 248 continue 249 } 250 251 if err := Fold(test.input, u); err != nil { 252 t.Errorf("Fold-Unfold failed with: %v", err) 253 continue 254 } 255 256 if st := &u.unfolder; len(st.stack) > 0 { 257 t.Errorf("Unfolder state stack not empty: %v, %v", st.stack, st.current) 258 continue 259 } 260 261 // serialize to json 262 var buf bytes.Buffer 263 if err := Fold(test.value, json.NewVisitor(&buf)); err != nil { 264 t.Errorf("serialize to json failed with: %v", err) 265 continue 266 } 267 268 // compare conversions did preserve type 269 assertJSON(t, test.json, buf.String()) 270 } 271 } 272 273 func TestUnfoldJsonInto(t *testing.T) { 274 tests := unfoldSamples 275 for i, test := range tests { 276 t.Logf("run test (%v): %v (%T -> %T)", i, test.json, test.input, test.value) 277 278 un, err := NewUnfolder(test.value) 279 if err != nil { 280 t.Fatal(err) 281 } 282 283 dec := json.NewParser(un) 284 input := test.json 285 286 err = dec.ParseString(input) 287 if err != nil { 288 t.Error(err) 289 continue 290 } 291 292 // check state valid by processing a second time 293 if err = un.SetTarget(test.value); err != nil { 294 t.Error(err) 295 continue 296 } 297 298 err = dec.ParseString(input) 299 if err != nil { 300 t.Error(err) 301 continue 302 } 303 } 304 } 305 306 func BenchmarkUnfoldJsonInto(b *testing.B) { 307 tests := unfoldSamples 308 for i, test := range tests { 309 name := fmt.Sprintf("%v (%T->%T)", test.json, test.input, test.value) 310 b.Logf("run test (%v): %v", i, name) 311 312 un, err := NewUnfolder(test.value) 313 if err != nil { 314 b.Fatal(err) 315 } 316 317 dec := json.NewParser(un) 318 input := test.json 319 // parse once to reset state for use of 'setTarget' in benchmark 320 if err := dec.ParseString(input); err != nil { 321 b.Error(err) 322 continue 323 } 324 325 b.Run(name, func(b *testing.B) { 326 for i := 0; i < b.N; i++ { 327 un.SetTarget(test.value) 328 err := dec.ParseString(input) 329 if err != nil { 330 b.Error(err) 331 } 332 333 } 334 }) 335 } 336 }