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