1
2
3
4
5 package json
6
7 import (
8 "bytes"
9 "encoding"
10 "errors"
11 "fmt"
12 "image"
13 "maps"
14 "math"
15 "math/big"
16 "net"
17 "reflect"
18 "slices"
19 "strconv"
20 "strings"
21 "testing"
22 "time"
23 )
24
25 type T struct {
26 X string
27 Y int
28 Z int `json:"-"`
29 }
30
31 type U struct {
32 Alphabet string `json:"alpha"`
33 }
34
35 type V struct {
36 F1 any
37 F2 int32
38 F3 Number
39 F4 *VOuter
40 }
41
42 type VOuter struct {
43 V V
44 }
45
46 type W struct {
47 S SS
48 }
49
50 type P struct {
51 PP PP
52 }
53
54 type PP struct {
55 T T
56 Ts []T
57 }
58
59 type SS string
60
61 func (*SS) UnmarshalJSON(data []byte) error {
62 return &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[SS]()}
63 }
64
65 type TAlias T
66
67 func (tt *TAlias) UnmarshalJSON(data []byte) error {
68 t := T{}
69 if err := Unmarshal(data, &t); err != nil {
70 return err
71 }
72 *tt = TAlias(t)
73 return nil
74 }
75
76 type TOuter struct {
77 T TAlias
78 }
79
80
81
82 var ifaceNumAsFloat64 = map[string]any{
83 "k1": float64(1),
84 "k2": "s",
85 "k3": []any{float64(1), float64(2.0), float64(3e-3)},
86 "k4": map[string]any{"kk1": "s", "kk2": float64(2)},
87 }
88
89 var ifaceNumAsNumber = map[string]any{
90 "k1": Number("1"),
91 "k2": "s",
92 "k3": []any{Number("1"), Number("2.0"), Number("3e-3")},
93 "k4": map[string]any{"kk1": "s", "kk2": Number("2")},
94 }
95
96 type tx struct {
97 x int
98 }
99
100 type u8 uint8
101
102
103
104 type unmarshaler struct {
105 T bool
106 }
107
108 func (u *unmarshaler) UnmarshalJSON(b []byte) error {
109 *u = unmarshaler{true}
110 return nil
111 }
112
113 type ustruct struct {
114 M unmarshaler
115 }
116
117 type unmarshalerText struct {
118 A, B string
119 }
120
121
122 func (u unmarshalerText) MarshalText() ([]byte, error) {
123 return []byte(u.A + ":" + u.B), nil
124 }
125
126 func (u *unmarshalerText) UnmarshalText(b []byte) error {
127 pos := bytes.IndexByte(b, ':')
128 if pos == -1 {
129 return errors.New("missing separator")
130 }
131 u.A, u.B = string(b[:pos]), string(b[pos+1:])
132 return nil
133 }
134
135 var _ encoding.TextUnmarshaler = (*unmarshalerText)(nil)
136
137 type ustructText struct {
138 M unmarshalerText
139 }
140
141
142 type u8marshal uint8
143
144 func (u8 u8marshal) MarshalText() ([]byte, error) {
145 return []byte(fmt.Sprintf("u%d", u8)), nil
146 }
147
148 var errMissingU8Prefix = errors.New("missing 'u' prefix")
149
150 func (u8 *u8marshal) UnmarshalText(b []byte) error {
151 if !bytes.HasPrefix(b, []byte{'u'}) {
152 return errMissingU8Prefix
153 }
154 n, err := strconv.Atoi(string(b[1:]))
155 if err != nil {
156 return err
157 }
158 *u8 = u8marshal(n)
159 return nil
160 }
161
162 var _ encoding.TextUnmarshaler = (*u8marshal)(nil)
163
164 var (
165 umtrue = unmarshaler{true}
166 umslice = []unmarshaler{{true}}
167 umstruct = ustruct{unmarshaler{true}}
168
169 umtrueXY = unmarshalerText{"x", "y"}
170 umsliceXY = []unmarshalerText{{"x", "y"}}
171 umstructXY = ustructText{unmarshalerText{"x", "y"}}
172
173 ummapXY = map[unmarshalerText]bool{{"x", "y"}: true}
174 )
175
176
177
178 type Point struct {
179 Z int
180 }
181
182 type Top struct {
183 Level0 int
184 Embed0
185 *Embed0a
186 *Embed0b `json:"e,omitempty"`
187 Embed0c `json:"-"`
188 Loop
189 Embed0p
190 Embed0q
191 embed
192 }
193
194 type Embed0 struct {
195 Level1a int
196 Level1b int
197 Level1c int
198 Level1d int
199 Level1e int `json:"x"`
200 }
201
202 type Embed0a struct {
203 Level1a int `json:"Level1a,omitempty"`
204 Level1b int `json:"LEVEL1B,omitempty"`
205 Level1c int `json:"-"`
206 Level1d int
207 Level1f int `json:"x"`
208 }
209
210 type Embed0b Embed0
211
212 type Embed0c Embed0
213
214 type Embed0p struct {
215 image.Point
216 }
217
218 type Embed0q struct {
219 Point
220 }
221
222 type embed struct {
223 Q int
224 }
225
226 type Loop struct {
227 Loop1 int `json:",omitempty"`
228 Loop2 int `json:",omitempty"`
229 *Loop
230 }
231
232
233
234 type S5 struct {
235 S6
236 S7
237 S8
238 }
239
240 type S6 struct {
241 X int
242 }
243
244 type S7 S6
245
246 type S8 struct {
247 S9
248 }
249
250 type S9 struct {
251 X int
252 Y int
253 }
254
255
256
257 type S10 struct {
258 S11
259 S12
260 S13
261 }
262
263 type S11 struct {
264 S6
265 }
266
267 type S12 struct {
268 S6
269 }
270
271 type S13 struct {
272 S8
273 }
274
275 type Ambig struct {
276
277 First int `json:"HELLO"`
278 Second int `json:"Hello"`
279 }
280
281 type XYZ struct {
282 X any
283 Y any
284 Z any
285 }
286
287 type unexportedWithMethods struct{}
288
289 func (unexportedWithMethods) F() {}
290
291 type byteWithMarshalJSON byte
292
293 func (b byteWithMarshalJSON) MarshalJSON() ([]byte, error) {
294 return []byte(fmt.Sprintf(`"Z%.2x"`, byte(b))), nil
295 }
296
297 func (b *byteWithMarshalJSON) UnmarshalJSON(data []byte) error {
298 if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' {
299 return fmt.Errorf("bad quoted string")
300 }
301 i, err := strconv.ParseInt(string(data[2:4]), 16, 8)
302 if err != nil {
303 return fmt.Errorf("bad hex")
304 }
305 *b = byteWithMarshalJSON(i)
306 return nil
307 }
308
309 type byteWithPtrMarshalJSON byte
310
311 func (b *byteWithPtrMarshalJSON) MarshalJSON() ([]byte, error) {
312 return byteWithMarshalJSON(*b).MarshalJSON()
313 }
314
315 func (b *byteWithPtrMarshalJSON) UnmarshalJSON(data []byte) error {
316 return (*byteWithMarshalJSON)(b).UnmarshalJSON(data)
317 }
318
319 type byteWithMarshalText byte
320
321 func (b byteWithMarshalText) MarshalText() ([]byte, error) {
322 return []byte(fmt.Sprintf(`Z%.2x`, byte(b))), nil
323 }
324
325 func (b *byteWithMarshalText) UnmarshalText(data []byte) error {
326 if len(data) != 3 || data[0] != 'Z' {
327 return fmt.Errorf("bad quoted string")
328 }
329 i, err := strconv.ParseInt(string(data[1:3]), 16, 8)
330 if err != nil {
331 return fmt.Errorf("bad hex")
332 }
333 *b = byteWithMarshalText(i)
334 return nil
335 }
336
337 type byteWithPtrMarshalText byte
338
339 func (b *byteWithPtrMarshalText) MarshalText() ([]byte, error) {
340 return byteWithMarshalText(*b).MarshalText()
341 }
342
343 func (b *byteWithPtrMarshalText) UnmarshalText(data []byte) error {
344 return (*byteWithMarshalText)(b).UnmarshalText(data)
345 }
346
347 type intWithMarshalJSON int
348
349 func (b intWithMarshalJSON) MarshalJSON() ([]byte, error) {
350 return []byte(fmt.Sprintf(`"Z%.2x"`, int(b))), nil
351 }
352
353 func (b *intWithMarshalJSON) UnmarshalJSON(data []byte) error {
354 if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' {
355 return fmt.Errorf("bad quoted string")
356 }
357 i, err := strconv.ParseInt(string(data[2:4]), 16, 8)
358 if err != nil {
359 return fmt.Errorf("bad hex")
360 }
361 *b = intWithMarshalJSON(i)
362 return nil
363 }
364
365 type intWithPtrMarshalJSON int
366
367 func (b *intWithPtrMarshalJSON) MarshalJSON() ([]byte, error) {
368 return intWithMarshalJSON(*b).MarshalJSON()
369 }
370
371 func (b *intWithPtrMarshalJSON) UnmarshalJSON(data []byte) error {
372 return (*intWithMarshalJSON)(b).UnmarshalJSON(data)
373 }
374
375 type intWithMarshalText int
376
377 func (b intWithMarshalText) MarshalText() ([]byte, error) {
378 return []byte(fmt.Sprintf(`Z%.2x`, int(b))), nil
379 }
380
381 func (b *intWithMarshalText) UnmarshalText(data []byte) error {
382 if len(data) != 3 || data[0] != 'Z' {
383 return fmt.Errorf("bad quoted string")
384 }
385 i, err := strconv.ParseInt(string(data[1:3]), 16, 8)
386 if err != nil {
387 return fmt.Errorf("bad hex")
388 }
389 *b = intWithMarshalText(i)
390 return nil
391 }
392
393 type intWithPtrMarshalText int
394
395 func (b *intWithPtrMarshalText) MarshalText() ([]byte, error) {
396 return intWithMarshalText(*b).MarshalText()
397 }
398
399 func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error {
400 return (*intWithMarshalText)(b).UnmarshalText(data)
401 }
402
403 type mapStringToStringData struct {
404 Data map[string]string `json:"data"`
405 }
406
407 type B struct {
408 B bool `json:",string"`
409 }
410
411 type DoublePtr struct {
412 I **int
413 J **int
414 }
415
416 var unmarshalTests = []struct {
417 CaseName
418 in string
419 ptr any
420 out any
421 err error
422 useNumber bool
423 golden bool
424 disallowUnknownFields bool
425 }{
426
427 {CaseName: Name(""), in: `true`, ptr: new(bool), out: true},
428 {CaseName: Name(""), in: `1`, ptr: new(int), out: 1},
429 {CaseName: Name(""), in: `1.2`, ptr: new(float64), out: 1.2},
430 {CaseName: Name(""), in: `-5`, ptr: new(int16), out: int16(-5)},
431 {CaseName: Name(""), in: `2`, ptr: new(Number), out: Number("2"), useNumber: true},
432 {CaseName: Name(""), in: `2`, ptr: new(Number), out: Number("2")},
433 {CaseName: Name(""), in: `2`, ptr: new(any), out: float64(2.0)},
434 {CaseName: Name(""), in: `2`, ptr: new(any), out: Number("2"), useNumber: true},
435 {CaseName: Name(""), in: `"a\u1234"`, ptr: new(string), out: "a\u1234"},
436 {CaseName: Name(""), in: `"http:\/\/"`, ptr: new(string), out: "http://"},
437 {CaseName: Name(""), in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"},
438 {CaseName: Name(""), in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},
439 {CaseName: Name(""), in: "null", ptr: new(any), out: nil},
440 {CaseName: Name(""), in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeFor[string](), 7, "T", "X"}},
441 {CaseName: Name(""), in: `{"X": 23}`, ptr: new(T), out: T{}, err: &UnmarshalTypeError{"number", reflect.TypeFor[string](), 8, "T", "X"}},
442 {CaseName: Name(""), in: `{"x": 1}`, ptr: new(tx), out: tx{}},
443 {CaseName: Name(""), in: `{"x": 1}`, ptr: new(tx), out: tx{}},
444 {CaseName: Name(""), in: `{"x": 1}`, ptr: new(tx), err: fmt.Errorf("json: unknown field \"x\""), disallowUnknownFields: true},
445 {CaseName: Name(""), in: `{"S": 23}`, ptr: new(W), out: W{}, err: &UnmarshalTypeError{"number", reflect.TypeFor[SS](), 0, "W", "S"}},
446 {CaseName: Name(""), in: `{"T": {"X": 23}}`, ptr: new(TOuter), out: TOuter{}, err: &UnmarshalTypeError{"number", reflect.TypeFor[string](), 8, "TOuter", "T.X"}},
447 {CaseName: Name(""), in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},
448 {CaseName: Name(""), in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},
449 {CaseName: Name(""), in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(any), out: ifaceNumAsFloat64},
450 {CaseName: Name(""), in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(any), out: ifaceNumAsNumber, useNumber: true},
451
452
453 {CaseName: Name(""), in: "\n true ", ptr: new(bool), out: true},
454 {CaseName: Name(""), in: "\t 1 ", ptr: new(int), out: 1},
455 {CaseName: Name(""), in: "\r 1.2 ", ptr: new(float64), out: 1.2},
456 {CaseName: Name(""), in: "\t -5 \n", ptr: new(int16), out: int16(-5)},
457 {CaseName: Name(""), in: "\t \"a\\u1234\" \n", ptr: new(string), out: "a\u1234"},
458
459
460 {CaseName: Name(""), in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}},
461 {CaseName: Name(""), in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}, err: fmt.Errorf("json: unknown field \"Z\""), disallowUnknownFields: true},
462
463 {CaseName: Name(""), in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}},
464 {CaseName: Name(""), in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}, err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true},
465 {CaseName: Name(""), in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}},
466 {CaseName: Name(""), in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}},
467 {CaseName: Name(""), in: `{"alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true},
468
469
470 {CaseName: Name(""), in: `{"X": "foo", "Y"}`, err: &SyntaxError{"invalid character '}' after object key", 17}},
471 {CaseName: Name(""), in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array element", 9}},
472 {CaseName: Name(""), in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true},
473 {CaseName: Name(""), in: `[2, 3`, err: &SyntaxError{msg: "unexpected end of JSON input", Offset: 5}},
474 {CaseName: Name(""), in: `{"F3": -}`, ptr: new(V), err: &SyntaxError{msg: "invalid character '}' in numeric literal", Offset: 9}},
475
476
477 {CaseName: Name(""), in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
478 {CaseName: Name(""), in: " 42 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 5}},
479 {CaseName: Name(""), in: "\x01 true", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
480 {CaseName: Name(""), in: " false \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 8}},
481 {CaseName: Name(""), in: "\x01 1.2", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
482 {CaseName: Name(""), in: " 3.4 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 6}},
483 {CaseName: Name(""), in: "\x01 \"string\"", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
484 {CaseName: Name(""), in: " \"string\" \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 11}},
485
486
487 {CaseName: Name(""), in: `[1, 2, 3]`, ptr: new([3]int), out: [3]int{1, 2, 3}},
488 {CaseName: Name(""), in: `[1, 2, 3]`, ptr: new([1]int), out: [1]int{1}},
489 {CaseName: Name(""), in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}},
490 {CaseName: Name(""), in: `[1, 2, 3]`, ptr: new(MustNotUnmarshalJSON), err: errors.New("MustNotUnmarshalJSON was used")},
491
492
493 {CaseName: Name(""), in: `[]`, ptr: new([]any), out: []any{}},
494 {CaseName: Name(""), in: `null`, ptr: new([]any), out: []any(nil)},
495 {CaseName: Name(""), in: `{"T":[]}`, ptr: new(map[string]any), out: map[string]any{"T": []any{}}},
496 {CaseName: Name(""), in: `{"T":null}`, ptr: new(map[string]any), out: map[string]any{"T": any(nil)}},
497
498
499 {CaseName: Name(""), in: allValueIndent, ptr: new(All), out: allValue},
500 {CaseName: Name(""), in: allValueCompact, ptr: new(All), out: allValue},
501 {CaseName: Name(""), in: allValueIndent, ptr: new(*All), out: &allValue},
502 {CaseName: Name(""), in: allValueCompact, ptr: new(*All), out: &allValue},
503 {CaseName: Name(""), in: pallValueIndent, ptr: new(All), out: pallValue},
504 {CaseName: Name(""), in: pallValueCompact, ptr: new(All), out: pallValue},
505 {CaseName: Name(""), in: pallValueIndent, ptr: new(*All), out: &pallValue},
506 {CaseName: Name(""), in: pallValueCompact, ptr: new(*All), out: &pallValue},
507
508
509 {CaseName: Name(""), in: `{"T":false}`, ptr: new(unmarshaler), out: umtrue},
510 {CaseName: Name(""), in: `{"T":false}`, ptr: new(*unmarshaler), out: &umtrue},
511 {CaseName: Name(""), in: `[{"T":false}]`, ptr: new([]unmarshaler), out: umslice},
512 {CaseName: Name(""), in: `[{"T":false}]`, ptr: new(*[]unmarshaler), out: &umslice},
513 {CaseName: Name(""), in: `{"M":{"T":"x:y"}}`, ptr: new(ustruct), out: umstruct},
514
515
516 {CaseName: Name(""), in: `"x:y"`, ptr: new(unmarshalerText), out: umtrueXY},
517 {CaseName: Name(""), in: `"x:y"`, ptr: new(*unmarshalerText), out: &umtrueXY},
518 {CaseName: Name(""), in: `["x:y"]`, ptr: new([]unmarshalerText), out: umsliceXY},
519 {CaseName: Name(""), in: `["x:y"]`, ptr: new(*[]unmarshalerText), out: &umsliceXY},
520 {CaseName: Name(""), in: `{"M":"x:y"}`, ptr: new(ustructText), out: umstructXY},
521
522
523 {
524 CaseName: Name(""),
525 in: `{"-1":"a","0":"b","1":"c"}`,
526 ptr: new(map[int]string),
527 out: map[int]string{-1: "a", 0: "b", 1: "c"},
528 },
529 {
530 CaseName: Name(""),
531 in: `{"0":"a","10":"c","9":"b"}`,
532 ptr: new(map[u8]string),
533 out: map[u8]string{0: "a", 9: "b", 10: "c"},
534 },
535 {
536 CaseName: Name(""),
537 in: `{"-9223372036854775808":"min","9223372036854775807":"max"}`,
538 ptr: new(map[int64]string),
539 out: map[int64]string{math.MinInt64: "min", math.MaxInt64: "max"},
540 },
541 {
542 CaseName: Name(""),
543 in: `{"18446744073709551615":"max"}`,
544 ptr: new(map[uint64]string),
545 out: map[uint64]string{math.MaxUint64: "max"},
546 },
547 {
548 CaseName: Name(""),
549 in: `{"0":false,"10":true}`,
550 ptr: new(map[uintptr]bool),
551 out: map[uintptr]bool{0: false, 10: true},
552 },
553
554
555
556 {
557 CaseName: Name(""),
558 in: `{"u2":4}`,
559 ptr: new(map[u8marshal]int),
560 out: map[u8marshal]int{2: 4},
561 },
562 {
563 CaseName: Name(""),
564 in: `{"2":4}`,
565 ptr: new(map[u8marshal]int),
566 out: map[u8marshal]int{},
567 err: errMissingU8Prefix,
568 },
569
570
571 {
572 CaseName: Name(""),
573 in: `{"abc":"abc"}`,
574 ptr: new(map[int]string),
575 out: map[int]string{},
576 err: &UnmarshalTypeError{Value: "number abc", Type: reflect.TypeFor[int](), Offset: 2},
577 },
578 {
579 CaseName: Name(""),
580 in: `{"256":"abc"}`,
581 ptr: new(map[uint8]string),
582 out: map[uint8]string{},
583 err: &UnmarshalTypeError{Value: "number 256", Type: reflect.TypeFor[uint8](), Offset: 2},
584 },
585 {
586 CaseName: Name(""),
587 in: `{"128":"abc"}`,
588 ptr: new(map[int8]string),
589 out: map[int8]string{},
590 err: &UnmarshalTypeError{Value: "number 128", Type: reflect.TypeFor[int8](), Offset: 2},
591 },
592 {
593 CaseName: Name(""),
594 in: `{"-1":"abc"}`,
595 ptr: new(map[uint8]string),
596 out: map[uint8]string{},
597 err: &UnmarshalTypeError{Value: "number -1", Type: reflect.TypeFor[uint8](), Offset: 2},
598 },
599 {
600 CaseName: Name(""),
601 in: `{"F":{"a":2,"3":4}}`,
602 ptr: new(map[string]map[int]int),
603 out: map[string]map[int]int{"F": {3: 4}},
604 err: &UnmarshalTypeError{Value: "number a", Type: reflect.TypeFor[int](), Offset: 7},
605 },
606 {
607 CaseName: Name(""),
608 in: `{"F":{"a":2,"3":4}}`,
609 ptr: new(map[string]map[uint]int),
610 out: map[string]map[uint]int{"F": {3: 4}},
611 err: &UnmarshalTypeError{Value: "number a", Type: reflect.TypeFor[uint](), Offset: 7},
612 },
613
614
615 {CaseName: Name(""), in: `{"x:y":true}`, ptr: new(map[unmarshalerText]bool), out: ummapXY},
616
617 {CaseName: Name(""), in: `{"x:y":false,"x:y":true}`, ptr: new(map[unmarshalerText]bool), out: ummapXY},
618
619 {
620 CaseName: Name(""),
621 in: `{
622 "Level0": 1,
623 "Level1b": 2,
624 "Level1c": 3,
625 "x": 4,
626 "Level1a": 5,
627 "LEVEL1B": 6,
628 "e": {
629 "Level1a": 8,
630 "Level1b": 9,
631 "Level1c": 10,
632 "Level1d": 11,
633 "x": 12
634 },
635 "Loop1": 13,
636 "Loop2": 14,
637 "X": 15,
638 "Y": 16,
639 "Z": 17,
640 "Q": 18
641 }`,
642 ptr: new(Top),
643 out: Top{
644 Level0: 1,
645 Embed0: Embed0{
646 Level1b: 2,
647 Level1c: 3,
648 },
649 Embed0a: &Embed0a{
650 Level1a: 5,
651 Level1b: 6,
652 },
653 Embed0b: &Embed0b{
654 Level1a: 8,
655 Level1b: 9,
656 Level1c: 10,
657 Level1d: 11,
658 Level1e: 12,
659 },
660 Loop: Loop{
661 Loop1: 13,
662 Loop2: 14,
663 },
664 Embed0p: Embed0p{
665 Point: image.Point{X: 15, Y: 16},
666 },
667 Embed0q: Embed0q{
668 Point: Point{Z: 17},
669 },
670 embed: embed{
671 Q: 18,
672 },
673 },
674 },
675 {
676 CaseName: Name(""),
677 in: `{"hello": 1}`,
678 ptr: new(Ambig),
679 out: Ambig{First: 1},
680 },
681
682 {
683 CaseName: Name(""),
684 in: `{"X": 1,"Y":2}`,
685 ptr: new(S5),
686 out: S5{S8: S8{S9: S9{Y: 2}}},
687 },
688 {
689 CaseName: Name(""),
690 in: `{"X": 1,"Y":2}`,
691 ptr: new(S5),
692 out: S5{S8: S8{S9{Y: 2}}},
693 err: fmt.Errorf("json: unknown field \"X\""),
694 disallowUnknownFields: true,
695 },
696 {
697 CaseName: Name(""),
698 in: `{"X": 1,"Y":2}`,
699 ptr: new(S10),
700 out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}},
701 },
702 {
703 CaseName: Name(""),
704 in: `{"X": 1,"Y":2}`,
705 ptr: new(S10),
706 out: S10{S13: S13{S8{S9{Y: 2}}}},
707 err: fmt.Errorf("json: unknown field \"X\""),
708 disallowUnknownFields: true,
709 },
710 {
711 CaseName: Name(""),
712 in: `{"I": 0, "I": null, "J": null}`,
713 ptr: new(DoublePtr),
714 out: DoublePtr{I: nil, J: nil},
715 },
716
717
718 {
719 CaseName: Name(""),
720 in: "\"hello\xffworld\"",
721 ptr: new(string),
722 out: "hello\ufffdworld",
723 },
724 {
725 CaseName: Name(""),
726 in: "\"hello\xc2\xc2world\"",
727 ptr: new(string),
728 out: "hello\ufffd\ufffdworld",
729 },
730 {
731 CaseName: Name(""),
732 in: "\"hello\xc2\xffworld\"",
733 ptr: new(string),
734 out: "hello\ufffd\ufffdworld",
735 },
736 {
737 CaseName: Name(""),
738 in: "\"hello\\ud800world\"",
739 ptr: new(string),
740 out: "hello\ufffdworld",
741 },
742 {
743 CaseName: Name(""),
744 in: "\"hello\\ud800\\ud800world\"",
745 ptr: new(string),
746 out: "hello\ufffd\ufffdworld",
747 },
748 {
749 CaseName: Name(""),
750 in: "\"hello\\ud800\\ud800world\"",
751 ptr: new(string),
752 out: "hello\ufffd\ufffdworld",
753 },
754 {
755 CaseName: Name(""),
756 in: "\"hello\xed\xa0\x80\xed\xb0\x80world\"",
757 ptr: new(string),
758 out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld",
759 },
760
761
762 {
763 CaseName: Name(""),
764 in: `{"2009-11-10T23:00:00Z": "hello world"}`,
765 ptr: new(map[time.Time]string),
766 out: map[time.Time]string{time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC): "hello world"},
767 },
768
769
770 {
771 CaseName: Name(""),
772 in: `{"2009-11-10T23:00:00Z": "hello world"}`,
773 ptr: new(map[Point]string),
774 err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeFor[map[Point]string](), Offset: 1},
775 },
776 {
777 CaseName: Name(""),
778 in: `{"asdf": "hello world"}`,
779 ptr: new(map[unmarshaler]string),
780 err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeFor[map[unmarshaler]string](), Offset: 1},
781 },
782
783
784
785
786
787
788
789
790 {
791 CaseName: Name(""),
792 in: `"AQID"`,
793 ptr: new([]byteWithMarshalJSON),
794 out: []byteWithMarshalJSON{1, 2, 3},
795 },
796 {
797 CaseName: Name(""),
798 in: `["Z01","Z02","Z03"]`,
799 ptr: new([]byteWithMarshalJSON),
800 out: []byteWithMarshalJSON{1, 2, 3},
801 golden: true,
802 },
803 {
804 CaseName: Name(""),
805 in: `"AQID"`,
806 ptr: new([]byteWithMarshalText),
807 out: []byteWithMarshalText{1, 2, 3},
808 },
809 {
810 CaseName: Name(""),
811 in: `["Z01","Z02","Z03"]`,
812 ptr: new([]byteWithMarshalText),
813 out: []byteWithMarshalText{1, 2, 3},
814 golden: true,
815 },
816 {
817 CaseName: Name(""),
818 in: `"AQID"`,
819 ptr: new([]byteWithPtrMarshalJSON),
820 out: []byteWithPtrMarshalJSON{1, 2, 3},
821 },
822 {
823 CaseName: Name(""),
824 in: `["Z01","Z02","Z03"]`,
825 ptr: new([]byteWithPtrMarshalJSON),
826 out: []byteWithPtrMarshalJSON{1, 2, 3},
827 golden: true,
828 },
829 {
830 CaseName: Name(""),
831 in: `"AQID"`,
832 ptr: new([]byteWithPtrMarshalText),
833 out: []byteWithPtrMarshalText{1, 2, 3},
834 },
835 {
836 CaseName: Name(""),
837 in: `["Z01","Z02","Z03"]`,
838 ptr: new([]byteWithPtrMarshalText),
839 out: []byteWithPtrMarshalText{1, 2, 3},
840 golden: true,
841 },
842
843
844 {
845 CaseName: Name(""),
846 in: `["Z01","Z02","Z03"]`,
847 ptr: new([]intWithMarshalJSON),
848 out: []intWithMarshalJSON{1, 2, 3},
849 golden: true,
850 },
851 {
852 CaseName: Name(""),
853 in: `["Z01","Z02","Z03"]`,
854 ptr: new([]intWithMarshalText),
855 out: []intWithMarshalText{1, 2, 3},
856 golden: true,
857 },
858 {
859 CaseName: Name(""),
860 in: `["Z01","Z02","Z03"]`,
861 ptr: new([]intWithPtrMarshalJSON),
862 out: []intWithPtrMarshalJSON{1, 2, 3},
863 golden: true,
864 },
865 {
866 CaseName: Name(""),
867 in: `["Z01","Z02","Z03"]`,
868 ptr: new([]intWithPtrMarshalText),
869 out: []intWithPtrMarshalText{1, 2, 3},
870 golden: true,
871 },
872
873 {CaseName: Name(""), in: `0.000001`, ptr: new(float64), out: 0.000001, golden: true},
874 {CaseName: Name(""), in: `1e-7`, ptr: new(float64), out: 1e-7, golden: true},
875 {CaseName: Name(""), in: `100000000000000000000`, ptr: new(float64), out: 100000000000000000000.0, golden: true},
876 {CaseName: Name(""), in: `1e+21`, ptr: new(float64), out: 1e21, golden: true},
877 {CaseName: Name(""), in: `-0.000001`, ptr: new(float64), out: -0.000001, golden: true},
878 {CaseName: Name(""), in: `-1e-7`, ptr: new(float64), out: -1e-7, golden: true},
879 {CaseName: Name(""), in: `-100000000000000000000`, ptr: new(float64), out: -100000000000000000000.0, golden: true},
880 {CaseName: Name(""), in: `-1e+21`, ptr: new(float64), out: -1e21, golden: true},
881 {CaseName: Name(""), in: `999999999999999900000`, ptr: new(float64), out: 999999999999999900000.0, golden: true},
882 {CaseName: Name(""), in: `9007199254740992`, ptr: new(float64), out: 9007199254740992.0, golden: true},
883 {CaseName: Name(""), in: `9007199254740993`, ptr: new(float64), out: 9007199254740992.0, golden: false},
884
885 {
886 CaseName: Name(""),
887 in: `{"V": {"F2": "hello"}}`,
888 ptr: new(VOuter),
889 err: &UnmarshalTypeError{
890 Value: "string",
891 Struct: "V",
892 Field: "V.F2",
893 Type: reflect.TypeFor[int32](),
894 Offset: 20,
895 },
896 },
897 {
898 CaseName: Name(""),
899 in: `{"V": {"F4": {}, "F2": "hello"}}`,
900 ptr: new(VOuter),
901 out: VOuter{V: V{F4: &VOuter{}}},
902 err: &UnmarshalTypeError{
903 Value: "string",
904 Struct: "V",
905 Field: "V.F2",
906 Type: reflect.TypeFor[int32](),
907 Offset: 30,
908 },
909 },
910
911 {
912 CaseName: Name(""),
913 in: `{"Level1a": "hello"}`,
914 ptr: new(Top),
915 out: Top{Embed0a: &Embed0a{}},
916 err: &UnmarshalTypeError{
917 Value: "string",
918 Struct: "Top",
919 Field: "Embed0a.Level1a",
920 Type: reflect.TypeFor[int](),
921 Offset: 19,
922 },
923 },
924
925
926
927 {CaseName: Name(""), in: `{"B":"true"}`, ptr: new(B), out: B{true}, golden: true},
928 {CaseName: Name(""), in: `{"B":"false"}`, ptr: new(B), out: B{false}, golden: true},
929 {CaseName: Name(""), in: `{"B": "maybe"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "maybe" into bool`)},
930 {CaseName: Name(""), in: `{"B": "tru"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "tru" into bool`)},
931 {CaseName: Name(""), in: `{"B": "False"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "False" into bool`)},
932 {CaseName: Name(""), in: `{"B": "null"}`, ptr: new(B), out: B{false}},
933 {CaseName: Name(""), in: `{"B": "nul"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "nul" into bool`)},
934 {CaseName: Name(""), in: `{"B": [2, 3]}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal unquoted value into bool`)},
935
936
937 {
938 CaseName: Name(""),
939 in: `{
940 "Level0": 1,
941 "Level1b": 2,
942 "Level1c": 3,
943 "x": 4,
944 "Level1a": 5,
945 "LEVEL1B": 6,
946 "e": {
947 "Level1a": 8,
948 "Level1b": 9,
949 "Level1c": 10,
950 "Level1d": 11,
951 "x": 12
952 },
953 "Loop1": 13,
954 "Loop2": 14,
955 "X": 15,
956 "Y": 16,
957 "Z": 17,
958 "Q": 18,
959 "extra": true
960 }`,
961 ptr: new(Top),
962 out: Top{
963 Level0: 1,
964 Embed0: Embed0{
965 Level1b: 2,
966 Level1c: 3,
967 },
968 Embed0a: &Embed0a{Level1a: 5, Level1b: 6},
969 Embed0b: &Embed0b{Level1a: 8, Level1b: 9, Level1c: 10, Level1d: 11, Level1e: 12},
970 Loop: Loop{
971 Loop1: 13,
972 Loop2: 14,
973 Loop: nil,
974 },
975 Embed0p: Embed0p{
976 Point: image.Point{
977 X: 15,
978 Y: 16,
979 },
980 },
981 Embed0q: Embed0q{Point: Point{Z: 17}},
982 embed: embed{Q: 18},
983 },
984 err: fmt.Errorf("json: unknown field \"extra\""),
985 disallowUnknownFields: true,
986 },
987 {
988 CaseName: Name(""),
989 in: `{
990 "Level0": 1,
991 "Level1b": 2,
992 "Level1c": 3,
993 "x": 4,
994 "Level1a": 5,
995 "LEVEL1B": 6,
996 "e": {
997 "Level1a": 8,
998 "Level1b": 9,
999 "Level1c": 10,
1000 "Level1d": 11,
1001 "x": 12,
1002 "extra": null
1003 },
1004 "Loop1": 13,
1005 "Loop2": 14,
1006 "X": 15,
1007 "Y": 16,
1008 "Z": 17,
1009 "Q": 18
1010 }`,
1011 ptr: new(Top),
1012 out: Top{
1013 Level0: 1,
1014 Embed0: Embed0{
1015 Level1b: 2,
1016 Level1c: 3,
1017 },
1018 Embed0a: &Embed0a{Level1a: 5, Level1b: 6},
1019 Embed0b: &Embed0b{Level1a: 8, Level1b: 9, Level1c: 10, Level1d: 11, Level1e: 12},
1020 Loop: Loop{
1021 Loop1: 13,
1022 Loop2: 14,
1023 Loop: nil,
1024 },
1025 Embed0p: Embed0p{
1026 Point: image.Point{
1027 X: 15,
1028 Y: 16,
1029 },
1030 },
1031 Embed0q: Embed0q{Point: Point{Z: 17}},
1032 embed: embed{Q: 18},
1033 },
1034 err: fmt.Errorf("json: unknown field \"extra\""),
1035 disallowUnknownFields: true,
1036 },
1037
1038
1039 {
1040 CaseName: Name(""),
1041 in: `{"data":{"test1": "bob", "test2": 123}}`,
1042 ptr: new(mapStringToStringData),
1043 out: mapStringToStringData{map[string]string{"test1": "bob", "test2": ""}},
1044 err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[string](), Offset: 37, Struct: "mapStringToStringData", Field: "data"},
1045 },
1046 {
1047 CaseName: Name(""),
1048 in: `{"data":{"test1": 123, "test2": "bob"}}`,
1049 ptr: new(mapStringToStringData),
1050 out: mapStringToStringData{Data: map[string]string{"test1": "", "test2": "bob"}},
1051 err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[string](), Offset: 21, Struct: "mapStringToStringData", Field: "data"},
1052 },
1053
1054
1055 {
1056 CaseName: Name(""),
1057 in: `[1, 2, 3]`,
1058 ptr: new(MustNotUnmarshalText),
1059 err: &UnmarshalTypeError{Value: "array", Type: reflect.TypeFor[*MustNotUnmarshalText](), Offset: 1},
1060 },
1061 {
1062 CaseName: Name(""),
1063 in: `{"foo": "bar"}`,
1064 ptr: new(MustNotUnmarshalText),
1065 err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeFor[*MustNotUnmarshalText](), Offset: 1},
1066 },
1067
1068 {
1069 CaseName: Name(""),
1070 in: `{"PP": {"T": {"Y": "bad-type"}}}`,
1071 ptr: new(P),
1072 err: &UnmarshalTypeError{
1073 Value: "string",
1074 Struct: "T",
1075 Field: "PP.T.Y",
1076 Type: reflect.TypeFor[int](),
1077 Offset: 29,
1078 },
1079 },
1080 {
1081 CaseName: Name(""),
1082 in: `{"Ts": [{"Y": 1}, {"Y": 2}, {"Y": "bad-type"}]}`,
1083 ptr: new(PP),
1084 out: PP{Ts: []T{{Y: 1}, {Y: 2}, {Y: 0}}},
1085 err: &UnmarshalTypeError{
1086 Value: "string",
1087 Struct: "T",
1088 Field: "Ts.Y",
1089 Type: reflect.TypeFor[int](),
1090 Offset: 44,
1091 },
1092 },
1093
1094 {
1095 CaseName: Name(""),
1096 in: `invalid`,
1097 ptr: new(Number),
1098 err: &SyntaxError{
1099 msg: "invalid character 'i' looking for beginning of value",
1100 Offset: 1,
1101 },
1102 },
1103 {
1104 CaseName: Name(""),
1105 in: `"invalid"`,
1106 ptr: new(Number),
1107 err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`),
1108 },
1109 {
1110 CaseName: Name(""),
1111 in: `{"A":"invalid"}`,
1112 ptr: new(struct{ A Number }),
1113 err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`),
1114 },
1115 {
1116 CaseName: Name(""),
1117 in: `{"A":"invalid"}`,
1118 ptr: new(struct {
1119 A Number `json:",string"`
1120 }),
1121 err: fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into json.Number", `invalid`),
1122 },
1123 {
1124 CaseName: Name(""),
1125 in: `{"A":"invalid"}`,
1126 ptr: new(map[string]Number),
1127 out: map[string]Number{},
1128 err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`),
1129 },
1130
1131 {
1132 CaseName: Name(""),
1133 in: `5`,
1134 ptr: new(Number),
1135 out: Number("5"),
1136 },
1137 {
1138 CaseName: Name(""),
1139 in: `"5"`,
1140 ptr: new(Number),
1141 out: Number("5"),
1142 },
1143 {
1144 CaseName: Name(""),
1145 in: `{"N":5}`,
1146 ptr: new(struct{ N Number }),
1147 out: struct{ N Number }{"5"},
1148 },
1149 {
1150 CaseName: Name(""),
1151 in: `{"N":"5"}`,
1152 ptr: new(struct{ N Number }),
1153 out: struct{ N Number }{"5"},
1154 },
1155 {
1156 CaseName: Name(""),
1157 in: `{"N":5}`,
1158 ptr: new(struct {
1159 N Number `json:",string"`
1160 }),
1161 err: fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into json.Number"),
1162 },
1163 {
1164 CaseName: Name(""),
1165 in: `{"N":"5"}`,
1166 ptr: new(struct {
1167 N Number `json:",string"`
1168 }),
1169 out: struct {
1170 N Number `json:",string"`
1171 }{"5"},
1172 },
1173
1174
1175
1176
1177 {
1178 CaseName: Name(""),
1179 in: `[1,2,true,4,5}`,
1180 ptr: new([]int),
1181 err: &SyntaxError{msg: "invalid character '}' after array element", Offset: 14},
1182 },
1183 {
1184 CaseName: Name(""),
1185 in: `[1,2,true,4,5]`,
1186 ptr: new([]int),
1187 out: []int{1, 2, 0, 4, 5},
1188 err: &UnmarshalTypeError{Value: "bool", Type: reflect.TypeFor[int](), Offset: 9},
1189 },
1190 }
1191
1192 func TestMarshal(t *testing.T) {
1193 b, err := Marshal(allValue)
1194 if err != nil {
1195 t.Fatalf("Marshal error: %v", err)
1196 }
1197 if string(b) != allValueCompact {
1198 t.Errorf("Marshal:")
1199 diff(t, b, []byte(allValueCompact))
1200 return
1201 }
1202
1203 b, err = Marshal(pallValue)
1204 if err != nil {
1205 t.Fatalf("Marshal error: %v", err)
1206 }
1207 if string(b) != pallValueCompact {
1208 t.Errorf("Marshal:")
1209 diff(t, b, []byte(pallValueCompact))
1210 return
1211 }
1212 }
1213
1214 func TestMarshalInvalidUTF8(t *testing.T) {
1215 tests := []struct {
1216 CaseName
1217 in string
1218 want string
1219 }{
1220 {Name(""), "hello\xffworld", `"hello\ufffdworld"`},
1221 {Name(""), "", `""`},
1222 {Name(""), "\xff", `"\ufffd"`},
1223 {Name(""), "\xff\xff", `"\ufffd\ufffd"`},
1224 {Name(""), "a\xffb", `"a\ufffdb"`},
1225 {Name(""), "\xe6\x97\xa5\xe6\x9c\xac\xff\xaa\x9e", `"日本\ufffd\ufffd\ufffd"`},
1226 }
1227 for _, tt := range tests {
1228 t.Run(tt.Name, func(t *testing.T) {
1229 got, err := Marshal(tt.in)
1230 if string(got) != tt.want || err != nil {
1231 t.Errorf("%s: Marshal(%q):\n\tgot: (%q, %v)\n\twant: (%q, nil)", tt.Where, tt.in, got, err, tt.want)
1232 }
1233 })
1234 }
1235 }
1236
1237 func TestMarshalNumberZeroVal(t *testing.T) {
1238 var n Number
1239 out, err := Marshal(n)
1240 if err != nil {
1241 t.Fatalf("Marshal error: %v", err)
1242 }
1243 got := string(out)
1244 if got != "0" {
1245 t.Fatalf("Marshal: got %s, want 0", got)
1246 }
1247 }
1248
1249 func TestMarshalEmbeds(t *testing.T) {
1250 top := &Top{
1251 Level0: 1,
1252 Embed0: Embed0{
1253 Level1b: 2,
1254 Level1c: 3,
1255 },
1256 Embed0a: &Embed0a{
1257 Level1a: 5,
1258 Level1b: 6,
1259 },
1260 Embed0b: &Embed0b{
1261 Level1a: 8,
1262 Level1b: 9,
1263 Level1c: 10,
1264 Level1d: 11,
1265 Level1e: 12,
1266 },
1267 Loop: Loop{
1268 Loop1: 13,
1269 Loop2: 14,
1270 },
1271 Embed0p: Embed0p{
1272 Point: image.Point{X: 15, Y: 16},
1273 },
1274 Embed0q: Embed0q{
1275 Point: Point{Z: 17},
1276 },
1277 embed: embed{
1278 Q: 18,
1279 },
1280 }
1281 got, err := Marshal(top)
1282 if err != nil {
1283 t.Fatalf("Marshal error: %v", err)
1284 }
1285 want := "{\"Level0\":1,\"Level1b\":2,\"Level1c\":3,\"Level1a\":5,\"LEVEL1B\":6,\"e\":{\"Level1a\":8,\"Level1b\":9,\"Level1c\":10,\"Level1d\":11,\"x\":12},\"Loop1\":13,\"Loop2\":14,\"X\":15,\"Y\":16,\"Z\":17,\"Q\":18}"
1286 if string(got) != want {
1287 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
1288 }
1289 }
1290
1291 func equalError(a, b error) bool {
1292 isJSONError := func(err error) bool {
1293 switch err.(type) {
1294 case
1295 *InvalidUTF8Error,
1296 *InvalidUnmarshalError,
1297 *MarshalerError,
1298 *SyntaxError,
1299 *UnmarshalFieldError,
1300 *UnmarshalTypeError,
1301 *UnsupportedTypeError,
1302 *UnsupportedValueError:
1303 return true
1304 }
1305 return false
1306 }
1307
1308 if a == nil || b == nil {
1309 return a == nil && b == nil
1310 }
1311 if isJSONError(a) || isJSONError(b) {
1312 return reflect.DeepEqual(a, b)
1313 }
1314 return a.Error() == b.Error()
1315 }
1316
1317 func TestUnmarshal(t *testing.T) {
1318 for _, tt := range unmarshalTests {
1319 t.Run(tt.Name, func(t *testing.T) {
1320 in := []byte(tt.in)
1321 var scan scanner
1322 if err := checkValid(in, &scan); err != nil {
1323 if !equalError(err, tt.err) {
1324 t.Fatalf("%s: checkValid error:\n\tgot %#v\n\twant %#v", tt.Where, err, tt.err)
1325 }
1326 }
1327 if tt.ptr == nil {
1328 return
1329 }
1330
1331 typ := reflect.TypeOf(tt.ptr)
1332 if typ.Kind() != reflect.Pointer {
1333 t.Fatalf("%s: unmarshalTest.ptr %T is not a pointer type", tt.Where, tt.ptr)
1334 }
1335 typ = typ.Elem()
1336
1337
1338 v := reflect.New(typ)
1339
1340 if !reflect.DeepEqual(tt.ptr, v.Interface()) {
1341
1342
1343
1344
1345
1346
1347 t.Fatalf("%s: unmarshalTest.ptr %#v is not a pointer to a zero value", tt.Where, tt.ptr)
1348 }
1349
1350 dec := NewDecoder(bytes.NewReader(in))
1351 if tt.useNumber {
1352 dec.UseNumber()
1353 }
1354 if tt.disallowUnknownFields {
1355 dec.DisallowUnknownFields()
1356 }
1357 if err := dec.Decode(v.Interface()); !equalError(err, tt.err) {
1358 t.Fatalf("%s: Decode error:\n\tgot: %v\n\twant: %v\n\n\tgot: %#v\n\twant: %#v", tt.Where, err, tt.err, err, tt.err)
1359 } else if err != nil && tt.out == nil {
1360
1361
1362 tt.out = reflect.Zero(v.Elem().Type()).Interface()
1363 }
1364 if got := v.Elem().Interface(); !reflect.DeepEqual(got, tt.out) {
1365 gotJSON, _ := Marshal(got)
1366 wantJSON, _ := Marshal(tt.out)
1367 t.Fatalf("%s: Decode:\n\tgot: %#+v\n\twant: %#+v\n\n\tgotJSON: %s\n\twantJSON: %s", tt.Where, got, tt.out, gotJSON, wantJSON)
1368 }
1369
1370
1371 if tt.err == nil {
1372 enc, err := Marshal(v.Interface())
1373 if err != nil {
1374 t.Fatalf("%s: Marshal error after roundtrip: %v", tt.Where, err)
1375 }
1376 if tt.golden && !bytes.Equal(enc, in) {
1377 t.Errorf("%s: Marshal:\n\tgot: %s\n\twant: %s", tt.Where, enc, in)
1378 }
1379 vv := reflect.New(reflect.TypeOf(tt.ptr).Elem())
1380 dec = NewDecoder(bytes.NewReader(enc))
1381 if tt.useNumber {
1382 dec.UseNumber()
1383 }
1384 if err := dec.Decode(vv.Interface()); err != nil {
1385 t.Fatalf("%s: Decode(%#q) error after roundtrip: %v", tt.Where, enc, err)
1386 }
1387 if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().Interface()) {
1388 t.Fatalf("%s: Decode:\n\tgot: %#+v\n\twant: %#+v\n\n\tgotJSON: %s\n\twantJSON: %s",
1389 tt.Where, v.Elem().Interface(), vv.Elem().Interface(),
1390 stripWhitespace(string(enc)), stripWhitespace(string(in)))
1391 }
1392 }
1393 })
1394 }
1395 }
1396
1397 func TestUnmarshalMarshal(t *testing.T) {
1398 initBig()
1399 var v any
1400 if err := Unmarshal(jsonBig, &v); err != nil {
1401 t.Fatalf("Unmarshal error: %v", err)
1402 }
1403 b, err := Marshal(v)
1404 if err != nil {
1405 t.Fatalf("Marshal error: %v", err)
1406 }
1407 if !bytes.Equal(jsonBig, b) {
1408 t.Errorf("Marshal:")
1409 diff(t, b, jsonBig)
1410 return
1411 }
1412 }
1413
1414
1415 func TestNumberAccessors(t *testing.T) {
1416 tests := []struct {
1417 CaseName
1418 in string
1419 i int64
1420 intErr string
1421 f float64
1422 floatErr string
1423 }{
1424 {CaseName: Name(""), in: "-1.23e1", intErr: "strconv.ParseInt: parsing \"-1.23e1\": invalid syntax", f: -1.23e1},
1425 {CaseName: Name(""), in: "-12", i: -12, f: -12.0},
1426 {CaseName: Name(""), in: "1e1000", intErr: "strconv.ParseInt: parsing \"1e1000\": invalid syntax", floatErr: "strconv.ParseFloat: parsing \"1e1000\": value out of range"},
1427 }
1428 for _, tt := range tests {
1429 t.Run(tt.Name, func(t *testing.T) {
1430 n := Number(tt.in)
1431 if got := n.String(); got != tt.in {
1432 t.Errorf("%s: Number(%q).String() = %s, want %s", tt.Where, tt.in, got, tt.in)
1433 }
1434 if i, err := n.Int64(); err == nil && tt.intErr == "" && i != tt.i {
1435 t.Errorf("%s: Number(%q).Int64() = %d, want %d", tt.Where, tt.in, i, tt.i)
1436 } else if (err == nil && tt.intErr != "") || (err != nil && err.Error() != tt.intErr) {
1437 t.Errorf("%s: Number(%q).Int64() error:\n\tgot: %v\n\twant: %v", tt.Where, tt.in, err, tt.intErr)
1438 }
1439 if f, err := n.Float64(); err == nil && tt.floatErr == "" && f != tt.f {
1440 t.Errorf("%s: Number(%q).Float64() = %g, want %g", tt.Where, tt.in, f, tt.f)
1441 } else if (err == nil && tt.floatErr != "") || (err != nil && err.Error() != tt.floatErr) {
1442 t.Errorf("%s: Number(%q).Float64() error:\n\tgot %v\n\twant: %v", tt.Where, tt.in, err, tt.floatErr)
1443 }
1444 })
1445 }
1446 }
1447
1448 func TestLargeByteSlice(t *testing.T) {
1449 s0 := make([]byte, 2000)
1450 for i := range s0 {
1451 s0[i] = byte(i)
1452 }
1453 b, err := Marshal(s0)
1454 if err != nil {
1455 t.Fatalf("Marshal error: %v", err)
1456 }
1457 var s1 []byte
1458 if err := Unmarshal(b, &s1); err != nil {
1459 t.Fatalf("Unmarshal error: %v", err)
1460 }
1461 if !bytes.Equal(s0, s1) {
1462 t.Errorf("Marshal:")
1463 diff(t, s0, s1)
1464 }
1465 }
1466
1467 type Xint struct {
1468 X int
1469 }
1470
1471 func TestUnmarshalInterface(t *testing.T) {
1472 var xint Xint
1473 var i any = &xint
1474 if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil {
1475 t.Fatalf("Unmarshal error: %v", err)
1476 }
1477 if xint.X != 1 {
1478 t.Fatalf("xint.X = %d, want 1", xint.X)
1479 }
1480 }
1481
1482 func TestUnmarshalPtrPtr(t *testing.T) {
1483 var xint Xint
1484 pxint := &xint
1485 if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil {
1486 t.Fatalf("Unmarshal: %v", err)
1487 }
1488 if xint.X != 1 {
1489 t.Fatalf("xint.X = %d, want 1", xint.X)
1490 }
1491 }
1492
1493 func TestEscape(t *testing.T) {
1494 const input = `"foobar"<html>` + " [\u2028 \u2029]"
1495 const want = `"\"foobar\"\u003chtml\u003e [\u2028 \u2029]"`
1496 got, err := Marshal(input)
1497 if err != nil {
1498 t.Fatalf("Marshal error: %v", err)
1499 }
1500 if string(got) != want {
1501 t.Errorf("Marshal(%#q):\n\tgot: %s\n\twant: %s", input, got, want)
1502 }
1503 }
1504
1505
1506
1507 func TestErrorMessageFromMisusedString(t *testing.T) {
1508
1509 type WrongString struct {
1510 Message string `json:"result,string"`
1511 }
1512 tests := []struct {
1513 CaseName
1514 in, err string
1515 }{
1516 {Name(""), `{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`},
1517 {Name(""), `{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`},
1518 {Name(""), `{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`},
1519 {Name(""), `{"result":123}`, `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into string`},
1520 {Name(""), `{"result":"\""}`, `json: invalid use of ,string struct tag, trying to unmarshal "\"" into string`},
1521 {Name(""), `{"result":"\"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "\"foo" into string`},
1522 }
1523 for _, tt := range tests {
1524 t.Run(tt.Name, func(t *testing.T) {
1525 r := strings.NewReader(tt.in)
1526 var s WrongString
1527 err := NewDecoder(r).Decode(&s)
1528 got := fmt.Sprintf("%v", err)
1529 if got != tt.err {
1530 t.Errorf("%s: Decode error:\n\tgot: %s\n\twant: %s", tt.Where, got, tt.err)
1531 }
1532 })
1533 }
1534 }
1535
1536 type All struct {
1537 Bool bool
1538 Int int
1539 Int8 int8
1540 Int16 int16
1541 Int32 int32
1542 Int64 int64
1543 Uint uint
1544 Uint8 uint8
1545 Uint16 uint16
1546 Uint32 uint32
1547 Uint64 uint64
1548 Uintptr uintptr
1549 Float32 float32
1550 Float64 float64
1551
1552 Foo string `json:"bar"`
1553 Foo2 string `json:"bar2,dummyopt"`
1554
1555 IntStr int64 `json:",string"`
1556 UintptrStr uintptr `json:",string"`
1557
1558 PBool *bool
1559 PInt *int
1560 PInt8 *int8
1561 PInt16 *int16
1562 PInt32 *int32
1563 PInt64 *int64
1564 PUint *uint
1565 PUint8 *uint8
1566 PUint16 *uint16
1567 PUint32 *uint32
1568 PUint64 *uint64
1569 PUintptr *uintptr
1570 PFloat32 *float32
1571 PFloat64 *float64
1572
1573 String string
1574 PString *string
1575
1576 Map map[string]Small
1577 MapP map[string]*Small
1578 PMap *map[string]Small
1579 PMapP *map[string]*Small
1580
1581 EmptyMap map[string]Small
1582 NilMap map[string]Small
1583
1584 Slice []Small
1585 SliceP []*Small
1586 PSlice *[]Small
1587 PSliceP *[]*Small
1588
1589 EmptySlice []Small
1590 NilSlice []Small
1591
1592 StringSlice []string
1593 ByteSlice []byte
1594
1595 Small Small
1596 PSmall *Small
1597 PPSmall **Small
1598
1599 Interface any
1600 PInterface *any
1601
1602 unexported int
1603 }
1604
1605 type Small struct {
1606 Tag string
1607 }
1608
1609 var allValue = All{
1610 Bool: true,
1611 Int: 2,
1612 Int8: 3,
1613 Int16: 4,
1614 Int32: 5,
1615 Int64: 6,
1616 Uint: 7,
1617 Uint8: 8,
1618 Uint16: 9,
1619 Uint32: 10,
1620 Uint64: 11,
1621 Uintptr: 12,
1622 Float32: 14.1,
1623 Float64: 15.1,
1624 Foo: "foo",
1625 Foo2: "foo2",
1626 IntStr: 42,
1627 UintptrStr: 44,
1628 String: "16",
1629 Map: map[string]Small{
1630 "17": {Tag: "tag17"},
1631 "18": {Tag: "tag18"},
1632 },
1633 MapP: map[string]*Small{
1634 "19": {Tag: "tag19"},
1635 "20": nil,
1636 },
1637 EmptyMap: map[string]Small{},
1638 Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}},
1639 SliceP: []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}},
1640 EmptySlice: []Small{},
1641 StringSlice: []string{"str24", "str25", "str26"},
1642 ByteSlice: []byte{27, 28, 29},
1643 Small: Small{Tag: "tag30"},
1644 PSmall: &Small{Tag: "tag31"},
1645 Interface: 5.2,
1646 }
1647
1648 var pallValue = All{
1649 PBool: &allValue.Bool,
1650 PInt: &allValue.Int,
1651 PInt8: &allValue.Int8,
1652 PInt16: &allValue.Int16,
1653 PInt32: &allValue.Int32,
1654 PInt64: &allValue.Int64,
1655 PUint: &allValue.Uint,
1656 PUint8: &allValue.Uint8,
1657 PUint16: &allValue.Uint16,
1658 PUint32: &allValue.Uint32,
1659 PUint64: &allValue.Uint64,
1660 PUintptr: &allValue.Uintptr,
1661 PFloat32: &allValue.Float32,
1662 PFloat64: &allValue.Float64,
1663 PString: &allValue.String,
1664 PMap: &allValue.Map,
1665 PMapP: &allValue.MapP,
1666 PSlice: &allValue.Slice,
1667 PSliceP: &allValue.SliceP,
1668 PPSmall: &allValue.PSmall,
1669 PInterface: &allValue.Interface,
1670 }
1671
1672 var allValueIndent = `{
1673 "Bool": true,
1674 "Int": 2,
1675 "Int8": 3,
1676 "Int16": 4,
1677 "Int32": 5,
1678 "Int64": 6,
1679 "Uint": 7,
1680 "Uint8": 8,
1681 "Uint16": 9,
1682 "Uint32": 10,
1683 "Uint64": 11,
1684 "Uintptr": 12,
1685 "Float32": 14.1,
1686 "Float64": 15.1,
1687 "bar": "foo",
1688 "bar2": "foo2",
1689 "IntStr": "42",
1690 "UintptrStr": "44",
1691 "PBool": null,
1692 "PInt": null,
1693 "PInt8": null,
1694 "PInt16": null,
1695 "PInt32": null,
1696 "PInt64": null,
1697 "PUint": null,
1698 "PUint8": null,
1699 "PUint16": null,
1700 "PUint32": null,
1701 "PUint64": null,
1702 "PUintptr": null,
1703 "PFloat32": null,
1704 "PFloat64": null,
1705 "String": "16",
1706 "PString": null,
1707 "Map": {
1708 "17": {
1709 "Tag": "tag17"
1710 },
1711 "18": {
1712 "Tag": "tag18"
1713 }
1714 },
1715 "MapP": {
1716 "19": {
1717 "Tag": "tag19"
1718 },
1719 "20": null
1720 },
1721 "PMap": null,
1722 "PMapP": null,
1723 "EmptyMap": {},
1724 "NilMap": null,
1725 "Slice": [
1726 {
1727 "Tag": "tag20"
1728 },
1729 {
1730 "Tag": "tag21"
1731 }
1732 ],
1733 "SliceP": [
1734 {
1735 "Tag": "tag22"
1736 },
1737 null,
1738 {
1739 "Tag": "tag23"
1740 }
1741 ],
1742 "PSlice": null,
1743 "PSliceP": null,
1744 "EmptySlice": [],
1745 "NilSlice": null,
1746 "StringSlice": [
1747 "str24",
1748 "str25",
1749 "str26"
1750 ],
1751 "ByteSlice": "Gxwd",
1752 "Small": {
1753 "Tag": "tag30"
1754 },
1755 "PSmall": {
1756 "Tag": "tag31"
1757 },
1758 "PPSmall": null,
1759 "Interface": 5.2,
1760 "PInterface": null
1761 }`
1762
1763 var allValueCompact = stripWhitespace(allValueIndent)
1764
1765 var pallValueIndent = `{
1766 "Bool": false,
1767 "Int": 0,
1768 "Int8": 0,
1769 "Int16": 0,
1770 "Int32": 0,
1771 "Int64": 0,
1772 "Uint": 0,
1773 "Uint8": 0,
1774 "Uint16": 0,
1775 "Uint32": 0,
1776 "Uint64": 0,
1777 "Uintptr": 0,
1778 "Float32": 0,
1779 "Float64": 0,
1780 "bar": "",
1781 "bar2": "",
1782 "IntStr": "0",
1783 "UintptrStr": "0",
1784 "PBool": true,
1785 "PInt": 2,
1786 "PInt8": 3,
1787 "PInt16": 4,
1788 "PInt32": 5,
1789 "PInt64": 6,
1790 "PUint": 7,
1791 "PUint8": 8,
1792 "PUint16": 9,
1793 "PUint32": 10,
1794 "PUint64": 11,
1795 "PUintptr": 12,
1796 "PFloat32": 14.1,
1797 "PFloat64": 15.1,
1798 "String": "",
1799 "PString": "16",
1800 "Map": null,
1801 "MapP": null,
1802 "PMap": {
1803 "17": {
1804 "Tag": "tag17"
1805 },
1806 "18": {
1807 "Tag": "tag18"
1808 }
1809 },
1810 "PMapP": {
1811 "19": {
1812 "Tag": "tag19"
1813 },
1814 "20": null
1815 },
1816 "EmptyMap": null,
1817 "NilMap": null,
1818 "Slice": null,
1819 "SliceP": null,
1820 "PSlice": [
1821 {
1822 "Tag": "tag20"
1823 },
1824 {
1825 "Tag": "tag21"
1826 }
1827 ],
1828 "PSliceP": [
1829 {
1830 "Tag": "tag22"
1831 },
1832 null,
1833 {
1834 "Tag": "tag23"
1835 }
1836 ],
1837 "EmptySlice": null,
1838 "NilSlice": null,
1839 "StringSlice": null,
1840 "ByteSlice": null,
1841 "Small": {
1842 "Tag": ""
1843 },
1844 "PSmall": null,
1845 "PPSmall": {
1846 "Tag": "tag31"
1847 },
1848 "Interface": null,
1849 "PInterface": 5.2
1850 }`
1851
1852 var pallValueCompact = stripWhitespace(pallValueIndent)
1853
1854 func TestRefUnmarshal(t *testing.T) {
1855 type S struct {
1856
1857 R0 Ref
1858 R1 *Ref
1859 R2 RefText
1860 R3 *RefText
1861 }
1862 want := S{
1863 R0: 12,
1864 R1: new(Ref),
1865 R2: 13,
1866 R3: new(RefText),
1867 }
1868 *want.R1 = 12
1869 *want.R3 = 13
1870
1871 var got S
1872 if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref","R2":"ref","R3":"ref"}`), &got); err != nil {
1873 t.Fatalf("Unmarshal error: %v", err)
1874 }
1875 if !reflect.DeepEqual(got, want) {
1876 t.Errorf("Unmarsha:\n\tgot: %+v\n\twant: %+v", got, want)
1877 }
1878 }
1879
1880
1881
1882 func TestEmptyString(t *testing.T) {
1883 type T2 struct {
1884 Number1 int `json:",string"`
1885 Number2 int `json:",string"`
1886 }
1887 data := `{"Number1":"1", "Number2":""}`
1888 dec := NewDecoder(strings.NewReader(data))
1889 var got T2
1890 switch err := dec.Decode(&got); {
1891 case err == nil:
1892 t.Fatalf("Decode error: got nil, want non-nil")
1893 case got.Number1 != 1:
1894 t.Fatalf("Decode: got.Number1 = %d, want 1", got.Number1)
1895 }
1896 }
1897
1898
1899
1900 func TestNullString(t *testing.T) {
1901 type T struct {
1902 A int `json:",string"`
1903 B int `json:",string"`
1904 C *int `json:",string"`
1905 }
1906 data := []byte(`{"A": "1", "B": null, "C": null}`)
1907 var s T
1908 s.B = 1
1909 s.C = new(int)
1910 *s.C = 2
1911 switch err := Unmarshal(data, &s); {
1912 case err != nil:
1913 t.Fatalf("Unmarshal error: %v", err)
1914 case s.B != 1:
1915 t.Fatalf("Unmarshal: s.B = %d, want 1", s.B)
1916 case s.C != nil:
1917 t.Fatalf("Unmarshal: s.C = %d, want non-nil", s.C)
1918 }
1919 }
1920
1921 func addr[T any](v T) *T {
1922 return &v
1923 }
1924
1925 func TestInterfaceSet(t *testing.T) {
1926 errUnmarshal := &UnmarshalTypeError{Value: "object", Offset: 6, Type: reflect.TypeFor[int](), Field: "X"}
1927 tests := []struct {
1928 CaseName
1929 pre any
1930 json string
1931 post any
1932 }{
1933 {Name(""), "foo", `"bar"`, "bar"},
1934 {Name(""), "foo", `2`, 2.0},
1935 {Name(""), "foo", `true`, true},
1936 {Name(""), "foo", `null`, nil},
1937 {Name(""), map[string]any{}, `true`, true},
1938 {Name(""), []string{}, `true`, true},
1939
1940 {Name(""), any(nil), `null`, any(nil)},
1941 {Name(""), (*int)(nil), `null`, any(nil)},
1942 {Name(""), (*int)(addr(0)), `null`, any(nil)},
1943 {Name(""), (*int)(addr(1)), `null`, any(nil)},
1944 {Name(""), (**int)(nil), `null`, any(nil)},
1945 {Name(""), (**int)(addr[*int](nil)), `null`, (**int)(addr[*int](nil))},
1946 {Name(""), (**int)(addr(addr(1))), `null`, (**int)(addr[*int](nil))},
1947 {Name(""), (***int)(nil), `null`, any(nil)},
1948 {Name(""), (***int)(addr[**int](nil)), `null`, (***int)(addr[**int](nil))},
1949 {Name(""), (***int)(addr(addr[*int](nil))), `null`, (***int)(addr[**int](nil))},
1950 {Name(""), (***int)(addr(addr(addr(1)))), `null`, (***int)(addr[**int](nil))},
1951
1952 {Name(""), any(nil), `2`, float64(2)},
1953 {Name(""), (int)(1), `2`, float64(2)},
1954 {Name(""), (*int)(nil), `2`, float64(2)},
1955 {Name(""), (*int)(addr(0)), `2`, (*int)(addr(2))},
1956 {Name(""), (*int)(addr(1)), `2`, (*int)(addr(2))},
1957 {Name(""), (**int)(nil), `2`, float64(2)},
1958 {Name(""), (**int)(addr[*int](nil)), `2`, (**int)(addr(addr(2)))},
1959 {Name(""), (**int)(addr(addr(1))), `2`, (**int)(addr(addr(2)))},
1960 {Name(""), (***int)(nil), `2`, float64(2)},
1961 {Name(""), (***int)(addr[**int](nil)), `2`, (***int)(addr(addr(addr(2))))},
1962 {Name(""), (***int)(addr(addr[*int](nil))), `2`, (***int)(addr(addr(addr(2))))},
1963 {Name(""), (***int)(addr(addr(addr(1)))), `2`, (***int)(addr(addr(addr(2))))},
1964
1965 {Name(""), any(nil), `{}`, map[string]any{}},
1966 {Name(""), (int)(1), `{}`, map[string]any{}},
1967 {Name(""), (*int)(nil), `{}`, map[string]any{}},
1968 {Name(""), (*int)(addr(0)), `{}`, errUnmarshal},
1969 {Name(""), (*int)(addr(1)), `{}`, errUnmarshal},
1970 {Name(""), (**int)(nil), `{}`, map[string]any{}},
1971 {Name(""), (**int)(addr[*int](nil)), `{}`, errUnmarshal},
1972 {Name(""), (**int)(addr(addr(1))), `{}`, errUnmarshal},
1973 {Name(""), (***int)(nil), `{}`, map[string]any{}},
1974 {Name(""), (***int)(addr[**int](nil)), `{}`, errUnmarshal},
1975 {Name(""), (***int)(addr(addr[*int](nil))), `{}`, errUnmarshal},
1976 {Name(""), (***int)(addr(addr(addr(1)))), `{}`, errUnmarshal},
1977 }
1978 for _, tt := range tests {
1979 t.Run(tt.Name, func(t *testing.T) {
1980 b := struct{ X any }{tt.pre}
1981 blob := `{"X":` + tt.json + `}`
1982 if err := Unmarshal([]byte(blob), &b); err != nil {
1983 if wantErr, _ := tt.post.(error); equalError(err, wantErr) {
1984 return
1985 }
1986 t.Fatalf("%s: Unmarshal(%#q) error: %v", tt.Where, blob, err)
1987 }
1988 if !reflect.DeepEqual(b.X, tt.post) {
1989 t.Errorf("%s: Unmarshal(%#q):\n\tpre.X: %#v\n\tgot.X: %#v\n\twant.X: %#v", tt.Where, blob, tt.pre, b.X, tt.post)
1990 }
1991 })
1992 }
1993 }
1994
1995 type NullTest struct {
1996 Bool bool
1997 Int int
1998 Int8 int8
1999 Int16 int16
2000 Int32 int32
2001 Int64 int64
2002 Uint uint
2003 Uint8 uint8
2004 Uint16 uint16
2005 Uint32 uint32
2006 Uint64 uint64
2007 Float32 float32
2008 Float64 float64
2009 String string
2010 PBool *bool
2011 Map map[string]string
2012 Slice []string
2013 Interface any
2014
2015 PRaw *RawMessage
2016 PTime *time.Time
2017 PBigInt *big.Int
2018 PText *MustNotUnmarshalText
2019 PBuffer *bytes.Buffer
2020 PStruct *struct{}
2021
2022 Raw RawMessage
2023 Time time.Time
2024 BigInt big.Int
2025 Text MustNotUnmarshalText
2026 Buffer bytes.Buffer
2027 Struct struct{}
2028 }
2029
2030
2031
2032 func TestUnmarshalNulls(t *testing.T) {
2033
2034
2035
2036
2037
2038
2039 jsonData := []byte(`{
2040 "Bool" : null,
2041 "Int" : null,
2042 "Int8" : null,
2043 "Int16" : null,
2044 "Int32" : null,
2045 "Int64" : null,
2046 "Uint" : null,
2047 "Uint8" : null,
2048 "Uint16" : null,
2049 "Uint32" : null,
2050 "Uint64" : null,
2051 "Float32" : null,
2052 "Float64" : null,
2053 "String" : null,
2054 "PBool": null,
2055 "Map": null,
2056 "Slice": null,
2057 "Interface": null,
2058 "PRaw": null,
2059 "PTime": null,
2060 "PBigInt": null,
2061 "PText": null,
2062 "PBuffer": null,
2063 "PStruct": null,
2064 "Raw": null,
2065 "Time": null,
2066 "BigInt": null,
2067 "Text": null,
2068 "Buffer": null,
2069 "Struct": null
2070 }`)
2071 nulls := NullTest{
2072 Bool: true,
2073 Int: 2,
2074 Int8: 3,
2075 Int16: 4,
2076 Int32: 5,
2077 Int64: 6,
2078 Uint: 7,
2079 Uint8: 8,
2080 Uint16: 9,
2081 Uint32: 10,
2082 Uint64: 11,
2083 Float32: 12.1,
2084 Float64: 13.1,
2085 String: "14",
2086 PBool: new(bool),
2087 Map: map[string]string{},
2088 Slice: []string{},
2089 Interface: new(MustNotUnmarshalJSON),
2090 PRaw: new(RawMessage),
2091 PTime: new(time.Time),
2092 PBigInt: new(big.Int),
2093 PText: new(MustNotUnmarshalText),
2094 PStruct: new(struct{}),
2095 PBuffer: new(bytes.Buffer),
2096 Raw: RawMessage("123"),
2097 Time: time.Unix(123456789, 0),
2098 BigInt: *big.NewInt(123),
2099 }
2100
2101 before := nulls.Time.String()
2102
2103 err := Unmarshal(jsonData, &nulls)
2104 if err != nil {
2105 t.Errorf("Unmarshal of null values failed: %v", err)
2106 }
2107 if !nulls.Bool || nulls.Int != 2 || nulls.Int8 != 3 || nulls.Int16 != 4 || nulls.Int32 != 5 || nulls.Int64 != 6 ||
2108 nulls.Uint != 7 || nulls.Uint8 != 8 || nulls.Uint16 != 9 || nulls.Uint32 != 10 || nulls.Uint64 != 11 ||
2109 nulls.Float32 != 12.1 || nulls.Float64 != 13.1 || nulls.String != "14" {
2110 t.Errorf("Unmarshal of null values affected primitives")
2111 }
2112
2113 if nulls.PBool != nil {
2114 t.Errorf("Unmarshal of null did not clear nulls.PBool")
2115 }
2116 if nulls.Map != nil {
2117 t.Errorf("Unmarshal of null did not clear nulls.Map")
2118 }
2119 if nulls.Slice != nil {
2120 t.Errorf("Unmarshal of null did not clear nulls.Slice")
2121 }
2122 if nulls.Interface != nil {
2123 t.Errorf("Unmarshal of null did not clear nulls.Interface")
2124 }
2125 if nulls.PRaw != nil {
2126 t.Errorf("Unmarshal of null did not clear nulls.PRaw")
2127 }
2128 if nulls.PTime != nil {
2129 t.Errorf("Unmarshal of null did not clear nulls.PTime")
2130 }
2131 if nulls.PBigInt != nil {
2132 t.Errorf("Unmarshal of null did not clear nulls.PBigInt")
2133 }
2134 if nulls.PText != nil {
2135 t.Errorf("Unmarshal of null did not clear nulls.PText")
2136 }
2137 if nulls.PBuffer != nil {
2138 t.Errorf("Unmarshal of null did not clear nulls.PBuffer")
2139 }
2140 if nulls.PStruct != nil {
2141 t.Errorf("Unmarshal of null did not clear nulls.PStruct")
2142 }
2143
2144 if string(nulls.Raw) != "null" {
2145 t.Errorf("Unmarshal of RawMessage null did not record null: %v", string(nulls.Raw))
2146 }
2147 if nulls.Time.String() != before {
2148 t.Errorf("Unmarshal of time.Time null set time to %v", nulls.Time.String())
2149 }
2150 if nulls.BigInt.String() != "123" {
2151 t.Errorf("Unmarshal of big.Int null set int to %v", nulls.BigInt.String())
2152 }
2153 }
2154
2155 type MustNotUnmarshalJSON struct{}
2156
2157 func (x MustNotUnmarshalJSON) UnmarshalJSON(data []byte) error {
2158 return errors.New("MustNotUnmarshalJSON was used")
2159 }
2160
2161 type MustNotUnmarshalText struct{}
2162
2163 func (x MustNotUnmarshalText) UnmarshalText(text []byte) error {
2164 return errors.New("MustNotUnmarshalText was used")
2165 }
2166
2167 func TestStringKind(t *testing.T) {
2168 type stringKind string
2169 want := map[stringKind]int{"foo": 42}
2170 data, err := Marshal(want)
2171 if err != nil {
2172 t.Fatalf("Marshal error: %v", err)
2173 }
2174 var got map[stringKind]int
2175 err = Unmarshal(data, &got)
2176 if err != nil {
2177 t.Fatalf("Unmarshal error: %v", err)
2178 }
2179 if !maps.Equal(got, want) {
2180 t.Fatalf("Marshal/Unmarshal mismatch:\n\tgot: %v\n\twant: %v", got, want)
2181 }
2182 }
2183
2184
2185
2186
2187 func TestByteKind(t *testing.T) {
2188 type byteKind []byte
2189 want := byteKind("hello")
2190 data, err := Marshal(want)
2191 if err != nil {
2192 t.Fatalf("Marshal error: %v", err)
2193 }
2194 var got byteKind
2195 err = Unmarshal(data, &got)
2196 if err != nil {
2197 t.Fatalf("Unmarshal error: %v", err)
2198 }
2199 if !slices.Equal(got, want) {
2200 t.Fatalf("Marshal/Unmarshal mismatch:\n\tgot: %v\n\twant: %v", got, want)
2201 }
2202 }
2203
2204
2205
2206 func TestSliceOfCustomByte(t *testing.T) {
2207 type Uint8 uint8
2208 want := []Uint8("hello")
2209 data, err := Marshal(want)
2210 if err != nil {
2211 t.Fatalf("Marshal error: %v", err)
2212 }
2213 var got []Uint8
2214 err = Unmarshal(data, &got)
2215 if err != nil {
2216 t.Fatalf("Unmarshal error: %v", err)
2217 }
2218 if !slices.Equal(got, want) {
2219 t.Fatalf("Marshal/Unmarshal mismatch:\n\tgot: %v\n\twant: %v", got, want)
2220 }
2221 }
2222
2223 func TestUnmarshalTypeError(t *testing.T) {
2224 tests := []struct {
2225 CaseName
2226 dest any
2227 in string
2228 }{
2229 {Name(""), new(string), `{"user": "name"}`},
2230 {Name(""), new(error), `{}`},
2231 {Name(""), new(error), `[]`},
2232 {Name(""), new(error), `""`},
2233 {Name(""), new(error), `123`},
2234 {Name(""), new(error), `true`},
2235 }
2236 for _, tt := range tests {
2237 t.Run(tt.Name, func(t *testing.T) {
2238 err := Unmarshal([]byte(tt.in), tt.dest)
2239 if _, ok := err.(*UnmarshalTypeError); !ok {
2240 t.Errorf("%s: Unmarshal(%#q, %T):\n\tgot: %T\n\twant: %T",
2241 tt.Where, tt.in, tt.dest, err, new(UnmarshalTypeError))
2242 }
2243 })
2244 }
2245 }
2246
2247 func TestUnmarshalSyntax(t *testing.T) {
2248 var x any
2249 tests := []struct {
2250 CaseName
2251 in string
2252 }{
2253 {Name(""), "tru"},
2254 {Name(""), "fals"},
2255 {Name(""), "nul"},
2256 {Name(""), "123e"},
2257 {Name(""), `"hello`},
2258 {Name(""), `[1,2,3`},
2259 {Name(""), `{"key":1`},
2260 {Name(""), `{"key":1,`},
2261 }
2262 for _, tt := range tests {
2263 t.Run(tt.Name, func(t *testing.T) {
2264 err := Unmarshal([]byte(tt.in), &x)
2265 if _, ok := err.(*SyntaxError); !ok {
2266 t.Errorf("%s: Unmarshal(%#q, any):\n\tgot: %T\n\twant: %T",
2267 tt.Where, tt.in, err, new(SyntaxError))
2268 }
2269 })
2270 }
2271 }
2272
2273
2274
2275 type unexportedFields struct {
2276 Name string
2277 m map[string]any `json:"-"`
2278 m2 map[string]any `json:"abcd"`
2279
2280 s []int `json:"-"`
2281 }
2282
2283 func TestUnmarshalUnexported(t *testing.T) {
2284 input := `{"Name": "Bob", "m": {"x": 123}, "m2": {"y": 456}, "abcd": {"z": 789}, "s": [2, 3]}`
2285 want := &unexportedFields{Name: "Bob"}
2286
2287 out := &unexportedFields{}
2288 err := Unmarshal([]byte(input), out)
2289 if err != nil {
2290 t.Errorf("Unmarshal error: %v", err)
2291 }
2292 if !reflect.DeepEqual(out, want) {
2293 t.Errorf("Unmarshal:\n\tgot: %+v\n\twant: %+v", out, want)
2294 }
2295 }
2296
2297
2298
2299 type Time3339 time.Time
2300
2301 func (t *Time3339) UnmarshalJSON(b []byte) error {
2302 if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' {
2303 return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time", b)
2304 }
2305 tm, err := time.Parse(time.RFC3339, string(b[1:len(b)-1]))
2306 if err != nil {
2307 return err
2308 }
2309 *t = Time3339(tm)
2310 return nil
2311 }
2312
2313 func TestUnmarshalJSONLiteralError(t *testing.T) {
2314 var t3 Time3339
2315 switch err := Unmarshal([]byte(`"0000-00-00T00:00:00Z"`), &t3); {
2316 case err == nil:
2317 t.Fatalf("Unmarshal error: got nil, want non-nil")
2318 case !strings.Contains(err.Error(), "range"):
2319 t.Errorf("Unmarshal error:\n\tgot: %v\n\twant: out of range", err)
2320 }
2321 }
2322
2323
2324
2325
2326 func TestSkipArrayObjects(t *testing.T) {
2327 json := `[{}]`
2328 var dest [0]any
2329
2330 err := Unmarshal([]byte(json), &dest)
2331 if err != nil {
2332 t.Errorf("Unmarshal error: %v", err)
2333 }
2334 }
2335
2336
2337
2338
2339 func TestPrefilled(t *testing.T) {
2340
2341 tests := []struct {
2342 CaseName
2343 in string
2344 ptr any
2345 out any
2346 }{{
2347 CaseName: Name(""),
2348 in: `{"X": 1, "Y": 2}`,
2349 ptr: &XYZ{X: float32(3), Y: int16(4), Z: 1.5},
2350 out: &XYZ{X: float64(1), Y: float64(2), Z: 1.5},
2351 }, {
2352 CaseName: Name(""),
2353 in: `{"X": 1, "Y": 2}`,
2354 ptr: &map[string]any{"X": float32(3), "Y": int16(4), "Z": 1.5},
2355 out: &map[string]any{"X": float64(1), "Y": float64(2), "Z": 1.5},
2356 }, {
2357 CaseName: Name(""),
2358 in: `[2]`,
2359 ptr: &[]int{1},
2360 out: &[]int{2},
2361 }, {
2362 CaseName: Name(""),
2363 in: `[2, 3]`,
2364 ptr: &[]int{1},
2365 out: &[]int{2, 3},
2366 }, {
2367 CaseName: Name(""),
2368 in: `[2, 3]`,
2369 ptr: &[...]int{1},
2370 out: &[...]int{2},
2371 }, {
2372 CaseName: Name(""),
2373 in: `[3]`,
2374 ptr: &[...]int{1, 2},
2375 out: &[...]int{3, 0},
2376 }}
2377 for _, tt := range tests {
2378 t.Run(tt.Name, func(t *testing.T) {
2379 ptrstr := fmt.Sprintf("%v", tt.ptr)
2380 err := Unmarshal([]byte(tt.in), tt.ptr)
2381 if err != nil {
2382 t.Errorf("%s: Unmarshal error: %v", tt.Where, err)
2383 }
2384 if !reflect.DeepEqual(tt.ptr, tt.out) {
2385 t.Errorf("%s: Unmarshal(%#q, %T):\n\tgot: %v\n\twant: %v", tt.Where, tt.in, ptrstr, tt.ptr, tt.out)
2386 }
2387 })
2388 }
2389 }
2390
2391 func TestInvalidUnmarshal(t *testing.T) {
2392 tests := []struct {
2393 CaseName
2394 in string
2395 v any
2396 wantErr error
2397 }{
2398 {Name(""), `{"a":"1"}`, nil, &InvalidUnmarshalError{}},
2399 {Name(""), `{"a":"1"}`, struct{}{}, &InvalidUnmarshalError{reflect.TypeFor[struct{}]()}},
2400 {Name(""), `{"a":"1"}`, (*int)(nil), &InvalidUnmarshalError{reflect.TypeFor[*int]()}},
2401 {Name(""), `123`, nil, &InvalidUnmarshalError{}},
2402 {Name(""), `123`, struct{}{}, &InvalidUnmarshalError{reflect.TypeFor[struct{}]()}},
2403 {Name(""), `123`, (*int)(nil), &InvalidUnmarshalError{reflect.TypeFor[*int]()}},
2404 {Name(""), `123`, new(net.IP), &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[*net.IP](), Offset: 3}},
2405 }
2406 for _, tt := range tests {
2407 t.Run(tt.Name, func(t *testing.T) {
2408 switch gotErr := Unmarshal([]byte(tt.in), tt.v); {
2409 case gotErr == nil:
2410 t.Fatalf("%s: Unmarshal error: got nil, want non-nil", tt.Where)
2411 case !reflect.DeepEqual(gotErr, tt.wantErr):
2412 t.Errorf("%s: Unmarshal error:\n\tgot: %#v\n\twant: %#v", tt.Where, gotErr, tt.wantErr)
2413 }
2414 })
2415 }
2416 }
2417
2418
2419
2420 func TestInvalidStringOption(t *testing.T) {
2421 num := 0
2422 item := struct {
2423 T time.Time `json:",string"`
2424 M map[string]string `json:",string"`
2425 S []string `json:",string"`
2426 A [1]string `json:",string"`
2427 I any `json:",string"`
2428 P *int `json:",string"`
2429 }{M: make(map[string]string), S: make([]string, 0), I: num, P: &num}
2430
2431 data, err := Marshal(item)
2432 if err != nil {
2433 t.Fatalf("Marshal error: %v", err)
2434 }
2435
2436 err = Unmarshal(data, &item)
2437 if err != nil {
2438 t.Fatalf("Unmarshal error: %v", err)
2439 }
2440 }
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452 func TestUnmarshalEmbeddedUnexported(t *testing.T) {
2453 type (
2454 embed1 struct{ Q int }
2455 embed2 struct{ Q int }
2456 embed3 struct {
2457 Q int64 `json:",string"`
2458 }
2459 S1 struct {
2460 *embed1
2461 R int
2462 }
2463 S2 struct {
2464 *embed1
2465 Q int
2466 }
2467 S3 struct {
2468 embed1
2469 R int
2470 }
2471 S4 struct {
2472 *embed1
2473 embed2
2474 }
2475 S5 struct {
2476 *embed3
2477 R int
2478 }
2479 S6 struct {
2480 embed1 `json:"embed1"`
2481 }
2482 S7 struct {
2483 embed1 `json:"embed1"`
2484 embed2
2485 }
2486 S8 struct {
2487 embed1 `json:"embed1"`
2488 embed2 `json:"embed2"`
2489 Q int
2490 }
2491 S9 struct {
2492 unexportedWithMethods `json:"embed"`
2493 }
2494 )
2495
2496 tests := []struct {
2497 CaseName
2498 in string
2499 ptr any
2500 out any
2501 err error
2502 }{{
2503
2504 CaseName: Name(""),
2505 in: `{"R":2,"Q":1}`,
2506 ptr: new(S1),
2507 out: &S1{R: 2},
2508 err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed1"),
2509 }, {
2510
2511 CaseName: Name(""),
2512 in: `{"Q":1}`,
2513 ptr: new(S2),
2514 out: &S2{Q: 1},
2515 }, {
2516
2517 CaseName: Name(""),
2518 in: `{"R":2,"Q":1}`,
2519 ptr: new(S3),
2520 out: &S3{embed1: embed1{Q: 1}, R: 2},
2521 }, {
2522
2523
2524 CaseName: Name(""),
2525 in: `{"R":2}`,
2526 ptr: new(S4),
2527 out: new(S4),
2528 }, {
2529
2530 CaseName: Name(""),
2531 in: `{"R":2,"Q":1}`,
2532 ptr: new(S5),
2533 out: &S5{R: 2},
2534 err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed3"),
2535 }, {
2536
2537 CaseName: Name(""),
2538 in: `{"embed1": {"Q": 1}}`,
2539 ptr: new(S6),
2540 out: &S6{embed1{1}},
2541 }, {
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554 CaseName: Name(""),
2555 in: `{"embed1": {"Q": 1}, "Q": 2}`,
2556 ptr: new(S7),
2557 out: &S7{embed1{1}, embed2{2}},
2558 }, {
2559
2560 CaseName: Name(""),
2561 in: `{"embed1": {"Q": 1}, "embed2": {"Q": 2}, "Q": 3}`,
2562 ptr: new(S8),
2563 out: &S8{embed1{1}, embed2{2}, 3},
2564 }, {
2565
2566 CaseName: Name(""),
2567 in: `{"embed": {}}`,
2568 ptr: new(S9),
2569 out: &S9{},
2570 }}
2571 for _, tt := range tests {
2572 t.Run(tt.Name, func(t *testing.T) {
2573 err := Unmarshal([]byte(tt.in), tt.ptr)
2574 if !equalError(err, tt.err) {
2575 t.Errorf("%s: Unmarshal error:\n\tgot: %v\n\twant: %v", tt.Where, err, tt.err)
2576 }
2577 if !reflect.DeepEqual(tt.ptr, tt.out) {
2578 t.Errorf("%s: Unmarshal:\n\tgot: %#+v\n\twant: %#+v", tt.Where, tt.ptr, tt.out)
2579 }
2580 })
2581 }
2582 }
2583
2584 func TestUnmarshalErrorAfterMultipleJSON(t *testing.T) {
2585 tests := []struct {
2586 CaseName
2587 in string
2588 err error
2589 }{{
2590 CaseName: Name(""),
2591 in: `1 false null :`,
2592 err: &SyntaxError{"invalid character ':' looking for beginning of value", 14},
2593 }, {
2594 CaseName: Name(""),
2595 in: `1 [] [,]`,
2596 err: &SyntaxError{"invalid character ',' looking for beginning of value", 7},
2597 }, {
2598 CaseName: Name(""),
2599 in: `1 [] [true:]`,
2600 err: &SyntaxError{"invalid character ':' after array element", 11},
2601 }, {
2602 CaseName: Name(""),
2603 in: `1 {} {"x"=}`,
2604 err: &SyntaxError{"invalid character '=' after object key", 14},
2605 }, {
2606 CaseName: Name(""),
2607 in: `falsetruenul#`,
2608 err: &SyntaxError{"invalid character '#' in literal null (expecting 'l')", 13},
2609 }}
2610 for _, tt := range tests {
2611 t.Run(tt.Name, func(t *testing.T) {
2612 dec := NewDecoder(strings.NewReader(tt.in))
2613 var err error
2614 for err == nil {
2615 var v any
2616 err = dec.Decode(&v)
2617 }
2618 if !reflect.DeepEqual(err, tt.err) {
2619 t.Errorf("%s: Decode error:\n\tgot: %v\n\twant: %v", tt.Where, err, tt.err)
2620 }
2621 })
2622 }
2623 }
2624
2625 type unmarshalPanic struct{}
2626
2627 func (unmarshalPanic) UnmarshalJSON([]byte) error { panic(0xdead) }
2628
2629 func TestUnmarshalPanic(t *testing.T) {
2630 defer func() {
2631 if got := recover(); !reflect.DeepEqual(got, 0xdead) {
2632 t.Errorf("panic() = (%T)(%v), want 0xdead", got, got)
2633 }
2634 }()
2635 Unmarshal([]byte("{}"), &unmarshalPanic{})
2636 t.Fatalf("Unmarshal should have panicked")
2637 }
2638
2639
2640
2641 func TestUnmarshalRecursivePointer(t *testing.T) {
2642 var v any
2643 v = &v
2644 data := []byte(`{"a": "b"}`)
2645
2646 if err := Unmarshal(data, v); err != nil {
2647 t.Fatalf("Unmarshal error: %v", err)
2648 }
2649 }
2650
2651 type textUnmarshalerString string
2652
2653 func (m *textUnmarshalerString) UnmarshalText(text []byte) error {
2654 *m = textUnmarshalerString(strings.ToLower(string(text)))
2655 return nil
2656 }
2657
2658
2659
2660 func TestUnmarshalMapWithTextUnmarshalerStringKey(t *testing.T) {
2661 var p map[textUnmarshalerString]string
2662 if err := Unmarshal([]byte(`{"FOO": "1"}`), &p); err != nil {
2663 t.Fatalf("Unmarshal error: %v", err)
2664 }
2665
2666 if _, ok := p["foo"]; !ok {
2667 t.Errorf(`key "foo" missing in map: %v`, p)
2668 }
2669 }
2670
2671 func TestUnmarshalRescanLiteralMangledUnquote(t *testing.T) {
2672
2673 var p map[textUnmarshalerString]string
2674 if err := Unmarshal([]byte(`{"开源":"12345开源"}`), &p); err != nil {
2675 t.Fatalf("Unmarshal error: %v", err)
2676 }
2677 if _, ok := p["开源"]; !ok {
2678 t.Errorf(`key "开源" missing in map: %v`, p)
2679 }
2680
2681
2682 type T struct {
2683 F1 string `json:"F1,string"`
2684 }
2685 wantT := T{"aaa\tbbb"}
2686
2687 b, err := Marshal(wantT)
2688 if err != nil {
2689 t.Fatalf("Marshal error: %v", err)
2690 }
2691 var gotT T
2692 if err := Unmarshal(b, &gotT); err != nil {
2693 t.Fatalf("Unmarshal error: %v", err)
2694 }
2695 if gotT != wantT {
2696 t.Errorf("Marshal/Unmarshal roundtrip:\n\tgot: %q\n\twant: %q", gotT, wantT)
2697 }
2698
2699
2700 input := map[textUnmarshalerString]string{"FOO": "", `"`: ""}
2701
2702 encoded, err := Marshal(input)
2703 if err != nil {
2704 t.Fatalf("Marshal error: %v", err)
2705 }
2706 var got map[textUnmarshalerString]string
2707 if err := Unmarshal(encoded, &got); err != nil {
2708 t.Fatalf("Unmarshal error: %v", err)
2709 }
2710 want := map[textUnmarshalerString]string{"foo": "", `"`: ""}
2711 if !maps.Equal(got, want) {
2712 t.Errorf("Marshal/Unmarshal roundtrip:\n\tgot: %q\n\twant: %q", gotT, wantT)
2713 }
2714 }
2715
2716 func TestUnmarshalMaxDepth(t *testing.T) {
2717 tests := []struct {
2718 CaseName
2719 data string
2720 errMaxDepth bool
2721 }{{
2722 CaseName: Name("ArrayUnderMaxNestingDepth"),
2723 data: `{"a":` + strings.Repeat(`[`, 10000-1) + strings.Repeat(`]`, 10000-1) + `}`,
2724 errMaxDepth: false,
2725 }, {
2726 CaseName: Name("ArrayOverMaxNestingDepth"),
2727 data: `{"a":` + strings.Repeat(`[`, 10000) + strings.Repeat(`]`, 10000) + `}`,
2728 errMaxDepth: true,
2729 }, {
2730 CaseName: Name("ArrayOverStackDepth"),
2731 data: `{"a":` + strings.Repeat(`[`, 3000000) + strings.Repeat(`]`, 3000000) + `}`,
2732 errMaxDepth: true,
2733 }, {
2734 CaseName: Name("ObjectUnderMaxNestingDepth"),
2735 data: `{"a":` + strings.Repeat(`{"a":`, 10000-1) + `0` + strings.Repeat(`}`, 10000-1) + `}`,
2736 errMaxDepth: false,
2737 }, {
2738 CaseName: Name("ObjectOverMaxNestingDepth"),
2739 data: `{"a":` + strings.Repeat(`{"a":`, 10000) + `0` + strings.Repeat(`}`, 10000) + `}`,
2740 errMaxDepth: true,
2741 }, {
2742 CaseName: Name("ObjectOverStackDepth"),
2743 data: `{"a":` + strings.Repeat(`{"a":`, 3000000) + `0` + strings.Repeat(`}`, 3000000) + `}`,
2744 errMaxDepth: true,
2745 }}
2746
2747 targets := []struct {
2748 CaseName
2749 newValue func() any
2750 }{{
2751 CaseName: Name("unstructured"),
2752 newValue: func() any {
2753 var v any
2754 return &v
2755 },
2756 }, {
2757 CaseName: Name("typed named field"),
2758 newValue: func() any {
2759 v := struct {
2760 A any `json:"a"`
2761 }{}
2762 return &v
2763 },
2764 }, {
2765 CaseName: Name("typed missing field"),
2766 newValue: func() any {
2767 v := struct {
2768 B any `json:"b"`
2769 }{}
2770 return &v
2771 },
2772 }, {
2773 CaseName: Name("custom unmarshaler"),
2774 newValue: func() any {
2775 v := unmarshaler{}
2776 return &v
2777 },
2778 }}
2779
2780 for _, tt := range tests {
2781 for _, target := range targets {
2782 t.Run(target.Name+"-"+tt.Name, func(t *testing.T) {
2783 err := Unmarshal([]byte(tt.data), target.newValue())
2784 if !tt.errMaxDepth {
2785 if err != nil {
2786 t.Errorf("%s: %s: Unmarshal error: %v", tt.Where, target.Where, err)
2787 }
2788 } else {
2789 if err == nil || !strings.Contains(err.Error(), "exceeded max depth") {
2790 t.Errorf("%s: %s: Unmarshal error:\n\tgot: %v\n\twant: exceeded max depth", tt.Where, target.Where, err)
2791 }
2792 }
2793 })
2794 }
2795 }
2796 }
2797
View as plain text