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