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