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