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 CaseName: Name("DashComma"),
1195 in: `{"-":"hello"}`,
1196 ptr: new(struct {
1197 F string `json:"-,"`
1198 }),
1199 out: struct {
1200 F string `json:"-,"`
1201 }{"hello"},
1202 },
1203 {
1204 CaseName: Name("DashCommaOmitEmpty"),
1205 in: `{"-":"hello"}`,
1206 ptr: new(struct {
1207 F string `json:"-,omitempty"`
1208 }),
1209 out: struct {
1210 F string `json:"-,omitempty"`
1211 }{"hello"},
1212 },
1213 }
1214
1215 func TestMarshal(t *testing.T) {
1216 b, err := Marshal(allValue)
1217 if err != nil {
1218 t.Fatalf("Marshal error: %v", err)
1219 }
1220 if string(b) != allValueCompact {
1221 t.Errorf("Marshal:")
1222 diff(t, b, []byte(allValueCompact))
1223 return
1224 }
1225
1226 b, err = Marshal(pallValue)
1227 if err != nil {
1228 t.Fatalf("Marshal error: %v", err)
1229 }
1230 if string(b) != pallValueCompact {
1231 t.Errorf("Marshal:")
1232 diff(t, b, []byte(pallValueCompact))
1233 return
1234 }
1235 }
1236
1237 func TestMarshalInvalidUTF8(t *testing.T) {
1238 tests := []struct {
1239 CaseName
1240 in string
1241 want string
1242 }{
1243 {Name(""), "hello\xffworld", `"hello\ufffdworld"`},
1244 {Name(""), "", `""`},
1245 {Name(""), "\xff", `"\ufffd"`},
1246 {Name(""), "\xff\xff", `"\ufffd\ufffd"`},
1247 {Name(""), "a\xffb", `"a\ufffdb"`},
1248 {Name(""), "\xe6\x97\xa5\xe6\x9c\xac\xff\xaa\x9e", `"日本\ufffd\ufffd\ufffd"`},
1249 }
1250 for _, tt := range tests {
1251 t.Run(tt.Name, func(t *testing.T) {
1252 got, err := Marshal(tt.in)
1253 if string(got) != tt.want || err != nil {
1254 t.Errorf("%s: Marshal(%q):\n\tgot: (%q, %v)\n\twant: (%q, nil)", tt.Where, tt.in, got, err, tt.want)
1255 }
1256 })
1257 }
1258 }
1259
1260 func TestMarshalNumberZeroVal(t *testing.T) {
1261 var n Number
1262 out, err := Marshal(n)
1263 if err != nil {
1264 t.Fatalf("Marshal error: %v", err)
1265 }
1266 got := string(out)
1267 if got != "0" {
1268 t.Fatalf("Marshal: got %s, want 0", got)
1269 }
1270 }
1271
1272 func TestMarshalEmbeds(t *testing.T) {
1273 top := &Top{
1274 Level0: 1,
1275 Embed0: Embed0{
1276 Level1b: 2,
1277 Level1c: 3,
1278 },
1279 Embed0a: &Embed0a{
1280 Level1a: 5,
1281 Level1b: 6,
1282 },
1283 Embed0b: &Embed0b{
1284 Level1a: 8,
1285 Level1b: 9,
1286 Level1c: 10,
1287 Level1d: 11,
1288 Level1e: 12,
1289 },
1290 Loop: Loop{
1291 Loop1: 13,
1292 Loop2: 14,
1293 },
1294 Embed0p: Embed0p{
1295 Point: image.Point{X: 15, Y: 16},
1296 },
1297 Embed0q: Embed0q{
1298 Point: Point{Z: 17},
1299 },
1300 embed: embed{
1301 Q: 18,
1302 },
1303 }
1304 got, err := Marshal(top)
1305 if err != nil {
1306 t.Fatalf("Marshal error: %v", err)
1307 }
1308 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}"
1309 if string(got) != want {
1310 t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want)
1311 }
1312 }
1313
1314 func equalError(a, b error) bool {
1315 isJSONError := func(err error) bool {
1316 switch err.(type) {
1317 case
1318 *InvalidUTF8Error,
1319 *InvalidUnmarshalError,
1320 *MarshalerError,
1321 *SyntaxError,
1322 *UnmarshalFieldError,
1323 *UnmarshalTypeError,
1324 *UnsupportedTypeError,
1325 *UnsupportedValueError:
1326 return true
1327 }
1328 return false
1329 }
1330
1331 if a == nil || b == nil {
1332 return a == nil && b == nil
1333 }
1334 if isJSONError(a) || isJSONError(b) {
1335 return reflect.DeepEqual(a, b)
1336 }
1337 return a.Error() == b.Error()
1338 }
1339
1340 func TestUnmarshal(t *testing.T) {
1341 for _, tt := range unmarshalTests {
1342 t.Run(tt.Name, func(t *testing.T) {
1343 in := []byte(tt.in)
1344 var scan scanner
1345 if err := checkValid(in, &scan); err != nil {
1346 if !equalError(err, tt.err) {
1347 t.Fatalf("%s: checkValid error:\n\tgot %#v\n\twant %#v", tt.Where, err, tt.err)
1348 }
1349 }
1350 if tt.ptr == nil {
1351 return
1352 }
1353
1354 typ := reflect.TypeOf(tt.ptr)
1355 if typ.Kind() != reflect.Pointer {
1356 t.Fatalf("%s: unmarshalTest.ptr %T is not a pointer type", tt.Where, tt.ptr)
1357 }
1358 typ = typ.Elem()
1359
1360
1361 v := reflect.New(typ)
1362
1363 if !reflect.DeepEqual(tt.ptr, v.Interface()) {
1364
1365
1366
1367
1368
1369
1370 t.Fatalf("%s: unmarshalTest.ptr %#v is not a pointer to a zero value", tt.Where, tt.ptr)
1371 }
1372
1373 dec := NewDecoder(bytes.NewReader(in))
1374 if tt.useNumber {
1375 dec.UseNumber()
1376 }
1377 if tt.disallowUnknownFields {
1378 dec.DisallowUnknownFields()
1379 }
1380 if err := dec.Decode(v.Interface()); !equalError(err, tt.err) {
1381 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)
1382 } else if err != nil && tt.out == nil {
1383
1384
1385 tt.out = reflect.Zero(v.Elem().Type()).Interface()
1386 }
1387 if got := v.Elem().Interface(); !reflect.DeepEqual(got, tt.out) {
1388 gotJSON, _ := Marshal(got)
1389 wantJSON, _ := Marshal(tt.out)
1390 t.Fatalf("%s: Decode:\n\tgot: %#+v\n\twant: %#+v\n\n\tgotJSON: %s\n\twantJSON: %s", tt.Where, got, tt.out, gotJSON, wantJSON)
1391 }
1392
1393
1394 if tt.err == nil {
1395 enc, err := Marshal(v.Interface())
1396 if err != nil {
1397 t.Fatalf("%s: Marshal error after roundtrip: %v", tt.Where, err)
1398 }
1399 if tt.golden && !bytes.Equal(enc, in) {
1400 t.Errorf("%s: Marshal:\n\tgot: %s\n\twant: %s", tt.Where, enc, in)
1401 }
1402 vv := reflect.New(reflect.TypeOf(tt.ptr).Elem())
1403 dec = NewDecoder(bytes.NewReader(enc))
1404 if tt.useNumber {
1405 dec.UseNumber()
1406 }
1407 if err := dec.Decode(vv.Interface()); err != nil {
1408 t.Fatalf("%s: Decode(%#q) error after roundtrip: %v", tt.Where, enc, err)
1409 }
1410 if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().Interface()) {
1411 t.Fatalf("%s: Decode:\n\tgot: %#+v\n\twant: %#+v\n\n\tgotJSON: %s\n\twantJSON: %s",
1412 tt.Where, v.Elem().Interface(), vv.Elem().Interface(),
1413 stripWhitespace(string(enc)), stripWhitespace(string(in)))
1414 }
1415 }
1416 })
1417 }
1418 }
1419
1420 func TestUnmarshalMarshal(t *testing.T) {
1421 initBig()
1422 var v any
1423 if err := Unmarshal(jsonBig, &v); err != nil {
1424 t.Fatalf("Unmarshal error: %v", err)
1425 }
1426 b, err := Marshal(v)
1427 if err != nil {
1428 t.Fatalf("Marshal error: %v", err)
1429 }
1430 if !bytes.Equal(jsonBig, b) {
1431 t.Errorf("Marshal:")
1432 diff(t, b, jsonBig)
1433 return
1434 }
1435 }
1436
1437
1438 func TestNumberAccessors(t *testing.T) {
1439 tests := []struct {
1440 CaseName
1441 in string
1442 i int64
1443 intErr string
1444 f float64
1445 floatErr string
1446 }{
1447 {CaseName: Name(""), in: "-1.23e1", intErr: "strconv.ParseInt: parsing \"-1.23e1\": invalid syntax", f: -1.23e1},
1448 {CaseName: Name(""), in: "-12", i: -12, f: -12.0},
1449 {CaseName: Name(""), in: "1e1000", intErr: "strconv.ParseInt: parsing \"1e1000\": invalid syntax", floatErr: "strconv.ParseFloat: parsing \"1e1000\": value out of range"},
1450 }
1451 for _, tt := range tests {
1452 t.Run(tt.Name, func(t *testing.T) {
1453 n := Number(tt.in)
1454 if got := n.String(); got != tt.in {
1455 t.Errorf("%s: Number(%q).String() = %s, want %s", tt.Where, tt.in, got, tt.in)
1456 }
1457 if i, err := n.Int64(); err == nil && tt.intErr == "" && i != tt.i {
1458 t.Errorf("%s: Number(%q).Int64() = %d, want %d", tt.Where, tt.in, i, tt.i)
1459 } else if (err == nil && tt.intErr != "") || (err != nil && err.Error() != tt.intErr) {
1460 t.Errorf("%s: Number(%q).Int64() error:\n\tgot: %v\n\twant: %v", tt.Where, tt.in, err, tt.intErr)
1461 }
1462 if f, err := n.Float64(); err == nil && tt.floatErr == "" && f != tt.f {
1463 t.Errorf("%s: Number(%q).Float64() = %g, want %g", tt.Where, tt.in, f, tt.f)
1464 } else if (err == nil && tt.floatErr != "") || (err != nil && err.Error() != tt.floatErr) {
1465 t.Errorf("%s: Number(%q).Float64() error:\n\tgot %v\n\twant: %v", tt.Where, tt.in, err, tt.floatErr)
1466 }
1467 })
1468 }
1469 }
1470
1471 func TestLargeByteSlice(t *testing.T) {
1472 s0 := make([]byte, 2000)
1473 for i := range s0 {
1474 s0[i] = byte(i)
1475 }
1476 b, err := Marshal(s0)
1477 if err != nil {
1478 t.Fatalf("Marshal error: %v", err)
1479 }
1480 var s1 []byte
1481 if err := Unmarshal(b, &s1); err != nil {
1482 t.Fatalf("Unmarshal error: %v", err)
1483 }
1484 if !bytes.Equal(s0, s1) {
1485 t.Errorf("Marshal:")
1486 diff(t, s0, s1)
1487 }
1488 }
1489
1490 type Xint struct {
1491 X int
1492 }
1493
1494 func TestUnmarshalInterface(t *testing.T) {
1495 var xint Xint
1496 var i any = &xint
1497 if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil {
1498 t.Fatalf("Unmarshal error: %v", err)
1499 }
1500 if xint.X != 1 {
1501 t.Fatalf("xint.X = %d, want 1", xint.X)
1502 }
1503 }
1504
1505 func TestUnmarshalPtrPtr(t *testing.T) {
1506 var xint Xint
1507 pxint := &xint
1508 if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil {
1509 t.Fatalf("Unmarshal: %v", err)
1510 }
1511 if xint.X != 1 {
1512 t.Fatalf("xint.X = %d, want 1", xint.X)
1513 }
1514 }
1515
1516 func TestEscape(t *testing.T) {
1517 const input = `"foobar"<html>` + " [\u2028 \u2029]"
1518 const want = `"\"foobar\"\u003chtml\u003e [\u2028 \u2029]"`
1519 got, err := Marshal(input)
1520 if err != nil {
1521 t.Fatalf("Marshal error: %v", err)
1522 }
1523 if string(got) != want {
1524 t.Errorf("Marshal(%#q):\n\tgot: %s\n\twant: %s", input, got, want)
1525 }
1526 }
1527
1528
1529
1530 func TestErrorMessageFromMisusedString(t *testing.T) {
1531
1532 type WrongString struct {
1533 Message string `json:"result,string"`
1534 }
1535 tests := []struct {
1536 CaseName
1537 in, err string
1538 }{
1539 {Name(""), `{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`},
1540 {Name(""), `{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`},
1541 {Name(""), `{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`},
1542 {Name(""), `{"result":123}`, `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into string`},
1543 {Name(""), `{"result":"\""}`, `json: invalid use of ,string struct tag, trying to unmarshal "\"" into string`},
1544 {Name(""), `{"result":"\"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "\"foo" into string`},
1545 }
1546 for _, tt := range tests {
1547 t.Run(tt.Name, func(t *testing.T) {
1548 r := strings.NewReader(tt.in)
1549 var s WrongString
1550 err := NewDecoder(r).Decode(&s)
1551 got := fmt.Sprintf("%v", err)
1552 if got != tt.err {
1553 t.Errorf("%s: Decode error:\n\tgot: %s\n\twant: %s", tt.Where, got, tt.err)
1554 }
1555 })
1556 }
1557 }
1558
1559 type All struct {
1560 Bool bool
1561 Int int
1562 Int8 int8
1563 Int16 int16
1564 Int32 int32
1565 Int64 int64
1566 Uint uint
1567 Uint8 uint8
1568 Uint16 uint16
1569 Uint32 uint32
1570 Uint64 uint64
1571 Uintptr uintptr
1572 Float32 float32
1573 Float64 float64
1574
1575 Foo string `json:"bar"`
1576 Foo2 string `json:"bar2,dummyopt"`
1577
1578 IntStr int64 `json:",string"`
1579 UintptrStr uintptr `json:",string"`
1580
1581 PBool *bool
1582 PInt *int
1583 PInt8 *int8
1584 PInt16 *int16
1585 PInt32 *int32
1586 PInt64 *int64
1587 PUint *uint
1588 PUint8 *uint8
1589 PUint16 *uint16
1590 PUint32 *uint32
1591 PUint64 *uint64
1592 PUintptr *uintptr
1593 PFloat32 *float32
1594 PFloat64 *float64
1595
1596 String string
1597 PString *string
1598
1599 Map map[string]Small
1600 MapP map[string]*Small
1601 PMap *map[string]Small
1602 PMapP *map[string]*Small
1603
1604 EmptyMap map[string]Small
1605 NilMap map[string]Small
1606
1607 Slice []Small
1608 SliceP []*Small
1609 PSlice *[]Small
1610 PSliceP *[]*Small
1611
1612 EmptySlice []Small
1613 NilSlice []Small
1614
1615 StringSlice []string
1616 ByteSlice []byte
1617
1618 Small Small
1619 PSmall *Small
1620 PPSmall **Small
1621
1622 Interface any
1623 PInterface *any
1624
1625 unexported int
1626 }
1627
1628 type Small struct {
1629 Tag string
1630 }
1631
1632 var allValue = All{
1633 Bool: true,
1634 Int: 2,
1635 Int8: 3,
1636 Int16: 4,
1637 Int32: 5,
1638 Int64: 6,
1639 Uint: 7,
1640 Uint8: 8,
1641 Uint16: 9,
1642 Uint32: 10,
1643 Uint64: 11,
1644 Uintptr: 12,
1645 Float32: 14.1,
1646 Float64: 15.1,
1647 Foo: "foo",
1648 Foo2: "foo2",
1649 IntStr: 42,
1650 UintptrStr: 44,
1651 String: "16",
1652 Map: map[string]Small{
1653 "17": {Tag: "tag17"},
1654 "18": {Tag: "tag18"},
1655 },
1656 MapP: map[string]*Small{
1657 "19": {Tag: "tag19"},
1658 "20": nil,
1659 },
1660 EmptyMap: map[string]Small{},
1661 Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}},
1662 SliceP: []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}},
1663 EmptySlice: []Small{},
1664 StringSlice: []string{"str24", "str25", "str26"},
1665 ByteSlice: []byte{27, 28, 29},
1666 Small: Small{Tag: "tag30"},
1667 PSmall: &Small{Tag: "tag31"},
1668 Interface: 5.2,
1669 }
1670
1671 var pallValue = All{
1672 PBool: &allValue.Bool,
1673 PInt: &allValue.Int,
1674 PInt8: &allValue.Int8,
1675 PInt16: &allValue.Int16,
1676 PInt32: &allValue.Int32,
1677 PInt64: &allValue.Int64,
1678 PUint: &allValue.Uint,
1679 PUint8: &allValue.Uint8,
1680 PUint16: &allValue.Uint16,
1681 PUint32: &allValue.Uint32,
1682 PUint64: &allValue.Uint64,
1683 PUintptr: &allValue.Uintptr,
1684 PFloat32: &allValue.Float32,
1685 PFloat64: &allValue.Float64,
1686 PString: &allValue.String,
1687 PMap: &allValue.Map,
1688 PMapP: &allValue.MapP,
1689 PSlice: &allValue.Slice,
1690 PSliceP: &allValue.SliceP,
1691 PPSmall: &allValue.PSmall,
1692 PInterface: &allValue.Interface,
1693 }
1694
1695 var allValueIndent = `{
1696 "Bool": true,
1697 "Int": 2,
1698 "Int8": 3,
1699 "Int16": 4,
1700 "Int32": 5,
1701 "Int64": 6,
1702 "Uint": 7,
1703 "Uint8": 8,
1704 "Uint16": 9,
1705 "Uint32": 10,
1706 "Uint64": 11,
1707 "Uintptr": 12,
1708 "Float32": 14.1,
1709 "Float64": 15.1,
1710 "bar": "foo",
1711 "bar2": "foo2",
1712 "IntStr": "42",
1713 "UintptrStr": "44",
1714 "PBool": null,
1715 "PInt": null,
1716 "PInt8": null,
1717 "PInt16": null,
1718 "PInt32": null,
1719 "PInt64": null,
1720 "PUint": null,
1721 "PUint8": null,
1722 "PUint16": null,
1723 "PUint32": null,
1724 "PUint64": null,
1725 "PUintptr": null,
1726 "PFloat32": null,
1727 "PFloat64": null,
1728 "String": "16",
1729 "PString": null,
1730 "Map": {
1731 "17": {
1732 "Tag": "tag17"
1733 },
1734 "18": {
1735 "Tag": "tag18"
1736 }
1737 },
1738 "MapP": {
1739 "19": {
1740 "Tag": "tag19"
1741 },
1742 "20": null
1743 },
1744 "PMap": null,
1745 "PMapP": null,
1746 "EmptyMap": {},
1747 "NilMap": null,
1748 "Slice": [
1749 {
1750 "Tag": "tag20"
1751 },
1752 {
1753 "Tag": "tag21"
1754 }
1755 ],
1756 "SliceP": [
1757 {
1758 "Tag": "tag22"
1759 },
1760 null,
1761 {
1762 "Tag": "tag23"
1763 }
1764 ],
1765 "PSlice": null,
1766 "PSliceP": null,
1767 "EmptySlice": [],
1768 "NilSlice": null,
1769 "StringSlice": [
1770 "str24",
1771 "str25",
1772 "str26"
1773 ],
1774 "ByteSlice": "Gxwd",
1775 "Small": {
1776 "Tag": "tag30"
1777 },
1778 "PSmall": {
1779 "Tag": "tag31"
1780 },
1781 "PPSmall": null,
1782 "Interface": 5.2,
1783 "PInterface": null
1784 }`
1785
1786 var allValueCompact = stripWhitespace(allValueIndent)
1787
1788 var pallValueIndent = `{
1789 "Bool": false,
1790 "Int": 0,
1791 "Int8": 0,
1792 "Int16": 0,
1793 "Int32": 0,
1794 "Int64": 0,
1795 "Uint": 0,
1796 "Uint8": 0,
1797 "Uint16": 0,
1798 "Uint32": 0,
1799 "Uint64": 0,
1800 "Uintptr": 0,
1801 "Float32": 0,
1802 "Float64": 0,
1803 "bar": "",
1804 "bar2": "",
1805 "IntStr": "0",
1806 "UintptrStr": "0",
1807 "PBool": true,
1808 "PInt": 2,
1809 "PInt8": 3,
1810 "PInt16": 4,
1811 "PInt32": 5,
1812 "PInt64": 6,
1813 "PUint": 7,
1814 "PUint8": 8,
1815 "PUint16": 9,
1816 "PUint32": 10,
1817 "PUint64": 11,
1818 "PUintptr": 12,
1819 "PFloat32": 14.1,
1820 "PFloat64": 15.1,
1821 "String": "",
1822 "PString": "16",
1823 "Map": null,
1824 "MapP": null,
1825 "PMap": {
1826 "17": {
1827 "Tag": "tag17"
1828 },
1829 "18": {
1830 "Tag": "tag18"
1831 }
1832 },
1833 "PMapP": {
1834 "19": {
1835 "Tag": "tag19"
1836 },
1837 "20": null
1838 },
1839 "EmptyMap": null,
1840 "NilMap": null,
1841 "Slice": null,
1842 "SliceP": null,
1843 "PSlice": [
1844 {
1845 "Tag": "tag20"
1846 },
1847 {
1848 "Tag": "tag21"
1849 }
1850 ],
1851 "PSliceP": [
1852 {
1853 "Tag": "tag22"
1854 },
1855 null,
1856 {
1857 "Tag": "tag23"
1858 }
1859 ],
1860 "EmptySlice": null,
1861 "NilSlice": null,
1862 "StringSlice": null,
1863 "ByteSlice": null,
1864 "Small": {
1865 "Tag": ""
1866 },
1867 "PSmall": null,
1868 "PPSmall": {
1869 "Tag": "tag31"
1870 },
1871 "Interface": null,
1872 "PInterface": 5.2
1873 }`
1874
1875 var pallValueCompact = stripWhitespace(pallValueIndent)
1876
1877 func TestRefUnmarshal(t *testing.T) {
1878 type S struct {
1879
1880 R0 Ref
1881 R1 *Ref
1882 R2 RefText
1883 R3 *RefText
1884 }
1885 want := S{
1886 R0: 12,
1887 R1: new(Ref),
1888 R2: 13,
1889 R3: new(RefText),
1890 }
1891 *want.R1 = 12
1892 *want.R3 = 13
1893
1894 var got S
1895 if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref","R2":"ref","R3":"ref"}`), &got); err != nil {
1896 t.Fatalf("Unmarshal error: %v", err)
1897 }
1898 if !reflect.DeepEqual(got, want) {
1899 t.Errorf("Unmarsha:\n\tgot: %+v\n\twant: %+v", got, want)
1900 }
1901 }
1902
1903
1904
1905 func TestEmptyString(t *testing.T) {
1906 type T2 struct {
1907 Number1 int `json:",string"`
1908 Number2 int `json:",string"`
1909 }
1910 data := `{"Number1":"1", "Number2":""}`
1911 dec := NewDecoder(strings.NewReader(data))
1912 var got T2
1913 switch err := dec.Decode(&got); {
1914 case err == nil:
1915 t.Fatalf("Decode error: got nil, want non-nil")
1916 case got.Number1 != 1:
1917 t.Fatalf("Decode: got.Number1 = %d, want 1", got.Number1)
1918 }
1919 }
1920
1921
1922
1923 func TestNullString(t *testing.T) {
1924 type T struct {
1925 A int `json:",string"`
1926 B int `json:",string"`
1927 C *int `json:",string"`
1928 }
1929 data := []byte(`{"A": "1", "B": null, "C": null}`)
1930 var s T
1931 s.B = 1
1932 s.C = new(int)
1933 *s.C = 2
1934 switch err := Unmarshal(data, &s); {
1935 case err != nil:
1936 t.Fatalf("Unmarshal error: %v", err)
1937 case s.B != 1:
1938 t.Fatalf("Unmarshal: s.B = %d, want 1", s.B)
1939 case s.C != nil:
1940 t.Fatalf("Unmarshal: s.C = %d, want non-nil", s.C)
1941 }
1942 }
1943
1944 func addr[T any](v T) *T {
1945 return &v
1946 }
1947
1948 func TestInterfaceSet(t *testing.T) {
1949 errUnmarshal := &UnmarshalTypeError{Value: "object", Offset: 6, Type: reflect.TypeFor[int](), Field: "X"}
1950 tests := []struct {
1951 CaseName
1952 pre any
1953 json string
1954 post any
1955 }{
1956 {Name(""), "foo", `"bar"`, "bar"},
1957 {Name(""), "foo", `2`, 2.0},
1958 {Name(""), "foo", `true`, true},
1959 {Name(""), "foo", `null`, nil},
1960 {Name(""), map[string]any{}, `true`, true},
1961 {Name(""), []string{}, `true`, true},
1962
1963 {Name(""), any(nil), `null`, any(nil)},
1964 {Name(""), (*int)(nil), `null`, any(nil)},
1965 {Name(""), (*int)(addr(0)), `null`, any(nil)},
1966 {Name(""), (*int)(addr(1)), `null`, any(nil)},
1967 {Name(""), (**int)(nil), `null`, any(nil)},
1968 {Name(""), (**int)(addr[*int](nil)), `null`, (**int)(addr[*int](nil))},
1969 {Name(""), (**int)(addr(addr(1))), `null`, (**int)(addr[*int](nil))},
1970 {Name(""), (***int)(nil), `null`, any(nil)},
1971 {Name(""), (***int)(addr[**int](nil)), `null`, (***int)(addr[**int](nil))},
1972 {Name(""), (***int)(addr(addr[*int](nil))), `null`, (***int)(addr[**int](nil))},
1973 {Name(""), (***int)(addr(addr(addr(1)))), `null`, (***int)(addr[**int](nil))},
1974
1975 {Name(""), any(nil), `2`, float64(2)},
1976 {Name(""), (int)(1), `2`, float64(2)},
1977 {Name(""), (*int)(nil), `2`, float64(2)},
1978 {Name(""), (*int)(addr(0)), `2`, (*int)(addr(2))},
1979 {Name(""), (*int)(addr(1)), `2`, (*int)(addr(2))},
1980 {Name(""), (**int)(nil), `2`, float64(2)},
1981 {Name(""), (**int)(addr[*int](nil)), `2`, (**int)(addr(addr(2)))},
1982 {Name(""), (**int)(addr(addr(1))), `2`, (**int)(addr(addr(2)))},
1983 {Name(""), (***int)(nil), `2`, float64(2)},
1984 {Name(""), (***int)(addr[**int](nil)), `2`, (***int)(addr(addr(addr(2))))},
1985 {Name(""), (***int)(addr(addr[*int](nil))), `2`, (***int)(addr(addr(addr(2))))},
1986 {Name(""), (***int)(addr(addr(addr(1)))), `2`, (***int)(addr(addr(addr(2))))},
1987
1988 {Name(""), any(nil), `{}`, map[string]any{}},
1989 {Name(""), (int)(1), `{}`, map[string]any{}},
1990 {Name(""), (*int)(nil), `{}`, map[string]any{}},
1991 {Name(""), (*int)(addr(0)), `{}`, errUnmarshal},
1992 {Name(""), (*int)(addr(1)), `{}`, errUnmarshal},
1993 {Name(""), (**int)(nil), `{}`, map[string]any{}},
1994 {Name(""), (**int)(addr[*int](nil)), `{}`, errUnmarshal},
1995 {Name(""), (**int)(addr(addr(1))), `{}`, errUnmarshal},
1996 {Name(""), (***int)(nil), `{}`, map[string]any{}},
1997 {Name(""), (***int)(addr[**int](nil)), `{}`, errUnmarshal},
1998 {Name(""), (***int)(addr(addr[*int](nil))), `{}`, errUnmarshal},
1999 {Name(""), (***int)(addr(addr(addr(1)))), `{}`, errUnmarshal},
2000 }
2001 for _, tt := range tests {
2002 t.Run(tt.Name, func(t *testing.T) {
2003 b := struct{ X any }{tt.pre}
2004 blob := `{"X":` + tt.json + `}`
2005 if err := Unmarshal([]byte(blob), &b); err != nil {
2006 if wantErr, _ := tt.post.(error); equalError(err, wantErr) {
2007 return
2008 }
2009 t.Fatalf("%s: Unmarshal(%#q) error: %v", tt.Where, blob, err)
2010 }
2011 if !reflect.DeepEqual(b.X, tt.post) {
2012 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)
2013 }
2014 })
2015 }
2016 }
2017
2018 type NullTest struct {
2019 Bool bool
2020 Int int
2021 Int8 int8
2022 Int16 int16
2023 Int32 int32
2024 Int64 int64
2025 Uint uint
2026 Uint8 uint8
2027 Uint16 uint16
2028 Uint32 uint32
2029 Uint64 uint64
2030 Float32 float32
2031 Float64 float64
2032 String string
2033 PBool *bool
2034 Map map[string]string
2035 Slice []string
2036 Interface any
2037
2038 PRaw *RawMessage
2039 PTime *time.Time
2040 PBigInt *big.Int
2041 PText *MustNotUnmarshalText
2042 PBuffer *bytes.Buffer
2043 PStruct *struct{}
2044
2045 Raw RawMessage
2046 Time time.Time
2047 BigInt big.Int
2048 Text MustNotUnmarshalText
2049 Buffer bytes.Buffer
2050 Struct struct{}
2051 }
2052
2053
2054
2055 func TestUnmarshalNulls(t *testing.T) {
2056
2057
2058
2059
2060
2061
2062 jsonData := []byte(`{
2063 "Bool" : null,
2064 "Int" : null,
2065 "Int8" : null,
2066 "Int16" : null,
2067 "Int32" : null,
2068 "Int64" : null,
2069 "Uint" : null,
2070 "Uint8" : null,
2071 "Uint16" : null,
2072 "Uint32" : null,
2073 "Uint64" : null,
2074 "Float32" : null,
2075 "Float64" : null,
2076 "String" : null,
2077 "PBool": null,
2078 "Map": null,
2079 "Slice": null,
2080 "Interface": null,
2081 "PRaw": null,
2082 "PTime": null,
2083 "PBigInt": null,
2084 "PText": null,
2085 "PBuffer": null,
2086 "PStruct": null,
2087 "Raw": null,
2088 "Time": null,
2089 "BigInt": null,
2090 "Text": null,
2091 "Buffer": null,
2092 "Struct": null
2093 }`)
2094 nulls := NullTest{
2095 Bool: true,
2096 Int: 2,
2097 Int8: 3,
2098 Int16: 4,
2099 Int32: 5,
2100 Int64: 6,
2101 Uint: 7,
2102 Uint8: 8,
2103 Uint16: 9,
2104 Uint32: 10,
2105 Uint64: 11,
2106 Float32: 12.1,
2107 Float64: 13.1,
2108 String: "14",
2109 PBool: new(bool),
2110 Map: map[string]string{},
2111 Slice: []string{},
2112 Interface: new(MustNotUnmarshalJSON),
2113 PRaw: new(RawMessage),
2114 PTime: new(time.Time),
2115 PBigInt: new(big.Int),
2116 PText: new(MustNotUnmarshalText),
2117 PStruct: new(struct{}),
2118 PBuffer: new(bytes.Buffer),
2119 Raw: RawMessage("123"),
2120 Time: time.Unix(123456789, 0),
2121 BigInt: *big.NewInt(123),
2122 }
2123
2124 before := nulls.Time.String()
2125
2126 err := Unmarshal(jsonData, &nulls)
2127 if err != nil {
2128 t.Errorf("Unmarshal of null values failed: %v", err)
2129 }
2130 if !nulls.Bool || nulls.Int != 2 || nulls.Int8 != 3 || nulls.Int16 != 4 || nulls.Int32 != 5 || nulls.Int64 != 6 ||
2131 nulls.Uint != 7 || nulls.Uint8 != 8 || nulls.Uint16 != 9 || nulls.Uint32 != 10 || nulls.Uint64 != 11 ||
2132 nulls.Float32 != 12.1 || nulls.Float64 != 13.1 || nulls.String != "14" {
2133 t.Errorf("Unmarshal of null values affected primitives")
2134 }
2135
2136 if nulls.PBool != nil {
2137 t.Errorf("Unmarshal of null did not clear nulls.PBool")
2138 }
2139 if nulls.Map != nil {
2140 t.Errorf("Unmarshal of null did not clear nulls.Map")
2141 }
2142 if nulls.Slice != nil {
2143 t.Errorf("Unmarshal of null did not clear nulls.Slice")
2144 }
2145 if nulls.Interface != nil {
2146 t.Errorf("Unmarshal of null did not clear nulls.Interface")
2147 }
2148 if nulls.PRaw != nil {
2149 t.Errorf("Unmarshal of null did not clear nulls.PRaw")
2150 }
2151 if nulls.PTime != nil {
2152 t.Errorf("Unmarshal of null did not clear nulls.PTime")
2153 }
2154 if nulls.PBigInt != nil {
2155 t.Errorf("Unmarshal of null did not clear nulls.PBigInt")
2156 }
2157 if nulls.PText != nil {
2158 t.Errorf("Unmarshal of null did not clear nulls.PText")
2159 }
2160 if nulls.PBuffer != nil {
2161 t.Errorf("Unmarshal of null did not clear nulls.PBuffer")
2162 }
2163 if nulls.PStruct != nil {
2164 t.Errorf("Unmarshal of null did not clear nulls.PStruct")
2165 }
2166
2167 if string(nulls.Raw) != "null" {
2168 t.Errorf("Unmarshal of RawMessage null did not record null: %v", string(nulls.Raw))
2169 }
2170 if nulls.Time.String() != before {
2171 t.Errorf("Unmarshal of time.Time null set time to %v", nulls.Time.String())
2172 }
2173 if nulls.BigInt.String() != "123" {
2174 t.Errorf("Unmarshal of big.Int null set int to %v", nulls.BigInt.String())
2175 }
2176 }
2177
2178 type MustNotUnmarshalJSON struct{}
2179
2180 func (x MustNotUnmarshalJSON) UnmarshalJSON(data []byte) error {
2181 return errors.New("MustNotUnmarshalJSON was used")
2182 }
2183
2184 type MustNotUnmarshalText struct{}
2185
2186 func (x MustNotUnmarshalText) UnmarshalText(text []byte) error {
2187 return errors.New("MustNotUnmarshalText was used")
2188 }
2189
2190 func TestStringKind(t *testing.T) {
2191 type stringKind string
2192 want := map[stringKind]int{"foo": 42}
2193 data, err := Marshal(want)
2194 if err != nil {
2195 t.Fatalf("Marshal error: %v", err)
2196 }
2197 var got map[stringKind]int
2198 err = Unmarshal(data, &got)
2199 if err != nil {
2200 t.Fatalf("Unmarshal error: %v", err)
2201 }
2202 if !maps.Equal(got, want) {
2203 t.Fatalf("Marshal/Unmarshal mismatch:\n\tgot: %v\n\twant: %v", got, want)
2204 }
2205 }
2206
2207
2208
2209
2210 func TestByteKind(t *testing.T) {
2211 type byteKind []byte
2212 want := byteKind("hello")
2213 data, err := Marshal(want)
2214 if err != nil {
2215 t.Fatalf("Marshal error: %v", err)
2216 }
2217 var got byteKind
2218 err = Unmarshal(data, &got)
2219 if err != nil {
2220 t.Fatalf("Unmarshal error: %v", err)
2221 }
2222 if !slices.Equal(got, want) {
2223 t.Fatalf("Marshal/Unmarshal mismatch:\n\tgot: %v\n\twant: %v", got, want)
2224 }
2225 }
2226
2227
2228
2229 func TestSliceOfCustomByte(t *testing.T) {
2230 type Uint8 uint8
2231 want := []Uint8("hello")
2232 data, err := Marshal(want)
2233 if err != nil {
2234 t.Fatalf("Marshal error: %v", err)
2235 }
2236 var got []Uint8
2237 err = Unmarshal(data, &got)
2238 if err != nil {
2239 t.Fatalf("Unmarshal error: %v", err)
2240 }
2241 if !slices.Equal(got, want) {
2242 t.Fatalf("Marshal/Unmarshal mismatch:\n\tgot: %v\n\twant: %v", got, want)
2243 }
2244 }
2245
2246 func TestUnmarshalTypeError(t *testing.T) {
2247 tests := []struct {
2248 CaseName
2249 dest any
2250 in string
2251 }{
2252 {Name(""), new(string), `{"user": "name"}`},
2253 {Name(""), new(error), `{}`},
2254 {Name(""), new(error), `[]`},
2255 {Name(""), new(error), `""`},
2256 {Name(""), new(error), `123`},
2257 {Name(""), new(error), `true`},
2258 }
2259 for _, tt := range tests {
2260 t.Run(tt.Name, func(t *testing.T) {
2261 err := Unmarshal([]byte(tt.in), tt.dest)
2262 if _, ok := err.(*UnmarshalTypeError); !ok {
2263 t.Errorf("%s: Unmarshal(%#q, %T):\n\tgot: %T\n\twant: %T",
2264 tt.Where, tt.in, tt.dest, err, new(UnmarshalTypeError))
2265 }
2266 })
2267 }
2268 }
2269
2270 func TestUnmarshalSyntax(t *testing.T) {
2271 var x any
2272 tests := []struct {
2273 CaseName
2274 in string
2275 }{
2276 {Name(""), "tru"},
2277 {Name(""), "fals"},
2278 {Name(""), "nul"},
2279 {Name(""), "123e"},
2280 {Name(""), `"hello`},
2281 {Name(""), `[1,2,3`},
2282 {Name(""), `{"key":1`},
2283 {Name(""), `{"key":1,`},
2284 }
2285 for _, tt := range tests {
2286 t.Run(tt.Name, func(t *testing.T) {
2287 err := Unmarshal([]byte(tt.in), &x)
2288 if _, ok := err.(*SyntaxError); !ok {
2289 t.Errorf("%s: Unmarshal(%#q, any):\n\tgot: %T\n\twant: %T",
2290 tt.Where, tt.in, err, new(SyntaxError))
2291 }
2292 })
2293 }
2294 }
2295
2296
2297
2298 type unexportedFields struct {
2299 Name string
2300 m map[string]any `json:"-"`
2301 m2 map[string]any `json:"abcd"`
2302
2303 s []int `json:"-"`
2304 }
2305
2306 func TestUnmarshalUnexported(t *testing.T) {
2307 input := `{"Name": "Bob", "m": {"x": 123}, "m2": {"y": 456}, "abcd": {"z": 789}, "s": [2, 3]}`
2308 want := &unexportedFields{Name: "Bob"}
2309
2310 out := &unexportedFields{}
2311 err := Unmarshal([]byte(input), out)
2312 if err != nil {
2313 t.Errorf("Unmarshal error: %v", err)
2314 }
2315 if !reflect.DeepEqual(out, want) {
2316 t.Errorf("Unmarshal:\n\tgot: %+v\n\twant: %+v", out, want)
2317 }
2318 }
2319
2320
2321
2322 type Time3339 time.Time
2323
2324 func (t *Time3339) UnmarshalJSON(b []byte) error {
2325 if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' {
2326 return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time", b)
2327 }
2328 tm, err := time.Parse(time.RFC3339, string(b[1:len(b)-1]))
2329 if err != nil {
2330 return err
2331 }
2332 *t = Time3339(tm)
2333 return nil
2334 }
2335
2336 func TestUnmarshalJSONLiteralError(t *testing.T) {
2337 var t3 Time3339
2338 switch err := Unmarshal([]byte(`"0000-00-00T00:00:00Z"`), &t3); {
2339 case err == nil:
2340 t.Fatalf("Unmarshal error: got nil, want non-nil")
2341 case !strings.Contains(err.Error(), "range"):
2342 t.Errorf("Unmarshal error:\n\tgot: %v\n\twant: out of range", err)
2343 }
2344 }
2345
2346
2347
2348
2349 func TestSkipArrayObjects(t *testing.T) {
2350 json := `[{}]`
2351 var dest [0]any
2352
2353 err := Unmarshal([]byte(json), &dest)
2354 if err != nil {
2355 t.Errorf("Unmarshal error: %v", err)
2356 }
2357 }
2358
2359
2360
2361
2362 func TestPrefilled(t *testing.T) {
2363
2364 tests := []struct {
2365 CaseName
2366 in string
2367 ptr any
2368 out any
2369 }{{
2370 CaseName: Name(""),
2371 in: `{"X": 1, "Y": 2}`,
2372 ptr: &XYZ{X: float32(3), Y: int16(4), Z: 1.5},
2373 out: &XYZ{X: float64(1), Y: float64(2), Z: 1.5},
2374 }, {
2375 CaseName: Name(""),
2376 in: `{"X": 1, "Y": 2}`,
2377 ptr: &map[string]any{"X": float32(3), "Y": int16(4), "Z": 1.5},
2378 out: &map[string]any{"X": float64(1), "Y": float64(2), "Z": 1.5},
2379 }, {
2380 CaseName: Name(""),
2381 in: `[2]`,
2382 ptr: &[]int{1},
2383 out: &[]int{2},
2384 }, {
2385 CaseName: Name(""),
2386 in: `[2, 3]`,
2387 ptr: &[]int{1},
2388 out: &[]int{2, 3},
2389 }, {
2390 CaseName: Name(""),
2391 in: `[2, 3]`,
2392 ptr: &[...]int{1},
2393 out: &[...]int{2},
2394 }, {
2395 CaseName: Name(""),
2396 in: `[3]`,
2397 ptr: &[...]int{1, 2},
2398 out: &[...]int{3, 0},
2399 }}
2400 for _, tt := range tests {
2401 t.Run(tt.Name, func(t *testing.T) {
2402 ptrstr := fmt.Sprintf("%v", tt.ptr)
2403 err := Unmarshal([]byte(tt.in), tt.ptr)
2404 if err != nil {
2405 t.Errorf("%s: Unmarshal error: %v", tt.Where, err)
2406 }
2407 if !reflect.DeepEqual(tt.ptr, tt.out) {
2408 t.Errorf("%s: Unmarshal(%#q, %T):\n\tgot: %v\n\twant: %v", tt.Where, tt.in, ptrstr, tt.ptr, tt.out)
2409 }
2410 })
2411 }
2412 }
2413
2414 func TestInvalidUnmarshal(t *testing.T) {
2415 tests := []struct {
2416 CaseName
2417 in string
2418 v any
2419 wantErr error
2420 }{
2421 {Name(""), `{"a":"1"}`, nil, &InvalidUnmarshalError{}},
2422 {Name(""), `{"a":"1"}`, struct{}{}, &InvalidUnmarshalError{reflect.TypeFor[struct{}]()}},
2423 {Name(""), `{"a":"1"}`, (*int)(nil), &InvalidUnmarshalError{reflect.TypeFor[*int]()}},
2424 {Name(""), `123`, nil, &InvalidUnmarshalError{}},
2425 {Name(""), `123`, struct{}{}, &InvalidUnmarshalError{reflect.TypeFor[struct{}]()}},
2426 {Name(""), `123`, (*int)(nil), &InvalidUnmarshalError{reflect.TypeFor[*int]()}},
2427 {Name(""), `123`, new(net.IP), &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[*net.IP](), Offset: 3}},
2428 }
2429 for _, tt := range tests {
2430 t.Run(tt.Name, func(t *testing.T) {
2431 switch gotErr := Unmarshal([]byte(tt.in), tt.v); {
2432 case gotErr == nil:
2433 t.Fatalf("%s: Unmarshal error: got nil, want non-nil", tt.Where)
2434 case !reflect.DeepEqual(gotErr, tt.wantErr):
2435 t.Errorf("%s: Unmarshal error:\n\tgot: %#v\n\twant: %#v", tt.Where, gotErr, tt.wantErr)
2436 }
2437 })
2438 }
2439 }
2440
2441
2442
2443 func TestInvalidStringOption(t *testing.T) {
2444 num := 0
2445 item := struct {
2446 T time.Time `json:",string"`
2447 M map[string]string `json:",string"`
2448 S []string `json:",string"`
2449 A [1]string `json:",string"`
2450 I any `json:",string"`
2451 P *int `json:",string"`
2452 }{M: make(map[string]string), S: make([]string, 0), I: num, P: &num}
2453
2454 data, err := Marshal(item)
2455 if err != nil {
2456 t.Fatalf("Marshal error: %v", err)
2457 }
2458
2459 err = Unmarshal(data, &item)
2460 if err != nil {
2461 t.Fatalf("Unmarshal error: %v", err)
2462 }
2463 }
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475 func TestUnmarshalEmbeddedUnexported(t *testing.T) {
2476 type (
2477 embed1 struct{ Q int }
2478 embed2 struct{ Q int }
2479 embed3 struct {
2480 Q int64 `json:",string"`
2481 }
2482 S1 struct {
2483 *embed1
2484 R int
2485 }
2486 S2 struct {
2487 *embed1
2488 Q int
2489 }
2490 S3 struct {
2491 embed1
2492 R int
2493 }
2494 S4 struct {
2495 *embed1
2496 embed2
2497 }
2498 S5 struct {
2499 *embed3
2500 R int
2501 }
2502 S6 struct {
2503 embed1 `json:"embed1"`
2504 }
2505 S7 struct {
2506 embed1 `json:"embed1"`
2507 embed2
2508 }
2509 S8 struct {
2510 embed1 `json:"embed1"`
2511 embed2 `json:"embed2"`
2512 Q int
2513 }
2514 S9 struct {
2515 unexportedWithMethods `json:"embed"`
2516 }
2517 )
2518
2519 tests := []struct {
2520 CaseName
2521 in string
2522 ptr any
2523 out any
2524 err error
2525 }{{
2526
2527 CaseName: Name(""),
2528 in: `{"R":2,"Q":1}`,
2529 ptr: new(S1),
2530 out: &S1{R: 2},
2531 err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed1"),
2532 }, {
2533
2534 CaseName: Name(""),
2535 in: `{"Q":1}`,
2536 ptr: new(S2),
2537 out: &S2{Q: 1},
2538 }, {
2539
2540 CaseName: Name(""),
2541 in: `{"R":2,"Q":1}`,
2542 ptr: new(S3),
2543 out: &S3{embed1: embed1{Q: 1}, R: 2},
2544 }, {
2545
2546
2547 CaseName: Name(""),
2548 in: `{"R":2}`,
2549 ptr: new(S4),
2550 out: new(S4),
2551 }, {
2552
2553 CaseName: Name(""),
2554 in: `{"R":2,"Q":1}`,
2555 ptr: new(S5),
2556 out: &S5{R: 2},
2557 err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed3"),
2558 }, {
2559
2560 CaseName: Name(""),
2561 in: `{"embed1": {"Q": 1}}`,
2562 ptr: new(S6),
2563 out: &S6{embed1{1}},
2564 }, {
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577 CaseName: Name(""),
2578 in: `{"embed1": {"Q": 1}, "Q": 2}`,
2579 ptr: new(S7),
2580 out: &S7{embed1{1}, embed2{2}},
2581 }, {
2582
2583 CaseName: Name(""),
2584 in: `{"embed1": {"Q": 1}, "embed2": {"Q": 2}, "Q": 3}`,
2585 ptr: new(S8),
2586 out: &S8{embed1{1}, embed2{2}, 3},
2587 }, {
2588
2589 CaseName: Name(""),
2590 in: `{"embed": {}}`,
2591 ptr: new(S9),
2592 out: &S9{},
2593 }}
2594 for _, tt := range tests {
2595 t.Run(tt.Name, func(t *testing.T) {
2596 err := Unmarshal([]byte(tt.in), tt.ptr)
2597 if !equalError(err, tt.err) {
2598 t.Errorf("%s: Unmarshal error:\n\tgot: %v\n\twant: %v", tt.Where, err, tt.err)
2599 }
2600 if !reflect.DeepEqual(tt.ptr, tt.out) {
2601 t.Errorf("%s: Unmarshal:\n\tgot: %#+v\n\twant: %#+v", tt.Where, tt.ptr, tt.out)
2602 }
2603 })
2604 }
2605 }
2606
2607 func TestUnmarshalErrorAfterMultipleJSON(t *testing.T) {
2608 tests := []struct {
2609 CaseName
2610 in string
2611 err error
2612 }{{
2613 CaseName: Name(""),
2614 in: `1 false null :`,
2615 err: &SyntaxError{"invalid character ':' looking for beginning of value", 14},
2616 }, {
2617 CaseName: Name(""),
2618 in: `1 [] [,]`,
2619 err: &SyntaxError{"invalid character ',' looking for beginning of value", 7},
2620 }, {
2621 CaseName: Name(""),
2622 in: `1 [] [true:]`,
2623 err: &SyntaxError{"invalid character ':' after array element", 11},
2624 }, {
2625 CaseName: Name(""),
2626 in: `1 {} {"x"=}`,
2627 err: &SyntaxError{"invalid character '=' after object key", 14},
2628 }, {
2629 CaseName: Name(""),
2630 in: `falsetruenul#`,
2631 err: &SyntaxError{"invalid character '#' in literal null (expecting 'l')", 13},
2632 }}
2633 for _, tt := range tests {
2634 t.Run(tt.Name, func(t *testing.T) {
2635 dec := NewDecoder(strings.NewReader(tt.in))
2636 var err error
2637 for err == nil {
2638 var v any
2639 err = dec.Decode(&v)
2640 }
2641 if !reflect.DeepEqual(err, tt.err) {
2642 t.Errorf("%s: Decode error:\n\tgot: %v\n\twant: %v", tt.Where, err, tt.err)
2643 }
2644 })
2645 }
2646 }
2647
2648 type unmarshalPanic struct{}
2649
2650 func (unmarshalPanic) UnmarshalJSON([]byte) error { panic(0xdead) }
2651
2652 func TestUnmarshalPanic(t *testing.T) {
2653 defer func() {
2654 if got := recover(); !reflect.DeepEqual(got, 0xdead) {
2655 t.Errorf("panic() = (%T)(%v), want 0xdead", got, got)
2656 }
2657 }()
2658 Unmarshal([]byte("{}"), &unmarshalPanic{})
2659 t.Fatalf("Unmarshal should have panicked")
2660 }
2661
2662
2663
2664 func TestUnmarshalRecursivePointer(t *testing.T) {
2665 var v any
2666 v = &v
2667 data := []byte(`{"a": "b"}`)
2668
2669 if err := Unmarshal(data, v); err != nil {
2670 t.Fatalf("Unmarshal error: %v", err)
2671 }
2672 }
2673
2674 type textUnmarshalerString string
2675
2676 func (m *textUnmarshalerString) UnmarshalText(text []byte) error {
2677 *m = textUnmarshalerString(strings.ToLower(string(text)))
2678 return nil
2679 }
2680
2681
2682
2683 func TestUnmarshalMapWithTextUnmarshalerStringKey(t *testing.T) {
2684 var p map[textUnmarshalerString]string
2685 if err := Unmarshal([]byte(`{"FOO": "1"}`), &p); err != nil {
2686 t.Fatalf("Unmarshal error: %v", err)
2687 }
2688
2689 if _, ok := p["foo"]; !ok {
2690 t.Errorf(`key "foo" missing in map: %v`, p)
2691 }
2692 }
2693
2694 func TestUnmarshalRescanLiteralMangledUnquote(t *testing.T) {
2695
2696 var p map[textUnmarshalerString]string
2697 if err := Unmarshal([]byte(`{"开源":"12345开源"}`), &p); err != nil {
2698 t.Fatalf("Unmarshal error: %v", err)
2699 }
2700 if _, ok := p["开源"]; !ok {
2701 t.Errorf(`key "开源" missing in map: %v`, p)
2702 }
2703
2704
2705 type T struct {
2706 F1 string `json:"F1,string"`
2707 }
2708 wantT := T{"aaa\tbbb"}
2709
2710 b, err := Marshal(wantT)
2711 if err != nil {
2712 t.Fatalf("Marshal error: %v", err)
2713 }
2714 var gotT T
2715 if err := Unmarshal(b, &gotT); err != nil {
2716 t.Fatalf("Unmarshal error: %v", err)
2717 }
2718 if gotT != wantT {
2719 t.Errorf("Marshal/Unmarshal roundtrip:\n\tgot: %q\n\twant: %q", gotT, wantT)
2720 }
2721
2722
2723 input := map[textUnmarshalerString]string{"FOO": "", `"`: ""}
2724
2725 encoded, err := Marshal(input)
2726 if err != nil {
2727 t.Fatalf("Marshal error: %v", err)
2728 }
2729 var got map[textUnmarshalerString]string
2730 if err := Unmarshal(encoded, &got); err != nil {
2731 t.Fatalf("Unmarshal error: %v", err)
2732 }
2733 want := map[textUnmarshalerString]string{"foo": "", `"`: ""}
2734 if !maps.Equal(got, want) {
2735 t.Errorf("Marshal/Unmarshal roundtrip:\n\tgot: %q\n\twant: %q", gotT, wantT)
2736 }
2737 }
2738
2739 func TestUnmarshalMaxDepth(t *testing.T) {
2740 tests := []struct {
2741 CaseName
2742 data string
2743 errMaxDepth bool
2744 }{{
2745 CaseName: Name("ArrayUnderMaxNestingDepth"),
2746 data: `{"a":` + strings.Repeat(`[`, 10000-1) + strings.Repeat(`]`, 10000-1) + `}`,
2747 errMaxDepth: false,
2748 }, {
2749 CaseName: Name("ArrayOverMaxNestingDepth"),
2750 data: `{"a":` + strings.Repeat(`[`, 10000) + strings.Repeat(`]`, 10000) + `}`,
2751 errMaxDepth: true,
2752 }, {
2753 CaseName: Name("ArrayOverStackDepth"),
2754 data: `{"a":` + strings.Repeat(`[`, 3000000) + strings.Repeat(`]`, 3000000) + `}`,
2755 errMaxDepth: true,
2756 }, {
2757 CaseName: Name("ObjectUnderMaxNestingDepth"),
2758 data: `{"a":` + strings.Repeat(`{"a":`, 10000-1) + `0` + strings.Repeat(`}`, 10000-1) + `}`,
2759 errMaxDepth: false,
2760 }, {
2761 CaseName: Name("ObjectOverMaxNestingDepth"),
2762 data: `{"a":` + strings.Repeat(`{"a":`, 10000) + `0` + strings.Repeat(`}`, 10000) + `}`,
2763 errMaxDepth: true,
2764 }, {
2765 CaseName: Name("ObjectOverStackDepth"),
2766 data: `{"a":` + strings.Repeat(`{"a":`, 3000000) + `0` + strings.Repeat(`}`, 3000000) + `}`,
2767 errMaxDepth: true,
2768 }}
2769
2770 targets := []struct {
2771 CaseName
2772 newValue func() any
2773 }{{
2774 CaseName: Name("unstructured"),
2775 newValue: func() any {
2776 var v any
2777 return &v
2778 },
2779 }, {
2780 CaseName: Name("typed named field"),
2781 newValue: func() any {
2782 v := struct {
2783 A any `json:"a"`
2784 }{}
2785 return &v
2786 },
2787 }, {
2788 CaseName: Name("typed missing field"),
2789 newValue: func() any {
2790 v := struct {
2791 B any `json:"b"`
2792 }{}
2793 return &v
2794 },
2795 }, {
2796 CaseName: Name("custom unmarshaler"),
2797 newValue: func() any {
2798 v := unmarshaler{}
2799 return &v
2800 },
2801 }}
2802
2803 for _, tt := range tests {
2804 for _, target := range targets {
2805 t.Run(target.Name+"-"+tt.Name, func(t *testing.T) {
2806 err := Unmarshal([]byte(tt.data), target.newValue())
2807 if !tt.errMaxDepth {
2808 if err != nil {
2809 t.Errorf("%s: %s: Unmarshal error: %v", tt.Where, target.Where, err)
2810 }
2811 } else {
2812 if err == nil || !strings.Contains(err.Error(), "exceeded max depth") {
2813 t.Errorf("%s: %s: Unmarshal error:\n\tgot: %v\n\twant: exceeded max depth", tt.Where, target.Where, err)
2814 }
2815 }
2816 })
2817 }
2818 }
2819 }
2820
View as plain text