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