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