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