1
2
3
4
5
6
7 package json
8
9 import (
10 "bytes"
11 "encoding"
12 "encoding/base32"
13 "encoding/base64"
14 "encoding/hex"
15 "errors"
16 "fmt"
17 "io"
18 "math"
19 "net"
20 "net/netip"
21 "reflect"
22 "strconv"
23 "strings"
24 "testing"
25 "time"
26
27 "encoding/json/internal"
28 "encoding/json/internal/jsonflags"
29 "encoding/json/internal/jsonopts"
30 "encoding/json/internal/jsontest"
31 "encoding/json/internal/jsonwire"
32 "encoding/json/jsontext"
33 )
34
35 func newNonStringNameError(offset int64, pointer jsontext.Pointer) error {
36 return &jsontext.SyntacticError{ByteOffset: offset, JSONPointer: pointer, Err: jsontext.ErrNonStringName}
37 }
38
39 func newInvalidCharacterError(prefix, where string, offset int64, pointer jsontext.Pointer) error {
40 return &jsontext.SyntacticError{ByteOffset: offset, JSONPointer: pointer, Err: jsonwire.NewInvalidCharacterError(prefix, where)}
41 }
42
43 func newInvalidUTF8Error(offset int64, pointer jsontext.Pointer) error {
44 return &jsontext.SyntacticError{ByteOffset: offset, JSONPointer: pointer, Err: jsonwire.ErrInvalidUTF8}
45 }
46
47 func newParseTimeError(layout, value, layoutElem, valueElem, message string) error {
48 return &time.ParseError{Layout: layout, Value: value, LayoutElem: layoutElem, ValueElem: valueElem, Message: message}
49 }
50
51 func EM(err error) *SemanticError {
52 return &SemanticError{action: "marshal", Err: err}
53 }
54
55 func EU(err error) *SemanticError {
56 return &SemanticError{action: "unmarshal", Err: err}
57 }
58
59 func (e *SemanticError) withVal(val string) *SemanticError {
60 e.JSONValue = jsontext.Value(val)
61 return e
62 }
63
64 func (e *SemanticError) withPos(prefix string, pointer jsontext.Pointer) *SemanticError {
65 e.ByteOffset = int64(len(prefix))
66 e.JSONPointer = pointer
67 return e
68 }
69
70 func (e *SemanticError) withType(k jsontext.Kind, t reflect.Type) *SemanticError {
71 e.JSONKind = k
72 e.GoType = t
73 return e
74 }
75
76 var (
77 errInvalidFormatFlag = errors.New(`invalid format flag "invalid"`)
78 errSomeError = errors.New("some error")
79 errMustNotCall = errors.New("must not call")
80 )
81
82 func T[T any]() reflect.Type { return reflect.TypeFor[T]() }
83
84 type (
85 jsonObject = map[string]any
86 jsonArray = []any
87
88 namedAny any
89 namedBool bool
90 namedString string
91 NamedString string
92 namedBytes []byte
93 namedInt64 int64
94 namedUint64 uint64
95 namedFloat64 float64
96 namedByte byte
97 netipAddr = netip.Addr
98
99 recursiveMap map[string]recursiveMap
100 recursiveSlice []recursiveSlice
101 recursivePointer struct{ P *recursivePointer }
102
103 structEmpty struct{}
104 structConflicting struct {
105 A string `json:"conflict"`
106 B string `json:"conflict"`
107 }
108 structNoneExported struct {
109 unexported string
110 }
111 structUnexportedIgnored struct {
112 ignored string `json:"-"`
113 }
114 structMalformedTag struct {
115 Malformed string `json:"\""`
116 }
117 structUnexportedTag struct {
118 unexported string `json:"name"`
119 }
120 structExportedEmbedded struct {
121 NamedString
122 }
123 structExportedEmbeddedTag struct {
124 NamedString `json:"name"`
125 }
126 structUnexportedEmbedded struct {
127 namedString
128 }
129 structUnexportedEmbeddedTag struct {
130 namedString `json:"name"`
131 }
132 structUnexportedEmbeddedMethodTag struct {
133
134
135 netipAddr `json:"name"`
136
137
138
139
140 }
141 structUnexportedEmbeddedStruct struct {
142 structOmitZeroAll
143 FizzBuzz int
144 structNestedAddr
145 }
146 structUnexportedEmbeddedStructPointer struct {
147 *structOmitZeroAll
148 FizzBuzz int
149 *structNestedAddr
150 }
151 structNestedAddr struct {
152 Addr netip.Addr
153 }
154 structIgnoredUnexportedEmbedded struct {
155 namedString `json:"-"`
156 }
157 structNoCase struct {
158 Aaa string `json:",case:strict"`
159 AA_A string
160 AaA string `json:",case:ignore"`
161 AAa string `json:",case:ignore"`
162 AAA string
163 }
164 structScalars struct {
165 unexported bool
166 Ignored bool `json:"-"`
167
168 Bool bool
169 String string
170 Bytes []byte
171 Int int64
172 Uint uint64
173 Float float64
174 }
175 structSlices struct {
176 unexported bool
177 Ignored bool `json:"-"`
178
179 SliceBool []bool
180 SliceString []string
181 SliceBytes [][]byte
182 SliceInt []int64
183 SliceUint []uint64
184 SliceFloat []float64
185 }
186 structMaps struct {
187 unexported bool
188 Ignored bool `json:"-"`
189
190 MapBool map[string]bool
191 MapString map[string]string
192 MapBytes map[string][]byte
193 MapInt map[string]int64
194 MapUint map[string]uint64
195 MapFloat map[string]float64
196 }
197 structAll struct {
198 Bool bool
199 String string
200 Bytes []byte
201 Int int64
202 Uint uint64
203 Float float64
204 Map map[string]string
205 StructScalars structScalars
206 StructMaps structMaps
207 StructSlices structSlices
208 Slice []string
209 Array [1]string
210 Pointer *structAll
211 Interface any
212 }
213 structOmitZeroAll struct {
214 Bool bool `json:",omitzero"`
215 String string `json:",omitzero"`
216 Bytes []byte `json:",omitzero"`
217 Int int64 `json:",omitzero"`
218 Uint uint64 `json:",omitzero"`
219 Float float64 `json:",omitzero"`
220 Map map[string]string `json:",omitzero"`
221 StructScalars structScalars `json:",omitzero"`
222 StructMaps structMaps `json:",omitzero"`
223 StructSlices structSlices `json:",omitzero"`
224 Slice []string `json:",omitzero"`
225 Array [1]string `json:",omitzero"`
226 Pointer *structOmitZeroAll `json:",omitzero"`
227 Interface any `json:",omitzero"`
228 }
229 structOmitZeroMethodAll struct {
230 ValueAlwaysZero valueAlwaysZero `json:",omitzero"`
231 ValueNeverZero valueNeverZero `json:",omitzero"`
232 PointerAlwaysZero pointerAlwaysZero `json:",omitzero"`
233 PointerNeverZero pointerNeverZero `json:",omitzero"`
234 PointerValueAlwaysZero *valueAlwaysZero `json:",omitzero"`
235 PointerValueNeverZero *valueNeverZero `json:",omitzero"`
236 PointerPointerAlwaysZero *pointerAlwaysZero `json:",omitzero"`
237 PointerPointerNeverZero *pointerNeverZero `json:",omitzero"`
238 PointerPointerValueAlwaysZero **valueAlwaysZero `json:",omitzero"`
239 PointerPointerValueNeverZero **valueNeverZero `json:",omitzero"`
240 PointerPointerPointerAlwaysZero **pointerAlwaysZero `json:",omitzero"`
241 PointerPointerPointerNeverZero **pointerNeverZero `json:",omitzero"`
242 }
243 structOmitZeroMethodInterfaceAll struct {
244 ValueAlwaysZero isZeroer `json:",omitzero"`
245 ValueNeverZero isZeroer `json:",omitzero"`
246 PointerValueAlwaysZero isZeroer `json:",omitzero"`
247 PointerValueNeverZero isZeroer `json:",omitzero"`
248 PointerPointerAlwaysZero isZeroer `json:",omitzero"`
249 PointerPointerNeverZero isZeroer `json:",omitzero"`
250 }
251 structOmitEmptyAll struct {
252 Bool bool `json:",omitempty"`
253 PointerBool *bool `json:",omitempty"`
254 String string `json:",omitempty"`
255 StringEmpty stringMarshalEmpty `json:",omitempty"`
256 StringNonEmpty stringMarshalNonEmpty `json:",omitempty"`
257 PointerString *string `json:",omitempty"`
258 PointerStringEmpty *stringMarshalEmpty `json:",omitempty"`
259 PointerStringNonEmpty *stringMarshalNonEmpty `json:",omitempty"`
260 Bytes []byte `json:",omitempty"`
261 BytesEmpty bytesMarshalEmpty `json:",omitempty"`
262 BytesNonEmpty bytesMarshalNonEmpty `json:",omitempty"`
263 PointerBytes *[]byte `json:",omitempty"`
264 PointerBytesEmpty *bytesMarshalEmpty `json:",omitempty"`
265 PointerBytesNonEmpty *bytesMarshalNonEmpty `json:",omitempty"`
266 Float float64 `json:",omitempty"`
267 PointerFloat *float64 `json:",omitempty"`
268 Map map[string]string `json:",omitempty"`
269 MapEmpty mapMarshalEmpty `json:",omitempty"`
270 MapNonEmpty mapMarshalNonEmpty `json:",omitempty"`
271 PointerMap *map[string]string `json:",omitempty"`
272 PointerMapEmpty *mapMarshalEmpty `json:",omitempty"`
273 PointerMapNonEmpty *mapMarshalNonEmpty `json:",omitempty"`
274 Slice []string `json:",omitempty"`
275 SliceEmpty sliceMarshalEmpty `json:",omitempty"`
276 SliceNonEmpty sliceMarshalNonEmpty `json:",omitempty"`
277 PointerSlice *[]string `json:",omitempty"`
278 PointerSliceEmpty *sliceMarshalEmpty `json:",omitempty"`
279 PointerSliceNonEmpty *sliceMarshalNonEmpty `json:",omitempty"`
280 Pointer *structOmitZeroEmptyAll `json:",omitempty"`
281 Interface any `json:",omitempty"`
282 }
283 structOmitZeroEmptyAll struct {
284 Bool bool `json:",omitzero,omitempty"`
285 String string `json:",omitzero,omitempty"`
286 Bytes []byte `json:",omitzero,omitempty"`
287 Int int64 `json:",omitzero,omitempty"`
288 Uint uint64 `json:",omitzero,omitempty"`
289 Float float64 `json:",omitzero,omitempty"`
290 Map map[string]string `json:",omitzero,omitempty"`
291 Slice []string `json:",omitzero,omitempty"`
292 Array [1]string `json:",omitzero,omitempty"`
293 Pointer *structOmitZeroEmptyAll `json:",omitzero,omitempty"`
294 Interface any `json:",omitzero,omitempty"`
295 }
296 structStringifiedLegacy struct {
297 Bool bool `json:",string"`
298 String string `json:",string"`
299 Int int64 `json:",string"`
300 Uint uint64 `json:",string"`
301 Float float64 `json:",string"`
302 PointerBool *bool `json:",string"`
303 PointerString *string `json:",string"`
304 PointerInt *int64 `json:",string"`
305 PointerUint *uint64 `json:",string"`
306 PointerFloat *float64 `json:",string"`
307 }
308 structStringified struct {
309 Int int64 `json:",string"`
310 Uint uint64 `json:",string"`
311 Float float64 `json:",string"`
312 PointerInt *int64 `json:",string"`
313 PointerUint *uint64 `json:",string"`
314 PointerFloat *float64 `json:",string"`
315 }
316 structStringifiedBool struct {
317 Bool bool `json:",string"`
318 }
319 structStringifiedString struct {
320 String string `json:",string"`
321 }
322 structStringifiedBytes struct {
323 Bytes []byte `json:",string"`
324 }
325 structStringifiedMap struct {
326 Map map[string]string `json:",string"`
327 }
328 structStringifiedSlice struct {
329 Slice []string `json:",string"`
330 }
331 structStringifiedArray struct {
332 Array [1]string `json:",string"`
333 }
334 structStringifiedStruct struct {
335 Struct structAll `json:",string"`
336 }
337 structStringifiedPointer struct {
338 Pointer *structAll `json:",string"`
339 }
340 structStringifiedPointerPointerInt struct {
341 Pointer **int `json:",string"`
342 }
343 structStringifiedInterface struct {
344 Interface any `json:",string"`
345 }
346 structFormatBytes struct {
347 Base16 []byte `json:",format:base16"`
348 Base32 []byte `json:",format:base32"`
349 Base32Hex []byte `json:",format:base32hex"`
350 Base64 []byte `json:",format:base64"`
351 Base64URL []byte `json:",format:base64url"`
352 Array []byte `json:",format:array"`
353 }
354 structFormatArrayBytes struct {
355 Base16 [4]byte `json:",format:base16"`
356 Base32 [4]byte `json:",format:base32"`
357 Base32Hex [4]byte `json:",format:base32hex"`
358 Base64 [4]byte `json:",format:base64"`
359 Base64URL [4]byte `json:",format:base64url"`
360 Array [4]byte `json:",format:array"`
361 Default [4]byte
362 }
363 structFormatFloats struct {
364 NonFinite float64 `json:",format:nonfinite"`
365 PointerNonFinite *float64 `json:",format:nonfinite"`
366 }
367 structFormatMaps struct {
368 EmitNull map[string]string `json:",format:emitnull"`
369 PointerEmitNull *map[string]string `json:",format:emitnull"`
370 EmitEmpty map[string]string `json:",format:emitempty"`
371 PointerEmitEmpty *map[string]string `json:",format:emitempty"`
372 EmitDefault map[string]string
373 PointerEmitDefault *map[string]string
374 }
375 structFormatSlices struct {
376 EmitNull []string `json:",format:emitnull"`
377 PointerEmitNull *[]string `json:",format:emitnull"`
378 EmitEmpty []string `json:",format:emitempty"`
379 PointerEmitEmpty *[]string `json:",format:emitempty"`
380 EmitDefault []string
381 PointerEmitDefault *[]string
382 }
383 structFormatInvalid struct {
384 Bool bool `json:",omitzero,format:invalid"`
385 String string `json:",omitzero,format:invalid"`
386 Bytes []byte `json:",omitzero,format:invalid"`
387 Int int64 `json:",omitzero,format:invalid"`
388 Uint uint64 `json:",omitzero,format:invalid"`
389 Float float64 `json:",omitzero,format:invalid"`
390 Map map[string]string `json:",omitzero,format:invalid"`
391 Struct structAll `json:",omitzero,format:invalid"`
392 Slice []string `json:",omitzero,format:invalid"`
393 Array [1]string `json:",omitzero,format:invalid"`
394 Interface any `json:",omitzero,format:invalid"`
395 }
396 structDurationFormat struct {
397 D1 time.Duration `json:",format:units"`
398 D2 time.Duration `json:",format:units"`
399 D3 time.Duration `json:",format:sec"`
400 D4 time.Duration `json:",string,format:sec"`
401 D5 time.Duration `json:",format:milli"`
402 D6 time.Duration `json:",string,format:milli"`
403 D7 time.Duration `json:",format:micro"`
404 D8 time.Duration `json:",string,format:micro"`
405 D9 time.Duration `json:",format:nano"`
406 D10 time.Duration `json:",string,format:nano"`
407 D11 time.Duration `json:",format:iso8601"`
408 }
409 structTimeFormat struct {
410 T1 time.Time
411 T2 time.Time `json:",format:ANSIC"`
412 T3 time.Time `json:",format:UnixDate"`
413 T4 time.Time `json:",format:RubyDate"`
414 T5 time.Time `json:",format:RFC822"`
415 T6 time.Time `json:",format:RFC822Z"`
416 T7 time.Time `json:",format:RFC850"`
417 T8 time.Time `json:",format:RFC1123"`
418 T9 time.Time `json:",format:RFC1123Z"`
419 T10 time.Time `json:",format:RFC3339"`
420 T11 time.Time `json:",format:RFC3339Nano"`
421 T12 time.Time `json:",format:Kitchen"`
422 T13 time.Time `json:",format:Stamp"`
423 T14 time.Time `json:",format:StampMilli"`
424 T15 time.Time `json:",format:StampMicro"`
425 T16 time.Time `json:",format:StampNano"`
426 T17 time.Time `json:",format:DateTime"`
427 T18 time.Time `json:",format:DateOnly"`
428 T19 time.Time `json:",format:TimeOnly"`
429 T20 time.Time `json:",format:'2006-01-02'"`
430 T21 time.Time `json:",format:'\"weird\"2006'"`
431 T22 time.Time `json:",format:unix"`
432 T23 time.Time `json:",string,format:unix"`
433 T24 time.Time `json:",format:unixmilli"`
434 T25 time.Time `json:",string,format:unixmilli"`
435 T26 time.Time `json:",format:unixmicro"`
436 T27 time.Time `json:",string,format:unixmicro"`
437 T28 time.Time `json:",format:unixnano"`
438 T29 time.Time `json:",string,format:unixnano"`
439 }
440 structTimeFormatStringInvalid struct {
441 T time.Time `json:",string,format:RFC3339"`
442 }
443 structEmbedded struct {
444 X structEmbeddedL1 `json:",embed"`
445 *StructEmbed2
446 }
447 structEmbeddedL1 struct {
448 X *structEmbeddedL2 `json:",embed"`
449 StructEmbed1 `json:",embed"`
450 }
451 structEmbeddedL2 struct{ A, B, C string }
452 StructEmbed1 struct{ C, D, E string }
453 StructEmbed2 struct{ E, F, G string }
454 structEmbedTextValue struct {
455 A int `json:",omitzero"`
456 X jsontext.Value `json:",embed"`
457 B int `json:",omitzero"`
458 }
459 structEmbedPointerTextValue struct {
460 A int `json:",omitzero"`
461 X *jsontext.Value `json:",embed"`
462 B int `json:",omitzero"`
463 }
464 structEmbedPointerEmbedTextValue struct {
465 X *struct {
466 A int
467 X jsontext.Value `json:",embed"`
468 } `json:",embed"`
469 }
470 structEmbedEmbedPointerTextValue struct {
471 X struct {
472 X *jsontext.Value `json:",embed"`
473 } `json:",embed"`
474 }
475 structEmbedMapStringAny struct {
476 A int `json:",omitzero"`
477 X jsonObject `json:",embed"`
478 B int `json:",omitzero"`
479 }
480 structEmbedPointerMapStringAny struct {
481 A int `json:",omitzero"`
482 X *jsonObject `json:",embed"`
483 B int `json:",omitzero"`
484 }
485 structEmbedPointerEmbedMapStringAny struct {
486 X *struct {
487 A int
488 X jsonObject `json:",embed"`
489 } `json:",embed"`
490 }
491 structEmbedEmbedPointerMapStringAny struct {
492 X struct {
493 X *jsonObject `json:",embed"`
494 } `json:",embed"`
495 }
496 structEmbedMapStringInt struct {
497 X map[string]int `json:",embed"`
498 }
499 structEmbedMapNamedStringInt struct {
500 X map[namedString]int `json:",embed"`
501 }
502 structEmbedMapNamedStringAny struct {
503 A int `json:",omitzero"`
504 X map[namedString]any `json:",embed"`
505 B int `json:",omitzero"`
506 }
507 structNoCaseEmbedTextValue struct {
508 AAA string `json:",omitempty,case:strict"`
509 AA_b string `json:",omitempty"`
510 AaA string `json:",omitempty,case:ignore"`
511 AAa string `json:",omitempty,case:ignore"`
512 Aaa string `json:",omitempty"`
513 X jsontext.Value `json:",embed"`
514 }
515 structNoCaseEmbedMapStringAny struct {
516 AAA string `json:",omitempty"`
517 AaA string `json:",omitempty,case:ignore"`
518 AAa string `json:",omitempty,case:ignore"`
519 Aaa string `json:",omitempty"`
520 X jsonObject `json:",embed"`
521 }
522
523 allMethods struct {
524 method string
525 value []byte
526 }
527 allMethodsExceptJSONv2 struct {
528 allMethods
529 MarshalJSONTo struct{}
530 UnmarshalJSONFrom struct{}
531 }
532 allMethodsExceptJSONv1 struct {
533 allMethods
534 MarshalJSON struct{}
535 UnmarshalJSON struct{}
536 }
537 allMethodsExceptText struct {
538 allMethods
539 MarshalText struct{}
540 UnmarshalText struct{}
541 }
542 onlyMethodJSONv2 struct {
543 allMethods
544 MarshalJSON struct{}
545 UnmarshalJSON struct{}
546 MarshalText struct{}
547 UnmarshalText struct{}
548 }
549 onlyMethodJSONv1 struct {
550 allMethods
551 MarshalJSONTo struct{}
552 UnmarshalJSONFrom struct{}
553 MarshalText struct{}
554 UnmarshalText struct{}
555 }
556 onlyMethodText struct {
557 allMethods
558 MarshalJSONTo struct{}
559 UnmarshalJSONFrom struct{}
560 MarshalJSON struct{}
561 UnmarshalJSON struct{}
562 }
563
564 unsupportedMethodJSONv2 map[string]int
565
566 structMethodJSONv2 struct{ value string }
567 structMethodJSONv1 struct{ value string }
568 structMethodText struct{ value string }
569
570 marshalJSONv2Func func(*jsontext.Encoder) error
571 marshalJSONv1Func func() ([]byte, error)
572 appendTextFunc func([]byte) ([]byte, error)
573 marshalTextFunc func() ([]byte, error)
574 unmarshalJSONv2Func func(*jsontext.Decoder) error
575 unmarshalJSONv1Func func([]byte) error
576 unmarshalTextFunc func([]byte) error
577
578 nocaseString string
579
580 stringMarshalEmpty string
581 stringMarshalNonEmpty string
582 bytesMarshalEmpty []byte
583 bytesMarshalNonEmpty []byte
584 mapMarshalEmpty map[string]string
585 mapMarshalNonEmpty map[string]string
586 sliceMarshalEmpty []string
587 sliceMarshalNonEmpty []string
588
589 valueAlwaysZero string
590 valueNeverZero string
591 pointerAlwaysZero string
592 pointerNeverZero string
593
594 valueStringer struct{}
595 pointerStringer struct{}
596
597 cyclicA struct {
598 B1 cyclicB `json:",embed"`
599 B2 cyclicB `json:",embed"`
600 }
601 cyclicB struct {
602 F int
603 A *cyclicA `json:",embed"`
604 }
605 )
606
607 func (structUnexportedEmbeddedMethodTag) MarshalText() {}
608 func (structUnexportedEmbeddedMethodTag) AppendText() {}
609
610 func (p *allMethods) MarshalJSONTo(enc *jsontext.Encoder) error {
611 if got, want := "MarshalJSONTo", p.method; got != want {
612 return fmt.Errorf("called wrong method: got %v, want %v", got, want)
613 }
614 return enc.WriteValue(p.value)
615 }
616 func (p *allMethods) MarshalJSON() ([]byte, error) {
617 if got, want := "MarshalJSON", p.method; got != want {
618 return nil, fmt.Errorf("called wrong method: got %v, want %v", got, want)
619 }
620 return p.value, nil
621 }
622 func (p *allMethods) MarshalText() ([]byte, error) {
623 if got, want := "MarshalText", p.method; got != want {
624 return nil, fmt.Errorf("called wrong method: got %v, want %v", got, want)
625 }
626 return p.value, nil
627 }
628
629 func (p *allMethods) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
630 p.method = "UnmarshalJSONFrom"
631 val, err := dec.ReadValue()
632 p.value = val
633 return err
634 }
635 func (p *allMethods) UnmarshalJSON(val []byte) error {
636 p.method = "UnmarshalJSON"
637 p.value = val
638 return nil
639 }
640 func (p *allMethods) UnmarshalText(val []byte) error {
641 p.method = "UnmarshalText"
642 p.value = val
643 return nil
644 }
645
646 func (s *unsupportedMethodJSONv2) MarshalJSONTo(enc *jsontext.Encoder) error {
647 (*s)["called"] += 1
648 return errors.ErrUnsupported
649 }
650 func (s *unsupportedMethodJSONv2) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
651 (*s)["called"] += 1
652 return errors.ErrUnsupported
653 }
654
655 func (s structMethodJSONv2) MarshalJSONTo(enc *jsontext.Encoder) error {
656 return enc.WriteToken(jsontext.String(s.value))
657 }
658 func (s *structMethodJSONv2) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
659 tok, err := dec.ReadToken()
660 if err != nil {
661 return err
662 }
663 if k := tok.Kind(); k != '"' {
664 return EU(nil).withType(k, T[structMethodJSONv2]())
665 }
666 s.value = tok.String()
667 return nil
668 }
669
670 func (s structMethodJSONv1) MarshalJSON() ([]byte, error) {
671 return jsontext.AppendQuote(nil, s.value)
672 }
673 func (s *structMethodJSONv1) UnmarshalJSON(b []byte) error {
674 if k := jsontext.Value(b).Kind(); k != '"' {
675 return EU(nil).withType(k, T[structMethodJSONv1]())
676 }
677 b, _ = jsontext.AppendUnquote(nil, b)
678 s.value = string(b)
679 return nil
680 }
681
682 func (s structMethodText) MarshalText() ([]byte, error) {
683 return []byte(s.value), nil
684 }
685 func (s *structMethodText) UnmarshalText(b []byte) error {
686 s.value = string(b)
687 return nil
688 }
689
690 func (f marshalJSONv2Func) MarshalJSONTo(enc *jsontext.Encoder) error {
691 return f(enc)
692 }
693 func (f marshalJSONv1Func) MarshalJSON() ([]byte, error) {
694 return f()
695 }
696 func (f appendTextFunc) AppendText(b []byte) ([]byte, error) {
697 return f(b)
698 }
699 func (f marshalTextFunc) MarshalText() ([]byte, error) {
700 return f()
701 }
702 func (f unmarshalJSONv2Func) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
703 return f(dec)
704 }
705 func (f unmarshalJSONv1Func) UnmarshalJSON(b []byte) error {
706 return f(b)
707 }
708 func (f unmarshalTextFunc) UnmarshalText(b []byte) error {
709 return f(b)
710 }
711
712 func (k nocaseString) MarshalText() ([]byte, error) {
713 return []byte(strings.ToLower(string(k))), nil
714 }
715 func (k *nocaseString) UnmarshalText(b []byte) error {
716 *k = nocaseString(strings.ToLower(string(b)))
717 return nil
718 }
719
720 func (stringMarshalEmpty) MarshalJSON() ([]byte, error) { return []byte(`""`), nil }
721 func (stringMarshalNonEmpty) MarshalJSON() ([]byte, error) { return []byte(`"value"`), nil }
722 func (bytesMarshalEmpty) MarshalJSON() ([]byte, error) { return []byte(`[]`), nil }
723 func (bytesMarshalNonEmpty) MarshalJSON() ([]byte, error) { return []byte(`["value"]`), nil }
724 func (mapMarshalEmpty) MarshalJSON() ([]byte, error) { return []byte(`{}`), nil }
725 func (mapMarshalNonEmpty) MarshalJSON() ([]byte, error) { return []byte(`{"key":"value"}`), nil }
726 func (sliceMarshalEmpty) MarshalJSON() ([]byte, error) { return []byte(`[]`), nil }
727 func (sliceMarshalNonEmpty) MarshalJSON() ([]byte, error) { return []byte(`["value"]`), nil }
728
729 func (valueAlwaysZero) IsZero() bool { return true }
730 func (valueNeverZero) IsZero() bool { return false }
731 func (*pointerAlwaysZero) IsZero() bool { return true }
732 func (*pointerNeverZero) IsZero() bool { return false }
733
734 func (valueStringer) String() string { return "" }
735 func (*pointerStringer) String() string { return "" }
736
737 func addr[T any](v T) *T {
738 return &v
739 }
740
741 func mustParseTime(layout, value string) time.Time {
742 t, err := time.Parse(layout, value)
743 if err != nil {
744 panic(err)
745 }
746 return t
747 }
748
749
750
751
752 var invalidFormatOption = &jsonopts.Struct{
753 ArshalValues: jsonopts.ArshalValues{Format: "invalid"},
754 }
755
756 func TestMarshal(t *testing.T) {
757 tests := []struct {
758 name jsontest.CaseName
759 opts []Options
760 in any
761 want string
762 wantErr error
763
764 canonicalize bool
765 useWriter bool
766 }{{
767 name: jsontest.Name("Nil"),
768 in: nil,
769 want: `null`,
770 }, {
771 name: jsontest.Name("Bools"),
772 in: []bool{false, true},
773 want: `[false,true]`,
774 }, {
775 name: jsontest.Name("Bools/Named"),
776 in: []namedBool{false, true},
777 want: `[false,true]`,
778 }, {
779 name: jsontest.Name("Bools/NotStringified"),
780 opts: []Options{StringifyNumbers(true)},
781 in: []bool{false, true},
782 want: `[false,true]`,
783 }, {
784 name: jsontest.Name("Bools/StringifiedBool/False"),
785 opts: []Options{jsonflags.StringTag | jsonflags.StringifyWithLegacySemantics | 1},
786 in: false,
787 want: `"false"`,
788 }, {
789 name: jsontest.Name("Bools/StringifiedBool/True"),
790 opts: []Options{jsonflags.StringTag | jsonflags.StringifyWithLegacySemantics | 1},
791 in: true,
792 want: `"true"`,
793 }, {
794 name: jsontest.Name("Bools/IgnoreInvalidFormat"),
795 opts: []Options{invalidFormatOption},
796 in: true,
797 want: `true`,
798 }, {
799 name: jsontest.Name("Strings"),
800 in: []string{"", "hello", "世界"},
801 want: `["","hello","世界"]`,
802 }, {
803 name: jsontest.Name("Strings/Named"),
804 in: []namedString{"", "hello", "世界"},
805 want: `["","hello","世界"]`,
806 }, {
807 name: jsontest.Name("Strings/StringifiedString"),
808 opts: []Options{jsonflags.StringTag | jsonflags.StringifyWithLegacySemantics | 1},
809 in: "hello",
810 want: `"\"hello\""`,
811 }, {
812 name: jsontest.Name("Strings/IgnoreInvalidFormat"),
813 opts: []Options{invalidFormatOption},
814 in: "string",
815 want: `"string"`,
816 }, {
817 name: jsontest.Name("Bytes"),
818 in: [][]byte{nil, {}, {1}, {1, 2}, {1, 2, 3}},
819 want: `["","","AQ==","AQI=","AQID"]`,
820 }, {
821 name: jsontest.Name("Bytes/FormatNilSliceAsNull"),
822 opts: []Options{FormatNilSliceAsNull(true)},
823 in: [][]byte{nil, {}},
824 want: `[null,""]`,
825 }, {
826 name: jsontest.Name("Bytes/Large"),
827 in: []byte("the quick brown fox jumped over the lazy dog and ate the homework that I spent so much time on."),
828 want: `"dGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2cgYW5kIGF0ZSB0aGUgaG9tZXdvcmsgdGhhdCBJIHNwZW50IHNvIG11Y2ggdGltZSBvbi4="`,
829 }, {
830 name: jsontest.Name("Bytes/Named"),
831 in: []namedBytes{nil, {}, {1}, {1, 2}, {1, 2, 3}},
832 want: `["","","AQ==","AQI=","AQID"]`,
833 }, {
834 name: jsontest.Name("Bytes/NotStringified"),
835 opts: []Options{StringifyNumbers(true)},
836 in: [][]byte{nil, {}, {1}, {1, 2}, {1, 2, 3}},
837 want: `["","","AQ==","AQI=","AQID"]`,
838 }, {
839
840
841 name: jsontest.Name("Bytes/Invariant"),
842 in: [][]namedByte{nil, {}, {1}, {1, 2}, {1, 2, 3}},
843 want: `[[],[],[1],[1,2],[1,2,3]]`,
844 }, {
845
846
847 name: jsontest.Name("Bytes/ByteArray"),
848 in: [5]byte{'h', 'e', 'l', 'l', 'o'},
849 want: `"aGVsbG8="`,
850 }, {
851
852
853 name: jsontest.Name("Bytes/NamedByteArray"),
854 in: [5]namedByte{'h', 'e', 'l', 'l', 'o'},
855 want: `[104,101,108,108,111]`,
856 }, {
857 name: jsontest.Name("Bytes/IgnoreInvalidFormat"),
858 opts: []Options{invalidFormatOption},
859 in: []byte("hello"),
860 want: `"aGVsbG8="`,
861 }, {
862 name: jsontest.Name("Ints"),
863 in: []any{
864 int(0), int8(math.MinInt8), int16(math.MinInt16), int32(math.MinInt32), int64(math.MinInt64), namedInt64(-6464),
865 },
866 want: `[0,-128,-32768,-2147483648,-9223372036854775808,-6464]`,
867 }, {
868 name: jsontest.Name("Ints/Stringified"),
869 opts: []Options{StringifyNumbers(true)},
870 in: []any{
871 int(0), int8(math.MinInt8), int16(math.MinInt16), int32(math.MinInt32), int64(math.MinInt64), namedInt64(-6464),
872 },
873 want: `["0","-128","-32768","-2147483648","-9223372036854775808","-6464"]`,
874 }, {
875 name: jsontest.Name("Ints/IgnoreInvalidFormat"),
876 opts: []Options{invalidFormatOption},
877 in: int(0),
878 want: `0`,
879 }, {
880 name: jsontest.Name("Uints"),
881 in: []any{
882 uint(0), uint8(math.MaxUint8), uint16(math.MaxUint16), uint32(math.MaxUint32), uint64(math.MaxUint64), namedUint64(6464), uintptr(1234),
883 },
884 want: `[0,255,65535,4294967295,18446744073709551615,6464,1234]`,
885 }, {
886 name: jsontest.Name("Uints/Stringified"),
887 opts: []Options{StringifyNumbers(true)},
888 in: []any{
889 uint(0), uint8(math.MaxUint8), uint16(math.MaxUint16), uint32(math.MaxUint32), uint64(math.MaxUint64), namedUint64(6464),
890 },
891 want: `["0","255","65535","4294967295","18446744073709551615","6464"]`,
892 }, {
893 name: jsontest.Name("Uints/IgnoreInvalidFormat"),
894 opts: []Options{invalidFormatOption},
895 in: uint(0),
896 want: `0`,
897 }, {
898 name: jsontest.Name("Floats"),
899 in: []any{
900 float32(math.MaxFloat32), float64(math.MaxFloat64), namedFloat64(64.64),
901 },
902 want: `[3.4028235e+38,1.7976931348623157e+308,64.64]`,
903 }, {
904 name: jsontest.Name("Floats/Stringified"),
905 opts: []Options{StringifyNumbers(true)},
906 in: []any{
907 float32(math.MaxFloat32), float64(math.MaxFloat64), namedFloat64(64.64),
908 },
909 want: `["3.4028235e+38","1.7976931348623157e+308","64.64"]`,
910 }, {
911 name: jsontest.Name("Floats/Invalid/NaN"),
912 opts: []Options{StringifyNumbers(true)},
913 in: math.NaN(),
914 wantErr: EM(fmt.Errorf("unsupported value: %v", math.NaN())).withType(0, float64Type),
915 }, {
916 name: jsontest.Name("Floats/Invalid/PositiveInfinity"),
917 in: math.Inf(+1),
918 wantErr: EM(fmt.Errorf("unsupported value: %v", math.Inf(+1))).withType(0, float64Type),
919 }, {
920 name: jsontest.Name("Floats/Invalid/NegativeInfinity"),
921 in: math.Inf(-1),
922 wantErr: EM(fmt.Errorf("unsupported value: %v", math.Inf(-1))).withType(0, float64Type),
923 }, {
924 name: jsontest.Name("Floats/IgnoreInvalidFormat"),
925 opts: []Options{invalidFormatOption},
926 in: float64(0),
927 want: `0`,
928 }, {
929 name: jsontest.Name("Maps/InvalidKey/Bool"),
930 in: map[bool]string{false: "value"},
931 want: `{`,
932 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, boolType),
933 }, {
934 name: jsontest.Name("Maps/InvalidKey/NamedBool"),
935 in: map[namedBool]string{false: "value"},
936 want: `{`,
937 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[namedBool]()),
938 }, {
939 name: jsontest.Name("Maps/InvalidKey/Array"),
940 in: map[[1]string]string{{"key"}: "value"},
941 want: `{`,
942 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[[1]string]()),
943 }, {
944 name: jsontest.Name("Maps/InvalidKey/Channel"),
945 in: map[chan string]string{make(chan string): "value"},
946 want: `{`,
947 wantErr: EM(nil).withPos(`{`, "").withType(0, T[chan string]()),
948 }, {
949 name: jsontest.Name("Maps/ValidKey/Int"),
950 in: map[int64]string{math.MinInt64: "MinInt64", 0: "Zero", math.MaxInt64: "MaxInt64"},
951 canonicalize: true,
952 want: `{"-9223372036854775808":"MinInt64","0":"Zero","9223372036854775807":"MaxInt64"}`,
953 }, {
954 name: jsontest.Name("Maps/ValidKey/PointerInt"),
955 in: map[*int64]string{addr(int64(math.MinInt64)): "MinInt64", addr(int64(0)): "Zero", addr(int64(math.MaxInt64)): "MaxInt64"},
956 canonicalize: true,
957 want: `{"-9223372036854775808":"MinInt64","0":"Zero","9223372036854775807":"MaxInt64"}`,
958 }, {
959 name: jsontest.Name("Maps/DuplicateName/PointerInt"),
960 in: map[*int64]string{addr(int64(0)): "0", addr(int64(0)): "0"},
961 canonicalize: true,
962 want: `{"0":"0"`,
963 wantErr: newDuplicateNameError("", []byte(`"0"`), len64(`{"0":"0",`)),
964 }, {
965 name: jsontest.Name("Maps/ValidKey/NamedInt"),
966 in: map[namedInt64]string{math.MinInt64: "MinInt64", 0: "Zero", math.MaxInt64: "MaxInt64"},
967 canonicalize: true,
968 want: `{"-9223372036854775808":"MinInt64","0":"Zero","9223372036854775807":"MaxInt64"}`,
969 }, {
970 name: jsontest.Name("Maps/ValidKey/Uint"),
971 in: map[uint64]string{0: "Zero", math.MaxUint64: "MaxUint64"},
972 canonicalize: true,
973 want: `{"0":"Zero","18446744073709551615":"MaxUint64"}`,
974 }, {
975 name: jsontest.Name("Maps/ValidKey/NamedUint"),
976 in: map[namedUint64]string{0: "Zero", math.MaxUint64: "MaxUint64"},
977 canonicalize: true,
978 want: `{"0":"Zero","18446744073709551615":"MaxUint64"}`,
979 }, {
980 name: jsontest.Name("Maps/ValidKey/Float"),
981 in: map[float64]string{3.14159: "value"},
982 want: `{"3.14159":"value"}`,
983 }, {
984 name: jsontest.Name("Maps/InvalidKey/Float/NaN"),
985 in: map[float64]string{math.NaN(): "NaN", math.NaN(): "NaN"},
986 want: `{`,
987 wantErr: EM(errors.New("unsupported value: NaN")).withPos(`{`, "").withType(0, float64Type),
988 }, {
989 name: jsontest.Name("Maps/ValidKey/Interface"),
990 in: map[any]any{
991 "key": "key",
992 namedInt64(-64): int32(-32),
993 namedUint64(+64): uint32(+32),
994 namedFloat64(64.64): float32(32.32),
995 },
996 canonicalize: true,
997 want: `{"-64":-32,"64":32,"64.64":32.32,"key":"key"}`,
998 }, {
999 name: jsontest.Name("Maps/DuplicateName/String/AllowInvalidUTF8+AllowDuplicateNames"),
1000 opts: []Options{jsontext.AllowInvalidUTF8(true), jsontext.AllowDuplicateNames(true)},
1001 in: map[string]string{"\x80": "", "\x81": ""},
1002 want: `{"�":"","�":""}`,
1003 }, {
1004 name: jsontest.Name("Maps/DuplicateName/String/AllowInvalidUTF8"),
1005 opts: []Options{jsontext.AllowInvalidUTF8(true)},
1006 in: map[string]string{"\x80": "", "\x81": ""},
1007 want: `{"�":""`,
1008 wantErr: newDuplicateNameError("", []byte(`"�"`), len64(`{"�":"",`)),
1009 }, {
1010 name: jsontest.Name("Maps/DuplicateName/NoCaseString/AllowDuplicateNames"),
1011 opts: []Options{jsontext.AllowDuplicateNames(true)},
1012 in: map[nocaseString]string{"hello": "", "HELLO": ""},
1013 want: `{"hello":"","hello":""}`,
1014 }, {
1015 name: jsontest.Name("Maps/DuplicateName/NoCaseString"),
1016 in: map[nocaseString]string{"hello": "", "HELLO": ""},
1017 want: `{"hello":""`,
1018 wantErr: EM(newDuplicateNameError("", []byte(`"hello"`), len64(`{"hello":"",`))).withPos(`{"hello":"",`, "").withType(0, T[nocaseString]()),
1019 }, {
1020 name: jsontest.Name("Maps/DuplicateName/NaNs/Deterministic+AllowDuplicateNames"),
1021 opts: []Options{
1022 WithMarshalers(
1023 MarshalFunc(func(v float64) ([]byte, error) { return []byte(`"NaN"`), nil }),
1024 ),
1025 Deterministic(true),
1026 jsontext.AllowDuplicateNames(true),
1027 },
1028 in: map[float64]string{math.NaN(): "NaN", math.NaN(): "NaN"},
1029 want: `{"NaN":"NaN","NaN":"NaN"}`,
1030 }, {
1031 name: jsontest.Name("Maps/InvalidValue/Channel"),
1032 in: map[string]chan string{
1033 "key": nil,
1034 },
1035 want: `{"key"`,
1036 wantErr: EM(nil).withPos(`{"key":`, "/key").withType(0, T[chan string]()),
1037 }, {
1038 name: jsontest.Name("Maps/String/Deterministic"),
1039 opts: []Options{Deterministic(true)},
1040 in: map[string]int{"a": 0, "b": 1, "c": 2},
1041 want: `{"a":0,"b":1,"c":2}`,
1042 }, {
1043 name: jsontest.Name("Maps/String/Deterministic+AllowInvalidUTF8+RejectDuplicateNames"),
1044 opts: []Options{
1045 Deterministic(true),
1046 jsontext.AllowInvalidUTF8(true),
1047 jsontext.AllowDuplicateNames(false),
1048 },
1049 in: map[string]int{"\xff": 0, "\xfe": 1},
1050 want: `{"�":1`,
1051 wantErr: newDuplicateNameError("", []byte(`"�"`), len64(`{"�":1,`)),
1052 }, {
1053 name: jsontest.Name("Maps/String/Deterministic+AllowInvalidUTF8+AllowDuplicateNames"),
1054 opts: []Options{
1055 Deterministic(true),
1056 jsontext.AllowInvalidUTF8(true),
1057 jsontext.AllowDuplicateNames(true),
1058 },
1059 in: map[string]int{"\xff": 0, "\xfe": 1},
1060 want: `{"�":1,"�":0}`,
1061 }, {
1062 name: jsontest.Name("Maps/String/Deterministic+MarshalFuncs"),
1063 opts: []Options{
1064 Deterministic(true),
1065 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v string) error {
1066 if p := enc.StackPointer(); p != "/X" {
1067 return fmt.Errorf("invalid stack pointer: got %s, want /X", p)
1068 }
1069 switch v {
1070 case "a":
1071 return enc.WriteToken(jsontext.String("b"))
1072 case "b":
1073 return enc.WriteToken(jsontext.String("a"))
1074 default:
1075 return fmt.Errorf("invalid value: %q", v)
1076 }
1077 })),
1078 },
1079 in: map[namedString]map[string]int{"X": {"a": -1, "b": 1}},
1080 want: `{"X":{"a":1,"b":-1}}`,
1081 }, {
1082 name: jsontest.Name("Maps/String/Deterministic+MarshalFuncs+RejectDuplicateNames"),
1083 opts: []Options{
1084 Deterministic(true),
1085 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v string) error {
1086 if p := enc.StackPointer(); p != "/X" {
1087 return fmt.Errorf("invalid stack pointer: got %s, want /X", p)
1088 }
1089 switch v {
1090 case "a", "b":
1091 return enc.WriteToken(jsontext.String("x"))
1092 default:
1093 return fmt.Errorf("invalid value: %q", v)
1094 }
1095 })),
1096 jsontext.AllowDuplicateNames(false),
1097 },
1098 in: map[namedString]map[string]int{"X": {"a": 1, "b": 1}},
1099 want: `{"X":{"x":1`,
1100 wantErr: newDuplicateNameError("/X/x", nil, len64(`{"X":{"x":1,`)),
1101 }, {
1102 name: jsontest.Name("Maps/String/Deterministic+MarshalFuncs+AllowDuplicateNames"),
1103 opts: []Options{
1104 Deterministic(true),
1105 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v string) error {
1106 if p := enc.StackPointer(); p != "/X" {
1107 return fmt.Errorf("invalid stack pointer: got %s, want /0", p)
1108 }
1109 switch v {
1110 case "a", "b":
1111 return enc.WriteToken(jsontext.String("x"))
1112 default:
1113 return fmt.Errorf("invalid value: %q", v)
1114 }
1115 })),
1116 jsontext.AllowDuplicateNames(true),
1117 },
1118 in: map[namedString]map[string]int{"X": {"a": 1, "b": 1}},
1119
1120
1121 want: `{"X":{"x":1,"x":1}}`,
1122 }, {
1123 name: jsontest.Name("Maps/RecursiveMap"),
1124 in: recursiveMap{
1125 "fizz": {
1126 "foo": {},
1127 "bar": nil,
1128 },
1129 "buzz": nil,
1130 },
1131 canonicalize: true,
1132 want: `{"buzz":{},"fizz":{"bar":{},"foo":{}}}`,
1133 }, {
1134 name: jsontest.Name("Maps/CyclicMap"),
1135 in: func() recursiveMap {
1136 m := recursiveMap{"k": nil}
1137 m["k"] = m
1138 return m
1139 }(),
1140 want: strings.Repeat(`{"k":`, startDetectingCyclesAfter) + `{"k"`,
1141 wantErr: EM(internal.ErrCycle).withPos(strings.Repeat(`{"k":`, startDetectingCyclesAfter+1), jsontext.Pointer(strings.Repeat("/k", startDetectingCyclesAfter+1))).withType(0, T[recursiveMap]()),
1142 }, {
1143 name: jsontest.Name("Maps/IgnoreInvalidFormat"),
1144 opts: []Options{invalidFormatOption},
1145 in: map[string]string{},
1146 want: `{}`,
1147 }, {
1148 name: jsontest.Name("Structs/Empty"),
1149 in: structEmpty{},
1150 want: `{}`,
1151 }, {
1152 name: jsontest.Name("Structs/UnexportedIgnored"),
1153 in: structUnexportedIgnored{ignored: "ignored"},
1154 want: `{}`,
1155 }, {
1156 name: jsontest.Name("Structs/IgnoredUnexportedEmbedded"),
1157 in: structIgnoredUnexportedEmbedded{namedString: "ignored"},
1158 want: `{}`,
1159 }, {
1160 name: jsontest.Name("Structs/NoCase"),
1161 in: structNoCase{AaA: "AaA", AAa: "AAa", Aaa: "Aaa", AAA: "AAA", AA_A: "AA_A"},
1162 want: `{"Aaa":"Aaa","AA_A":"AA_A","AaA":"AaA","AAa":"AAa","AAA":"AAA"}`,
1163 }, {
1164 name: jsontest.Name("Structs/NoCase/MatchCaseInsensitiveNames"),
1165 opts: []Options{MatchCaseInsensitiveNames(true)},
1166 in: structNoCase{AaA: "AaA", AAa: "AAa", Aaa: "Aaa", AAA: "AAA", AA_A: "AA_A"},
1167 want: `{"Aaa":"Aaa","AA_A":"AA_A","AaA":"AaA","AAa":"AAa","AAA":"AAA"}`,
1168 }, {
1169 name: jsontest.Name("Structs/NoCase/MatchCaseInsensitiveNames+MatchCaseSensitiveDelimiter"),
1170 opts: []Options{MatchCaseInsensitiveNames(true), jsonflags.MatchCaseSensitiveDelimiter | 1},
1171 in: structNoCase{AaA: "AaA", AAa: "AAa", Aaa: "Aaa", AAA: "AAA", AA_A: "AA_A"},
1172 want: `{"Aaa":"Aaa","AA_A":"AA_A","AaA":"AaA","AAa":"AAa","AAA":"AAA"}`,
1173 }, {
1174 name: jsontest.Name("Structs/Normal"),
1175 opts: []Options{jsontext.Multiline(true)},
1176 in: structAll{
1177 Bool: true,
1178 String: "hello",
1179 Bytes: []byte{1, 2, 3},
1180 Int: -64,
1181 Uint: +64,
1182 Float: 3.14159,
1183 Map: map[string]string{"key": "value"},
1184 StructScalars: structScalars{
1185 Bool: true,
1186 String: "hello",
1187 Bytes: []byte{1, 2, 3},
1188 Int: -64,
1189 Uint: +64,
1190 Float: 3.14159,
1191 },
1192 StructMaps: structMaps{
1193 MapBool: map[string]bool{"": true},
1194 MapString: map[string]string{"": "hello"},
1195 MapBytes: map[string][]byte{"": {1, 2, 3}},
1196 MapInt: map[string]int64{"": -64},
1197 MapUint: map[string]uint64{"": +64},
1198 MapFloat: map[string]float64{"": 3.14159},
1199 },
1200 StructSlices: structSlices{
1201 SliceBool: []bool{true},
1202 SliceString: []string{"hello"},
1203 SliceBytes: [][]byte{{1, 2, 3}},
1204 SliceInt: []int64{-64},
1205 SliceUint: []uint64{+64},
1206 SliceFloat: []float64{3.14159},
1207 },
1208 Slice: []string{"fizz", "buzz"},
1209 Array: [1]string{"goodbye"},
1210 Pointer: new(structAll),
1211 Interface: (*structAll)(nil),
1212 },
1213 want: `{
1214 "Bool": true,
1215 "String": "hello",
1216 "Bytes": "AQID",
1217 "Int": -64,
1218 "Uint": 64,
1219 "Float": 3.14159,
1220 "Map": {
1221 "key": "value"
1222 },
1223 "StructScalars": {
1224 "Bool": true,
1225 "String": "hello",
1226 "Bytes": "AQID",
1227 "Int": -64,
1228 "Uint": 64,
1229 "Float": 3.14159
1230 },
1231 "StructMaps": {
1232 "MapBool": {
1233 "": true
1234 },
1235 "MapString": {
1236 "": "hello"
1237 },
1238 "MapBytes": {
1239 "": "AQID"
1240 },
1241 "MapInt": {
1242 "": -64
1243 },
1244 "MapUint": {
1245 "": 64
1246 },
1247 "MapFloat": {
1248 "": 3.14159
1249 }
1250 },
1251 "StructSlices": {
1252 "SliceBool": [
1253 true
1254 ],
1255 "SliceString": [
1256 "hello"
1257 ],
1258 "SliceBytes": [
1259 "AQID"
1260 ],
1261 "SliceInt": [
1262 -64
1263 ],
1264 "SliceUint": [
1265 64
1266 ],
1267 "SliceFloat": [
1268 3.14159
1269 ]
1270 },
1271 "Slice": [
1272 "fizz",
1273 "buzz"
1274 ],
1275 "Array": [
1276 "goodbye"
1277 ],
1278 "Pointer": {
1279 "Bool": false,
1280 "String": "",
1281 "Bytes": "",
1282 "Int": 0,
1283 "Uint": 0,
1284 "Float": 0,
1285 "Map": {},
1286 "StructScalars": {
1287 "Bool": false,
1288 "String": "",
1289 "Bytes": "",
1290 "Int": 0,
1291 "Uint": 0,
1292 "Float": 0
1293 },
1294 "StructMaps": {
1295 "MapBool": {},
1296 "MapString": {},
1297 "MapBytes": {},
1298 "MapInt": {},
1299 "MapUint": {},
1300 "MapFloat": {}
1301 },
1302 "StructSlices": {
1303 "SliceBool": [],
1304 "SliceString": [],
1305 "SliceBytes": [],
1306 "SliceInt": [],
1307 "SliceUint": [],
1308 "SliceFloat": []
1309 },
1310 "Slice": [],
1311 "Array": [
1312 ""
1313 ],
1314 "Pointer": null,
1315 "Interface": null
1316 },
1317 "Interface": null
1318 }`,
1319 }, {
1320 name: jsontest.Name("Structs/SpaceAfterColonAndComma"),
1321 opts: []Options{jsontext.SpaceAfterColon(true), jsontext.SpaceAfterComma(true)},
1322 in: structOmitZeroAll{Int: 1, Uint: 1},
1323 want: `{"Int": 1, "Uint": 1}`,
1324 }, {
1325 name: jsontest.Name("Structs/SpaceAfterColon"),
1326 opts: []Options{jsontext.SpaceAfterColon(true)},
1327 in: structOmitZeroAll{Int: 1, Uint: 1},
1328 want: `{"Int": 1,"Uint": 1}`,
1329 }, {
1330 name: jsontest.Name("Structs/SpaceAfterComma"),
1331 opts: []Options{jsontext.SpaceAfterComma(true)},
1332 in: structOmitZeroAll{Int: 1, Uint: 1, Slice: []string{"a", "b"}},
1333 want: `{"Int":1, "Uint":1, "Slice":["a", "b"]}`,
1334 }, {
1335 name: jsontest.Name("Structs/Stringified"),
1336 opts: []Options{jsontext.Multiline(true)},
1337 in: structStringified{
1338 Int: -64,
1339 Uint: +64,
1340 Float: 3.14159,
1341 PointerInt: new(int64(-64)),
1342 PointerUint: new(uint64(+64)),
1343 PointerFloat: new(float64(3.14159)),
1344 },
1345 want: `{
1346 "Int": "-64",
1347 "Uint": "64",
1348 "Float": "3.14159",
1349 "PointerInt": "-64",
1350 "PointerUint": "64",
1351 "PointerFloat": "3.14159"
1352 }`,
1353 }, {
1354 name: jsontest.Name("Structs/LegacyStringified"),
1355 opts: []Options{jsontext.Multiline(true), jsonflags.StringifyWithLegacySemantics | 1},
1356 in: structStringifiedLegacy{
1357 Bool: true,
1358 String: "hello",
1359 Int: -64,
1360 Uint: +64,
1361 Float: 3.14159,
1362 PointerBool: new(true),
1363 PointerString: new("hello"),
1364 PointerInt: new(int64(-64)),
1365 PointerUint: new(uint64(+64)),
1366 PointerFloat: new(float64(3.14159)),
1367 },
1368 want: `{
1369 "Bool": "true",
1370 "String": "\"hello\"",
1371 "Int": "-64",
1372 "Uint": "64",
1373 "Float": "3.14159",
1374 "PointerBool": "true",
1375 "PointerString": "\"hello\"",
1376 "PointerInt": "-64",
1377 "PointerUint": "64",
1378 "PointerFloat": "3.14159"
1379 }`,
1380 }, {
1381 name: jsontest.Name("Structs/Stringified/Invalid/Bool"),
1382 in: structStringifiedBool{},
1383 want: `{"Bool"`,
1384 wantErr: EM(errInvalidStringTag).withPos(`{"Bool":`, "/Bool").withType(0, boolType),
1385 }, {
1386 name: jsontest.Name("Structs/Stringified/Ignored/Bool"),
1387 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
1388 in: structStringifiedBool{},
1389 want: `{"Bool":false}`,
1390 }, {
1391 name: jsontest.Name("Structs/Stringified/Invalid/String"),
1392 in: structStringifiedString{},
1393 want: `{"String"`,
1394 wantErr: EM(errInvalidStringTag).withPos(`{"String":`, "/String").withType(0, stringType),
1395 }, {
1396 name: jsontest.Name("Structs/Stringified/Ignored/String"),
1397 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
1398 in: structStringifiedString{},
1399 want: `{"String":""}`,
1400 }, {
1401 name: jsontest.Name("Structs/Stringified/Invalid/Bytes"),
1402 in: structStringifiedBytes{},
1403 want: `{"Bytes"`,
1404 wantErr: EM(errInvalidStringTag).withPos(`{"Bytes":`, "/Bytes").withType(0, bytesType),
1405 }, {
1406 name: jsontest.Name("Structs/Stringified/Ignored/Bytes"),
1407 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
1408 in: structStringifiedBytes{},
1409 want: `{"Bytes":""}`,
1410 }, {
1411 name: jsontest.Name("Structs/Stringified/Invalid/Map"),
1412 in: structStringifiedMap{},
1413 want: `{"Map"`,
1414 wantErr: EM(errInvalidStringTag).withPos(`{"Map":`, "/Map").withType(0, reflect.TypeFor[map[string]string]()),
1415 }, {
1416 name: jsontest.Name("Structs/Stringified/Ignored/Map"),
1417 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
1418 in: structStringifiedMap{},
1419 want: `{"Map":{}}`,
1420 }, {
1421 name: jsontest.Name("Structs/Stringified/Invalid/Slice"),
1422 in: structStringifiedSlice{},
1423 want: `{"Slice"`,
1424 wantErr: EM(errInvalidStringTag).withPos(`{"Slice":`, "/Slice").withType(0, reflect.TypeFor[[]string]()),
1425 }, {
1426 name: jsontest.Name("Structs/Stringified/Ignored/Slice"),
1427 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
1428 in: structStringifiedSlice{},
1429 want: `{"Slice":[]}`,
1430 }, {
1431 name: jsontest.Name("Structs/Stringified/Invalid/Array"),
1432 in: structStringifiedArray{},
1433 want: `{"Array"`,
1434 wantErr: EM(errInvalidStringTag).withPos(`{"Array":`, "/Array").withType(0, reflect.TypeFor[[1]string]()),
1435 }, {
1436 name: jsontest.Name("Structs/Stringified/Ignored/Array"),
1437 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
1438 in: structStringifiedArray{},
1439 want: `{"Array":[""]}`,
1440 }, {
1441 name: jsontest.Name("Structs/Stringified/Invalid/Struct"),
1442 in: structStringifiedStruct{},
1443 want: `{"Struct"`,
1444 wantErr: EM(errInvalidStringTag).withPos(`{"Struct":`, "/Struct").withType(0, reflect.TypeFor[structAll]()),
1445 }, {
1446 name: jsontest.Name("Structs/Stringified/Ignored/Struct"),
1447 opts: []Options{jsontext.Multiline(true), jsonflags.ReportErrorsWithLegacySemantics | 1},
1448 in: structStringifiedStruct{},
1449 want: `{
1450 "Struct": {
1451 "Bool": false,
1452 "String": "",
1453 "Bytes": "",
1454 "Int": 0,
1455 "Uint": 0,
1456 "Float": 0,
1457 "Map": {},
1458 "StructScalars": {
1459 "Bool": false,
1460 "String": "",
1461 "Bytes": "",
1462 "Int": 0,
1463 "Uint": 0,
1464 "Float": 0
1465 },
1466 "StructMaps": {
1467 "MapBool": {},
1468 "MapString": {},
1469 "MapBytes": {},
1470 "MapInt": {},
1471 "MapUint": {},
1472 "MapFloat": {}
1473 },
1474 "StructSlices": {
1475 "SliceBool": [],
1476 "SliceString": [],
1477 "SliceBytes": [],
1478 "SliceInt": [],
1479 "SliceUint": [],
1480 "SliceFloat": []
1481 },
1482 "Slice": [],
1483 "Array": [
1484 ""
1485 ],
1486 "Pointer": null,
1487 "Interface": null
1488 }
1489 }`,
1490 }, {
1491 name: jsontest.Name("Structs/Stringified/Invalid/Pointer"),
1492 in: structStringifiedPointer{},
1493 want: `{"Pointer":null}`,
1494 }, {
1495 name: jsontest.Name("Structs/Stringified/Ignored/Pointer"),
1496 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
1497 in: structStringifiedPointer{},
1498 want: `{"Pointer":null}`,
1499 }, {
1500 name: jsontest.Name("Structs/Stringified/PointerPointerInt"),
1501 in: structStringifiedPointerPointerInt{Pointer: new(new(5))},
1502 want: `{"Pointer":"5"}`,
1503 }, {
1504 name: jsontest.Name("Structs/Stringified/Invalid/Interface"),
1505 in: structStringifiedInterface{Interface: 1000},
1506 want: `{"Interface"`,
1507 wantErr: EM(errInvalidStringTag).withPos(`{"Interface":`, "/Interface").withType(0, anyType),
1508 }, {
1509 name: jsontest.Name("Structs/Stringified/Ignored/Interface"),
1510 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
1511 in: structStringifiedInterface{Interface: 1000},
1512 want: `{"Interface":"1000"}`,
1513 }, {
1514 name: jsontest.Name("Structs/LegacyStringified/Invalid/Bytes"),
1515 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
1516 want: `{"Bytes"`,
1517 wantErr: EM(errInvalidStringTag).withPos(`{"Bytes":`, "/Bytes").withType(0, bytesType),
1518 in: structStringifiedBytes{},
1519 }, {
1520 name: jsontest.Name("Structs/LegacyStringified/Ignored/Bytes"),
1521 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1, jsonflags.ReportErrorsWithLegacySemantics | 1},
1522 in: structStringifiedBytes{},
1523 want: `{"Bytes":""}`,
1524 }, {
1525 name: jsontest.Name("Structs/LegacyStringified/Invalid/Map"),
1526 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
1527 in: structStringifiedMap{},
1528 want: `{"Map"`,
1529 wantErr: EM(errInvalidStringTag).withPos(`{"Map":`, "/Map").withType(0, reflect.TypeFor[map[string]string]()),
1530 }, {
1531 name: jsontest.Name("Structs/LegacyStringified/Ignored/Map"),
1532 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1, jsonflags.ReportErrorsWithLegacySemantics | 1},
1533 in: structStringifiedMap{},
1534 want: `{"Map":{}}`,
1535 }, {
1536 name: jsontest.Name("Structs/LegacyStringified/Invalid/Slice"),
1537 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
1538 in: structStringifiedSlice{},
1539 want: `{"Slice"`,
1540 wantErr: EM(errInvalidStringTag).withPos(`{"Slice":`, "/Slice").withType(0, reflect.TypeFor[[]string]()),
1541 }, {
1542 name: jsontest.Name("Structs/LegacyStringified/Ignored/Slice"),
1543 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1, jsonflags.ReportErrorsWithLegacySemantics | 1},
1544 in: structStringifiedSlice{},
1545 want: `{"Slice":[]}`,
1546 }, {
1547 name: jsontest.Name("Structs/LegacyStringified/Invalid/Array"),
1548 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
1549 in: structStringifiedArray{},
1550 want: `{"Array"`,
1551 wantErr: EM(errInvalidStringTag).withPos(`{"Array":`, "/Array").withType(0, reflect.TypeFor[[1]string]()),
1552 }, {
1553 name: jsontest.Name("Structs/LegacyStringified/Ignored/Array"),
1554 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1, jsonflags.ReportErrorsWithLegacySemantics | 1},
1555 in: structStringifiedArray{},
1556 want: `{"Array":[""]}`,
1557 }, {
1558 name: jsontest.Name("Structs/LegacyStringified/Invalid/Struct"),
1559 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
1560 in: structStringifiedStruct{},
1561 want: `{"Struct"`,
1562 wantErr: EM(errInvalidStringTag).withPos(`{"Struct":`, "/Struct").withType(0, reflect.TypeFor[structAll]()),
1563 }, {
1564 name: jsontest.Name("Structs/LegacyStringified/Ignored/Struct"),
1565 opts: []Options{jsontext.Multiline(true), jsonflags.StringifyWithLegacySemantics | 1, jsonflags.ReportErrorsWithLegacySemantics | 1},
1566 in: structStringifiedStruct{},
1567 want: `{
1568 "Struct": {
1569 "Bool": false,
1570 "String": "",
1571 "Bytes": "",
1572 "Int": 0,
1573 "Uint": 0,
1574 "Float": 0,
1575 "Map": {},
1576 "StructScalars": {
1577 "Bool": false,
1578 "String": "",
1579 "Bytes": "",
1580 "Int": 0,
1581 "Uint": 0,
1582 "Float": 0
1583 },
1584 "StructMaps": {
1585 "MapBool": {},
1586 "MapString": {},
1587 "MapBytes": {},
1588 "MapInt": {},
1589 "MapUint": {},
1590 "MapFloat": {}
1591 },
1592 "StructSlices": {
1593 "SliceBool": [],
1594 "SliceString": [],
1595 "SliceBytes": [],
1596 "SliceInt": [],
1597 "SliceUint": [],
1598 "SliceFloat": []
1599 },
1600 "Slice": [],
1601 "Array": [
1602 ""
1603 ],
1604 "Pointer": null,
1605 "Interface": null
1606 }
1607 }`,
1608 }, {
1609 name: jsontest.Name("Structs/LegacyStringified/Invalid/Pointer"),
1610 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
1611 in: structStringifiedPointer{Pointer: new(structAll)},
1612 want: `{"Pointer"`,
1613 wantErr: EM(errInvalidStringTag).withPos(`{"Pointer":`, "/Pointer").withType(0, reflect.TypeFor[structAll]()),
1614 }, {
1615 name: jsontest.Name("Structs/LegacyStringified/Ignored/Pointer"),
1616 opts: []Options{jsontext.Multiline(true), jsonflags.StringifyWithLegacySemantics | 1, jsonflags.ReportErrorsWithLegacySemantics | 1},
1617 in: structStringifiedPointer{Pointer: new(structAll)},
1618 want: `{
1619 "Pointer": {
1620 "Bool": false,
1621 "String": "",
1622 "Bytes": "",
1623 "Int": 0,
1624 "Uint": 0,
1625 "Float": 0,
1626 "Map": {},
1627 "StructScalars": {
1628 "Bool": false,
1629 "String": "",
1630 "Bytes": "",
1631 "Int": 0,
1632 "Uint": 0,
1633 "Float": 0
1634 },
1635 "StructMaps": {
1636 "MapBool": {},
1637 "MapString": {},
1638 "MapBytes": {},
1639 "MapInt": {},
1640 "MapUint": {},
1641 "MapFloat": {}
1642 },
1643 "StructSlices": {
1644 "SliceBool": [],
1645 "SliceString": [],
1646 "SliceBytes": [],
1647 "SliceInt": [],
1648 "SliceUint": [],
1649 "SliceFloat": []
1650 },
1651 "Slice": [],
1652 "Array": [
1653 ""
1654 ],
1655 "Pointer": null,
1656 "Interface": null
1657 }
1658 }`,
1659 }, {
1660 name: jsontest.Name("Structs/LegacyStringified/Invalid/PointerPointerInt"),
1661 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
1662 in: structStringifiedPointerPointerInt{Pointer: new(new(5))},
1663 want: `{"Pointer"`,
1664 wantErr: EM(errInvalidStringTag).withPos(`{"Pointer":`, "/Pointer").withType(0, reflect.TypeFor[**int]()),
1665 }, {
1666 name: jsontest.Name("Structs/LegacyStringified/Ignored/PointerPointerInt"),
1667 opts: []Options{jsonflags.StringifyWithLegacySemantics | jsonflags.ReportErrorsWithLegacySemantics | 1},
1668 in: structStringifiedPointerPointerInt{Pointer: new(new(5))},
1669 want: `{"Pointer":5}`,
1670 }, {
1671 name: jsontest.Name("Structs/LegacyStringified/Invalid/Interface"),
1672 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
1673 in: structStringifiedInterface{},
1674 want: `{"Interface"`,
1675 wantErr: EM(errInvalidStringTag).withPos(`{"Interface":`, "/Interface").withType(0, anyType),
1676 }, {
1677 name: jsontest.Name("Structs/LegacyStringified/Ignored/Interface"),
1678 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1, jsonflags.ReportErrorsWithLegacySemantics | 1},
1679 in: structStringifiedInterface{Interface: 1000},
1680 want: `{"Interface":1000}`,
1681 }, {
1682 name: jsontest.Name("Structs/OmitZero/Zero"),
1683 in: structOmitZeroAll{},
1684 want: `{}`,
1685 }, {
1686 name: jsontest.Name("Structs/OmitZeroOption/Zero"),
1687 opts: []Options{OmitZeroStructFields(true)},
1688 in: structAll{},
1689 want: `{}`,
1690 }, {
1691 name: jsontest.Name("Structs/OmitZero/NonZero"),
1692 opts: []Options{jsontext.Multiline(true)},
1693 in: structOmitZeroAll{
1694 Bool: true,
1695 String: " ",
1696 Bytes: []byte{},
1697 Int: 1,
1698 Uint: 1,
1699 Float: math.SmallestNonzeroFloat64,
1700 Map: map[string]string{},
1701 StructScalars: structScalars{unexported: true},
1702 StructSlices: structSlices{Ignored: true},
1703 StructMaps: structMaps{MapBool: map[string]bool{}},
1704 Slice: []string{},
1705 Array: [1]string{" "},
1706 Pointer: new(structOmitZeroAll),
1707 Interface: (*structOmitZeroAll)(nil),
1708 },
1709 want: `{
1710 "Bool": true,
1711 "String": " ",
1712 "Bytes": "",
1713 "Int": 1,
1714 "Uint": 1,
1715 "Float": 5e-324,
1716 "Map": {},
1717 "StructScalars": {
1718 "Bool": false,
1719 "String": "",
1720 "Bytes": "",
1721 "Int": 0,
1722 "Uint": 0,
1723 "Float": 0
1724 },
1725 "StructMaps": {
1726 "MapBool": {},
1727 "MapString": {},
1728 "MapBytes": {},
1729 "MapInt": {},
1730 "MapUint": {},
1731 "MapFloat": {}
1732 },
1733 "StructSlices": {
1734 "SliceBool": [],
1735 "SliceString": [],
1736 "SliceBytes": [],
1737 "SliceInt": [],
1738 "SliceUint": [],
1739 "SliceFloat": []
1740 },
1741 "Slice": [],
1742 "Array": [
1743 " "
1744 ],
1745 "Pointer": {},
1746 "Interface": null
1747 }`,
1748 }, {
1749 name: jsontest.Name("Structs/OmitZeroOption/NonZero"),
1750 opts: []Options{OmitZeroStructFields(true), jsontext.Multiline(true)},
1751 in: structAll{
1752 Bool: true,
1753 String: " ",
1754 Bytes: []byte{},
1755 Int: 1,
1756 Uint: 1,
1757 Float: math.SmallestNonzeroFloat64,
1758 Map: map[string]string{},
1759 StructScalars: structScalars{unexported: true},
1760 StructSlices: structSlices{Ignored: true},
1761 StructMaps: structMaps{MapBool: map[string]bool{}},
1762 Slice: []string{},
1763 Array: [1]string{" "},
1764 Pointer: new(structAll),
1765 Interface: (*structAll)(nil),
1766 },
1767 want: `{
1768 "Bool": true,
1769 "String": " ",
1770 "Bytes": "",
1771 "Int": 1,
1772 "Uint": 1,
1773 "Float": 5e-324,
1774 "Map": {},
1775 "StructScalars": {},
1776 "StructMaps": {
1777 "MapBool": {}
1778 },
1779 "StructSlices": {},
1780 "Slice": [],
1781 "Array": [
1782 " "
1783 ],
1784 "Pointer": {},
1785 "Interface": null
1786 }`,
1787 }, {
1788 name: jsontest.Name("Structs/OmitZeroMethod/Zero"),
1789 in: structOmitZeroMethodAll{},
1790 want: `{"ValueNeverZero":"","PointerNeverZero":""}`,
1791 }, {
1792 name: jsontest.Name("Structs/OmitZeroMethod/NonZero"),
1793 opts: []Options{jsontext.Multiline(true)},
1794 in: structOmitZeroMethodAll{
1795 ValueAlwaysZero: valueAlwaysZero("nonzero"),
1796 ValueNeverZero: valueNeverZero("nonzero"),
1797 PointerAlwaysZero: pointerAlwaysZero("nonzero"),
1798 PointerNeverZero: pointerNeverZero("nonzero"),
1799 PointerValueAlwaysZero: addr(valueAlwaysZero("nonzero")),
1800 PointerValueNeverZero: addr(valueNeverZero("nonzero")),
1801 PointerPointerAlwaysZero: addr(pointerAlwaysZero("nonzero")),
1802 PointerPointerNeverZero: addr(pointerNeverZero("nonzero")),
1803 PointerPointerValueAlwaysZero: addr(addr(valueAlwaysZero("nonzero"))),
1804 PointerPointerValueNeverZero: addr(addr(valueNeverZero("nonzero"))),
1805 PointerPointerPointerAlwaysZero: addr(addr(pointerAlwaysZero("nonzero"))),
1806 PointerPointerPointerNeverZero: addr(addr(pointerNeverZero("nonzero"))),
1807 },
1808 want: `{
1809 "ValueNeverZero": "nonzero",
1810 "PointerNeverZero": "nonzero",
1811 "PointerValueNeverZero": "nonzero",
1812 "PointerPointerNeverZero": "nonzero",
1813 "PointerPointerValueAlwaysZero": "nonzero",
1814 "PointerPointerValueNeverZero": "nonzero",
1815 "PointerPointerPointerAlwaysZero": "nonzero",
1816 "PointerPointerPointerNeverZero": "nonzero"
1817 }`,
1818 }, {
1819 name: jsontest.Name("Structs/OmitZeroMethod/Interface/Zero"),
1820 opts: []Options{jsontext.Multiline(true)},
1821 in: structOmitZeroMethodInterfaceAll{},
1822 want: `{}`,
1823 }, {
1824 name: jsontest.Name("Structs/OmitZeroMethod/Interface/PartialZero"),
1825 opts: []Options{jsontext.Multiline(true)},
1826 in: structOmitZeroMethodInterfaceAll{
1827 ValueAlwaysZero: valueAlwaysZero(""),
1828 ValueNeverZero: valueNeverZero(""),
1829 PointerValueAlwaysZero: (*valueAlwaysZero)(nil),
1830 PointerValueNeverZero: (*valueNeverZero)(nil),
1831 PointerPointerAlwaysZero: (*pointerAlwaysZero)(nil),
1832 PointerPointerNeverZero: (*pointerNeverZero)(nil),
1833 },
1834 want: `{
1835 "ValueNeverZero": ""
1836 }`,
1837 }, {
1838 name: jsontest.Name("Structs/OmitZeroMethod/Interface/NonZero"),
1839 opts: []Options{jsontext.Multiline(true)},
1840 in: structOmitZeroMethodInterfaceAll{
1841 ValueAlwaysZero: valueAlwaysZero("nonzero"),
1842 ValueNeverZero: valueNeverZero("nonzero"),
1843 PointerValueAlwaysZero: addr(valueAlwaysZero("nonzero")),
1844 PointerValueNeverZero: addr(valueNeverZero("nonzero")),
1845 PointerPointerAlwaysZero: addr(pointerAlwaysZero("nonzero")),
1846 PointerPointerNeverZero: addr(pointerNeverZero("nonzero")),
1847 },
1848 want: `{
1849 "ValueNeverZero": "nonzero",
1850 "PointerValueNeverZero": "nonzero",
1851 "PointerPointerNeverZero": "nonzero"
1852 }`,
1853 }, {
1854 name: jsontest.Name("Structs/OmitEmpty/Zero"),
1855 opts: []Options{jsontext.Multiline(true)},
1856 in: structOmitEmptyAll{},
1857 want: `{
1858 "Bool": false,
1859 "StringNonEmpty": "value",
1860 "BytesNonEmpty": [
1861 "value"
1862 ],
1863 "Float": 0,
1864 "MapNonEmpty": {
1865 "key": "value"
1866 },
1867 "SliceNonEmpty": [
1868 "value"
1869 ]
1870 }`,
1871 }, {
1872 name: jsontest.Name("Structs/OmitEmpty/EmptyNonZero"),
1873 opts: []Options{jsontext.Multiline(true)},
1874 in: structOmitEmptyAll{
1875 String: string(""),
1876 StringEmpty: stringMarshalEmpty(""),
1877 StringNonEmpty: stringMarshalNonEmpty(""),
1878 PointerString: addr(string("")),
1879 PointerStringEmpty: addr(stringMarshalEmpty("")),
1880 PointerStringNonEmpty: addr(stringMarshalNonEmpty("")),
1881 Bytes: []byte(""),
1882 BytesEmpty: bytesMarshalEmpty([]byte("")),
1883 BytesNonEmpty: bytesMarshalNonEmpty([]byte("")),
1884 PointerBytes: addr([]byte("")),
1885 PointerBytesEmpty: addr(bytesMarshalEmpty([]byte(""))),
1886 PointerBytesNonEmpty: addr(bytesMarshalNonEmpty([]byte(""))),
1887 Map: map[string]string{},
1888 MapEmpty: mapMarshalEmpty{},
1889 MapNonEmpty: mapMarshalNonEmpty{},
1890 PointerMap: addr(map[string]string{}),
1891 PointerMapEmpty: addr(mapMarshalEmpty{}),
1892 PointerMapNonEmpty: addr(mapMarshalNonEmpty{}),
1893 Slice: []string{},
1894 SliceEmpty: sliceMarshalEmpty{},
1895 SliceNonEmpty: sliceMarshalNonEmpty{},
1896 PointerSlice: addr([]string{}),
1897 PointerSliceEmpty: addr(sliceMarshalEmpty{}),
1898 PointerSliceNonEmpty: addr(sliceMarshalNonEmpty{}),
1899 Pointer: &structOmitZeroEmptyAll{},
1900 Interface: []string{},
1901 },
1902 want: `{
1903 "Bool": false,
1904 "StringNonEmpty": "value",
1905 "PointerStringNonEmpty": "value",
1906 "BytesNonEmpty": [
1907 "value"
1908 ],
1909 "PointerBytesNonEmpty": [
1910 "value"
1911 ],
1912 "Float": 0,
1913 "MapNonEmpty": {
1914 "key": "value"
1915 },
1916 "PointerMapNonEmpty": {
1917 "key": "value"
1918 },
1919 "SliceNonEmpty": [
1920 "value"
1921 ],
1922 "PointerSliceNonEmpty": [
1923 "value"
1924 ]
1925 }`,
1926 }, {
1927 name: jsontest.Name("Structs/OmitEmpty/NonEmpty"),
1928 opts: []Options{jsontext.Multiline(true)},
1929 in: structOmitEmptyAll{
1930 Bool: true,
1931 PointerBool: addr(true),
1932 String: string("value"),
1933 StringEmpty: stringMarshalEmpty("value"),
1934 StringNonEmpty: stringMarshalNonEmpty("value"),
1935 PointerString: addr(string("value")),
1936 PointerStringEmpty: addr(stringMarshalEmpty("value")),
1937 PointerStringNonEmpty: addr(stringMarshalNonEmpty("value")),
1938 Bytes: []byte("value"),
1939 BytesEmpty: bytesMarshalEmpty([]byte("value")),
1940 BytesNonEmpty: bytesMarshalNonEmpty([]byte("value")),
1941 PointerBytes: addr([]byte("value")),
1942 PointerBytesEmpty: addr(bytesMarshalEmpty([]byte("value"))),
1943 PointerBytesNonEmpty: addr(bytesMarshalNonEmpty([]byte("value"))),
1944 Float: math.Copysign(0, -1),
1945 PointerFloat: addr(math.Copysign(0, -1)),
1946 Map: map[string]string{"": ""},
1947 MapEmpty: mapMarshalEmpty{"key": "value"},
1948 MapNonEmpty: mapMarshalNonEmpty{"key": "value"},
1949 PointerMap: addr(map[string]string{"": ""}),
1950 PointerMapEmpty: addr(mapMarshalEmpty{"key": "value"}),
1951 PointerMapNonEmpty: addr(mapMarshalNonEmpty{"key": "value"}),
1952 Slice: []string{""},
1953 SliceEmpty: sliceMarshalEmpty{"value"},
1954 SliceNonEmpty: sliceMarshalNonEmpty{"value"},
1955 PointerSlice: addr([]string{""}),
1956 PointerSliceEmpty: addr(sliceMarshalEmpty{"value"}),
1957 PointerSliceNonEmpty: addr(sliceMarshalNonEmpty{"value"}),
1958 Pointer: &structOmitZeroEmptyAll{Float: math.SmallestNonzeroFloat64},
1959 Interface: []string{""},
1960 },
1961 want: `{
1962 "Bool": true,
1963 "PointerBool": true,
1964 "String": "value",
1965 "StringNonEmpty": "value",
1966 "PointerString": "value",
1967 "PointerStringNonEmpty": "value",
1968 "Bytes": "dmFsdWU=",
1969 "BytesNonEmpty": [
1970 "value"
1971 ],
1972 "PointerBytes": "dmFsdWU=",
1973 "PointerBytesNonEmpty": [
1974 "value"
1975 ],
1976 "Float": -0,
1977 "PointerFloat": -0,
1978 "Map": {
1979 "": ""
1980 },
1981 "MapNonEmpty": {
1982 "key": "value"
1983 },
1984 "PointerMap": {
1985 "": ""
1986 },
1987 "PointerMapNonEmpty": {
1988 "key": "value"
1989 },
1990 "Slice": [
1991 ""
1992 ],
1993 "SliceNonEmpty": [
1994 "value"
1995 ],
1996 "PointerSlice": [
1997 ""
1998 ],
1999 "PointerSliceNonEmpty": [
2000 "value"
2001 ],
2002 "Pointer": {
2003 "Float": 5e-324
2004 },
2005 "Interface": [
2006 ""
2007 ]
2008 }`,
2009 }, {
2010 name: jsontest.Name("Structs/OmitEmpty/Legacy/Zero"),
2011 opts: []Options{jsonflags.OmitEmptyWithLegacySemantics | 1},
2012 in: structOmitEmptyAll{},
2013 want: `{}`,
2014 }, {
2015 name: jsontest.Name("Structs/OmitEmpty/Legacy/NonEmpty"),
2016 opts: []Options{jsontext.Multiline(true), jsonflags.OmitEmptyWithLegacySemantics | 1},
2017 in: structOmitEmptyAll{
2018 Bool: true,
2019 PointerBool: addr(true),
2020 String: string("value"),
2021 StringEmpty: stringMarshalEmpty("value"),
2022 StringNonEmpty: stringMarshalNonEmpty("value"),
2023 PointerString: addr(string("value")),
2024 PointerStringEmpty: addr(stringMarshalEmpty("value")),
2025 PointerStringNonEmpty: addr(stringMarshalNonEmpty("value")),
2026 Bytes: []byte("value"),
2027 BytesEmpty: bytesMarshalEmpty([]byte("value")),
2028 BytesNonEmpty: bytesMarshalNonEmpty([]byte("value")),
2029 PointerBytes: addr([]byte("value")),
2030 PointerBytesEmpty: addr(bytesMarshalEmpty([]byte("value"))),
2031 PointerBytesNonEmpty: addr(bytesMarshalNonEmpty([]byte("value"))),
2032 Float: math.Copysign(0, -1),
2033 PointerFloat: addr(math.Copysign(0, -1)),
2034 Map: map[string]string{"": ""},
2035 MapEmpty: mapMarshalEmpty{"key": "value"},
2036 MapNonEmpty: mapMarshalNonEmpty{"key": "value"},
2037 PointerMap: addr(map[string]string{"": ""}),
2038 PointerMapEmpty: addr(mapMarshalEmpty{"key": "value"}),
2039 PointerMapNonEmpty: addr(mapMarshalNonEmpty{"key": "value"}),
2040 Slice: []string{""},
2041 SliceEmpty: sliceMarshalEmpty{"value"},
2042 SliceNonEmpty: sliceMarshalNonEmpty{"value"},
2043 PointerSlice: addr([]string{""}),
2044 PointerSliceEmpty: addr(sliceMarshalEmpty{"value"}),
2045 PointerSliceNonEmpty: addr(sliceMarshalNonEmpty{"value"}),
2046 Pointer: &structOmitZeroEmptyAll{Float: math.Copysign(0, -1)},
2047 Interface: []string{""},
2048 },
2049 want: `{
2050 "Bool": true,
2051 "PointerBool": true,
2052 "String": "value",
2053 "StringEmpty": "",
2054 "StringNonEmpty": "value",
2055 "PointerString": "value",
2056 "PointerStringEmpty": "",
2057 "PointerStringNonEmpty": "value",
2058 "Bytes": "dmFsdWU=",
2059 "BytesEmpty": [],
2060 "BytesNonEmpty": [
2061 "value"
2062 ],
2063 "PointerBytes": "dmFsdWU=",
2064 "PointerBytesEmpty": [],
2065 "PointerBytesNonEmpty": [
2066 "value"
2067 ],
2068 "PointerFloat": -0,
2069 "Map": {
2070 "": ""
2071 },
2072 "MapEmpty": {},
2073 "MapNonEmpty": {
2074 "key": "value"
2075 },
2076 "PointerMap": {
2077 "": ""
2078 },
2079 "PointerMapEmpty": {},
2080 "PointerMapNonEmpty": {
2081 "key": "value"
2082 },
2083 "Slice": [
2084 ""
2085 ],
2086 "SliceEmpty": [],
2087 "SliceNonEmpty": [
2088 "value"
2089 ],
2090 "PointerSlice": [
2091 ""
2092 ],
2093 "PointerSliceEmpty": [],
2094 "PointerSliceNonEmpty": [
2095 "value"
2096 ],
2097 "Pointer": {},
2098 "Interface": [
2099 ""
2100 ]
2101 }`,
2102 }, {
2103 name: jsontest.Name("Structs/OmitEmpty/NonEmptyString"),
2104 in: struct {
2105 X string `json:",omitempty"`
2106 }{`"`},
2107 want: `{"X":"\""}`,
2108 }, {
2109 name: jsontest.Name("Structs/OmitZeroEmpty/Zero"),
2110 in: structOmitZeroEmptyAll{},
2111 want: `{}`,
2112 }, {
2113 name: jsontest.Name("Structs/OmitZeroEmpty/Empty"),
2114 in: structOmitZeroEmptyAll{
2115 Bytes: []byte{},
2116 Map: map[string]string{},
2117 Slice: []string{},
2118 Pointer: &structOmitZeroEmptyAll{},
2119 Interface: []string{},
2120 },
2121 want: `{}`,
2122 }, {
2123 name: jsontest.Name("Structs/OmitEmpty/PathologicalDepth"),
2124 in: func() any {
2125 type X struct {
2126 X *X `json:",omitempty"`
2127 }
2128 var make func(int) *X
2129 make = func(n int) *X {
2130 if n == 0 {
2131 return nil
2132 }
2133 return &X{make(n - 1)}
2134 }
2135 return make(100)
2136 }(),
2137 want: `{}`,
2138 useWriter: true,
2139 }, {
2140 name: jsontest.Name("Structs/OmitEmpty/PathologicalBreadth"),
2141 in: func() any {
2142 var fields []reflect.StructField
2143 for i := range 100 {
2144 fields = append(fields, reflect.StructField{
2145 Name: fmt.Sprintf("X%d", i),
2146 Type: T[stringMarshalEmpty](),
2147 Tag: `json:",omitempty"`,
2148 })
2149 }
2150 return reflect.New(reflect.StructOf(fields)).Interface()
2151 }(),
2152 want: `{}`,
2153 useWriter: true,
2154 }, {
2155 name: jsontest.Name("Structs/OmitEmpty/PathologicalTree"),
2156 in: func() any {
2157 type X struct {
2158 XL, XR *X `json:",omitempty"`
2159 }
2160 var make func(int) *X
2161 make = func(n int) *X {
2162 if n == 0 {
2163 return nil
2164 }
2165 return &X{make(n - 1), make(n - 1)}
2166 }
2167 return make(8)
2168 }(),
2169 want: `{}`,
2170 useWriter: true,
2171 }, {
2172 name: jsontest.Name("Structs/OmitZeroEmpty/NonEmpty"),
2173 in: structOmitZeroEmptyAll{
2174 Bytes: []byte("value"),
2175 Map: map[string]string{"": ""},
2176 Slice: []string{""},
2177 Pointer: &structOmitZeroEmptyAll{Bool: true},
2178 Interface: []string{""},
2179 },
2180 want: `{"Bytes":"dmFsdWU=","Map":{"":""},"Slice":[""],"Pointer":{"Bool":true},"Interface":[""]}`,
2181 }, {
2182 name: jsontest.Name("Structs/Format/Bytes/Unsupported"),
2183 opts: []Options{jsontext.Multiline(true)},
2184 in: structFormatBytes{},
2185 wantErr: EM(errors.New("Go struct field Base16 has unsupported `format` tag option")).withType(0, T[structFormatBytes]()),
2186 }, {
2187 name: jsontest.Name("Structs/Format/Bytes"),
2188 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true), jsontext.Multiline(true)},
2189 in: structFormatBytes{
2190 Base16: []byte("\x01\x23\x45\x67\x89\xab\xcd\xef"),
2191 Base32: []byte("\x00D2\x14\xc7BT\xb65τe:V\xd7\xc6u\xbew\xdf"),
2192 Base32Hex: []byte("\x00D2\x14\xc7BT\xb65τe:V\xd7\xc6u\xbew\xdf"),
2193 Base64: []byte("\x00\x10\x83\x10Q\x87 \x92\x8b0ӏA\x14\x93QU\x97a\x96\x9bqן\x82\x18\xa3\x92Y\xa7\xa2\x9a\xab\xb2ۯ\xc3\x1c\xb3\xd3]\xb7㞻\xf3߿"),
2194 Base64URL: []byte("\x00\x10\x83\x10Q\x87 \x92\x8b0ӏA\x14\x93QU\x97a\x96\x9bqן\x82\x18\xa3\x92Y\xa7\xa2\x9a\xab\xb2ۯ\xc3\x1c\xb3\xd3]\xb7㞻\xf3߿"),
2195 Array: []byte{1, 2, 3, 4},
2196 },
2197 want: `{
2198 "Base16": "0123456789abcdef",
2199 "Base32": "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
2200 "Base32Hex": "0123456789ABCDEFGHIJKLMNOPQRSTUV",
2201 "Base64": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
2202 "Base64URL": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
2203 "Array": [
2204 1,
2205 2,
2206 3,
2207 4
2208 ]
2209 }`,
2210 }, {
2211 name: jsontest.Name("Structs/Format/ArrayBytes"),
2212 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true), jsontext.Multiline(true)},
2213 in: structFormatArrayBytes{
2214 Base16: [4]byte{1, 2, 3, 4},
2215 Base32: [4]byte{1, 2, 3, 4},
2216 Base32Hex: [4]byte{1, 2, 3, 4},
2217 Base64: [4]byte{1, 2, 3, 4},
2218 Base64URL: [4]byte{1, 2, 3, 4},
2219 Array: [4]byte{1, 2, 3, 4},
2220 Default: [4]byte{1, 2, 3, 4},
2221 },
2222 want: `{
2223 "Base16": "01020304",
2224 "Base32": "AEBAGBA=",
2225 "Base32Hex": "0410610=",
2226 "Base64": "AQIDBA==",
2227 "Base64URL": "AQIDBA==",
2228 "Array": [
2229 1,
2230 2,
2231 3,
2232 4
2233 ],
2234 "Default": "AQIDBA=="
2235 }`,
2236 }, {
2237 name: jsontest.Name("Structs/Format/ArrayBytes/Legacy"),
2238 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true), jsontext.Multiline(true), jsonflags.FormatByteArrayAsArray | jsonflags.FormatBytesWithLegacySemantics | 1},
2239 in: structFormatArrayBytes{
2240 Base16: [4]byte{1, 2, 3, 4},
2241 Base32: [4]byte{1, 2, 3, 4},
2242 Base32Hex: [4]byte{1, 2, 3, 4},
2243 Base64: [4]byte{1, 2, 3, 4},
2244 Base64URL: [4]byte{1, 2, 3, 4},
2245 Array: [4]byte{1, 2, 3, 4},
2246 Default: [4]byte{1, 2, 3, 4},
2247 },
2248 want: `{
2249 "Base16": "01020304",
2250 "Base32": "AEBAGBA=",
2251 "Base32Hex": "0410610=",
2252 "Base64": "AQIDBA==",
2253 "Base64URL": "AQIDBA==",
2254 "Array": [
2255 1,
2256 2,
2257 3,
2258 4
2259 ],
2260 "Default": [
2261 1,
2262 2,
2263 3,
2264 4
2265 ]
2266 }`,
2267 }, {
2268 name: jsontest.Name("Structs/Format/Bytes/Array"),
2269 opts: []Options{
2270 jsonopts.ExperimentalSupportFormatTag(true),
2271 WithMarshalers(MarshalFunc(func(in byte) ([]byte, error) {
2272 if in > 3 {
2273 return []byte("true"), nil
2274 } else {
2275 return []byte("false"), nil
2276 }
2277 })),
2278 },
2279 in: struct {
2280 Array []byte `json:",format:array"`
2281 }{
2282 Array: []byte{1, 6, 2, 5, 3, 4},
2283 },
2284 want: `{"Array":[false,true,false,true,false,true]}`,
2285 }, {
2286 name: jsontest.Name("Structs/Format/Floats"),
2287 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true), jsontext.Multiline(true)},
2288 in: []structFormatFloats{
2289 {NonFinite: math.Pi, PointerNonFinite: addr(math.Pi)},
2290 {NonFinite: math.NaN(), PointerNonFinite: addr(math.NaN())},
2291 {NonFinite: math.Inf(-1), PointerNonFinite: addr(math.Inf(-1))},
2292 {NonFinite: math.Inf(+1), PointerNonFinite: addr(math.Inf(+1))},
2293 },
2294 want: `[
2295 {
2296 "NonFinite": 3.141592653589793,
2297 "PointerNonFinite": 3.141592653589793
2298 },
2299 {
2300 "NonFinite": "NaN",
2301 "PointerNonFinite": "NaN"
2302 },
2303 {
2304 "NonFinite": "-Infinity",
2305 "PointerNonFinite": "-Infinity"
2306 },
2307 {
2308 "NonFinite": "Infinity",
2309 "PointerNonFinite": "Infinity"
2310 }
2311 ]`,
2312 }, {
2313 name: jsontest.Name("Structs/Format/Maps"),
2314 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true), jsontext.Multiline(true)},
2315 in: []structFormatMaps{{
2316 EmitNull: map[string]string(nil), PointerEmitNull: addr(map[string]string(nil)),
2317 EmitEmpty: map[string]string(nil), PointerEmitEmpty: addr(map[string]string(nil)),
2318 EmitDefault: map[string]string(nil), PointerEmitDefault: addr(map[string]string(nil)),
2319 }, {
2320 EmitNull: map[string]string{}, PointerEmitNull: addr(map[string]string{}),
2321 EmitEmpty: map[string]string{}, PointerEmitEmpty: addr(map[string]string{}),
2322 EmitDefault: map[string]string{}, PointerEmitDefault: addr(map[string]string{}),
2323 }, {
2324 EmitNull: map[string]string{"k": "v"}, PointerEmitNull: addr(map[string]string{"k": "v"}),
2325 EmitEmpty: map[string]string{"k": "v"}, PointerEmitEmpty: addr(map[string]string{"k": "v"}),
2326 EmitDefault: map[string]string{"k": "v"}, PointerEmitDefault: addr(map[string]string{"k": "v"}),
2327 }},
2328 want: `[
2329 {
2330 "EmitNull": null,
2331 "PointerEmitNull": null,
2332 "EmitEmpty": {},
2333 "PointerEmitEmpty": {},
2334 "EmitDefault": {},
2335 "PointerEmitDefault": {}
2336 },
2337 {
2338 "EmitNull": {},
2339 "PointerEmitNull": {},
2340 "EmitEmpty": {},
2341 "PointerEmitEmpty": {},
2342 "EmitDefault": {},
2343 "PointerEmitDefault": {}
2344 },
2345 {
2346 "EmitNull": {
2347 "k": "v"
2348 },
2349 "PointerEmitNull": {
2350 "k": "v"
2351 },
2352 "EmitEmpty": {
2353 "k": "v"
2354 },
2355 "PointerEmitEmpty": {
2356 "k": "v"
2357 },
2358 "EmitDefault": {
2359 "k": "v"
2360 },
2361 "PointerEmitDefault": {
2362 "k": "v"
2363 }
2364 }
2365 ]`,
2366 }, {
2367 name: jsontest.Name("Structs/Format/Maps/FormatNilMapAsNull"),
2368 opts: []Options{
2369 jsonopts.ExperimentalSupportFormatTag(true),
2370 FormatNilMapAsNull(true),
2371 jsontext.Multiline(true),
2372 },
2373 in: []structFormatMaps{{
2374 EmitNull: map[string]string(nil), PointerEmitNull: addr(map[string]string(nil)),
2375 EmitEmpty: map[string]string(nil), PointerEmitEmpty: addr(map[string]string(nil)),
2376 EmitDefault: map[string]string(nil), PointerEmitDefault: addr(map[string]string(nil)),
2377 }, {
2378 EmitNull: map[string]string{}, PointerEmitNull: addr(map[string]string{}),
2379 EmitEmpty: map[string]string{}, PointerEmitEmpty: addr(map[string]string{}),
2380 EmitDefault: map[string]string{}, PointerEmitDefault: addr(map[string]string{}),
2381 }, {
2382 EmitNull: map[string]string{"k": "v"}, PointerEmitNull: addr(map[string]string{"k": "v"}),
2383 EmitEmpty: map[string]string{"k": "v"}, PointerEmitEmpty: addr(map[string]string{"k": "v"}),
2384 EmitDefault: map[string]string{"k": "v"}, PointerEmitDefault: addr(map[string]string{"k": "v"}),
2385 }},
2386 want: `[
2387 {
2388 "EmitNull": null,
2389 "PointerEmitNull": null,
2390 "EmitEmpty": {},
2391 "PointerEmitEmpty": {},
2392 "EmitDefault": null,
2393 "PointerEmitDefault": null
2394 },
2395 {
2396 "EmitNull": {},
2397 "PointerEmitNull": {},
2398 "EmitEmpty": {},
2399 "PointerEmitEmpty": {},
2400 "EmitDefault": {},
2401 "PointerEmitDefault": {}
2402 },
2403 {
2404 "EmitNull": {
2405 "k": "v"
2406 },
2407 "PointerEmitNull": {
2408 "k": "v"
2409 },
2410 "EmitEmpty": {
2411 "k": "v"
2412 },
2413 "PointerEmitEmpty": {
2414 "k": "v"
2415 },
2416 "EmitDefault": {
2417 "k": "v"
2418 },
2419 "PointerEmitDefault": {
2420 "k": "v"
2421 }
2422 }
2423 ]`,
2424 }, {
2425 name: jsontest.Name("Structs/Format/Slices"),
2426 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true), jsontext.Multiline(true)},
2427 in: []structFormatSlices{{
2428 EmitNull: []string(nil), PointerEmitNull: addr([]string(nil)),
2429 EmitEmpty: []string(nil), PointerEmitEmpty: addr([]string(nil)),
2430 EmitDefault: []string(nil), PointerEmitDefault: addr([]string(nil)),
2431 }, {
2432 EmitNull: []string{}, PointerEmitNull: addr([]string{}),
2433 EmitEmpty: []string{}, PointerEmitEmpty: addr([]string{}),
2434 EmitDefault: []string{}, PointerEmitDefault: addr([]string{}),
2435 }, {
2436 EmitNull: []string{"v"}, PointerEmitNull: addr([]string{"v"}),
2437 EmitEmpty: []string{"v"}, PointerEmitEmpty: addr([]string{"v"}),
2438 EmitDefault: []string{"v"}, PointerEmitDefault: addr([]string{"v"}),
2439 }},
2440 want: `[
2441 {
2442 "EmitNull": null,
2443 "PointerEmitNull": null,
2444 "EmitEmpty": [],
2445 "PointerEmitEmpty": [],
2446 "EmitDefault": [],
2447 "PointerEmitDefault": []
2448 },
2449 {
2450 "EmitNull": [],
2451 "PointerEmitNull": [],
2452 "EmitEmpty": [],
2453 "PointerEmitEmpty": [],
2454 "EmitDefault": [],
2455 "PointerEmitDefault": []
2456 },
2457 {
2458 "EmitNull": [
2459 "v"
2460 ],
2461 "PointerEmitNull": [
2462 "v"
2463 ],
2464 "EmitEmpty": [
2465 "v"
2466 ],
2467 "PointerEmitEmpty": [
2468 "v"
2469 ],
2470 "EmitDefault": [
2471 "v"
2472 ],
2473 "PointerEmitDefault": [
2474 "v"
2475 ]
2476 }
2477 ]`,
2478 }, {
2479 name: jsontest.Name("Structs/Format/Invalid/Bool"),
2480 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
2481 in: structFormatInvalid{Bool: true},
2482 want: `{"Bool"`,
2483 wantErr: EM(errInvalidFormatFlag).withPos(`{"Bool":`, "/Bool").withType(0, boolType),
2484 }, {
2485 name: jsontest.Name("Structs/Format/Invalid/String"),
2486 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
2487 in: structFormatInvalid{String: "string"},
2488 want: `{"String"`,
2489 wantErr: EM(errInvalidFormatFlag).withPos(`{"String":`, "/String").withType(0, stringType),
2490 }, {
2491 name: jsontest.Name("Structs/Format/Invalid/Bytes"),
2492 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
2493 in: structFormatInvalid{Bytes: []byte("bytes")},
2494 want: `{"Bytes"`,
2495 wantErr: EM(errInvalidFormatFlag).withPos(`{"Bytes":`, "/Bytes").withType(0, bytesType),
2496 }, {
2497 name: jsontest.Name("Structs/Format/Invalid/Int"),
2498 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
2499 in: structFormatInvalid{Int: 1},
2500 want: `{"Int"`,
2501 wantErr: EM(errInvalidFormatFlag).withPos(`{"Int":`, "/Int").withType(0, T[int64]()),
2502 }, {
2503 name: jsontest.Name("Structs/Format/Invalid/Uint"),
2504 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
2505 in: structFormatInvalid{Uint: 1},
2506 want: `{"Uint"`,
2507 wantErr: EM(errInvalidFormatFlag).withPos(`{"Uint":`, "/Uint").withType(0, T[uint64]()),
2508 }, {
2509 name: jsontest.Name("Structs/Format/Invalid/Float"),
2510 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
2511 in: structFormatInvalid{Float: 1},
2512 want: `{"Float"`,
2513 wantErr: EM(errInvalidFormatFlag).withPos(`{"Float":`, "/Float").withType(0, T[float64]()),
2514 }, {
2515 name: jsontest.Name("Structs/Format/Invalid/Map"),
2516 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
2517 in: structFormatInvalid{Map: map[string]string{}},
2518 want: `{"Map"`,
2519 wantErr: EM(errInvalidFormatFlag).withPos(`{"Map":`, "/Map").withType(0, T[map[string]string]()),
2520 }, {
2521 name: jsontest.Name("Structs/Format/Invalid/Struct"),
2522 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
2523 in: structFormatInvalid{Struct: structAll{Bool: true}},
2524 want: `{"Struct"`,
2525 wantErr: EM(errInvalidFormatFlag).withPos(`{"Struct":`, "/Struct").withType(0, T[structAll]()),
2526 }, {
2527 name: jsontest.Name("Structs/Format/Invalid/Slice"),
2528 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
2529 in: structFormatInvalid{Slice: []string{}},
2530 want: `{"Slice"`,
2531 wantErr: EM(errInvalidFormatFlag).withPos(`{"Slice":`, "/Slice").withType(0, T[[]string]()),
2532 }, {
2533 name: jsontest.Name("Structs/Format/Invalid/Array"),
2534 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
2535 in: structFormatInvalid{Array: [1]string{"string"}},
2536 want: `{"Array"`,
2537 wantErr: EM(errInvalidFormatFlag).withPos(`{"Array":`, "/Array").withType(0, T[[1]string]()),
2538 }, {
2539 name: jsontest.Name("Structs/Format/Invalid/Interface"),
2540 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
2541 in: structFormatInvalid{Interface: "anything"},
2542 want: `{"Interface"`,
2543 wantErr: EM(errInvalidFormatFlag).withPos(`{"Interface":`, "/Interface").withType(0, T[any]()),
2544 }, {
2545 name: jsontest.Name("Structs/Embed/Zero"),
2546 in: structEmbedded{},
2547 want: `{"D":""}`,
2548 }, {
2549 name: jsontest.Name("Structs/Embed/Alloc"),
2550 in: structEmbedded{
2551 X: structEmbeddedL1{
2552 X: &structEmbeddedL2{},
2553 StructEmbed1: StructEmbed1{},
2554 },
2555 StructEmbed2: &StructEmbed2{},
2556 },
2557 want: `{"A":"","B":"","D":"","E":"","F":"","G":""}`,
2558 }, {
2559 name: jsontest.Name("Structs/Embed/NonZero"),
2560 in: structEmbedded{
2561 X: structEmbeddedL1{
2562 X: &structEmbeddedL2{A: "A1", B: "B1", C: "C1"},
2563 StructEmbed1: StructEmbed1{C: "C2", D: "D2", E: "E2"},
2564 },
2565 StructEmbed2: &StructEmbed2{E: "E3", F: "F3", G: "G3"},
2566 },
2567 want: `{"A":"A1","B":"B1","D":"D2","E":"E3","F":"F3","G":"G3"}`,
2568 }, {
2569 name: jsontest.Name("Structs/Embed/DualCycle"),
2570 in: cyclicA{
2571 B1: cyclicB{F: 1},
2572 B2: cyclicB{F: 2},
2573 },
2574 want: `{}`,
2575 }, {
2576 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/Nil"),
2577 in: structEmbedTextValue{X: jsontext.Value(nil)},
2578 want: `{}`,
2579 }, {
2580 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/Empty"),
2581 in: structEmbedTextValue{X: jsontext.Value("")},
2582 want: `{}`,
2583 }, {
2584 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/NonEmptyN1"),
2585 in: structEmbedTextValue{X: jsontext.Value(` { "fizz" : "buzz" } `)},
2586 want: `{"fizz":"buzz"}`,
2587 }, {
2588 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/NonEmptyN2"),
2589 in: structEmbedTextValue{X: jsontext.Value(` { "fizz" : "buzz" , "foo" : "bar" } `)},
2590 want: `{"fizz":"buzz","foo":"bar"}`,
2591 }, {
2592 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/NonEmptyWithOthers"),
2593 in: structEmbedTextValue{
2594 A: 1,
2595 X: jsontext.Value(` { "fizz" : "buzz" , "foo" : "bar" } `),
2596 B: 2,
2597 },
2598
2599 want: `{"A":1,"B":2,"fizz":"buzz","foo":"bar"}`,
2600 }, {
2601 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/RejectDuplicateNames"),
2602 opts: []Options{jsontext.AllowDuplicateNames(false)},
2603 in: structEmbedTextValue{X: jsontext.Value(` { "fizz" : "buzz" , "fizz" : "buzz" } `)},
2604 want: `{"fizz":"buzz"`,
2605 wantErr: newDuplicateNameError("/fizz", nil, len64(`{"fizz":"buzz"`)),
2606 }, {
2607 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/AllowDuplicateNames"),
2608 opts: []Options{jsontext.AllowDuplicateNames(true)},
2609 in: structEmbedTextValue{X: jsontext.Value(` { "fizz" : "buzz" , "fizz" : "buzz" } `)},
2610 want: `{"fizz":"buzz","fizz":"buzz"}`,
2611 }, {
2612 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/RejectInvalidUTF8"),
2613 opts: []Options{jsontext.AllowInvalidUTF8(false)},
2614 in: structEmbedTextValue{X: jsontext.Value(`{"` + "\xde\xad\xbe\xef" + `":"value"}`)},
2615 want: `{`,
2616 wantErr: newInvalidUTF8Error(len64(`{"`+"\xde\xad"), ""),
2617 }, {
2618 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/AllowInvalidUTF8"),
2619 opts: []Options{jsontext.AllowInvalidUTF8(true)},
2620 in: structEmbedTextValue{X: jsontext.Value(`{"` + "\xde\xad\xbe\xef" + `":"value"}`)},
2621 want: `{"ޭ��":"value"}`,
2622 }, {
2623 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/InvalidWhitespace"),
2624 in: structEmbedTextValue{X: jsontext.Value("\n\r\t ")},
2625 want: `{`,
2626 wantErr: EM(io.ErrUnexpectedEOF).withPos(`{`, "").withType(0, T[jsontext.Value]()),
2627 }, {
2628 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/InvalidObject"),
2629 in: structEmbedTextValue{X: jsontext.Value(` true `)},
2630 want: `{`,
2631 wantErr: EM(errRawEmbedNotObject).withPos(`{`, "").withType(0, T[jsontext.Value]()),
2632 }, {
2633 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/InvalidObjectName"),
2634 in: structEmbedTextValue{X: jsontext.Value(` { true : false } `)},
2635 want: `{`,
2636 wantErr: EM(newNonStringNameError(len64(" { "), "")).withPos(`{`, "").withType(0, T[jsontext.Value]()),
2637 }, {
2638 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/InvalidEndObject"),
2639 in: structEmbedTextValue{X: jsontext.Value(` { "name" : false , } `)},
2640 want: `{"name":false`,
2641 wantErr: EM(newInvalidCharacterError(",", "at start of value", len64(` { "name" : false `), "")).withPos(`{"name":false,`, "").withType(0, T[jsontext.Value]()),
2642 }, {
2643 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/InvalidDualObject"),
2644 in: structEmbedTextValue{X: jsontext.Value(`{}{}`)},
2645 want: `{`,
2646 wantErr: EM(newInvalidCharacterError("{", "after top-level value", len64(`{}`), "")).withPos(`{`, "").withType(0, T[jsontext.Value]()),
2647 }, {
2648 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/Nested/Nil"),
2649 in: structEmbedPointerEmbedTextValue{},
2650 want: `{}`,
2651 }, {
2652 name: jsontest.Name("Structs/EmbeddedFallback/PointerTextValue/Nil"),
2653 in: structEmbedPointerTextValue{},
2654 want: `{}`,
2655 }, {
2656 name: jsontest.Name("Structs/EmbeddedFallback/PointerTextValue/NonEmpty"),
2657 in: structEmbedPointerTextValue{X: addr(jsontext.Value(` { "fizz" : "buzz" } `))},
2658 want: `{"fizz":"buzz"}`,
2659 }, {
2660 name: jsontest.Name("Structs/EmbeddedFallback/PointerTextValue/Nested/Nil"),
2661 in: structEmbedEmbedPointerTextValue{},
2662 want: `{}`,
2663 }, {
2664 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/Nil"),
2665 in: structEmbedMapStringAny{X: nil},
2666 want: `{}`,
2667 }, {
2668 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/Empty"),
2669 in: structEmbedMapStringAny{X: make(jsonObject)},
2670 want: `{}`,
2671 }, {
2672 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/NonEmptyN1"),
2673 in: structEmbedMapStringAny{X: jsonObject{"fizz": nil}},
2674 want: `{"fizz":null}`,
2675 }, {
2676 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/NonEmptyN2"),
2677 in: structEmbedMapStringAny{X: jsonObject{"fizz": time.Time{}, "buzz": math.Pi}},
2678 want: `{"buzz":3.141592653589793,"fizz":"0001-01-01T00:00:00Z"}`,
2679 canonicalize: true,
2680 }, {
2681 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/NonEmptyWithOthers"),
2682 in: structEmbedMapStringAny{
2683 A: 1,
2684 X: jsonObject{"fizz": nil},
2685 B: 2,
2686 },
2687
2688 want: `{"A":1,"B":2,"fizz":null}`,
2689 }, {
2690 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/RejectInvalidUTF8"),
2691 opts: []Options{jsontext.AllowInvalidUTF8(false)},
2692 in: structEmbedMapStringAny{X: jsonObject{"\xde\xad\xbe\xef": nil}},
2693 want: `{`,
2694 wantErr: EM(jsonwire.ErrInvalidUTF8).withPos(`{`, "").withType(0, stringType),
2695 }, {
2696 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/AllowInvalidUTF8"),
2697 opts: []Options{jsontext.AllowInvalidUTF8(true)},
2698 in: structEmbedMapStringAny{X: jsonObject{"\xde\xad\xbe\xef": nil}},
2699 want: `{"ޭ��":null}`,
2700 }, {
2701 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/InvalidValue"),
2702 opts: []Options{jsontext.AllowInvalidUTF8(true)},
2703 in: structEmbedMapStringAny{X: jsonObject{"name": make(chan string)}},
2704 want: `{"name"`,
2705 wantErr: EM(nil).withPos(`{"name":`, "/name").withType(0, T[chan string]()),
2706 }, {
2707 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/Nested/Nil"),
2708 in: structEmbedPointerEmbedMapStringAny{},
2709 want: `{}`,
2710 }, {
2711 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/MarshalFunc"),
2712 opts: []Options{
2713 WithMarshalers(MarshalFunc(func(v float64) ([]byte, error) {
2714 return []byte(fmt.Sprintf(`"%v"`, v)), nil
2715 })),
2716 },
2717 in: structEmbedMapStringAny{X: jsonObject{"fizz": 3.14159}},
2718 want: `{"fizz":"3.14159"}`,
2719 }, {
2720 name: jsontest.Name("Structs/EmbeddedFallback/PointerMapStringAny/Nil"),
2721 in: structEmbedPointerMapStringAny{X: nil},
2722 want: `{}`,
2723 }, {
2724 name: jsontest.Name("Structs/EmbeddedFallback/PointerMapStringAny/NonEmpty"),
2725 in: structEmbedPointerMapStringAny{X: addr(jsonObject{"name": "value"})},
2726 want: `{"name":"value"}`,
2727 }, {
2728 name: jsontest.Name("Structs/EmbeddedFallback/PointerMapStringAny/Nested/Nil"),
2729 in: structEmbedEmbedPointerMapStringAny{},
2730 want: `{}`,
2731 }, {
2732 name: jsontest.Name("Structs/EmbeddedFallback/MapStringInt"),
2733 in: structEmbedMapStringInt{
2734 X: map[string]int{"zero": 0, "one": 1, "two": 2},
2735 },
2736 want: `{"one":1,"two":2,"zero":0}`,
2737 canonicalize: true,
2738 }, {
2739 name: jsontest.Name("Structs/EmbeddedFallback/MapStringInt/Deterministic"),
2740 opts: []Options{Deterministic(true)},
2741 in: structEmbedMapStringInt{
2742 X: map[string]int{"zero": 0, "one": 1, "two": 2},
2743 },
2744 want: `{"one":1,"two":2,"zero":0}`,
2745 }, {
2746 name: jsontest.Name("Structs/EmbeddedFallback/MapStringInt/Deterministic+AllowInvalidUTF8+RejectDuplicateNames"),
2747 opts: []Options{Deterministic(true), jsontext.AllowInvalidUTF8(true), jsontext.AllowDuplicateNames(false)},
2748 in: structEmbedMapStringInt{
2749 X: map[string]int{"\xff": 0, "\xfe": 1},
2750 },
2751 want: `{"�":1`,
2752 wantErr: newDuplicateNameError("", []byte(`"�"`), len64(`{"�":1`)),
2753 }, {
2754 name: jsontest.Name("Structs/EmbeddedFallback/MapStringInt/Deterministic+AllowInvalidUTF8+AllowDuplicateNames"),
2755 opts: []Options{Deterministic(true), jsontext.AllowInvalidUTF8(true), jsontext.AllowDuplicateNames(true)},
2756 in: structEmbedMapStringInt{
2757 X: map[string]int{"\xff": 0, "\xfe": 1},
2758 },
2759 want: `{"�":1,"�":0}`,
2760 }, {
2761 name: jsontest.Name("Structs/EmbeddedFallback/MapStringInt/StringifiedNumbers"),
2762 opts: []Options{StringifyNumbers(true)},
2763 in: structEmbedMapStringInt{
2764 X: map[string]int{"zero": 0, "one": 1, "two": 2},
2765 },
2766 want: `{"one":"1","two":"2","zero":"0"}`,
2767 canonicalize: true,
2768 }, {
2769 name: jsontest.Name("Structs/EmbeddedFallback/MapStringInt/MarshalFunc"),
2770 opts: []Options{
2771 WithMarshalers(JoinMarshalers(
2772
2773 MarshalFunc(func(v string) ([]byte, error) {
2774 return []byte(fmt.Sprintf(`"%q"`, strings.ToUpper(v))), nil
2775 }),
2776 MarshalFunc(func(v int) ([]byte, error) {
2777 return []byte(fmt.Sprintf(`"%v"`, v)), nil
2778 }),
2779 )),
2780 },
2781 in: structEmbedMapStringInt{
2782 X: map[string]int{"zero": 0, "one": 1, "two": 2},
2783 },
2784 want: `{"one":"1","two":"2","zero":"0"}`,
2785 canonicalize: true,
2786 }, {
2787 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringInt"),
2788 in: structEmbedMapNamedStringInt{
2789 X: map[namedString]int{"zero": 0, "one": 1, "two": 2},
2790 },
2791 want: `{"one":1,"two":2,"zero":0}`,
2792 canonicalize: true,
2793 }, {
2794 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringInt/Deterministic"),
2795 opts: []Options{Deterministic(true)},
2796 in: structEmbedMapNamedStringInt{
2797 X: map[namedString]int{"zero": 0, "one": 1, "two": 2},
2798 },
2799 want: `{"one":1,"two":2,"zero":0}`,
2800 }, {
2801 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/Nil"),
2802 in: structEmbedMapNamedStringAny{X: nil},
2803 want: `{}`,
2804 }, {
2805 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/Empty"),
2806 in: structEmbedMapNamedStringAny{X: make(map[namedString]any)},
2807 want: `{}`,
2808 }, {
2809 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/NonEmptyN1"),
2810 in: structEmbedMapNamedStringAny{X: map[namedString]any{"fizz": nil}},
2811 want: `{"fizz":null}`,
2812 }, {
2813 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/NonEmptyN2"),
2814 in: structEmbedMapNamedStringAny{X: map[namedString]any{"fizz": time.Time{}, "buzz": math.Pi}},
2815 want: `{"buzz":3.141592653589793,"fizz":"0001-01-01T00:00:00Z"}`,
2816 canonicalize: true,
2817 }, {
2818 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/NonEmptyWithOthers"),
2819 in: structEmbedMapNamedStringAny{
2820 A: 1,
2821 X: map[namedString]any{"fizz": nil},
2822 B: 2,
2823 },
2824
2825 want: `{"A":1,"B":2,"fizz":null}`,
2826 }, {
2827 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/RejectInvalidUTF8"),
2828 opts: []Options{jsontext.AllowInvalidUTF8(false)},
2829 in: structEmbedMapNamedStringAny{X: map[namedString]any{"\xde\xad\xbe\xef": nil}},
2830 want: `{`,
2831 wantErr: EM(jsonwire.ErrInvalidUTF8).withPos(`{`, "").withType(0, T[namedString]()),
2832 }, {
2833 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/AllowInvalidUTF8"),
2834 opts: []Options{jsontext.AllowInvalidUTF8(true)},
2835 in: structEmbedMapNamedStringAny{X: map[namedString]any{"\xde\xad\xbe\xef": nil}},
2836 want: `{"ޭ��":null}`,
2837 }, {
2838 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/InvalidValue"),
2839 opts: []Options{jsontext.AllowInvalidUTF8(true)},
2840 in: structEmbedMapNamedStringAny{X: map[namedString]any{"name": make(chan string)}},
2841 want: `{"name"`,
2842 wantErr: EM(nil).withPos(`{"name":`, "/name").withType(0, T[chan string]()),
2843 }, {
2844 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/MarshalFunc"),
2845 opts: []Options{
2846 WithMarshalers(MarshalFunc(func(v float64) ([]byte, error) {
2847 return []byte(fmt.Sprintf(`"%v"`, v)), nil
2848 })),
2849 },
2850 in: structEmbedMapNamedStringAny{X: map[namedString]any{"fizz": 3.14159}},
2851 want: `{"fizz":"3.14159"}`,
2852 }, {
2853 name: jsontest.Name("Structs/DuplicateName/NoCaseEmbedTextValue/Other"),
2854 in: structNoCaseEmbedTextValue{
2855 X: jsontext.Value(`{"dupe":"","dupe":""}`),
2856 },
2857 want: `{"dupe":""`,
2858 wantErr: newDuplicateNameError("", []byte(`"dupe"`), len64(`{"dupe":""`)),
2859 }, {
2860 name: jsontest.Name("Structs/DuplicateName/NoCaseEmbedTextValue/Other/AllowDuplicateNames"),
2861 opts: []Options{jsontext.AllowDuplicateNames(true)},
2862 in: structNoCaseEmbedTextValue{
2863 X: jsontext.Value(`{"dupe": "", "dupe": ""}`),
2864 },
2865 want: `{"dupe":"","dupe":""}`,
2866 }, {
2867 name: jsontest.Name("Structs/DuplicateName/NoCaseEmbedTextValue/ExactDifferent"),
2868 in: structNoCaseEmbedTextValue{
2869 X: jsontext.Value(`{"Aaa": "", "AaA": "", "AAa": "", "AAA": ""}`),
2870 },
2871 want: `{"Aaa":"","AaA":"","AAa":"","AAA":""}`,
2872 }, {
2873 name: jsontest.Name("Structs/DuplicateName/NoCaseEmbedTextValue/ExactConflict"),
2874 in: structNoCaseEmbedTextValue{
2875 X: jsontext.Value(`{"Aaa": "", "Aaa": ""}`),
2876 },
2877 want: `{"Aaa":""`,
2878 wantErr: newDuplicateNameError("", []byte(`"Aaa"`), len64(`{"Aaa":""`)),
2879 }, {
2880 name: jsontest.Name("Structs/DuplicateName/NoCaseEmbedTextValue/ExactConflict/AllowDuplicateNames"),
2881 opts: []Options{jsontext.AllowDuplicateNames(true)},
2882 in: structNoCaseEmbedTextValue{
2883 X: jsontext.Value(`{"Aaa": "", "Aaa": ""}`),
2884 },
2885 want: `{"Aaa":"","Aaa":""}`,
2886 }, {
2887 name: jsontest.Name("Structs/DuplicateName/NoCaseEmbedTextValue/NoCaseConflict"),
2888 in: structNoCaseEmbedTextValue{
2889 X: jsontext.Value(`{"Aaa": "", "AaA": "", "aaa": ""}`),
2890 },
2891 want: `{"Aaa":"","AaA":""`,
2892 wantErr: newDuplicateNameError("", []byte(`"aaa"`), len64(`{"Aaa":"","AaA":""`)),
2893 }, {
2894 name: jsontest.Name("Structs/DuplicateName/NoCaseEmbedTextValue/NoCaseConflict/AllowDuplicateNames"),
2895 opts: []Options{jsontext.AllowDuplicateNames(true)},
2896 in: structNoCaseEmbedTextValue{
2897 X: jsontext.Value(`{"Aaa": "", "AaA": "", "aaa": ""}`),
2898 },
2899 want: `{"Aaa":"","AaA":"","aaa":""}`,
2900 }, {
2901 name: jsontest.Name("Structs/DuplicateName/NoCaseEmbedTextValue/ExactDifferentWithField"),
2902 in: structNoCaseEmbedTextValue{
2903 AAA: "x",
2904 AaA: "x",
2905 X: jsontext.Value(`{"Aaa": ""}`),
2906 },
2907 want: `{"AAA":"x","AaA":"x","Aaa":""}`,
2908 }, {
2909 name: jsontest.Name("Structs/DuplicateName/NoCaseEmbedTextValue/ExactConflictWithField"),
2910 in: structNoCaseEmbedTextValue{
2911 AAA: "x",
2912 AaA: "x",
2913 X: jsontext.Value(`{"AAA": ""}`),
2914 },
2915 want: `{"AAA":"x","AaA":"x"`,
2916 wantErr: newDuplicateNameError("", []byte(`"AAA"`), len64(`{"AAA":"x","AaA":"x"`)),
2917 }, {
2918 name: jsontest.Name("Structs/DuplicateName/NoCaseEmbedTextValue/NoCaseConflictWithField"),
2919 in: structNoCaseEmbedTextValue{
2920 AAA: "x",
2921 AaA: "x",
2922 X: jsontext.Value(`{"aaa": ""}`),
2923 },
2924 want: `{"AAA":"x","AaA":"x"`,
2925 wantErr: newDuplicateNameError("", []byte(`"aaa"`), len64(`{"AAA":"x","AaA":"x"`)),
2926 }, {
2927 name: jsontest.Name("Structs/DuplicateName/MatchCaseInsensitiveDelimiter"),
2928 in: structNoCaseEmbedTextValue{
2929 AaA: "x",
2930 X: jsontext.Value(`{"aa_a": ""}`),
2931 },
2932 want: `{"AaA":"x"`,
2933 wantErr: newDuplicateNameError("", []byte(`"aa_a"`), len64(`{"AaA":"x"`)),
2934 }, {
2935 name: jsontest.Name("Structs/DuplicateName/MatchCaseSensitiveDelimiter"),
2936 opts: []Options{jsonflags.MatchCaseSensitiveDelimiter | 1},
2937 in: structNoCaseEmbedTextValue{
2938 AaA: "x",
2939 X: jsontext.Value(`{"aa_a": ""}`),
2940 },
2941 want: `{"AaA":"x","aa_a":""}`,
2942 }, {
2943 name: jsontest.Name("Structs/DuplicateName/MatchCaseInsensitiveNames+MatchCaseSensitiveDelimiter"),
2944 opts: []Options{MatchCaseInsensitiveNames(true), jsonflags.MatchCaseSensitiveDelimiter | 1},
2945 in: structNoCaseEmbedTextValue{
2946 AaA: "x",
2947 X: jsontext.Value(`{"aa_a": ""}`),
2948 },
2949 want: `{"AaA":"x","aa_a":""}`,
2950 }, {
2951 name: jsontest.Name("Structs/DuplicateName/MatchCaseInsensitiveNames+MatchCaseSensitiveDelimiter"),
2952 opts: []Options{MatchCaseInsensitiveNames(true), jsonflags.MatchCaseSensitiveDelimiter | 1},
2953 in: structNoCaseEmbedTextValue{
2954 AA_b: "x",
2955 X: jsontext.Value(`{"aa_b": ""}`),
2956 },
2957 want: `{"AA_b":"x"`,
2958 wantErr: newDuplicateNameError("", []byte(`"aa_b"`), len64(`{"AA_b":"x"`)),
2959 }, {
2960 name: jsontest.Name("Structs/DuplicateName/NoCaseEmbedMapStringAny/ExactDifferent"),
2961 in: structNoCaseEmbedMapStringAny{
2962 X: jsonObject{"Aaa": "", "AaA": "", "AAa": "", "AAA": ""},
2963 },
2964 want: `{"AAA":"","AAa":"","AaA":"","Aaa":""}`,
2965 canonicalize: true,
2966 }, {
2967 name: jsontest.Name("Structs/DuplicateName/NoCaseEmbedMapStringAny/ExactDifferentWithField"),
2968 in: structNoCaseEmbedMapStringAny{
2969 AAA: "x",
2970 AaA: "x",
2971 X: jsonObject{"Aaa": ""},
2972 },
2973 want: `{"AAA":"x","AaA":"x","Aaa":""}`,
2974 }, {
2975 name: jsontest.Name("Structs/DuplicateName/NoCaseEmbedMapStringAny/ExactConflictWithField"),
2976 in: structNoCaseEmbedMapStringAny{
2977 AAA: "x",
2978 AaA: "x",
2979 X: jsonObject{"AAA": ""},
2980 },
2981 want: `{"AAA":"x","AaA":"x"`,
2982 wantErr: newDuplicateNameError("", []byte(`"AAA"`), len64(`{"AAA":"x","AaA":"x"`)),
2983 }, {
2984 name: jsontest.Name("Structs/DuplicateName/NoCaseEmbedMapStringAny/NoCaseConflictWithField"),
2985 in: structNoCaseEmbedMapStringAny{
2986 AAA: "x",
2987 AaA: "x",
2988 X: jsonObject{"aaa": ""},
2989 },
2990 want: `{"AAA":"x","AaA":"x"`,
2991 wantErr: newDuplicateNameError("", []byte(`"aaa"`), len64(`{"AAA":"x","AaA":"x"`)),
2992 }, {
2993 name: jsontest.Name("Structs/Invalid/Conflicting"),
2994 in: structConflicting{},
2995 want: ``,
2996 wantErr: EM(errors.New("Go struct fields A and B conflict over JSON object name \"conflict\"")).withType(0, T[structConflicting]()),
2997 }, {
2998 name: jsontest.Name("Structs/Invalid/NoneExported"),
2999 in: structNoneExported{},
3000 want: ``,
3001 wantErr: EM(errNoExportedFields).withType(0, T[structNoneExported]()),
3002 }, {
3003 name: jsontest.Name("Structs/Invalid/MalformedTag"),
3004 in: structMalformedTag{},
3005 want: ``,
3006 wantErr: EM(errors.New("Go struct field Malformed has malformed `json` tag: invalid character '\"' at start of option (expecting Unicode letter)")).withType(0, T[structMalformedTag]()),
3007 }, {
3008 name: jsontest.Name("Structs/Invalid/UnexportedTag"),
3009 in: structUnexportedTag{},
3010 want: ``,
3011 wantErr: EM(errors.New("unexported Go struct field unexported cannot have non-ignored `json:\"name\"` tag")).withType(0, T[structUnexportedTag]()),
3012 }, {
3013 name: jsontest.Name("Structs/Invalid/ExportedEmbedded"),
3014 in: structExportedEmbedded{"hello"},
3015 want: ``,
3016 wantErr: EM(errors.New("embedded Go struct field NamedString of non-struct type must be explicitly given a JSON name")).withType(0, T[structExportedEmbedded]()),
3017 }, {
3018 name: jsontest.Name("Structs/Valid/ExportedEmbedded"),
3019 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
3020 in: structExportedEmbedded{"hello"},
3021 want: `{"NamedString":"hello"}`,
3022 }, {
3023 name: jsontest.Name("Structs/Valid/ExportedEmbeddedTag"),
3024 in: structExportedEmbeddedTag{"hello"},
3025 want: `{"name":"hello"}`,
3026 }, {
3027 name: jsontest.Name("Structs/Invalid/UnexportedEmbedded"),
3028 in: structUnexportedEmbedded{},
3029 want: ``,
3030 wantErr: EM(errors.New("embedded Go struct field namedString of non-struct type must be explicitly given a JSON name")).withType(0, T[structUnexportedEmbedded]()),
3031 }, {
3032 name: jsontest.Name("Structs/Valid/UnexportedEmbedded"),
3033 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
3034 in: structUnexportedEmbedded{},
3035 want: `{}`,
3036 }, {
3037 name: jsontest.Name("Structs/Invalid/UnexportedEmbeddedTag"),
3038 in: structUnexportedEmbeddedTag{},
3039 wantErr: EM(errors.New("Go struct field namedString is not exported")).withType(0, T[structUnexportedEmbeddedTag]()),
3040 }, {
3041 name: jsontest.Name("Structs/Valid/UnexportedEmbeddedTag"),
3042 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
3043 in: structUnexportedEmbeddedTag{},
3044 want: `{}`,
3045 }, {
3046 name: jsontest.Name("Structs/Invalid/UnexportedEmbeddedMethodTag"),
3047 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
3048 in: structUnexportedEmbeddedMethodTag{},
3049 want: `{}`,
3050 }, {
3051 name: jsontest.Name("Structs/UnexportedEmbeddedStruct/Zero"),
3052 in: structUnexportedEmbeddedStruct{},
3053 want: `{"FizzBuzz":0,"Addr":""}`,
3054 }, {
3055 name: jsontest.Name("Structs/UnexportedEmbeddedStruct/NonZero"),
3056 in: structUnexportedEmbeddedStruct{structOmitZeroAll{Bool: true}, 5, structNestedAddr{netip.AddrFrom4([4]byte{192, 168, 0, 1})}},
3057 want: `{"Bool":true,"FizzBuzz":5,"Addr":"192.168.0.1"}`,
3058 }, {
3059 name: jsontest.Name("Structs/UnexportedEmbeddedStructPointer/Nil"),
3060 in: structUnexportedEmbeddedStructPointer{},
3061 want: `{"FizzBuzz":0}`,
3062 }, {
3063 name: jsontest.Name("Structs/UnexportedEmbeddedStructPointer/Zero"),
3064 in: structUnexportedEmbeddedStructPointer{&structOmitZeroAll{}, 0, &structNestedAddr{}},
3065 want: `{"FizzBuzz":0,"Addr":""}`,
3066 }, {
3067 name: jsontest.Name("Structs/UnexportedEmbeddedStructPointer/NonZero"),
3068 in: structUnexportedEmbeddedStructPointer{&structOmitZeroAll{Bool: true}, 5, &structNestedAddr{netip.AddrFrom4([4]byte{192, 168, 0, 1})}},
3069 want: `{"Bool":true,"FizzBuzz":5,"Addr":"192.168.0.1"}`,
3070 }, {
3071 name: jsontest.Name("Structs/IgnoreInvalidFormat"),
3072 opts: []Options{invalidFormatOption},
3073 in: struct{}{},
3074 want: `{}`,
3075 }, {
3076 name: jsontest.Name("Slices/Interface"),
3077 in: []any{
3078 false, true,
3079 "hello", []byte("world"),
3080 int32(-32), namedInt64(-64),
3081 uint32(+32), namedUint64(+64),
3082 float32(32.32), namedFloat64(64.64),
3083 },
3084 want: `[false,true,"hello","d29ybGQ=",-32,-64,32,64,32.32,64.64]`,
3085 }, {
3086 name: jsontest.Name("Slices/Invalid/Channel"),
3087 in: [](chan string){nil},
3088 want: `[`,
3089 wantErr: EM(nil).withPos(`[`, "/0").withType(0, T[chan string]()),
3090 }, {
3091 name: jsontest.Name("Slices/RecursiveSlice"),
3092 in: recursiveSlice{
3093 nil,
3094 {},
3095 {nil},
3096 {nil, {}},
3097 },
3098 want: `[[],[],[[]],[[],[]]]`,
3099 }, {
3100 name: jsontest.Name("Slices/CyclicSlice"),
3101 in: func() recursiveSlice {
3102 s := recursiveSlice{{}}
3103 s[0] = s
3104 return s
3105 }(),
3106 want: strings.Repeat(`[`, startDetectingCyclesAfter) + `[`,
3107 wantErr: EM(internal.ErrCycle).withPos(strings.Repeat("[", startDetectingCyclesAfter+1), jsontext.Pointer(strings.Repeat("/0", startDetectingCyclesAfter+1))).withType(0, T[recursiveSlice]()),
3108 }, {
3109 name: jsontest.Name("Slices/NonCyclicSlice"),
3110 in: func() []any {
3111 v := []any{nil, nil}
3112 v[1] = v[:1]
3113 for i := 1000; i > 0; i-- {
3114 v = []any{v}
3115 }
3116 return v
3117 }(),
3118 want: strings.Repeat(`[`, startDetectingCyclesAfter) + `[null,[null]]` + strings.Repeat(`]`, startDetectingCyclesAfter),
3119 }, {
3120 name: jsontest.Name("Slices/IgnoreInvalidFormat"),
3121 opts: []Options{invalidFormatOption},
3122 in: []string{"hello", "goodbye"},
3123 want: `["hello","goodbye"]`,
3124 }, {
3125 name: jsontest.Name("Arrays/Empty"),
3126 in: [0]struct{}{},
3127 want: `[]`,
3128 }, {
3129 name: jsontest.Name("Arrays/Bool"),
3130 in: [2]bool{false, true},
3131 want: `[false,true]`,
3132 }, {
3133 name: jsontest.Name("Arrays/String"),
3134 in: [2]string{"hello", "goodbye"},
3135 want: `["hello","goodbye"]`,
3136 }, {
3137 name: jsontest.Name("Arrays/Bytes"),
3138 in: [2][]byte{[]byte("hello"), []byte("goodbye")},
3139 want: `["aGVsbG8=","Z29vZGJ5ZQ=="]`,
3140 }, {
3141 name: jsontest.Name("Arrays/Int"),
3142 in: [2]int64{math.MinInt64, math.MaxInt64},
3143 want: `[-9223372036854775808,9223372036854775807]`,
3144 }, {
3145 name: jsontest.Name("Arrays/Uint"),
3146 in: [2]uint64{0, math.MaxUint64},
3147 want: `[0,18446744073709551615]`,
3148 }, {
3149 name: jsontest.Name("Arrays/Float"),
3150 in: [2]float64{-math.MaxFloat64, +math.MaxFloat64},
3151 want: `[-1.7976931348623157e+308,1.7976931348623157e+308]`,
3152 }, {
3153 name: jsontest.Name("Arrays/Invalid/Channel"),
3154 in: new([1]chan string),
3155 want: `[`,
3156 wantErr: EM(nil).withPos(`[`, "/0").withType(0, T[chan string]()),
3157 }, {
3158 name: jsontest.Name("Arrays/IgnoreInvalidFormat"),
3159 opts: []Options{invalidFormatOption},
3160 in: [2]string{"hello", "goodbye"},
3161 want: `["hello","goodbye"]`,
3162 }, {
3163 name: jsontest.Name("Pointers/NilL0"),
3164 in: (*int)(nil),
3165 want: `null`,
3166 }, {
3167 name: jsontest.Name("Pointers/NilL1"),
3168 in: new(*int),
3169 want: `null`,
3170 }, {
3171 name: jsontest.Name("Pointers/Bool"),
3172 in: addr(addr(bool(true))),
3173 want: `true`,
3174 }, {
3175 name: jsontest.Name("Pointers/String"),
3176 in: addr(addr(string("string"))),
3177 want: `"string"`,
3178 }, {
3179 name: jsontest.Name("Pointers/Bytes"),
3180 in: addr(addr([]byte("bytes"))),
3181 want: `"Ynl0ZXM="`,
3182 }, {
3183 name: jsontest.Name("Pointers/Int"),
3184 in: addr(addr(int(-100))),
3185 want: `-100`,
3186 }, {
3187 name: jsontest.Name("Pointers/Uint"),
3188 in: addr(addr(uint(100))),
3189 want: `100`,
3190 }, {
3191 name: jsontest.Name("Pointers/Float"),
3192 in: addr(addr(float64(3.14159))),
3193 want: `3.14159`,
3194 }, {
3195 name: jsontest.Name("Pointers/CyclicPointer"),
3196 in: func() *recursivePointer {
3197 p := new(recursivePointer)
3198 p.P = p
3199 return p
3200 }(),
3201 want: strings.Repeat(`{"P":`, startDetectingCyclesAfter) + `{"P"`,
3202 wantErr: EM(internal.ErrCycle).withPos(strings.Repeat(`{"P":`, startDetectingCyclesAfter+1), jsontext.Pointer(strings.Repeat("/P", startDetectingCyclesAfter+1))).withType(0, T[*recursivePointer]()),
3203 }, {
3204 name: jsontest.Name("Pointers/IgnoreInvalidFormat"),
3205 opts: []Options{invalidFormatOption},
3206 in: addr(addr(bool(true))),
3207 want: `true`,
3208 }, {
3209 name: jsontest.Name("Interfaces/Nil/Empty"),
3210 in: [1]any{nil},
3211 want: `[null]`,
3212 }, {
3213 name: jsontest.Name("Interfaces/Nil/NonEmpty"),
3214 in: [1]io.Reader{nil},
3215 want: `[null]`,
3216 }, {
3217 name: jsontest.Name("Interfaces/IgnoreInvalidFormat"),
3218 opts: []Options{invalidFormatOption},
3219 in: [1]io.Reader{nil},
3220 want: `[null]`,
3221 }, {
3222 name: jsontest.Name("Interfaces/Any"),
3223 in: struct{ X any }{[]any{nil, false, "", 0.0, map[string]any{}, []any{}, [8]byte{}}},
3224 want: `{"X":[null,false,"",0,{},[],"AAAAAAAAAAA="]}`,
3225 }, {
3226 name: jsontest.Name("Interfaces/Any/Named"),
3227 in: struct{ X namedAny }{[]namedAny{nil, false, "", 0.0, map[string]namedAny{}, []namedAny{}, [8]byte{}}},
3228 want: `{"X":[null,false,"",0,{},[],"AAAAAAAAAAA="]}`,
3229 }, {
3230 name: jsontest.Name("Interfaces/Any/Stringified"),
3231 opts: []Options{StringifyNumbers(true)},
3232 in: struct{ X any }{0.0},
3233 want: `{"X":"0"}`,
3234 }, {
3235 name: jsontest.Name("Interfaces/Any/MarshalFunc/Any"),
3236 opts: []Options{
3237 WithMarshalers(MarshalFunc(func(v any) ([]byte, error) {
3238 return []byte(`"called"`), nil
3239 })),
3240 },
3241 in: struct{ X any }{[]any{nil, false, "", 0.0, map[string]any{}, []any{}}},
3242 want: `"called"`,
3243 }, {
3244 name: jsontest.Name("Interfaces/Any/MarshalFunc/Bool"),
3245 opts: []Options{
3246 WithMarshalers(MarshalFunc(func(v bool) ([]byte, error) {
3247 return []byte(`"called"`), nil
3248 })),
3249 },
3250 in: struct{ X any }{[]any{nil, false, "", 0.0, map[string]any{}, []any{}}},
3251 want: `{"X":[null,"called","",0,{},[]]}`,
3252 }, {
3253 name: jsontest.Name("Interfaces/Any/MarshalFunc/String"),
3254 opts: []Options{
3255 WithMarshalers(MarshalFunc(func(v string) ([]byte, error) {
3256 return []byte(`"called"`), nil
3257 })),
3258 },
3259 in: struct{ X any }{[]any{nil, false, "", 0.0, map[string]any{}, []any{}}},
3260 want: `{"X":[null,false,"called",0,{},[]]}`,
3261 }, {
3262 name: jsontest.Name("Interfaces/Any/MarshalFunc/Float64"),
3263 opts: []Options{
3264 WithMarshalers(MarshalFunc(func(v float64) ([]byte, error) {
3265 return []byte(`"called"`), nil
3266 })),
3267 },
3268 in: struct{ X any }{[]any{nil, false, "", 0.0, map[string]any{}, []any{}}},
3269 want: `{"X":[null,false,"","called",{},[]]}`,
3270 }, {
3271 name: jsontest.Name("Interfaces/Any/MarshalFunc/MapStringAny"),
3272 opts: []Options{
3273 WithMarshalers(MarshalFunc(func(v map[string]any) ([]byte, error) {
3274 return []byte(`"called"`), nil
3275 })),
3276 },
3277 in: struct{ X any }{[]any{nil, false, "", 0.0, map[string]any{}, []any{}}},
3278 want: `{"X":[null,false,"",0,"called",[]]}`,
3279 }, {
3280 name: jsontest.Name("Interfaces/Any/MarshalFunc/SliceAny"),
3281 opts: []Options{
3282 WithMarshalers(MarshalFunc(func(v []any) ([]byte, error) {
3283 return []byte(`"called"`), nil
3284 })),
3285 },
3286 in: struct{ X any }{[]any{nil, false, "", 0.0, map[string]any{}, []any{}}},
3287 want: `{"X":"called"}`,
3288 }, {
3289 name: jsontest.Name("Interfaces/Any/MarshalFunc/Bytes"),
3290 opts: []Options{
3291 WithMarshalers(MarshalFunc(func(v [8]byte) ([]byte, error) {
3292 return []byte(`"called"`), nil
3293 })),
3294 },
3295 in: struct{ X any }{[8]byte{}},
3296 want: `{"X":"called"}`,
3297 }, {
3298 name: jsontest.Name("Interfaces/Any/Float/NaN"),
3299 in: struct{ X any }{math.NaN()},
3300 want: `{"X"`,
3301 wantErr: EM(fmt.Errorf("unsupported value: %v", math.NaN())).withType(0, reflect.TypeFor[float64]()).withPos(`{"X":`, "/X"),
3302 }, {
3303 name: jsontest.Name("Interfaces/Any/Maps/Nil"),
3304 in: struct{ X any }{map[string]any(nil)},
3305 want: `{"X":{}}`,
3306 }, {
3307 name: jsontest.Name("Interfaces/Any/Maps/Nil/FormatNilMapAsNull"),
3308 opts: []Options{FormatNilMapAsNull(true)},
3309 in: struct{ X any }{map[string]any(nil)},
3310 want: `{"X":null}`,
3311 }, {
3312 name: jsontest.Name("Interfaces/Any/Maps/Empty"),
3313 in: struct{ X any }{map[string]any{}},
3314 want: `{"X":{}}`,
3315 }, {
3316 name: jsontest.Name("Interfaces/Any/Maps/Empty/Multiline"),
3317 opts: []Options{jsontext.Multiline(true), jsontext.WithIndent("")},
3318 in: struct{ X any }{map[string]any{}},
3319 want: "{\n\"X\": {}\n}",
3320 }, {
3321 name: jsontest.Name("Interfaces/Any/Maps/NonEmpty"),
3322 in: struct{ X any }{map[string]any{"fizz": "buzz"}},
3323 want: `{"X":{"fizz":"buzz"}}`,
3324 }, {
3325 name: jsontest.Name("Interfaces/Any/Maps/Deterministic"),
3326 opts: []Options{Deterministic(true)},
3327 in: struct{ X any }{map[string]any{"alpha": "", "bravo": ""}},
3328 want: `{"X":{"alpha":"","bravo":""}}`,
3329 }, {
3330 name: jsontest.Name("Interfaces/Any/Maps/Deterministic+AllowInvalidUTF8+RejectDuplicateNames"),
3331 opts: []Options{Deterministic(true), jsontext.AllowInvalidUTF8(true), jsontext.AllowDuplicateNames(false)},
3332 in: struct{ X any }{map[string]any{"\xff": "", "\xfe": ""}},
3333 want: `{"X":{"�":""`,
3334 wantErr: newDuplicateNameError("/X", []byte(`"�"`), len64(`{"X":{"�":"",`)),
3335 }, {
3336 name: jsontest.Name("Interfaces/Any/Maps/Deterministic+AllowInvalidUTF8+AllowDuplicateNames"),
3337 opts: []Options{Deterministic(true), jsontext.AllowInvalidUTF8(true), jsontext.AllowDuplicateNames(true)},
3338 in: struct{ X any }{map[string]any{"\xff": "alpha", "\xfe": "bravo"}},
3339 want: `{"X":{"�":"bravo","�":"alpha"}}`,
3340 }, {
3341 name: jsontest.Name("Interfaces/Any/Maps/RejectInvalidUTF8"),
3342 in: struct{ X any }{map[string]any{"\xff": "", "\xfe": ""}},
3343 want: `{"X":{`,
3344 wantErr: newInvalidUTF8Error(len64(`{"X":{`), "/X"),
3345 }, {
3346 name: jsontest.Name("Interfaces/Any/Maps/AllowInvalidUTF8+RejectDuplicateNames"),
3347 opts: []Options{jsontext.AllowInvalidUTF8(true)},
3348 in: struct{ X any }{map[string]any{"\xff": "", "\xfe": ""}},
3349 want: `{"X":{"�":""`,
3350 wantErr: newDuplicateNameError("/X", []byte(`"�"`), len64(`{"X":{"�":"",`)),
3351 }, {
3352 name: jsontest.Name("Interfaces/Any/Maps/AllowInvalidUTF8+AllowDuplicateNames"),
3353 opts: []Options{jsontext.AllowInvalidUTF8(true), jsontext.AllowDuplicateNames(true)},
3354 in: struct{ X any }{map[string]any{"\xff": "", "\xfe": ""}},
3355 want: `{"X":{"�":"","�":""}}`,
3356 }, {
3357 name: jsontest.Name("Interfaces/Any/Maps/Cyclic"),
3358 in: func() any {
3359 m := map[string]any{}
3360 m[""] = m
3361 return struct{ X any }{m}
3362 }(),
3363 want: `{"X"` + strings.Repeat(`:{""`, startDetectingCyclesAfter),
3364 wantErr: EM(internal.ErrCycle).withPos(`{"X":`+strings.Repeat(`{"":`, startDetectingCyclesAfter), "/X"+jsontext.Pointer(strings.Repeat("/", startDetectingCyclesAfter))).withType(0, T[map[string]any]()),
3365 }, {
3366 name: jsontest.Name("Interfaces/Any/Slices/Nil"),
3367 in: struct{ X any }{[]any(nil)},
3368 want: `{"X":[]}`,
3369 }, {
3370 name: jsontest.Name("Interfaces/Any/Slices/Nil/FormatNilSliceAsNull"),
3371 opts: []Options{FormatNilSliceAsNull(true)},
3372 in: struct{ X any }{[]any(nil)},
3373 want: `{"X":null}`,
3374 }, {
3375 name: jsontest.Name("Interfaces/Any/Slices/Empty"),
3376 in: struct{ X any }{[]any{}},
3377 want: `{"X":[]}`,
3378 }, {
3379 name: jsontest.Name("Interfaces/Any/Slices/Empty/Multiline"),
3380 opts: []Options{jsontext.Multiline(true), jsontext.WithIndent("")},
3381 in: struct{ X any }{[]any{}},
3382 want: "{\n\"X\": []\n}",
3383 }, {
3384 name: jsontest.Name("Interfaces/Any/Slices/NonEmpty"),
3385 in: struct{ X any }{[]any{"fizz", "buzz"}},
3386 want: `{"X":["fizz","buzz"]}`,
3387 }, {
3388 name: jsontest.Name("Interfaces/Any/Slices/Cyclic"),
3389 in: func() any {
3390 s := make([]any, 1)
3391 s[0] = s
3392 return struct{ X any }{s}
3393 }(),
3394 want: `{"X":` + strings.Repeat(`[`, startDetectingCyclesAfter),
3395 wantErr: EM(internal.ErrCycle).withPos(`{"X":`+strings.Repeat(`[`, startDetectingCyclesAfter), "/X"+jsontext.Pointer(strings.Repeat("/0", startDetectingCyclesAfter))).withType(0, T[[]any]()),
3396 }, {
3397 name: jsontest.Name("Methods/NilPointer"),
3398 in: struct{ X *allMethods }{X: (*allMethods)(nil)},
3399 want: `{"X":null}`,
3400 }, {
3401
3402 name: jsontest.Name("Methods/NilInterface"),
3403 in: struct{ X MarshalerTo }{X: (*allMethods)(nil)},
3404 want: `{"X":null}`,
3405 }, {
3406 name: jsontest.Name("Methods/AllMethods"),
3407 in: struct{ X *allMethods }{X: &allMethods{method: "MarshalJSONTo", value: []byte(`"hello"`)}},
3408 want: `{"X":"hello"}`,
3409 }, {
3410 name: jsontest.Name("Methods/AllMethodsExceptJSONv2"),
3411 in: struct{ X *allMethodsExceptJSONv2 }{X: &allMethodsExceptJSONv2{allMethods: allMethods{method: "MarshalJSON", value: []byte(`"hello"`)}}},
3412 want: `{"X":"hello"}`,
3413 }, {
3414 name: jsontest.Name("Methods/AllMethodsExceptJSONv1"),
3415 in: struct{ X *allMethodsExceptJSONv1 }{X: &allMethodsExceptJSONv1{allMethods: allMethods{method: "MarshalJSONTo", value: []byte(`"hello"`)}}},
3416 want: `{"X":"hello"}`,
3417 }, {
3418 name: jsontest.Name("Methods/AllMethodsExceptText"),
3419 in: struct{ X *allMethodsExceptText }{X: &allMethodsExceptText{allMethods: allMethods{method: "MarshalJSONTo", value: []byte(`"hello"`)}}},
3420 want: `{"X":"hello"}`,
3421 }, {
3422 name: jsontest.Name("Methods/OnlyMethodJSONv2"),
3423 in: struct{ X *onlyMethodJSONv2 }{X: &onlyMethodJSONv2{allMethods: allMethods{method: "MarshalJSONTo", value: []byte(`"hello"`)}}},
3424 want: `{"X":"hello"}`,
3425 }, {
3426 name: jsontest.Name("Methods/OnlyMethodJSONv1"),
3427 in: struct{ X *onlyMethodJSONv1 }{X: &onlyMethodJSONv1{allMethods: allMethods{method: "MarshalJSON", value: []byte(`"hello"`)}}},
3428 want: `{"X":"hello"}`,
3429 }, {
3430 name: jsontest.Name("Methods/OnlyMethodText"),
3431 in: struct{ X *onlyMethodText }{X: &onlyMethodText{allMethods: allMethods{method: "MarshalText", value: []byte(`hello`)}}},
3432 want: `{"X":"hello"}`,
3433 }, {
3434 name: jsontest.Name("Methods/IP"),
3435 in: net.IPv4(192, 168, 0, 100),
3436 want: `"192.168.0.100"`,
3437 }, {
3438 name: jsontest.Name("Methods/NetIP"),
3439 in: struct {
3440 Addr netip.Addr
3441 AddrPort netip.AddrPort
3442 Prefix netip.Prefix
3443 }{
3444 Addr: netip.AddrFrom4([4]byte{1, 2, 3, 4}),
3445 AddrPort: netip.AddrPortFrom(netip.AddrFrom4([4]byte{1, 2, 3, 4}), 1234),
3446 Prefix: netip.PrefixFrom(netip.AddrFrom4([4]byte{1, 2, 3, 4}), 24),
3447 },
3448 want: `{"Addr":"1.2.3.4","AddrPort":"1.2.3.4:1234","Prefix":"1.2.3.4/24"}`,
3449 }, {
3450
3451 name: jsontest.Name("Methods/Anonymous"),
3452 in: struct{ X struct{ allMethods } }{X: struct{ allMethods }{allMethods{method: "MarshalJSONTo", value: []byte(`"hello"`)}}},
3453 want: `{"X":"hello"}`,
3454 }, {
3455
3456 name: jsontest.Name("Methods/Addressable"),
3457 in: struct {
3458 V allMethods
3459 M map[string]allMethods
3460 I any
3461 }{
3462 V: allMethods{method: "MarshalJSONTo", value: []byte(`"hello"`)},
3463 M: map[string]allMethods{"K": {method: "MarshalJSONTo", value: []byte(`"hello"`)}},
3464 I: allMethods{method: "MarshalJSONTo", value: []byte(`"hello"`)},
3465 },
3466 want: `{"V":"hello","M":{"K":"hello"},"I":"hello"}`,
3467 }, {
3468
3469 name: jsontest.Name("Methods/MapKey/JSONv2"),
3470 in: map[structMethodJSONv2]string{{"k1"}: "v1", {"k2"}: "v2"},
3471 want: `{"k1":"v1","k2":"v2"}`,
3472 canonicalize: true,
3473 }, {
3474
3475 name: jsontest.Name("Methods/MapKey/JSONv1"),
3476 in: map[structMethodJSONv1]string{{"k1"}: "v1", {"k2"}: "v2"},
3477 want: `{"k1":"v1","k2":"v2"}`,
3478 canonicalize: true,
3479 }, {
3480 name: jsontest.Name("Methods/MapKey/Text"),
3481 in: map[structMethodText]string{{"k1"}: "v1", {"k2"}: "v2"},
3482 want: `{"k1":"v1","k2":"v2"}`,
3483 canonicalize: true,
3484 }, {
3485 name: jsontest.Name("Methods/JSONv2/ErrUnsupported"),
3486 opts: []Options{Deterministic(true)},
3487 in: unsupportedMethodJSONv2{"fizz": 123},
3488 want: `{"called":1,"fizz":123}`,
3489 }, {
3490 name: jsontest.Name("Methods/Invalid/JSONv2/Error"),
3491 in: marshalJSONv2Func(func(*jsontext.Encoder) error {
3492 return errSomeError
3493 }),
3494 wantErr: EM(errSomeError).withType(0, T[marshalJSONv2Func]()),
3495 }, {
3496 name: jsontest.Name("Methods/Invalid/JSONv2/TooFew"),
3497 in: marshalJSONv2Func(func(*jsontext.Encoder) error {
3498 return nil
3499 }),
3500 wantErr: EM(errNonSingularValue).withType(0, T[marshalJSONv2Func]()),
3501 }, {
3502 name: jsontest.Name("Methods/Invalid/JSONv2/TooMany"),
3503 in: marshalJSONv2Func(func(enc *jsontext.Encoder) error {
3504 enc.WriteToken(jsontext.Null)
3505 enc.WriteToken(jsontext.Null)
3506 return nil
3507 }),
3508 want: `nullnull`,
3509 wantErr: EM(errNonSingularValue).withPos(`nullnull`, "").withType(0, T[marshalJSONv2Func]()),
3510 }, {
3511 name: jsontest.Name("Methods/Invalid/JSONv2/ErrUnsupported"),
3512 in: marshalJSONv2Func(func(enc *jsontext.Encoder) error {
3513 return errors.ErrUnsupported
3514 }),
3515 wantErr: EM(nil).withType(0, T[marshalJSONv2Func]()),
3516 }, {
3517 name: jsontest.Name("Methods/Invalid/JSONv1/Error"),
3518 in: marshalJSONv1Func(func() ([]byte, error) {
3519 return nil, errSomeError
3520 }),
3521 wantErr: EM(errSomeError).withType(0, T[marshalJSONv1Func]()),
3522 }, {
3523 name: jsontest.Name("Methods/Invalid/JSONv1/Syntax"),
3524 in: marshalJSONv1Func(func() ([]byte, error) {
3525 return []byte("invalid"), nil
3526 }),
3527 wantErr: EM(newInvalidCharacterError("i", "at start of value", 0, "")).withType(0, T[marshalJSONv1Func]()),
3528 }, {
3529 name: jsontest.Name("Methods/Invalid/JSONv1/ErrUnsupported"),
3530 in: marshalJSONv1Func(func() ([]byte, error) {
3531 return nil, errors.ErrUnsupported
3532 }),
3533 wantErr: EM(errors.New("MarshalJSON method may not return errors.ErrUnsupported")).withType(0, T[marshalJSONv1Func]()),
3534 }, {
3535 name: jsontest.Name("Methods/AppendText"),
3536 in: appendTextFunc(func(b []byte) ([]byte, error) { return append(b, "hello"...), nil }),
3537 want: `"hello"`,
3538 }, {
3539 name: jsontest.Name("Methods/AppendText/Error"),
3540 in: appendTextFunc(func(b []byte) ([]byte, error) { return append(b, "hello"...), errSomeError }),
3541 wantErr: EM(errSomeError).withType(0, T[appendTextFunc]()),
3542 }, {
3543 name: jsontest.Name("Methods/AppendText/NeedEscape"),
3544 in: appendTextFunc(func(b []byte) ([]byte, error) { return append(b, `"`...), nil }),
3545 want: `"\""`,
3546 }, {
3547 name: jsontest.Name("Methods/AppendText/RejectInvalidUTF8"),
3548 in: appendTextFunc(func(b []byte) ([]byte, error) { return append(b, "\xde\xad\xbe\xef"...), nil }),
3549 wantErr: EM(newInvalidUTF8Error(0, "")).withType(0, T[appendTextFunc]()),
3550 }, {
3551 name: jsontest.Name("Methods/AppendText/AllowInvalidUTF8"),
3552 opts: []Options{jsontext.AllowInvalidUTF8(true)},
3553 in: appendTextFunc(func(b []byte) ([]byte, error) { return append(b, "\xde\xad\xbe\xef"...), nil }),
3554 want: "\"\xde\xad\ufffd\ufffd\"",
3555 }, {
3556 name: jsontest.Name("Methods/Invalid/Text/Error"),
3557 in: marshalTextFunc(func() ([]byte, error) {
3558 return nil, errSomeError
3559 }),
3560 wantErr: EM(errSomeError).withType(0, T[marshalTextFunc]()),
3561 }, {
3562 name: jsontest.Name("Methods/Text/RejectInvalidUTF8"),
3563 in: marshalTextFunc(func() ([]byte, error) {
3564 return []byte("\xde\xad\xbe\xef"), nil
3565 }),
3566 wantErr: EM(newInvalidUTF8Error(0, "")).withType(0, T[marshalTextFunc]()),
3567 }, {
3568 name: jsontest.Name("Methods/Text/AllowInvalidUTF8"),
3569 opts: []Options{jsontext.AllowInvalidUTF8(true)},
3570 in: marshalTextFunc(func() ([]byte, error) {
3571 return []byte("\xde\xad\xbe\xef"), nil
3572 }),
3573 want: "\"\xde\xad\ufffd\ufffd\"",
3574 }, {
3575 name: jsontest.Name("Methods/Invalid/Text/ErrUnsupported"),
3576 in: marshalTextFunc(func() ([]byte, error) {
3577 return nil, errors.ErrUnsupported
3578 }),
3579 wantErr: EM(wrapErrUnsupported(errors.ErrUnsupported, "MarshalText method")).withType(0, T[marshalTextFunc]()),
3580 }, {
3581 name: jsontest.Name("Methods/Invalid/MapKey/JSONv2/Syntax"),
3582 in: map[any]string{
3583 addr(marshalJSONv2Func(func(enc *jsontext.Encoder) error {
3584 return enc.WriteToken(jsontext.Null)
3585 })): "invalid",
3586 },
3587 want: `{`,
3588 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[marshalJSONv2Func]()),
3589 }, {
3590 name: jsontest.Name("Methods/Invalid/MapKey/JSONv1/Syntax"),
3591 in: map[any]string{
3592 addr(marshalJSONv1Func(func() ([]byte, error) {
3593 return []byte(`null`), nil
3594 })): "invalid",
3595 },
3596 want: `{`,
3597 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[marshalJSONv1Func]()),
3598 }, {
3599 name: jsontest.Name("Functions/Bool/V1"),
3600 opts: []Options{
3601 WithMarshalers(MarshalFunc(func(bool) ([]byte, error) {
3602 return []byte(`"called"`), nil
3603 })),
3604 },
3605 in: true,
3606 want: `"called"`,
3607 }, {
3608 name: jsontest.Name("Functions/Bool/Empty"),
3609 opts: []Options{WithMarshalers(nil)},
3610 in: true,
3611 want: `true`,
3612 }, {
3613 name: jsontest.Name("Functions/NamedBool/V1/NoMatch"),
3614 opts: []Options{
3615 WithMarshalers(MarshalFunc(func(namedBool) ([]byte, error) {
3616 return nil, errMustNotCall
3617 })),
3618 },
3619 in: true,
3620 want: `true`,
3621 }, {
3622 name: jsontest.Name("Functions/NamedBool/V1/Match"),
3623 opts: []Options{
3624 WithMarshalers(MarshalFunc(func(namedBool) ([]byte, error) {
3625 return []byte(`"called"`), nil
3626 })),
3627 },
3628 in: namedBool(true),
3629 want: `"called"`,
3630 }, {
3631 name: jsontest.Name("Functions/PointerBool/V1/Match"),
3632 opts: []Options{
3633 WithMarshalers(MarshalFunc(func(v *bool) ([]byte, error) {
3634 _ = *v
3635 return []byte(`"called"`), nil
3636 })),
3637 },
3638 in: true,
3639 want: `"called"`,
3640 }, {
3641 name: jsontest.Name("Functions/Bool/V2"),
3642 opts: []Options{
3643 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
3644 return enc.WriteToken(jsontext.String("called"))
3645 })),
3646 },
3647 in: true,
3648 want: `"called"`,
3649 }, {
3650 name: jsontest.Name("Functions/NamedBool/V2/NoMatch"),
3651 opts: []Options{
3652 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v namedBool) error {
3653 return errMustNotCall
3654 })),
3655 },
3656 in: true,
3657 want: `true`,
3658 }, {
3659 name: jsontest.Name("Functions/NamedBool/V2/Match"),
3660 opts: []Options{
3661 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v namedBool) error {
3662 return enc.WriteToken(jsontext.String("called"))
3663 })),
3664 },
3665 in: namedBool(true),
3666 want: `"called"`,
3667 }, {
3668 name: jsontest.Name("Functions/PointerBool/V2/Match"),
3669 opts: []Options{
3670 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v *bool) error {
3671 _ = *v
3672 return enc.WriteToken(jsontext.String("called"))
3673 })),
3674 },
3675 in: true,
3676 want: `"called"`,
3677 }, {
3678 name: jsontest.Name("Functions/Bool/Empty1/NoMatch"),
3679 opts: []Options{
3680 WithMarshalers(new(Marshalers)),
3681 },
3682 in: true,
3683 want: `true`,
3684 }, {
3685 name: jsontest.Name("Functions/Bool/Empty2/NoMatch"),
3686 opts: []Options{
3687 WithMarshalers(JoinMarshalers()),
3688 },
3689 in: true,
3690 want: `true`,
3691 }, {
3692 name: jsontest.Name("Functions/Bool/V1/DirectError"),
3693 opts: []Options{
3694 WithMarshalers(MarshalFunc(func(bool) ([]byte, error) {
3695 return nil, errSomeError
3696 })),
3697 },
3698 in: true,
3699 wantErr: EM(errSomeError).withType(0, T[bool]()),
3700 }, {
3701 name: jsontest.Name("Functions/Bool/V1/SkipError"),
3702 opts: []Options{
3703 WithMarshalers(MarshalFunc(func(bool) ([]byte, error) {
3704 return nil, errors.ErrUnsupported
3705 })),
3706 },
3707 in: true,
3708 wantErr: EM(wrapErrUnsupported(errors.ErrUnsupported, "marshal function of type func(T) ([]byte, error)")).withType(0, T[bool]()),
3709 }, {
3710 name: jsontest.Name("Functions/Bool/V1/InvalidValue"),
3711 opts: []Options{
3712 WithMarshalers(MarshalFunc(func(bool) ([]byte, error) {
3713 return []byte("invalid"), nil
3714 })),
3715 },
3716 in: true,
3717 wantErr: EM(newInvalidCharacterError("i", "at start of value", 0, "")).withType(0, T[bool]()),
3718 }, {
3719 name: jsontest.Name("Functions/Bool/V2/DirectError"),
3720 opts: []Options{
3721 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
3722 return errSomeError
3723 })),
3724 },
3725 in: true,
3726 wantErr: EM(errSomeError).withType(0, T[bool]()),
3727 }, {
3728 name: jsontest.Name("Functions/Bool/V2/TooFew"),
3729 opts: []Options{
3730 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
3731 return nil
3732 })),
3733 },
3734 in: true,
3735 wantErr: EM(errNonSingularValue).withType(0, T[bool]()),
3736 }, {
3737 name: jsontest.Name("Functions/Bool/V2/TooMany"),
3738 opts: []Options{
3739 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
3740 enc.WriteValue([]byte(`"hello"`))
3741 enc.WriteValue([]byte(`"world"`))
3742 return nil
3743 })),
3744 },
3745 in: true,
3746 want: `"hello""world"`,
3747 wantErr: EM(errNonSingularValue).withPos(`"hello""world"`, "").withType(0, T[bool]()),
3748 }, {
3749 name: jsontest.Name("Functions/Bool/V2/Skipped"),
3750 opts: []Options{
3751 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
3752 return errors.ErrUnsupported
3753 })),
3754 },
3755 in: true,
3756 want: `true`,
3757 }, {
3758 name: jsontest.Name("Functions/Bool/V2/ProcessBeforeSkip"),
3759 opts: []Options{
3760 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
3761 enc.WriteValue([]byte(`"hello"`))
3762 return errors.ErrUnsupported
3763 })),
3764 },
3765 in: true,
3766 want: `"hello"`,
3767 wantErr: EM(errUnsupportedMutation).withPos(`"hello"`, "").withType(0, T[bool]()),
3768 }, {
3769 name: jsontest.Name("Functions/Bool/V2/WrappedUnsupportedError"),
3770 opts: []Options{
3771 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
3772 return fmt.Errorf("wrap: %w", errors.ErrUnsupported)
3773 })),
3774 },
3775 in: true,
3776 want: `true`,
3777 }, {
3778 name: jsontest.Name("Functions/Map/Key/NoCaseString/V1"),
3779 opts: []Options{
3780 WithMarshalers(MarshalFunc(func(v nocaseString) ([]byte, error) {
3781 return []byte(`"called"`), nil
3782 })),
3783 },
3784 in: map[nocaseString]string{"hello": "world"},
3785 want: `{"called":"world"}`,
3786 }, {
3787 name: jsontest.Name("Functions/Map/Key/PointerNoCaseString/V1"),
3788 opts: []Options{
3789 WithMarshalers(MarshalFunc(func(v *nocaseString) ([]byte, error) {
3790 _ = *v
3791 return []byte(`"called"`), nil
3792 })),
3793 },
3794 in: map[nocaseString]string{"hello": "world"},
3795 want: `{"called":"world"}`,
3796 }, {
3797 name: jsontest.Name("Functions/Map/Key/TextMarshaler/V1"),
3798 opts: []Options{
3799 WithMarshalers(MarshalFunc(func(v encoding.TextMarshaler) ([]byte, error) {
3800 _ = *v.(*nocaseString)
3801 return []byte(`"called"`), nil
3802 })),
3803 },
3804 in: map[nocaseString]string{"hello": "world"},
3805 want: `{"called":"world"}`,
3806 }, {
3807 name: jsontest.Name("Functions/Map/Key/NoCaseString/V1/InvalidValue"),
3808 opts: []Options{
3809 WithMarshalers(MarshalFunc(func(v nocaseString) ([]byte, error) {
3810 return []byte(`null`), nil
3811 })),
3812 },
3813 in: map[nocaseString]string{"hello": "world"},
3814 want: `{`,
3815 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[nocaseString]()),
3816 }, {
3817 name: jsontest.Name("Functions/Map/Key/NoCaseString/V2/InvalidKind"),
3818 opts: []Options{
3819 WithMarshalers(MarshalFunc(func(v nocaseString) ([]byte, error) {
3820 return []byte(`null`), nil
3821 })),
3822 },
3823 in: map[nocaseString]string{"hello": "world"},
3824 want: `{`,
3825 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[nocaseString]()),
3826 }, {
3827 name: jsontest.Name("Functions/Map/Key/String/V1/DuplicateName"),
3828 opts: []Options{
3829 WithMarshalers(MarshalFunc(func(v string) ([]byte, error) {
3830 return []byte(`"name"`), nil
3831 })),
3832 },
3833 in: map[string]string{"name1": "value", "name2": "value"},
3834 want: `{"name":"name"`,
3835 wantErr: EM(newDuplicateNameError("", []byte(`"name"`), len64(`{"name":"name",`))).
3836 withPos(`{"name":"name",`, "").withType(0, T[string]()),
3837 }, {
3838 name: jsontest.Name("Functions/Map/Key/NoCaseString/V2"),
3839 opts: []Options{
3840 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v nocaseString) error {
3841 return enc.WriteValue([]byte(`"called"`))
3842 })),
3843 },
3844 in: map[nocaseString]string{"hello": "world"},
3845 want: `{"called":"world"}`,
3846 }, {
3847 name: jsontest.Name("Functions/Map/Key/PointerNoCaseString/V2"),
3848 opts: []Options{
3849 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v *nocaseString) error {
3850 _ = *v
3851 return enc.WriteValue([]byte(`"called"`))
3852 })),
3853 },
3854 in: map[nocaseString]string{"hello": "world"},
3855 want: `{"called":"world"}`,
3856 }, {
3857 name: jsontest.Name("Functions/Map/Key/TextMarshaler/V2"),
3858 opts: []Options{
3859 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v encoding.TextMarshaler) error {
3860 _ = *v.(*nocaseString)
3861 return enc.WriteValue([]byte(`"called"`))
3862 })),
3863 },
3864 in: map[nocaseString]string{"hello": "world"},
3865 want: `{"called":"world"}`,
3866 }, {
3867 name: jsontest.Name("Functions/Map/Key/NoCaseString/V2/InvalidToken"),
3868 opts: []Options{
3869 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v nocaseString) error {
3870 return enc.WriteToken(jsontext.Null)
3871 })),
3872 },
3873 in: map[nocaseString]string{"hello": "world"},
3874 want: `{`,
3875 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[nocaseString]()),
3876 }, {
3877 name: jsontest.Name("Functions/Map/Key/NoCaseString/V2/InvalidValue"),
3878 opts: []Options{
3879 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v nocaseString) error {
3880 return enc.WriteValue([]byte(`null`))
3881 })),
3882 },
3883 in: map[nocaseString]string{"hello": "world"},
3884 want: `{`,
3885 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[nocaseString]()),
3886 }, {
3887 name: jsontest.Name("Functions/Map/Value/NoCaseString/V1"),
3888 opts: []Options{
3889 WithMarshalers(MarshalFunc(func(v nocaseString) ([]byte, error) {
3890 return []byte(`"called"`), nil
3891 })),
3892 },
3893 in: map[string]nocaseString{"hello": "world"},
3894 want: `{"hello":"called"}`,
3895 }, {
3896 name: jsontest.Name("Functions/Map/Value/PointerNoCaseString/V1"),
3897 opts: []Options{
3898 WithMarshalers(MarshalFunc(func(v *nocaseString) ([]byte, error) {
3899 _ = *v
3900 return []byte(`"called"`), nil
3901 })),
3902 },
3903 in: map[string]nocaseString{"hello": "world"},
3904 want: `{"hello":"called"}`,
3905 }, {
3906 name: jsontest.Name("Functions/Map/Value/TextMarshaler/V1"),
3907 opts: []Options{
3908 WithMarshalers(MarshalFunc(func(v encoding.TextMarshaler) ([]byte, error) {
3909 _ = *v.(*nocaseString)
3910 return []byte(`"called"`), nil
3911 })),
3912 },
3913 in: map[string]nocaseString{"hello": "world"},
3914 want: `{"hello":"called"}`,
3915 }, {
3916 name: jsontest.Name("Functions/Map/Value/NoCaseString/V2"),
3917 opts: []Options{
3918 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v nocaseString) error {
3919 return enc.WriteValue([]byte(`"called"`))
3920 })),
3921 },
3922 in: map[string]nocaseString{"hello": "world"},
3923 want: `{"hello":"called"}`,
3924 }, {
3925 name: jsontest.Name("Functions/Map/Value/PointerNoCaseString/V2"),
3926 opts: []Options{
3927 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v *nocaseString) error {
3928 _ = *v
3929 return enc.WriteValue([]byte(`"called"`))
3930 })),
3931 },
3932 in: map[string]nocaseString{"hello": "world"},
3933 want: `{"hello":"called"}`,
3934 }, {
3935 name: jsontest.Name("Functions/Map/Value/TextMarshaler/V2"),
3936 opts: []Options{
3937 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v encoding.TextMarshaler) error {
3938 _ = *v.(*nocaseString)
3939 return enc.WriteValue([]byte(`"called"`))
3940 })),
3941 },
3942 in: map[string]nocaseString{"hello": "world"},
3943 want: `{"hello":"called"}`,
3944 }, {
3945 name: jsontest.Name("Funtions/Struct/Fields"),
3946 opts: []Options{
3947 WithMarshalers(JoinMarshalers(
3948 MarshalFunc(func(v bool) ([]byte, error) {
3949 return []byte(`"called1"`), nil
3950 }),
3951 MarshalFunc(func(v *string) ([]byte, error) {
3952 return []byte(`"called2"`), nil
3953 }),
3954 MarshalToFunc(func(enc *jsontext.Encoder, v []byte) error {
3955 return enc.WriteValue([]byte(`"called3"`))
3956 }),
3957 MarshalToFunc(func(enc *jsontext.Encoder, v *int64) error {
3958 return enc.WriteValue([]byte(`"called4"`))
3959 }),
3960 )),
3961 },
3962 in: structScalars{},
3963 want: `{"Bool":"called1","String":"called2","Bytes":"called3","Int":"called4","Uint":0,"Float":0}`,
3964 }, {
3965 name: jsontest.Name("Functions/Struct/OmitEmpty"),
3966 opts: []Options{
3967 WithMarshalers(JoinMarshalers(
3968 MarshalFunc(func(v bool) ([]byte, error) {
3969 return []byte(`null`), nil
3970 }),
3971 MarshalFunc(func(v string) ([]byte, error) {
3972 return []byte(`"called1"`), nil
3973 }),
3974 MarshalFunc(func(v *stringMarshalNonEmpty) ([]byte, error) {
3975 return []byte(`""`), nil
3976 }),
3977 MarshalToFunc(func(enc *jsontext.Encoder, v bytesMarshalNonEmpty) error {
3978 return enc.WriteValue([]byte(`{}`))
3979 }),
3980 MarshalToFunc(func(enc *jsontext.Encoder, v *float64) error {
3981 return enc.WriteValue([]byte(`[]`))
3982 }),
3983 MarshalFunc(func(v mapMarshalNonEmpty) ([]byte, error) {
3984 return []byte(`"called2"`), nil
3985 }),
3986 MarshalFunc(func(v []string) ([]byte, error) {
3987 return []byte(`"called3"`), nil
3988 }),
3989 MarshalToFunc(func(enc *jsontext.Encoder, v *sliceMarshalNonEmpty) error {
3990 return enc.WriteValue([]byte(`"called4"`))
3991 }),
3992 )),
3993 },
3994 in: structOmitEmptyAll{},
3995 want: `{"String":"called1","MapNonEmpty":"called2","Slice":"called3","SliceNonEmpty":"called4"}`,
3996 }, {
3997 name: jsontest.Name("Functions/Struct/OmitZero"),
3998 opts: []Options{
3999 WithMarshalers(JoinMarshalers(
4000 MarshalFunc(func(v bool) ([]byte, error) {
4001 panic("should not be called")
4002 }),
4003 MarshalFunc(func(v *string) ([]byte, error) {
4004 panic("should not be called")
4005 }),
4006 MarshalToFunc(func(enc *jsontext.Encoder, v []byte) error {
4007 panic("should not be called")
4008 }),
4009 MarshalToFunc(func(enc *jsontext.Encoder, v *int64) error {
4010 panic("should not be called")
4011 }),
4012 )),
4013 },
4014 in: structOmitZeroAll{},
4015 want: `{}`,
4016 }, {
4017 name: jsontest.Name("Functions/Struct/Embedded"),
4018 opts: []Options{
4019 WithMarshalers(JoinMarshalers(
4020 MarshalFunc(func(v structEmbeddedL1) ([]byte, error) {
4021 panic("should not be called")
4022 }),
4023 MarshalToFunc(func(enc *jsontext.Encoder, v *StructEmbed2) error {
4024 panic("should not be called")
4025 }),
4026 )),
4027 },
4028 in: structEmbedded{},
4029 want: `{"D":""}`,
4030 }, {
4031 name: jsontest.Name("Functions/Slice/Elem"),
4032 opts: []Options{
4033 WithMarshalers(MarshalFunc(func(v bool) ([]byte, error) {
4034 return []byte(`"` + strconv.FormatBool(v) + `"`), nil
4035 })),
4036 },
4037 in: []bool{true, false},
4038 want: `["true","false"]`,
4039 }, {
4040 name: jsontest.Name("Functions/Array/Elem"),
4041 opts: []Options{
4042 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v *bool) error {
4043 return enc.WriteValue([]byte(`"` + strconv.FormatBool(*v) + `"`))
4044 })),
4045 },
4046 in: [2]bool{true, false},
4047 want: `["true","false"]`,
4048 }, {
4049 name: jsontest.Name("Functions/Pointer/Nil"),
4050 opts: []Options{
4051 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v *bool) error {
4052 panic("should not be called")
4053 })),
4054 },
4055 in: struct{ X *bool }{nil},
4056 want: `{"X":null}`,
4057 }, {
4058 name: jsontest.Name("Functions/Pointer/NonNil"),
4059 opts: []Options{
4060 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v *bool) error {
4061 return enc.WriteValue([]byte(`"called"`))
4062 })),
4063 },
4064 in: struct{ X *bool }{addr(false)},
4065 want: `{"X":"called"}`,
4066 }, {
4067 name: jsontest.Name("Functions/Interface/Nil"),
4068 opts: []Options{
4069 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v fmt.Stringer) error {
4070 panic("should not be called")
4071 })),
4072 },
4073 in: struct{ X fmt.Stringer }{nil},
4074 want: `{"X":null}`,
4075 }, {
4076 name: jsontest.Name("Functions/Interface/NonNil/MatchInterface"),
4077 opts: []Options{
4078 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v fmt.Stringer) error {
4079 return enc.WriteValue([]byte(`"called"`))
4080 })),
4081 },
4082 in: struct{ X fmt.Stringer }{valueStringer{}},
4083 want: `{"X":"called"}`,
4084 }, {
4085 name: jsontest.Name("Functions/Interface/NonNil/MatchConcrete"),
4086 opts: []Options{
4087 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v valueStringer) error {
4088 return enc.WriteValue([]byte(`"called"`))
4089 })),
4090 },
4091 in: struct{ X fmt.Stringer }{valueStringer{}},
4092 want: `{"X":"called"}`,
4093 }, {
4094 name: jsontest.Name("Functions/Interface/NonNil/MatchPointer"),
4095 opts: []Options{
4096 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v *valueStringer) error {
4097 return enc.WriteValue([]byte(`"called"`))
4098 })),
4099 },
4100 in: struct{ X fmt.Stringer }{valueStringer{}},
4101 want: `{"X":"called"}`,
4102 }, {
4103 name: jsontest.Name("Functions/Interface/Any"),
4104 opts: []Options{
4105 WithMarshalers(func() *Marshalers {
4106 type P struct {
4107 D int
4108 N int64
4109 }
4110 type PV struct {
4111 P P
4112 V any
4113 }
4114
4115 var lastChecks []func() error
4116 checkLast := func() error {
4117 for _, fn := range lastChecks {
4118 if err := fn(); err != nil {
4119 return err
4120 }
4121 }
4122 return errors.ErrUnsupported
4123 }
4124 makeValueChecker := func(name string, want []PV) func(e *jsontext.Encoder, v any) error {
4125 checkNext := func(e *jsontext.Encoder, v any) error {
4126 xe := export.Encoder(e)
4127 p := P{len(xe.Tokens.Stack), xe.Tokens.Last.Length()}
4128 rv := reflect.ValueOf(v)
4129 pv := PV{p, v}
4130 switch {
4131 case len(want) == 0:
4132 return fmt.Errorf("%s: %v: got more values than expected", name, p)
4133 case !rv.IsValid() || rv.Kind() != reflect.Pointer || rv.IsNil():
4134 return fmt.Errorf("%s: %v: got %#v, want non-nil pointer type", name, p, v)
4135 case !reflect.DeepEqual(pv, want[0]):
4136 return fmt.Errorf("%s:\n\tgot %#v\n\twant %#v", name, pv, want[0])
4137 default:
4138 want = want[1:]
4139 return errors.ErrUnsupported
4140 }
4141 }
4142 lastChecks = append(lastChecks, func() error {
4143 if len(want) > 0 {
4144 return fmt.Errorf("%s: did not get enough values, want %d more", name, len(want))
4145 }
4146 return nil
4147 })
4148 return checkNext
4149 }
4150 makePositionChecker := func(name string, want []P) func(e *jsontext.Encoder, v any) error {
4151 checkNext := func(e *jsontext.Encoder, v any) error {
4152 xe := export.Encoder(e)
4153 p := P{len(xe.Tokens.Stack), xe.Tokens.Last.Length()}
4154 switch {
4155 case len(want) == 0:
4156 return fmt.Errorf("%s: %v: got more values than wanted", name, p)
4157 case p != want[0]:
4158 return fmt.Errorf("%s: got %v, want %v", name, p, want[0])
4159 default:
4160 want = want[1:]
4161 return errors.ErrUnsupported
4162 }
4163 }
4164 lastChecks = append(lastChecks, func() error {
4165 if len(want) > 0 {
4166 return fmt.Errorf("%s: did not get enough values, want %d more", name, len(want))
4167 }
4168 return nil
4169 })
4170 return checkNext
4171 }
4172
4173 wantAny := []PV{
4174 {P{0, 0}, addr([]any{
4175 nil,
4176 valueStringer{},
4177 (*valueStringer)(nil),
4178 addr(valueStringer{}),
4179 (**valueStringer)(nil),
4180 addr((*valueStringer)(nil)),
4181 addr(addr(valueStringer{})),
4182 pointerStringer{},
4183 (*pointerStringer)(nil),
4184 addr(pointerStringer{}),
4185 (**pointerStringer)(nil),
4186 addr((*pointerStringer)(nil)),
4187 addr(addr(pointerStringer{})),
4188 "LAST",
4189 })},
4190 {P{1, 0}, addr(any(nil))},
4191 {P{1, 1}, addr(any(valueStringer{}))},
4192 {P{1, 1}, addr(valueStringer{})},
4193 {P{1, 2}, addr(any((*valueStringer)(nil)))},
4194 {P{1, 2}, addr((*valueStringer)(nil))},
4195 {P{1, 3}, addr(any(addr(valueStringer{})))},
4196 {P{1, 3}, addr(addr(valueStringer{}))},
4197 {P{1, 3}, addr(valueStringer{})},
4198 {P{1, 4}, addr(any((**valueStringer)(nil)))},
4199 {P{1, 4}, addr((**valueStringer)(nil))},
4200 {P{1, 5}, addr(any(addr((*valueStringer)(nil))))},
4201 {P{1, 5}, addr(addr((*valueStringer)(nil)))},
4202 {P{1, 5}, addr((*valueStringer)(nil))},
4203 {P{1, 6}, addr(any(addr(addr(valueStringer{}))))},
4204 {P{1, 6}, addr(addr(addr(valueStringer{})))},
4205 {P{1, 6}, addr(addr(valueStringer{}))},
4206 {P{1, 6}, addr(valueStringer{})},
4207 {P{1, 7}, addr(any(pointerStringer{}))},
4208 {P{1, 7}, addr(pointerStringer{})},
4209 {P{1, 8}, addr(any((*pointerStringer)(nil)))},
4210 {P{1, 8}, addr((*pointerStringer)(nil))},
4211 {P{1, 9}, addr(any(addr(pointerStringer{})))},
4212 {P{1, 9}, addr(addr(pointerStringer{}))},
4213 {P{1, 9}, addr(pointerStringer{})},
4214 {P{1, 10}, addr(any((**pointerStringer)(nil)))},
4215 {P{1, 10}, addr((**pointerStringer)(nil))},
4216 {P{1, 11}, addr(any(addr((*pointerStringer)(nil))))},
4217 {P{1, 11}, addr(addr((*pointerStringer)(nil)))},
4218 {P{1, 11}, addr((*pointerStringer)(nil))},
4219 {P{1, 12}, addr(any(addr(addr(pointerStringer{}))))},
4220 {P{1, 12}, addr(addr(addr(pointerStringer{})))},
4221 {P{1, 12}, addr(addr(pointerStringer{}))},
4222 {P{1, 12}, addr(pointerStringer{})},
4223 {P{1, 13}, addr(any("LAST"))},
4224 {P{1, 13}, addr("LAST")},
4225 }
4226 checkAny := makeValueChecker("any", wantAny)
4227 anyMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v any) error {
4228 return checkAny(enc, v)
4229 })
4230
4231 var wantPointerAny []PV
4232 for _, v := range wantAny {
4233 if _, ok := v.V.(*any); ok {
4234 wantPointerAny = append(wantPointerAny, v)
4235 }
4236 }
4237 checkPointerAny := makeValueChecker("*any", wantPointerAny)
4238 pointerAnyMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v *any) error {
4239 return checkPointerAny(enc, v)
4240 })
4241
4242 checkNamedAny := makeValueChecker("namedAny", wantAny)
4243 namedAnyMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v namedAny) error {
4244 return checkNamedAny(enc, v)
4245 })
4246
4247 checkPointerNamedAny := makeValueChecker("*namedAny", nil)
4248 pointerNamedAnyMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v *namedAny) error {
4249 return checkPointerNamedAny(enc, v)
4250 })
4251
4252 type stringer = fmt.Stringer
4253 var wantStringer []PV
4254 for _, v := range wantAny {
4255 if _, ok := v.V.(stringer); ok {
4256 wantStringer = append(wantStringer, v)
4257 }
4258 }
4259 checkStringer := makeValueChecker("stringer", wantStringer)
4260 stringerMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v stringer) error {
4261 return checkStringer(enc, v)
4262 })
4263
4264 checkPointerStringer := makeValueChecker("*stringer", nil)
4265 pointerStringerMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v *stringer) error {
4266 return checkPointerStringer(enc, v)
4267 })
4268
4269 wantValueStringer := []P{{1, 1}, {1, 3}, {1, 6}}
4270 checkValueValueStringer := makePositionChecker("valueStringer", wantValueStringer)
4271 valueValueStringerMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v valueStringer) error {
4272 return checkValueValueStringer(enc, v)
4273 })
4274
4275 checkPointerValueStringer := makePositionChecker("*valueStringer", wantValueStringer)
4276 pointerValueStringerMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v *valueStringer) error {
4277 return checkPointerValueStringer(enc, v)
4278 })
4279
4280 wantPointerStringer := []P{{1, 7}, {1, 9}, {1, 12}}
4281 checkValuePointerStringer := makePositionChecker("pointerStringer", wantPointerStringer)
4282 valuePointerStringerMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v pointerStringer) error {
4283 return checkValuePointerStringer(enc, v)
4284 })
4285
4286 checkPointerPointerStringer := makePositionChecker("*pointerStringer", wantPointerStringer)
4287 pointerPointerStringerMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v *pointerStringer) error {
4288 return checkPointerPointerStringer(enc, v)
4289 })
4290
4291 lastMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v string) error {
4292 return checkLast()
4293 })
4294
4295 return JoinMarshalers(
4296 anyMarshaler,
4297 pointerAnyMarshaler,
4298 namedAnyMarshaler,
4299 pointerNamedAnyMarshaler,
4300 stringerMarshaler,
4301 pointerStringerMarshaler,
4302 valueValueStringerMarshaler,
4303 pointerValueStringerMarshaler,
4304 valuePointerStringerMarshaler,
4305 pointerPointerStringerMarshaler,
4306 lastMarshaler,
4307 )
4308 }()),
4309 },
4310 in: []any{
4311 nil,
4312 valueStringer{},
4313 (*valueStringer)(nil),
4314 addr(valueStringer{}),
4315 (**valueStringer)(nil),
4316 addr((*valueStringer)(nil)),
4317 addr(addr(valueStringer{})),
4318 pointerStringer{},
4319 (*pointerStringer)(nil),
4320 addr(pointerStringer{}),
4321 (**pointerStringer)(nil),
4322 addr((*pointerStringer)(nil)),
4323 addr(addr(pointerStringer{})),
4324 "LAST",
4325 },
4326 want: `[null,{},null,{},null,null,{},{},null,{},null,null,{},"LAST"]`,
4327 }, {
4328 name: jsontest.Name("Functions/Precedence/V1First"),
4329 opts: []Options{
4330 WithMarshalers(JoinMarshalers(
4331 MarshalFunc(func(bool) ([]byte, error) {
4332 return []byte(`"called"`), nil
4333 }),
4334 MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
4335 panic("should not be called")
4336 }),
4337 )),
4338 },
4339 in: true,
4340 want: `"called"`,
4341 }, {
4342 name: jsontest.Name("Functions/Precedence/V2First"),
4343 opts: []Options{
4344 WithMarshalers(JoinMarshalers(
4345 MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
4346 return enc.WriteToken(jsontext.String("called"))
4347 }),
4348 MarshalFunc(func(bool) ([]byte, error) {
4349 panic("should not be called")
4350 }),
4351 )),
4352 },
4353 in: true,
4354 want: `"called"`,
4355 }, {
4356 name: jsontest.Name("Functions/Precedence/V2Skipped"),
4357 opts: []Options{
4358 WithMarshalers(JoinMarshalers(
4359 MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
4360 return errors.ErrUnsupported
4361 }),
4362 MarshalFunc(func(bool) ([]byte, error) {
4363 return []byte(`"called"`), nil
4364 }),
4365 )),
4366 },
4367 in: true,
4368 want: `"called"`,
4369 }, {
4370 name: jsontest.Name("Functions/Precedence/NestedFirst"),
4371 opts: []Options{
4372 WithMarshalers(JoinMarshalers(
4373 JoinMarshalers(
4374 MarshalFunc(func(bool) ([]byte, error) {
4375 return []byte(`"called"`), nil
4376 }),
4377 ),
4378 MarshalFunc(func(bool) ([]byte, error) {
4379 panic("should not be called")
4380 }),
4381 )),
4382 },
4383 in: true,
4384 want: `"called"`,
4385 }, {
4386 name: jsontest.Name("Functions/Precedence/NestedLast"),
4387 opts: []Options{
4388 WithMarshalers(JoinMarshalers(
4389 MarshalFunc(func(bool) ([]byte, error) {
4390 return []byte(`"called"`), nil
4391 }),
4392 JoinMarshalers(
4393 MarshalFunc(func(bool) ([]byte, error) {
4394 panic("should not be called")
4395 }),
4396 ),
4397 )),
4398 },
4399 in: true,
4400 want: `"called"`,
4401 }, {
4402 name: jsontest.Name("Duration/Zero"),
4403 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
4404 in: struct {
4405 D1 time.Duration `json:",format:units"`
4406 D2 time.Duration `json:",format:nano"`
4407 }{0, 0},
4408 want: `{"D1":"0s","D2":0}`,
4409 }, {
4410 name: jsontest.Name("Duration/Positive"),
4411 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
4412 in: struct {
4413 D1 time.Duration `json:",format:units"`
4414 D2 time.Duration `json:",format:nano"`
4415 }{
4416 123456789123456789,
4417 123456789123456789,
4418 },
4419 want: `{"D1":"34293h33m9.123456789s","D2":123456789123456789}`,
4420 }, {
4421 name: jsontest.Name("Duration/Negative"),
4422 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
4423 in: struct {
4424 D1 time.Duration `json:",format:units"`
4425 D2 time.Duration `json:",format:nano"`
4426 }{
4427 -123456789123456789,
4428 -123456789123456789,
4429 },
4430 want: `{"D1":"-34293h33m9.123456789s","D2":-123456789123456789}`,
4431 }, {
4432 name: jsontest.Name("Duration/Nanos/String"),
4433 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
4434 in: struct {
4435 D1 time.Duration `json:",string,format:nano"`
4436 D2 time.Duration `json:",string,format:nano"`
4437 D3 time.Duration `json:",string,format:nano"`
4438 }{
4439 math.MinInt64,
4440 0,
4441 math.MaxInt64,
4442 },
4443 want: `{"D1":"-9223372036854775808","D2":"0","D3":"9223372036854775807"}`,
4444 }, {
4445 name: jsontest.Name("Duration/Format/Invalid"),
4446 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
4447 in: struct {
4448 D time.Duration `json:",format:invalid"`
4449 }{},
4450 want: `{"D"`,
4451 wantErr: EM(errInvalidFormatFlag).withPos(`{"D":`, "/D").withType(0, T[time.Duration]()),
4452 }, {
4453
4459 name: jsontest.Name("Duration/Format"),
4460 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true), jsontext.Multiline(true)},
4461 in: structDurationFormat{
4462 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4463 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4464 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4465 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4466 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4467 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4468 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4469 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4470 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4471 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4472 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4473 },
4474 want: `{
4475 "D1": "12h34m56.078090012s",
4476 "D2": "12h34m56.078090012s",
4477 "D3": 45296.078090012,
4478 "D4": "45296.078090012",
4479 "D5": 45296078.090012,
4480 "D6": "45296078.090012",
4481 "D7": 45296078090.012,
4482 "D8": "45296078090.012",
4483 "D9": 45296078090012,
4484 "D10": "45296078090012",
4485 "D11": "PT12H34M56.078090012S"
4486 }`,
4487 }, {
4488
4497
4502 name: jsontest.Name("Duration/MapKey/Legacy"),
4503 opts: []Options{jsonflags.FormatDurationAsNano | 1},
4504 in: map[time.Duration]string{time.Second: ""},
4505 want: `{"1000000000":""}`,
4506 }, {
4507 name: jsontest.Name("Time/Zero"),
4508 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
4509 in: struct {
4510 T1 time.Time
4511 T2 time.Time `json:",format:RFC822"`
4512 T3 time.Time `json:",format:'2006-01-02'"`
4513 T4 time.Time `json:",omitzero"`
4514 T5 time.Time `json:",omitempty"`
4515 }{
4516 time.Time{},
4517 time.Time{},
4518 time.Time{},
4519
4520
4521 time.Date(1, 1, 1, 0, 0, 0, 0, time.FixedZone("UTC", 0)),
4522 time.Time{},
4523 },
4524 want: `{"T1":"0001-01-01T00:00:00Z","T2":"01 Jan 01 00:00 UTC","T3":"0001-01-01","T5":"0001-01-01T00:00:00Z"}`,
4525 }, {
4526 name: jsontest.Name("Time/Format"),
4527 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true), jsontext.Multiline(true)},
4528 in: structTimeFormat{
4529 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4530 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4531 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4532 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4533 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4534 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4535 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4536 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4537 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4538 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4539 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4540 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4541 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4542 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4543 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4544 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4545 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4546 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4547 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4548 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4549 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4550 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4551 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4552 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4553 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4554 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4555 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4556 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4557 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4558 },
4559 want: `{
4560 "T1": "1234-01-02T03:04:05.000000006Z",
4561 "T2": "Mon Jan 2 03:04:05 1234",
4562 "T3": "Mon Jan 2 03:04:05 UTC 1234",
4563 "T4": "Mon Jan 02 03:04:05 +0000 1234",
4564 "T5": "02 Jan 34 03:04 UTC",
4565 "T6": "02 Jan 34 03:04 +0000",
4566 "T7": "Monday, 02-Jan-34 03:04:05 UTC",
4567 "T8": "Mon, 02 Jan 1234 03:04:05 UTC",
4568 "T9": "Mon, 02 Jan 1234 03:04:05 +0000",
4569 "T10": "1234-01-02T03:04:05Z",
4570 "T11": "1234-01-02T03:04:05.000000006Z",
4571 "T12": "3:04AM",
4572 "T13": "Jan 2 03:04:05",
4573 "T14": "Jan 2 03:04:05.000",
4574 "T15": "Jan 2 03:04:05.000000",
4575 "T16": "Jan 2 03:04:05.000000006",
4576 "T17": "1234-01-02 03:04:05",
4577 "T18": "1234-01-02",
4578 "T19": "03:04:05",
4579 "T20": "1234-01-02",
4580 "T21": "\"weird\"1234",
4581 "T22": -23225777754.999999994,
4582 "T23": "-23225777754.999999994",
4583 "T24": -23225777754999.999994,
4584 "T25": "-23225777754999.999994",
4585 "T26": -23225777754999999.994,
4586 "T27": "-23225777754999999.994",
4587 "T28": -23225777754999999994,
4588 "T29": "-23225777754999999994"
4589 }`,
4590 }, {
4591 name: jsontest.Name("Time/Format/Invalid"),
4592 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
4593 in: struct {
4594 T time.Time `json:",format:UndefinedConstant"`
4595 }{},
4596 want: `{"T"`,
4597 wantErr: EM(errors.New(`invalid format flag "UndefinedConstant"`)).withPos(`{"T":`, "/T").withType(0, timeTimeType),
4598 }, {
4599 name: jsontest.Name("Time/Format/String/Invalid"),
4600 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
4601 in: structTimeFormatStringInvalid{},
4602 want: `{"T"`,
4603 wantErr: EM(errInvalidStringTag).withPos(`{"T":`, "/T").withType(0, timeTimeType),
4604 }, {
4605 name: jsontest.Name("Time/Format/YearOverflow"),
4606 in: struct {
4607 T1 time.Time
4608 T2 time.Time
4609 }{
4610 time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Add(-time.Second),
4611 time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC),
4612 },
4613 want: `{"T1":"9999-12-31T23:59:59Z","T2"`,
4614 wantErr: EM(errors.New(`year outside of range [0,9999]`)).withPos(`{"T1":"9999-12-31T23:59:59Z","T2":`, "/T2").withType(0, timeTimeType),
4615 }, {
4616 name: jsontest.Name("Time/Format/YearUnderflow"),
4617 in: struct {
4618 T1 time.Time
4619 T2 time.Time
4620 }{
4621 time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC),
4622 time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC).Add(-time.Second),
4623 },
4624 want: `{"T1":"0000-01-01T00:00:00Z","T2"`,
4625 wantErr: EM(errors.New(`year outside of range [0,9999]`)).withPos(`{"T1":"0000-01-01T00:00:00Z","T2":`, "/T2").withType(0, timeTimeType),
4626 }, {
4627 name: jsontest.Name("Time/Format/YearUnderflow"),
4628 in: struct{ T time.Time }{time.Date(-998, 1, 1, 0, 0, 0, 0, time.UTC).Add(-time.Second)},
4629 want: `{"T"`,
4630 wantErr: EM(errors.New(`year outside of range [0,9999]`)).withPos(`{"T":`, "/T").withType(0, timeTimeType),
4631 }, {
4632 name: jsontest.Name("Time/Format/ZoneExact"),
4633 in: struct{ T time.Time }{time.Date(2020, 1, 1, 0, 0, 0, 0, time.FixedZone("", 23*60*60+59*60))},
4634 want: `{"T":"2020-01-01T00:00:00+23:59"}`,
4635 }, {
4636 name: jsontest.Name("Time/Format/ZoneHourOverflow"),
4637 in: struct{ T time.Time }{time.Date(2020, 1, 1, 0, 0, 0, 0, time.FixedZone("", 24*60*60))},
4638 want: `{"T"`,
4639 wantErr: EM(errors.New(`timezone hour outside of range [0,23]`)).withPos(`{"T":`, "/T").withType(0, timeTimeType),
4640 }, {
4641 name: jsontest.Name("Time/Format/ZoneHourOverflow"),
4642 in: struct{ T time.Time }{time.Date(2020, 1, 1, 0, 0, 0, 0, time.FixedZone("", 123*60*60))},
4643 want: `{"T"`,
4644 wantErr: EM(errors.New(`timezone hour outside of range [0,23]`)).withPos(`{"T":`, "/T").withType(0, timeTimeType),
4645 }, {
4646 name: jsontest.Name("Time/IgnoreInvalidFormat"),
4647 opts: []Options{invalidFormatOption},
4648 in: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC),
4649 want: `"2000-01-01T00:00:00Z"`,
4650 }}
4651
4652 for _, tt := range tests {
4653 t.Run(tt.name.Name, func(t *testing.T) {
4654 var got []byte
4655 var gotErr error
4656 if tt.useWriter {
4657 bb := new(struct{ bytes.Buffer })
4658 gotErr = MarshalWrite(bb, tt.in, tt.opts...)
4659 got = bb.Bytes()
4660 } else {
4661 got, gotErr = Marshal(tt.in, tt.opts...)
4662 }
4663 if tt.canonicalize {
4664 (*jsontext.Value)(&got).Canonicalize()
4665 }
4666 if string(got) != tt.want {
4667 t.Errorf("%s: Marshal output mismatch:\ngot %s\nwant %s", tt.name.Where, got, tt.want)
4668 }
4669 if !reflect.DeepEqual(gotErr, tt.wantErr) {
4670 t.Errorf("%s: Marshal error mismatch:\ngot %v\nwant %v", tt.name.Where, gotErr, tt.wantErr)
4671 }
4672 })
4673 }
4674 }
4675
4676 func TestUnmarshal(t *testing.T) {
4677 tests := []struct {
4678 name jsontest.CaseName
4679 opts []Options
4680 inBuf string
4681 inVal any
4682 want any
4683 wantErr error
4684 skip bool
4685 }{{
4686 name: jsontest.Name("Nil"),
4687 inBuf: `null`,
4688 wantErr: EU(internal.ErrNonNilReference),
4689 }, {
4690 name: jsontest.Name("NilPointer"),
4691 inBuf: `null`,
4692 inVal: (*string)(nil),
4693 want: (*string)(nil),
4694 wantErr: EU(internal.ErrNonNilReference).withType(0, T[*string]()),
4695 }, {
4696 name: jsontest.Name("NonPointer"),
4697 inBuf: `null`,
4698 inVal: "unchanged",
4699 want: "unchanged",
4700 wantErr: EU(internal.ErrNonNilReference).withType(0, T[string]()),
4701 }, {
4702 name: jsontest.Name("Bools/TrailingJunk"),
4703 inBuf: `falsetrue`,
4704 inVal: addr(true),
4705 want: addr(false),
4706 wantErr: newInvalidCharacterError("t", "after top-level value", len64(`false`), ""),
4707 }, {
4708 name: jsontest.Name("Bools/Null"),
4709 inBuf: `null`,
4710 inVal: addr(true),
4711 want: addr(false),
4712 }, {
4713 name: jsontest.Name("Bools"),
4714 inBuf: `[null,false,true]`,
4715 inVal: new([]bool),
4716 want: addr([]bool{false, false, true}),
4717 }, {
4718 name: jsontest.Name("Bools/Named"),
4719 inBuf: `[null,false,true]`,
4720 inVal: new([]namedBool),
4721 want: addr([]namedBool{false, false, true}),
4722 }, {
4723 name: jsontest.Name("Bools/Invalid/StringifiedFalse"),
4724 opts: []Options{StringifyNumbers(true)},
4725 inBuf: `"false"`,
4726 inVal: addr(true),
4727 want: addr(true),
4728 wantErr: EU(nil).withType('"', boolType),
4729 }, {
4730 name: jsontest.Name("Bools/Invalid/StringifiedTrue"),
4731 opts: []Options{StringifyNumbers(true)},
4732 inBuf: `"true"`,
4733 inVal: addr(true),
4734 want: addr(true),
4735 wantErr: EU(nil).withType('"', boolType),
4736 }, {
4737 name: jsontest.Name("Bools/StringifiedBool/True"),
4738 opts: []Options{jsonflags.StringTag | jsonflags.StringifyWithLegacySemantics | 1},
4739 inBuf: `"true"`,
4740 inVal: addr(false),
4741 want: addr(true),
4742 }, {
4743 name: jsontest.Name("Bools/StringifiedBool/False"),
4744 opts: []Options{jsonflags.StringTag | jsonflags.StringifyWithLegacySemantics | 1},
4745 inBuf: `"false"`,
4746 inVal: addr(true),
4747 want: addr(false),
4748 }, {
4749 name: jsontest.Name("Bools/StringifiedBool/InvalidWhitespace"),
4750 opts: []Options{jsonflags.StringTag | jsonflags.StringifyWithLegacySemantics | 1},
4751 inBuf: `"false "`,
4752 inVal: addr(true),
4753 want: addr(true),
4754 wantErr: EU(strconv.ErrSyntax).withVal(`"false "`).withType('"', boolType),
4755 }, {
4756 name: jsontest.Name("Bools/StringifiedBool/InvalidBool"),
4757 opts: []Options{jsonflags.StringTag | jsonflags.StringifyWithLegacySemantics | 1},
4758 inBuf: `false`,
4759 inVal: addr(true),
4760 want: addr(true),
4761 wantErr: EU(nil).withType('f', boolType),
4762 }, {
4763 name: jsontest.Name("Bools/Invalid/Number"),
4764 inBuf: `0`,
4765 inVal: addr(true),
4766 want: addr(true),
4767 wantErr: EU(nil).withType('0', boolType),
4768 }, {
4769 name: jsontest.Name("Bools/Invalid/String"),
4770 inBuf: `""`,
4771 inVal: addr(true),
4772 want: addr(true),
4773 wantErr: EU(nil).withType('"', boolType),
4774 }, {
4775 name: jsontest.Name("Bools/Invalid/Object"),
4776 inBuf: `{}`,
4777 inVal: addr(true),
4778 want: addr(true),
4779 wantErr: EU(nil).withType('{', boolType),
4780 }, {
4781 name: jsontest.Name("Bools/Invalid/Array"),
4782 inBuf: `[]`,
4783 inVal: addr(true),
4784 want: addr(true),
4785 wantErr: EU(nil).withType('[', boolType),
4786 }, {
4787 name: jsontest.Name("Bools/IgnoreInvalidFormat"),
4788 opts: []Options{invalidFormatOption},
4789 inBuf: `false`,
4790 inVal: addr(true),
4791 want: addr(false),
4792 }, {
4793 name: jsontest.Name("Strings/Null"),
4794 inBuf: `null`,
4795 inVal: addr("something"),
4796 want: addr(""),
4797 }, {
4798 name: jsontest.Name("Strings"),
4799 inBuf: `[null,"","hello","世界"]`,
4800 inVal: new([]string),
4801 want: addr([]string{"", "", "hello", "世界"}),
4802 }, {
4803 name: jsontest.Name("Strings/Escaped"),
4804 inBuf: `[null,"","\u0068\u0065\u006c\u006c\u006f","\u4e16\u754c"]`,
4805 inVal: new([]string),
4806 want: addr([]string{"", "", "hello", "世界"}),
4807 }, {
4808 name: jsontest.Name("Strings/Named"),
4809 inBuf: `[null,"","hello","世界"]`,
4810 inVal: new([]namedString),
4811 want: addr([]namedString{"", "", "hello", "世界"}),
4812 }, {
4813 name: jsontest.Name("Strings/Invalid/False"),
4814 inBuf: `false`,
4815 inVal: addr("nochange"),
4816 want: addr("nochange"),
4817 wantErr: EU(nil).withType('f', stringType),
4818 }, {
4819 name: jsontest.Name("Strings/Invalid/True"),
4820 inBuf: `true`,
4821 inVal: addr("nochange"),
4822 want: addr("nochange"),
4823 wantErr: EU(nil).withType('t', stringType),
4824 }, {
4825 name: jsontest.Name("Strings/Invalid/Object"),
4826 inBuf: `{}`,
4827 inVal: addr("nochange"),
4828 want: addr("nochange"),
4829 wantErr: EU(nil).withType('{', stringType),
4830 }, {
4831 name: jsontest.Name("Strings/Invalid/Array"),
4832 inBuf: `[]`,
4833 inVal: addr("nochange"),
4834 want: addr("nochange"),
4835 wantErr: EU(nil).withType('[', stringType),
4836 }, {
4837 name: jsontest.Name("Strings/IgnoreInvalidFormat"),
4838 opts: []Options{invalidFormatOption},
4839 inBuf: `"hello"`,
4840 inVal: addr("goodbye"),
4841 want: addr("hello"),
4842 }, {
4843 name: jsontest.Name("Strings/StringifiedString"),
4844 opts: []Options{jsonflags.StringTag | jsonflags.StringifyWithLegacySemantics | 1},
4845 inBuf: `"\"foo\""`,
4846 inVal: new(string),
4847 want: addr("foo"),
4848 }, {
4849 name: jsontest.Name("Strings/StringifiedString/InvalidWhitespace"),
4850 opts: []Options{jsonflags.StringTag | jsonflags.StringifyWithLegacySemantics | 1},
4851 inBuf: `"\"foo\" "`,
4852 inVal: new(string),
4853 want: new(string),
4854 wantErr: EU(newInvalidCharacterError(" ", "after string value", 0, "")).withType('"', stringType),
4855 }, {
4856 name: jsontest.Name("Strings/StringifiedString/InvalidString"),
4857 opts: []Options{jsonflags.StringTag | jsonflags.StringifyWithLegacySemantics | 1},
4858 inBuf: `""`,
4859 inVal: new(string),
4860 want: new(string),
4861 wantErr: EU(&jsontext.SyntacticError{Err: io.ErrUnexpectedEOF}).withType('"', stringType),
4862 }, {
4863 name: jsontest.Name("Bytes/Null"),
4864 inBuf: `null`,
4865 inVal: addr([]byte("something")),
4866 want: addr([]byte(nil)),
4867 }, {
4868 name: jsontest.Name("Bytes"),
4869 inBuf: `[null,"","AQ==","AQI=","AQID"]`,
4870 inVal: new([][]byte),
4871 want: addr([][]byte{nil, {}, {1}, {1, 2}, {1, 2, 3}}),
4872 }, {
4873 name: jsontest.Name("Bytes/Large"),
4874 inBuf: `"dGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2cgYW5kIGF0ZSB0aGUgaG9tZXdvcmsgdGhhdCBJIHNwZW50IHNvIG11Y2ggdGltZSBvbi4="`,
4875 inVal: new([]byte),
4876 want: addr([]byte("the quick brown fox jumped over the lazy dog and ate the homework that I spent so much time on.")),
4877 }, {
4878 name: jsontest.Name("Bytes/Reuse"),
4879 inBuf: `"AQID"`,
4880 inVal: addr([]byte("changed")),
4881 want: addr([]byte{1, 2, 3}),
4882 }, {
4883 name: jsontest.Name("Bytes/Escaped"),
4884 inBuf: `[null,"","\u0041\u0051\u003d\u003d","\u0041\u0051\u0049\u003d","\u0041\u0051\u0049\u0044"]`,
4885 inVal: new([][]byte),
4886 want: addr([][]byte{nil, {}, {1}, {1, 2}, {1, 2, 3}}),
4887 }, {
4888 name: jsontest.Name("Bytes/Named"),
4889 inBuf: `[null,"","AQ==","AQI=","AQID"]`,
4890 inVal: new([]namedBytes),
4891 want: addr([]namedBytes{nil, {}, {1}, {1, 2}, {1, 2, 3}}),
4892 }, {
4893 name: jsontest.Name("Bytes/NotStringified"),
4894 opts: []Options{StringifyNumbers(true)},
4895 inBuf: `[null,"","AQ==","AQI=","AQID"]`,
4896 inVal: new([][]byte),
4897 want: addr([][]byte{nil, {}, {1}, {1, 2}, {1, 2, 3}}),
4898 }, {
4899
4900
4901 name: jsontest.Name("Bytes/Invariant"),
4902 inBuf: `[null,[],[1],[1,2],[1,2,3]]`,
4903 inVal: new([][]namedByte),
4904 want: addr([][]namedByte{nil, {}, {1}, {1, 2}, {1, 2, 3}}),
4905 }, {
4906
4907
4908 name: jsontest.Name("Bytes/ByteArray"),
4909 inBuf: `"aGVsbG8="`,
4910 inVal: new([5]byte),
4911 want: addr([5]byte{'h', 'e', 'l', 'l', 'o'}),
4912 }, {
4913 name: jsontest.Name("Bytes/ByteArray0/Valid"),
4914 inBuf: `""`,
4915 inVal: new([0]byte),
4916 want: addr([0]byte{}),
4917 }, {
4918 name: jsontest.Name("Bytes/ByteArray0/Invalid"),
4919 inBuf: `"A"`,
4920 inVal: new([0]byte),
4921 want: addr([0]byte{}),
4922 wantErr: EU(func() error {
4923 _, err := base64.StdEncoding.Decode(make([]byte, 0), []byte("A"))
4924 return err
4925 }()).withType('"', T[[0]byte]()),
4926 }, {
4927 name: jsontest.Name("Bytes/ByteArray0/Overflow"),
4928 inBuf: `"AA=="`,
4929 inVal: new([0]byte),
4930 want: addr([0]byte{}),
4931 wantErr: EU(errors.New("decoded length of 1 mismatches array length of 0")).withType('"', T[[0]byte]()),
4932 }, {
4933 name: jsontest.Name("Bytes/ByteArray1/Valid"),
4934 inBuf: `"AQ=="`,
4935 inVal: new([1]byte),
4936 want: addr([1]byte{1}),
4937 }, {
4938 name: jsontest.Name("Bytes/ByteArray1/Invalid"),
4939 inBuf: `"$$=="`,
4940 inVal: new([1]byte),
4941 want: addr([1]byte{}),
4942 wantErr: EU(func() error {
4943 _, err := base64.StdEncoding.Decode(make([]byte, 1), []byte("$$=="))
4944 return err
4945 }()).withType('"', T[[1]byte]()),
4946 }, {
4947 name: jsontest.Name("Bytes/ByteArray1/Underflow"),
4948 inBuf: `""`,
4949 inVal: new([1]byte),
4950 want: addr([1]byte{}),
4951 wantErr: EU(errors.New("decoded length of 0 mismatches array length of 1")).withType('"', T[[1]byte]()),
4952 }, {
4953 name: jsontest.Name("Bytes/ByteArray1/Overflow"),
4954 inBuf: `"AQI="`,
4955 inVal: new([1]byte),
4956 want: addr([1]byte{1}),
4957 wantErr: EU(errors.New("decoded length of 2 mismatches array length of 1")).withType('"', T[[1]byte]()),
4958 }, {
4959 name: jsontest.Name("Bytes/ByteArray2/Valid"),
4960 inBuf: `"AQI="`,
4961 inVal: new([2]byte),
4962 want: addr([2]byte{1, 2}),
4963 }, {
4964 name: jsontest.Name("Bytes/ByteArray2/Invalid"),
4965 inBuf: `"$$$="`,
4966 inVal: new([2]byte),
4967 want: addr([2]byte{}),
4968 wantErr: EU(func() error {
4969 _, err := base64.StdEncoding.Decode(make([]byte, 2), []byte("$$$="))
4970 return err
4971 }()).withType('"', T[[2]byte]()),
4972 }, {
4973 name: jsontest.Name("Bytes/ByteArray2/Underflow"),
4974 inBuf: `"AQ=="`,
4975 inVal: new([2]byte),
4976 want: addr([2]byte{1, 0}),
4977 wantErr: EU(errors.New("decoded length of 1 mismatches array length of 2")).withType('"', T[[2]byte]()),
4978 }, {
4979 name: jsontest.Name("Bytes/ByteArray2/Underflow/Allowed"),
4980 opts: []Options{jsonflags.UnmarshalArrayFromAnyLength | 1},
4981 inBuf: `"AQ=="`,
4982 inVal: new([2]byte),
4983 want: addr([2]byte{1, 0}),
4984 }, {
4985 name: jsontest.Name("Bytes/ByteArray2/Overflow"),
4986 inBuf: `"AQID"`,
4987 inVal: new([2]byte),
4988 want: addr([2]byte{1, 2}),
4989 wantErr: EU(errors.New("decoded length of 3 mismatches array length of 2")).withType('"', T[[2]byte]()),
4990 }, {
4991 name: jsontest.Name("Bytes/ByteArray2/Overflow/Allowed"),
4992 opts: []Options{jsonflags.UnmarshalArrayFromAnyLength | 1},
4993 inBuf: `"AQID"`,
4994 inVal: new([2]byte),
4995 want: addr([2]byte{1, 2}),
4996 }, {
4997 name: jsontest.Name("Bytes/ByteArray3/Valid"),
4998 inBuf: `"AQID"`,
4999 inVal: new([3]byte),
5000 want: addr([3]byte{1, 2, 3}),
5001 }, {
5002 name: jsontest.Name("Bytes/ByteArray3/Invalid"),
5003 inBuf: `"$$$$"`,
5004 inVal: new([3]byte),
5005 want: addr([3]byte{}),
5006 wantErr: EU(func() error {
5007 _, err := base64.StdEncoding.Decode(make([]byte, 3), []byte("$$$$"))
5008 return err
5009 }()).withType('"', T[[3]byte]()),
5010 }, {
5011 name: jsontest.Name("Bytes/ByteArray3/Underflow"),
5012 inBuf: `"AQI="`,
5013 inVal: addr([3]byte{0xff, 0xff, 0xff}),
5014 want: addr([3]byte{1, 2, 0}),
5015 wantErr: EU(errors.New("decoded length of 2 mismatches array length of 3")).withType('"', T[[3]byte]()),
5016 }, {
5017 name: jsontest.Name("Bytes/ByteArray3/Overflow"),
5018 inBuf: `"AQIDAQ=="`,
5019 inVal: new([3]byte),
5020 want: addr([3]byte{1, 2, 3}),
5021 wantErr: EU(errors.New("decoded length of 4 mismatches array length of 3")).withType('"', T[[3]byte]()),
5022 }, {
5023 name: jsontest.Name("Bytes/ByteArray4/Valid"),
5024 inBuf: `"AQIDBA=="`,
5025 inVal: new([4]byte),
5026 want: addr([4]byte{1, 2, 3, 4}),
5027 }, {
5028 name: jsontest.Name("Bytes/ByteArray4/Invalid"),
5029 inBuf: `"$$$$$$=="`,
5030 inVal: new([4]byte),
5031 want: addr([4]byte{}),
5032 wantErr: EU(func() error {
5033 _, err := base64.StdEncoding.Decode(make([]byte, 4), []byte("$$$$$$=="))
5034 return err
5035 }()).withType('"', T[[4]byte]()),
5036 }, {
5037 name: jsontest.Name("Bytes/ByteArray4/Underflow"),
5038 inBuf: `"AQID"`,
5039 inVal: new([4]byte),
5040 want: addr([4]byte{1, 2, 3, 0}),
5041 wantErr: EU(errors.New("decoded length of 3 mismatches array length of 4")).withType('"', T[[4]byte]()),
5042 }, {
5043 name: jsontest.Name("Bytes/ByteArray4/Overflow"),
5044 inBuf: `"AQIDBAU="`,
5045 inVal: new([4]byte),
5046 want: addr([4]byte{1, 2, 3, 4}),
5047 wantErr: EU(errors.New("decoded length of 5 mismatches array length of 4")).withType('"', T[[4]byte]()),
5048 }, {
5049
5050
5051 name: jsontest.Name("Bytes/NamedByteArray"),
5052 inBuf: `[104,101,108,108,111]`,
5053 inVal: new([5]namedByte),
5054 want: addr([5]namedByte{'h', 'e', 'l', 'l', 'o'}),
5055 }, {
5056 name: jsontest.Name("Bytes/Valid/Denormalized"),
5057 inBuf: `"AR=="`,
5058 inVal: new([]byte),
5059 want: addr([]byte{1}),
5060 }, {
5061 name: jsontest.Name("Bytes/Invalid/Unpadded1"),
5062 inBuf: `"AQ="`,
5063 inVal: addr([]byte("nochange")),
5064 want: addr([]byte("nochange")),
5065 wantErr: EU(func() error {
5066 _, err := base64.StdEncoding.Decode(make([]byte, 0), []byte("AQ="))
5067 return err
5068 }()).withType('"', bytesType),
5069 }, {
5070 name: jsontest.Name("Bytes/Invalid/Unpadded2"),
5071 inBuf: `"AQ"`,
5072 inVal: addr([]byte("nochange")),
5073 want: addr([]byte("nochange")),
5074 wantErr: EU(func() error {
5075 _, err := base64.StdEncoding.Decode(make([]byte, 0), []byte("AQ"))
5076 return err
5077 }()).withType('"', bytesType),
5078 }, {
5079 name: jsontest.Name("Bytes/Invalid/Character"),
5080 inBuf: `"@@@@"`,
5081 inVal: addr([]byte("nochange")),
5082 want: addr([]byte("nochange")),
5083 wantErr: EU(func() error {
5084 _, err := base64.StdEncoding.Decode(make([]byte, 3), []byte("@@@@"))
5085 return err
5086 }()).withType('"', bytesType),
5087 }, {
5088 name: jsontest.Name("Bytes/Invalid/Bool"),
5089 inBuf: `true`,
5090 inVal: addr([]byte("nochange")),
5091 want: addr([]byte("nochange")),
5092 wantErr: EU(nil).withType('t', bytesType),
5093 }, {
5094 name: jsontest.Name("Bytes/Invalid/Number"),
5095 inBuf: `0`,
5096 inVal: addr([]byte("nochange")),
5097 want: addr([]byte("nochange")),
5098 wantErr: EU(nil).withType('0', bytesType),
5099 }, {
5100 name: jsontest.Name("Bytes/Invalid/Object"),
5101 inBuf: `{}`,
5102 inVal: addr([]byte("nochange")),
5103 want: addr([]byte("nochange")),
5104 wantErr: EU(nil).withType('{', bytesType),
5105 }, {
5106 name: jsontest.Name("Bytes/Invalid/Array"),
5107 inBuf: `[]`,
5108 inVal: addr([]byte("nochange")),
5109 want: addr([]byte("nochange")),
5110 wantErr: EU(nil).withType('[', bytesType),
5111 }, {
5112 name: jsontest.Name("Bytes/IgnoreInvalidFormat"),
5113 opts: []Options{invalidFormatOption},
5114 inBuf: `"aGVsbG8="`,
5115 inVal: new([]byte),
5116 want: addr([]byte("hello")),
5117 }, {
5118 name: jsontest.Name("Ints/Null"),
5119 inBuf: `null`,
5120 inVal: addr(int(1)),
5121 want: addr(int(0)),
5122 }, {
5123 name: jsontest.Name("Ints/Int"),
5124 inBuf: `1`,
5125 inVal: addr(int(0)),
5126 want: addr(int(1)),
5127 }, {
5128 name: jsontest.Name("Ints/Int8/MinOverflow"),
5129 inBuf: `-129`,
5130 inVal: addr(int8(-1)),
5131 want: addr(int8(-1)),
5132 wantErr: EU(strconv.ErrRange).withVal(`-129`).withType('0', T[int8]()),
5133 }, {
5134 name: jsontest.Name("Ints/Int8/Min"),
5135 inBuf: `-128`,
5136 inVal: addr(int8(0)),
5137 want: addr(int8(-128)),
5138 }, {
5139 name: jsontest.Name("Ints/Int8/Max"),
5140 inBuf: `127`,
5141 inVal: addr(int8(0)),
5142 want: addr(int8(127)),
5143 }, {
5144 name: jsontest.Name("Ints/Int8/MaxOverflow"),
5145 inBuf: `128`,
5146 inVal: addr(int8(-1)),
5147 want: addr(int8(-1)),
5148 wantErr: EU(strconv.ErrRange).withVal(`128`).withType('0', T[int8]()),
5149 }, {
5150 name: jsontest.Name("Ints/Int16/MinOverflow"),
5151 inBuf: `-32769`,
5152 inVal: addr(int16(-1)),
5153 want: addr(int16(-1)),
5154 wantErr: EU(strconv.ErrRange).withVal(`-32769`).withType('0', T[int16]()),
5155 }, {
5156 name: jsontest.Name("Ints/Int16/Min"),
5157 inBuf: `-32768`,
5158 inVal: addr(int16(0)),
5159 want: addr(int16(-32768)),
5160 }, {
5161 name: jsontest.Name("Ints/Int16/Max"),
5162 inBuf: `32767`,
5163 inVal: addr(int16(0)),
5164 want: addr(int16(32767)),
5165 }, {
5166 name: jsontest.Name("Ints/Int16/MaxOverflow"),
5167 inBuf: `32768`,
5168 inVal: addr(int16(-1)),
5169 want: addr(int16(-1)),
5170 wantErr: EU(strconv.ErrRange).withVal(`32768`).withType('0', T[int16]()),
5171 }, {
5172 name: jsontest.Name("Ints/Int32/MinOverflow"),
5173 inBuf: `-2147483649`,
5174 inVal: addr(int32(-1)),
5175 want: addr(int32(-1)),
5176 wantErr: EU(strconv.ErrRange).withVal(`-2147483649`).withType('0', T[int32]()),
5177 }, {
5178 name: jsontest.Name("Ints/Int32/Min"),
5179 inBuf: `-2147483648`,
5180 inVal: addr(int32(0)),
5181 want: addr(int32(-2147483648)),
5182 }, {
5183 name: jsontest.Name("Ints/Int32/Max"),
5184 inBuf: `2147483647`,
5185 inVal: addr(int32(0)),
5186 want: addr(int32(2147483647)),
5187 }, {
5188 name: jsontest.Name("Ints/Int32/MaxOverflow"),
5189 inBuf: `2147483648`,
5190 inVal: addr(int32(-1)),
5191 want: addr(int32(-1)),
5192 wantErr: EU(strconv.ErrRange).withVal(`2147483648`).withType('0', T[int32]()),
5193 }, {
5194 name: jsontest.Name("Ints/Int64/MinOverflow"),
5195 inBuf: `-9223372036854775809`,
5196 inVal: addr(int64(-1)),
5197 want: addr(int64(-1)),
5198 wantErr: EU(strconv.ErrRange).withVal(`-9223372036854775809`).withType('0', T[int64]()),
5199 }, {
5200 name: jsontest.Name("Ints/Int64/Min"),
5201 inBuf: `-9223372036854775808`,
5202 inVal: addr(int64(0)),
5203 want: addr(int64(-9223372036854775808)),
5204 }, {
5205 name: jsontest.Name("Ints/Int64/Max"),
5206 inBuf: `9223372036854775807`,
5207 inVal: addr(int64(0)),
5208 want: addr(int64(9223372036854775807)),
5209 }, {
5210 name: jsontest.Name("Ints/Int64/MaxOverflow"),
5211 inBuf: `9223372036854775808`,
5212 inVal: addr(int64(-1)),
5213 want: addr(int64(-1)),
5214 wantErr: EU(strconv.ErrRange).withVal(`9223372036854775808`).withType('0', T[int64]()),
5215 }, {
5216 name: jsontest.Name("Ints/Named"),
5217 inBuf: `-6464`,
5218 inVal: addr(namedInt64(0)),
5219 want: addr(namedInt64(-6464)),
5220 }, {
5221 name: jsontest.Name("Ints/Stringified"),
5222 opts: []Options{StringifyNumbers(true)},
5223 inBuf: `"-6464"`,
5224 inVal: new(int),
5225 want: addr(int(-6464)),
5226 }, {
5227 name: jsontest.Name("Ints/Stringified/Invalid"),
5228 opts: []Options{StringifyNumbers(true)},
5229 inBuf: `-6464`,
5230 inVal: new(int),
5231 want: new(int),
5232 wantErr: EU(nil).withType('0', T[int]()),
5233 }, {
5234 name: jsontest.Name("Ints/Stringified/LeadingZero"),
5235 opts: []Options{StringifyNumbers(true)},
5236 inBuf: `"00"`,
5237 inVal: addr(int(-1)),
5238 want: addr(int(-1)),
5239 wantErr: EU(strconv.ErrSyntax).withVal(`"00"`).withType('"', T[int]()),
5240 }, {
5241 name: jsontest.Name("Ints/Escaped"),
5242 opts: []Options{StringifyNumbers(true)},
5243 inBuf: `"\u002d\u0036\u0034\u0036\u0034"`,
5244 inVal: new(int),
5245 want: addr(int(-6464)),
5246 }, {
5247 name: jsontest.Name("Ints/Valid/NegativeZero"),
5248 inBuf: `-0`,
5249 inVal: addr(int(1)),
5250 want: addr(int(0)),
5251 }, {
5252 name: jsontest.Name("Ints/Invalid/Fraction"),
5253 inBuf: `1.0`,
5254 inVal: addr(int(-1)),
5255 want: addr(int(-1)),
5256 wantErr: EU(strconv.ErrSyntax).withVal(`1.0`).withType('0', T[int]()),
5257 }, {
5258 name: jsontest.Name("Ints/Invalid/Exponent"),
5259 inBuf: `1e0`,
5260 inVal: addr(int(-1)),
5261 want: addr(int(-1)),
5262 wantErr: EU(strconv.ErrSyntax).withVal(`1e0`).withType('0', T[int]()),
5263 }, {
5264 name: jsontest.Name("Ints/Invalid/StringifiedFraction"),
5265 opts: []Options{StringifyNumbers(true)},
5266 inBuf: `"1.0"`,
5267 inVal: addr(int(-1)),
5268 want: addr(int(-1)),
5269 wantErr: EU(strconv.ErrSyntax).withVal(`"1.0"`).withType('"', T[int]()),
5270 }, {
5271 name: jsontest.Name("Ints/Invalid/StringifiedExponent"),
5272 opts: []Options{StringifyNumbers(true)},
5273 inBuf: `"1e0"`,
5274 inVal: addr(int(-1)),
5275 want: addr(int(-1)),
5276 wantErr: EU(strconv.ErrSyntax).withVal(`"1e0"`).withType('"', T[int]()),
5277 }, {
5278 name: jsontest.Name("Ints/Invalid/Overflow"),
5279 inBuf: `100000000000000000000000000000`,
5280 inVal: addr(int(-1)),
5281 want: addr(int(-1)),
5282 wantErr: EU(strconv.ErrRange).withVal(`100000000000000000000000000000`).withType('0', T[int]()),
5283 }, {
5284 name: jsontest.Name("Ints/Invalid/OverflowSyntax"),
5285 opts: []Options{StringifyNumbers(true)},
5286 inBuf: `"100000000000000000000000000000x"`,
5287 inVal: addr(int(-1)),
5288 want: addr(int(-1)),
5289 wantErr: EU(strconv.ErrSyntax).withVal(`"100000000000000000000000000000x"`).withType('"', T[int]()),
5290 }, {
5291 name: jsontest.Name("Ints/Invalid/Whitespace"),
5292 opts: []Options{StringifyNumbers(true)},
5293 inBuf: `"0 "`,
5294 inVal: addr(int(-1)),
5295 want: addr(int(-1)),
5296 wantErr: EU(strconv.ErrSyntax).withVal(`"0 "`).withType('"', T[int]()),
5297 }, {
5298 name: jsontest.Name("Ints/Invalid/Bool"),
5299 inBuf: `true`,
5300 inVal: addr(int(-1)),
5301 want: addr(int(-1)),
5302 wantErr: EU(nil).withType('t', T[int]()),
5303 }, {
5304 name: jsontest.Name("Ints/Invalid/String"),
5305 inBuf: `"0"`,
5306 inVal: addr(int(-1)),
5307 want: addr(int(-1)),
5308 wantErr: EU(nil).withType('"', T[int]()),
5309 }, {
5310 name: jsontest.Name("Ints/Invalid/Object"),
5311 inBuf: `{}`,
5312 inVal: addr(int(-1)),
5313 want: addr(int(-1)),
5314 wantErr: EU(nil).withType('{', T[int]()),
5315 }, {
5316 name: jsontest.Name("Ints/Invalid/Array"),
5317 inBuf: `[]`,
5318 inVal: addr(int(-1)),
5319 want: addr(int(-1)),
5320 wantErr: EU(nil).withType('[', T[int]()),
5321 }, {
5322 name: jsontest.Name("Ints/IgnoreInvalidFormat"),
5323 opts: []Options{invalidFormatOption},
5324 inBuf: `1`,
5325 inVal: addr(int(0)),
5326 want: addr(int(1)),
5327 }, {
5328 name: jsontest.Name("Uints/Null"),
5329 inBuf: `null`,
5330 inVal: addr(uint(1)),
5331 want: addr(uint(0)),
5332 }, {
5333 name: jsontest.Name("Uints/Uint"),
5334 inBuf: `1`,
5335 inVal: addr(uint(0)),
5336 want: addr(uint(1)),
5337 }, {
5338 name: jsontest.Name("Uints/Uint8/Min"),
5339 inBuf: `0`,
5340 inVal: addr(uint8(1)),
5341 want: addr(uint8(0)),
5342 }, {
5343 name: jsontest.Name("Uints/Uint8/Max"),
5344 inBuf: `255`,
5345 inVal: addr(uint8(0)),
5346 want: addr(uint8(255)),
5347 }, {
5348 name: jsontest.Name("Uints/Uint8/MaxOverflow"),
5349 inBuf: `256`,
5350 inVal: addr(uint8(1)),
5351 want: addr(uint8(1)),
5352 wantErr: EU(strconv.ErrRange).withVal(`256`).withType('0', T[uint8]()),
5353 }, {
5354 name: jsontest.Name("Uints/Uint16/Min"),
5355 inBuf: `0`,
5356 inVal: addr(uint16(1)),
5357 want: addr(uint16(0)),
5358 }, {
5359 name: jsontest.Name("Uints/Uint16/Max"),
5360 inBuf: `65535`,
5361 inVal: addr(uint16(0)),
5362 want: addr(uint16(65535)),
5363 }, {
5364 name: jsontest.Name("Uints/Uint16/MaxOverflow"),
5365 inBuf: `65536`,
5366 inVal: addr(uint16(1)),
5367 want: addr(uint16(1)),
5368 wantErr: EU(strconv.ErrRange).withVal(`65536`).withType('0', T[uint16]()),
5369 }, {
5370 name: jsontest.Name("Uints/Uint32/Min"),
5371 inBuf: `0`,
5372 inVal: addr(uint32(1)),
5373 want: addr(uint32(0)),
5374 }, {
5375 name: jsontest.Name("Uints/Uint32/Max"),
5376 inBuf: `4294967295`,
5377 inVal: addr(uint32(0)),
5378 want: addr(uint32(4294967295)),
5379 }, {
5380 name: jsontest.Name("Uints/Uint32/MaxOverflow"),
5381 inBuf: `4294967296`,
5382 inVal: addr(uint32(1)),
5383 want: addr(uint32(1)),
5384 wantErr: EU(strconv.ErrRange).withVal(`4294967296`).withType('0', T[uint32]()),
5385 }, {
5386 name: jsontest.Name("Uints/Uint64/Min"),
5387 inBuf: `0`,
5388 inVal: addr(uint64(1)),
5389 want: addr(uint64(0)),
5390 }, {
5391 name: jsontest.Name("Uints/Uint64/Max"),
5392 inBuf: `18446744073709551615`,
5393 inVal: addr(uint64(0)),
5394 want: addr(uint64(18446744073709551615)),
5395 }, {
5396 name: jsontest.Name("Uints/Uint64/MaxOverflow"),
5397 inBuf: `18446744073709551616`,
5398 inVal: addr(uint64(1)),
5399 want: addr(uint64(1)),
5400 wantErr: EU(strconv.ErrRange).withVal(`18446744073709551616`).withType('0', T[uint64]()),
5401 }, {
5402 name: jsontest.Name("Uints/Uintptr"),
5403 inBuf: `1`,
5404 inVal: addr(uintptr(0)),
5405 want: addr(uintptr(1)),
5406 }, {
5407 name: jsontest.Name("Uints/Named"),
5408 inBuf: `6464`,
5409 inVal: addr(namedUint64(0)),
5410 want: addr(namedUint64(6464)),
5411 }, {
5412 name: jsontest.Name("Uints/Stringified"),
5413 opts: []Options{StringifyNumbers(true)},
5414 inBuf: `"6464"`,
5415 inVal: new(uint),
5416 want: addr(uint(6464)),
5417 }, {
5418 name: jsontest.Name("Uints/Stringified/Invalid"),
5419 opts: []Options{StringifyNumbers(true)},
5420 inBuf: `6464`,
5421 inVal: new(uint),
5422 want: new(uint),
5423 wantErr: EU(nil).withType('0', T[uint]()),
5424 }, {
5425 name: jsontest.Name("Uints/Stringified/LeadingZero"),
5426 opts: []Options{StringifyNumbers(true)},
5427 inBuf: `"00"`,
5428 inVal: addr(uint(1)),
5429 want: addr(uint(1)),
5430 wantErr: EU(strconv.ErrSyntax).withVal(`"00"`).withType('"', T[uint]()),
5431 }, {
5432 name: jsontest.Name("Uints/Escaped"),
5433 opts: []Options{StringifyNumbers(true)},
5434 inBuf: `"\u0036\u0034\u0036\u0034"`,
5435 inVal: new(uint),
5436 want: addr(uint(6464)),
5437 }, {
5438 name: jsontest.Name("Uints/Invalid/NegativeOne"),
5439 inBuf: `-1`,
5440 inVal: addr(uint(1)),
5441 want: addr(uint(1)),
5442 wantErr: EU(strconv.ErrSyntax).withVal(`-1`).withType('0', T[uint]()),
5443 }, {
5444 name: jsontest.Name("Uints/Invalid/NegativeZero"),
5445 inBuf: `-0`,
5446 inVal: addr(uint(1)),
5447 want: addr(uint(1)),
5448 wantErr: EU(strconv.ErrSyntax).withVal(`-0`).withType('0', T[uint]()),
5449 }, {
5450 name: jsontest.Name("Uints/Invalid/Fraction"),
5451 inBuf: `1.0`,
5452 inVal: addr(uint(10)),
5453 want: addr(uint(10)),
5454 wantErr: EU(strconv.ErrSyntax).withVal(`1.0`).withType('0', T[uint]()),
5455 }, {
5456 name: jsontest.Name("Uints/Invalid/Exponent"),
5457 inBuf: `1e0`,
5458 inVal: addr(uint(10)),
5459 want: addr(uint(10)),
5460 wantErr: EU(strconv.ErrSyntax).withVal(`1e0`).withType('0', T[uint]()),
5461 }, {
5462 name: jsontest.Name("Uints/Invalid/StringifiedFraction"),
5463 opts: []Options{StringifyNumbers(true)},
5464 inBuf: `"1.0"`,
5465 inVal: addr(uint(10)),
5466 want: addr(uint(10)),
5467 wantErr: EU(strconv.ErrSyntax).withVal(`"1.0"`).withType('"', T[uint]()),
5468 }, {
5469 name: jsontest.Name("Uints/Invalid/StringifiedExponent"),
5470 opts: []Options{StringifyNumbers(true)},
5471 inBuf: `"1e0"`,
5472 inVal: addr(uint(10)),
5473 want: addr(uint(10)),
5474 wantErr: EU(strconv.ErrSyntax).withVal(`"1e0"`).withType('"', T[uint]()),
5475 }, {
5476 name: jsontest.Name("Uints/Invalid/Overflow"),
5477 inBuf: `100000000000000000000000000000`,
5478 inVal: addr(uint(1)),
5479 want: addr(uint(1)),
5480 wantErr: EU(strconv.ErrRange).withVal(`100000000000000000000000000000`).withType('0', T[uint]()),
5481 }, {
5482 name: jsontest.Name("Uints/Invalid/OverflowSyntax"),
5483 opts: []Options{StringifyNumbers(true)},
5484 inBuf: `"100000000000000000000000000000x"`,
5485 inVal: addr(uint(1)),
5486 want: addr(uint(1)),
5487 wantErr: EU(strconv.ErrSyntax).withVal(`"100000000000000000000000000000x"`).withType('"', T[uint]()),
5488 }, {
5489 name: jsontest.Name("Uints/Invalid/Whitespace"),
5490 opts: []Options{StringifyNumbers(true)},
5491 inBuf: `"0 "`,
5492 inVal: addr(uint(1)),
5493 want: addr(uint(1)),
5494 wantErr: EU(strconv.ErrSyntax).withVal(`"0 "`).withType('"', T[uint]()),
5495 }, {
5496 name: jsontest.Name("Uints/Invalid/Bool"),
5497 inBuf: `true`,
5498 inVal: addr(uint(1)),
5499 want: addr(uint(1)),
5500 wantErr: EU(nil).withType('t', T[uint]()),
5501 }, {
5502 name: jsontest.Name("Uints/Invalid/String"),
5503 inBuf: `"0"`,
5504 inVal: addr(uint(1)),
5505 want: addr(uint(1)),
5506 wantErr: EU(nil).withType('"', T[uint]()),
5507 }, {
5508 name: jsontest.Name("Uints/Invalid/Object"),
5509 inBuf: `{}`,
5510 inVal: addr(uint(1)),
5511 want: addr(uint(1)),
5512 wantErr: EU(nil).withType('{', T[uint]()),
5513 }, {
5514 name: jsontest.Name("Uints/Invalid/Array"),
5515 inBuf: `[]`,
5516 inVal: addr(uint(1)),
5517 want: addr(uint(1)),
5518 wantErr: EU(nil).withType('[', T[uint]()),
5519 }, {
5520 name: jsontest.Name("Uints/IgnoreInvalidFormat"),
5521 opts: []Options{invalidFormatOption},
5522 inBuf: `1`,
5523 inVal: addr(uint(0)),
5524 want: addr(uint(1)),
5525 }, {
5526 name: jsontest.Name("Floats/Null"),
5527 inBuf: `null`,
5528 inVal: addr(float64(64.64)),
5529 want: addr(float64(0)),
5530 }, {
5531 name: jsontest.Name("Floats/Float32/Pi"),
5532 inBuf: `3.14159265358979323846264338327950288419716939937510582097494459`,
5533 inVal: addr(float32(32.32)),
5534 want: addr(float32(math.Pi)),
5535 }, {
5536 name: jsontest.Name("Floats/Float32/Underflow"),
5537 inBuf: `1e-1000`,
5538 inVal: addr(float32(32.32)),
5539 want: addr(float32(0)),
5540 }, {
5541 name: jsontest.Name("Floats/Float32/Overflow"),
5542 inBuf: `-1e1000`,
5543 inVal: addr(float32(32.32)),
5544 want: addr(float32(math.Inf(-1))),
5545 wantErr: EU(strconv.ErrRange).withVal(`-1e1000`).withType('0', T[float32]()),
5546 }, {
5547 name: jsontest.Name("Floats/Float64/Pi"),
5548 inBuf: `3.14159265358979323846264338327950288419716939937510582097494459`,
5549 inVal: addr(float64(64.64)),
5550 want: addr(float64(math.Pi)),
5551 }, {
5552 name: jsontest.Name("Floats/Float64/Underflow"),
5553 inBuf: `1e-1000`,
5554 inVal: addr(float64(64.64)),
5555 want: addr(float64(0)),
5556 }, {
5557 name: jsontest.Name("Floats/Float64/Overflow"),
5558 inBuf: `-1e1000`,
5559 inVal: addr(float64(64.64)),
5560 want: addr(float64(math.Inf(-1))),
5561 wantErr: EU(strconv.ErrRange).withVal(`-1e1000`).withType('0', T[float64]()),
5562 }, {
5563 name: jsontest.Name("Floats/Any/Overflow"),
5564 inBuf: `1e1000`,
5565 inVal: new(any),
5566 want: addr(any(float64(math.Inf(+1)))),
5567 wantErr: EU(strconv.ErrRange).withVal(`1e1000`).withType('0', T[float64]()),
5568 }, {
5569 name: jsontest.Name("Floats/Named"),
5570 inBuf: `64.64`,
5571 inVal: addr(namedFloat64(0)),
5572 want: addr(namedFloat64(64.64)),
5573 }, {
5574 name: jsontest.Name("Floats/Stringified"),
5575 opts: []Options{StringifyNumbers(true)},
5576 inBuf: `"64.64"`,
5577 inVal: new(float64),
5578 want: addr(float64(64.64)),
5579 }, {
5580 name: jsontest.Name("Floats/Stringified/Invalid"),
5581 opts: []Options{StringifyNumbers(true)},
5582 inBuf: `64.64`,
5583 inVal: new(float64),
5584 want: new(float64),
5585 wantErr: EU(nil).withType('0', T[float64]()),
5586 }, {
5587 name: jsontest.Name("Floats/Escaped"),
5588 opts: []Options{StringifyNumbers(true)},
5589 inBuf: `"\u0036\u0034\u002e\u0036\u0034"`,
5590 inVal: new(float64),
5591 want: addr(float64(64.64)),
5592 }, {
5593 name: jsontest.Name("Floats/Invalid/NaN"),
5594 opts: []Options{StringifyNumbers(true)},
5595 inBuf: `"NaN"`,
5596 inVal: addr(float64(64.64)),
5597 want: addr(float64(64.64)),
5598 wantErr: EU(strconv.ErrSyntax).withVal(`"NaN"`).withType('"', float64Type),
5599 }, {
5600 name: jsontest.Name("Floats/Invalid/Infinity"),
5601 opts: []Options{StringifyNumbers(true)},
5602 inBuf: `"Infinity"`,
5603 inVal: addr(float64(64.64)),
5604 want: addr(float64(64.64)),
5605 wantErr: EU(strconv.ErrSyntax).withVal(`"Infinity"`).withType('"', float64Type),
5606 }, {
5607 name: jsontest.Name("Floats/Invalid/Whitespace"),
5608 opts: []Options{StringifyNumbers(true)},
5609 inBuf: `"1 "`,
5610 inVal: addr(float64(64.64)),
5611 want: addr(float64(64.64)),
5612 wantErr: EU(strconv.ErrSyntax).withVal(`"1 "`).withType('"', float64Type),
5613 }, {
5614 name: jsontest.Name("Floats/Invalid/GoSyntax"),
5615 opts: []Options{StringifyNumbers(true)},
5616 inBuf: `"1p-2"`,
5617 inVal: addr(float64(64.64)),
5618 want: addr(float64(64.64)),
5619 wantErr: EU(strconv.ErrSyntax).withVal(`"1p-2"`).withType('"', float64Type),
5620 }, {
5621 name: jsontest.Name("Floats/Invalid/Bool"),
5622 inBuf: `true`,
5623 inVal: addr(float64(64.64)),
5624 want: addr(float64(64.64)),
5625 wantErr: EU(nil).withType('t', float64Type),
5626 }, {
5627 name: jsontest.Name("Floats/Invalid/String"),
5628 inBuf: `"0"`,
5629 inVal: addr(float64(64.64)),
5630 want: addr(float64(64.64)),
5631 wantErr: EU(nil).withType('"', float64Type),
5632 }, {
5633 name: jsontest.Name("Floats/Invalid/Object"),
5634 inBuf: `{}`,
5635 inVal: addr(float64(64.64)),
5636 want: addr(float64(64.64)),
5637 wantErr: EU(nil).withType('{', float64Type),
5638 }, {
5639 name: jsontest.Name("Floats/Invalid/Array"),
5640 inBuf: `[]`,
5641 inVal: addr(float64(64.64)),
5642 want: addr(float64(64.64)),
5643 wantErr: EU(nil).withType('[', float64Type),
5644 }, {
5645 name: jsontest.Name("Floats/IgnoreInvalidFormat"),
5646 opts: []Options{invalidFormatOption},
5647 inBuf: `1`,
5648 inVal: addr(float64(0)),
5649 want: addr(float64(1)),
5650 }, {
5651 name: jsontest.Name("Maps/Null"),
5652 inBuf: `null`,
5653 inVal: addr(map[string]string{"key": "value"}),
5654 want: new(map[string]string),
5655 }, {
5656 name: jsontest.Name("Maps/InvalidKey/Bool"),
5657 inBuf: `{"true":"false"}`,
5658 inVal: new(map[bool]bool),
5659 want: addr(make(map[bool]bool)),
5660 wantErr: EU(nil).withPos(`{`, "/true").withType('"', boolType),
5661 }, {
5662 name: jsontest.Name("Maps/InvalidKey/NamedBool"),
5663 inBuf: `{"true":"false"}`,
5664 inVal: new(map[namedBool]bool),
5665 want: addr(make(map[namedBool]bool)),
5666 wantErr: EU(nil).withPos(`{`, "/true").withType('"', T[namedBool]()),
5667 }, {
5668 name: jsontest.Name("Maps/InvalidKey/Array"),
5669 inBuf: `{"key":"value"}`,
5670 inVal: new(map[[1]string]string),
5671 want: addr(make(map[[1]string]string)),
5672 wantErr: EU(nil).withPos(`{`, "/key").withType('"', T[[1]string]()),
5673 }, {
5674 name: jsontest.Name("Maps/InvalidKey/Channel"),
5675 inBuf: `{"key":"value"}`,
5676 inVal: new(map[chan string]string),
5677 want: addr(make(map[chan string]string)),
5678 wantErr: EU(nil).withPos(`{`, "").withType(0, T[chan string]()),
5679 }, {
5680 name: jsontest.Name("Maps/ValidKey/Int"),
5681 inBuf: `{"0":0,"-1":1,"2":2,"-3":3}`,
5682 inVal: new(map[int]int),
5683 want: addr(map[int]int{0: 0, -1: 1, 2: 2, -3: 3}),
5684 }, {
5685 name: jsontest.Name("Maps/ValidKey/NamedInt"),
5686 inBuf: `{"0":0,"-1":1,"2":2,"-3":3}`,
5687 inVal: new(map[namedInt64]int),
5688 want: addr(map[namedInt64]int{0: 0, -1: 1, 2: 2, -3: 3}),
5689 }, {
5690 name: jsontest.Name("Maps/ValidKey/Uint"),
5691 inBuf: `{"0":0,"1":1,"2":2,"3":3}`,
5692 inVal: new(map[uint]uint),
5693 want: addr(map[uint]uint{0: 0, 1: 1, 2: 2, 3: 3}),
5694 }, {
5695 name: jsontest.Name("Maps/ValidKey/NamedUint"),
5696 inBuf: `{"0":0,"1":1,"2":2,"3":3}`,
5697 inVal: new(map[namedUint64]uint),
5698 want: addr(map[namedUint64]uint{0: 0, 1: 1, 2: 2, 3: 3}),
5699 }, {
5700 name: jsontest.Name("Maps/ValidKey/Float"),
5701 inBuf: `{"1.234":1.234,"12.34":12.34,"123.4":123.4}`,
5702 inVal: new(map[float64]float64),
5703 want: addr(map[float64]float64{1.234: 1.234, 12.34: 12.34, 123.4: 123.4}),
5704 }, {
5705 name: jsontest.Name("Maps/DuplicateName/Int"),
5706 inBuf: `{"0":1,"-0":-1}`,
5707 inVal: new(map[int]int),
5708 want: addr(map[int]int{0: 1}),
5709 wantErr: newDuplicateNameError("", []byte(`"-0"`), len64(`{"0":1,`)),
5710 }, {
5711 name: jsontest.Name("Maps/DuplicateName/Int/MergeWithLegacySemantics"),
5712 opts: []Options{jsonflags.MergeWithLegacySemantics | 1},
5713 inBuf: `{"0":1,"-0":-1}`,
5714 inVal: new(map[int]int),
5715 want: addr(map[int]int{0: 1}),
5716 wantErr: newDuplicateNameError("", []byte(`"-0"`), len64(`{"0":1,`)),
5717 }, {
5718 name: jsontest.Name("Maps/DuplicateName/Int/AllowDuplicateNames"),
5719 opts: []Options{jsontext.AllowDuplicateNames(true)},
5720 inBuf: `{"0":1,"-0":-1}`,
5721 inVal: new(map[int]int),
5722 want: addr(map[int]int{0: -1}),
5723 }, {
5724 name: jsontest.Name("Maps/DuplicateName/Int/OverwriteExisting"),
5725 inBuf: `{"-0":-1}`,
5726 inVal: addr(map[int]int{0: 1}),
5727 want: addr(map[int]int{0: -1}),
5728 }, {
5729 name: jsontest.Name("Maps/DuplicateName/Float"),
5730 inBuf: `{"1.0":"1.0","1":"1","1e0":"1e0"}`,
5731 inVal: new(map[float64]string),
5732 want: addr(map[float64]string{1: "1.0"}),
5733 wantErr: newDuplicateNameError("", []byte(`"1"`), len64(`{"1.0":"1.0",`)),
5734 }, {
5735 name: jsontest.Name("Maps/DuplicateName/Float/AllowDuplicateNames"),
5736 opts: []Options{jsontext.AllowDuplicateNames(true)},
5737 inBuf: `{"1.0":"1.0","1":"1","1e0":"1e0"}`,
5738 inVal: new(map[float64]string),
5739 want: addr(map[float64]string{1: "1e0"}),
5740 }, {
5741 name: jsontest.Name("Maps/DuplicateName/Float/OverwriteExisting"),
5742 inBuf: `{"1.0":"1.0"}`,
5743 inVal: addr(map[float64]string{1: "1"}),
5744 want: addr(map[float64]string{1: "1.0"}),
5745 }, {
5746 name: jsontest.Name("Maps/DuplicateName/NoCaseString"),
5747 inBuf: `{"hello":"hello","HELLO":"HELLO"}`,
5748 inVal: new(map[nocaseString]string),
5749 want: addr(map[nocaseString]string{"hello": "hello"}),
5750 wantErr: newDuplicateNameError("", []byte(`"HELLO"`), len64(`{"hello":"hello",`)),
5751 }, {
5752 name: jsontest.Name("Maps/DuplicateName/NoCaseString/AllowDuplicateNames"),
5753 opts: []Options{jsontext.AllowDuplicateNames(true)},
5754 inBuf: `{"hello":"hello","HELLO":"HELLO"}`,
5755 inVal: new(map[nocaseString]string),
5756 want: addr(map[nocaseString]string{"hello": "HELLO"}),
5757 }, {
5758 name: jsontest.Name("Maps/DuplicateName/NoCaseString/OverwriteExisting"),
5759 opts: []Options{jsontext.AllowDuplicateNames(true)},
5760 inBuf: `{"HELLO":"HELLO"}`,
5761 inVal: addr(map[nocaseString]string{"hello": "hello"}),
5762 want: addr(map[nocaseString]string{"hello": "HELLO"}),
5763 }, {
5764 name: jsontest.Name("Maps/ValidKey/Interface"),
5765 inBuf: `{"false":"false","true":"true","string":"string","0":"0","[]":"[]","{}":"{}"}`,
5766 inVal: new(map[any]string),
5767 want: addr(map[any]string{
5768 "false": "false",
5769 "true": "true",
5770 "string": "string",
5771 "0": "0",
5772 "[]": "[]",
5773 "{}": "{}",
5774 }),
5775 }, {
5776 name: jsontest.Name("Maps/InvalidValue/Channel"),
5777 inBuf: `{"key":"value"}`,
5778 inVal: new(map[string]chan string),
5779 want: addr(map[string]chan string{
5780 "key": nil,
5781 }),
5782 wantErr: EU(nil).withPos(`{"key":`, "/key").withType(0, T[chan string]()),
5783 }, {
5784 name: jsontest.Name("Maps/RecursiveMap"),
5785 inBuf: `{"buzz":{},"fizz":{"bar":{},"foo":{}}}`,
5786 inVal: new(recursiveMap),
5787 want: addr(recursiveMap{
5788 "fizz": {
5789 "foo": {},
5790 "bar": {},
5791 },
5792 "buzz": {},
5793 }),
5794 }, {
5795
5796
5797
5798 name: jsontest.Name("Maps/Merge"),
5799 opts: []Options{jsontext.AllowDuplicateNames(true)},
5800 inBuf: `{"k1":{"k2":"v2"},"k2":{"k1":"v1"},"k2":{"k2":"v2"}}`,
5801 inVal: addr(map[string]map[string]string{
5802 "k1": {"k1": "v1"},
5803 }),
5804 want: addr(map[string]map[string]string{
5805 "k1": {"k1": "v1", "k2": "v2"},
5806 "k2": {"k1": "v1", "k2": "v2"},
5807 }),
5808 }, {
5809 name: jsontest.Name("Maps/Invalid/Bool"),
5810 inBuf: `true`,
5811 inVal: addr(map[string]string{"key": "value"}),
5812 want: addr(map[string]string{"key": "value"}),
5813 wantErr: EU(nil).withType('t', T[map[string]string]()),
5814 }, {
5815 name: jsontest.Name("Maps/Invalid/String"),
5816 inBuf: `""`,
5817 inVal: addr(map[string]string{"key": "value"}),
5818 want: addr(map[string]string{"key": "value"}),
5819 wantErr: EU(nil).withType('"', T[map[string]string]()),
5820 }, {
5821 name: jsontest.Name("Maps/Invalid/Number"),
5822 inBuf: `0`,
5823 inVal: addr(map[string]string{"key": "value"}),
5824 want: addr(map[string]string{"key": "value"}),
5825 wantErr: EU(nil).withType('0', T[map[string]string]()),
5826 }, {
5827 name: jsontest.Name("Maps/Invalid/Array"),
5828 inBuf: `[]`,
5829 inVal: addr(map[string]string{"key": "value"}),
5830 want: addr(map[string]string{"key": "value"}),
5831 wantErr: EU(nil).withType('[', T[map[string]string]()),
5832 }, {
5833 name: jsontest.Name("Maps/IgnoreInvalidFormat"),
5834 opts: []Options{invalidFormatOption},
5835 inBuf: `{"hello":"goodbye"}`,
5836 inVal: addr(map[string]string{}),
5837 want: addr(map[string]string{"hello": "goodbye"}),
5838 }, {
5839 name: jsontest.Name("Structs/Null"),
5840 inBuf: `null`,
5841 inVal: addr(structAll{String: "something"}),
5842 want: addr(structAll{}),
5843 }, {
5844 name: jsontest.Name("Structs/Empty"),
5845 inBuf: `{}`,
5846 inVal: addr(structAll{
5847 String: "hello",
5848 Map: map[string]string{},
5849 Slice: []string{},
5850 }),
5851 want: addr(structAll{
5852 String: "hello",
5853 Map: map[string]string{},
5854 Slice: []string{},
5855 }),
5856 }, {
5857 name: jsontest.Name("Structs/Normal"),
5858 inBuf: `{
5859 "Bool": true,
5860 "String": "hello",
5861 "Bytes": "AQID",
5862 "Int": -64,
5863 "Uint": 64,
5864 "Float": 3.14159,
5865 "Map": {"key": "value"},
5866 "StructScalars": {
5867 "Bool": true,
5868 "String": "hello",
5869 "Bytes": "AQID",
5870 "Int": -64,
5871 "Uint": 64,
5872 "Float": 3.14159
5873 },
5874 "StructMaps": {
5875 "MapBool": {"": true},
5876 "MapString": {"": "hello"},
5877 "MapBytes": {"": "AQID"},
5878 "MapInt": {"": -64},
5879 "MapUint": {"": 64},
5880 "MapFloat": {"": 3.14159}
5881 },
5882 "StructSlices": {
5883 "SliceBool": [true],
5884 "SliceString": ["hello"],
5885 "SliceBytes": ["AQID"],
5886 "SliceInt": [-64],
5887 "SliceUint": [64],
5888 "SliceFloat": [3.14159]
5889 },
5890 "Slice": ["fizz","buzz"],
5891 "Array": ["goodbye"],
5892 "Pointer": {},
5893 "Interface": null
5894 }`,
5895 inVal: new(structAll),
5896 want: addr(structAll{
5897 Bool: true,
5898 String: "hello",
5899 Bytes: []byte{1, 2, 3},
5900 Int: -64,
5901 Uint: +64,
5902 Float: 3.14159,
5903 Map: map[string]string{"key": "value"},
5904 StructScalars: structScalars{
5905 Bool: true,
5906 String: "hello",
5907 Bytes: []byte{1, 2, 3},
5908 Int: -64,
5909 Uint: +64,
5910 Float: 3.14159,
5911 },
5912 StructMaps: structMaps{
5913 MapBool: map[string]bool{"": true},
5914 MapString: map[string]string{"": "hello"},
5915 MapBytes: map[string][]byte{"": {1, 2, 3}},
5916 MapInt: map[string]int64{"": -64},
5917 MapUint: map[string]uint64{"": +64},
5918 MapFloat: map[string]float64{"": 3.14159},
5919 },
5920 StructSlices: structSlices{
5921 SliceBool: []bool{true},
5922 SliceString: []string{"hello"},
5923 SliceBytes: [][]byte{{1, 2, 3}},
5924 SliceInt: []int64{-64},
5925 SliceUint: []uint64{+64},
5926 SliceFloat: []float64{3.14159},
5927 },
5928 Slice: []string{"fizz", "buzz"},
5929 Array: [1]string{"goodbye"},
5930 Pointer: new(structAll),
5931 }),
5932 }, {
5933 name: jsontest.Name("Structs/Merge"),
5934 inBuf: `{
5935 "Bool": false,
5936 "String": "goodbye",
5937 "Int": -64,
5938 "Float": 3.14159,
5939 "Map": {"k2": "v2"},
5940 "StructScalars": {
5941 "Bool": true,
5942 "String": "hello",
5943 "Bytes": "AQID",
5944 "Int": -64
5945 },
5946 "StructMaps": {
5947 "MapBool": {"": true},
5948 "MapString": {"": "hello"},
5949 "MapBytes": {"": "AQID"},
5950 "MapInt": {"": -64},
5951 "MapUint": {"": 64},
5952 "MapFloat": {"": 3.14159}
5953 },
5954 "StructSlices": {
5955 "SliceString": ["hello"],
5956 "SliceBytes": ["AQID"],
5957 "SliceInt": [-64],
5958 "SliceUint": [64]
5959 },
5960 "Slice": ["fizz","buzz"],
5961 "Array": ["goodbye"],
5962 "Pointer": {},
5963 "Interface": {"k2":"v2"}
5964 }`,
5965 inVal: addr(structAll{
5966 Bool: true,
5967 String: "hello",
5968 Bytes: []byte{1, 2, 3},
5969 Uint: +64,
5970 Float: math.NaN(),
5971 Map: map[string]string{"k1": "v1"},
5972 StructScalars: structScalars{
5973 String: "hello",
5974 Bytes: make([]byte, 2, 4),
5975 Uint: +64,
5976 Float: 3.14159,
5977 },
5978 StructMaps: structMaps{
5979 MapBool: map[string]bool{"": false},
5980 MapBytes: map[string][]byte{"": {}},
5981 MapInt: map[string]int64{"": 123},
5982 MapFloat: map[string]float64{"": math.Inf(+1)},
5983 },
5984 StructSlices: structSlices{
5985 SliceBool: []bool{true},
5986 SliceBytes: [][]byte{nil, nil},
5987 SliceInt: []int64{-123},
5988 SliceUint: []uint64{+123},
5989 SliceFloat: []float64{3.14159},
5990 },
5991 Slice: []string{"buzz", "fizz", "gizz"},
5992 Array: [1]string{"hello"},
5993 Pointer: new(structAll),
5994 Interface: map[string]string{"k1": "v1"},
5995 }),
5996 want: addr(structAll{
5997 Bool: false,
5998 String: "goodbye",
5999 Bytes: []byte{1, 2, 3},
6000 Int: -64,
6001 Uint: +64,
6002 Float: 3.14159,
6003 Map: map[string]string{"k1": "v1", "k2": "v2"},
6004 StructScalars: structScalars{
6005 Bool: true,
6006 String: "hello",
6007 Bytes: []byte{1, 2, 3},
6008 Int: -64,
6009 Uint: +64,
6010 Float: 3.14159,
6011 },
6012 StructMaps: structMaps{
6013 MapBool: map[string]bool{"": true},
6014 MapString: map[string]string{"": "hello"},
6015 MapBytes: map[string][]byte{"": {1, 2, 3}},
6016 MapInt: map[string]int64{"": -64},
6017 MapUint: map[string]uint64{"": +64},
6018 MapFloat: map[string]float64{"": 3.14159},
6019 },
6020 StructSlices: structSlices{
6021 SliceBool: []bool{true},
6022 SliceString: []string{"hello"},
6023 SliceBytes: [][]byte{{1, 2, 3}},
6024 SliceInt: []int64{-64},
6025 SliceUint: []uint64{+64},
6026 SliceFloat: []float64{3.14159},
6027 },
6028 Slice: []string{"fizz", "buzz"},
6029 Array: [1]string{"goodbye"},
6030 Pointer: new(structAll),
6031 Interface: map[string]string{"k1": "v1", "k2": "v2"},
6032 }),
6033 }, {
6034 name: jsontest.Name("Structs/Stringified"),
6035 inBuf: `{
6036 "Int": "-64",
6037 "Uint": "64",
6038 "Float": "3.14159",
6039 "PointerInt": "-64",
6040 "PointerUint": "64",
6041 "PointerFloat": "3.14159"
6042 }`,
6043 inVal: new(structStringified),
6044 want: addr(structStringified{
6045 Int: -64,
6046 Uint: +64,
6047 Float: 3.14159,
6048 PointerInt: new(int64(-64)),
6049 PointerUint: new(uint64(+64)),
6050 PointerFloat: new(float64(3.14159)),
6051 }),
6052 }, {
6053 name: jsontest.Name("Structs/Stringified/Invalid/EmptyIntString"),
6054 inBuf: `{"Int":""}`,
6055 inVal: new(structStringified),
6056 want: new(structStringified),
6057 wantErr: EU(strconv.ErrSyntax).withVal(`""`).withPos(`{"Int":`, "/Int").withType('"', T[int64]()),
6058 }, {
6059 name: jsontest.Name("Structs/Stringified/Invalid/Bool"),
6060 inBuf: `{"Bool": "true"}`,
6061 inVal: new(structStringifiedBool),
6062 want: new(structStringifiedBool),
6063 wantErr: EU(errInvalidStringTag).withPos(`{"Bool": `, "/Bool").withType(0, T[bool]()),
6064 }, {
6065 name: jsontest.Name("Structs/Stringified/Ignored/Bool"),
6066 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
6067 inBuf: `{"Bool": true}`,
6068 inVal: new(structStringifiedBool),
6069 want: new(structStringifiedBool{Bool: true}),
6070 }, {
6071 name: jsontest.Name("Structs/Stringified/Invalid/String"),
6072 inBuf: `{"String": "\"hello\""}`,
6073 inVal: new(structStringifiedString),
6074 want: new(structStringifiedString),
6075 wantErr: EU(errInvalidStringTag).withPos(`{"String": `, "/String").withType(0, T[string]()),
6076 }, {
6077 name: jsontest.Name("Structs/Stringified/Ignored/String"),
6078 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
6079 inBuf: `{"String": "\"hello\""}`,
6080 inVal: new(structStringifiedString),
6081 want: new(structStringifiedString{String: `"hello"`}),
6082 }, {
6083 name: jsontest.Name("Structs/Stringified/Invalid/Bytes"),
6084 inBuf: `{"Bytes": "AQID"}`,
6085 inVal: new(structStringifiedBytes),
6086 want: new(structStringifiedBytes),
6087 wantErr: EU(errInvalidStringTag).withPos(`{"Bytes": `, "/Bytes").withType(0, T[[]byte]()),
6088 }, {
6089 name: jsontest.Name("Structs/Stringified/Ignored/Bytes"),
6090 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
6091 inBuf: `{"Bytes": "AQID"}`,
6092 inVal: new(structStringifiedBytes),
6093 want: new(structStringifiedBytes{Bytes: []byte{1, 2, 3}}),
6094 }, {
6095 name: jsontest.Name("Structs/Stringified/Invalid/Map"),
6096 inBuf: `{"Map": {"Key": "Value"}}`,
6097 inVal: new(structStringifiedMap),
6098 want: new(structStringifiedMap),
6099 wantErr: EU(errInvalidStringTag).withPos(`{"Map": `, "/Map").withType(0, T[map[string]string]()),
6100 }, {
6101 name: jsontest.Name("Structs/Stringified/Ignored/Map"),
6102 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
6103 inBuf: `{"Map": {"Key": "Value"}}`,
6104 inVal: new(structStringifiedMap),
6105 want: new(structStringifiedMap{Map: map[string]string{"Key": "Value"}}),
6106 }, {
6107 name: jsontest.Name("Structs/Stringified/Invalid/Slice"),
6108 inBuf: `{"Slice": ["hello"]}`,
6109 inVal: new(structStringifiedSlice),
6110 want: new(structStringifiedSlice),
6111 wantErr: EU(errInvalidStringTag).withPos(`{"Slice": `, "/Slice").withType(0, T[[]string]()),
6112 }, {
6113 name: jsontest.Name("Structs/Stringified/Ignored/Slice"),
6114 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
6115 inBuf: `{"Slice": ["hello"]}`,
6116 inVal: new(structStringifiedSlice),
6117 want: new(structStringifiedSlice{Slice: []string{"hello"}}),
6118 }, {
6119 name: jsontest.Name("Structs/Stringified/Invalid/Array"),
6120 inBuf: `{"Array": ["hello"]}`,
6121 inVal: new(structStringifiedArray),
6122 want: new(structStringifiedArray),
6123 wantErr: EU(errInvalidStringTag).withPos(`{"Array": `, "/Array").withType(0, T[[1]string]()),
6124 }, {
6125 name: jsontest.Name("Structs/Stringified/Ignored/Array"),
6126 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
6127 inBuf: `{"Array": ["hello"]}`,
6128 inVal: new(structStringifiedArray),
6129 want: new(structStringifiedArray{Array: [1]string{"hello"}}),
6130 }, {
6131 name: jsontest.Name("Structs/Stringified/Invalid/Struct"),
6132 inBuf: `{"Struct": {"Bool": true}}`,
6133 inVal: new(structStringifiedStruct),
6134 want: new(structStringifiedStruct),
6135 wantErr: EU(errInvalidStringTag).withPos(`{"Struct": `, "/Struct").withType(0, T[structAll]()),
6136 }, {
6137 name: jsontest.Name("Structs/Stringified/Ignored/Struct"),
6138 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
6139 inBuf: `{"Struct": {"Bool": true}}`,
6140 inVal: new(structStringifiedStruct),
6141 want: new(structStringifiedStruct{Struct: structAll{Bool: true}}),
6142 }, {
6143 name: jsontest.Name("Structs/Stringified/Invalid/Pointer"),
6144 inBuf: `{"Pointer": {"Bool": true}}`,
6145 inVal: new(structStringifiedPointer),
6146 want: new(structStringifiedPointer{Pointer: new(structAll)}),
6147 wantErr: EU(errInvalidStringTag).withPos(`{"Pointer": `, "/Pointer").withType(0, T[structAll]()),
6148 }, {
6149 name: jsontest.Name("Structs/Stringified/Ignored/Pointer"),
6150 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
6151 inBuf: `{"Pointer": {"Bool": true}}`,
6152 inVal: new(structStringifiedPointer),
6153 want: new(structStringifiedPointer{Pointer: new(structAll{Bool: true})}),
6154 }, {
6155 name: jsontest.Name("Structs/Stringified/PointerPointerInt"),
6156 inBuf: `{"Pointer": "5"}`,
6157 inVal: new(structStringifiedPointerPointerInt),
6158 want: new(structStringifiedPointerPointerInt{Pointer: new(new(5))}),
6159 }, {
6160 name: jsontest.Name("Structs/Stringified/Invalid/Interface"),
6161 inBuf: `{"Interface": null}`,
6162 inVal: new(structStringifiedInterface),
6163 want: new(structStringifiedInterface),
6164 wantErr: EU(errInvalidStringTag).withPos(`{"Interface": `, "/Interface").withType(0, T[any]()),
6165 }, {
6166 name: jsontest.Name("Structs/Stringified/Ignored/Interface"),
6167 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
6168 inBuf: `{"Interface": null}`,
6169 inVal: new(structStringifiedInterface),
6170 want: new(structStringifiedInterface),
6171 }, {
6172 name: jsontest.Name("Structs/LegacyStringified"),
6173 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6174 inBuf: `{
6175 "Bool": "true",
6176 "String": "\"hello\"",
6177 "Int": "-64",
6178 "Uint": "64",
6179 "Float": "3.14159",
6180 "PointerBool": "true",
6181 "PointerString": "\"hello\"",
6182 "PointerInt": "-64",
6183 "PointerUint": "64",
6184 "PointerFloat": "3.14159"
6185 }`,
6186 inVal: new(structStringifiedLegacy),
6187 want: addr(structStringifiedLegacy{
6188 Bool: true,
6189 String: "hello",
6190 Int: -64,
6191 Uint: +64,
6192 Float: 3.14159,
6193 PointerBool: new(true),
6194 PointerString: new("hello"),
6195 PointerInt: new(int64(-64)),
6196 PointerUint: new(uint64(+64)),
6197 PointerFloat: new(float64(3.14159)),
6198 }),
6199 }, {
6200 name: jsontest.Name("Structs/LegacyStringified/Invalid/EmptyIntString"),
6201 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6202 inBuf: `{"Int":""}`,
6203 inVal: new(structStringifiedLegacy),
6204 want: new(structStringifiedLegacy),
6205 wantErr: EU(strconv.ErrSyntax).withVal(`""`).withPos(`{"Int":`, "/Int").withType('"', T[int64]()),
6206 }, {
6207 name: jsontest.Name("Structs/LegacyStringified/Invalid/Bool"),
6208 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6209 inBuf: `{"Bool": true}`,
6210 inVal: new(structStringifiedLegacy),
6211 wantErr: EU(nil).withPos(`{"Bool": `, "/Bool").withType('t', T[bool]()),
6212 }, {
6213 name: jsontest.Name("Structs/LegacyStringified/Invalid/String"),
6214 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6215 inBuf: `{"String": "string"}`,
6216 inVal: new(structStringifiedLegacy),
6217 wantErr: EU(newInvalidCharacterError("s", "at start of string (expecting '\"')", 0, "")).
6218 withPos(`{"String": `, "/String").withType('"', T[string]()),
6219 }, {
6220 name: jsontest.Name("Structs/LegacyStringified/Invalid/Bytes"),
6221 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6222 inBuf: `{"Bytes": "AQID"}`,
6223 inVal: new(structStringifiedBytes),
6224 want: new(structStringifiedBytes),
6225 wantErr: EU(errInvalidStringTag).withPos(`{"Bytes": `, "/Bytes").withType(0, T[[]byte]()),
6226 }, {
6227 name: jsontest.Name("Structs/LegacyStringified/Ignored/Bytes"),
6228 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1, jsonflags.ReportErrorsWithLegacySemantics | 1},
6229 inBuf: `{"Bytes": "AQID"}`,
6230 inVal: new(structStringifiedBytes),
6231 want: new(structStringifiedBytes{Bytes: []byte{1, 2, 3}}),
6232 }, {
6233 name: jsontest.Name("Structs/LegacyStringified/Invalid/Map"),
6234 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6235 inBuf: `{"Map": {"Key": "Value"}}`,
6236 inVal: new(structStringifiedMap),
6237 want: new(structStringifiedMap),
6238 wantErr: EU(errInvalidStringTag).withPos(`{"Map": `, "/Map").withType(0, T[map[string]string]()),
6239 }, {
6240 name: jsontest.Name("Structs/LegacyStringified/Ignored/Map"),
6241 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1, jsonflags.ReportErrorsWithLegacySemantics | 1},
6242 inBuf: `{"Map": {"Key": "Value"}}`,
6243 inVal: new(structStringifiedMap),
6244 want: new(structStringifiedMap{Map: map[string]string{"Key": "Value"}}),
6245 }, {
6246 name: jsontest.Name("Structs/LegacyStringified/Invalid/Slice"),
6247 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6248 inBuf: `{"Slice": ["hello"]}`,
6249 inVal: new(structStringifiedSlice),
6250 want: new(structStringifiedSlice),
6251 wantErr: EU(errInvalidStringTag).withPos(`{"Slice": `, "/Slice").withType(0, T[[]string]()),
6252 }, {
6253 name: jsontest.Name("Structs/LegacyStringified/Ignored/Slice"),
6254 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1, jsonflags.ReportErrorsWithLegacySemantics | 1},
6255 inBuf: `{"Slice": ["hello"]}`,
6256 inVal: new(structStringifiedSlice),
6257 want: new(structStringifiedSlice{Slice: []string{"hello"}}),
6258 }, {
6259 name: jsontest.Name("Structs/LegacyStringified/Invalid/Array"),
6260 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6261 inBuf: `{"Array": ["hello"]}`,
6262 inVal: new(structStringifiedArray),
6263 want: new(structStringifiedArray),
6264 wantErr: EU(errInvalidStringTag).withPos(`{"Array": `, "/Array").withType(0, T[[1]string]()),
6265 }, {
6266 name: jsontest.Name("Structs/LegacyStringified/Ignored/Array"),
6267 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1, jsonflags.ReportErrorsWithLegacySemantics | 1},
6268 inBuf: `{"Array": ["hello"]}`,
6269 inVal: new(structStringifiedArray),
6270 want: new(structStringifiedArray{Array: [1]string{"hello"}}),
6271 }, {
6272 name: jsontest.Name("Structs/LegacyStringified/Invalid/Struct"),
6273 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6274 inBuf: `{"Struct": {"Bool": true}}`,
6275 inVal: new(structStringifiedStruct),
6276 want: new(structStringifiedStruct),
6277 wantErr: EU(errInvalidStringTag).withPos(`{"Struct": `, "/Struct").withType(0, T[structAll]()),
6278 }, {
6279 name: jsontest.Name("Structs/LegacyStringified/Ignored/Struct"),
6280 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1, jsonflags.ReportErrorsWithLegacySemantics | 1},
6281 inBuf: `{"Struct": {"Bool": true}}`,
6282 inVal: new(structStringifiedStruct),
6283 want: new(structStringifiedStruct{Struct: structAll{Bool: true}}),
6284 }, {
6285 name: jsontest.Name("Structs/LegacyStringified/Invalid/Pointer"),
6286 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6287 inBuf: `{"Pointer": {"Bool": true}}`,
6288 inVal: new(structStringifiedPointer),
6289 want: new(structStringifiedPointer{Pointer: new(structAll)}),
6290 wantErr: EU(errInvalidStringTag).withPos(`{"Pointer": `, "/Pointer").withType(0, T[structAll]()),
6291 }, {
6292 name: jsontest.Name("Structs/LegacyStringified/Ignored/Pointer"),
6293 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1, jsonflags.ReportErrorsWithLegacySemantics | 1},
6294 inBuf: `{"Pointer": {"Bool": true}}`,
6295 inVal: new(structStringifiedPointer),
6296 want: new(structStringifiedPointer{Pointer: new(structAll{Bool: true})}),
6297 }, {
6298 name: jsontest.Name("Structs/Stringified/Invalid/PointerPointerInt"),
6299 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6300 inBuf: `{"Pointer": 5}`,
6301 inVal: new(structStringifiedPointerPointerInt),
6302 want: new(structStringifiedPointerPointerInt{}),
6303 wantErr: EU(errInvalidStringTag).withPos(`{"Pointer": `, "/Pointer").withType(0, T[**int]()),
6304 }, {
6305 name: jsontest.Name("Structs/Stringified/Ignored/PointerPointerInt"),
6306 opts: []Options{jsonflags.StringifyWithLegacySemantics | jsonflags.ReportErrorsWithLegacySemantics | 1},
6307 inBuf: `{"Pointer": 5}`,
6308 inVal: new(structStringifiedPointerPointerInt),
6309 want: new(structStringifiedPointerPointerInt{Pointer: new(new(5))}),
6310 }, {
6311 name: jsontest.Name("Structs/LegacyStringified/Invalid/Interface"),
6312 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6313 inBuf: `{"Interface": null}`,
6314 inVal: new(structStringifiedInterface),
6315 want: new(structStringifiedInterface),
6316 wantErr: EU(errInvalidStringTag).withPos(`{"Interface": `, "/Interface").withType(0, T[any]()),
6317 }, {
6318 name: jsontest.Name("Structs/LegacyStringified/Ignored/Interface"),
6319 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1, jsonflags.ReportErrorsWithLegacySemantics | 1},
6320 inBuf: `{"Interface": null}`,
6321 inVal: new(structStringifiedInterface),
6322 want: new(structStringifiedInterface),
6323 }, {
6324 name: jsontest.Name("Structs/Format/Bytes/Unsupported"),
6325 inBuf: `{}`,
6326 inVal: new(structFormatBytes),
6327 wantErr: EU(errors.New("Go struct field Base16 has unsupported `format` tag option")).withType('{', T[structFormatBytes]()),
6328 }, {
6329 name: jsontest.Name("Structs/Format/Bytes"),
6330 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6331 inBuf: `{
6332 "Base16": "0123456789abcdef",
6333 "Base32": "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
6334 "Base32Hex": "0123456789ABCDEFGHIJKLMNOPQRSTUV",
6335 "Base64": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
6336 "Base64URL": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
6337 "Array": [1, 2, 3, 4]
6338 }`,
6339 inVal: new(structFormatBytes),
6340 want: addr(structFormatBytes{
6341 Base16: []byte("\x01\x23\x45\x67\x89\xab\xcd\xef"),
6342 Base32: []byte("\x00D2\x14\xc7BT\xb65τe:V\xd7\xc6u\xbew\xdf"),
6343 Base32Hex: []byte("\x00D2\x14\xc7BT\xb65τe:V\xd7\xc6u\xbew\xdf"),
6344 Base64: []byte("\x00\x10\x83\x10Q\x87 \x92\x8b0ӏA\x14\x93QU\x97a\x96\x9bqן\x82\x18\xa3\x92Y\xa7\xa2\x9a\xab\xb2ۯ\xc3\x1c\xb3\xd3]\xb7㞻\xf3߿"),
6345 Base64URL: []byte("\x00\x10\x83\x10Q\x87 \x92\x8b0ӏA\x14\x93QU\x97a\x96\x9bqן\x82\x18\xa3\x92Y\xa7\xa2\x9a\xab\xb2ۯ\xc3\x1c\xb3\xd3]\xb7㞻\xf3߿"),
6346 Array: []byte{1, 2, 3, 4},
6347 }),
6348 }, {
6349 name: jsontest.Name("Structs/Format/ArrayBytes"),
6350 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6351 inBuf: `{
6352 "Base16": "01020304",
6353 "Base32": "AEBAGBA=",
6354 "Base32Hex": "0410610=",
6355 "Base64": "AQIDBA==",
6356 "Base64URL": "AQIDBA==",
6357 "Array": [1, 2, 3, 4],
6358 "Default": "AQIDBA=="
6359 }`,
6360 inVal: new(structFormatArrayBytes),
6361 want: addr(structFormatArrayBytes{
6362 Base16: [4]byte{1, 2, 3, 4},
6363 Base32: [4]byte{1, 2, 3, 4},
6364 Base32Hex: [4]byte{1, 2, 3, 4},
6365 Base64: [4]byte{1, 2, 3, 4},
6366 Base64URL: [4]byte{1, 2, 3, 4},
6367 Array: [4]byte{1, 2, 3, 4},
6368 Default: [4]byte{1, 2, 3, 4},
6369 }),
6370 }, {
6371 name: jsontest.Name("Structs/Format/ArrayBytes/Legacy"),
6372 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true), jsonflags.FormatBytesWithLegacySemantics | 1},
6373 inBuf: `{
6374 "Base16": "01020304",
6375 "Base32": "AEBAGBA=",
6376 "Base32Hex": "0410610=",
6377 "Base64": "AQIDBA==",
6378 "Base64URL": "AQIDBA==",
6379 "Array": [1, 2, 3, 4],
6380 "Default": [1, 2, 3, 4]
6381 }`,
6382 inVal: new(structFormatArrayBytes),
6383 want: addr(structFormatArrayBytes{
6384 Base16: [4]byte{1, 2, 3, 4},
6385 Base32: [4]byte{1, 2, 3, 4},
6386 Base32Hex: [4]byte{1, 2, 3, 4},
6387 Base64: [4]byte{1, 2, 3, 4},
6388 Base64URL: [4]byte{1, 2, 3, 4},
6389 Array: [4]byte{1, 2, 3, 4},
6390 Default: [4]byte{1, 2, 3, 4},
6391 }),
6392 }, {
6393 name: jsontest.Name("Structs/Format/Bytes/Array"),
6394 opts: []Options{
6395 jsonopts.ExperimentalSupportFormatTag(true),
6396 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *byte) error {
6397 if string(b) == "true" {
6398 *v = 1
6399 } else {
6400 *v = 0
6401 }
6402 return nil
6403 })),
6404 },
6405 inBuf: `{"Array":[false,true,false,true,false,true]}`,
6406 inVal: new(struct {
6407 Array []byte `json:",format:array"`
6408 }),
6409 want: addr(struct {
6410 Array []byte `json:",format:array"`
6411 }{
6412 Array: []byte{0, 1, 0, 1, 0, 1},
6413 }),
6414 }, {
6415 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base16/WrongKind"),
6416 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6417 inBuf: `{"Base16": [1,2,3,4]}`,
6418 inVal: new(structFormatBytes),
6419 wantErr: EU(nil).withPos(`{"Base16": `, "/Base16").withType('[', T[[]byte]()),
6420 }, {
6421 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base16/AllPadding"),
6422 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6423 inBuf: `{"Base16": "===="}`,
6424 inVal: new(structFormatBytes),
6425 wantErr: EU(func() error {
6426 _, err := hex.Decode(make([]byte, 2), []byte("====="))
6427 return err
6428 }()).withPos(`{"Base16": `, "/Base16").withType('"', T[[]byte]()),
6429 }, {
6430 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base16/EvenPadding"),
6431 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6432 inBuf: `{"Base16": "0123456789abcdef="}`,
6433 inVal: new(structFormatBytes),
6434 wantErr: EU(func() error {
6435 _, err := hex.Decode(make([]byte, 8), []byte("0123456789abcdef="))
6436 return err
6437 }()).withPos(`{"Base16": `, "/Base16").withType('"', T[[]byte]()),
6438 }, {
6439 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base16/OddPadding"),
6440 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6441 inBuf: `{"Base16": "0123456789abcdef0="}`,
6442 inVal: new(structFormatBytes),
6443 wantErr: EU(func() error {
6444 _, err := hex.Decode(make([]byte, 9), []byte("0123456789abcdef0="))
6445 return err
6446 }()).withPos(`{"Base16": `, "/Base16").withType('"', T[[]byte]()),
6447 }, {
6448 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base16/NonAlphabet/LineFeed"),
6449 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6450 inBuf: `{"Base16": "aa\naa"}`,
6451 inVal: new(structFormatBytes),
6452 wantErr: EU(func() error {
6453 _, err := hex.Decode(make([]byte, 9), []byte("aa\naa"))
6454 return err
6455 }()).withPos(`{"Base16": `, "/Base16").withType('"', T[[]byte]()),
6456 }, {
6457 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base16/NonAlphabet/CarriageReturn"),
6458 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6459 inBuf: `{"Base16": "aa\raa"}`,
6460 inVal: new(structFormatBytes),
6461 wantErr: EU(func() error {
6462 _, err := hex.Decode(make([]byte, 9), []byte("aa\raa"))
6463 return err
6464 }()).withPos(`{"Base16": `, "/Base16").withType('"', T[[]byte]()),
6465 }, {
6466 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base16/NonAlphabet/Space"),
6467 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6468 inBuf: `{"Base16": "aa aa"}`,
6469 inVal: new(structFormatBytes),
6470 wantErr: EU(func() error {
6471 _, err := hex.Decode(make([]byte, 9), []byte("aa aa"))
6472 return err
6473 }()).withPos(`{"Base16": `, "/Base16").withType('"', T[[]byte]()),
6474 }, {
6475 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base32/Padding"),
6476 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6477 inBuf: `[
6478 {"Base32": "NA======"},
6479 {"Base32": "NBSQ===="},
6480 {"Base32": "NBSWY==="},
6481 {"Base32": "NBSWY3A="},
6482 {"Base32": "NBSWY3DP"}
6483 ]`,
6484 inVal: new([]structFormatBytes),
6485 want: addr([]structFormatBytes{
6486 {Base32: []byte("h")},
6487 {Base32: []byte("he")},
6488 {Base32: []byte("hel")},
6489 {Base32: []byte("hell")},
6490 {Base32: []byte("hello")},
6491 }),
6492 }, {
6493 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base32/Invalid/NoPadding"),
6494 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6495 inBuf: `[
6496 {"Base32": "NA"},
6497 {"Base32": "NBSQ"},
6498 {"Base32": "NBSWY"},
6499 {"Base32": "NBSWY3A"},
6500 {"Base32": "NBSWY3DP"}
6501 ]`,
6502 inVal: new([]structFormatBytes),
6503 wantErr: EU(func() error {
6504 _, err := base32.StdEncoding.Decode(make([]byte, 1), []byte("NA"))
6505 return err
6506 }()).withPos(`[`+"\n\t\t\t\t"+`{"Base32": `, "/0/Base32").withType('"', T[[]byte]()),
6507 }, {
6508 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base32/WrongAlphabet"),
6509 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6510 inBuf: `{"Base32": "0123456789ABCDEFGHIJKLMNOPQRSTUV"}`,
6511 inVal: new(structFormatBytes),
6512 wantErr: EU(func() error {
6513 _, err := base32.StdEncoding.Decode(make([]byte, 20), []byte("0123456789ABCDEFGHIJKLMNOPQRSTUV"))
6514 return err
6515 }()).withPos(`{"Base32": `, "/Base32").withType('"', T[[]byte]()),
6516 }, {
6517 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base32Hex/WrongAlphabet"),
6518 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6519 inBuf: `{"Base32Hex": "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"}`,
6520 inVal: new(structFormatBytes),
6521 wantErr: EU(func() error {
6522 _, err := base32.HexEncoding.Decode(make([]byte, 20), []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"))
6523 return err
6524 }()).withPos(`{"Base32Hex": `, "/Base32Hex").withType('"', T[[]byte]()),
6525 }, {
6526 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base32/NonAlphabet/LineFeed"),
6527 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6528 inBuf: `{"Base32": "AAAA\nAAAA"}`,
6529 inVal: new(structFormatBytes),
6530 wantErr: EU(errors.New("illegal character '\\n' at offset 4")).withPos(`{"Base32": `, "/Base32").withType('"', T[[]byte]()),
6531 }, {
6532 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base32/NonAlphabet/CarriageReturn"),
6533 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6534 inBuf: `{"Base32": "AAAA\rAAAA"}`,
6535 inVal: new(structFormatBytes),
6536 wantErr: EU(errors.New("illegal character '\\r' at offset 4")).withPos(`{"Base32": `, "/Base32").withType('"', T[[]byte]()),
6537 }, {
6538 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base32/NonAlphabet/Space"),
6539 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6540 inBuf: `{"Base32": "AAAA AAAA"}`,
6541 inVal: new(structFormatBytes),
6542 wantErr: EU(base32.CorruptInputError(4)).withPos(`{"Base32": `, "/Base32").withType('"', T[[]byte]()),
6543 }, {
6544 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base64/WrongAlphabet"),
6545 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6546 inBuf: `{"Base64": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"}`,
6547 inVal: new(structFormatBytes),
6548 wantErr: EU(func() error {
6549 _, err := base64.StdEncoding.Decode(make([]byte, 48), []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"))
6550 return err
6551 }()).withPos(`{"Base64": `, "/Base64").withType('"', T[[]byte]()),
6552 }, {
6553 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base64URL/WrongAlphabet"),
6554 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6555 inBuf: `{"Base64URL": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"}`,
6556 inVal: new(structFormatBytes),
6557 wantErr: EU(func() error {
6558 _, err := base64.URLEncoding.Decode(make([]byte, 48), []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"))
6559 return err
6560 }()).withPos(`{"Base64URL": `, "/Base64URL").withType('"', T[[]byte]()),
6561 }, {
6562 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base64/NonAlphabet/LineFeed"),
6563 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6564 inBuf: `{"Base64": "aa=\n="}`,
6565 inVal: new(structFormatBytes),
6566 wantErr: EU(errors.New("illegal character '\\n' at offset 3")).withPos(`{"Base64": `, "/Base64").withType('"', T[[]byte]()),
6567 }, {
6568 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base64/NonAlphabet/CarriageReturn"),
6569 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6570 inBuf: `{"Base64": "aa=\r="}`,
6571 inVal: new(structFormatBytes),
6572 wantErr: EU(errors.New("illegal character '\\r' at offset 3")).withPos(`{"Base64": `, "/Base64").withType('"', T[[]byte]()),
6573 }, {
6574 name: jsontest.Name("Structs/Format/Bytes/Base64/NonAlphabet/Ignored"),
6575 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true), jsonflags.ParseBytesWithLooseRFC4648 | 1},
6576 inBuf: `{"Base64": "aa=\r\n="}`,
6577 inVal: new(structFormatBytes),
6578 want: &structFormatBytes{Base64: []byte{105}},
6579 }, {
6580 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base64/NonAlphabet/Space"),
6581 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6582 inBuf: `{"Base64": "aa= ="}`,
6583 inVal: new(structFormatBytes),
6584 wantErr: EU(base64.CorruptInputError(2)).withPos(`{"Base64": `, "/Base64").withType('"', T[[]byte]()),
6585 }, {
6586 name: jsontest.Name("Structs/Format/Floats"),
6587 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6588 inBuf: `[
6589 {"NonFinite": 3.141592653589793, "PointerNonFinite": 3.141592653589793},
6590 {"NonFinite": "-Infinity", "PointerNonFinite": "-Infinity"},
6591 {"NonFinite": "Infinity", "PointerNonFinite": "Infinity"}
6592 ]`,
6593 inVal: new([]structFormatFloats),
6594 want: addr([]structFormatFloats{
6595 {NonFinite: math.Pi, PointerNonFinite: addr(math.Pi)},
6596 {NonFinite: math.Inf(-1), PointerNonFinite: addr(math.Inf(-1))},
6597 {NonFinite: math.Inf(+1), PointerNonFinite: addr(math.Inf(+1))},
6598 }),
6599 }, {
6600 name: jsontest.Name("Structs/Format/Floats/NaN"),
6601 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6602 inBuf: `{"NonFinite": "NaN"}`,
6603 inVal: new(structFormatFloats),
6604
6605 }, {
6606 name: jsontest.Name("Structs/Format/Floats/Invalid/NaN"),
6607 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6608 inBuf: `{"NonFinite": "nan"}`,
6609 inVal: new(structFormatFloats),
6610 wantErr: EU(nil).withPos(`{"NonFinite": `, "/NonFinite").withType('"', T[float64]()),
6611 }, {
6612 name: jsontest.Name("Structs/Format/Floats/Invalid/PositiveInfinity"),
6613 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6614 inBuf: `{"NonFinite": "+Infinity"}`,
6615 inVal: new(structFormatFloats),
6616 wantErr: EU(nil).withPos(`{"NonFinite": `, "/NonFinite").withType('"', T[float64]()),
6617 }, {
6618 name: jsontest.Name("Structs/Format/Floats/Invalid/NegativeInfinitySpace"),
6619 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6620 inBuf: `{"NonFinite": "-Infinity "}`,
6621 inVal: new(structFormatFloats),
6622 wantErr: EU(nil).withPos(`{"NonFinite": `, "/NonFinite").withType('"', T[float64]()),
6623 }, {
6624 name: jsontest.Name("Structs/Format/Maps"),
6625 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6626 inBuf: `[
6627 {"EmitNull": null, "PointerEmitNull": null, "EmitEmpty": null, "PointerEmitEmpty": null, "EmitDefault": null, "PointerEmitDefault": null},
6628 {"EmitNull": {}, "PointerEmitNull": {}, "EmitEmpty": {}, "PointerEmitEmpty": {}, "EmitDefault": {}, "PointerEmitDefault": {}},
6629 {"EmitNull": {"k": "v"}, "PointerEmitNull": {"k": "v"}, "EmitEmpty": {"k": "v"}, "PointerEmitEmpty": {"k": "v"}, "EmitDefault": {"k": "v"}, "PointerEmitDefault": {"k": "v"}}
6630 ]`,
6631 inVal: new([]structFormatMaps),
6632 want: addr([]structFormatMaps{{
6633 EmitNull: map[string]string(nil), PointerEmitNull: (*map[string]string)(nil),
6634 EmitEmpty: map[string]string(nil), PointerEmitEmpty: (*map[string]string)(nil),
6635 EmitDefault: map[string]string(nil), PointerEmitDefault: (*map[string]string)(nil),
6636 }, {
6637 EmitNull: map[string]string{}, PointerEmitNull: addr(map[string]string{}),
6638 EmitEmpty: map[string]string{}, PointerEmitEmpty: addr(map[string]string{}),
6639 EmitDefault: map[string]string{}, PointerEmitDefault: addr(map[string]string{}),
6640 }, {
6641 EmitNull: map[string]string{"k": "v"}, PointerEmitNull: addr(map[string]string{"k": "v"}),
6642 EmitEmpty: map[string]string{"k": "v"}, PointerEmitEmpty: addr(map[string]string{"k": "v"}),
6643 EmitDefault: map[string]string{"k": "v"}, PointerEmitDefault: addr(map[string]string{"k": "v"}),
6644 }}),
6645 }, {
6646 name: jsontest.Name("Structs/Format/Slices"),
6647 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6648 inBuf: `[
6649 {"EmitNull": null, "PointerEmitNull": null, "EmitEmpty": null, "PointerEmitEmpty": null, "EmitDefault": null, "PointerEmitDefault": null},
6650 {"EmitNull": [], "PointerEmitNull": [], "EmitEmpty": [], "PointerEmitEmpty": [], "EmitDefault": [], "PointerEmitDefault": []},
6651 {"EmitNull": ["v"], "PointerEmitNull": ["v"], "EmitEmpty": ["v"], "PointerEmitEmpty": ["v"], "EmitDefault": ["v"], "PointerEmitDefault": ["v"]}
6652 ]`,
6653 inVal: new([]structFormatSlices),
6654 want: addr([]structFormatSlices{{
6655 EmitNull: []string(nil), PointerEmitNull: (*[]string)(nil),
6656 EmitEmpty: []string(nil), PointerEmitEmpty: (*[]string)(nil),
6657 EmitDefault: []string(nil), PointerEmitDefault: (*[]string)(nil),
6658 }, {
6659 EmitNull: []string{}, PointerEmitNull: addr([]string{}),
6660 EmitEmpty: []string{}, PointerEmitEmpty: addr([]string{}),
6661 EmitDefault: []string{}, PointerEmitDefault: addr([]string{}),
6662 }, {
6663 EmitNull: []string{"v"}, PointerEmitNull: addr([]string{"v"}),
6664 EmitEmpty: []string{"v"}, PointerEmitEmpty: addr([]string{"v"}),
6665 EmitDefault: []string{"v"}, PointerEmitDefault: addr([]string{"v"}),
6666 }}),
6667 }, {
6668 name: jsontest.Name("Structs/Format/Invalid/Bool"),
6669 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6670 inBuf: `{"Bool":true}`,
6671 inVal: new(structFormatInvalid),
6672 wantErr: EU(errInvalidFormatFlag).withPos(`{"Bool":`, "/Bool").withType(0, T[bool]()),
6673 }, {
6674 name: jsontest.Name("Structs/Format/Invalid/String"),
6675 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6676 inBuf: `{"String": "string"}`,
6677 inVal: new(structFormatInvalid),
6678 wantErr: EU(errInvalidFormatFlag).withPos(`{"String": `, "/String").withType(0, T[string]()),
6679 }, {
6680 name: jsontest.Name("Structs/Format/Invalid/Bytes"),
6681 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6682 inBuf: `{"Bytes": "bytes"}`,
6683 inVal: new(structFormatInvalid),
6684 wantErr: EU(errInvalidFormatFlag).withPos(`{"Bytes": `, "/Bytes").withType(0, T[[]byte]()),
6685 }, {
6686 name: jsontest.Name("Structs/Format/Invalid/Int"),
6687 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6688 inBuf: `{"Int": 1}`,
6689 inVal: new(structFormatInvalid),
6690 wantErr: EU(errInvalidFormatFlag).withPos(`{"Int": `, "/Int").withType(0, T[int64]()),
6691 }, {
6692 name: jsontest.Name("Structs/Format/Invalid/Uint"),
6693 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6694 inBuf: `{"Uint": 1}`,
6695 inVal: new(structFormatInvalid),
6696 wantErr: EU(errInvalidFormatFlag).withPos(`{"Uint": `, "/Uint").withType(0, T[uint64]()),
6697 }, {
6698 name: jsontest.Name("Structs/Format/Invalid/Float"),
6699 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6700 inBuf: `{"Float" : 1}`,
6701 inVal: new(structFormatInvalid),
6702 wantErr: EU(errInvalidFormatFlag).withPos(`{"Float" : `, "/Float").withType(0, T[float64]()),
6703 }, {
6704 name: jsontest.Name("Structs/Format/Invalid/Map"),
6705 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6706 inBuf: `{"Map":{}}`,
6707 inVal: new(structFormatInvalid),
6708 wantErr: EU(errInvalidFormatFlag).withPos(`{"Map":`, "/Map").withType(0, T[map[string]string]()),
6709 }, {
6710 name: jsontest.Name("Structs/Format/Invalid/Struct"),
6711 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6712 inBuf: `{"Struct": {}}`,
6713 inVal: new(structFormatInvalid),
6714 wantErr: EU(errInvalidFormatFlag).withPos(`{"Struct": `, "/Struct").withType(0, T[structAll]()),
6715 }, {
6716 name: jsontest.Name("Structs/Format/Invalid/Slice"),
6717 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6718 inBuf: `{"Slice": {}}`,
6719 inVal: new(structFormatInvalid),
6720 wantErr: EU(errInvalidFormatFlag).withPos(`{"Slice": `, "/Slice").withType(0, T[[]string]()),
6721 }, {
6722 name: jsontest.Name("Structs/Format/Invalid/Array"),
6723 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6724 inBuf: `{"Array": []}`,
6725 inVal: new(structFormatInvalid),
6726 wantErr: EU(errInvalidFormatFlag).withPos(`{"Array": `, "/Array").withType(0, T[[1]string]()),
6727 }, {
6728 name: jsontest.Name("Structs/Format/Invalid/Interface"),
6729 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
6730 inBuf: `{"Interface": "anything"}`,
6731 inVal: new(structFormatInvalid),
6732 wantErr: EU(errInvalidFormatFlag).withPos(`{"Interface": `, "/Interface").withType(0, T[any]()),
6733 }, {
6734 name: jsontest.Name("Structs/Embed/Zero"),
6735 inBuf: `{"D":""}`,
6736 inVal: new(structEmbedded),
6737 want: new(structEmbedded),
6738 }, {
6739 name: jsontest.Name("Structs/Embed/Alloc"),
6740 inBuf: `{"E":"","F":"","G":"","A":"","B":"","D":""}`,
6741 inVal: new(structEmbedded),
6742 want: addr(structEmbedded{
6743 X: structEmbeddedL1{
6744 X: &structEmbeddedL2{},
6745 StructEmbed1: StructEmbed1{},
6746 },
6747 StructEmbed2: &StructEmbed2{},
6748 }),
6749 }, {
6750 name: jsontest.Name("Structs/Embed/NonZero"),
6751 inBuf: `{"E":"E3","F":"F3","G":"G3","A":"A1","B":"B1","D":"D2"}`,
6752 inVal: new(structEmbedded),
6753 want: addr(structEmbedded{
6754 X: structEmbeddedL1{
6755 X: &structEmbeddedL2{A: "A1", B: "B1" },
6756 StructEmbed1: StructEmbed1{ D: "D2" },
6757 },
6758 StructEmbed2: &StructEmbed2{E: "E3", F: "F3", G: "G3"},
6759 }),
6760 }, {
6761 name: jsontest.Name("Structs/Embed/Merge"),
6762 inBuf: `{"E":"E3","F":"F3","G":"G3","A":"A1","B":"B1","D":"D2"}`,
6763 inVal: addr(structEmbedded{
6764 X: structEmbeddedL1{
6765 X: &structEmbeddedL2{B: "##", C: "C1"},
6766 StructEmbed1: StructEmbed1{C: "C2", E: "E2"},
6767 },
6768 StructEmbed2: &StructEmbed2{E: "##", G: "G3"},
6769 }),
6770 want: addr(structEmbedded{
6771 X: structEmbeddedL1{
6772 X: &structEmbeddedL2{A: "A1", B: "B1", C: "C1"},
6773 StructEmbed1: StructEmbed1{C: "C2", D: "D2", E: "E2"},
6774 },
6775 StructEmbed2: &StructEmbed2{E: "E3", F: "F3", G: "G3"},
6776 }),
6777 }, {
6778 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/Noop"),
6779 inBuf: `{"A":1,"B":2}`,
6780 inVal: new(structEmbedTextValue),
6781 want: addr(structEmbedTextValue{A: 1, X: jsontext.Value(nil), B: 2}),
6782 }, {
6783 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/MergeN1/Nil"),
6784 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6785 inVal: new(structEmbedTextValue),
6786 want: addr(structEmbedTextValue{A: 1, X: jsontext.Value(`{"fizz":"buzz"}`), B: 2}),
6787 }, {
6788 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/MergeN1/Empty"),
6789 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6790 inVal: addr(structEmbedTextValue{X: jsontext.Value{}}),
6791 want: addr(structEmbedTextValue{A: 1, X: jsontext.Value(`{"fizz":"buzz"}`), B: 2}),
6792 }, {
6793 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/MergeN1/Whitespace"),
6794 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6795 inVal: addr(structEmbedTextValue{X: jsontext.Value("\n\r\t ")}),
6796 want: addr(structEmbedTextValue{A: 1, X: jsontext.Value("")}),
6797 wantErr: EU(errRawEmbedNotObject).withPos(`{"A":1,`, "/fizz").withType('"', T[jsontext.Value]()),
6798 }, {
6799 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/MergeN1/Null"),
6800 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6801 inVal: addr(structEmbedTextValue{X: jsontext.Value("null")}),
6802 want: addr(structEmbedTextValue{A: 1, X: jsontext.Value("null")}),
6803 wantErr: EU(errRawEmbedNotObject).withPos(`{"A":1,`, "/fizz").withType('"', T[jsontext.Value]()),
6804 }, {
6805 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/MergeN1/ObjectN0"),
6806 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6807 inVal: addr(structEmbedTextValue{X: jsontext.Value(` { } `)}),
6808 want: addr(structEmbedTextValue{A: 1, X: jsontext.Value(` {"fizz":"buzz"}`), B: 2}),
6809 }, {
6810 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/MergeN2/ObjectN1"),
6811 inBuf: `{"A":1,"fizz":"buzz","B":2,"foo": [ 1 , 2 , 3 ]}`,
6812 inVal: addr(structEmbedTextValue{X: jsontext.Value(` { "fizz" : "buzz" } `)}),
6813 want: addr(structEmbedTextValue{A: 1, X: jsontext.Value(` { "fizz" : "buzz","fizz":"buzz","foo":[ 1 , 2 , 3 ]}`), B: 2}),
6814 }, {
6815 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/Merge/EndObject"),
6816 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6817 inVal: addr(structEmbedTextValue{X: jsontext.Value(` } `)}),
6818
6819
6820 want: addr(structEmbedTextValue{A: 1, X: jsontext.Value(`,"fizz":"buzz"}`), B: 2}),
6821 }, {
6822 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/MergeInvalidValue"),
6823 inBuf: `{"A":1,"fizz":nil,"B":2}`,
6824 inVal: new(structEmbedTextValue),
6825 want: addr(structEmbedTextValue{A: 1, X: jsontext.Value(`{"fizz":`)}),
6826 wantErr: newInvalidCharacterError("i", "in literal null (expecting 'u')", len64(`{"A":1,"fizz":n`), "/fizz"),
6827 }, {
6828 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/CaseSensitive"),
6829 inBuf: `{"A":1,"fizz":"buzz","B":2,"a":3}`,
6830 inVal: new(structEmbedTextValue),
6831 want: addr(structEmbedTextValue{A: 1, X: jsontext.Value(`{"fizz":"buzz","a":3}`), B: 2}),
6832 }, {
6833 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/RejectDuplicateNames"),
6834 opts: []Options{jsontext.AllowDuplicateNames(false)},
6835 inBuf: `{"A":1,"fizz":"buzz","B":2,"fizz":"buzz"}`,
6836 inVal: new(structEmbedTextValue),
6837 want: addr(structEmbedTextValue{A: 1, X: jsontext.Value(`{"fizz":"buzz"}`), B: 2}),
6838 wantErr: newDuplicateNameError("", []byte(`"fizz"`), len64(`{"A":1,"fizz":"buzz","B":2,`)),
6839 }, {
6840 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/AllowDuplicateNames"),
6841 opts: []Options{jsontext.AllowDuplicateNames(true)},
6842 inBuf: `{"A":1,"fizz":"buzz","B":2,"fizz":"buzz"}`,
6843 inVal: new(structEmbedTextValue),
6844 want: addr(structEmbedTextValue{A: 1, X: jsontext.Value(`{"fizz":"buzz","fizz":"buzz"}`), B: 2}),
6845 }, {
6846 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/Nested/Noop"),
6847 inBuf: `{}`,
6848 inVal: new(structEmbedPointerEmbedTextValue),
6849 want: new(structEmbedPointerEmbedTextValue),
6850 }, {
6851 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/Nested/Alloc"),
6852 inBuf: `{"A":1,"fizz":"buzz"}`,
6853 inVal: new(structEmbedPointerEmbedTextValue),
6854 want: addr(structEmbedPointerEmbedTextValue{
6855 X: &struct {
6856 A int
6857 X jsontext.Value `json:",embed"`
6858 }{A: 1, X: jsontext.Value(`{"fizz":"buzz"}`)},
6859 }),
6860 }, {
6861 name: jsontest.Name("Structs/EmbeddedFallback/TextValue/Nested/Merge"),
6862 inBuf: `{"fizz":"buzz"}`,
6863 inVal: addr(structEmbedPointerEmbedTextValue{
6864 X: &struct {
6865 A int
6866 X jsontext.Value `json:",embed"`
6867 }{A: 1},
6868 }),
6869 want: addr(structEmbedPointerEmbedTextValue{
6870 X: &struct {
6871 A int
6872 X jsontext.Value `json:",embed"`
6873 }{A: 1, X: jsontext.Value(`{"fizz":"buzz"}`)},
6874 }),
6875 }, {
6876 name: jsontest.Name("Structs/EmbeddedFallback/PointerTextValue/Noop"),
6877 inBuf: `{"A":1,"B":2}`,
6878 inVal: new(structEmbedPointerTextValue),
6879 want: addr(structEmbedPointerTextValue{A: 1, X: nil, B: 2}),
6880 }, {
6881 name: jsontest.Name("Structs/EmbeddedFallback/PointerTextValue/Alloc"),
6882 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6883 inVal: new(structEmbedPointerTextValue),
6884 want: addr(structEmbedPointerTextValue{A: 1, X: addr(jsontext.Value(`{"fizz":"buzz"}`)), B: 2}),
6885 }, {
6886 name: jsontest.Name("Structs/EmbeddedFallback/PointerTextValue/Merge"),
6887 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6888 inVal: addr(structEmbedPointerTextValue{X: addr(jsontext.Value(`{"fizz":"buzz"}`))}),
6889 want: addr(structEmbedPointerTextValue{A: 1, X: addr(jsontext.Value(`{"fizz":"buzz","fizz":"buzz"}`)), B: 2}),
6890 }, {
6891 name: jsontest.Name("Structs/EmbeddedFallback/PointerTextValue/Nested/Nil"),
6892 inBuf: `{"fizz":"buzz"}`,
6893 inVal: new(structEmbedEmbedPointerTextValue),
6894 want: addr(structEmbedEmbedPointerTextValue{
6895 X: struct {
6896 X *jsontext.Value `json:",embed"`
6897 }{X: addr(jsontext.Value(`{"fizz":"buzz"}`))},
6898 }),
6899 }, {
6900 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/Noop"),
6901 inBuf: `{"A":1,"B":2}`,
6902 inVal: new(structEmbedMapStringAny),
6903 want: addr(structEmbedMapStringAny{A: 1, X: nil, B: 2}),
6904 }, {
6905 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/MergeN1/Nil"),
6906 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6907 inVal: new(structEmbedMapStringAny),
6908 want: addr(structEmbedMapStringAny{A: 1, X: jsonObject{"fizz": "buzz"}, B: 2}),
6909 }, {
6910 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/MergeN1/Empty"),
6911 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6912 inVal: addr(structEmbedMapStringAny{X: jsonObject{}}),
6913 want: addr(structEmbedMapStringAny{A: 1, X: jsonObject{"fizz": "buzz"}, B: 2}),
6914 }, {
6915 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/MergeN1/ObjectN1"),
6916 inBuf: `{"A":1,"fizz":{"charlie":"DELTA","echo":"foxtrot"},"B":2}`,
6917 inVal: addr(structEmbedMapStringAny{X: jsonObject{"fizz": jsonObject{
6918 "alpha": "bravo",
6919 "charlie": "delta",
6920 }}}),
6921 want: addr(structEmbedMapStringAny{A: 1, X: jsonObject{"fizz": jsonObject{
6922 "alpha": "bravo",
6923 "charlie": "DELTA",
6924 "echo": "foxtrot",
6925 }}, B: 2}),
6926 }, {
6927 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/MergeN2/ObjectN1"),
6928 inBuf: `{"A":1,"fizz":"buzz","B":2,"foo": [ 1 , 2 , 3 ]}`,
6929 inVal: addr(structEmbedMapStringAny{X: jsonObject{"fizz": "wuzz"}}),
6930 want: addr(structEmbedMapStringAny{A: 1, X: jsonObject{"fizz": "buzz", "foo": jsonArray{1.0, 2.0, 3.0}}, B: 2}),
6931 }, {
6932 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/MergeInvalidValue"),
6933 inBuf: `{"A":1,"fizz":nil,"B":2}`,
6934 inVal: new(structEmbedMapStringAny),
6935 want: addr(structEmbedMapStringAny{A: 1, X: jsonObject{"fizz": nil}}),
6936 wantErr: newInvalidCharacterError("i", "in literal null (expecting 'u')", len64(`{"A":1,"fizz":n`), "/fizz"),
6937 }, {
6938 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/MergeInvalidValue/Existing"),
6939 inBuf: `{"A":1,"fizz":nil,"B":2}`,
6940 inVal: addr(structEmbedMapStringAny{A: 1, X: jsonObject{"fizz": true}}),
6941 want: addr(structEmbedMapStringAny{A: 1, X: jsonObject{"fizz": true}}),
6942 wantErr: newInvalidCharacterError("i", "in literal null (expecting 'u')", len64(`{"A":1,"fizz":n`), "/fizz"),
6943 }, {
6944 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/CaseSensitive"),
6945 inBuf: `{"A":1,"fizz":"buzz","B":2,"a":3}`,
6946 inVal: new(structEmbedMapStringAny),
6947 want: addr(structEmbedMapStringAny{A: 1, X: jsonObject{"fizz": "buzz", "a": 3.0}, B: 2}),
6948 }, {
6949 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/RejectDuplicateNames"),
6950 opts: []Options{jsontext.AllowDuplicateNames(false)},
6951 inBuf: `{"A":1,"fizz":"buzz","B":2,"fizz":"buzz"}`,
6952 inVal: new(structEmbedMapStringAny),
6953 want: addr(structEmbedMapStringAny{A: 1, X: jsonObject{"fizz": "buzz"}, B: 2}),
6954 wantErr: newDuplicateNameError("", []byte(`"fizz"`), len64(`{"A":1,"fizz":"buzz","B":2,`)),
6955 }, {
6956 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/AllowDuplicateNames"),
6957 opts: []Options{jsontext.AllowDuplicateNames(true)},
6958 inBuf: `{"A":1,"fizz":{"one":1,"two":-2},"B":2,"fizz":{"two":2,"three":3}}`,
6959 inVal: new(structEmbedMapStringAny),
6960 want: addr(structEmbedMapStringAny{A: 1, X: jsonObject{"fizz": jsonObject{"one": 1.0, "two": 2.0, "three": 3.0}}, B: 2}),
6961 }, {
6962 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/Nested/Noop"),
6963 inBuf: `{}`,
6964 inVal: new(structEmbedPointerEmbedMapStringAny),
6965 want: new(structEmbedPointerEmbedMapStringAny),
6966 }, {
6967 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/Nested/Alloc"),
6968 inBuf: `{"A":1,"fizz":"buzz"}`,
6969 inVal: new(structEmbedPointerEmbedMapStringAny),
6970 want: addr(structEmbedPointerEmbedMapStringAny{
6971 X: &struct {
6972 A int
6973 X jsonObject `json:",embed"`
6974 }{A: 1, X: jsonObject{"fizz": "buzz"}},
6975 }),
6976 }, {
6977 name: jsontest.Name("Structs/EmbeddedFallback/MapStringAny/Nested/Merge"),
6978 inBuf: `{"fizz":"buzz"}`,
6979 inVal: addr(structEmbedPointerEmbedMapStringAny{
6980 X: &struct {
6981 A int
6982 X jsonObject `json:",embed"`
6983 }{A: 1},
6984 }),
6985 want: addr(structEmbedPointerEmbedMapStringAny{
6986 X: &struct {
6987 A int
6988 X jsonObject `json:",embed"`
6989 }{A: 1, X: jsonObject{"fizz": "buzz"}},
6990 }),
6991 }, {
6992 name: jsontest.Name("Structs/EmbeddedFallback/MapStringInt/UnmarshalFunc"),
6993 opts: []Options{
6994 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *any) error {
6995 var err error
6996 *v, err = strconv.ParseFloat(string(bytes.Trim(b, `"`)), 64)
6997 return err
6998 })),
6999 },
7000 inBuf: `{"D":"1.1","E":"2.2","F":"3.3"}`,
7001 inVal: new(structEmbedMapStringAny),
7002 want: addr(structEmbedMapStringAny{X: jsonObject{"D": 1.1, "E": 2.2, "F": 3.3}}),
7003 }, {
7004 name: jsontest.Name("Structs/EmbeddedFallback/PointerMapStringAny/Noop"),
7005 inBuf: `{"A":1,"B":2}`,
7006 inVal: new(structEmbedPointerMapStringAny),
7007 want: addr(structEmbedPointerMapStringAny{A: 1, X: nil, B: 2}),
7008 }, {
7009 name: jsontest.Name("Structs/EmbeddedFallback/PointerMapStringAny/Alloc"),
7010 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
7011 inVal: new(structEmbedPointerMapStringAny),
7012 want: addr(structEmbedPointerMapStringAny{A: 1, X: addr(jsonObject{"fizz": "buzz"}), B: 2}),
7013 }, {
7014 name: jsontest.Name("Structs/EmbeddedFallback/PointerMapStringAny/Merge"),
7015 inBuf: `{"A":1,"fizz":"wuzz","B":2}`,
7016 inVal: addr(structEmbedPointerMapStringAny{X: addr(jsonObject{"fizz": "buzz"})}),
7017 want: addr(structEmbedPointerMapStringAny{A: 1, X: addr(jsonObject{"fizz": "wuzz"}), B: 2}),
7018 }, {
7019 name: jsontest.Name("Structs/EmbeddedFallback/PointerMapStringAny/Nested/Nil"),
7020 inBuf: `{"fizz":"buzz"}`,
7021 inVal: new(structEmbedEmbedPointerMapStringAny),
7022 want: addr(structEmbedEmbedPointerMapStringAny{
7023 X: struct {
7024 X *jsonObject `json:",embed"`
7025 }{X: addr(jsonObject{"fizz": "buzz"})},
7026 }),
7027 }, {
7028 name: jsontest.Name("Structs/EmbeddedFallback/MapStringInt"),
7029 inBuf: `{"zero": 0, "one": 1, "two": 2}`,
7030 inVal: new(structEmbedMapStringInt),
7031 want: addr(structEmbedMapStringInt{
7032 X: map[string]int{"zero": 0, "one": 1, "two": 2},
7033 }),
7034 }, {
7035 name: jsontest.Name("Structs/EmbeddedFallback/MapStringInt/Null"),
7036 inBuf: `{"zero": 0, "one": null, "two": 2}`,
7037 inVal: new(structEmbedMapStringInt),
7038 want: addr(structEmbedMapStringInt{
7039 X: map[string]int{"zero": 0, "one": 0, "two": 2},
7040 }),
7041 }, {
7042 name: jsontest.Name("Structs/EmbeddedFallback/MapStringInt/Invalid"),
7043 inBuf: `{"zero": 0, "one": {}, "two": 2}`,
7044 inVal: new(structEmbedMapStringInt),
7045 want: addr(structEmbedMapStringInt{
7046 X: map[string]int{"zero": 0, "one": 0},
7047 }),
7048 wantErr: EU(nil).withPos(`{"zero": 0, "one": `, "/one").withType('{', T[int]()),
7049 }, {
7050 name: jsontest.Name("Structs/EmbeddedFallback/MapStringInt/StringifiedNumbers"),
7051 opts: []Options{StringifyNumbers(true)},
7052 inBuf: `{"zero": "0", "one": "1", "two": "2"}`,
7053 inVal: new(structEmbedMapStringInt),
7054 want: addr(structEmbedMapStringInt{
7055 X: map[string]int{"zero": 0, "one": 1, "two": 2},
7056 }),
7057 }, {
7058 name: jsontest.Name("Structs/EmbeddedFallback/MapStringInt/UnmarshalFunc"),
7059 opts: []Options{
7060 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *int) error {
7061 i, err := strconv.ParseInt(string(bytes.Trim(b, `"`)), 10, 64)
7062 if err != nil {
7063 return err
7064 }
7065 *v = int(i)
7066 return nil
7067 })),
7068 },
7069 inBuf: `{"zero": "0", "one": "1", "two": "2"}`,
7070 inVal: new(structEmbedMapStringInt),
7071 want: addr(structEmbedMapStringInt{
7072 X: map[string]int{"zero": 0, "one": 1, "two": 2},
7073 }),
7074 }, {
7075 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringInt"),
7076 inBuf: `{"zero": 0, "one": 1, "two": 2}`,
7077 inVal: new(structEmbedMapNamedStringInt),
7078 want: addr(structEmbedMapNamedStringInt{
7079 X: map[namedString]int{"zero": 0, "one": 1, "two": 2},
7080 }),
7081 }, {
7082 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringInt/Null"),
7083 inBuf: `{"zero": 0, "one": null, "two": 2}`,
7084 inVal: new(structEmbedMapNamedStringInt),
7085 want: addr(structEmbedMapNamedStringInt{
7086 X: map[namedString]int{"zero": 0, "one": 0, "two": 2},
7087 }),
7088 }, {
7089 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringInt/Invalid"),
7090 inBuf: `{"zero": 0, "one": {}, "two": 2}`,
7091 inVal: new(structEmbedMapNamedStringInt),
7092 want: addr(structEmbedMapNamedStringInt{
7093 X: map[namedString]int{"zero": 0, "one": 0},
7094 }),
7095 wantErr: EU(nil).withPos(`{"zero": 0, "one": `, "/one").withType('{', T[int]()),
7096 }, {
7097 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringInt/StringifiedNumbers"),
7098 opts: []Options{StringifyNumbers(true)},
7099 inBuf: `{"zero": "0", "one": 1, "two": "2"}`,
7100 inVal: new(structEmbedMapNamedStringInt),
7101 want: addr(structEmbedMapNamedStringInt{
7102 X: map[namedString]int{"zero": 0, "one": 0},
7103 }),
7104 wantErr: EU(nil).withPos(`{"zero": "0", "one": `, "/one").withType('0', T[int]()),
7105 }, {
7106 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringInt/UnmarshalFunc"),
7107 opts: []Options{
7108 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *int) error {
7109 i, err := strconv.ParseInt(string(bytes.Trim(b, `"`)), 10, 64)
7110 if err != nil {
7111 return err
7112 }
7113 *v = int(i)
7114 return nil
7115 })),
7116 },
7117 inBuf: `{"zero": "0", "one": "1", "two": "2"}`,
7118 inVal: new(structEmbedMapNamedStringInt),
7119 want: addr(structEmbedMapNamedStringInt{
7120 X: map[namedString]int{"zero": 0, "one": 1, "two": 2},
7121 }),
7122 }, {
7123 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/Noop"),
7124 inBuf: `{"A":1,"B":2}`,
7125 inVal: new(structEmbedMapNamedStringAny),
7126 want: addr(structEmbedMapNamedStringAny{A: 1, X: nil, B: 2}),
7127 }, {
7128 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/MergeN1/Nil"),
7129 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
7130 inVal: new(structEmbedMapNamedStringAny),
7131 want: addr(structEmbedMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": "buzz"}, B: 2}),
7132 }, {
7133 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/MergeN1/Empty"),
7134 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
7135 inVal: addr(structEmbedMapNamedStringAny{X: map[namedString]any{}}),
7136 want: addr(structEmbedMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": "buzz"}, B: 2}),
7137 }, {
7138 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/MergeN1/ObjectN1"),
7139 inBuf: `{"A":1,"fizz":{"charlie":"DELTA","echo":"foxtrot"},"B":2}`,
7140 inVal: addr(structEmbedMapNamedStringAny{X: map[namedString]any{"fizz": jsonObject{
7141 "alpha": "bravo",
7142 "charlie": "delta",
7143 }}}),
7144 want: addr(structEmbedMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": jsonObject{
7145 "alpha": "bravo",
7146 "charlie": "DELTA",
7147 "echo": "foxtrot",
7148 }}, B: 2}),
7149 }, {
7150 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/MergeN2/ObjectN1"),
7151 inBuf: `{"A":1,"fizz":"buzz","B":2,"foo": [ 1 , 2 , 3 ]}`,
7152 inVal: addr(structEmbedMapNamedStringAny{X: map[namedString]any{"fizz": "wuzz"}}),
7153 want: addr(structEmbedMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": "buzz", "foo": jsonArray{1.0, 2.0, 3.0}}, B: 2}),
7154 }, {
7155 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/MergeInvalidValue"),
7156 inBuf: `{"A":1,"fizz":nil,"B":2}`,
7157 inVal: new(structEmbedMapNamedStringAny),
7158 want: addr(structEmbedMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": nil}}),
7159 wantErr: newInvalidCharacterError("i", "in literal null (expecting 'u')", len64(`{"A":1,"fizz":n`), "/fizz"),
7160 }, {
7161 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/MergeInvalidValue/Existing"),
7162 inBuf: `{"A":1,"fizz":nil,"B":2}`,
7163 inVal: addr(structEmbedMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": true}}),
7164 want: addr(structEmbedMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": true}}),
7165 wantErr: newInvalidCharacterError("i", "in literal null (expecting 'u')", len64(`{"A":1,"fizz":n`), "/fizz"),
7166 }, {
7167 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/CaseSensitive"),
7168 inBuf: `{"A":1,"fizz":"buzz","B":2,"a":3}`,
7169 inVal: new(structEmbedMapNamedStringAny),
7170 want: addr(structEmbedMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": "buzz", "a": 3.0}, B: 2}),
7171 }, {
7172 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/RejectDuplicateNames"),
7173 opts: []Options{jsontext.AllowDuplicateNames(false)},
7174 inBuf: `{"A":1,"fizz":"buzz","B":2,"fizz":"buzz"}`,
7175 inVal: new(structEmbedMapNamedStringAny),
7176 want: addr(structEmbedMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": "buzz"}, B: 2}),
7177 wantErr: newDuplicateNameError("", []byte(`"fizz"`), len64(`{"A":1,"fizz":"buzz","B":2,`)),
7178 }, {
7179 name: jsontest.Name("Structs/EmbeddedFallback/MapNamedStringAny/AllowDuplicateNames"),
7180 opts: []Options{jsontext.AllowDuplicateNames(true)},
7181 inBuf: `{"A":1,"fizz":{"one":1,"two":-2},"B":2,"fizz":{"two":2,"three":3}}`,
7182 inVal: new(structEmbedMapNamedStringAny),
7183 want: addr(structEmbedMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": map[string]any{"one": 1.0, "two": 2.0, "three": 3.0}}, B: 2}),
7184 }, {
7185 name: jsontest.Name("Structs/EmbeddedFallback/RejectUnknownMembers"),
7186 opts: []Options{RejectUnknownMembers(true)},
7187 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
7188 inVal: new(structEmbedTextValue),
7189 want: addr(structEmbedTextValue{
7190 A: 1,
7191 X: jsontext.Value(`{"fizz":"buzz"}`),
7192 B: 2,
7193 }),
7194 }, {
7195 name: jsontest.Name("Structs/UnknownIgnored"),
7196 opts: []Options{RejectUnknownMembers(false)},
7197 inBuf: `{"unknown":"fizzbuzz"}`,
7198 inVal: new(structAll),
7199 want: new(structAll),
7200 }, {
7201 name: jsontest.Name("Structs/RejectUnknownMembers"),
7202 opts: []Options{RejectUnknownMembers(true)},
7203 inBuf: `{"unknown":"fizzbuzz"}`,
7204 inVal: new(structAll),
7205 want: new(structAll),
7206 wantErr: EU(ErrUnknownName).withPos(`{`, "/unknown").withType('"', T[structAll]()),
7207 }, {
7208 name: jsontest.Name("Structs/UnexportedIgnored"),
7209 inBuf: `{"ignored":"unused"}`,
7210 inVal: new(structUnexportedIgnored),
7211 want: new(structUnexportedIgnored),
7212 }, {
7213 name: jsontest.Name("Structs/IgnoredUnexportedEmbedded"),
7214 inBuf: `{"namedString":"unused"}`,
7215 inVal: new(structIgnoredUnexportedEmbedded),
7216 want: new(structIgnoredUnexportedEmbedded),
7217 }, {
7218 name: jsontest.Name("Structs/NoCase/Exact"),
7219 inBuf: `{"Aaa":"Aaa","AA_A":"AA_A","AaA":"AaA","AAa":"AAa","AAA":"AAA"}`,
7220 inVal: new(structNoCase),
7221 want: addr(structNoCase{AaA: "AaA", AAa: "AAa", Aaa: "Aaa", AAA: "AAA", AA_A: "AA_A"}),
7222 }, {
7223 name: jsontest.Name("Structs/NoCase/CaseInsensitiveDefault/Ambiguous"),
7224 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
7225 inBuf: `{"aa_a":"aa_a"}`,
7226 inVal: new(structNoCase),
7227 want: addr(structNoCase{AaA: "aa_a"}),
7228 }, {
7229 name: jsontest.Name("Structs/NoCase/CaseInsensitiveDefault/Ambiguous"),
7230 inBuf: `{"aa_a":"aa_a"}`,
7231 inVal: new(structNoCase),
7232 want: addr(structNoCase{}),
7233 wantErr: EU(errAmbiguousName).withPos(`{`, "/aa_a").withType('"', T[structNoCase]()),
7234 }, {
7235 name: jsontest.Name("Structs/NoCase/MatchCaseSensitiveDelimiter"),
7236 opts: []Options{jsonflags.MatchCaseSensitiveDelimiter | 1},
7237 inBuf: `{"aa_a":"aa_a"}`,
7238 inVal: new(structNoCase),
7239 want: addr(structNoCase{}),
7240 }, {
7241 name: jsontest.Name("Structs/NoCase/MatchCaseInsensitiveNames+MatchCaseSensitiveDelimiter"),
7242 opts: []Options{MatchCaseInsensitiveNames(true), jsonflags.MatchCaseSensitiveDelimiter | 1},
7243 inBuf: `{"aa_a":"aa_a"}`,
7244 inVal: new(structNoCase),
7245 want: addr(structNoCase{AA_A: "aa_a"}),
7246 }, {
7247 name: jsontest.Name("Structs/NoCase/Merge/AllowDuplicateNames"),
7248 opts: []Options{jsontext.AllowDuplicateNames(true), jsonflags.ReportErrorsWithLegacySemantics | 1},
7249 inBuf: `{"AaA":"AaA","aaa":"aaa","aAa":"aAa"}`,
7250 inVal: new(structNoCase),
7251 want: addr(structNoCase{AaA: "aAa"}),
7252 }, {
7253 name: jsontest.Name("Structs/NoCase/Merge/AllowDuplicateNames/Ambiguous"),
7254 opts: []Options{jsontext.AllowDuplicateNames(true)},
7255 inBuf: `{"AaA":"AaA","aaa":"aaa","aAa":"aAa"}`,
7256 inVal: new(structNoCase),
7257 want: addr(structNoCase{AaA: "AaA"}),
7258 wantErr: EU(errAmbiguousName).withPos(`{"AaA":"AaA",`, "/aaa").withType('"', T[structNoCase]()),
7259 }, {
7260 name: jsontest.Name("Structs/NoCase/Merge/RejectDuplicateNames/Ambiguous"),
7261 opts: []Options{jsontext.AllowDuplicateNames(false)},
7262 inBuf: `{"AaA":"AaA","aaa":"aaa"}`,
7263 inVal: new(structNoCase),
7264 want: addr(structNoCase{AaA: "AaA"}),
7265 wantErr: EU(errAmbiguousName).withPos(`{"AaA":"AaA",`, "/aaa").withType('"', T[structNoCase]()),
7266 }, {
7267 name: jsontest.Name("Structs/CaseSensitive"),
7268 inBuf: `{"BOOL": true, "STRING": "hello", "BYTES": "AQID", "INT": -64, "UINT": 64, "FLOAT": 3.14159}`,
7269 inVal: new(structScalars),
7270 want: addr(structScalars{}),
7271 }, {
7272 name: jsontest.Name("Structs/DuplicateName/NoCase/ExactDifferent"),
7273 inBuf: `{"AAA":"AAA","AaA":"AaA","AAa":"AAa","Aaa":"Aaa"}`,
7274 inVal: addr(structNoCaseEmbedTextValue{}),
7275 want: addr(structNoCaseEmbedTextValue{AAA: "AAA", AaA: "AaA", AAa: "AAa", Aaa: "Aaa"}),
7276 }, {
7277 name: jsontest.Name("Structs/DuplicateName/NoCase/ExactConflict"),
7278 inBuf: `{"AAA":"AAA","AAA":"AAA"}`,
7279 inVal: addr(structNoCaseEmbedTextValue{}),
7280 want: addr(structNoCaseEmbedTextValue{AAA: "AAA"}),
7281 wantErr: newDuplicateNameError("", []byte(`"AAA"`), len64(`{"AAA":"AAA",`)),
7282 }, {
7283 name: jsontest.Name("Structs/DuplicateName/NoCase/OverwriteExact"),
7284 inBuf: `{"AAA":"after"}`,
7285 inVal: addr(structNoCaseEmbedTextValue{AAA: "before"}),
7286 want: addr(structNoCaseEmbedTextValue{AAA: "after"}),
7287 }, {
7288 name: jsontest.Name("Structs/AmbiguousName/NoCase"),
7289 inBuf: `{"aaa":"aaa"}`,
7290 inVal: addr(structNoCaseEmbedTextValue{}),
7291 want: addr(structNoCaseEmbedTextValue{}),
7292 wantErr: EU(errAmbiguousName).withPos(`{`, "/aaa").withType('"', T[structNoCaseEmbedTextValue]()),
7293 }, {
7294 name: jsontest.Name("Structs/DuplicateName/Embed/Unknown"),
7295 inBuf: `{"unknown":""}`,
7296 inVal: addr(structNoCaseEmbedTextValue{}),
7297 want: addr(structNoCaseEmbedTextValue{X: jsontext.Value(`{"unknown":""}`)}),
7298 }, {
7299 name: jsontest.Name("Structs/DuplicateName/Embed/UnknownMerge"),
7300 inBuf: `{"unknown":""}`,
7301 inVal: addr(structNoCaseEmbedTextValue{X: jsontext.Value(`{"unknown":""}`)}),
7302 want: addr(structNoCaseEmbedTextValue{X: jsontext.Value(`{"unknown":"","unknown":""}`)}),
7303 }, {
7304 name: jsontest.Name("Structs/DuplicateName/Embed/NoCaseOkay"),
7305 inBuf: `{"b":"","B":""}`,
7306 inVal: addr(structNoCaseEmbedTextValue{}),
7307 want: addr(structNoCaseEmbedTextValue{X: jsontext.Value(`{"b":"","B":""}`)}),
7308 }, {
7309 name: jsontest.Name("Structs/DuplicateName/Embed/ExactConflict"),
7310 inBuf: `{"b":"","b":""}`,
7311 inVal: addr(structNoCaseEmbedTextValue{}),
7312 want: addr(structNoCaseEmbedTextValue{X: jsontext.Value(`{"b":""}`)}),
7313 wantErr: newDuplicateNameError("", []byte(`"b"`), len64(`{"b":"",`)),
7314 }, {
7315 name: jsontest.Name("Structs/Invalid/ErrUnexpectedEOF"),
7316 inBuf: ``,
7317 inVal: addr(structAll{}),
7318 want: addr(structAll{}),
7319 wantErr: &jsontext.SyntacticError{Err: io.ErrUnexpectedEOF},
7320 }, {
7321 name: jsontest.Name("Structs/Invalid/ErrUnexpectedEOF"),
7322 inBuf: " \n\r\t",
7323 inVal: addr(structAll{}),
7324 want: addr(structAll{}),
7325 wantErr: &jsontext.SyntacticError{Err: io.ErrUnexpectedEOF, ByteOffset: len64(" \n\r\t")},
7326 }, {
7327 name: jsontest.Name("Structs/Invalid/NestedErrUnexpectedEOF"),
7328 inBuf: `{"Pointer":`,
7329 inVal: addr(structAll{}),
7330 want: addr(structAll{Pointer: new(structAll)}),
7331 wantErr: &jsontext.SyntacticError{ByteOffset: len64(`{"Pointer":`), JSONPointer: "/Pointer", Err: io.ErrUnexpectedEOF},
7332 }, {
7333 name: jsontest.Name("Structs/Invalid/Conflicting"),
7334 inBuf: `{}`,
7335 inVal: addr(structConflicting{}),
7336 want: addr(structConflicting{}),
7337 wantErr: EU(errors.New(`Go struct fields A and B conflict over JSON object name "conflict"`)).withType('{', T[structConflicting]()),
7338 }, {
7339 name: jsontest.Name("Structs/Invalid/NoneExported"),
7340 inBuf: ` {}`,
7341 inVal: addr(structNoneExported{}),
7342 want: addr(structNoneExported{}),
7343 wantErr: EU(errNoExportedFields).withPos(` `, "").withType('{', T[structNoneExported]()),
7344 }, {
7345 name: jsontest.Name("Structs/Invalid/MalformedTag"),
7346 inBuf: `{}`,
7347 inVal: addr(structMalformedTag{}),
7348 want: addr(structMalformedTag{}),
7349 wantErr: EU(errors.New("Go struct field Malformed has malformed `json` tag: invalid character '\"' at start of option (expecting Unicode letter)")).withType('{', T[structMalformedTag]()),
7350 }, {
7351 name: jsontest.Name("Structs/Invalid/UnexportedTag"),
7352 inBuf: `{}`,
7353 inVal: addr(structUnexportedTag{}),
7354 want: addr(structUnexportedTag{}),
7355 wantErr: EU(errors.New("unexported Go struct field unexported cannot have non-ignored `json:\"name\"` tag")).withType('{', T[structUnexportedTag]()),
7356 }, {
7357 name: jsontest.Name("Structs/Invalid/ExportedEmbedded"),
7358 inBuf: `{"NamedString":"hello"}`,
7359 inVal: addr(structExportedEmbedded{}),
7360 want: addr(structExportedEmbedded{}),
7361 wantErr: EU(errors.New("embedded Go struct field NamedString of non-struct type must be explicitly given a JSON name")).withType('{', T[structExportedEmbedded]()),
7362 }, {
7363 name: jsontest.Name("Structs/Valid/ExportedEmbedded"),
7364 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
7365 inBuf: `{"NamedString":"hello"}`,
7366 inVal: addr(structExportedEmbedded{}),
7367 want: addr(structExportedEmbedded{"hello"}),
7368 }, {
7369 name: jsontest.Name("Structs/Valid/ExportedEmbeddedTag"),
7370 inBuf: `{"name":"hello"}`,
7371 inVal: addr(structExportedEmbeddedTag{}),
7372 want: addr(structExportedEmbeddedTag{"hello"}),
7373 }, {
7374 name: jsontest.Name("Structs/Invalid/UnexportedEmbedded"),
7375 inBuf: `{}`,
7376 inVal: addr(structUnexportedEmbedded{}),
7377 want: addr(structUnexportedEmbedded{}),
7378 wantErr: EU(errors.New("embedded Go struct field namedString of non-struct type must be explicitly given a JSON name")).withType('{', T[structUnexportedEmbedded]()),
7379 }, {
7380 name: jsontest.Name("Structs/UnexportedEmbeddedStruct"),
7381 inBuf: `{"Bool":true,"FizzBuzz":5,"Addr":"192.168.0.1"}`,
7382 inVal: addr(structUnexportedEmbeddedStruct{}),
7383 want: addr(structUnexportedEmbeddedStruct{structOmitZeroAll{Bool: true}, 5, structNestedAddr{netip.AddrFrom4([4]byte{192, 168, 0, 1})}}),
7384 }, {
7385 name: jsontest.Name("Structs/UnexportedEmbeddedStructPointer/Nil"),
7386 inBuf: `{"Bool":true,"FizzBuzz":5}`,
7387 inVal: addr(structUnexportedEmbeddedStructPointer{}),
7388 wantErr: EU(errNilField).withPos(`{"Bool":`, "/Bool").withType(0, T[structUnexportedEmbeddedStructPointer]()),
7389 }, {
7390 name: jsontest.Name("Structs/UnexportedEmbeddedStructPointer/Nil"),
7391 inBuf: `{"FizzBuzz":5,"Addr":"192.168.0.1"}`,
7392 inVal: addr(structUnexportedEmbeddedStructPointer{}),
7393 wantErr: EU(errNilField).withPos(`{"FizzBuzz":5,"Addr":`, "/Addr").withType(0, T[structUnexportedEmbeddedStructPointer]()),
7394 }, {
7395 name: jsontest.Name("Structs/UnexportedEmbeddedStructPointer/Nil"),
7396 inBuf: `{"Bool":true,"FizzBuzz":10,"Addr":"192.168.0.1"}`,
7397 inVal: addr(structUnexportedEmbeddedStructPointer{&structOmitZeroAll{Int: 5}, 5, &structNestedAddr{netip.AddrFrom4([4]byte{127, 0, 0, 1})}}),
7398 want: addr(structUnexportedEmbeddedStructPointer{&structOmitZeroAll{Bool: true, Int: 5}, 10, &structNestedAddr{netip.AddrFrom4([4]byte{192, 168, 0, 1})}}),
7399 }, {
7400 name: jsontest.Name("Structs/Unknown"),
7401 inBuf: `{
7402 "object0": {},
7403 "object1": {"key1": "value"},
7404 "object2": {"key1": "value", "key2": "value"},
7405 "objects": {"":{"":{"":{}}}},
7406 "array0": [],
7407 "array1": ["value1"],
7408 "array2": ["value1", "value2"],
7409 "array": [[[]]],
7410 "scalars": [null, false, true, "string", 12.345]
7411 }`,
7412 inVal: addr(struct{}{}),
7413 want: addr(struct{}{}),
7414 }, {
7415 name: jsontest.Name("Structs/IgnoreInvalidFormat"),
7416 opts: []Options{invalidFormatOption},
7417 inBuf: `{"Field":"Value"}`,
7418 inVal: addr(struct{ Field string }{}),
7419 want: addr(struct{ Field string }{"Value"}),
7420 }, {
7421 name: jsontest.Name("Slices/Null"),
7422 inBuf: `null`,
7423 inVal: addr([]string{"something"}),
7424 want: addr([]string(nil)),
7425 }, {
7426 name: jsontest.Name("Slices/Bool"),
7427 inBuf: `[true,false]`,
7428 inVal: new([]bool),
7429 want: addr([]bool{true, false}),
7430 }, {
7431 name: jsontest.Name("Slices/String"),
7432 inBuf: `["hello","goodbye"]`,
7433 inVal: new([]string),
7434 want: addr([]string{"hello", "goodbye"}),
7435 }, {
7436 name: jsontest.Name("Slices/Bytes"),
7437 inBuf: `["aGVsbG8=","Z29vZGJ5ZQ=="]`,
7438 inVal: new([][]byte),
7439 want: addr([][]byte{[]byte("hello"), []byte("goodbye")}),
7440 }, {
7441 name: jsontest.Name("Slices/Int"),
7442 inBuf: `[-2,-1,0,1,2]`,
7443 inVal: new([]int),
7444 want: addr([]int{-2, -1, 0, 1, 2}),
7445 }, {
7446 name: jsontest.Name("Slices/Uint"),
7447 inBuf: `[0,1,2,3,4]`,
7448 inVal: new([]uint),
7449 want: addr([]uint{0, 1, 2, 3, 4}),
7450 }, {
7451 name: jsontest.Name("Slices/Float"),
7452 inBuf: `[3.14159,12.34]`,
7453 inVal: new([]float64),
7454 want: addr([]float64{3.14159, 12.34}),
7455 }, {
7456
7457
7458
7459 name: jsontest.Name("Slices/Merge"),
7460 inBuf: `[{"k3":"v3"},{"k4":"v4"}]`,
7461 inVal: addr([]map[string]string{{"k1": "v1"}, {"k2": "v2"}}[:1]),
7462 want: addr([]map[string]string{{"k3": "v3"}, {"k4": "v4"}}),
7463 }, {
7464 name: jsontest.Name("Slices/Invalid/Channel"),
7465 inBuf: `["hello"]`,
7466 inVal: new([]chan string),
7467 want: addr([]chan string{nil}),
7468 wantErr: EU(nil).withPos(`[`, "/0").withType(0, T[chan string]()),
7469 }, {
7470 name: jsontest.Name("Slices/RecursiveSlice"),
7471 inBuf: `[[],[],[[]],[[],[]]]`,
7472 inVal: new(recursiveSlice),
7473 want: addr(recursiveSlice{
7474 {},
7475 {},
7476 {{}},
7477 {{}, {}},
7478 }),
7479 }, {
7480 name: jsontest.Name("Slices/Invalid/Bool"),
7481 inBuf: `true`,
7482 inVal: addr([]string{"nochange"}),
7483 want: addr([]string{"nochange"}),
7484 wantErr: EU(nil).withType('t', T[[]string]()),
7485 }, {
7486 name: jsontest.Name("Slices/Invalid/String"),
7487 inBuf: `""`,
7488 inVal: addr([]string{"nochange"}),
7489 want: addr([]string{"nochange"}),
7490 wantErr: EU(nil).withType('"', T[[]string]()),
7491 }, {
7492 name: jsontest.Name("Slices/Invalid/Number"),
7493 inBuf: `0`,
7494 inVal: addr([]string{"nochange"}),
7495 want: addr([]string{"nochange"}),
7496 wantErr: EU(nil).withType('0', T[[]string]()),
7497 }, {
7498 name: jsontest.Name("Slices/Invalid/Object"),
7499 inBuf: `{}`,
7500 inVal: addr([]string{"nochange"}),
7501 want: addr([]string{"nochange"}),
7502 wantErr: EU(nil).withType('{', T[[]string]()),
7503 }, {
7504 name: jsontest.Name("Slices/IgnoreInvalidFormat"),
7505 opts: []Options{invalidFormatOption},
7506 inBuf: `[false,true]`,
7507 inVal: addr([]bool{true, false}),
7508 want: addr([]bool{false, true}),
7509 }, {
7510 name: jsontest.Name("Arrays/Null"),
7511 inBuf: `null`,
7512 inVal: addr([1]string{"something"}),
7513 want: addr([1]string{}),
7514 }, {
7515 name: jsontest.Name("Arrays/Bool"),
7516 inBuf: `[true,false]`,
7517 inVal: new([2]bool),
7518 want: addr([2]bool{true, false}),
7519 }, {
7520 name: jsontest.Name("Arrays/String"),
7521 inBuf: `["hello","goodbye"]`,
7522 inVal: new([2]string),
7523 want: addr([2]string{"hello", "goodbye"}),
7524 }, {
7525 name: jsontest.Name("Arrays/Bytes"),
7526 inBuf: `["aGVsbG8=","Z29vZGJ5ZQ=="]`,
7527 inVal: new([2][]byte),
7528 want: addr([2][]byte{[]byte("hello"), []byte("goodbye")}),
7529 }, {
7530 name: jsontest.Name("Arrays/Int"),
7531 inBuf: `[-2,-1,0,1,2]`,
7532 inVal: new([5]int),
7533 want: addr([5]int{-2, -1, 0, 1, 2}),
7534 }, {
7535 name: jsontest.Name("Arrays/Uint"),
7536 inBuf: `[0,1,2,3,4]`,
7537 inVal: new([5]uint),
7538 want: addr([5]uint{0, 1, 2, 3, 4}),
7539 }, {
7540 name: jsontest.Name("Arrays/Float"),
7541 inBuf: `[3.14159,12.34]`,
7542 inVal: new([2]float64),
7543 want: addr([2]float64{3.14159, 12.34}),
7544 }, {
7545
7546
7547 name: jsontest.Name("Arrays/Merge"),
7548 inBuf: `[{"k3":"v3"},{"k4":"v4"}]`,
7549 inVal: addr([2]map[string]string{{"k1": "v1"}, {"k2": "v2"}}),
7550 want: addr([2]map[string]string{{"k3": "v3"}, {"k4": "v4"}}),
7551 }, {
7552 name: jsontest.Name("Arrays/Invalid/Channel"),
7553 inBuf: `["hello"]`,
7554 inVal: new([1]chan string),
7555 want: new([1]chan string),
7556 wantErr: EU(nil).withPos(`[`, "/0").withType(0, T[chan string]()),
7557 }, {
7558 name: jsontest.Name("Arrays/Invalid/Underflow"),
7559 inBuf: `{"F":[ ]}`,
7560 inVal: new(struct{ F [1]string }),
7561 want: addr(struct{ F [1]string }{}),
7562 wantErr: EU(errArrayUnderflow).withPos(`{"F":[ `, "/F").withType(']', T[[1]string]()),
7563 }, {
7564 name: jsontest.Name("Arrays/Invalid/Underflow/UnmarshalArrayFromAnyLength"),
7565 opts: []Options{jsonflags.UnmarshalArrayFromAnyLength | 1},
7566 inBuf: `[-1,-2]`,
7567 inVal: addr([4]int{1, 2, 3, 4}),
7568 want: addr([4]int{-1, -2, 0, 0}),
7569 }, {
7570 name: jsontest.Name("Arrays/Invalid/Overflow"),
7571 inBuf: `["1","2"]`,
7572 inVal: new([1]string),
7573 want: addr([1]string{"1"}),
7574 wantErr: EU(errArrayOverflow).withPos(`["1","2"`, "").withType(']', T[[1]string]()),
7575 }, {
7576 name: jsontest.Name("Arrays/Invalid/Overflow/UnmarshalArrayFromAnyLength"),
7577 opts: []Options{jsonflags.UnmarshalArrayFromAnyLength | 1},
7578 inBuf: `[-1,-2,-3,-4,-5,-6]`,
7579 inVal: addr([4]int{1, 2, 3, 4}),
7580 want: addr([4]int{-1, -2, -3, -4}),
7581 }, {
7582 name: jsontest.Name("Arrays/Invalid/Bool"),
7583 inBuf: `true`,
7584 inVal: addr([1]string{"nochange"}),
7585 want: addr([1]string{"nochange"}),
7586 wantErr: EU(nil).withType('t', T[[1]string]()),
7587 }, {
7588 name: jsontest.Name("Arrays/Invalid/String"),
7589 inBuf: `""`,
7590 inVal: addr([1]string{"nochange"}),
7591 want: addr([1]string{"nochange"}),
7592 wantErr: EU(nil).withType('"', T[[1]string]()),
7593 }, {
7594 name: jsontest.Name("Arrays/Invalid/Number"),
7595 inBuf: `0`,
7596 inVal: addr([1]string{"nochange"}),
7597 want: addr([1]string{"nochange"}),
7598 wantErr: EU(nil).withType('0', T[[1]string]()),
7599 }, {
7600 name: jsontest.Name("Arrays/Invalid/Object"),
7601 inBuf: `{}`,
7602 inVal: addr([1]string{"nochange"}),
7603 want: addr([1]string{"nochange"}),
7604 wantErr: EU(nil).withType('{', T[[1]string]()),
7605 }, {
7606 name: jsontest.Name("Arrays/IgnoreInvalidFormat"),
7607 opts: []Options{invalidFormatOption},
7608 inBuf: `[false,true]`,
7609 inVal: addr([2]bool{true, false}),
7610 want: addr([2]bool{false, true}),
7611 }, {
7612 name: jsontest.Name("Pointers/NullL0"),
7613 inBuf: `null`,
7614 inVal: new(*string),
7615 want: addr((*string)(nil)),
7616 }, {
7617 name: jsontest.Name("Pointers/NullL1"),
7618 inBuf: `null`,
7619 inVal: addr(new(*string)),
7620 want: addr((**string)(nil)),
7621 }, {
7622 name: jsontest.Name("Pointers/Bool"),
7623 inBuf: `true`,
7624 inVal: addr(new(bool)),
7625 want: addr(addr(true)),
7626 }, {
7627 name: jsontest.Name("Pointers/String"),
7628 inBuf: `"hello"`,
7629 inVal: addr(new(string)),
7630 want: addr(addr("hello")),
7631 }, {
7632 name: jsontest.Name("Pointers/Bytes"),
7633 inBuf: `"aGVsbG8="`,
7634 inVal: addr(new([]byte)),
7635 want: addr(addr([]byte("hello"))),
7636 }, {
7637 name: jsontest.Name("Pointers/Int"),
7638 inBuf: `-123`,
7639 inVal: addr(new(int)),
7640 want: addr(addr(int(-123))),
7641 }, {
7642 name: jsontest.Name("Pointers/Uint"),
7643 inBuf: `123`,
7644 inVal: addr(new(int)),
7645 want: addr(addr(int(123))),
7646 }, {
7647 name: jsontest.Name("Pointers/Float"),
7648 inBuf: `123.456`,
7649 inVal: addr(new(float64)),
7650 want: addr(addr(float64(123.456))),
7651 }, {
7652 name: jsontest.Name("Pointers/Allocate"),
7653 inBuf: `"hello"`,
7654 inVal: addr((*string)(nil)),
7655 want: addr(addr("hello")),
7656 }, {
7657 name: jsontest.Name("Points/IgnoreInvalidFormat"),
7658 opts: []Options{invalidFormatOption},
7659 inBuf: `true`,
7660 inVal: addr(new(bool)),
7661 want: addr(addr(true)),
7662 }, {
7663 name: jsontest.Name("Interfaces/Empty/Null"),
7664 inBuf: `null`,
7665 inVal: new(any),
7666 want: new(any),
7667 }, {
7668 name: jsontest.Name("Interfaces/NonEmpty/Null"),
7669 inBuf: `null`,
7670 inVal: new(io.Reader),
7671 want: new(io.Reader),
7672 }, {
7673 name: jsontest.Name("Interfaces/NonEmpty/Invalid"),
7674 inBuf: `"hello"`,
7675 inVal: new(io.Reader),
7676 want: new(io.Reader),
7677 wantErr: EU(internal.ErrNilInterface).withType(0, T[io.Reader]()),
7678 }, {
7679 name: jsontest.Name("Interfaces/Empty/False"),
7680 inBuf: `false`,
7681 inVal: new(any),
7682 want: func() any {
7683 var vi any = false
7684 return &vi
7685 }(),
7686 }, {
7687 name: jsontest.Name("Interfaces/Empty/True"),
7688 inBuf: `true`,
7689 inVal: new(any),
7690 want: func() any {
7691 var vi any = true
7692 return &vi
7693 }(),
7694 }, {
7695 name: jsontest.Name("Interfaces/Empty/String"),
7696 inBuf: `"string"`,
7697 inVal: new(any),
7698 want: func() any {
7699 var vi any = "string"
7700 return &vi
7701 }(),
7702 }, {
7703 name: jsontest.Name("Interfaces/Empty/Number"),
7704 inBuf: `3.14159`,
7705 inVal: new(any),
7706 want: func() any {
7707 var vi any = 3.14159
7708 return &vi
7709 }(),
7710 }, {
7711 name: jsontest.Name("Interfaces/Empty/Object"),
7712 inBuf: `{"k":"v"}`,
7713 inVal: new(any),
7714 want: func() any {
7715 var vi any = map[string]any{"k": "v"}
7716 return &vi
7717 }(),
7718 }, {
7719 name: jsontest.Name("Interfaces/Empty/Array"),
7720 inBuf: `["v"]`,
7721 inVal: new(any),
7722 want: func() any {
7723 var vi any = []any{"v"}
7724 return &vi
7725 }(),
7726 }, {
7727 name: jsontest.Name("Interfaces/NamedAny/String"),
7728 inBuf: `"string"`,
7729 inVal: new(namedAny),
7730 want: func() namedAny {
7731 var vi namedAny = "string"
7732 return &vi
7733 }(),
7734 }, {
7735 name: jsontest.Name("Interfaces/Invalid"),
7736 inBuf: `]`,
7737 inVal: new(any),
7738 want: new(any),
7739 wantErr: newInvalidCharacterError("]", "at start of value", 0, ""),
7740 }, {
7741
7742
7743
7744
7745 name: jsontest.Name("Interfaces/Merge/Map"),
7746 inBuf: `{"k2":"v2"}`,
7747 inVal: func() any {
7748 var vi any = map[string]string{"k1": "v1"}
7749 return &vi
7750 }(),
7751 want: func() any {
7752 var vi any = map[string]string{"k1": "v1", "k2": "v2"}
7753 return &vi
7754 }(),
7755 }, {
7756 name: jsontest.Name("Interfaces/Merge/Struct"),
7757 inBuf: `{"Array":["goodbye"]}`,
7758 inVal: func() any {
7759 var vi any = structAll{String: "hello"}
7760 return &vi
7761 }(),
7762 want: func() any {
7763 var vi any = structAll{String: "hello", Array: [1]string{"goodbye"}}
7764 return &vi
7765 }(),
7766 }, {
7767 name: jsontest.Name("Interfaces/Merge/NamedInt"),
7768 inBuf: `64`,
7769 inVal: func() any {
7770 var vi any = namedInt64(-64)
7771 return &vi
7772 }(),
7773 want: func() any {
7774 var vi any = namedInt64(+64)
7775 return &vi
7776 }(),
7777 }, {
7778 name: jsontest.Name("Interfaces/IgnoreInvalidFormat"),
7779 opts: []Options{invalidFormatOption},
7780 inBuf: `true`,
7781 inVal: new(any),
7782 want: func() any {
7783 var vi any = true
7784 return &vi
7785 }(),
7786 }, {
7787 name: jsontest.Name("Interfaces/Any"),
7788 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7789 inVal: new(struct{ X any }),
7790 want: addr(struct{ X any }{[]any{nil, false, true, "", 0.0, map[string]any{}, []any{}}}),
7791 }, {
7792 name: jsontest.Name("Interfaces/Any/Named"),
7793 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7794 inVal: new(struct{ X namedAny }),
7795 want: addr(struct{ X namedAny }{[]any{nil, false, true, "", 0.0, map[string]any{}, []any{}}}),
7796 }, {
7797 name: jsontest.Name("Interfaces/Any/Stringified"),
7798 opts: []Options{StringifyNumbers(true)},
7799 inBuf: `{"X":"0"}`,
7800 inVal: new(struct{ X any }),
7801 want: addr(struct{ X any }{"0"}),
7802 }, {
7803 name: jsontest.Name("Interfaces/Any/UnmarshalFunc/Any"),
7804 opts: []Options{
7805 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *any) error {
7806 *v = "called"
7807 return nil
7808 })),
7809 },
7810 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7811 inVal: new(struct{ X any }),
7812 want: addr(struct{ X any }{"called"}),
7813 }, {
7814 name: jsontest.Name("Interfaces/Any/UnmarshalFunc/Bool"),
7815 opts: []Options{
7816 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *bool) error {
7817 *v = string(b) != "true"
7818 return nil
7819 })),
7820 },
7821 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7822 inVal: new(struct{ X any }),
7823 want: addr(struct{ X any }{[]any{nil, true, false, "", 0.0, map[string]any{}, []any{}}}),
7824 }, {
7825 name: jsontest.Name("Interfaces/Any/UnmarshalFunc/String"),
7826 opts: []Options{
7827 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *string) error {
7828 *v = "called"
7829 return nil
7830 })),
7831 },
7832 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7833 inVal: new(struct{ X any }),
7834 want: addr(struct{ X any }{[]any{nil, false, true, "called", 0.0, map[string]any{}, []any{}}}),
7835 }, {
7836 name: jsontest.Name("Interfaces/Any/UnmarshalFunc/Float64"),
7837 opts: []Options{
7838 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *float64) error {
7839 *v = 3.14159
7840 return nil
7841 })),
7842 },
7843 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7844 inVal: new(struct{ X any }),
7845 want: addr(struct{ X any }{[]any{nil, false, true, "", 3.14159, map[string]any{}, []any{}}}),
7846 }, {
7847 name: jsontest.Name("Interfaces/Any/UnmarshalFunc/MapStringAny"),
7848 opts: []Options{
7849 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *map[string]any) error {
7850 *v = map[string]any{"called": nil}
7851 return nil
7852 })),
7853 },
7854 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7855 inVal: new(struct{ X any }),
7856 want: addr(struct{ X any }{[]any{nil, false, true, "", 0.0, map[string]any{"called": nil}, []any{}}}),
7857 }, {
7858 name: jsontest.Name("Interfaces/Any/UnmarshalFunc/SliceAny"),
7859 opts: []Options{
7860 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *[]any) error {
7861 *v = []any{"called"}
7862 return nil
7863 })),
7864 },
7865 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7866 inVal: new(struct{ X any }),
7867 want: addr(struct{ X any }{[]any{"called"}}),
7868 }, {
7869 name: jsontest.Name("Interfaces/Any/Maps/NonEmpty"),
7870 inBuf: `{"X":{"fizz":"buzz"}}`,
7871 inVal: new(struct{ X any }),
7872 want: addr(struct{ X any }{map[string]any{"fizz": "buzz"}}),
7873 }, {
7874 name: jsontest.Name("Interfaces/Any/Maps/RejectDuplicateNames"),
7875 inBuf: `{"X":{"fizz":"buzz","fizz":true}}`,
7876 inVal: new(struct{ X any }),
7877 want: addr(struct{ X any }{map[string]any{"fizz": "buzz"}}),
7878 wantErr: newDuplicateNameError("/X", []byte(`"fizz"`), len64(`{"X":{"fizz":"buzz",`)),
7879 }, {
7880 name: jsontest.Name("Interfaces/Any/Maps/AllowDuplicateNames"),
7881 opts: []Options{jsontext.AllowDuplicateNames(true)},
7882 inBuf: `{"X":{"fizz":"buzz","fizz":true}}`,
7883 inVal: new(struct{ X any }),
7884 want: addr(struct{ X any }{map[string]any{"fizz": "buzz"}}),
7885 wantErr: EU(nil).withPos(`{"X":{"fizz":"buzz","fizz":`, "/X/fizz").withType('t', T[string]()),
7886 }, {
7887 name: jsontest.Name("Interfaces/Any/Slices/NonEmpty"),
7888 inBuf: `{"X":["fizz","buzz"]}`,
7889 inVal: new(struct{ X any }),
7890 want: addr(struct{ X any }{[]any{"fizz", "buzz"}}),
7891 }, {
7892 name: jsontest.Name("Methods/NilPointer/Null"),
7893 inBuf: `{"X":null}`,
7894 inVal: addr(struct{ X *allMethods }{X: (*allMethods)(nil)}),
7895 want: addr(struct{ X *allMethods }{X: (*allMethods)(nil)}),
7896 }, {
7897 name: jsontest.Name("Methods/NilPointer/Value"),
7898 inBuf: `{"X":"value"}`,
7899 inVal: addr(struct{ X *allMethods }{X: (*allMethods)(nil)}),
7900 want: addr(struct{ X *allMethods }{X: &allMethods{method: "UnmarshalJSONFrom", value: []byte(`"value"`)}}),
7901 }, {
7902 name: jsontest.Name("Methods/NilInterface/Null"),
7903 inBuf: `{"X":null}`,
7904 inVal: addr(struct{ X MarshalerTo }{X: (*allMethods)(nil)}),
7905 want: addr(struct{ X MarshalerTo }{X: nil}),
7906 }, {
7907 name: jsontest.Name("Methods/NilInterface/Value"),
7908 inBuf: `{"X":"value"}`,
7909 inVal: addr(struct{ X MarshalerTo }{X: (*allMethods)(nil)}),
7910 want: addr(struct{ X MarshalerTo }{X: &allMethods{method: "UnmarshalJSONFrom", value: []byte(`"value"`)}}),
7911 }, {
7912 name: jsontest.Name("Methods/AllMethods"),
7913 inBuf: `{"X":"hello"}`,
7914 inVal: new(struct{ X *allMethods }),
7915 want: addr(struct{ X *allMethods }{X: &allMethods{method: "UnmarshalJSONFrom", value: []byte(`"hello"`)}}),
7916 }, {
7917 name: jsontest.Name("Methods/AllMethodsExceptJSONv2"),
7918 inBuf: `{"X":"hello"}`,
7919 inVal: new(struct{ X *allMethodsExceptJSONv2 }),
7920 want: addr(struct{ X *allMethodsExceptJSONv2 }{X: &allMethodsExceptJSONv2{allMethods: allMethods{method: "UnmarshalJSON", value: []byte(`"hello"`)}}}),
7921 }, {
7922 name: jsontest.Name("Methods/AllMethodsExceptJSONv1"),
7923 inBuf: `{"X":"hello"}`,
7924 inVal: new(struct{ X *allMethodsExceptJSONv1 }),
7925 want: addr(struct{ X *allMethodsExceptJSONv1 }{X: &allMethodsExceptJSONv1{allMethods: allMethods{method: "UnmarshalJSONFrom", value: []byte(`"hello"`)}}}),
7926 }, {
7927 name: jsontest.Name("Methods/AllMethodsExceptText"),
7928 inBuf: `{"X":"hello"}`,
7929 inVal: new(struct{ X *allMethodsExceptText }),
7930 want: addr(struct{ X *allMethodsExceptText }{X: &allMethodsExceptText{allMethods: allMethods{method: "UnmarshalJSONFrom", value: []byte(`"hello"`)}}}),
7931 }, {
7932 name: jsontest.Name("Methods/OnlyMethodJSONv2"),
7933 inBuf: `{"X":"hello"}`,
7934 inVal: new(struct{ X *onlyMethodJSONv2 }),
7935 want: addr(struct{ X *onlyMethodJSONv2 }{X: &onlyMethodJSONv2{allMethods: allMethods{method: "UnmarshalJSONFrom", value: []byte(`"hello"`)}}}),
7936 }, {
7937 name: jsontest.Name("Methods/OnlyMethodJSONv1"),
7938 inBuf: `{"X":"hello"}`,
7939 inVal: new(struct{ X *onlyMethodJSONv1 }),
7940 want: addr(struct{ X *onlyMethodJSONv1 }{X: &onlyMethodJSONv1{allMethods: allMethods{method: "UnmarshalJSON", value: []byte(`"hello"`)}}}),
7941 }, {
7942 name: jsontest.Name("Methods/OnlyMethodText"),
7943 inBuf: `{"X":"hello"}`,
7944 inVal: new(struct{ X *onlyMethodText }),
7945 want: addr(struct{ X *onlyMethodText }{X: &onlyMethodText{allMethods: allMethods{method: "UnmarshalText", value: []byte(`hello`)}}}),
7946 }, {
7947 name: jsontest.Name("Methods/Text/Null"),
7948 inBuf: `{"X":null}`,
7949 inVal: addr(struct{ X unmarshalTextFunc }{unmarshalTextFunc(func(b []byte) error {
7950 return errMustNotCall
7951 })}),
7952 want: addr(struct{ X unmarshalTextFunc }{nil}),
7953 }, {
7954 name: jsontest.Name("Methods/IP"),
7955 inBuf: `"192.168.0.100"`,
7956 inVal: new(net.IP),
7957 want: addr(net.IPv4(192, 168, 0, 100)),
7958 }, {
7959
7960 name: jsontest.Name("Methods/Anonymous"),
7961 inBuf: `{"X":"hello"}`,
7962 inVal: new(struct{ X struct{ allMethods } }),
7963 want: addr(struct{ X struct{ allMethods } }{X: struct{ allMethods }{allMethods{method: "UnmarshalJSONFrom", value: []byte(`"hello"`)}}}),
7964 }, {
7965
7966 name: jsontest.Name("Methods/Addressable"),
7967 inBuf: `{"V":"hello","M":{"K":"hello"},"I":"hello"}`,
7968 inVal: addr(struct {
7969 V allMethods
7970 M map[string]allMethods
7971 I any
7972 }{
7973 I: allMethods{},
7974 }),
7975 want: addr(struct {
7976 V allMethods
7977 M map[string]allMethods
7978 I any
7979 }{
7980 V: allMethods{method: "UnmarshalJSONFrom", value: []byte(`"hello"`)},
7981 M: map[string]allMethods{"K": {method: "UnmarshalJSONFrom", value: []byte(`"hello"`)}},
7982 I: allMethods{method: "UnmarshalJSONFrom", value: []byte(`"hello"`)},
7983 }),
7984 }, {
7985
7986 name: jsontest.Name("Methods/MapKey/JSONv2"),
7987 inBuf: `{"k1":"v1b","k2":"v2"}`,
7988 inVal: addr(map[structMethodJSONv2]string{{"k1"}: "v1a", {"k3"}: "v3"}),
7989 want: addr(map[structMethodJSONv2]string{{"k1"}: "v1b", {"k2"}: "v2", {"k3"}: "v3"}),
7990 }, {
7991
7992 name: jsontest.Name("Methods/MapKey/JSONv1"),
7993 inBuf: `{"k1":"v1b","k2":"v2"}`,
7994 inVal: addr(map[structMethodJSONv1]string{{"k1"}: "v1a", {"k3"}: "v3"}),
7995 want: addr(map[structMethodJSONv1]string{{"k1"}: "v1b", {"k2"}: "v2", {"k3"}: "v3"}),
7996 }, {
7997 name: jsontest.Name("Methods/MapKey/Text"),
7998 inBuf: `{"k1":"v1b","k2":"v2"}`,
7999 inVal: addr(map[structMethodText]string{{"k1"}: "v1a", {"k3"}: "v3"}),
8000 want: addr(map[structMethodText]string{{"k1"}: "v1b", {"k2"}: "v2", {"k3"}: "v3"}),
8001 }, {
8002 name: jsontest.Name("Methods/JSONv2/ErrUnsupported"),
8003 inBuf: `{"fizz":123}`,
8004 inVal: addr(unsupportedMethodJSONv2{}),
8005 want: addr(unsupportedMethodJSONv2{"called": 1, "fizz": 123}),
8006 }, {
8007 name: jsontest.Name("Methods/Invalid/JSONv2/Error"),
8008 inBuf: `{}`,
8009 inVal: addr(unmarshalJSONv2Func(func(*jsontext.Decoder) error {
8010 return errSomeError
8011 })),
8012 wantErr: EU(errSomeError).withType(0, T[unmarshalJSONv2Func]()),
8013 }, {
8014 name: jsontest.Name("Methods/Invalid/JSONv2/TooFew"),
8015 inBuf: `{}`,
8016 inVal: addr(unmarshalJSONv2Func(func(*jsontext.Decoder) error {
8017 return nil
8018 })),
8019 wantErr: EU(errNonSingularValue).withType(0, T[unmarshalJSONv2Func]()),
8020 }, {
8021 name: jsontest.Name("Methods/Invalid/JSONv2/TooMany"),
8022 inBuf: `{}{}`,
8023 inVal: addr(unmarshalJSONv2Func(func(dec *jsontext.Decoder) error {
8024 dec.ReadValue()
8025 dec.ReadValue()
8026 return nil
8027 })),
8028 wantErr: EU(errNonSingularValue).withPos(`{}`, "").withType(0, T[unmarshalJSONv2Func]()),
8029 }, {
8030 name: jsontest.Name("Methods/Invalid/JSONv2/ErrUnsupported"),
8031 inBuf: `{}`,
8032 inVal: addr(unmarshalJSONv2Func(func(*jsontext.Decoder) error {
8033 return errors.ErrUnsupported
8034 })),
8035 wantErr: EU(nil).withType(0, T[unmarshalJSONv2Func]()),
8036 }, {
8037 name: jsontest.Name("Methods/Invalid/JSONv1/Error"),
8038 inBuf: `{}`,
8039 inVal: addr(unmarshalJSONv1Func(func([]byte) error {
8040 return errSomeError
8041 })),
8042 wantErr: EU(errSomeError).withType('{', T[unmarshalJSONv1Func]()),
8043 }, {
8044 name: jsontest.Name("Methods/Invalid/JSONv1/ErrUnsupported"),
8045 inBuf: `{}`,
8046 inVal: addr(unmarshalJSONv1Func(func([]byte) error {
8047 return errors.ErrUnsupported
8048 })),
8049 wantErr: EU(wrapErrUnsupported(errors.ErrUnsupported, "UnmarshalJSON method")).withType('{', T[unmarshalJSONv1Func]()),
8050 }, {
8051 name: jsontest.Name("Methods/Invalid/Text/Error"),
8052 inBuf: `"value"`,
8053 inVal: addr(unmarshalTextFunc(func([]byte) error {
8054 return errSomeError
8055 })),
8056 wantErr: EU(errSomeError).withType('"', T[unmarshalTextFunc]()),
8057 }, {
8058 name: jsontest.Name("Methods/Invalid/Text/Syntax"),
8059 inBuf: `{}`,
8060 inVal: addr(unmarshalTextFunc(func([]byte) error {
8061 panic("should not be called")
8062 })),
8063 wantErr: EU(errNonStringValue).withType('{', T[unmarshalTextFunc]()),
8064 }, {
8065 name: jsontest.Name("Methods/Invalid/Text/ErrUnsupported"),
8066 inBuf: `"value"`,
8067 inVal: addr(unmarshalTextFunc(func([]byte) error {
8068 return errors.ErrUnsupported
8069 })),
8070 wantErr: EU(wrapErrUnsupported(errors.ErrUnsupported, "UnmarshalText method")).withType('"', T[unmarshalTextFunc]()),
8071 }, {
8072 name: jsontest.Name("Functions/String/V1"),
8073 opts: []Options{
8074 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *string) error {
8075 if string(b) != `""` {
8076 return fmt.Errorf("got %s, want %s", b, `""`)
8077 }
8078 *v = "called"
8079 return nil
8080 })),
8081 },
8082 inBuf: `""`,
8083 inVal: addr(""),
8084 want: addr("called"),
8085 }, {
8086 name: jsontest.Name("Functions/String/Empty"),
8087 opts: []Options{WithUnmarshalers(nil)},
8088 inBuf: `"hello"`,
8089 inVal: addr(""),
8090 want: addr("hello"),
8091 }, {
8092 name: jsontest.Name("Functions/NamedString/V1/NoMatch"),
8093 opts: []Options{
8094 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *namedString) error {
8095 panic("should not be called")
8096 })),
8097 },
8098 inBuf: `""`,
8099 inVal: addr(""),
8100 want: addr(""),
8101 }, {
8102 name: jsontest.Name("Functions/NamedString/V1/Match"),
8103 opts: []Options{
8104 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *namedString) error {
8105 if string(b) != `""` {
8106 return fmt.Errorf("got %s, want %s", b, `""`)
8107 }
8108 *v = "called"
8109 return nil
8110 })),
8111 },
8112 inBuf: `""`,
8113 inVal: addr(namedString("")),
8114 want: addr(namedString("called")),
8115 }, {
8116 name: jsontest.Name("Functions/String/V2"),
8117 opts: []Options{
8118 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8119 switch b, err := dec.ReadValue(); {
8120 case err != nil:
8121 return err
8122 case string(b) != `""`:
8123 return fmt.Errorf("got %s, want %s", b, `""`)
8124 }
8125 *v = "called"
8126 return nil
8127 })),
8128 },
8129 inBuf: `""`,
8130 inVal: addr(""),
8131 want: addr("called"),
8132 }, {
8133 name: jsontest.Name("Functions/NamedString/V2/NoMatch"),
8134 opts: []Options{
8135 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *namedString) error {
8136 panic("should not be called")
8137 })),
8138 },
8139 inBuf: `""`,
8140 inVal: addr(""),
8141 want: addr(""),
8142 }, {
8143 name: jsontest.Name("Functions/NamedString/V2/Match"),
8144 opts: []Options{
8145 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *namedString) error {
8146 switch t, err := dec.ReadToken(); {
8147 case err != nil:
8148 return err
8149 case t.String() != ``:
8150 return fmt.Errorf("got %q, want %q", t, ``)
8151 }
8152 *v = "called"
8153 return nil
8154 })),
8155 },
8156 inBuf: `""`,
8157 inVal: addr(namedString("")),
8158 want: addr(namedString("called")),
8159 }, {
8160 name: jsontest.Name("Functions/String/Empty1/NoMatch"),
8161 opts: []Options{
8162 WithUnmarshalers(new(Unmarshalers)),
8163 },
8164 inBuf: `""`,
8165 inVal: addr(""),
8166 want: addr(""),
8167 }, {
8168 name: jsontest.Name("Functions/String/Empty2/NoMatch"),
8169 opts: []Options{
8170 WithUnmarshalers(JoinUnmarshalers()),
8171 },
8172 inBuf: `""`,
8173 inVal: addr(""),
8174 want: addr(""),
8175 }, {
8176 name: jsontest.Name("Functions/String/V1/DirectError"),
8177 opts: []Options{
8178 WithUnmarshalers(UnmarshalFunc(func([]byte, *string) error {
8179 return errSomeError
8180 })),
8181 },
8182 inBuf: `""`,
8183 inVal: addr(""),
8184 want: addr(""),
8185 wantErr: EU(errSomeError).withType('"', reflect.PointerTo(stringType)),
8186 }, {
8187 name: jsontest.Name("Functions/String/V1/SkipError"),
8188 opts: []Options{
8189 WithUnmarshalers(UnmarshalFunc(func([]byte, *string) error {
8190 return errors.ErrUnsupported
8191 })),
8192 },
8193 inBuf: `""`,
8194 inVal: addr(""),
8195 want: addr(""),
8196 wantErr: EU(wrapErrUnsupported(errors.ErrUnsupported, "unmarshal function of type func([]byte, T) error")).withType('"', reflect.PointerTo(stringType)),
8197 }, {
8198 name: jsontest.Name("Functions/String/V2/DirectError"),
8199 opts: []Options{
8200 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8201 return errSomeError
8202 })),
8203 },
8204 inBuf: `""`,
8205 inVal: addr(""),
8206 want: addr(""),
8207 wantErr: EU(errSomeError).withType(0, reflect.PointerTo(stringType)),
8208 }, {
8209 name: jsontest.Name("Functions/String/V2/TooFew"),
8210 opts: []Options{
8211 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8212 return nil
8213 })),
8214 },
8215 inBuf: `""`,
8216 inVal: addr(""),
8217 want: addr(""),
8218 wantErr: EU(errNonSingularValue).withType(0, reflect.PointerTo(stringType)),
8219 }, {
8220 name: jsontest.Name("Functions/String/V2/TooMany"),
8221 opts: []Options{
8222 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8223 if _, err := dec.ReadValue(); err != nil {
8224 return err
8225 }
8226 if _, err := dec.ReadValue(); err != nil {
8227 return err
8228 }
8229 return nil
8230 })),
8231 },
8232 inBuf: `{"X":["",""]}`,
8233 inVal: addr(struct{ X []string }{}),
8234 want: addr(struct{ X []string }{[]string{""}}),
8235 wantErr: EU(errNonSingularValue).withPos(`{"X":["",`, "/X").withType(0, reflect.PointerTo(stringType)),
8236 }, {
8237 name: jsontest.Name("Functions/String/V2/Skipped"),
8238 opts: []Options{
8239 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8240 return errors.ErrUnsupported
8241 })),
8242 },
8243 inBuf: `""`,
8244 inVal: addr(""),
8245 want: addr(""),
8246 }, {
8247 name: jsontest.Name("Functions/String/V2/ProcessBeforeSkip"),
8248 opts: []Options{
8249 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8250 if _, err := dec.ReadValue(); err != nil {
8251 return err
8252 }
8253 return errors.ErrUnsupported
8254 })),
8255 },
8256 inBuf: `""`,
8257 inVal: addr(""),
8258 want: addr(""),
8259 wantErr: EU(errUnsupportedMutation).withType(0, reflect.PointerTo(stringType)),
8260 }, {
8261 name: jsontest.Name("Functions/String/V2/WrappedUnsupported"),
8262 opts: []Options{
8263 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8264 return fmt.Errorf("wrap: %w", errors.ErrUnsupported)
8265 })),
8266 },
8267 inBuf: `""`,
8268 inVal: addr(""),
8269 want: addr(""),
8270 }, {
8271 name: jsontest.Name("Functions/Map/Key/NoCaseString/V1"),
8272 opts: []Options{
8273 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *nocaseString) error {
8274 if string(b) != `"hello"` {
8275 return fmt.Errorf("got %s, want %s", b, `"hello"`)
8276 }
8277 *v = "called"
8278 return nil
8279 })),
8280 },
8281 inBuf: `{"hello":"world"}`,
8282 inVal: addr(map[nocaseString]string{}),
8283 want: addr(map[nocaseString]string{"called": "world"}),
8284 }, {
8285 name: jsontest.Name("Functions/Map/Key/TextMarshaler/V1"),
8286 opts: []Options{
8287 WithUnmarshalers(UnmarshalFunc(func(b []byte, v encoding.TextMarshaler) error {
8288 if string(b) != `"hello"` {
8289 return fmt.Errorf("got %s, want %s", b, `"hello"`)
8290 }
8291 *v.(*nocaseString) = "called"
8292 return nil
8293 })),
8294 },
8295 inBuf: `{"hello":"world"}`,
8296 inVal: addr(map[nocaseString]string{}),
8297 want: addr(map[nocaseString]string{"called": "world"}),
8298 }, {
8299 name: jsontest.Name("Functions/Map/Key/NoCaseString/V2"),
8300 opts: []Options{
8301 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *nocaseString) error {
8302 switch t, err := dec.ReadToken(); {
8303 case err != nil:
8304 return err
8305 case t.String() != "hello":
8306 return fmt.Errorf("got %q, want %q", t, "hello")
8307 }
8308 *v = "called"
8309 return nil
8310 })),
8311 },
8312 inBuf: `{"hello":"world"}`,
8313 inVal: addr(map[nocaseString]string{}),
8314 want: addr(map[nocaseString]string{"called": "world"}),
8315 }, {
8316 name: jsontest.Name("Functions/Map/Key/TextMarshaler/V2"),
8317 opts: []Options{
8318 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v encoding.TextMarshaler) error {
8319 switch b, err := dec.ReadValue(); {
8320 case err != nil:
8321 return err
8322 case string(b) != `"hello"`:
8323 return fmt.Errorf("got %s, want %s", b, `"hello"`)
8324 }
8325 *v.(*nocaseString) = "called"
8326 return nil
8327 })),
8328 },
8329 inBuf: `{"hello":"world"}`,
8330 inVal: addr(map[nocaseString]string{}),
8331 want: addr(map[nocaseString]string{"called": "world"}),
8332 }, {
8333 name: jsontest.Name("Functions/Map/Key/String/V1/DuplicateName"),
8334 opts: []Options{
8335 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8336 if _, err := dec.ReadValue(); err != nil {
8337 return err
8338 }
8339 xd := export.Decoder(dec)
8340 *v = fmt.Sprintf("%d-%d", len(xd.Tokens.Stack), xd.Tokens.Last.Length())
8341 return nil
8342 })),
8343 },
8344 inBuf: `{"name":"value","name":"value"}`,
8345 inVal: addr(map[string]string{}),
8346 want: addr(map[string]string{"1-1": "1-2"}),
8347 wantErr: newDuplicateNameError("", []byte(`"name"`), len64(`{"name":"value",`)),
8348 }, {
8349 name: jsontest.Name("Functions/Map/Value/NoCaseString/V1"),
8350 opts: []Options{
8351 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *nocaseString) error {
8352 if string(b) != `"world"` {
8353 return fmt.Errorf("got %s, want %s", b, `"world"`)
8354 }
8355 *v = "called"
8356 return nil
8357 })),
8358 },
8359 inBuf: `{"hello":"world"}`,
8360 inVal: addr(map[string]nocaseString{}),
8361 want: addr(map[string]nocaseString{"hello": "called"}),
8362 }, {
8363 name: jsontest.Name("Functions/Map/Value/TextMarshaler/V1"),
8364 opts: []Options{
8365 WithUnmarshalers(UnmarshalFunc(func(b []byte, v encoding.TextMarshaler) error {
8366 if string(b) != `"world"` {
8367 return fmt.Errorf("got %s, want %s", b, `"world"`)
8368 }
8369 *v.(*nocaseString) = "called"
8370 return nil
8371 })),
8372 },
8373 inBuf: `{"hello":"world"}`,
8374 inVal: addr(map[string]nocaseString{}),
8375 want: addr(map[string]nocaseString{"hello": "called"}),
8376 }, {
8377 name: jsontest.Name("Functions/Map/Value/NoCaseString/V2"),
8378 opts: []Options{
8379 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *nocaseString) error {
8380 switch t, err := dec.ReadToken(); {
8381 case err != nil:
8382 return err
8383 case t.String() != "world":
8384 return fmt.Errorf("got %q, want %q", t, "world")
8385 }
8386 *v = "called"
8387 return nil
8388 })),
8389 },
8390 inBuf: `{"hello":"world"}`,
8391 inVal: addr(map[string]nocaseString{}),
8392 want: addr(map[string]nocaseString{"hello": "called"}),
8393 }, {
8394 name: jsontest.Name("Functions/Map/Value/TextMarshaler/V2"),
8395 opts: []Options{
8396 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v encoding.TextMarshaler) error {
8397 switch b, err := dec.ReadValue(); {
8398 case err != nil:
8399 return err
8400 case string(b) != `"world"`:
8401 return fmt.Errorf("got %s, want %s", b, `"world"`)
8402 }
8403 *v.(*nocaseString) = "called"
8404 return nil
8405 })),
8406 },
8407 inBuf: `{"hello":"world"}`,
8408 inVal: addr(map[string]nocaseString{}),
8409 want: addr(map[string]nocaseString{"hello": "called"}),
8410 }, {
8411 name: jsontest.Name("Funtions/Struct/Fields"),
8412 opts: []Options{
8413 WithUnmarshalers(JoinUnmarshalers(
8414 UnmarshalFunc(func(b []byte, v *bool) error {
8415 if string(b) != `"called1"` {
8416 return fmt.Errorf("got %s, want %s", b, `"called1"`)
8417 }
8418 *v = true
8419 return nil
8420 }),
8421 UnmarshalFunc(func(b []byte, v *string) error {
8422 if string(b) != `"called2"` {
8423 return fmt.Errorf("got %s, want %s", b, `"called2"`)
8424 }
8425 *v = "called2"
8426 return nil
8427 }),
8428 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *[]byte) error {
8429 switch t, err := dec.ReadToken(); {
8430 case err != nil:
8431 return err
8432 case t.String() != "called3":
8433 return fmt.Errorf("got %q, want %q", t, "called3")
8434 }
8435 *v = []byte("called3")
8436 return nil
8437 }),
8438 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *int64) error {
8439 switch b, err := dec.ReadValue(); {
8440 case err != nil:
8441 return err
8442 case string(b) != `"called4"`:
8443 return fmt.Errorf("got %s, want %s", b, `"called4"`)
8444 }
8445 *v = 123
8446 return nil
8447 }),
8448 )),
8449 },
8450 inBuf: `{"Bool":"called1","String":"called2","Bytes":"called3","Int":"called4","Uint":456,"Float":789}`,
8451 inVal: addr(structScalars{}),
8452 want: addr(structScalars{Bool: true, String: "called2", Bytes: []byte("called3"), Int: 123, Uint: 456, Float: 789}),
8453 }, {
8454 name: jsontest.Name("Functions/Struct/Embedded"),
8455 opts: []Options{
8456 WithUnmarshalers(JoinUnmarshalers(
8457 UnmarshalFunc(func([]byte, *structEmbeddedL1) error {
8458 panic("should not be called")
8459 }),
8460 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *StructEmbed2) error {
8461 panic("should not be called")
8462 }),
8463 )),
8464 },
8465 inBuf: `{"E":"E3","F":"F3","G":"G3","A":"A1","B":"B1","D":"D2"}`,
8466 inVal: new(structEmbedded),
8467 want: addr(structEmbedded{
8468 X: structEmbeddedL1{
8469 X: &structEmbeddedL2{A: "A1", B: "B1" },
8470 StructEmbed1: StructEmbed1{ D: "D2" },
8471 },
8472 StructEmbed2: &StructEmbed2{E: "E3", F: "F3", G: "G3"},
8473 }),
8474 }, {
8475 name: jsontest.Name("Functions/Slice/Elem"),
8476 opts: []Options{
8477 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *string) error {
8478 *v = strings.Trim(strings.ToUpper(string(b)), `"`)
8479 return nil
8480 })),
8481 },
8482 inBuf: `["hello","World"]`,
8483 inVal: addr([]string{}),
8484 want: addr([]string{"HELLO", "WORLD"}),
8485 }, {
8486 name: jsontest.Name("Functions/Array/Elem"),
8487 opts: []Options{
8488 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *string) error {
8489 *v = strings.Trim(strings.ToUpper(string(b)), `"`)
8490 return nil
8491 })),
8492 },
8493 inBuf: `["hello","World"]`,
8494 inVal: addr([2]string{}),
8495 want: addr([2]string{"HELLO", "WORLD"}),
8496 }, {
8497 name: jsontest.Name("Functions/Pointer/Nil"),
8498 opts: []Options{
8499 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8500 t, err := dec.ReadToken()
8501 *v = strings.ToUpper(t.String())
8502 return err
8503 })),
8504 },
8505 inBuf: `{"X":"hello"}`,
8506 inVal: addr(struct{ X *string }{nil}),
8507 want: addr(struct{ X *string }{addr("HELLO")}),
8508 }, {
8509 name: jsontest.Name("Functions/Pointer/NonNil"),
8510 opts: []Options{
8511 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8512 t, err := dec.ReadToken()
8513 *v = strings.ToUpper(t.String())
8514 return err
8515 })),
8516 },
8517 inBuf: `{"X":"hello"}`,
8518 inVal: addr(struct{ X *string }{addr("")}),
8519 want: addr(struct{ X *string }{addr("HELLO")}),
8520 }, {
8521 name: jsontest.Name("Functions/Interface/Nil"),
8522 opts: []Options{
8523 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v fmt.Stringer) error {
8524 panic("should not be called")
8525 })),
8526 },
8527 inBuf: `{"X":"hello"}`,
8528 inVal: addr(struct{ X fmt.Stringer }{nil}),
8529 want: addr(struct{ X fmt.Stringer }{nil}),
8530 wantErr: EU(internal.ErrNilInterface).withPos(`{"X":`, "/X").withType(0, T[fmt.Stringer]()),
8531 }, {
8532 name: jsontest.Name("Functions/Interface/NetIP"),
8533 opts: []Options{
8534 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *fmt.Stringer) error {
8535 *v = net.IP{}
8536 return errors.ErrUnsupported
8537 })),
8538 },
8539 inBuf: `{"X":"1.1.1.1"}`,
8540 inVal: addr(struct{ X fmt.Stringer }{nil}),
8541 want: addr(struct{ X fmt.Stringer }{net.IPv4(1, 1, 1, 1)}),
8542 }, {
8543 name: jsontest.Name("Functions/Interface/NewPointerNetIP"),
8544 opts: []Options{
8545 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *fmt.Stringer) error {
8546 *v = new(net.IP)
8547 return errors.ErrUnsupported
8548 })),
8549 },
8550 inBuf: `{"X":"1.1.1.1"}`,
8551 inVal: addr(struct{ X fmt.Stringer }{nil}),
8552 want: addr(struct{ X fmt.Stringer }{addr(net.IPv4(1, 1, 1, 1))}),
8553 }, {
8554 name: jsontest.Name("Functions/Interface/NilPointerNetIP"),
8555 opts: []Options{
8556 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *fmt.Stringer) error {
8557 *v = (*net.IP)(nil)
8558 return errors.ErrUnsupported
8559 })),
8560 },
8561 inBuf: `{"X":"1.1.1.1"}`,
8562 inVal: addr(struct{ X fmt.Stringer }{nil}),
8563 want: addr(struct{ X fmt.Stringer }{addr(net.IPv4(1, 1, 1, 1))}),
8564 }, {
8565 name: jsontest.Name("Functions/Interface/NilPointerNetIP/Override"),
8566 opts: []Options{
8567 WithUnmarshalers(JoinUnmarshalers(
8568 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *fmt.Stringer) error {
8569 *v = (*net.IP)(nil)
8570 return errors.ErrUnsupported
8571 }),
8572 UnmarshalFunc(func(b []byte, v *net.IP) error {
8573 b = bytes.ReplaceAll(b, []byte(`1`), []byte(`8`))
8574 return v.UnmarshalText(bytes.Trim(b, `"`))
8575 }),
8576 )),
8577 },
8578 inBuf: `{"X":"1.1.1.1"}`,
8579 inVal: addr(struct{ X fmt.Stringer }{nil}),
8580 want: addr(struct{ X fmt.Stringer }{addr(net.IPv4(8, 8, 8, 8))}),
8581 }, {
8582 name: jsontest.Name("Functions/Interface/Any"),
8583 opts: []Options{
8584 WithUnmarshalers(func() *Unmarshalers {
8585 type P struct {
8586 D int
8587 N int64
8588 }
8589 type PV struct {
8590 P P
8591 V any
8592 }
8593
8594 var lastChecks []func() error
8595 checkLast := func() error {
8596 for _, fn := range lastChecks {
8597 if err := fn(); err != nil {
8598 return err
8599 }
8600 }
8601 return errors.ErrUnsupported
8602 }
8603 makeValueChecker := func(name string, want []PV) func(d *jsontext.Decoder, v any) error {
8604 checkNext := func(d *jsontext.Decoder, v any) error {
8605 xd := export.Decoder(d)
8606 p := P{len(xd.Tokens.Stack), xd.Tokens.Last.Length()}
8607 rv := reflect.ValueOf(v)
8608 pv := PV{p, v}
8609 switch {
8610 case len(want) == 0:
8611 return fmt.Errorf("%s: %v: got more values than expected", name, p)
8612 case !rv.IsValid() || rv.Kind() != reflect.Pointer || rv.IsNil():
8613 return fmt.Errorf("%s: %v: got %#v, want non-nil pointer type", name, p, v)
8614 case !reflect.DeepEqual(pv, want[0]):
8615 return fmt.Errorf("%s:\n\tgot %#v\n\twant %#v", name, pv, want[0])
8616 default:
8617 want = want[1:]
8618 return errors.ErrUnsupported
8619 }
8620 }
8621 lastChecks = append(lastChecks, func() error {
8622 if len(want) > 0 {
8623 return fmt.Errorf("%s: did not get enough values, want %d more", name, len(want))
8624 }
8625 return nil
8626 })
8627 return checkNext
8628 }
8629 makePositionChecker := func(name string, want []P) func(d *jsontext.Decoder, v any) error {
8630 checkNext := func(d *jsontext.Decoder, v any) error {
8631 xd := export.Decoder(d)
8632 p := P{len(xd.Tokens.Stack), xd.Tokens.Last.Length()}
8633 switch {
8634 case len(want) == 0:
8635 return fmt.Errorf("%s: %v: got more values than wanted", name, p)
8636 case p != want[0]:
8637 return fmt.Errorf("%s: got %v, want %v", name, p, want[0])
8638 default:
8639 want = want[1:]
8640 return errors.ErrUnsupported
8641 }
8642 }
8643 lastChecks = append(lastChecks, func() error {
8644 if len(want) > 0 {
8645 return fmt.Errorf("%s: did not get enough values, want %d more", name, len(want))
8646 }
8647 return nil
8648 })
8649 return checkNext
8650 }
8651
8652
8653
8654 wantAny := []PV{
8655 {P{1, 0}, addr(any(nil))},
8656 {P{1, 1}, addr(any(valueStringer{}))},
8657 {P{1, 1}, addr(valueStringer{})},
8658 {P{1, 2}, addr(any((*valueStringer)(nil)))},
8659 {P{1, 2}, addr((*valueStringer)(nil))},
8660 {P{1, 2}, addr(valueStringer{})},
8661 {P{1, 3}, addr(any(addr(valueStringer{})))},
8662 {P{1, 3}, addr(addr(valueStringer{}))},
8663 {P{1, 3}, addr(valueStringer{})},
8664 {P{1, 4}, addr(any((**valueStringer)(nil)))},
8665 {P{1, 4}, addr((**valueStringer)(nil))},
8666 {P{1, 4}, addr((*valueStringer)(nil))},
8667 {P{1, 4}, addr(valueStringer{})},
8668 {P{1, 5}, addr(any(addr((*valueStringer)(nil))))},
8669 {P{1, 5}, addr(addr((*valueStringer)(nil)))},
8670 {P{1, 5}, addr((*valueStringer)(nil))},
8671 {P{1, 5}, addr(valueStringer{})},
8672 {P{1, 6}, addr(any(addr(addr(valueStringer{}))))},
8673 {P{1, 6}, addr(addr(addr(valueStringer{})))},
8674 {P{1, 6}, addr(addr(valueStringer{}))},
8675 {P{1, 6}, addr(valueStringer{})},
8676 {P{1, 7}, addr(any(pointerStringer{}))},
8677 {P{1, 7}, addr(pointerStringer{})},
8678 {P{1, 8}, addr(any((*pointerStringer)(nil)))},
8679 {P{1, 8}, addr((*pointerStringer)(nil))},
8680 {P{1, 8}, addr(pointerStringer{})},
8681 {P{1, 9}, addr(any(addr(pointerStringer{})))},
8682 {P{1, 9}, addr(addr(pointerStringer{}))},
8683 {P{1, 9}, addr(pointerStringer{})},
8684 {P{1, 10}, addr(any((**pointerStringer)(nil)))},
8685 {P{1, 10}, addr((**pointerStringer)(nil))},
8686 {P{1, 10}, addr((*pointerStringer)(nil))},
8687 {P{1, 10}, addr(pointerStringer{})},
8688 {P{1, 11}, addr(any(addr((*pointerStringer)(nil))))},
8689 {P{1, 11}, addr(addr((*pointerStringer)(nil)))},
8690 {P{1, 11}, addr((*pointerStringer)(nil))},
8691 {P{1, 11}, addr(pointerStringer{})},
8692 {P{1, 12}, addr(any(addr(addr(pointerStringer{}))))},
8693 {P{1, 12}, addr(addr(addr(pointerStringer{})))},
8694 {P{1, 12}, addr(addr(pointerStringer{}))},
8695 {P{1, 12}, addr(pointerStringer{})},
8696 {P{1, 13}, addr(any("LAST"))},
8697 {P{1, 13}, addr("LAST")},
8698 }
8699 checkAny := makeValueChecker("any", wantAny)
8700 anyUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v any) error {
8701 return checkAny(dec, v)
8702 })
8703
8704 var wantPointerAny []PV
8705 for _, v := range wantAny {
8706 if _, ok := v.V.(*any); ok {
8707 wantPointerAny = append(wantPointerAny, v)
8708 }
8709 }
8710 checkPointerAny := makeValueChecker("*any", wantPointerAny)
8711 pointerAnyUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v *any) error {
8712 return checkPointerAny(dec, v)
8713 })
8714
8715 checkNamedAny := makeValueChecker("namedAny", wantAny)
8716 namedAnyUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v namedAny) error {
8717 return checkNamedAny(dec, v)
8718 })
8719
8720 checkPointerNamedAny := makeValueChecker("*namedAny", nil)
8721 pointerNamedAnyUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v *namedAny) error {
8722 return checkPointerNamedAny(dec, v)
8723 })
8724
8725 type stringer = fmt.Stringer
8726 var wantStringer []PV
8727 for _, v := range wantAny {
8728 if _, ok := v.V.(stringer); ok {
8729 wantStringer = append(wantStringer, v)
8730 }
8731 }
8732 checkStringer := makeValueChecker("stringer", wantStringer)
8733 stringerUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v stringer) error {
8734 return checkStringer(dec, v)
8735 })
8736
8737 checkPointerStringer := makeValueChecker("*stringer", nil)
8738 pointerStringerUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v *stringer) error {
8739 return checkPointerStringer(dec, v)
8740 })
8741
8742 wantValueStringer := []P{{1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}}
8743 checkPointerValueStringer := makePositionChecker("*valueStringer", wantValueStringer)
8744 pointerValueStringerUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v *valueStringer) error {
8745 return checkPointerValueStringer(dec, v)
8746 })
8747
8748 wantPointerStringer := []P{{1, 7}, {1, 8}, {1, 9}, {1, 10}, {1, 11}, {1, 12}}
8749 checkPointerPointerStringer := makePositionChecker("*pointerStringer", wantPointerStringer)
8750 pointerPointerStringerUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v *pointerStringer) error {
8751 return checkPointerPointerStringer(dec, v)
8752 })
8753
8754 lastUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8755 return checkLast()
8756 })
8757
8758 return JoinUnmarshalers(
8759
8760
8761 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *[14]any) error {
8762 if _, err := dec.ReadToken(); err != nil {
8763 return err
8764 }
8765 for i := range len(*v) {
8766 if err := UnmarshalDecode(dec, &(*v)[i]); err != nil {
8767 return err
8768 }
8769 }
8770 if _, err := dec.ReadToken(); err != nil {
8771 return err
8772 }
8773 return nil
8774 }),
8775
8776 anyUnmarshaler,
8777 pointerAnyUnmarshaler,
8778 namedAnyUnmarshaler,
8779 pointerNamedAnyUnmarshaler,
8780 stringerUnmarshaler,
8781 pointerStringerUnmarshaler,
8782 pointerValueStringerUnmarshaler,
8783 pointerPointerStringerUnmarshaler,
8784 lastUnmarshaler,
8785 )
8786 }()),
8787 },
8788 inBuf: `[null,{},{},{},{},{},{},{},{},{},{},{},{},"LAST"]`,
8789 inVal: addr([...]any{
8790 nil,
8791 valueStringer{},
8792 (*valueStringer)(nil),
8793 addr(valueStringer{}),
8794 (**valueStringer)(nil),
8795 addr((*valueStringer)(nil)),
8796 addr(addr(valueStringer{})),
8797 pointerStringer{},
8798 (*pointerStringer)(nil),
8799 addr(pointerStringer{}),
8800 (**pointerStringer)(nil),
8801 addr((*pointerStringer)(nil)),
8802 addr(addr(pointerStringer{})),
8803 "LAST",
8804 }),
8805 }, {
8806 name: jsontest.Name("Functions/Precedence/V1First"),
8807 opts: []Options{
8808 WithUnmarshalers(JoinUnmarshalers(
8809 UnmarshalFunc(func(b []byte, v *string) error {
8810 if string(b) != `"called"` {
8811 return fmt.Errorf("got %s, want %s", b, `"called"`)
8812 }
8813 *v = "called"
8814 return nil
8815 }),
8816 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8817 panic("should not be called")
8818 }),
8819 )),
8820 },
8821 inBuf: `"called"`,
8822 inVal: addr(""),
8823 want: addr("called"),
8824 }, {
8825 name: jsontest.Name("Functions/Precedence/V2First"),
8826 opts: []Options{
8827 WithUnmarshalers(JoinUnmarshalers(
8828 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8829 switch t, err := dec.ReadToken(); {
8830 case err != nil:
8831 return err
8832 case t.String() != "called":
8833 return fmt.Errorf("got %q, want %q", t, "called")
8834 }
8835 *v = "called"
8836 return nil
8837 }),
8838 UnmarshalFunc(func([]byte, *string) error {
8839 panic("should not be called")
8840 }),
8841 )),
8842 },
8843 inBuf: `"called"`,
8844 inVal: addr(""),
8845 want: addr("called"),
8846 }, {
8847 name: jsontest.Name("Functions/Precedence/V2Skipped"),
8848 opts: []Options{
8849 WithUnmarshalers(JoinUnmarshalers(
8850 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8851 return errors.ErrUnsupported
8852 }),
8853 UnmarshalFunc(func(b []byte, v *string) error {
8854 if string(b) != `"called"` {
8855 return fmt.Errorf("got %s, want %s", b, `"called"`)
8856 }
8857 *v = "called"
8858 return nil
8859 }),
8860 )),
8861 },
8862 inBuf: `"called"`,
8863 inVal: addr(""),
8864 want: addr("called"),
8865 }, {
8866 name: jsontest.Name("Functions/Precedence/NestedFirst"),
8867 opts: []Options{
8868 WithUnmarshalers(JoinUnmarshalers(
8869 JoinUnmarshalers(
8870 UnmarshalFunc(func(b []byte, v *string) error {
8871 if string(b) != `"called"` {
8872 return fmt.Errorf("got %s, want %s", b, `"called"`)
8873 }
8874 *v = "called"
8875 return nil
8876 }),
8877 ),
8878 UnmarshalFunc(func([]byte, *string) error {
8879 panic("should not be called")
8880 }),
8881 )),
8882 },
8883 inBuf: `"called"`,
8884 inVal: addr(""),
8885 want: addr("called"),
8886 }, {
8887 name: jsontest.Name("Functions/Precedence/NestedLast"),
8888 opts: []Options{
8889 WithUnmarshalers(JoinUnmarshalers(
8890 UnmarshalFunc(func(b []byte, v *string) error {
8891 if string(b) != `"called"` {
8892 return fmt.Errorf("got %s, want %s", b, `"called"`)
8893 }
8894 *v = "called"
8895 return nil
8896 }),
8897 JoinUnmarshalers(
8898 UnmarshalFunc(func([]byte, *string) error {
8899 panic("should not be called")
8900 }),
8901 ),
8902 )),
8903 },
8904 inBuf: `"called"`,
8905 inVal: addr(""),
8906 want: addr("called"),
8907 }, {
8908 name: jsontest.Name("Duration/Null"),
8909 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
8910 inBuf: `{"D1":null,"D2":null}`,
8911 inVal: addr(struct {
8912 D1 time.Duration `json:",format:units"`
8913 D2 time.Duration `json:",format:nano"`
8914 }{1, 1}),
8915 want: addr(struct {
8916 D1 time.Duration `json:",format:units"`
8917 D2 time.Duration `json:",format:nano"`
8918 }{0, 0}),
8919 }, {
8920 name: jsontest.Name("Duration/Zero"),
8921 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
8922 inBuf: `{"D1":"0s","D2":0}`,
8923 inVal: addr(struct {
8924 D1 time.Duration `json:",format:units"`
8925 D2 time.Duration `json:",format:nano"`
8926 }{1, 1}),
8927 want: addr(struct {
8928 D1 time.Duration `json:",format:units"`
8929 D2 time.Duration `json:",format:nano"`
8930 }{0, 0}),
8931 }, {
8932 name: jsontest.Name("Duration/Positive"),
8933 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
8934 inBuf: `{"D1":"34293h33m9.123456789s","D2":123456789123456789}`,
8935 inVal: new(struct {
8936 D1 time.Duration `json:",format:units"`
8937 D2 time.Duration `json:",format:nano"`
8938 }),
8939 want: addr(struct {
8940 D1 time.Duration `json:",format:units"`
8941 D2 time.Duration `json:",format:nano"`
8942 }{
8943 123456789123456789,
8944 123456789123456789,
8945 }),
8946 }, {
8947 name: jsontest.Name("Duration/Negative"),
8948 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
8949 inBuf: `{"D1":"-34293h33m9.123456789s","D2":-123456789123456789}`,
8950 inVal: new(struct {
8951 D1 time.Duration `json:",format:units"`
8952 D2 time.Duration `json:",format:nano"`
8953 }),
8954 want: addr(struct {
8955 D1 time.Duration `json:",format:units"`
8956 D2 time.Duration `json:",format:nano"`
8957 }{
8958 -123456789123456789,
8959 -123456789123456789,
8960 }),
8961 }, {
8962 name: jsontest.Name("Duration/Nanos/String"),
8963 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
8964 inBuf: `{"D":"12345"}`,
8965 inVal: addr(struct {
8966 D time.Duration `json:",string,format:nano"`
8967 }{1}),
8968 want: addr(struct {
8969 D time.Duration `json:",string,format:nano"`
8970 }{12345}),
8971 }, {
8972 name: jsontest.Name("Duration/Nanos/String/Invalid"),
8973 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
8974 inBuf: `{"D":"+12345"}`,
8975 inVal: addr(struct {
8976 D time.Duration `json:",string,format:nano"`
8977 }{1}),
8978 want: addr(struct {
8979 D time.Duration `json:",string,format:nano"`
8980 }{1}),
8981 wantErr: EU(fmt.Errorf(`invalid duration "+12345": %w`, strconv.ErrSyntax)).withPos(`{"D":`, "/D").withType('"', timeDurationType),
8982 }, {
8983 name: jsontest.Name("Duration/Nanos/Mismatch"),
8984 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
8985 inBuf: `{"D":"34293h33m9.123456789s"}`,
8986 inVal: addr(struct {
8987 D time.Duration `json:",format:nano"`
8988 }{1}),
8989 want: addr(struct {
8990 D time.Duration `json:",format:nano"`
8991 }{1}),
8992 wantErr: EU(nil).withPos(`{"D":`, "/D").withType('"', timeDurationType),
8993 }, {
8994 name: jsontest.Name("Duration/Nanos"),
8995 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
8996 inBuf: `{"D":1.324}`,
8997 inVal: addr(struct {
8998 D time.Duration `json:",format:nano"`
8999 }{-1}),
9000 want: addr(struct {
9001 D time.Duration `json:",format:nano"`
9002 }{1}),
9003 }, {
9004 name: jsontest.Name("Duration/String/Mismatch"),
9005 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
9006 inBuf: `{"D":-123456789123456789}`,
9007 inVal: addr(struct {
9008 D time.Duration `json:",format:units"`
9009 }{1}),
9010 want: addr(struct {
9011 D time.Duration `json:",format:units"`
9012 }{1}),
9013 wantErr: EU(nil).withPos(`{"D":`, "/D").withType('0', timeDurationType),
9014 }, {
9015 name: jsontest.Name("Duration/String/Invalid"),
9016 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
9017 inBuf: `{"D":"5minkutes"}`,
9018 inVal: addr(struct {
9019 D time.Duration `json:",format:units"`
9020 }{1}),
9021 want: addr(struct {
9022 D time.Duration `json:",format:units"`
9023 }{1}),
9024 wantErr: EU(func() error {
9025 _, err := time.ParseDuration("5minkutes")
9026 return err
9027 }()).withPos(`{"D":`, "/D").withType('"', timeDurationType),
9028 }, {
9029 name: jsontest.Name("Duration/Syntax/Invalid"),
9030 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
9031 inBuf: `{"D":x}`,
9032 inVal: addr(struct {
9033 D time.Duration `json:",format:units"`
9034 }{1}),
9035 want: addr(struct {
9036 D time.Duration `json:",format:units"`
9037 }{1}),
9038 wantErr: newInvalidCharacterError("x", "at start of value", len64(`{"D":`), "/D"),
9039 }, {
9040 name: jsontest.Name("Duration/Format"),
9041 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
9042 inBuf: `{
9043 "D1": "12h34m56.078090012s",
9044 "D2": "12h34m56.078090012s",
9045 "D3": 45296.078090012,
9046 "D4": "45296.078090012",
9047 "D5": 45296078.090012,
9048 "D6": "45296078.090012",
9049 "D7": 45296078090.012,
9050 "D8": "45296078090.012",
9051 "D9": 45296078090012,
9052 "D10": "45296078090012",
9053 "D11": "PT12H34M56.078090012S"
9054 }`,
9055 inVal: new(structDurationFormat),
9056 want: addr(structDurationFormat{
9057 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
9058 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
9059 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
9060 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
9061 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
9062 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
9063 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
9064 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
9065 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
9066 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
9067 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
9068 }),
9069 }, {
9070 name: jsontest.Name("Duration/Format/Invalid"),
9071 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
9072 inBuf: `{"D":"0s"}`,
9073 inVal: addr(struct {
9074 D time.Duration `json:",format:invalid"`
9075 }{1}),
9076 want: addr(struct {
9077 D time.Duration `json:",format:invalid"`
9078 }{1}),
9079 wantErr: EU(errInvalidFormatFlag).withPos(`{"D":`, "/D").withType(0, timeDurationType),
9080 }, {
9081
9091
9097 name: jsontest.Name("Duration/MapKey/Legacy"),
9098 opts: []Options{jsonflags.FormatDurationAsNano | 1},
9099 inBuf: `{"1000000000":""}`,
9100 inVal: new(map[time.Duration]string),
9101 want: addr(map[time.Duration]string{time.Second: ""}),
9102 }, {
9103
9110 name: jsontest.Name("Time/Zero"),
9111 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
9112 inBuf: `{"T1":"0001-01-01T00:00:00Z","T2":"01 Jan 01 00:00 UTC","T3":"0001-01-01","T4":"0001-01-01T00:00:00Z","T5":"0001-01-01T00:00:00Z"}`,
9113 inVal: new(struct {
9114 T1 time.Time
9115 T2 time.Time `json:",format:RFC822"`
9116 T3 time.Time `json:",format:'2006-01-02'"`
9117 T4 time.Time `json:",omitzero"`
9118 T5 time.Time `json:",omitempty"`
9119 }),
9120 want: addr(struct {
9121 T1 time.Time
9122 T2 time.Time `json:",format:RFC822"`
9123 T3 time.Time `json:",format:'2006-01-02'"`
9124 T4 time.Time `json:",omitzero"`
9125 T5 time.Time `json:",omitempty"`
9126 }{
9127 mustParseTime(time.RFC3339Nano, "0001-01-01T00:00:00Z"),
9128 mustParseTime(time.RFC822, "01 Jan 01 00:00 UTC"),
9129 mustParseTime("2006-01-02", "0001-01-01"),
9130 mustParseTime(time.RFC3339Nano, "0001-01-01T00:00:00Z"),
9131 mustParseTime(time.RFC3339Nano, "0001-01-01T00:00:00Z"),
9132 }),
9133 }, {
9134 name: jsontest.Name("Time/Format"),
9135 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
9136 inBuf: `{
9137 "T1": "1234-01-02T03:04:05.000000006Z",
9138 "T2": "Mon Jan 2 03:04:05 1234",
9139 "T3": "Mon Jan 2 03:04:05 UTC 1234",
9140 "T4": "Mon Jan 02 03:04:05 +0000 1234",
9141 "T5": "02 Jan 34 03:04 UTC",
9142 "T6": "02 Jan 34 03:04 +0000",
9143 "T7": "Monday, 02-Jan-34 03:04:05 UTC",
9144 "T8": "Mon, 02 Jan 1234 03:04:05 UTC",
9145 "T9": "Mon, 02 Jan 1234 03:04:05 +0000",
9146 "T10": "1234-01-02T03:04:05Z",
9147 "T11": "1234-01-02T03:04:05.000000006Z",
9148 "T12": "3:04AM",
9149 "T13": "Jan 2 03:04:05",
9150 "T14": "Jan 2 03:04:05.000",
9151 "T15": "Jan 2 03:04:05.000000",
9152 "T16": "Jan 2 03:04:05.000000006",
9153 "T17": "1234-01-02 03:04:05",
9154 "T18": "1234-01-02",
9155 "T19": "03:04:05",
9156 "T20": "1234-01-02",
9157 "T21": "\"weird\"1234",
9158 "T22": -23225777754.999999994,
9159 "T23": "-23225777754.999999994",
9160 "T24": -23225777754999.999994,
9161 "T25": "-23225777754999.999994",
9162 "T26": -23225777754999999.994,
9163 "T27": "-23225777754999999.994",
9164 "T28": -23225777754999999994,
9165 "T29": "-23225777754999999994"
9166 }`,
9167 inVal: new(structTimeFormat),
9168 want: addr(structTimeFormat{
9169 mustParseTime(time.RFC3339Nano, "1234-01-02T03:04:05.000000006Z"),
9170 mustParseTime(time.ANSIC, "Mon Jan 2 03:04:05 1234"),
9171 mustParseTime(time.UnixDate, "Mon Jan 2 03:04:05 UTC 1234"),
9172 mustParseTime(time.RubyDate, "Mon Jan 02 03:04:05 +0000 1234"),
9173 mustParseTime(time.RFC822, "02 Jan 34 03:04 UTC"),
9174 mustParseTime(time.RFC822Z, "02 Jan 34 03:04 +0000"),
9175 mustParseTime(time.RFC850, "Monday, 02-Jan-34 03:04:05 UTC"),
9176 mustParseTime(time.RFC1123, "Mon, 02 Jan 1234 03:04:05 UTC"),
9177 mustParseTime(time.RFC1123Z, "Mon, 02 Jan 1234 03:04:05 +0000"),
9178 mustParseTime(time.RFC3339, "1234-01-02T03:04:05Z"),
9179 mustParseTime(time.RFC3339Nano, "1234-01-02T03:04:05.000000006Z"),
9180 mustParseTime(time.Kitchen, "3:04AM"),
9181 mustParseTime(time.Stamp, "Jan 2 03:04:05"),
9182 mustParseTime(time.StampMilli, "Jan 2 03:04:05.000"),
9183 mustParseTime(time.StampMicro, "Jan 2 03:04:05.000000"),
9184 mustParseTime(time.StampNano, "Jan 2 03:04:05.000000006"),
9185 mustParseTime(time.DateTime, "1234-01-02 03:04:05"),
9186 mustParseTime(time.DateOnly, "1234-01-02"),
9187 mustParseTime(time.TimeOnly, "03:04:05"),
9188 mustParseTime("2006-01-02", "1234-01-02"),
9189 mustParseTime(`\"weird\"2006`, `\"weird\"1234`),
9190 time.Unix(-23225777755, 6).UTC(),
9191 time.Unix(-23225777755, 6).UTC(),
9192 time.Unix(-23225777755, 6).UTC(),
9193 time.Unix(-23225777755, 6).UTC(),
9194 time.Unix(-23225777755, 6).UTC(),
9195 time.Unix(-23225777755, 6).UTC(),
9196 time.Unix(-23225777755, 6).UTC(),
9197 time.Unix(-23225777755, 6).UTC(),
9198 }),
9199 }, {
9200 name: jsontest.Name("Time/Format/String/Invalid"),
9201 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
9202 inBuf: `{"T":"2023-01-01T00:00:00Z"}`,
9203 inVal: new(structTimeFormatStringInvalid),
9204 want: new(structTimeFormatStringInvalid),
9205 wantErr: EU(errInvalidStringTag).withPos(`{"T":`, "/T").withType(0, timeTimeType),
9206 }, {
9207 name: jsontest.Name("Time/Format/UnixString/InvalidNumber"),
9208 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
9209 inBuf: `{
9210 "T23": -23225777754.999999994,
9211 "T25": -23225777754999.999994,
9212 "T27": -23225777754999999.994,
9213 "T29": -23225777754999999994
9214 }`,
9215 inVal: new(structTimeFormat),
9216 want: new(structTimeFormat),
9217 wantErr: EU(nil).withPos(`{`+"\n\t\t\t"+`"T23": `, "/T23").withType('0', timeTimeType),
9218 }, {
9219 name: jsontest.Name("Time/Format/UnixString/InvalidString"),
9220 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
9221 inBuf: `{
9222 "T22": "-23225777754.999999994",
9223 "T24": "-23225777754999.999994",
9224 "T26": "-23225777754999999.994",
9225 "T28": "-23225777754999999994"
9226 }`,
9227 inVal: new(structTimeFormat),
9228 want: new(structTimeFormat),
9229 wantErr: EU(nil).withPos(`{`+"\n\t\t\t"+`"T22": `, "/T22").withType('"', timeTimeType),
9230 }, {
9231 name: jsontest.Name("Time/Format/Null"),
9232 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
9233 inBuf: `{"T1":null,"T2":null,"T3":null,"T4":null,"T5":null,"T6":null,"T7":null,"T8":null,"T9":null,"T10":null,"T11":null,"T12":null,"T13":null,"T14":null,"T15":null,"T16":null,"T17":null,"T18":null,"T19":null,"T20":null,"T21":null,"T22":null,"T23":null,"T24":null,"T25":null,"T26":null,"T27":null,"T28":null,"T29":null}`,
9234 inVal: addr(structTimeFormat{
9235 mustParseTime(time.RFC3339Nano, "1234-01-02T03:04:05.000000006Z"),
9236 mustParseTime(time.ANSIC, "Mon Jan 2 03:04:05 1234"),
9237 mustParseTime(time.UnixDate, "Mon Jan 2 03:04:05 UTC 1234"),
9238 mustParseTime(time.RubyDate, "Mon Jan 02 03:04:05 +0000 1234"),
9239 mustParseTime(time.RFC822, "02 Jan 34 03:04 UTC"),
9240 mustParseTime(time.RFC822Z, "02 Jan 34 03:04 +0000"),
9241 mustParseTime(time.RFC850, "Monday, 02-Jan-34 03:04:05 UTC"),
9242 mustParseTime(time.RFC1123, "Mon, 02 Jan 1234 03:04:05 UTC"),
9243 mustParseTime(time.RFC1123Z, "Mon, 02 Jan 1234 03:04:05 +0000"),
9244 mustParseTime(time.RFC3339, "1234-01-02T03:04:05Z"),
9245 mustParseTime(time.RFC3339Nano, "1234-01-02T03:04:05.000000006Z"),
9246 mustParseTime(time.Kitchen, "3:04AM"),
9247 mustParseTime(time.Stamp, "Jan 2 03:04:05"),
9248 mustParseTime(time.StampMilli, "Jan 2 03:04:05.000"),
9249 mustParseTime(time.StampMicro, "Jan 2 03:04:05.000000"),
9250 mustParseTime(time.StampNano, "Jan 2 03:04:05.000000006"),
9251 mustParseTime(time.DateTime, "1234-01-02 03:04:05"),
9252 mustParseTime(time.DateOnly, "1234-01-02"),
9253 mustParseTime(time.TimeOnly, "03:04:05"),
9254 mustParseTime("2006-01-02", "1234-01-02"),
9255 mustParseTime(`\"weird\"2006`, `\"weird\"1234`),
9256 time.Unix(-23225777755, 6).UTC(),
9257 time.Unix(-23225777755, 6).UTC(),
9258 time.Unix(-23225777755, 6).UTC(),
9259 time.Unix(-23225777755, 6).UTC(),
9260 time.Unix(-23225777755, 6).UTC(),
9261 time.Unix(-23225777755, 6).UTC(),
9262 time.Unix(-23225777755, 6).UTC(),
9263 time.Unix(-23225777755, 6).UTC(),
9264 }),
9265 want: new(structTimeFormat),
9266 }, {
9267 name: jsontest.Name("Time/RFC3339/Mismatch"),
9268 inBuf: `{"T":1234}`,
9269 inVal: new(struct {
9270 T time.Time
9271 }),
9272 wantErr: EU(nil).withPos(`{"T":`, "/T").withType('0', timeTimeType),
9273 }, {
9274 name: jsontest.Name("Time/RFC3339/ParseError"),
9275 inBuf: `{"T":"2021-09-29T12:44:52"}`,
9276 inVal: new(struct {
9277 T time.Time
9278 }),
9279 wantErr: EU(func() error {
9280 _, err := time.Parse(time.RFC3339, "2021-09-29T12:44:52")
9281 return err
9282 }()).withPos(`{"T":`, "/T").withType('"', timeTimeType),
9283 }, {
9284 name: jsontest.Name("Time/Format/Invalid"),
9285 opts: []Options{jsonopts.ExperimentalSupportFormatTag(true)},
9286 inBuf: `{"T":""}`,
9287 inVal: new(struct {
9288 T time.Time `json:",format:UndefinedConstant"`
9289 }),
9290 wantErr: EU(errors.New(`invalid format flag "UndefinedConstant"`)).withPos(`{"T":`, "/T").withType(0, timeTimeType),
9291 }, {
9292 name: jsontest.Name("Time/Format/SingleDigitHour"),
9293 inBuf: `{"T":"2000-01-01T1:12:34Z"}`,
9294 inVal: new(struct{ T time.Time }),
9295 wantErr: EU(newParseTimeError(time.RFC3339, "2000-01-01T1:12:34Z", "15", "1", "")).withPos(`{"T":`, "/T").withType('"', timeTimeType),
9296 }, {
9297 name: jsontest.Name("Time/Format/SubsecondComma"),
9298 inBuf: `{"T":"2000-01-01T00:00:00,000Z"}`,
9299 inVal: new(struct{ T time.Time }),
9300 wantErr: EU(newParseTimeError(time.RFC3339, "2000-01-01T00:00:00,000Z", ".", ",", "")).withPos(`{"T":`, "/T").withType('"', timeTimeType),
9301 }, {
9302 name: jsontest.Name("Time/Format/TimezoneHourOverflow"),
9303 inBuf: `{"T":"2000-01-01T00:00:00+24:00"}`,
9304 inVal: new(struct{ T time.Time }),
9305 wantErr: EU(newParseTimeError(time.RFC3339, "2000-01-01T00:00:00+24:00", "Z07:00", "+24:00", ": timezone hour out of range")).withPos(`{"T":`, "/T").withType('"', timeTimeType),
9306 }, {
9307 name: jsontest.Name("Time/Format/TimezoneMinuteOverflow"),
9308 inBuf: `{"T":"2000-01-01T00:00:00+00:60"}`,
9309 inVal: new(struct{ T time.Time }),
9310 wantErr: EU(newParseTimeError(time.RFC3339, "2000-01-01T00:00:00+00:60", "Z07:00", "+00:60", ": timezone minute out of range")).withPos(`{"T":`, "/T").withType('"', timeTimeType),
9311 }, {
9312 name: jsontest.Name("Time/Syntax/Invalid"),
9313 inBuf: `{"T":x}`,
9314 inVal: new(struct {
9315 T time.Time
9316 }),
9317 wantErr: newInvalidCharacterError("x", "at start of value", len64(`{"T":`), "/T"),
9318 }, {
9319 name: jsontest.Name("Time/IgnoreInvalidFormat"),
9320 opts: []Options{invalidFormatOption},
9321 inBuf: `"2000-01-01T00:00:00Z"`,
9322 inVal: addr(time.Time{}),
9323 want: addr(time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)),
9324 }}
9325
9326 for _, tt := range tests {
9327 if tt.skip {
9328 continue
9329 }
9330 t.Run(tt.name.Name, func(t *testing.T) {
9331 got := tt.inVal
9332 gotErr := Unmarshal([]byte(tt.inBuf), got, tt.opts...)
9333 if !reflect.DeepEqual(got, tt.want) && tt.want != nil {
9334 t.Errorf("%s: Unmarshal output mismatch:\ngot %v\nwant %v", tt.name.Where, got, tt.want)
9335 }
9336 if !reflect.DeepEqual(gotErr, tt.wantErr) {
9337 t.Errorf("%s: Unmarshal error mismatch:\ngot %v\nwant %v", tt.name.Where, gotErr, tt.wantErr)
9338 }
9339 })
9340 }
9341 }
9342
9343 func TestMarshalInvalidNamespace(t *testing.T) {
9344 tests := []struct {
9345 name jsontest.CaseName
9346 val any
9347 }{
9348 {jsontest.Name("Map"), map[string]string{"X": "\xde\xad\xbe\xef"}},
9349 {jsontest.Name("Struct"), struct{ X string }{"\xde\xad\xbe\xef"}},
9350 {jsontest.Name("MapBadKey"), map[string]int{"\xde\xad\xbe\xef": 0}},
9351 }
9352 for _, tt := range tests {
9353 t.Run(tt.name.Name, func(t *testing.T) {
9354 enc := jsontext.NewEncoder(new(bytes.Buffer))
9355 if err := MarshalEncode(enc, tt.val); err == nil {
9356 t.Fatalf("%s: MarshalEncode error is nil, want non-nil", tt.name.Where)
9357 }
9358 for _, tok := range []jsontext.Token{
9359 jsontext.Null, jsontext.String(""), jsontext.Int(0), jsontext.BeginObject, jsontext.EndObject, jsontext.BeginArray, jsontext.EndArray,
9360 } {
9361 if err := enc.WriteToken(tok); err == nil {
9362 t.Fatalf("%s: WriteToken error is nil, want non-nil", tt.name.Where)
9363 }
9364 }
9365 for _, val := range []string{`null`, `""`, `0`, `{}`, `[]`} {
9366 if err := enc.WriteValue([]byte(val)); err == nil {
9367 t.Fatalf("%s: WriteToken error is nil, want non-nil", tt.name.Where)
9368 }
9369 }
9370 })
9371 }
9372 }
9373
9374
9375
9376
9377 func TestMarshalEncodeInvalidNamespaceAtName(t *testing.T) {
9378 enc := jsontext.NewEncoder(new(bytes.Buffer))
9379
9380
9381
9382
9383 if err := MarshalEncode(enc, map[string]int{"\xde\xad\xbe\xef": 0}); err == nil {
9384 t.Fatal("MarshalEncode error is nil, want non-nil")
9385 }
9386
9387 var serr *jsontext.SyntacticError
9388 if err := MarshalEncode(enc, 0); !errors.As(err, &serr) || serr.Err == nil {
9389 t.Fatalf("MarshalEncode error = %v, want *jsontext.SyntacticError wrapping a non-nil error", err)
9390 }
9391 }
9392
9393 func TestUnmarshalInvalidNamespace(t *testing.T) {
9394 tests := []struct {
9395 name jsontest.CaseName
9396 val any
9397 }{
9398 {jsontest.Name("Map"), addr(map[string]int{})},
9399 {jsontest.Name("Struct"), addr(struct{ X int }{})},
9400 }
9401 for _, tt := range tests {
9402 t.Run(tt.name.Name, func(t *testing.T) {
9403 dec := jsontext.NewDecoder(strings.NewReader(`{"X":""}`))
9404 if err := UnmarshalDecode(dec, tt.val); err == nil {
9405 t.Fatalf("%s: UnmarshalDecode error is nil, want non-nil", tt.name.Where)
9406 }
9407 if _, err := dec.ReadToken(); err == nil {
9408 t.Fatalf("%s: ReadToken error is nil, want non-nil", tt.name.Where)
9409 }
9410 if _, err := dec.ReadValue(); err == nil {
9411 t.Fatalf("%s: ReadValue error is nil, want non-nil", tt.name.Where)
9412 }
9413 })
9414 }
9415 }
9416
9417 func TestUnmarshalReuse(t *testing.T) {
9418 t.Run("Bytes", func(t *testing.T) {
9419 in := make([]byte, 3)
9420 want := &in[0]
9421 if err := Unmarshal([]byte(`"AQID"`), &in); err != nil {
9422 t.Fatalf("Unmarshal error: %v", err)
9423 }
9424 got := &in[0]
9425 if got != want {
9426 t.Errorf("input buffer was not reused")
9427 }
9428 })
9429 t.Run("Slices", func(t *testing.T) {
9430 in := make([]int, 3)
9431 want := &in[0]
9432 if err := Unmarshal([]byte(`[0,1,2]`), &in); err != nil {
9433 t.Fatalf("Unmarshal error: %v", err)
9434 }
9435 got := &in[0]
9436 if got != want {
9437 t.Errorf("input slice was not reused")
9438 }
9439 })
9440 t.Run("Maps", func(t *testing.T) {
9441 in := make(map[string]string)
9442 want := reflect.ValueOf(in).Pointer()
9443 if err := Unmarshal([]byte(`{"key":"value"}`), &in); err != nil {
9444 t.Fatalf("Unmarshal error: %v", err)
9445 }
9446 got := reflect.ValueOf(in).Pointer()
9447 if got != want {
9448 t.Errorf("input map was not reused")
9449 }
9450 })
9451 t.Run("Pointers", func(t *testing.T) {
9452 in := addr(addr(addr("hello")))
9453 want := **in
9454 if err := Unmarshal([]byte(`"goodbye"`), &in); err != nil {
9455 t.Fatalf("Unmarshal error: %v", err)
9456 }
9457 got := **in
9458 if got != want {
9459 t.Errorf("input pointer was not reused")
9460 }
9461 })
9462 }
9463
9464 type unmarshalerEOF struct{}
9465
9466 func (unmarshalerEOF) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
9467 return io.EOF
9468 }
9469
9470
9471
9472 func TestUnmarshalEOF(t *testing.T) {
9473 opts := WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, _ *struct{}) error {
9474 return io.EOF
9475 }))
9476
9477 for _, in := range []string{"", "[", "[null", "[null]"} {
9478 for _, newOut := range []func() any{
9479 func() any { return new(unmarshalerEOF) },
9480 func() any { return new([]unmarshalerEOF) },
9481 func() any { return new(struct{}) },
9482 func() any { return new([]struct{}) },
9483 } {
9484 wantErr := io.ErrUnexpectedEOF
9485 if gotErr := Unmarshal([]byte(in), newOut(), opts); !errors.Is(gotErr, wantErr) {
9486 t.Errorf("Unmarshal = %v, want %v", gotErr, wantErr)
9487 }
9488 if gotErr := UnmarshalRead(strings.NewReader(in), newOut(), opts); !errors.Is(gotErr, wantErr) {
9489 t.Errorf("Unmarshal = %v, want %v", gotErr, wantErr)
9490 }
9491 switch gotErr := UnmarshalDecode(jsontext.NewDecoder(strings.NewReader(in)), newOut(), opts); {
9492 case in != "" && !errors.Is(gotErr, wantErr):
9493 t.Errorf("Unmarshal = %v, want %v", gotErr, wantErr)
9494 case in == "" && gotErr != io.EOF:
9495 t.Errorf("Unmarshal = %v, want %v", gotErr, io.EOF)
9496 }
9497 }
9498 }
9499 }
9500
9501 type ReaderFunc func([]byte) (int, error)
9502
9503 func (f ReaderFunc) Read(b []byte) (int, error) { return f(b) }
9504
9505 type WriterFunc func([]byte) (int, error)
9506
9507 func (f WriterFunc) Write(b []byte) (int, error) { return f(b) }
9508
9509 func TestCoderBufferGrowth(t *testing.T) {
9510
9511
9512 checkGrowth := func(ns []int) {
9513 t.Helper()
9514 var sumBytes, sumRates, numGrows float64
9515 prev := ns[0]
9516 for i := 1; i < len(ns)-1; i++ {
9517 n := ns[i]
9518 if n != prev {
9519 sumRates += float64(n) / float64(prev)
9520 numGrows++
9521 prev = n
9522 }
9523 if n > 1<<20 {
9524 t.Fatalf("single Read/Write too large: %d", n)
9525 }
9526 sumBytes += float64(n)
9527 }
9528 if mean := sumBytes / float64(len(ns)); mean < 1<<10 {
9529 t.Fatalf("average Read/Write too small: %0.1f", mean)
9530 }
9531 switch mean := sumRates / numGrows; {
9532 case mean < 1.25:
9533 t.Fatalf("average growth rate too slow: %0.3f", mean)
9534 case mean > 2.00:
9535 t.Fatalf("average growth rate too fast: %0.3f", mean)
9536 }
9537 }
9538
9539
9540
9541 bb := struct{ *bytes.Buffer }{new(bytes.Buffer)}
9542
9543 var writeSizes []int
9544 if err := MarshalWrite(WriterFunc(func(b []byte) (int, error) {
9545 n, err := bb.Write(b)
9546 writeSizes = append(writeSizes, n)
9547 return n, err
9548 }), make([]struct{}, 1e6)); err != nil {
9549 t.Fatalf("MarshalWrite error: %v", err)
9550 }
9551 checkGrowth(writeSizes)
9552
9553 var readSizes []int
9554 if err := UnmarshalRead(ReaderFunc(func(b []byte) (int, error) {
9555 n, err := bb.Read(b)
9556 readSizes = append(readSizes, n)
9557 return n, err
9558 }), new([]struct{})); err != nil {
9559 t.Fatalf("UnmarshalRead error: %v", err)
9560 }
9561 checkGrowth(readSizes)
9562 }
9563
9564 func TestUintSet(t *testing.T) {
9565 type operation any
9566 type has struct {
9567 in uint
9568 want bool
9569 }
9570 type insert struct {
9571 in uint
9572 want bool
9573 }
9574
9575
9576 ops := []operation{
9577 has{0, false},
9578 has{63, false},
9579 has{64, false},
9580 has{1234, false},
9581 insert{3, true},
9582 has{2, false},
9583 has{3, true},
9584 has{4, false},
9585 has{63, false},
9586 insert{3, false},
9587 insert{63, true},
9588 has{63, true},
9589 insert{64, true},
9590 insert{64, false},
9591 has{64, true},
9592 insert{3264, true},
9593 has{3264, true},
9594 insert{3, false},
9595 has{3, true},
9596 }
9597
9598 var us uintSet
9599 for i, op := range ops {
9600 switch op := op.(type) {
9601 case has:
9602 if got := us.has(op.in); got != op.want {
9603 t.Fatalf("%d: uintSet.has(%v) = %v, want %v", i, op.in, got, op.want)
9604 }
9605 case insert:
9606 if got := us.insert(op.in); got != op.want {
9607 t.Fatalf("%d: uintSet.insert(%v) = %v, want %v", i, op.in, got, op.want)
9608 }
9609 default:
9610 panic(fmt.Sprintf("unknown operation: %T", op))
9611 }
9612 }
9613 }
9614
9615 func TestUnmarshalDecodeOptions(t *testing.T) {
9616 var calledFuncs int
9617 var calledOptions Options
9618 in := strings.NewReader(strings.Repeat("\"\xde\xad\xbe\xef\"\n", 5))
9619 dec := jsontext.NewDecoder(in,
9620 jsontext.AllowInvalidUTF8(true),
9621 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, _ any) error {
9622 opts := dec.Options()
9623 if v, _ := GetOption(opts, jsontext.AllowInvalidUTF8); !v {
9624 t.Errorf("nested Options.AllowInvalidUTF8 = false, want true")
9625 }
9626 calledFuncs++
9627 calledOptions = opts
9628 return errors.ErrUnsupported
9629 })),
9630 )
9631
9632 if err := UnmarshalDecode(dec, new(string)); err != nil {
9633 t.Fatalf("UnmarshalDecode: %v", err)
9634 }
9635 if calledFuncs != 1 {
9636 t.Fatalf("calledFuncs = %d, want 1", calledFuncs)
9637 }
9638 if err := UnmarshalDecode(dec, new(string), calledOptions); err != nil {
9639 t.Fatalf("UnmarshalDecode: %v", err)
9640 }
9641 if calledFuncs != 2 {
9642 t.Fatalf("calledFuncs = %d, want 2", calledFuncs)
9643 }
9644 if err := UnmarshalDecode(dec, new(string),
9645 jsontext.AllowInvalidUTF8(false),
9646 WithUnmarshalers(nil),
9647 ); !errors.Is(err, jsonwire.ErrInvalidUTF8) {
9648 t.Fatalf("UnmarshalDecode = %v, want %v", err, jsonwire.ErrInvalidUTF8)
9649 }
9650 if err := UnmarshalDecode(dec, new(string),
9651 WithUnmarshalers(nil),
9652 ); err != nil {
9653 t.Fatalf("UnmarshalDecode: %v", err)
9654 }
9655 if calledFuncs != 2 {
9656 t.Fatalf("calledFuncs = %d, want 2", calledFuncs)
9657 }
9658 if err := UnmarshalDecode(dec, new(string)); err != nil {
9659 t.Fatalf("UnmarshalDecode: %v", err)
9660 }
9661 if calledFuncs != 3 {
9662 t.Fatalf("calledFuncs = %d, want 3", calledFuncs)
9663 }
9664 if err := UnmarshalDecode(dec, new(string), JoinOptions(
9665 WithUnmarshalers(UnmarshalFromFunc(func(_ *jsontext.Decoder, _ any) error {
9666 opts := dec.Options()
9667 if v, _ := GetOption(opts, jsontext.AllowInvalidUTF8); !v {
9668 t.Errorf("nested Options.AllowInvalidUTF8 = false, want true")
9669 }
9670 calledFuncs = math.MaxInt
9671 return errors.ErrUnsupported
9672 })),
9673 )); err != nil {
9674 t.Fatalf("UnmarshalDecode: %v", err)
9675 }
9676 if calledFuncs != math.MaxInt {
9677 t.Fatalf("calledFuncs = %d, want %d", calledFuncs, math.MaxInt)
9678 }
9679
9680
9681
9682 opts := dec.Options()
9683 dec.Reset(in, jsontext.AllowInvalidUTF8(false), opts)
9684 if v, _ := GetOption(dec.Options(), jsontext.AllowInvalidUTF8); v == false {
9685 t.Errorf("Options.AllowInvalidUTF8 = false, want true")
9686 }
9687
9688
9689
9690 {
9691 dec2 := jsontext.NewDecoder(strings.NewReader(`{"name":{"dupe":"value","dupe":"value"}}`))
9692 if tok, err := dec2.ReadToken(); tok.Kind() != '{' || err != nil {
9693 t.Fatalf("ReadToken = (%v, %v), want ('{', nil)", tok.Kind(), err)
9694 }
9695 var name string
9696 if err := UnmarshalDecode(dec2, &name, jsontext.AllowDuplicateNames(true)); !errors.Is(err, errChangingDuplicateNames) {
9697 t.Errorf("UnmarshalDecode(name) = %v, want %v", err, errChangingDuplicateNames)
9698 }
9699 if err := UnmarshalDecode(dec2, &name, jsontext.AllowInvalidUTF8(true)); !errors.Is(err, errChangingInvalidUTF8) {
9700 t.Errorf("UnmarshalDecode(name) = %v, want %v", err, errChangingInvalidUTF8)
9701 }
9702
9703 if err := UnmarshalDecode(dec2, &name, jsontext.AllowDuplicateNames(false)); err != nil {
9704 t.Errorf("UnmarshalDecode(name) = %v, want nil", err)
9705 } else if name != "name" {
9706 t.Errorf("UnmarshalDecode(name) = %q, want %q", name, "name")
9707 }
9708
9709 var value jsontext.Value
9710 if err := UnmarshalDecode(dec2, &value, jsontext.AllowDuplicateNames(true)); err != nil {
9711 t.Errorf("UnmarshalDecode(value) = %v, want nil", err)
9712 }
9713 const want = `{"dupe":"value","dupe":"value"}`
9714 if string(value) != string(want) {
9715 t.Errorf("UnmarshalDecode(value) = %s, want %s", value, want)
9716 }
9717 }
9718 }
9719
9720 func TestUnmarshalDecodeStream(t *testing.T) {
9721 tests := []struct {
9722 in string
9723 want []any
9724 err error
9725 }{
9726 {in: ``, err: io.EOF},
9727 {in: `{`, err: &jsontext.SyntacticError{ByteOffset: len64(`{`), Err: io.ErrUnexpectedEOF}},
9728 {in: `{"`, err: &jsontext.SyntacticError{ByteOffset: len64(`{"`), Err: io.ErrUnexpectedEOF}},
9729 {in: `{"k"`, err: &jsontext.SyntacticError{ByteOffset: len64(`{"k"`), JSONPointer: "/k", Err: io.ErrUnexpectedEOF}},
9730 {in: `{"k":`, err: &jsontext.SyntacticError{ByteOffset: len64(`{"k":`), JSONPointer: "/k", Err: io.ErrUnexpectedEOF}},
9731 {in: `{"k",`, err: &jsontext.SyntacticError{ByteOffset: len64(`{"k"`), JSONPointer: "/k", Err: jsonwire.NewInvalidCharacterError(",", "after object name (expecting ':')")}},
9732 {in: `{"k"}`, err: &jsontext.SyntacticError{ByteOffset: len64(`{"k"`), JSONPointer: "/k", Err: jsonwire.NewInvalidCharacterError("}", "after object name (expecting ':')")}},
9733 {in: `[`, err: &jsontext.SyntacticError{ByteOffset: len64(`[`), Err: io.ErrUnexpectedEOF}},
9734 {in: `[0`, err: &jsontext.SyntacticError{ByteOffset: len64(`[0`), Err: io.ErrUnexpectedEOF}},
9735 {in: ` [0`, err: &jsontext.SyntacticError{ByteOffset: len64(` [0`), Err: io.ErrUnexpectedEOF}},
9736 {in: `[0.`, err: &jsontext.SyntacticError{ByteOffset: len64(`[`), JSONPointer: "/0", Err: io.ErrUnexpectedEOF}},
9737 {in: `[0. `, err: &jsontext.SyntacticError{ByteOffset: len64(`[0.`), JSONPointer: "/0", Err: jsonwire.NewInvalidCharacterError(" ", "in number (expecting digit)")}},
9738 {in: `[0,`, err: &jsontext.SyntacticError{ByteOffset: len64(`[0,`), Err: io.ErrUnexpectedEOF}},
9739 {in: `[0:`, err: &jsontext.SyntacticError{ByteOffset: len64(`[0`), Err: jsonwire.NewInvalidCharacterError(":", "after array element (expecting ',' or ']')")}},
9740 {in: `n`, err: &jsontext.SyntacticError{ByteOffset: len64(`n`), Err: io.ErrUnexpectedEOF}},
9741 {in: `nul`, err: &jsontext.SyntacticError{ByteOffset: len64(`nul`), Err: io.ErrUnexpectedEOF}},
9742 {in: `fal `, err: &jsontext.SyntacticError{ByteOffset: len64(`fal`), Err: jsonwire.NewInvalidCharacterError(" ", "in literal false (expecting 's')")}},
9743 {in: `false`, want: []any{false}, err: io.EOF},
9744 {in: `false0.0[]null`, want: []any{false, 0.0, []any{}, nil}, err: io.EOF},
9745 }
9746 for _, tt := range tests {
9747 d := jsontext.NewDecoder(strings.NewReader(tt.in))
9748 var got []any
9749 for {
9750 var v any
9751 if err := UnmarshalDecode(d, &v); err != nil {
9752 if !reflect.DeepEqual(err, tt.err) {
9753 t.Errorf("`%s`: UnmarshalDecode error = %v, want %v", tt.in, err, tt.err)
9754 }
9755 break
9756 }
9757 got = append(got, v)
9758 }
9759 if !reflect.DeepEqual(got, tt.want) {
9760 t.Errorf("`%s`: UnmarshalDecode = %v, want %v", tt.in, got, tt.want)
9761 }
9762 }
9763 }
9764
9765
9766
9767 func BenchmarkUnmarshalDecodeOptions(b *testing.B) {
9768 var i int
9769 in := new(bytes.Buffer)
9770 dec := jsontext.NewDecoder(in)
9771 makeBench := func(opts ...Options) func(*testing.B) {
9772 return func(b *testing.B) {
9773 for range b.N {
9774 in.WriteString("0 ")
9775 }
9776 dec.Reset(in)
9777 b.ResetTimer()
9778 for range b.N {
9779 UnmarshalDecode(dec, &i, opts...)
9780 }
9781 }
9782 }
9783 b.Run("None", makeBench())
9784 b.Run("Same", makeBench(&export.Decoder(dec).Struct))
9785 b.Run("New", makeBench(DefaultOptionsV2()))
9786 }
9787
9788 func TestMarshalEncodeOptions(t *testing.T) {
9789 var calledFuncs int
9790 var calledOptions Options
9791 out := new(bytes.Buffer)
9792 enc := jsontext.NewEncoder(
9793 out,
9794 jsontext.AllowInvalidUTF8(true),
9795 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, _ any) error {
9796 opts := enc.Options()
9797 if v, _ := GetOption(opts, jsontext.AllowInvalidUTF8); !v {
9798 t.Errorf("nested Options.AllowInvalidUTF8 = false, want true")
9799 }
9800 calledFuncs++
9801 calledOptions = opts
9802 return errors.ErrUnsupported
9803 })),
9804 )
9805
9806 if err := MarshalEncode(enc, "\xde\xad\xbe\xef"); err != nil {
9807 t.Fatalf("MarshalEncode: %v", err)
9808 }
9809 if calledFuncs != 1 {
9810 t.Fatalf("calledFuncs = %d, want 1", calledFuncs)
9811 }
9812 if err := MarshalEncode(enc, "\xde\xad\xbe\xef", calledOptions); err != nil {
9813 t.Fatalf("MarshalEncode: %v", err)
9814 }
9815 if calledFuncs != 2 {
9816 t.Fatalf("calledFuncs = %d, want 2", calledFuncs)
9817 }
9818 if err := MarshalEncode(enc, "\xde\xad\xbe\xef",
9819 jsontext.AllowInvalidUTF8(false),
9820 WithMarshalers(nil),
9821 ); !errors.Is(err, jsonwire.ErrInvalidUTF8) {
9822 t.Fatalf("MarshalEncode = %v, want %v", err, jsonwire.ErrInvalidUTF8)
9823 }
9824 if err := MarshalEncode(enc, "\xde\xad\xbe\xef",
9825 WithMarshalers(nil),
9826 ); err != nil {
9827 t.Fatalf("MarshalEncode: %v", err)
9828 }
9829 if calledFuncs != 2 {
9830 t.Fatalf("calledFuncs = %d, want 2", calledFuncs)
9831 }
9832 if err := MarshalEncode(enc, "\xde\xad\xbe\xef"); err != nil {
9833 t.Fatalf("MarshalEncode: %v", err)
9834 }
9835 if calledFuncs != 3 {
9836 t.Fatalf("calledFuncs = %d, want 3", calledFuncs)
9837 }
9838 if err := MarshalEncode(enc, "\xde\xad\xbe\xef", JoinOptions(
9839 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, _ any) error {
9840 opts := enc.Options()
9841 if v, _ := GetOption(opts, jsontext.AllowInvalidUTF8); !v {
9842 t.Errorf("nested Options.AllowInvalidUTF8 = false, want true")
9843 }
9844 calledFuncs = math.MaxInt
9845 return errors.ErrUnsupported
9846 })),
9847 )); err != nil {
9848 t.Fatalf("MarshalEncode: %v", err)
9849 }
9850 if calledFuncs != math.MaxInt {
9851 t.Fatalf("calledFuncs = %d, want %d", calledFuncs, math.MaxInt)
9852 }
9853 if out.String() != strings.Repeat("\"\xde\xad\ufffd\ufffd\"\n", 5) {
9854 t.Fatalf("output mismatch:\n\tgot: %s\n\twant: %s", out.String(), strings.Repeat("\"\xde\xad\xbe\xef\"\n", 5))
9855 }
9856
9857
9858
9859 opts := enc.Options()
9860 enc.Reset(out, jsontext.AllowInvalidUTF8(false), opts)
9861 if v, _ := GetOption(enc.Options(), jsontext.AllowInvalidUTF8); v == false {
9862 t.Errorf("Options.AllowInvalidUTF8 = false, want true")
9863 }
9864
9865
9866
9867 {
9868 var buf2 bytes.Buffer
9869 enc2 := jsontext.NewEncoder(&buf2)
9870 if err := enc2.WriteToken(jsontext.BeginObject); err != nil {
9871 t.Fatalf("WriteToken(BeginObject) = %v, want nil", err)
9872 }
9873
9874
9875 if err := MarshalEncode(enc2, "name", jsontext.AllowDuplicateNames(true)); !errors.Is(err, errChangingDuplicateNames) {
9876 t.Errorf("MarshalEncode(name) = %v, want %v", err, errChangingDuplicateNames)
9877 }
9878 if err := MarshalEncode(enc2, "name", jsontext.AllowInvalidUTF8(true)); !errors.Is(err, errChangingInvalidUTF8) {
9879 t.Errorf("MarshalEncode(name) = %v, want %v", err, errChangingInvalidUTF8)
9880 }
9881
9882 if err := MarshalEncode(enc2, "name", jsontext.AllowDuplicateNames(false)); err != nil {
9883 t.Errorf("MarshalEncode(name) = %v, want nil", err)
9884 }
9885
9886 if err := MarshalEncode(enc2, jsontext.Value(`{"dupe":"value","dupe":"value"}`), jsontext.AllowDuplicateNames(true)); err != nil {
9887 t.Errorf("MarshalEncode(value) = %v, want nil", err)
9888 }
9889
9890
9891 if err := MarshalEncode(enc2, "name2"); err != nil {
9892 t.Errorf("MarshalEncode(name) = %v, want nil", err)
9893 }
9894 if err := MarshalEncode(enc2, "value\xde\xad\xbe\xef"); !errors.Is(err, jsonwire.ErrInvalidUTF8) {
9895 t.Errorf("MarshalEncode(value) = %v, want %v", err, jsonwire.ErrInvalidUTF8)
9896 }
9897 if err := MarshalEncode(enc2, "value\xde\xad\xbe\xef", jsontext.AllowInvalidUTF8(true)); err != nil {
9898 t.Errorf("MarshalEncode(value) = %v, want nil", err)
9899 }
9900
9901 if err := enc2.WriteToken(jsontext.EndObject); err != nil {
9902 t.Errorf("WriteToken(EndObject) = %v, want nil", err)
9903 }
9904 }
9905
9906
9907
9908 {
9909 var buf3 bytes.Buffer
9910 enc3 := jsontext.NewEncoder(&buf3, jsontext.WithIndent("\t"))
9911 if err := MarshalEncode(enc3, "value", jsontext.Multiline(false)); !errors.Is(err, errChangingWhitespace) {
9912 t.Errorf("MarshalEncode = %v, want %v", err, errChangingWhitespace)
9913 }
9914 if err := MarshalEncode(enc3, "value", jsontext.WithIndent(" ")); !errors.Is(err, errChangingWhitespace) {
9915 t.Errorf("MarshalEncode = %v, want %v", err, errChangingWhitespace)
9916 }
9917
9918 if err := MarshalEncode(enc3, "value", enc3.Options()); err != nil {
9919 t.Errorf("MarshalEncode = %v, want nil", err)
9920 }
9921 }
9922 }
9923
9924
9925
9926 func BenchmarkMarshalEncodeOptions(b *testing.B) {
9927 var i int
9928 out := new(bytes.Buffer)
9929 enc := jsontext.NewEncoder(out)
9930 makeBench := func(opts ...Options) func(*testing.B) {
9931 return func(b *testing.B) {
9932 out.Reset()
9933 enc.Reset(out)
9934 b.ResetTimer()
9935 for range b.N {
9936 MarshalEncode(enc, &i, opts...)
9937 }
9938 }
9939 }
9940 b.Run("None", makeBench())
9941 b.Run("Same", makeBench(&export.Encoder(enc).Struct))
9942 b.Run("New", makeBench(DefaultOptionsV2()))
9943 }
9944
View as plain text