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 structWeirdNames struct {
158 Empty string `json:"''"`
159 Comma string `json:"','"`
160 Quote string `json:"'\"'"`
161 }
162 structNoCase struct {
163 Aaa string `json:",case:strict"`
164 AA_A string
165 AaA string `json:",case:ignore"`
166 AAa string `json:",case:ignore"`
167 AAA string
168 }
169 structScalars struct {
170 unexported bool
171 Ignored bool `json:"-"`
172
173 Bool bool
174 String string
175 Bytes []byte
176 Int int64
177 Uint uint64
178 Float float64
179 }
180 structSlices struct {
181 unexported bool
182 Ignored bool `json:"-"`
183
184 SliceBool []bool
185 SliceString []string
186 SliceBytes [][]byte
187 SliceInt []int64
188 SliceUint []uint64
189 SliceFloat []float64
190 }
191 structMaps struct {
192 unexported bool
193 Ignored bool `json:"-"`
194
195 MapBool map[string]bool
196 MapString map[string]string
197 MapBytes map[string][]byte
198 MapInt map[string]int64
199 MapUint map[string]uint64
200 MapFloat map[string]float64
201 }
202 structAll struct {
203 Bool bool
204 String string
205 Bytes []byte
206 Int int64
207 Uint uint64
208 Float float64
209 Map map[string]string
210 StructScalars structScalars
211 StructMaps structMaps
212 StructSlices structSlices
213 Slice []string
214 Array [1]string
215 Pointer *structAll
216 Interface any
217 }
218 structStringifiedAll struct {
219 Bool bool `json:",string"`
220 String string `json:",string"`
221 Bytes []byte `json:",string"`
222 Int int64 `json:",string"`
223 Uint uint64 `json:",string"`
224 Float float64 `json:",string"`
225 Map map[string]string `json:",string"`
226 StructScalars structScalars `json:",string"`
227 StructMaps structMaps `json:",string"`
228 StructSlices structSlices `json:",string"`
229 Slice []string `json:",string"`
230 Array [1]string `json:",string"`
231 Pointer *structStringifiedAll `json:",string"`
232 Interface any `json:",string"`
233 }
234 structOmitZeroAll struct {
235 Bool bool `json:",omitzero"`
236 String string `json:",omitzero"`
237 Bytes []byte `json:",omitzero"`
238 Int int64 `json:",omitzero"`
239 Uint uint64 `json:",omitzero"`
240 Float float64 `json:",omitzero"`
241 Map map[string]string `json:",omitzero"`
242 StructScalars structScalars `json:",omitzero"`
243 StructMaps structMaps `json:",omitzero"`
244 StructSlices structSlices `json:",omitzero"`
245 Slice []string `json:",omitzero"`
246 Array [1]string `json:",omitzero"`
247 Pointer *structOmitZeroAll `json:",omitzero"`
248 Interface any `json:",omitzero"`
249 }
250 structOmitZeroMethodAll struct {
251 ValueAlwaysZero valueAlwaysZero `json:",omitzero"`
252 ValueNeverZero valueNeverZero `json:",omitzero"`
253 PointerAlwaysZero pointerAlwaysZero `json:",omitzero"`
254 PointerNeverZero pointerNeverZero `json:",omitzero"`
255 PointerValueAlwaysZero *valueAlwaysZero `json:",omitzero"`
256 PointerValueNeverZero *valueNeverZero `json:",omitzero"`
257 PointerPointerAlwaysZero *pointerAlwaysZero `json:",omitzero"`
258 PointerPointerNeverZero *pointerNeverZero `json:",omitzero"`
259 PointerPointerValueAlwaysZero **valueAlwaysZero `json:",omitzero"`
260 PointerPointerValueNeverZero **valueNeverZero `json:",omitzero"`
261 PointerPointerPointerAlwaysZero **pointerAlwaysZero `json:",omitzero"`
262 PointerPointerPointerNeverZero **pointerNeverZero `json:",omitzero"`
263 }
264 structOmitZeroMethodInterfaceAll struct {
265 ValueAlwaysZero isZeroer `json:",omitzero"`
266 ValueNeverZero isZeroer `json:",omitzero"`
267 PointerValueAlwaysZero isZeroer `json:",omitzero"`
268 PointerValueNeverZero isZeroer `json:",omitzero"`
269 PointerPointerAlwaysZero isZeroer `json:",omitzero"`
270 PointerPointerNeverZero isZeroer `json:",omitzero"`
271 }
272 structOmitEmptyAll struct {
273 Bool bool `json:",omitempty"`
274 PointerBool *bool `json:",omitempty"`
275 String string `json:",omitempty"`
276 StringEmpty stringMarshalEmpty `json:",omitempty"`
277 StringNonEmpty stringMarshalNonEmpty `json:",omitempty"`
278 PointerString *string `json:",omitempty"`
279 PointerStringEmpty *stringMarshalEmpty `json:",omitempty"`
280 PointerStringNonEmpty *stringMarshalNonEmpty `json:",omitempty"`
281 Bytes []byte `json:",omitempty"`
282 BytesEmpty bytesMarshalEmpty `json:",omitempty"`
283 BytesNonEmpty bytesMarshalNonEmpty `json:",omitempty"`
284 PointerBytes *[]byte `json:",omitempty"`
285 PointerBytesEmpty *bytesMarshalEmpty `json:",omitempty"`
286 PointerBytesNonEmpty *bytesMarshalNonEmpty `json:",omitempty"`
287 Float float64 `json:",omitempty"`
288 PointerFloat *float64 `json:",omitempty"`
289 Map map[string]string `json:",omitempty"`
290 MapEmpty mapMarshalEmpty `json:",omitempty"`
291 MapNonEmpty mapMarshalNonEmpty `json:",omitempty"`
292 PointerMap *map[string]string `json:",omitempty"`
293 PointerMapEmpty *mapMarshalEmpty `json:",omitempty"`
294 PointerMapNonEmpty *mapMarshalNonEmpty `json:",omitempty"`
295 Slice []string `json:",omitempty"`
296 SliceEmpty sliceMarshalEmpty `json:",omitempty"`
297 SliceNonEmpty sliceMarshalNonEmpty `json:",omitempty"`
298 PointerSlice *[]string `json:",omitempty"`
299 PointerSliceEmpty *sliceMarshalEmpty `json:",omitempty"`
300 PointerSliceNonEmpty *sliceMarshalNonEmpty `json:",omitempty"`
301 Pointer *structOmitZeroEmptyAll `json:",omitempty"`
302 Interface any `json:",omitempty"`
303 }
304 structOmitZeroEmptyAll struct {
305 Bool bool `json:",omitzero,omitempty"`
306 String string `json:",omitzero,omitempty"`
307 Bytes []byte `json:",omitzero,omitempty"`
308 Int int64 `json:",omitzero,omitempty"`
309 Uint uint64 `json:",omitzero,omitempty"`
310 Float float64 `json:",omitzero,omitempty"`
311 Map map[string]string `json:",omitzero,omitempty"`
312 Slice []string `json:",omitzero,omitempty"`
313 Array [1]string `json:",omitzero,omitempty"`
314 Pointer *structOmitZeroEmptyAll `json:",omitzero,omitempty"`
315 Interface any `json:",omitzero,omitempty"`
316 }
317 structFormatBytes struct {
318 Base16 []byte `json:",format:base16"`
319 Base32 []byte `json:",format:base32"`
320 Base32Hex []byte `json:",format:base32hex"`
321 Base64 []byte `json:",format:base64"`
322 Base64URL []byte `json:",format:base64url"`
323 Array []byte `json:",format:array"`
324 }
325 structFormatArrayBytes struct {
326 Base16 [4]byte `json:",format:base16"`
327 Base32 [4]byte `json:",format:base32"`
328 Base32Hex [4]byte `json:",format:base32hex"`
329 Base64 [4]byte `json:",format:base64"`
330 Base64URL [4]byte `json:",format:base64url"`
331 Array [4]byte `json:",format:array"`
332 Default [4]byte
333 }
334 structFormatFloats struct {
335 NonFinite float64 `json:",format:nonfinite"`
336 PointerNonFinite *float64 `json:",format:nonfinite"`
337 }
338 structFormatMaps struct {
339 EmitNull map[string]string `json:",format:emitnull"`
340 PointerEmitNull *map[string]string `json:",format:emitnull"`
341 EmitEmpty map[string]string `json:",format:emitempty"`
342 PointerEmitEmpty *map[string]string `json:",format:emitempty"`
343 EmitDefault map[string]string
344 PointerEmitDefault *map[string]string
345 }
346 structFormatSlices struct {
347 EmitNull []string `json:",format:emitnull"`
348 PointerEmitNull *[]string `json:",format:emitnull"`
349 EmitEmpty []string `json:",format:emitempty"`
350 PointerEmitEmpty *[]string `json:",format:emitempty"`
351 EmitDefault []string
352 PointerEmitDefault *[]string
353 }
354 structFormatInvalid struct {
355 Bool bool `json:",omitzero,format:invalid"`
356 String string `json:",omitzero,format:invalid"`
357 Bytes []byte `json:",omitzero,format:invalid"`
358 Int int64 `json:",omitzero,format:invalid"`
359 Uint uint64 `json:",omitzero,format:invalid"`
360 Float float64 `json:",omitzero,format:invalid"`
361 Map map[string]string `json:",omitzero,format:invalid"`
362 Struct structAll `json:",omitzero,format:invalid"`
363 Slice []string `json:",omitzero,format:invalid"`
364 Array [1]string `json:",omitzero,format:invalid"`
365 Interface any `json:",omitzero,format:invalid"`
366 }
367 structDurationFormat struct {
368 D1 time.Duration
369 D2 time.Duration `json:",format:units"`
370 D3 time.Duration `json:",format:sec"`
371 D4 time.Duration `json:",string,format:sec"`
372 D5 time.Duration `json:",format:milli"`
373 D6 time.Duration `json:",string,format:milli"`
374 D7 time.Duration `json:",format:micro"`
375 D8 time.Duration `json:",string,format:micro"`
376 D9 time.Duration `json:",format:nano"`
377 D10 time.Duration `json:",string,format:nano"`
378 }
379 structTimeFormat struct {
380 T1 time.Time
381 T2 time.Time `json:",format:ANSIC"`
382 T3 time.Time `json:",format:UnixDate"`
383 T4 time.Time `json:",format:RubyDate"`
384 T5 time.Time `json:",format:RFC822"`
385 T6 time.Time `json:",format:RFC822Z"`
386 T7 time.Time `json:",format:RFC850"`
387 T8 time.Time `json:",format:RFC1123"`
388 T9 time.Time `json:",format:RFC1123Z"`
389 T10 time.Time `json:",format:RFC3339"`
390 T11 time.Time `json:",format:RFC3339Nano"`
391 T12 time.Time `json:",format:Kitchen"`
392 T13 time.Time `json:",format:Stamp"`
393 T14 time.Time `json:",format:StampMilli"`
394 T15 time.Time `json:",format:StampMicro"`
395 T16 time.Time `json:",format:StampNano"`
396 T17 time.Time `json:",format:DateTime"`
397 T18 time.Time `json:",format:DateOnly"`
398 T19 time.Time `json:",format:TimeOnly"`
399 T20 time.Time `json:",format:'2006-01-02'"`
400 T21 time.Time `json:",format:'\"weird\"2006'"`
401 T22 time.Time `json:",format:unix"`
402 T23 time.Time `json:",string,format:unix"`
403 T24 time.Time `json:",format:unixmilli"`
404 T25 time.Time `json:",string,format:unixmilli"`
405 T26 time.Time `json:",format:unixmicro"`
406 T27 time.Time `json:",string,format:unixmicro"`
407 T28 time.Time `json:",format:unixnano"`
408 T29 time.Time `json:",string,format:unixnano"`
409 }
410 structInlined struct {
411 X structInlinedL1 `json:",inline"`
412 *StructEmbed2
413 }
414 structInlinedL1 struct {
415 X *structInlinedL2 `json:",inline"`
416 StructEmbed1 `json:",inline"`
417 }
418 structInlinedL2 struct{ A, B, C string }
419 StructEmbed1 struct{ C, D, E string }
420 StructEmbed2 struct{ E, F, G string }
421 structUnknownTextValue struct {
422 A int `json:",omitzero"`
423 X jsontext.Value `json:",unknown"`
424 B int `json:",omitzero"`
425 }
426 structInlineTextValue struct {
427 A int `json:",omitzero"`
428 X jsontext.Value `json:",inline"`
429 B int `json:",omitzero"`
430 }
431 structInlinePointerTextValue struct {
432 A int `json:",omitzero"`
433 X *jsontext.Value `json:",inline"`
434 B int `json:",omitzero"`
435 }
436 structInlinePointerInlineTextValue struct {
437 X *struct {
438 A int
439 X jsontext.Value `json:",inline"`
440 } `json:",inline"`
441 }
442 structInlineInlinePointerTextValue struct {
443 X struct {
444 X *jsontext.Value `json:",inline"`
445 } `json:",inline"`
446 }
447 structInlineMapStringAny struct {
448 A int `json:",omitzero"`
449 X jsonObject `json:",inline"`
450 B int `json:",omitzero"`
451 }
452 structInlinePointerMapStringAny struct {
453 A int `json:",omitzero"`
454 X *jsonObject `json:",inline"`
455 B int `json:",omitzero"`
456 }
457 structInlinePointerInlineMapStringAny struct {
458 X *struct {
459 A int
460 X jsonObject `json:",inline"`
461 } `json:",inline"`
462 }
463 structInlineInlinePointerMapStringAny struct {
464 X struct {
465 X *jsonObject `json:",inline"`
466 } `json:",inline"`
467 }
468 structInlineMapStringInt struct {
469 X map[string]int `json:",inline"`
470 }
471 structInlineMapNamedStringInt struct {
472 X map[namedString]int `json:",inline"`
473 }
474 structInlineMapNamedStringAny struct {
475 A int `json:",omitzero"`
476 X map[namedString]any `json:",inline"`
477 B int `json:",omitzero"`
478 }
479 structNoCaseInlineTextValue struct {
480 AAA string `json:",omitempty,case:strict"`
481 AA_b string `json:",omitempty"`
482 AaA string `json:",omitempty,case:ignore"`
483 AAa string `json:",omitempty,case:ignore"`
484 Aaa string `json:",omitempty"`
485 X jsontext.Value `json:",inline"`
486 }
487 structNoCaseInlineMapStringAny struct {
488 AAA string `json:",omitempty"`
489 AaA string `json:",omitempty,case:ignore"`
490 AAa string `json:",omitempty,case:ignore"`
491 Aaa string `json:",omitempty"`
492 X jsonObject `json:",inline"`
493 }
494
495 allMethods struct {
496 method string
497 value []byte
498 }
499 allMethodsExceptJSONv2 struct {
500 allMethods
501 MarshalJSONTo struct{}
502 UnmarshalJSONFrom struct{}
503 }
504 allMethodsExceptJSONv1 struct {
505 allMethods
506 MarshalJSON struct{}
507 UnmarshalJSON struct{}
508 }
509 allMethodsExceptText struct {
510 allMethods
511 MarshalText struct{}
512 UnmarshalText struct{}
513 }
514 onlyMethodJSONv2 struct {
515 allMethods
516 MarshalJSON struct{}
517 UnmarshalJSON struct{}
518 MarshalText struct{}
519 UnmarshalText struct{}
520 }
521 onlyMethodJSONv1 struct {
522 allMethods
523 MarshalJSONTo struct{}
524 UnmarshalJSONFrom struct{}
525 MarshalText struct{}
526 UnmarshalText struct{}
527 }
528 onlyMethodText struct {
529 allMethods
530 MarshalJSONTo struct{}
531 UnmarshalJSONFrom struct{}
532 MarshalJSON struct{}
533 UnmarshalJSON struct{}
534 }
535
536 structMethodJSONv2 struct{ value string }
537 structMethodJSONv1 struct{ value string }
538 structMethodText struct{ value string }
539
540 marshalJSONv2Func func(*jsontext.Encoder) error
541 marshalJSONv1Func func() ([]byte, error)
542 appendTextFunc func([]byte) ([]byte, error)
543 marshalTextFunc func() ([]byte, error)
544 unmarshalJSONv2Func func(*jsontext.Decoder) error
545 unmarshalJSONv1Func func([]byte) error
546 unmarshalTextFunc func([]byte) error
547
548 nocaseString string
549
550 stringMarshalEmpty string
551 stringMarshalNonEmpty string
552 bytesMarshalEmpty []byte
553 bytesMarshalNonEmpty []byte
554 mapMarshalEmpty map[string]string
555 mapMarshalNonEmpty map[string]string
556 sliceMarshalEmpty []string
557 sliceMarshalNonEmpty []string
558
559 valueAlwaysZero string
560 valueNeverZero string
561 pointerAlwaysZero string
562 pointerNeverZero string
563
564 valueStringer struct{}
565 pointerStringer struct{}
566
567 cyclicA struct {
568 B1 cyclicB `json:",inline"`
569 B2 cyclicB `json:",inline"`
570 }
571 cyclicB struct {
572 F int
573 A *cyclicA `json:",inline"`
574 }
575 )
576
577 func (structUnexportedEmbeddedMethodTag) MarshalText() {}
578 func (structUnexportedEmbeddedMethodTag) AppendText() {}
579
580 func (p *allMethods) MarshalJSONTo(enc *jsontext.Encoder) error {
581 if got, want := "MarshalJSONTo", p.method; got != want {
582 return fmt.Errorf("called wrong method: got %v, want %v", got, want)
583 }
584 return enc.WriteValue(p.value)
585 }
586 func (p *allMethods) MarshalJSON() ([]byte, error) {
587 if got, want := "MarshalJSON", p.method; got != want {
588 return nil, fmt.Errorf("called wrong method: got %v, want %v", got, want)
589 }
590 return p.value, nil
591 }
592 func (p *allMethods) MarshalText() ([]byte, error) {
593 if got, want := "MarshalText", p.method; got != want {
594 return nil, fmt.Errorf("called wrong method: got %v, want %v", got, want)
595 }
596 return p.value, nil
597 }
598
599 func (p *allMethods) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
600 p.method = "UnmarshalJSONFrom"
601 val, err := dec.ReadValue()
602 p.value = val
603 return err
604 }
605 func (p *allMethods) UnmarshalJSON(val []byte) error {
606 p.method = "UnmarshalJSON"
607 p.value = val
608 return nil
609 }
610 func (p *allMethods) UnmarshalText(val []byte) error {
611 p.method = "UnmarshalText"
612 p.value = val
613 return nil
614 }
615
616 func (s structMethodJSONv2) MarshalJSONTo(enc *jsontext.Encoder) error {
617 return enc.WriteToken(jsontext.String(s.value))
618 }
619 func (s *structMethodJSONv2) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
620 tok, err := dec.ReadToken()
621 if err != nil {
622 return err
623 }
624 if k := tok.Kind(); k != '"' {
625 return EU(nil).withType(k, T[structMethodJSONv2]())
626 }
627 s.value = tok.String()
628 return nil
629 }
630
631 func (s structMethodJSONv1) MarshalJSON() ([]byte, error) {
632 return jsontext.AppendQuote(nil, s.value)
633 }
634 func (s *structMethodJSONv1) UnmarshalJSON(b []byte) error {
635 if k := jsontext.Value(b).Kind(); k != '"' {
636 return EU(nil).withType(k, T[structMethodJSONv1]())
637 }
638 b, _ = jsontext.AppendUnquote(nil, b)
639 s.value = string(b)
640 return nil
641 }
642
643 func (s structMethodText) MarshalText() ([]byte, error) {
644 return []byte(s.value), nil
645 }
646 func (s *structMethodText) UnmarshalText(b []byte) error {
647 s.value = string(b)
648 return nil
649 }
650
651 func (f marshalJSONv2Func) MarshalJSONTo(enc *jsontext.Encoder) error {
652 return f(enc)
653 }
654 func (f marshalJSONv1Func) MarshalJSON() ([]byte, error) {
655 return f()
656 }
657 func (f appendTextFunc) AppendText(b []byte) ([]byte, error) {
658 return f(b)
659 }
660 func (f marshalTextFunc) MarshalText() ([]byte, error) {
661 return f()
662 }
663 func (f unmarshalJSONv2Func) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
664 return f(dec)
665 }
666 func (f unmarshalJSONv1Func) UnmarshalJSON(b []byte) error {
667 return f(b)
668 }
669 func (f unmarshalTextFunc) UnmarshalText(b []byte) error {
670 return f(b)
671 }
672
673 func (k nocaseString) MarshalText() ([]byte, error) {
674 return []byte(strings.ToLower(string(k))), nil
675 }
676 func (k *nocaseString) UnmarshalText(b []byte) error {
677 *k = nocaseString(strings.ToLower(string(b)))
678 return nil
679 }
680
681 func (stringMarshalEmpty) MarshalJSON() ([]byte, error) { return []byte(`""`), nil }
682 func (stringMarshalNonEmpty) MarshalJSON() ([]byte, error) { return []byte(`"value"`), nil }
683 func (bytesMarshalEmpty) MarshalJSON() ([]byte, error) { return []byte(`[]`), nil }
684 func (bytesMarshalNonEmpty) MarshalJSON() ([]byte, error) { return []byte(`["value"]`), nil }
685 func (mapMarshalEmpty) MarshalJSON() ([]byte, error) { return []byte(`{}`), nil }
686 func (mapMarshalNonEmpty) MarshalJSON() ([]byte, error) { return []byte(`{"key":"value"}`), nil }
687 func (sliceMarshalEmpty) MarshalJSON() ([]byte, error) { return []byte(`[]`), nil }
688 func (sliceMarshalNonEmpty) MarshalJSON() ([]byte, error) { return []byte(`["value"]`), nil }
689
690 func (valueAlwaysZero) IsZero() bool { return true }
691 func (valueNeverZero) IsZero() bool { return false }
692 func (*pointerAlwaysZero) IsZero() bool { return true }
693 func (*pointerNeverZero) IsZero() bool { return false }
694
695 func (valueStringer) String() string { return "" }
696 func (*pointerStringer) String() string { return "" }
697
698 func addr[T any](v T) *T {
699 return &v
700 }
701
702 func mustParseTime(layout, value string) time.Time {
703 t, err := time.Parse(layout, value)
704 if err != nil {
705 panic(err)
706 }
707 return t
708 }
709
710 var invalidFormatOption = &jsonopts.Struct{
711 ArshalValues: jsonopts.ArshalValues{FormatDepth: 1000, Format: "invalid"},
712 }
713
714 func TestMarshal(t *testing.T) {
715 tests := []struct {
716 name jsontest.CaseName
717 opts []Options
718 in any
719 want string
720 wantErr error
721
722 canonicalize bool
723 useWriter bool
724 }{{
725 name: jsontest.Name("Nil"),
726 in: nil,
727 want: `null`,
728 }, {
729 name: jsontest.Name("Bools"),
730 in: []bool{false, true},
731 want: `[false,true]`,
732 }, {
733 name: jsontest.Name("Bools/Named"),
734 in: []namedBool{false, true},
735 want: `[false,true]`,
736 }, {
737 name: jsontest.Name("Bools/NotStringified"),
738 opts: []Options{StringifyNumbers(true)},
739 in: []bool{false, true},
740 want: `[false,true]`,
741 }, {
742 name: jsontest.Name("Bools/StringifiedBool"),
743 opts: []Options{jsonflags.StringifyBoolsAndStrings | 1},
744 in: []bool{false, true},
745 want: `["false","true"]`,
746 }, {
747 name: jsontest.Name("Bools/IgnoreInvalidFormat"),
748 opts: []Options{invalidFormatOption},
749 in: true,
750 want: `true`,
751 }, {
752 name: jsontest.Name("Strings"),
753 in: []string{"", "hello", "世界"},
754 want: `["","hello","世界"]`,
755 }, {
756 name: jsontest.Name("Strings/Named"),
757 in: []namedString{"", "hello", "世界"},
758 want: `["","hello","世界"]`,
759 }, {
760 name: jsontest.Name("Strings/StringifiedBool"),
761 opts: []Options{jsonflags.StringifyBoolsAndStrings | 1},
762 in: []string{"", "hello", "世界"},
763 want: `["\"\"","\"hello\"","\"世界\""]`,
764 }, {
765 name: jsontest.Name("Strings/IgnoreInvalidFormat"),
766 opts: []Options{invalidFormatOption},
767 in: "string",
768 want: `"string"`,
769 }, {
770 name: jsontest.Name("Bytes"),
771 in: [][]byte{nil, {}, {1}, {1, 2}, {1, 2, 3}},
772 want: `["","","AQ==","AQI=","AQID"]`,
773 }, {
774 name: jsontest.Name("Bytes/FormatNilSliceAsNull"),
775 opts: []Options{FormatNilSliceAsNull(true)},
776 in: [][]byte{nil, {}},
777 want: `[null,""]`,
778 }, {
779 name: jsontest.Name("Bytes/Large"),
780 in: []byte("the quick brown fox jumped over the lazy dog and ate the homework that I spent so much time on."),
781 want: `"dGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2cgYW5kIGF0ZSB0aGUgaG9tZXdvcmsgdGhhdCBJIHNwZW50IHNvIG11Y2ggdGltZSBvbi4="`,
782 }, {
783 name: jsontest.Name("Bytes/Named"),
784 in: []namedBytes{nil, {}, {1}, {1, 2}, {1, 2, 3}},
785 want: `["","","AQ==","AQI=","AQID"]`,
786 }, {
787 name: jsontest.Name("Bytes/NotStringified"),
788 opts: []Options{StringifyNumbers(true)},
789 in: [][]byte{nil, {}, {1}, {1, 2}, {1, 2, 3}},
790 want: `["","","AQ==","AQI=","AQID"]`,
791 }, {
792
793
794 name: jsontest.Name("Bytes/Invariant"),
795 in: [][]namedByte{nil, {}, {1}, {1, 2}, {1, 2, 3}},
796 want: `[[],[],[1],[1,2],[1,2,3]]`,
797 }, {
798
799
800 name: jsontest.Name("Bytes/ByteArray"),
801 in: [5]byte{'h', 'e', 'l', 'l', 'o'},
802 want: `"aGVsbG8="`,
803 }, {
804
805
806 name: jsontest.Name("Bytes/NamedByteArray"),
807 in: [5]namedByte{'h', 'e', 'l', 'l', 'o'},
808 want: `[104,101,108,108,111]`,
809 }, {
810 name: jsontest.Name("Bytes/IgnoreInvalidFormat"),
811 opts: []Options{invalidFormatOption},
812 in: []byte("hello"),
813 want: `"aGVsbG8="`,
814 }, {
815 name: jsontest.Name("Ints"),
816 in: []any{
817 int(0), int8(math.MinInt8), int16(math.MinInt16), int32(math.MinInt32), int64(math.MinInt64), namedInt64(-6464),
818 },
819 want: `[0,-128,-32768,-2147483648,-9223372036854775808,-6464]`,
820 }, {
821 name: jsontest.Name("Ints/Stringified"),
822 opts: []Options{StringifyNumbers(true)},
823 in: []any{
824 int(0), int8(math.MinInt8), int16(math.MinInt16), int32(math.MinInt32), int64(math.MinInt64), namedInt64(-6464),
825 },
826 want: `["0","-128","-32768","-2147483648","-9223372036854775808","-6464"]`,
827 }, {
828 name: jsontest.Name("Ints/IgnoreInvalidFormat"),
829 opts: []Options{invalidFormatOption},
830 in: int(0),
831 want: `0`,
832 }, {
833 name: jsontest.Name("Uints"),
834 in: []any{
835 uint(0), uint8(math.MaxUint8), uint16(math.MaxUint16), uint32(math.MaxUint32), uint64(math.MaxUint64), namedUint64(6464), uintptr(1234),
836 },
837 want: `[0,255,65535,4294967295,18446744073709551615,6464,1234]`,
838 }, {
839 name: jsontest.Name("Uints/Stringified"),
840 opts: []Options{StringifyNumbers(true)},
841 in: []any{
842 uint(0), uint8(math.MaxUint8), uint16(math.MaxUint16), uint32(math.MaxUint32), uint64(math.MaxUint64), namedUint64(6464),
843 },
844 want: `["0","255","65535","4294967295","18446744073709551615","6464"]`,
845 }, {
846 name: jsontest.Name("Uints/IgnoreInvalidFormat"),
847 opts: []Options{invalidFormatOption},
848 in: uint(0),
849 want: `0`,
850 }, {
851 name: jsontest.Name("Floats"),
852 in: []any{
853 float32(math.MaxFloat32), float64(math.MaxFloat64), namedFloat64(64.64),
854 },
855 want: `[3.4028235e+38,1.7976931348623157e+308,64.64]`,
856 }, {
857 name: jsontest.Name("Floats/Stringified"),
858 opts: []Options{StringifyNumbers(true)},
859 in: []any{
860 float32(math.MaxFloat32), float64(math.MaxFloat64), namedFloat64(64.64),
861 },
862 want: `["3.4028235e+38","1.7976931348623157e+308","64.64"]`,
863 }, {
864 name: jsontest.Name("Floats/Invalid/NaN"),
865 opts: []Options{StringifyNumbers(true)},
866 in: math.NaN(),
867 wantErr: EM(fmt.Errorf("unsupported value: %v", math.NaN())).withType(0, float64Type),
868 }, {
869 name: jsontest.Name("Floats/Invalid/PositiveInfinity"),
870 in: math.Inf(+1),
871 wantErr: EM(fmt.Errorf("unsupported value: %v", math.Inf(+1))).withType(0, float64Type),
872 }, {
873 name: jsontest.Name("Floats/Invalid/NegativeInfinity"),
874 in: math.Inf(-1),
875 wantErr: EM(fmt.Errorf("unsupported value: %v", math.Inf(-1))).withType(0, float64Type),
876 }, {
877 name: jsontest.Name("Floats/IgnoreInvalidFormat"),
878 opts: []Options{invalidFormatOption},
879 in: float64(0),
880 want: `0`,
881 }, {
882 name: jsontest.Name("Maps/InvalidKey/Bool"),
883 in: map[bool]string{false: "value"},
884 want: `{`,
885 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, boolType),
886 }, {
887 name: jsontest.Name("Maps/InvalidKey/NamedBool"),
888 in: map[namedBool]string{false: "value"},
889 want: `{`,
890 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[namedBool]()),
891 }, {
892 name: jsontest.Name("Maps/InvalidKey/Array"),
893 in: map[[1]string]string{{"key"}: "value"},
894 want: `{`,
895 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[[1]string]()),
896 }, {
897 name: jsontest.Name("Maps/InvalidKey/Channel"),
898 in: map[chan string]string{make(chan string): "value"},
899 want: `{`,
900 wantErr: EM(nil).withPos(`{`, "").withType(0, T[chan string]()),
901 }, {
902 name: jsontest.Name("Maps/ValidKey/Int"),
903 in: map[int64]string{math.MinInt64: "MinInt64", 0: "Zero", math.MaxInt64: "MaxInt64"},
904 canonicalize: true,
905 want: `{"-9223372036854775808":"MinInt64","0":"Zero","9223372036854775807":"MaxInt64"}`,
906 }, {
907 name: jsontest.Name("Maps/ValidKey/PointerInt"),
908 in: map[*int64]string{addr(int64(math.MinInt64)): "MinInt64", addr(int64(0)): "Zero", addr(int64(math.MaxInt64)): "MaxInt64"},
909 canonicalize: true,
910 want: `{"-9223372036854775808":"MinInt64","0":"Zero","9223372036854775807":"MaxInt64"}`,
911 }, {
912 name: jsontest.Name("Maps/DuplicateName/PointerInt"),
913 in: map[*int64]string{addr(int64(0)): "0", addr(int64(0)): "0"},
914 canonicalize: true,
915 want: `{"0":"0"`,
916 wantErr: newDuplicateNameError("", []byte(`"0"`), len64(`{"0":"0",`)),
917 }, {
918 name: jsontest.Name("Maps/ValidKey/NamedInt"),
919 in: map[namedInt64]string{math.MinInt64: "MinInt64", 0: "Zero", math.MaxInt64: "MaxInt64"},
920 canonicalize: true,
921 want: `{"-9223372036854775808":"MinInt64","0":"Zero","9223372036854775807":"MaxInt64"}`,
922 }, {
923 name: jsontest.Name("Maps/ValidKey/Uint"),
924 in: map[uint64]string{0: "Zero", math.MaxUint64: "MaxUint64"},
925 canonicalize: true,
926 want: `{"0":"Zero","18446744073709551615":"MaxUint64"}`,
927 }, {
928 name: jsontest.Name("Maps/ValidKey/NamedUint"),
929 in: map[namedUint64]string{0: "Zero", math.MaxUint64: "MaxUint64"},
930 canonicalize: true,
931 want: `{"0":"Zero","18446744073709551615":"MaxUint64"}`,
932 }, {
933 name: jsontest.Name("Maps/ValidKey/Float"),
934 in: map[float64]string{3.14159: "value"},
935 want: `{"3.14159":"value"}`,
936 }, {
937 name: jsontest.Name("Maps/InvalidKey/Float/NaN"),
938 in: map[float64]string{math.NaN(): "NaN", math.NaN(): "NaN"},
939 want: `{`,
940 wantErr: EM(errors.New("unsupported value: NaN")).withPos(`{`, "").withType(0, float64Type),
941 }, {
942 name: jsontest.Name("Maps/ValidKey/Interface"),
943 in: map[any]any{
944 "key": "key",
945 namedInt64(-64): int32(-32),
946 namedUint64(+64): uint32(+32),
947 namedFloat64(64.64): float32(32.32),
948 },
949 canonicalize: true,
950 want: `{"-64":-32,"64":32,"64.64":32.32,"key":"key"}`,
951 }, {
952 name: jsontest.Name("Maps/DuplicateName/String/AllowInvalidUTF8+AllowDuplicateNames"),
953 opts: []Options{jsontext.AllowInvalidUTF8(true), jsontext.AllowDuplicateNames(true)},
954 in: map[string]string{"\x80": "", "\x81": ""},
955 want: `{"�":"","�":""}`,
956 }, {
957 name: jsontest.Name("Maps/DuplicateName/String/AllowInvalidUTF8"),
958 opts: []Options{jsontext.AllowInvalidUTF8(true)},
959 in: map[string]string{"\x80": "", "\x81": ""},
960 want: `{"�":""`,
961 wantErr: newDuplicateNameError("", []byte(`"�"`), len64(`{"�":"",`)),
962 }, {
963 name: jsontest.Name("Maps/DuplicateName/NoCaseString/AllowDuplicateNames"),
964 opts: []Options{jsontext.AllowDuplicateNames(true)},
965 in: map[nocaseString]string{"hello": "", "HELLO": ""},
966 want: `{"hello":"","hello":""}`,
967 }, {
968 name: jsontest.Name("Maps/DuplicateName/NoCaseString"),
969 in: map[nocaseString]string{"hello": "", "HELLO": ""},
970 want: `{"hello":""`,
971 wantErr: EM(newDuplicateNameError("", []byte(`"hello"`), len64(`{"hello":"",`))).withPos(`{"hello":"",`, "").withType(0, T[nocaseString]()),
972 }, {
973 name: jsontest.Name("Maps/DuplicateName/NaNs/Deterministic+AllowDuplicateNames"),
974 opts: []Options{
975 WithMarshalers(
976 MarshalFunc(func(v float64) ([]byte, error) { return []byte(`"NaN"`), nil }),
977 ),
978 Deterministic(true),
979 jsontext.AllowDuplicateNames(true),
980 },
981 in: map[float64]string{math.NaN(): "NaN", math.NaN(): "NaN"},
982 want: `{"NaN":"NaN","NaN":"NaN"}`,
983 }, {
984 name: jsontest.Name("Maps/InvalidValue/Channel"),
985 in: map[string]chan string{
986 "key": nil,
987 },
988 want: `{"key"`,
989 wantErr: EM(nil).withPos(`{"key":`, "/key").withType(0, T[chan string]()),
990 }, {
991 name: jsontest.Name("Maps/String/Deterministic"),
992 opts: []Options{Deterministic(true)},
993 in: map[string]int{"a": 0, "b": 1, "c": 2},
994 want: `{"a":0,"b":1,"c":2}`,
995 }, {
996 name: jsontest.Name("Maps/String/Deterministic+AllowInvalidUTF8+RejectDuplicateNames"),
997 opts: []Options{
998 Deterministic(true),
999 jsontext.AllowInvalidUTF8(true),
1000 jsontext.AllowDuplicateNames(false),
1001 },
1002 in: map[string]int{"\xff": 0, "\xfe": 1},
1003 want: `{"�":1`,
1004 wantErr: newDuplicateNameError("", []byte(`"�"`), len64(`{"�":1,`)),
1005 }, {
1006 name: jsontest.Name("Maps/String/Deterministic+AllowInvalidUTF8+AllowDuplicateNames"),
1007 opts: []Options{
1008 Deterministic(true),
1009 jsontext.AllowInvalidUTF8(true),
1010 jsontext.AllowDuplicateNames(true),
1011 },
1012 in: map[string]int{"\xff": 0, "\xfe": 1},
1013 want: `{"�":1,"�":0}`,
1014 }, {
1015 name: jsontest.Name("Maps/String/Deterministic+MarshalFuncs"),
1016 opts: []Options{
1017 Deterministic(true),
1018 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v string) error {
1019 if p := enc.StackPointer(); p != "/X" {
1020 return fmt.Errorf("invalid stack pointer: got %s, want /X", p)
1021 }
1022 switch v {
1023 case "a":
1024 return enc.WriteToken(jsontext.String("b"))
1025 case "b":
1026 return enc.WriteToken(jsontext.String("a"))
1027 default:
1028 return fmt.Errorf("invalid value: %q", v)
1029 }
1030 })),
1031 },
1032 in: map[namedString]map[string]int{"X": {"a": -1, "b": 1}},
1033 want: `{"X":{"a":1,"b":-1}}`,
1034 }, {
1035 name: jsontest.Name("Maps/String/Deterministic+MarshalFuncs+RejectDuplicateNames"),
1036 opts: []Options{
1037 Deterministic(true),
1038 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v string) error {
1039 if p := enc.StackPointer(); p != "/X" {
1040 return fmt.Errorf("invalid stack pointer: got %s, want /X", p)
1041 }
1042 switch v {
1043 case "a", "b":
1044 return enc.WriteToken(jsontext.String("x"))
1045 default:
1046 return fmt.Errorf("invalid value: %q", v)
1047 }
1048 })),
1049 jsontext.AllowDuplicateNames(false),
1050 },
1051 in: map[namedString]map[string]int{"X": {"a": 1, "b": 1}},
1052 want: `{"X":{"x":1`,
1053 wantErr: newDuplicateNameError("/X/x", nil, len64(`{"X":{"x":1,`)),
1054 }, {
1055 name: jsontest.Name("Maps/String/Deterministic+MarshalFuncs+AllowDuplicateNames"),
1056 opts: []Options{
1057 Deterministic(true),
1058 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v string) error {
1059 if p := enc.StackPointer(); p != "/X" {
1060 return fmt.Errorf("invalid stack pointer: got %s, want /0", p)
1061 }
1062 switch v {
1063 case "a", "b":
1064 return enc.WriteToken(jsontext.String("x"))
1065 default:
1066 return fmt.Errorf("invalid value: %q", v)
1067 }
1068 })),
1069 jsontext.AllowDuplicateNames(true),
1070 },
1071 in: map[namedString]map[string]int{"X": {"a": 1, "b": 1}},
1072
1073
1074 want: `{"X":{"x":1,"x":1}}`,
1075 }, {
1076 name: jsontest.Name("Maps/RecursiveMap"),
1077 in: recursiveMap{
1078 "fizz": {
1079 "foo": {},
1080 "bar": nil,
1081 },
1082 "buzz": nil,
1083 },
1084 canonicalize: true,
1085 want: `{"buzz":{},"fizz":{"bar":{},"foo":{}}}`,
1086 }, {
1087 name: jsontest.Name("Maps/CyclicMap"),
1088 in: func() recursiveMap {
1089 m := recursiveMap{"k": nil}
1090 m["k"] = m
1091 return m
1092 }(),
1093 want: strings.Repeat(`{"k":`, startDetectingCyclesAfter) + `{"k"`,
1094 wantErr: EM(internal.ErrCycle).withPos(strings.Repeat(`{"k":`, startDetectingCyclesAfter+1), jsontext.Pointer(strings.Repeat("/k", startDetectingCyclesAfter+1))).withType(0, T[recursiveMap]()),
1095 }, {
1096 name: jsontest.Name("Maps/IgnoreInvalidFormat"),
1097 opts: []Options{invalidFormatOption},
1098 in: map[string]string{},
1099 want: `{}`,
1100 }, {
1101 name: jsontest.Name("Structs/Empty"),
1102 in: structEmpty{},
1103 want: `{}`,
1104 }, {
1105 name: jsontest.Name("Structs/UnexportedIgnored"),
1106 in: structUnexportedIgnored{ignored: "ignored"},
1107 want: `{}`,
1108 }, {
1109 name: jsontest.Name("Structs/IgnoredUnexportedEmbedded"),
1110 in: structIgnoredUnexportedEmbedded{namedString: "ignored"},
1111 want: `{}`,
1112 }, {
1113 name: jsontest.Name("Structs/WeirdNames"),
1114 in: structWeirdNames{Empty: "empty", Comma: "comma", Quote: "quote"},
1115 want: `{"":"empty",",":"comma","\"":"quote"}`,
1116 }, {
1117 name: jsontest.Name("Structs/EscapedNames"),
1118 opts: []Options{jsontext.EscapeForHTML(true), jsontext.EscapeForJS(true)},
1119 in: struct {
1120 S string "json:\"'abc<>&\u2028\u2029xyz'\""
1121 M any
1122 I structInlineTextValue
1123 }{
1124 S: "abc<>&\u2028\u2029xyz",
1125 M: map[string]string{"abc<>&\u2028\u2029xyz": "abc<>&\u2028\u2029xyz"},
1126 I: structInlineTextValue{X: jsontext.Value(`{"abc<>&` + "\u2028\u2029" + `xyz":"abc<>&` + "\u2028\u2029" + `xyz"}`)},
1127 },
1128 want: `{"abc\u003c\u003e\u0026\u2028\u2029xyz":"abc\u003c\u003e\u0026\u2028\u2029xyz","M":{"abc\u003c\u003e\u0026\u2028\u2029xyz":"abc\u003c\u003e\u0026\u2028\u2029xyz"},"I":{"abc\u003c\u003e\u0026\u2028\u2029xyz":"abc\u003c\u003e\u0026\u2028\u2029xyz"}}`,
1129 }, {
1130 name: jsontest.Name("Structs/NoCase"),
1131 in: structNoCase{AaA: "AaA", AAa: "AAa", Aaa: "Aaa", AAA: "AAA", AA_A: "AA_A"},
1132 want: `{"Aaa":"Aaa","AA_A":"AA_A","AaA":"AaA","AAa":"AAa","AAA":"AAA"}`,
1133 }, {
1134 name: jsontest.Name("Structs/NoCase/MatchCaseInsensitiveNames"),
1135 opts: []Options{MatchCaseInsensitiveNames(true)},
1136 in: structNoCase{AaA: "AaA", AAa: "AAa", Aaa: "Aaa", AAA: "AAA", AA_A: "AA_A"},
1137 want: `{"Aaa":"Aaa","AA_A":"AA_A","AaA":"AaA","AAa":"AAa","AAA":"AAA"}`,
1138 }, {
1139 name: jsontest.Name("Structs/NoCase/MatchCaseInsensitiveNames+MatchCaseSensitiveDelimiter"),
1140 opts: []Options{MatchCaseInsensitiveNames(true), jsonflags.MatchCaseSensitiveDelimiter | 1},
1141 in: structNoCase{AaA: "AaA", AAa: "AAa", Aaa: "Aaa", AAA: "AAA", AA_A: "AA_A"},
1142 want: `{"Aaa":"Aaa","AA_A":"AA_A","AaA":"AaA","AAa":"AAa","AAA":"AAA"}`,
1143 }, {
1144 name: jsontest.Name("Structs/Normal"),
1145 opts: []Options{jsontext.Multiline(true)},
1146 in: structAll{
1147 Bool: true,
1148 String: "hello",
1149 Bytes: []byte{1, 2, 3},
1150 Int: -64,
1151 Uint: +64,
1152 Float: 3.14159,
1153 Map: map[string]string{"key": "value"},
1154 StructScalars: structScalars{
1155 Bool: true,
1156 String: "hello",
1157 Bytes: []byte{1, 2, 3},
1158 Int: -64,
1159 Uint: +64,
1160 Float: 3.14159,
1161 },
1162 StructMaps: structMaps{
1163 MapBool: map[string]bool{"": true},
1164 MapString: map[string]string{"": "hello"},
1165 MapBytes: map[string][]byte{"": {1, 2, 3}},
1166 MapInt: map[string]int64{"": -64},
1167 MapUint: map[string]uint64{"": +64},
1168 MapFloat: map[string]float64{"": 3.14159},
1169 },
1170 StructSlices: structSlices{
1171 SliceBool: []bool{true},
1172 SliceString: []string{"hello"},
1173 SliceBytes: [][]byte{{1, 2, 3}},
1174 SliceInt: []int64{-64},
1175 SliceUint: []uint64{+64},
1176 SliceFloat: []float64{3.14159},
1177 },
1178 Slice: []string{"fizz", "buzz"},
1179 Array: [1]string{"goodbye"},
1180 Pointer: new(structAll),
1181 Interface: (*structAll)(nil),
1182 },
1183 want: `{
1184 "Bool": true,
1185 "String": "hello",
1186 "Bytes": "AQID",
1187 "Int": -64,
1188 "Uint": 64,
1189 "Float": 3.14159,
1190 "Map": {
1191 "key": "value"
1192 },
1193 "StructScalars": {
1194 "Bool": true,
1195 "String": "hello",
1196 "Bytes": "AQID",
1197 "Int": -64,
1198 "Uint": 64,
1199 "Float": 3.14159
1200 },
1201 "StructMaps": {
1202 "MapBool": {
1203 "": true
1204 },
1205 "MapString": {
1206 "": "hello"
1207 },
1208 "MapBytes": {
1209 "": "AQID"
1210 },
1211 "MapInt": {
1212 "": -64
1213 },
1214 "MapUint": {
1215 "": 64
1216 },
1217 "MapFloat": {
1218 "": 3.14159
1219 }
1220 },
1221 "StructSlices": {
1222 "SliceBool": [
1223 true
1224 ],
1225 "SliceString": [
1226 "hello"
1227 ],
1228 "SliceBytes": [
1229 "AQID"
1230 ],
1231 "SliceInt": [
1232 -64
1233 ],
1234 "SliceUint": [
1235 64
1236 ],
1237 "SliceFloat": [
1238 3.14159
1239 ]
1240 },
1241 "Slice": [
1242 "fizz",
1243 "buzz"
1244 ],
1245 "Array": [
1246 "goodbye"
1247 ],
1248 "Pointer": {
1249 "Bool": false,
1250 "String": "",
1251 "Bytes": "",
1252 "Int": 0,
1253 "Uint": 0,
1254 "Float": 0,
1255 "Map": {},
1256 "StructScalars": {
1257 "Bool": false,
1258 "String": "",
1259 "Bytes": "",
1260 "Int": 0,
1261 "Uint": 0,
1262 "Float": 0
1263 },
1264 "StructMaps": {
1265 "MapBool": {},
1266 "MapString": {},
1267 "MapBytes": {},
1268 "MapInt": {},
1269 "MapUint": {},
1270 "MapFloat": {}
1271 },
1272 "StructSlices": {
1273 "SliceBool": [],
1274 "SliceString": [],
1275 "SliceBytes": [],
1276 "SliceInt": [],
1277 "SliceUint": [],
1278 "SliceFloat": []
1279 },
1280 "Slice": [],
1281 "Array": [
1282 ""
1283 ],
1284 "Pointer": null,
1285 "Interface": null
1286 },
1287 "Interface": null
1288 }`,
1289 }, {
1290 name: jsontest.Name("Structs/SpaceAfterColonAndComma"),
1291 opts: []Options{jsontext.SpaceAfterColon(true), jsontext.SpaceAfterComma(true)},
1292 in: structOmitZeroAll{Int: 1, Uint: 1},
1293 want: `{"Int": 1, "Uint": 1}`,
1294 }, {
1295 name: jsontest.Name("Structs/SpaceAfterColon"),
1296 opts: []Options{jsontext.SpaceAfterColon(true)},
1297 in: structOmitZeroAll{Int: 1, Uint: 1},
1298 want: `{"Int": 1,"Uint": 1}`,
1299 }, {
1300 name: jsontest.Name("Structs/SpaceAfterComma"),
1301 opts: []Options{jsontext.SpaceAfterComma(true)},
1302 in: structOmitZeroAll{Int: 1, Uint: 1, Slice: []string{"a", "b"}},
1303 want: `{"Int":1, "Uint":1, "Slice":["a", "b"]}`,
1304 }, {
1305 name: jsontest.Name("Structs/Stringified"),
1306 opts: []Options{jsontext.Multiline(true)},
1307 in: structStringifiedAll{
1308 Bool: true,
1309 String: "hello",
1310 Bytes: []byte{1, 2, 3},
1311 Int: -64,
1312 Uint: +64,
1313 Float: 3.14159,
1314 Map: map[string]string{"key": "value"},
1315 StructScalars: structScalars{
1316 Bool: true,
1317 String: "hello",
1318 Bytes: []byte{1, 2, 3},
1319 Int: -64,
1320 Uint: +64,
1321 Float: 3.14159,
1322 },
1323 StructMaps: structMaps{
1324 MapBool: map[string]bool{"": true},
1325 MapString: map[string]string{"": "hello"},
1326 MapBytes: map[string][]byte{"": {1, 2, 3}},
1327 MapInt: map[string]int64{"": -64},
1328 MapUint: map[string]uint64{"": +64},
1329 MapFloat: map[string]float64{"": 3.14159},
1330 },
1331 StructSlices: structSlices{
1332 SliceBool: []bool{true},
1333 SliceString: []string{"hello"},
1334 SliceBytes: [][]byte{{1, 2, 3}},
1335 SliceInt: []int64{-64},
1336 SliceUint: []uint64{+64},
1337 SliceFloat: []float64{3.14159},
1338 },
1339 Slice: []string{"fizz", "buzz"},
1340 Array: [1]string{"goodbye"},
1341 Pointer: new(structStringifiedAll),
1342 Interface: (*structStringifiedAll)(nil),
1343 },
1344 want: `{
1345 "Bool": true,
1346 "String": "hello",
1347 "Bytes": "AQID",
1348 "Int": "-64",
1349 "Uint": "64",
1350 "Float": "3.14159",
1351 "Map": {
1352 "key": "value"
1353 },
1354 "StructScalars": {
1355 "Bool": true,
1356 "String": "hello",
1357 "Bytes": "AQID",
1358 "Int": "-64",
1359 "Uint": "64",
1360 "Float": "3.14159"
1361 },
1362 "StructMaps": {
1363 "MapBool": {
1364 "": true
1365 },
1366 "MapString": {
1367 "": "hello"
1368 },
1369 "MapBytes": {
1370 "": "AQID"
1371 },
1372 "MapInt": {
1373 "": "-64"
1374 },
1375 "MapUint": {
1376 "": "64"
1377 },
1378 "MapFloat": {
1379 "": "3.14159"
1380 }
1381 },
1382 "StructSlices": {
1383 "SliceBool": [
1384 true
1385 ],
1386 "SliceString": [
1387 "hello"
1388 ],
1389 "SliceBytes": [
1390 "AQID"
1391 ],
1392 "SliceInt": [
1393 "-64"
1394 ],
1395 "SliceUint": [
1396 "64"
1397 ],
1398 "SliceFloat": [
1399 "3.14159"
1400 ]
1401 },
1402 "Slice": [
1403 "fizz",
1404 "buzz"
1405 ],
1406 "Array": [
1407 "goodbye"
1408 ],
1409 "Pointer": {
1410 "Bool": false,
1411 "String": "",
1412 "Bytes": "",
1413 "Int": "0",
1414 "Uint": "0",
1415 "Float": "0",
1416 "Map": {},
1417 "StructScalars": {
1418 "Bool": false,
1419 "String": "",
1420 "Bytes": "",
1421 "Int": "0",
1422 "Uint": "0",
1423 "Float": "0"
1424 },
1425 "StructMaps": {
1426 "MapBool": {},
1427 "MapString": {},
1428 "MapBytes": {},
1429 "MapInt": {},
1430 "MapUint": {},
1431 "MapFloat": {}
1432 },
1433 "StructSlices": {
1434 "SliceBool": [],
1435 "SliceString": [],
1436 "SliceBytes": [],
1437 "SliceInt": [],
1438 "SliceUint": [],
1439 "SliceFloat": []
1440 },
1441 "Slice": [],
1442 "Array": [
1443 ""
1444 ],
1445 "Pointer": null,
1446 "Interface": null
1447 },
1448 "Interface": null
1449 }`,
1450 }, {
1451 name: jsontest.Name("Structs/LegacyStringified"),
1452 opts: []Options{jsontext.Multiline(true), jsonflags.StringifyWithLegacySemantics | 1},
1453 in: structStringifiedAll{
1454 Bool: true,
1455 String: "hello",
1456 Bytes: []byte{1, 2, 3},
1457 Int: -64,
1458 Uint: +64,
1459 Float: 3.14159,
1460 Map: map[string]string{"key": "value"},
1461 StructScalars: structScalars{
1462 Bool: true,
1463 String: "hello",
1464 Bytes: []byte{1, 2, 3},
1465 Int: -64,
1466 Uint: +64,
1467 Float: 3.14159,
1468 },
1469 StructMaps: structMaps{
1470 MapBool: map[string]bool{"": true},
1471 MapString: map[string]string{"": "hello"},
1472 MapBytes: map[string][]byte{"": {1, 2, 3}},
1473 MapInt: map[string]int64{"": -64},
1474 MapUint: map[string]uint64{"": +64},
1475 MapFloat: map[string]float64{"": 3.14159},
1476 },
1477 StructSlices: structSlices{
1478 SliceBool: []bool{true},
1479 SliceString: []string{"hello"},
1480 SliceBytes: [][]byte{{1, 2, 3}},
1481 SliceInt: []int64{-64},
1482 SliceUint: []uint64{+64},
1483 SliceFloat: []float64{3.14159},
1484 },
1485 Slice: []string{"fizz", "buzz"},
1486 Array: [1]string{"goodbye"},
1487 Pointer: new(structStringifiedAll),
1488 Interface: (*structStringifiedAll)(nil),
1489 },
1490 want: `{
1491 "Bool": "true",
1492 "String": "\"hello\"",
1493 "Bytes": "AQID",
1494 "Int": "-64",
1495 "Uint": "64",
1496 "Float": "3.14159",
1497 "Map": {
1498 "key": "value"
1499 },
1500 "StructScalars": {
1501 "Bool": true,
1502 "String": "hello",
1503 "Bytes": "AQID",
1504 "Int": -64,
1505 "Uint": 64,
1506 "Float": 3.14159
1507 },
1508 "StructMaps": {
1509 "MapBool": {
1510 "": true
1511 },
1512 "MapString": {
1513 "": "hello"
1514 },
1515 "MapBytes": {
1516 "": "AQID"
1517 },
1518 "MapInt": {
1519 "": -64
1520 },
1521 "MapUint": {
1522 "": 64
1523 },
1524 "MapFloat": {
1525 "": 3.14159
1526 }
1527 },
1528 "StructSlices": {
1529 "SliceBool": [
1530 true
1531 ],
1532 "SliceString": [
1533 "hello"
1534 ],
1535 "SliceBytes": [
1536 "AQID"
1537 ],
1538 "SliceInt": [
1539 -64
1540 ],
1541 "SliceUint": [
1542 64
1543 ],
1544 "SliceFloat": [
1545 3.14159
1546 ]
1547 },
1548 "Slice": [
1549 "fizz",
1550 "buzz"
1551 ],
1552 "Array": [
1553 "goodbye"
1554 ],
1555 "Pointer": {
1556 "Bool": "false",
1557 "String": "\"\"",
1558 "Bytes": "",
1559 "Int": "0",
1560 "Uint": "0",
1561 "Float": "0",
1562 "Map": {},
1563 "StructScalars": {
1564 "Bool": false,
1565 "String": "",
1566 "Bytes": "",
1567 "Int": 0,
1568 "Uint": 0,
1569 "Float": 0
1570 },
1571 "StructMaps": {
1572 "MapBool": {},
1573 "MapString": {},
1574 "MapBytes": {},
1575 "MapInt": {},
1576 "MapUint": {},
1577 "MapFloat": {}
1578 },
1579 "StructSlices": {
1580 "SliceBool": [],
1581 "SliceString": [],
1582 "SliceBytes": [],
1583 "SliceInt": [],
1584 "SliceUint": [],
1585 "SliceFloat": []
1586 },
1587 "Slice": [],
1588 "Array": [
1589 ""
1590 ],
1591 "Pointer": null,
1592 "Interface": null
1593 },
1594 "Interface": null
1595 }`,
1596 }, {
1597 name: jsontest.Name("Structs/OmitZero/Zero"),
1598 in: structOmitZeroAll{},
1599 want: `{}`,
1600 }, {
1601 name: jsontest.Name("Structs/OmitZeroOption/Zero"),
1602 opts: []Options{OmitZeroStructFields(true)},
1603 in: structAll{},
1604 want: `{}`,
1605 }, {
1606 name: jsontest.Name("Structs/OmitZero/NonZero"),
1607 opts: []Options{jsontext.Multiline(true)},
1608 in: structOmitZeroAll{
1609 Bool: true,
1610 String: " ",
1611 Bytes: []byte{},
1612 Int: 1,
1613 Uint: 1,
1614 Float: math.SmallestNonzeroFloat64,
1615 Map: map[string]string{},
1616 StructScalars: structScalars{unexported: true},
1617 StructSlices: structSlices{Ignored: true},
1618 StructMaps: structMaps{MapBool: map[string]bool{}},
1619 Slice: []string{},
1620 Array: [1]string{" "},
1621 Pointer: new(structOmitZeroAll),
1622 Interface: (*structOmitZeroAll)(nil),
1623 },
1624 want: `{
1625 "Bool": true,
1626 "String": " ",
1627 "Bytes": "",
1628 "Int": 1,
1629 "Uint": 1,
1630 "Float": 5e-324,
1631 "Map": {},
1632 "StructScalars": {
1633 "Bool": false,
1634 "String": "",
1635 "Bytes": "",
1636 "Int": 0,
1637 "Uint": 0,
1638 "Float": 0
1639 },
1640 "StructMaps": {
1641 "MapBool": {},
1642 "MapString": {},
1643 "MapBytes": {},
1644 "MapInt": {},
1645 "MapUint": {},
1646 "MapFloat": {}
1647 },
1648 "StructSlices": {
1649 "SliceBool": [],
1650 "SliceString": [],
1651 "SliceBytes": [],
1652 "SliceInt": [],
1653 "SliceUint": [],
1654 "SliceFloat": []
1655 },
1656 "Slice": [],
1657 "Array": [
1658 " "
1659 ],
1660 "Pointer": {},
1661 "Interface": null
1662 }`,
1663 }, {
1664 name: jsontest.Name("Structs/OmitZeroOption/NonZero"),
1665 opts: []Options{OmitZeroStructFields(true), jsontext.Multiline(true)},
1666 in: structAll{
1667 Bool: true,
1668 String: " ",
1669 Bytes: []byte{},
1670 Int: 1,
1671 Uint: 1,
1672 Float: math.SmallestNonzeroFloat64,
1673 Map: map[string]string{},
1674 StructScalars: structScalars{unexported: true},
1675 StructSlices: structSlices{Ignored: true},
1676 StructMaps: structMaps{MapBool: map[string]bool{}},
1677 Slice: []string{},
1678 Array: [1]string{" "},
1679 Pointer: new(structAll),
1680 Interface: (*structAll)(nil),
1681 },
1682 want: `{
1683 "Bool": true,
1684 "String": " ",
1685 "Bytes": "",
1686 "Int": 1,
1687 "Uint": 1,
1688 "Float": 5e-324,
1689 "Map": {},
1690 "StructScalars": {},
1691 "StructMaps": {
1692 "MapBool": {}
1693 },
1694 "StructSlices": {},
1695 "Slice": [],
1696 "Array": [
1697 " "
1698 ],
1699 "Pointer": {},
1700 "Interface": null
1701 }`,
1702 }, {
1703 name: jsontest.Name("Structs/OmitZeroMethod/Zero"),
1704 in: structOmitZeroMethodAll{},
1705 want: `{"ValueNeverZero":"","PointerNeverZero":""}`,
1706 }, {
1707 name: jsontest.Name("Structs/OmitZeroMethod/NonZero"),
1708 opts: []Options{jsontext.Multiline(true)},
1709 in: structOmitZeroMethodAll{
1710 ValueAlwaysZero: valueAlwaysZero("nonzero"),
1711 ValueNeverZero: valueNeverZero("nonzero"),
1712 PointerAlwaysZero: pointerAlwaysZero("nonzero"),
1713 PointerNeverZero: pointerNeverZero("nonzero"),
1714 PointerValueAlwaysZero: addr(valueAlwaysZero("nonzero")),
1715 PointerValueNeverZero: addr(valueNeverZero("nonzero")),
1716 PointerPointerAlwaysZero: addr(pointerAlwaysZero("nonzero")),
1717 PointerPointerNeverZero: addr(pointerNeverZero("nonzero")),
1718 PointerPointerValueAlwaysZero: addr(addr(valueAlwaysZero("nonzero"))),
1719 PointerPointerValueNeverZero: addr(addr(valueNeverZero("nonzero"))),
1720 PointerPointerPointerAlwaysZero: addr(addr(pointerAlwaysZero("nonzero"))),
1721 PointerPointerPointerNeverZero: addr(addr(pointerNeverZero("nonzero"))),
1722 },
1723 want: `{
1724 "ValueNeverZero": "nonzero",
1725 "PointerNeverZero": "nonzero",
1726 "PointerValueNeverZero": "nonzero",
1727 "PointerPointerNeverZero": "nonzero",
1728 "PointerPointerValueAlwaysZero": "nonzero",
1729 "PointerPointerValueNeverZero": "nonzero",
1730 "PointerPointerPointerAlwaysZero": "nonzero",
1731 "PointerPointerPointerNeverZero": "nonzero"
1732 }`,
1733 }, {
1734 name: jsontest.Name("Structs/OmitZeroMethod/Interface/Zero"),
1735 opts: []Options{jsontext.Multiline(true)},
1736 in: structOmitZeroMethodInterfaceAll{},
1737 want: `{}`,
1738 }, {
1739 name: jsontest.Name("Structs/OmitZeroMethod/Interface/PartialZero"),
1740 opts: []Options{jsontext.Multiline(true)},
1741 in: structOmitZeroMethodInterfaceAll{
1742 ValueAlwaysZero: valueAlwaysZero(""),
1743 ValueNeverZero: valueNeverZero(""),
1744 PointerValueAlwaysZero: (*valueAlwaysZero)(nil),
1745 PointerValueNeverZero: (*valueNeverZero)(nil),
1746 PointerPointerAlwaysZero: (*pointerAlwaysZero)(nil),
1747 PointerPointerNeverZero: (*pointerNeverZero)(nil),
1748 },
1749 want: `{
1750 "ValueNeverZero": ""
1751 }`,
1752 }, {
1753 name: jsontest.Name("Structs/OmitZeroMethod/Interface/NonZero"),
1754 opts: []Options{jsontext.Multiline(true)},
1755 in: structOmitZeroMethodInterfaceAll{
1756 ValueAlwaysZero: valueAlwaysZero("nonzero"),
1757 ValueNeverZero: valueNeverZero("nonzero"),
1758 PointerValueAlwaysZero: addr(valueAlwaysZero("nonzero")),
1759 PointerValueNeverZero: addr(valueNeverZero("nonzero")),
1760 PointerPointerAlwaysZero: addr(pointerAlwaysZero("nonzero")),
1761 PointerPointerNeverZero: addr(pointerNeverZero("nonzero")),
1762 },
1763 want: `{
1764 "ValueNeverZero": "nonzero",
1765 "PointerValueNeverZero": "nonzero",
1766 "PointerPointerNeverZero": "nonzero"
1767 }`,
1768 }, {
1769 name: jsontest.Name("Structs/OmitEmpty/Zero"),
1770 opts: []Options{jsontext.Multiline(true)},
1771 in: structOmitEmptyAll{},
1772 want: `{
1773 "Bool": false,
1774 "StringNonEmpty": "value",
1775 "BytesNonEmpty": [
1776 "value"
1777 ],
1778 "Float": 0,
1779 "MapNonEmpty": {
1780 "key": "value"
1781 },
1782 "SliceNonEmpty": [
1783 "value"
1784 ]
1785 }`,
1786 }, {
1787 name: jsontest.Name("Structs/OmitEmpty/EmptyNonZero"),
1788 opts: []Options{jsontext.Multiline(true)},
1789 in: structOmitEmptyAll{
1790 String: string(""),
1791 StringEmpty: stringMarshalEmpty(""),
1792 StringNonEmpty: stringMarshalNonEmpty(""),
1793 PointerString: addr(string("")),
1794 PointerStringEmpty: addr(stringMarshalEmpty("")),
1795 PointerStringNonEmpty: addr(stringMarshalNonEmpty("")),
1796 Bytes: []byte(""),
1797 BytesEmpty: bytesMarshalEmpty([]byte("")),
1798 BytesNonEmpty: bytesMarshalNonEmpty([]byte("")),
1799 PointerBytes: addr([]byte("")),
1800 PointerBytesEmpty: addr(bytesMarshalEmpty([]byte(""))),
1801 PointerBytesNonEmpty: addr(bytesMarshalNonEmpty([]byte(""))),
1802 Map: map[string]string{},
1803 MapEmpty: mapMarshalEmpty{},
1804 MapNonEmpty: mapMarshalNonEmpty{},
1805 PointerMap: addr(map[string]string{}),
1806 PointerMapEmpty: addr(mapMarshalEmpty{}),
1807 PointerMapNonEmpty: addr(mapMarshalNonEmpty{}),
1808 Slice: []string{},
1809 SliceEmpty: sliceMarshalEmpty{},
1810 SliceNonEmpty: sliceMarshalNonEmpty{},
1811 PointerSlice: addr([]string{}),
1812 PointerSliceEmpty: addr(sliceMarshalEmpty{}),
1813 PointerSliceNonEmpty: addr(sliceMarshalNonEmpty{}),
1814 Pointer: &structOmitZeroEmptyAll{},
1815 Interface: []string{},
1816 },
1817 want: `{
1818 "Bool": false,
1819 "StringNonEmpty": "value",
1820 "PointerStringNonEmpty": "value",
1821 "BytesNonEmpty": [
1822 "value"
1823 ],
1824 "PointerBytesNonEmpty": [
1825 "value"
1826 ],
1827 "Float": 0,
1828 "MapNonEmpty": {
1829 "key": "value"
1830 },
1831 "PointerMapNonEmpty": {
1832 "key": "value"
1833 },
1834 "SliceNonEmpty": [
1835 "value"
1836 ],
1837 "PointerSliceNonEmpty": [
1838 "value"
1839 ]
1840 }`,
1841 }, {
1842 name: jsontest.Name("Structs/OmitEmpty/NonEmpty"),
1843 opts: []Options{jsontext.Multiline(true)},
1844 in: structOmitEmptyAll{
1845 Bool: true,
1846 PointerBool: addr(true),
1847 String: string("value"),
1848 StringEmpty: stringMarshalEmpty("value"),
1849 StringNonEmpty: stringMarshalNonEmpty("value"),
1850 PointerString: addr(string("value")),
1851 PointerStringEmpty: addr(stringMarshalEmpty("value")),
1852 PointerStringNonEmpty: addr(stringMarshalNonEmpty("value")),
1853 Bytes: []byte("value"),
1854 BytesEmpty: bytesMarshalEmpty([]byte("value")),
1855 BytesNonEmpty: bytesMarshalNonEmpty([]byte("value")),
1856 PointerBytes: addr([]byte("value")),
1857 PointerBytesEmpty: addr(bytesMarshalEmpty([]byte("value"))),
1858 PointerBytesNonEmpty: addr(bytesMarshalNonEmpty([]byte("value"))),
1859 Float: math.Copysign(0, -1),
1860 PointerFloat: addr(math.Copysign(0, -1)),
1861 Map: map[string]string{"": ""},
1862 MapEmpty: mapMarshalEmpty{"key": "value"},
1863 MapNonEmpty: mapMarshalNonEmpty{"key": "value"},
1864 PointerMap: addr(map[string]string{"": ""}),
1865 PointerMapEmpty: addr(mapMarshalEmpty{"key": "value"}),
1866 PointerMapNonEmpty: addr(mapMarshalNonEmpty{"key": "value"}),
1867 Slice: []string{""},
1868 SliceEmpty: sliceMarshalEmpty{"value"},
1869 SliceNonEmpty: sliceMarshalNonEmpty{"value"},
1870 PointerSlice: addr([]string{""}),
1871 PointerSliceEmpty: addr(sliceMarshalEmpty{"value"}),
1872 PointerSliceNonEmpty: addr(sliceMarshalNonEmpty{"value"}),
1873 Pointer: &structOmitZeroEmptyAll{Float: math.SmallestNonzeroFloat64},
1874 Interface: []string{""},
1875 },
1876 want: `{
1877 "Bool": true,
1878 "PointerBool": true,
1879 "String": "value",
1880 "StringNonEmpty": "value",
1881 "PointerString": "value",
1882 "PointerStringNonEmpty": "value",
1883 "Bytes": "dmFsdWU=",
1884 "BytesNonEmpty": [
1885 "value"
1886 ],
1887 "PointerBytes": "dmFsdWU=",
1888 "PointerBytesNonEmpty": [
1889 "value"
1890 ],
1891 "Float": -0,
1892 "PointerFloat": -0,
1893 "Map": {
1894 "": ""
1895 },
1896 "MapNonEmpty": {
1897 "key": "value"
1898 },
1899 "PointerMap": {
1900 "": ""
1901 },
1902 "PointerMapNonEmpty": {
1903 "key": "value"
1904 },
1905 "Slice": [
1906 ""
1907 ],
1908 "SliceNonEmpty": [
1909 "value"
1910 ],
1911 "PointerSlice": [
1912 ""
1913 ],
1914 "PointerSliceNonEmpty": [
1915 "value"
1916 ],
1917 "Pointer": {
1918 "Float": 5e-324
1919 },
1920 "Interface": [
1921 ""
1922 ]
1923 }`,
1924 }, {
1925 name: jsontest.Name("Structs/OmitEmpty/Legacy/Zero"),
1926 opts: []Options{jsonflags.OmitEmptyWithLegacyDefinition | 1},
1927 in: structOmitEmptyAll{},
1928 want: `{}`,
1929 }, {
1930 name: jsontest.Name("Structs/OmitEmpty/Legacy/NonEmpty"),
1931 opts: []Options{jsontext.Multiline(true), jsonflags.OmitEmptyWithLegacyDefinition | 1},
1932 in: structOmitEmptyAll{
1933 Bool: true,
1934 PointerBool: addr(true),
1935 String: string("value"),
1936 StringEmpty: stringMarshalEmpty("value"),
1937 StringNonEmpty: stringMarshalNonEmpty("value"),
1938 PointerString: addr(string("value")),
1939 PointerStringEmpty: addr(stringMarshalEmpty("value")),
1940 PointerStringNonEmpty: addr(stringMarshalNonEmpty("value")),
1941 Bytes: []byte("value"),
1942 BytesEmpty: bytesMarshalEmpty([]byte("value")),
1943 BytesNonEmpty: bytesMarshalNonEmpty([]byte("value")),
1944 PointerBytes: addr([]byte("value")),
1945 PointerBytesEmpty: addr(bytesMarshalEmpty([]byte("value"))),
1946 PointerBytesNonEmpty: addr(bytesMarshalNonEmpty([]byte("value"))),
1947 Float: math.Copysign(0, -1),
1948 PointerFloat: addr(math.Copysign(0, -1)),
1949 Map: map[string]string{"": ""},
1950 MapEmpty: mapMarshalEmpty{"key": "value"},
1951 MapNonEmpty: mapMarshalNonEmpty{"key": "value"},
1952 PointerMap: addr(map[string]string{"": ""}),
1953 PointerMapEmpty: addr(mapMarshalEmpty{"key": "value"}),
1954 PointerMapNonEmpty: addr(mapMarshalNonEmpty{"key": "value"}),
1955 Slice: []string{""},
1956 SliceEmpty: sliceMarshalEmpty{"value"},
1957 SliceNonEmpty: sliceMarshalNonEmpty{"value"},
1958 PointerSlice: addr([]string{""}),
1959 PointerSliceEmpty: addr(sliceMarshalEmpty{"value"}),
1960 PointerSliceNonEmpty: addr(sliceMarshalNonEmpty{"value"}),
1961 Pointer: &structOmitZeroEmptyAll{Float: math.Copysign(0, -1)},
1962 Interface: []string{""},
1963 },
1964 want: `{
1965 "Bool": true,
1966 "PointerBool": true,
1967 "String": "value",
1968 "StringEmpty": "",
1969 "StringNonEmpty": "value",
1970 "PointerString": "value",
1971 "PointerStringEmpty": "",
1972 "PointerStringNonEmpty": "value",
1973 "Bytes": "dmFsdWU=",
1974 "BytesEmpty": [],
1975 "BytesNonEmpty": [
1976 "value"
1977 ],
1978 "PointerBytes": "dmFsdWU=",
1979 "PointerBytesEmpty": [],
1980 "PointerBytesNonEmpty": [
1981 "value"
1982 ],
1983 "PointerFloat": -0,
1984 "Map": {
1985 "": ""
1986 },
1987 "MapEmpty": {},
1988 "MapNonEmpty": {
1989 "key": "value"
1990 },
1991 "PointerMap": {
1992 "": ""
1993 },
1994 "PointerMapEmpty": {},
1995 "PointerMapNonEmpty": {
1996 "key": "value"
1997 },
1998 "Slice": [
1999 ""
2000 ],
2001 "SliceEmpty": [],
2002 "SliceNonEmpty": [
2003 "value"
2004 ],
2005 "PointerSlice": [
2006 ""
2007 ],
2008 "PointerSliceEmpty": [],
2009 "PointerSliceNonEmpty": [
2010 "value"
2011 ],
2012 "Pointer": {},
2013 "Interface": [
2014 ""
2015 ]
2016 }`,
2017 }, {
2018 name: jsontest.Name("Structs/OmitEmpty/NonEmptyString"),
2019 in: struct {
2020 X string `json:",omitempty"`
2021 }{`"`},
2022 want: `{"X":"\""}`,
2023 }, {
2024 name: jsontest.Name("Structs/OmitZeroEmpty/Zero"),
2025 in: structOmitZeroEmptyAll{},
2026 want: `{}`,
2027 }, {
2028 name: jsontest.Name("Structs/OmitZeroEmpty/Empty"),
2029 in: structOmitZeroEmptyAll{
2030 Bytes: []byte{},
2031 Map: map[string]string{},
2032 Slice: []string{},
2033 Pointer: &structOmitZeroEmptyAll{},
2034 Interface: []string{},
2035 },
2036 want: `{}`,
2037 }, {
2038 name: jsontest.Name("Structs/OmitEmpty/PathologicalDepth"),
2039 in: func() any {
2040 type X struct {
2041 X *X `json:",omitempty"`
2042 }
2043 var make func(int) *X
2044 make = func(n int) *X {
2045 if n == 0 {
2046 return nil
2047 }
2048 return &X{make(n - 1)}
2049 }
2050 return make(100)
2051 }(),
2052 want: `{}`,
2053 useWriter: true,
2054 }, {
2055 name: jsontest.Name("Structs/OmitEmpty/PathologicalBreadth"),
2056 in: func() any {
2057 var fields []reflect.StructField
2058 for i := range 100 {
2059 fields = append(fields, reflect.StructField{
2060 Name: fmt.Sprintf("X%d", i),
2061 Type: T[stringMarshalEmpty](),
2062 Tag: `json:",omitempty"`,
2063 })
2064 }
2065 return reflect.New(reflect.StructOf(fields)).Interface()
2066 }(),
2067 want: `{}`,
2068 useWriter: true,
2069 }, {
2070 name: jsontest.Name("Structs/OmitEmpty/PathologicalTree"),
2071 in: func() any {
2072 type X struct {
2073 XL, XR *X `json:",omitempty"`
2074 }
2075 var make func(int) *X
2076 make = func(n int) *X {
2077 if n == 0 {
2078 return nil
2079 }
2080 return &X{make(n - 1), make(n - 1)}
2081 }
2082 return make(8)
2083 }(),
2084 want: `{}`,
2085 useWriter: true,
2086 }, {
2087 name: jsontest.Name("Structs/OmitZeroEmpty/NonEmpty"),
2088 in: structOmitZeroEmptyAll{
2089 Bytes: []byte("value"),
2090 Map: map[string]string{"": ""},
2091 Slice: []string{""},
2092 Pointer: &structOmitZeroEmptyAll{Bool: true},
2093 Interface: []string{""},
2094 },
2095 want: `{"Bytes":"dmFsdWU=","Map":{"":""},"Slice":[""],"Pointer":{"Bool":true},"Interface":[""]}`,
2096 }, {
2097 name: jsontest.Name("Structs/Format/Bytes"),
2098 opts: []Options{jsontext.Multiline(true)},
2099 in: structFormatBytes{
2100 Base16: []byte("\x01\x23\x45\x67\x89\xab\xcd\xef"),
2101 Base32: []byte("\x00D2\x14\xc7BT\xb65τe:V\xd7\xc6u\xbew\xdf"),
2102 Base32Hex: []byte("\x00D2\x14\xc7BT\xb65τe:V\xd7\xc6u\xbew\xdf"),
2103 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߿"),
2104 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߿"),
2105 Array: []byte{1, 2, 3, 4},
2106 },
2107 want: `{
2108 "Base16": "0123456789abcdef",
2109 "Base32": "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
2110 "Base32Hex": "0123456789ABCDEFGHIJKLMNOPQRSTUV",
2111 "Base64": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
2112 "Base64URL": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
2113 "Array": [
2114 1,
2115 2,
2116 3,
2117 4
2118 ]
2119 }`}, {
2120 name: jsontest.Name("Structs/Format/ArrayBytes"),
2121 opts: []Options{jsontext.Multiline(true)},
2122 in: structFormatArrayBytes{
2123 Base16: [4]byte{1, 2, 3, 4},
2124 Base32: [4]byte{1, 2, 3, 4},
2125 Base32Hex: [4]byte{1, 2, 3, 4},
2126 Base64: [4]byte{1, 2, 3, 4},
2127 Base64URL: [4]byte{1, 2, 3, 4},
2128 Array: [4]byte{1, 2, 3, 4},
2129 Default: [4]byte{1, 2, 3, 4},
2130 },
2131 want: `{
2132 "Base16": "01020304",
2133 "Base32": "AEBAGBA=",
2134 "Base32Hex": "0410610=",
2135 "Base64": "AQIDBA==",
2136 "Base64URL": "AQIDBA==",
2137 "Array": [
2138 1,
2139 2,
2140 3,
2141 4
2142 ],
2143 "Default": "AQIDBA=="
2144 }`}, {
2145 name: jsontest.Name("Structs/Format/ArrayBytes/Legacy"),
2146 opts: []Options{jsontext.Multiline(true), jsonflags.FormatBytesWithLegacySemantics | 1},
2147 in: structFormatArrayBytes{
2148 Base16: [4]byte{1, 2, 3, 4},
2149 Base32: [4]byte{1, 2, 3, 4},
2150 Base32Hex: [4]byte{1, 2, 3, 4},
2151 Base64: [4]byte{1, 2, 3, 4},
2152 Base64URL: [4]byte{1, 2, 3, 4},
2153 Array: [4]byte{1, 2, 3, 4},
2154 Default: [4]byte{1, 2, 3, 4},
2155 },
2156 want: `{
2157 "Base16": "01020304",
2158 "Base32": "AEBAGBA=",
2159 "Base32Hex": "0410610=",
2160 "Base64": "AQIDBA==",
2161 "Base64URL": "AQIDBA==",
2162 "Array": [
2163 1,
2164 2,
2165 3,
2166 4
2167 ],
2168 "Default": [
2169 1,
2170 2,
2171 3,
2172 4
2173 ]
2174 }`}, {
2175 name: jsontest.Name("Structs/Format/Bytes/Array"),
2176 opts: []Options{
2177 WithMarshalers(MarshalFunc(func(in byte) ([]byte, error) {
2178 if in > 3 {
2179 return []byte("true"), nil
2180 } else {
2181 return []byte("false"), nil
2182 }
2183 })),
2184 },
2185 in: struct {
2186 Array []byte `json:",format:array"`
2187 }{
2188 Array: []byte{1, 6, 2, 5, 3, 4},
2189 },
2190 want: `{"Array":[false,true,false,true,false,true]}`,
2191 }, {
2192 name: jsontest.Name("Structs/Format/Floats"),
2193 opts: []Options{jsontext.Multiline(true)},
2194 in: []structFormatFloats{
2195 {NonFinite: math.Pi, PointerNonFinite: addr(math.Pi)},
2196 {NonFinite: math.NaN(), PointerNonFinite: addr(math.NaN())},
2197 {NonFinite: math.Inf(-1), PointerNonFinite: addr(math.Inf(-1))},
2198 {NonFinite: math.Inf(+1), PointerNonFinite: addr(math.Inf(+1))},
2199 },
2200 want: `[
2201 {
2202 "NonFinite": 3.141592653589793,
2203 "PointerNonFinite": 3.141592653589793
2204 },
2205 {
2206 "NonFinite": "NaN",
2207 "PointerNonFinite": "NaN"
2208 },
2209 {
2210 "NonFinite": "-Infinity",
2211 "PointerNonFinite": "-Infinity"
2212 },
2213 {
2214 "NonFinite": "Infinity",
2215 "PointerNonFinite": "Infinity"
2216 }
2217 ]`,
2218 }, {
2219 name: jsontest.Name("Structs/Format/Maps"),
2220 opts: []Options{jsontext.Multiline(true)},
2221 in: []structFormatMaps{{
2222 EmitNull: map[string]string(nil), PointerEmitNull: addr(map[string]string(nil)),
2223 EmitEmpty: map[string]string(nil), PointerEmitEmpty: addr(map[string]string(nil)),
2224 EmitDefault: map[string]string(nil), PointerEmitDefault: addr(map[string]string(nil)),
2225 }, {
2226 EmitNull: map[string]string{}, PointerEmitNull: addr(map[string]string{}),
2227 EmitEmpty: map[string]string{}, PointerEmitEmpty: addr(map[string]string{}),
2228 EmitDefault: map[string]string{}, PointerEmitDefault: addr(map[string]string{}),
2229 }, {
2230 EmitNull: map[string]string{"k": "v"}, PointerEmitNull: addr(map[string]string{"k": "v"}),
2231 EmitEmpty: map[string]string{"k": "v"}, PointerEmitEmpty: addr(map[string]string{"k": "v"}),
2232 EmitDefault: map[string]string{"k": "v"}, PointerEmitDefault: addr(map[string]string{"k": "v"}),
2233 }},
2234 want: `[
2235 {
2236 "EmitNull": null,
2237 "PointerEmitNull": null,
2238 "EmitEmpty": {},
2239 "PointerEmitEmpty": {},
2240 "EmitDefault": {},
2241 "PointerEmitDefault": {}
2242 },
2243 {
2244 "EmitNull": {},
2245 "PointerEmitNull": {},
2246 "EmitEmpty": {},
2247 "PointerEmitEmpty": {},
2248 "EmitDefault": {},
2249 "PointerEmitDefault": {}
2250 },
2251 {
2252 "EmitNull": {
2253 "k": "v"
2254 },
2255 "PointerEmitNull": {
2256 "k": "v"
2257 },
2258 "EmitEmpty": {
2259 "k": "v"
2260 },
2261 "PointerEmitEmpty": {
2262 "k": "v"
2263 },
2264 "EmitDefault": {
2265 "k": "v"
2266 },
2267 "PointerEmitDefault": {
2268 "k": "v"
2269 }
2270 }
2271 ]`,
2272 }, {
2273 name: jsontest.Name("Structs/Format/Maps/FormatNilMapAsNull"),
2274 opts: []Options{
2275 FormatNilMapAsNull(true),
2276 jsontext.Multiline(true),
2277 },
2278 in: []structFormatMaps{{
2279 EmitNull: map[string]string(nil), PointerEmitNull: addr(map[string]string(nil)),
2280 EmitEmpty: map[string]string(nil), PointerEmitEmpty: addr(map[string]string(nil)),
2281 EmitDefault: map[string]string(nil), PointerEmitDefault: addr(map[string]string(nil)),
2282 }, {
2283 EmitNull: map[string]string{}, PointerEmitNull: addr(map[string]string{}),
2284 EmitEmpty: map[string]string{}, PointerEmitEmpty: addr(map[string]string{}),
2285 EmitDefault: map[string]string{}, PointerEmitDefault: addr(map[string]string{}),
2286 }, {
2287 EmitNull: map[string]string{"k": "v"}, PointerEmitNull: addr(map[string]string{"k": "v"}),
2288 EmitEmpty: map[string]string{"k": "v"}, PointerEmitEmpty: addr(map[string]string{"k": "v"}),
2289 EmitDefault: map[string]string{"k": "v"}, PointerEmitDefault: addr(map[string]string{"k": "v"}),
2290 }},
2291 want: `[
2292 {
2293 "EmitNull": null,
2294 "PointerEmitNull": null,
2295 "EmitEmpty": {},
2296 "PointerEmitEmpty": {},
2297 "EmitDefault": null,
2298 "PointerEmitDefault": null
2299 },
2300 {
2301 "EmitNull": {},
2302 "PointerEmitNull": {},
2303 "EmitEmpty": {},
2304 "PointerEmitEmpty": {},
2305 "EmitDefault": {},
2306 "PointerEmitDefault": {}
2307 },
2308 {
2309 "EmitNull": {
2310 "k": "v"
2311 },
2312 "PointerEmitNull": {
2313 "k": "v"
2314 },
2315 "EmitEmpty": {
2316 "k": "v"
2317 },
2318 "PointerEmitEmpty": {
2319 "k": "v"
2320 },
2321 "EmitDefault": {
2322 "k": "v"
2323 },
2324 "PointerEmitDefault": {
2325 "k": "v"
2326 }
2327 }
2328 ]`,
2329 }, {
2330 name: jsontest.Name("Structs/Format/Slices"),
2331 opts: []Options{jsontext.Multiline(true)},
2332 in: []structFormatSlices{{
2333 EmitNull: []string(nil), PointerEmitNull: addr([]string(nil)),
2334 EmitEmpty: []string(nil), PointerEmitEmpty: addr([]string(nil)),
2335 EmitDefault: []string(nil), PointerEmitDefault: addr([]string(nil)),
2336 }, {
2337 EmitNull: []string{}, PointerEmitNull: addr([]string{}),
2338 EmitEmpty: []string{}, PointerEmitEmpty: addr([]string{}),
2339 EmitDefault: []string{}, PointerEmitDefault: addr([]string{}),
2340 }, {
2341 EmitNull: []string{"v"}, PointerEmitNull: addr([]string{"v"}),
2342 EmitEmpty: []string{"v"}, PointerEmitEmpty: addr([]string{"v"}),
2343 EmitDefault: []string{"v"}, PointerEmitDefault: addr([]string{"v"}),
2344 }},
2345 want: `[
2346 {
2347 "EmitNull": null,
2348 "PointerEmitNull": null,
2349 "EmitEmpty": [],
2350 "PointerEmitEmpty": [],
2351 "EmitDefault": [],
2352 "PointerEmitDefault": []
2353 },
2354 {
2355 "EmitNull": [],
2356 "PointerEmitNull": [],
2357 "EmitEmpty": [],
2358 "PointerEmitEmpty": [],
2359 "EmitDefault": [],
2360 "PointerEmitDefault": []
2361 },
2362 {
2363 "EmitNull": [
2364 "v"
2365 ],
2366 "PointerEmitNull": [
2367 "v"
2368 ],
2369 "EmitEmpty": [
2370 "v"
2371 ],
2372 "PointerEmitEmpty": [
2373 "v"
2374 ],
2375 "EmitDefault": [
2376 "v"
2377 ],
2378 "PointerEmitDefault": [
2379 "v"
2380 ]
2381 }
2382 ]`,
2383 }, {
2384 name: jsontest.Name("Structs/Format/Invalid/Bool"),
2385 in: structFormatInvalid{Bool: true},
2386 want: `{"Bool"`,
2387 wantErr: EM(errInvalidFormatFlag).withPos(`{"Bool":`, "/Bool").withType(0, boolType),
2388 }, {
2389 name: jsontest.Name("Structs/Format/Invalid/String"),
2390 in: structFormatInvalid{String: "string"},
2391 want: `{"String"`,
2392 wantErr: EM(errInvalidFormatFlag).withPos(`{"String":`, "/String").withType(0, stringType),
2393 }, {
2394 name: jsontest.Name("Structs/Format/Invalid/Bytes"),
2395 in: structFormatInvalid{Bytes: []byte("bytes")},
2396 want: `{"Bytes"`,
2397 wantErr: EM(errInvalidFormatFlag).withPos(`{"Bytes":`, "/Bytes").withType(0, bytesType),
2398 }, {
2399 name: jsontest.Name("Structs/Format/Invalid/Int"),
2400 in: structFormatInvalid{Int: 1},
2401 want: `{"Int"`,
2402 wantErr: EM(errInvalidFormatFlag).withPos(`{"Int":`, "/Int").withType(0, T[int64]()),
2403 }, {
2404 name: jsontest.Name("Structs/Format/Invalid/Uint"),
2405 in: structFormatInvalid{Uint: 1},
2406 want: `{"Uint"`,
2407 wantErr: EM(errInvalidFormatFlag).withPos(`{"Uint":`, "/Uint").withType(0, T[uint64]()),
2408 }, {
2409 name: jsontest.Name("Structs/Format/Invalid/Float"),
2410 in: structFormatInvalid{Float: 1},
2411 want: `{"Float"`,
2412 wantErr: EM(errInvalidFormatFlag).withPos(`{"Float":`, "/Float").withType(0, T[float64]()),
2413 }, {
2414 name: jsontest.Name("Structs/Format/Invalid/Map"),
2415 in: structFormatInvalid{Map: map[string]string{}},
2416 want: `{"Map"`,
2417 wantErr: EM(errInvalidFormatFlag).withPos(`{"Map":`, "/Map").withType(0, T[map[string]string]()),
2418 }, {
2419 name: jsontest.Name("Structs/Format/Invalid/Struct"),
2420 in: structFormatInvalid{Struct: structAll{Bool: true}},
2421 want: `{"Struct"`,
2422 wantErr: EM(errInvalidFormatFlag).withPos(`{"Struct":`, "/Struct").withType(0, T[structAll]()),
2423 }, {
2424 name: jsontest.Name("Structs/Format/Invalid/Slice"),
2425 in: structFormatInvalid{Slice: []string{}},
2426 want: `{"Slice"`,
2427 wantErr: EM(errInvalidFormatFlag).withPos(`{"Slice":`, "/Slice").withType(0, T[[]string]()),
2428 }, {
2429 name: jsontest.Name("Structs/Format/Invalid/Array"),
2430 in: structFormatInvalid{Array: [1]string{"string"}},
2431 want: `{"Array"`,
2432 wantErr: EM(errInvalidFormatFlag).withPos(`{"Array":`, "/Array").withType(0, T[[1]string]()),
2433 }, {
2434 name: jsontest.Name("Structs/Format/Invalid/Interface"),
2435 in: structFormatInvalid{Interface: "anything"},
2436 want: `{"Interface"`,
2437 wantErr: EM(errInvalidFormatFlag).withPos(`{"Interface":`, "/Interface").withType(0, T[any]()),
2438 }, {
2439 name: jsontest.Name("Structs/Inline/Zero"),
2440 in: structInlined{},
2441 want: `{"D":""}`,
2442 }, {
2443 name: jsontest.Name("Structs/Inline/Alloc"),
2444 in: structInlined{
2445 X: structInlinedL1{
2446 X: &structInlinedL2{},
2447 StructEmbed1: StructEmbed1{},
2448 },
2449 StructEmbed2: &StructEmbed2{},
2450 },
2451 want: `{"A":"","B":"","D":"","E":"","F":"","G":""}`,
2452 }, {
2453 name: jsontest.Name("Structs/Inline/NonZero"),
2454 in: structInlined{
2455 X: structInlinedL1{
2456 X: &structInlinedL2{A: "A1", B: "B1", C: "C1"},
2457 StructEmbed1: StructEmbed1{C: "C2", D: "D2", E: "E2"},
2458 },
2459 StructEmbed2: &StructEmbed2{E: "E3", F: "F3", G: "G3"},
2460 },
2461 want: `{"A":"A1","B":"B1","D":"D2","E":"E3","F":"F3","G":"G3"}`,
2462 }, {
2463 name: jsontest.Name("Structs/Inline/DualCycle"),
2464 in: cyclicA{
2465 B1: cyclicB{F: 1},
2466 B2: cyclicB{F: 2},
2467 },
2468 want: `{}`,
2469 }, {
2470 name: jsontest.Name("Structs/InlinedFallback/TextValue/Nil"),
2471 in: structInlineTextValue{X: jsontext.Value(nil)},
2472 want: `{}`,
2473 }, {
2474 name: jsontest.Name("Structs/InlinedFallback/TextValue/Empty"),
2475 in: structInlineTextValue{X: jsontext.Value("")},
2476 want: `{}`,
2477 }, {
2478 name: jsontest.Name("Structs/InlinedFallback/TextValue/NonEmptyN1"),
2479 in: structInlineTextValue{X: jsontext.Value(` { "fizz" : "buzz" } `)},
2480 want: `{"fizz":"buzz"}`,
2481 }, {
2482 name: jsontest.Name("Structs/InlinedFallback/TextValue/NonEmptyN2"),
2483 in: structInlineTextValue{X: jsontext.Value(` { "fizz" : "buzz" , "foo" : "bar" } `)},
2484 want: `{"fizz":"buzz","foo":"bar"}`,
2485 }, {
2486 name: jsontest.Name("Structs/InlinedFallback/TextValue/NonEmptyWithOthers"),
2487 in: structInlineTextValue{
2488 A: 1,
2489 X: jsontext.Value(` { "fizz" : "buzz" , "foo" : "bar" } `),
2490 B: 2,
2491 },
2492
2493 want: `{"A":1,"B":2,"fizz":"buzz","foo":"bar"}`,
2494 }, {
2495 name: jsontest.Name("Structs/InlinedFallback/TextValue/RejectDuplicateNames"),
2496 opts: []Options{jsontext.AllowDuplicateNames(false)},
2497 in: structInlineTextValue{X: jsontext.Value(` { "fizz" : "buzz" , "fizz" : "buzz" } `)},
2498 want: `{"fizz":"buzz"`,
2499 wantErr: newDuplicateNameError("/fizz", nil, len64(`{"fizz":"buzz"`)),
2500 }, {
2501 name: jsontest.Name("Structs/InlinedFallback/TextValue/AllowDuplicateNames"),
2502 opts: []Options{jsontext.AllowDuplicateNames(true)},
2503 in: structInlineTextValue{X: jsontext.Value(` { "fizz" : "buzz" , "fizz" : "buzz" } `)},
2504 want: `{"fizz":"buzz","fizz":"buzz"}`,
2505 }, {
2506 name: jsontest.Name("Structs/InlinedFallback/TextValue/RejectInvalidUTF8"),
2507 opts: []Options{jsontext.AllowInvalidUTF8(false)},
2508 in: structInlineTextValue{X: jsontext.Value(`{"` + "\xde\xad\xbe\xef" + `":"value"}`)},
2509 want: `{`,
2510 wantErr: newInvalidUTF8Error(len64(`{"`+"\xde\xad"), ""),
2511 }, {
2512 name: jsontest.Name("Structs/InlinedFallback/TextValue/AllowInvalidUTF8"),
2513 opts: []Options{jsontext.AllowInvalidUTF8(true)},
2514 in: structInlineTextValue{X: jsontext.Value(`{"` + "\xde\xad\xbe\xef" + `":"value"}`)},
2515 want: `{"ޭ��":"value"}`,
2516 }, {
2517 name: jsontest.Name("Structs/InlinedFallback/TextValue/InvalidWhitespace"),
2518 in: structInlineTextValue{X: jsontext.Value("\n\r\t ")},
2519 want: `{`,
2520 wantErr: EM(io.ErrUnexpectedEOF).withPos(`{`, "").withType(0, T[jsontext.Value]()),
2521 }, {
2522 name: jsontest.Name("Structs/InlinedFallback/TextValue/InvalidObject"),
2523 in: structInlineTextValue{X: jsontext.Value(` true `)},
2524 want: `{`,
2525 wantErr: EM(errRawInlinedNotObject).withPos(`{`, "").withType(0, T[jsontext.Value]()),
2526 }, {
2527 name: jsontest.Name("Structs/InlinedFallback/TextValue/InvalidObjectName"),
2528 in: structInlineTextValue{X: jsontext.Value(` { true : false } `)},
2529 want: `{`,
2530 wantErr: EM(newNonStringNameError(len64(" { "), "")).withPos(`{`, "").withType(0, T[jsontext.Value]()),
2531 }, {
2532 name: jsontest.Name("Structs/InlinedFallback/TextValue/InvalidEndObject"),
2533 in: structInlineTextValue{X: jsontext.Value(` { "name" : false , } `)},
2534 want: `{"name":false`,
2535 wantErr: EM(newInvalidCharacterError(",", "at start of value", len64(` { "name" : false `), "")).withPos(`{"name":false,`, "").withType(0, T[jsontext.Value]()),
2536 }, {
2537 name: jsontest.Name("Structs/InlinedFallback/TextValue/InvalidDualObject"),
2538 in: structInlineTextValue{X: jsontext.Value(`{}{}`)},
2539 want: `{`,
2540 wantErr: EM(newInvalidCharacterError("{", "after top-level value", len64(`{}`), "")).withPos(`{`, "").withType(0, T[jsontext.Value]()),
2541 }, {
2542 name: jsontest.Name("Structs/InlinedFallback/TextValue/Nested/Nil"),
2543 in: structInlinePointerInlineTextValue{},
2544 want: `{}`,
2545 }, {
2546 name: jsontest.Name("Structs/InlinedFallback/PointerTextValue/Nil"),
2547 in: structInlinePointerTextValue{},
2548 want: `{}`,
2549 }, {
2550 name: jsontest.Name("Structs/InlinedFallback/PointerTextValue/NonEmpty"),
2551 in: structInlinePointerTextValue{X: addr(jsontext.Value(` { "fizz" : "buzz" } `))},
2552 want: `{"fizz":"buzz"}`,
2553 }, {
2554 name: jsontest.Name("Structs/InlinedFallback/PointerTextValue/Nested/Nil"),
2555 in: structInlineInlinePointerTextValue{},
2556 want: `{}`,
2557 }, {
2558 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/Nil"),
2559 in: structInlineMapStringAny{X: nil},
2560 want: `{}`,
2561 }, {
2562 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/Empty"),
2563 in: structInlineMapStringAny{X: make(jsonObject)},
2564 want: `{}`,
2565 }, {
2566 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/NonEmptyN1"),
2567 in: structInlineMapStringAny{X: jsonObject{"fizz": nil}},
2568 want: `{"fizz":null}`,
2569 }, {
2570 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/NonEmptyN2"),
2571 in: structInlineMapStringAny{X: jsonObject{"fizz": time.Time{}, "buzz": math.Pi}},
2572 want: `{"buzz":3.141592653589793,"fizz":"0001-01-01T00:00:00Z"}`,
2573 canonicalize: true,
2574 }, {
2575 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/NonEmptyWithOthers"),
2576 in: structInlineMapStringAny{
2577 A: 1,
2578 X: jsonObject{"fizz": nil},
2579 B: 2,
2580 },
2581
2582 want: `{"A":1,"B":2,"fizz":null}`,
2583 }, {
2584 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/RejectInvalidUTF8"),
2585 opts: []Options{jsontext.AllowInvalidUTF8(false)},
2586 in: structInlineMapStringAny{X: jsonObject{"\xde\xad\xbe\xef": nil}},
2587 want: `{`,
2588 wantErr: EM(jsonwire.ErrInvalidUTF8).withPos(`{`, "").withType(0, stringType),
2589 }, {
2590 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/AllowInvalidUTF8"),
2591 opts: []Options{jsontext.AllowInvalidUTF8(true)},
2592 in: structInlineMapStringAny{X: jsonObject{"\xde\xad\xbe\xef": nil}},
2593 want: `{"ޭ��":null}`,
2594 }, {
2595 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/InvalidValue"),
2596 opts: []Options{jsontext.AllowInvalidUTF8(true)},
2597 in: structInlineMapStringAny{X: jsonObject{"name": make(chan string)}},
2598 want: `{"name"`,
2599 wantErr: EM(nil).withPos(`{"name":`, "/name").withType(0, T[chan string]()),
2600 }, {
2601 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/Nested/Nil"),
2602 in: structInlinePointerInlineMapStringAny{},
2603 want: `{}`,
2604 }, {
2605 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/MarshalFunc"),
2606 opts: []Options{
2607 WithMarshalers(MarshalFunc(func(v float64) ([]byte, error) {
2608 return []byte(fmt.Sprintf(`"%v"`, v)), nil
2609 })),
2610 },
2611 in: structInlineMapStringAny{X: jsonObject{"fizz": 3.14159}},
2612 want: `{"fizz":"3.14159"}`,
2613 }, {
2614 name: jsontest.Name("Structs/InlinedFallback/PointerMapStringAny/Nil"),
2615 in: structInlinePointerMapStringAny{X: nil},
2616 want: `{}`,
2617 }, {
2618 name: jsontest.Name("Structs/InlinedFallback/PointerMapStringAny/NonEmpty"),
2619 in: structInlinePointerMapStringAny{X: addr(jsonObject{"name": "value"})},
2620 want: `{"name":"value"}`,
2621 }, {
2622 name: jsontest.Name("Structs/InlinedFallback/PointerMapStringAny/Nested/Nil"),
2623 in: structInlineInlinePointerMapStringAny{},
2624 want: `{}`,
2625 }, {
2626 name: jsontest.Name("Structs/InlinedFallback/MapStringInt"),
2627 in: structInlineMapStringInt{
2628 X: map[string]int{"zero": 0, "one": 1, "two": 2},
2629 },
2630 want: `{"one":1,"two":2,"zero":0}`,
2631 canonicalize: true,
2632 }, {
2633 name: jsontest.Name("Structs/InlinedFallback/MapStringInt/Deterministic"),
2634 opts: []Options{Deterministic(true)},
2635 in: structInlineMapStringInt{
2636 X: map[string]int{"zero": 0, "one": 1, "two": 2},
2637 },
2638 want: `{"one":1,"two":2,"zero":0}`,
2639 }, {
2640 name: jsontest.Name("Structs/InlinedFallback/MapStringInt/Deterministic+AllowInvalidUTF8+RejectDuplicateNames"),
2641 opts: []Options{Deterministic(true), jsontext.AllowInvalidUTF8(true), jsontext.AllowDuplicateNames(false)},
2642 in: structInlineMapStringInt{
2643 X: map[string]int{"\xff": 0, "\xfe": 1},
2644 },
2645 want: `{"�":1`,
2646 wantErr: newDuplicateNameError("", []byte(`"�"`), len64(`{"�":1`)),
2647 }, {
2648 name: jsontest.Name("Structs/InlinedFallback/MapStringInt/Deterministic+AllowInvalidUTF8+AllowDuplicateNames"),
2649 opts: []Options{Deterministic(true), jsontext.AllowInvalidUTF8(true), jsontext.AllowDuplicateNames(true)},
2650 in: structInlineMapStringInt{
2651 X: map[string]int{"\xff": 0, "\xfe": 1},
2652 },
2653 want: `{"�":1,"�":0}`,
2654 }, {
2655 name: jsontest.Name("Structs/InlinedFallback/MapStringInt/StringifiedNumbers"),
2656 opts: []Options{StringifyNumbers(true)},
2657 in: structInlineMapStringInt{
2658 X: map[string]int{"zero": 0, "one": 1, "two": 2},
2659 },
2660 want: `{"one":"1","two":"2","zero":"0"}`,
2661 canonicalize: true,
2662 }, {
2663 name: jsontest.Name("Structs/InlinedFallback/MapStringInt/MarshalFunc"),
2664 opts: []Options{
2665 WithMarshalers(JoinMarshalers(
2666
2667 MarshalFunc(func(v string) ([]byte, error) {
2668 return []byte(fmt.Sprintf(`"%q"`, strings.ToUpper(v))), nil
2669 }),
2670 MarshalFunc(func(v int) ([]byte, error) {
2671 return []byte(fmt.Sprintf(`"%v"`, v)), nil
2672 }),
2673 )),
2674 },
2675 in: structInlineMapStringInt{
2676 X: map[string]int{"zero": 0, "one": 1, "two": 2},
2677 },
2678 want: `{"one":"1","two":"2","zero":"0"}`,
2679 canonicalize: true,
2680 }, {
2681 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringInt"),
2682 in: structInlineMapNamedStringInt{
2683 X: map[namedString]int{"zero": 0, "one": 1, "two": 2},
2684 },
2685 want: `{"one":1,"two":2,"zero":0}`,
2686 canonicalize: true,
2687 }, {
2688 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringInt/Deterministic"),
2689 opts: []Options{Deterministic(true)},
2690 in: structInlineMapNamedStringInt{
2691 X: map[namedString]int{"zero": 0, "one": 1, "two": 2},
2692 },
2693 want: `{"one":1,"two":2,"zero":0}`,
2694 }, {
2695 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/Nil"),
2696 in: structInlineMapNamedStringAny{X: nil},
2697 want: `{}`,
2698 }, {
2699 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/Empty"),
2700 in: structInlineMapNamedStringAny{X: make(map[namedString]any)},
2701 want: `{}`,
2702 }, {
2703 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/NonEmptyN1"),
2704 in: structInlineMapNamedStringAny{X: map[namedString]any{"fizz": nil}},
2705 want: `{"fizz":null}`,
2706 }, {
2707 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/NonEmptyN2"),
2708 in: structInlineMapNamedStringAny{X: map[namedString]any{"fizz": time.Time{}, "buzz": math.Pi}},
2709 want: `{"buzz":3.141592653589793,"fizz":"0001-01-01T00:00:00Z"}`,
2710 canonicalize: true,
2711 }, {
2712 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/NonEmptyWithOthers"),
2713 in: structInlineMapNamedStringAny{
2714 A: 1,
2715 X: map[namedString]any{"fizz": nil},
2716 B: 2,
2717 },
2718
2719 want: `{"A":1,"B":2,"fizz":null}`,
2720 }, {
2721 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/RejectInvalidUTF8"),
2722 opts: []Options{jsontext.AllowInvalidUTF8(false)},
2723 in: structInlineMapNamedStringAny{X: map[namedString]any{"\xde\xad\xbe\xef": nil}},
2724 want: `{`,
2725 wantErr: EM(jsonwire.ErrInvalidUTF8).withPos(`{`, "").withType(0, T[namedString]()),
2726 }, {
2727 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/AllowInvalidUTF8"),
2728 opts: []Options{jsontext.AllowInvalidUTF8(true)},
2729 in: structInlineMapNamedStringAny{X: map[namedString]any{"\xde\xad\xbe\xef": nil}},
2730 want: `{"ޭ��":null}`,
2731 }, {
2732 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/InvalidValue"),
2733 opts: []Options{jsontext.AllowInvalidUTF8(true)},
2734 in: structInlineMapNamedStringAny{X: map[namedString]any{"name": make(chan string)}},
2735 want: `{"name"`,
2736 wantErr: EM(nil).withPos(`{"name":`, "/name").withType(0, T[chan string]()),
2737 }, {
2738 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/MarshalFunc"),
2739 opts: []Options{
2740 WithMarshalers(MarshalFunc(func(v float64) ([]byte, error) {
2741 return []byte(fmt.Sprintf(`"%v"`, v)), nil
2742 })),
2743 },
2744 in: structInlineMapNamedStringAny{X: map[namedString]any{"fizz": 3.14159}},
2745 want: `{"fizz":"3.14159"}`,
2746 }, {
2747 name: jsontest.Name("Structs/InlinedFallback/DiscardUnknownMembers"),
2748 opts: []Options{DiscardUnknownMembers(true)},
2749 in: structInlineTextValue{
2750 A: 1,
2751 X: jsontext.Value(` { "fizz" : "buzz" } `),
2752 B: 2,
2753 },
2754
2755 want: `{"A":1,"B":2,"fizz":"buzz"}`,
2756 }, {
2757 name: jsontest.Name("Structs/UnknownFallback/DiscardUnknownMembers"),
2758 opts: []Options{DiscardUnknownMembers(true)},
2759 in: structUnknownTextValue{
2760 A: 1,
2761 X: jsontext.Value(` { "fizz" : "buzz" } `),
2762 B: 2,
2763 },
2764 want: `{"A":1,"B":2}`,
2765 }, {
2766 name: jsontest.Name("Structs/UnknownFallback"),
2767 in: structUnknownTextValue{
2768 A: 1,
2769 X: jsontext.Value(` { "fizz" : "buzz" } `),
2770 B: 2,
2771 },
2772 want: `{"A":1,"B":2,"fizz":"buzz"}`,
2773 }, {
2774 name: jsontest.Name("Structs/DuplicateName/NoCaseInlineTextValue/Other"),
2775 in: structNoCaseInlineTextValue{
2776 X: jsontext.Value(`{"dupe":"","dupe":""}`),
2777 },
2778 want: `{"dupe":""`,
2779 wantErr: newDuplicateNameError("", []byte(`"dupe"`), len64(`{"dupe":""`)),
2780 }, {
2781 name: jsontest.Name("Structs/DuplicateName/NoCaseInlineTextValue/Other/AllowDuplicateNames"),
2782 opts: []Options{jsontext.AllowDuplicateNames(true)},
2783 in: structNoCaseInlineTextValue{
2784 X: jsontext.Value(`{"dupe": "", "dupe": ""}`),
2785 },
2786 want: `{"dupe":"","dupe":""}`,
2787 }, {
2788 name: jsontest.Name("Structs/DuplicateName/NoCaseInlineTextValue/ExactDifferent"),
2789 in: structNoCaseInlineTextValue{
2790 X: jsontext.Value(`{"Aaa": "", "AaA": "", "AAa": "", "AAA": ""}`),
2791 },
2792 want: `{"Aaa":"","AaA":"","AAa":"","AAA":""}`,
2793 }, {
2794 name: jsontest.Name("Structs/DuplicateName/NoCaseInlineTextValue/ExactConflict"),
2795 in: structNoCaseInlineTextValue{
2796 X: jsontext.Value(`{"Aaa": "", "Aaa": ""}`),
2797 },
2798 want: `{"Aaa":""`,
2799 wantErr: newDuplicateNameError("", []byte(`"Aaa"`), len64(`{"Aaa":""`)),
2800 }, {
2801 name: jsontest.Name("Structs/DuplicateName/NoCaseInlineTextValue/ExactConflict/AllowDuplicateNames"),
2802 opts: []Options{jsontext.AllowDuplicateNames(true)},
2803 in: structNoCaseInlineTextValue{
2804 X: jsontext.Value(`{"Aaa": "", "Aaa": ""}`),
2805 },
2806 want: `{"Aaa":"","Aaa":""}`,
2807 }, {
2808 name: jsontest.Name("Structs/DuplicateName/NoCaseInlineTextValue/NoCaseConflict"),
2809 in: structNoCaseInlineTextValue{
2810 X: jsontext.Value(`{"Aaa": "", "AaA": "", "aaa": ""}`),
2811 },
2812 want: `{"Aaa":"","AaA":""`,
2813 wantErr: newDuplicateNameError("", []byte(`"aaa"`), len64(`{"Aaa":"","AaA":""`)),
2814 }, {
2815 name: jsontest.Name("Structs/DuplicateName/NoCaseInlineTextValue/NoCaseConflict/AllowDuplicateNames"),
2816 opts: []Options{jsontext.AllowDuplicateNames(true)},
2817 in: structNoCaseInlineTextValue{
2818 X: jsontext.Value(`{"Aaa": "", "AaA": "", "aaa": ""}`),
2819 },
2820 want: `{"Aaa":"","AaA":"","aaa":""}`,
2821 }, {
2822 name: jsontest.Name("Structs/DuplicateName/NoCaseInlineTextValue/ExactDifferentWithField"),
2823 in: structNoCaseInlineTextValue{
2824 AAA: "x",
2825 AaA: "x",
2826 X: jsontext.Value(`{"Aaa": ""}`),
2827 },
2828 want: `{"AAA":"x","AaA":"x","Aaa":""}`,
2829 }, {
2830 name: jsontest.Name("Structs/DuplicateName/NoCaseInlineTextValue/ExactConflictWithField"),
2831 in: structNoCaseInlineTextValue{
2832 AAA: "x",
2833 AaA: "x",
2834 X: jsontext.Value(`{"AAA": ""}`),
2835 },
2836 want: `{"AAA":"x","AaA":"x"`,
2837 wantErr: newDuplicateNameError("", []byte(`"AAA"`), len64(`{"AAA":"x","AaA":"x"`)),
2838 }, {
2839 name: jsontest.Name("Structs/DuplicateName/NoCaseInlineTextValue/NoCaseConflictWithField"),
2840 in: structNoCaseInlineTextValue{
2841 AAA: "x",
2842 AaA: "x",
2843 X: jsontext.Value(`{"aaa": ""}`),
2844 },
2845 want: `{"AAA":"x","AaA":"x"`,
2846 wantErr: newDuplicateNameError("", []byte(`"aaa"`), len64(`{"AAA":"x","AaA":"x"`)),
2847 }, {
2848 name: jsontest.Name("Structs/DuplicateName/MatchCaseInsensitiveDelimiter"),
2849 in: structNoCaseInlineTextValue{
2850 AaA: "x",
2851 X: jsontext.Value(`{"aa_a": ""}`),
2852 },
2853 want: `{"AaA":"x"`,
2854 wantErr: newDuplicateNameError("", []byte(`"aa_a"`), len64(`{"AaA":"x"`)),
2855 }, {
2856 name: jsontest.Name("Structs/DuplicateName/MatchCaseSensitiveDelimiter"),
2857 opts: []Options{jsonflags.MatchCaseSensitiveDelimiter | 1},
2858 in: structNoCaseInlineTextValue{
2859 AaA: "x",
2860 X: jsontext.Value(`{"aa_a": ""}`),
2861 },
2862 want: `{"AaA":"x","aa_a":""}`,
2863 }, {
2864 name: jsontest.Name("Structs/DuplicateName/MatchCaseInsensitiveNames+MatchCaseSensitiveDelimiter"),
2865 opts: []Options{MatchCaseInsensitiveNames(true), jsonflags.MatchCaseSensitiveDelimiter | 1},
2866 in: structNoCaseInlineTextValue{
2867 AaA: "x",
2868 X: jsontext.Value(`{"aa_a": ""}`),
2869 },
2870 want: `{"AaA":"x","aa_a":""}`,
2871 }, {
2872 name: jsontest.Name("Structs/DuplicateName/MatchCaseInsensitiveNames+MatchCaseSensitiveDelimiter"),
2873 opts: []Options{MatchCaseInsensitiveNames(true), jsonflags.MatchCaseSensitiveDelimiter | 1},
2874 in: structNoCaseInlineTextValue{
2875 AA_b: "x",
2876 X: jsontext.Value(`{"aa_b": ""}`),
2877 },
2878 want: `{"AA_b":"x"`,
2879 wantErr: newDuplicateNameError("", []byte(`"aa_b"`), len64(`{"AA_b":"x"`)),
2880 }, {
2881 name: jsontest.Name("Structs/DuplicateName/NoCaseInlineMapStringAny/ExactDifferent"),
2882 in: structNoCaseInlineMapStringAny{
2883 X: jsonObject{"Aaa": "", "AaA": "", "AAa": "", "AAA": ""},
2884 },
2885 want: `{"AAA":"","AAa":"","AaA":"","Aaa":""}`,
2886 canonicalize: true,
2887 }, {
2888 name: jsontest.Name("Structs/DuplicateName/NoCaseInlineMapStringAny/ExactDifferentWithField"),
2889 in: structNoCaseInlineMapStringAny{
2890 AAA: "x",
2891 AaA: "x",
2892 X: jsonObject{"Aaa": ""},
2893 },
2894 want: `{"AAA":"x","AaA":"x","Aaa":""}`,
2895 }, {
2896 name: jsontest.Name("Structs/DuplicateName/NoCaseInlineMapStringAny/ExactConflictWithField"),
2897 in: structNoCaseInlineMapStringAny{
2898 AAA: "x",
2899 AaA: "x",
2900 X: jsonObject{"AAA": ""},
2901 },
2902 want: `{"AAA":"x","AaA":"x"`,
2903 wantErr: newDuplicateNameError("", []byte(`"AAA"`), len64(`{"AAA":"x","AaA":"x"`)),
2904 }, {
2905 name: jsontest.Name("Structs/DuplicateName/NoCaseInlineMapStringAny/NoCaseConflictWithField"),
2906 in: structNoCaseInlineMapStringAny{
2907 AAA: "x",
2908 AaA: "x",
2909 X: jsonObject{"aaa": ""},
2910 },
2911 want: `{"AAA":"x","AaA":"x"`,
2912 wantErr: newDuplicateNameError("", []byte(`"aaa"`), len64(`{"AAA":"x","AaA":"x"`)),
2913 }, {
2914 name: jsontest.Name("Structs/Invalid/Conflicting"),
2915 in: structConflicting{},
2916 want: ``,
2917 wantErr: EM(errors.New("Go struct fields A and B conflict over JSON object name \"conflict\"")).withType(0, T[structConflicting]()),
2918 }, {
2919 name: jsontest.Name("Structs/Invalid/NoneExported"),
2920 in: structNoneExported{},
2921 want: ``,
2922 wantErr: EM(errNoExportedFields).withType(0, T[structNoneExported]()),
2923 }, {
2924 name: jsontest.Name("Structs/Invalid/MalformedTag"),
2925 in: structMalformedTag{},
2926 want: ``,
2927 wantErr: EM(errors.New("Go struct field Malformed has malformed `json` tag: invalid character '\"' at start of option (expecting Unicode letter or single quote)")).withType(0, T[structMalformedTag]()),
2928 }, {
2929 name: jsontest.Name("Structs/Invalid/UnexportedTag"),
2930 in: structUnexportedTag{},
2931 want: ``,
2932 wantErr: EM(errors.New("unexported Go struct field unexported cannot have non-ignored `json:\"name\"` tag")).withType(0, T[structUnexportedTag]()),
2933 }, {
2934 name: jsontest.Name("Structs/Invalid/ExportedEmbedded"),
2935 in: structExportedEmbedded{"hello"},
2936 want: ``,
2937 wantErr: EM(errors.New("embedded Go struct field NamedString of non-struct type must be explicitly given a JSON name")).withType(0, T[structExportedEmbedded]()),
2938 }, {
2939 name: jsontest.Name("Structs/Valid/ExportedEmbedded"),
2940 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
2941 in: structExportedEmbedded{"hello"},
2942 want: `{"NamedString":"hello"}`,
2943 }, {
2944 name: jsontest.Name("Structs/Valid/ExportedEmbeddedTag"),
2945 in: structExportedEmbeddedTag{"hello"},
2946 want: `{"name":"hello"}`,
2947 }, {
2948 name: jsontest.Name("Structs/Invalid/UnexportedEmbedded"),
2949 in: structUnexportedEmbedded{},
2950 want: ``,
2951 wantErr: EM(errors.New("embedded Go struct field namedString of non-struct type must be explicitly given a JSON name")).withType(0, T[structUnexportedEmbedded]()),
2952 }, {
2953 name: jsontest.Name("Structs/Valid/UnexportedEmbedded"),
2954 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
2955 in: structUnexportedEmbedded{},
2956 want: `{}`,
2957 }, {
2958 name: jsontest.Name("Structs/Invalid/UnexportedEmbeddedTag"),
2959 in: structUnexportedEmbeddedTag{},
2960 wantErr: EM(errors.New("Go struct field namedString is not exported")).withType(0, T[structUnexportedEmbeddedTag]()),
2961 }, {
2962 name: jsontest.Name("Structs/Valid/UnexportedEmbeddedTag"),
2963 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
2964 in: structUnexportedEmbeddedTag{},
2965 want: `{}`,
2966 }, {
2967 name: jsontest.Name("Structs/Invalid/UnexportedEmbeddedMethodTag"),
2968 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
2969 in: structUnexportedEmbeddedMethodTag{},
2970 want: `{}`,
2971 }, {
2972 name: jsontest.Name("Structs/UnexportedEmbeddedStruct/Zero"),
2973 in: structUnexportedEmbeddedStruct{},
2974 want: `{"FizzBuzz":0,"Addr":""}`,
2975 }, {
2976 name: jsontest.Name("Structs/UnexportedEmbeddedStruct/NonZero"),
2977 in: structUnexportedEmbeddedStruct{structOmitZeroAll{Bool: true}, 5, structNestedAddr{netip.AddrFrom4([4]byte{192, 168, 0, 1})}},
2978 want: `{"Bool":true,"FizzBuzz":5,"Addr":"192.168.0.1"}`,
2979 }, {
2980 name: jsontest.Name("Structs/UnexportedEmbeddedStructPointer/Nil"),
2981 in: structUnexportedEmbeddedStructPointer{},
2982 want: `{"FizzBuzz":0}`,
2983 }, {
2984 name: jsontest.Name("Structs/UnexportedEmbeddedStructPointer/Zero"),
2985 in: structUnexportedEmbeddedStructPointer{&structOmitZeroAll{}, 0, &structNestedAddr{}},
2986 want: `{"FizzBuzz":0,"Addr":""}`,
2987 }, {
2988 name: jsontest.Name("Structs/UnexportedEmbeddedStructPointer/NonZero"),
2989 in: structUnexportedEmbeddedStructPointer{&structOmitZeroAll{Bool: true}, 5, &structNestedAddr{netip.AddrFrom4([4]byte{192, 168, 0, 1})}},
2990 want: `{"Bool":true,"FizzBuzz":5,"Addr":"192.168.0.1"}`,
2991 }, {
2992 name: jsontest.Name("Structs/IgnoreInvalidFormat"),
2993 opts: []Options{invalidFormatOption},
2994 in: struct{}{},
2995 want: `{}`,
2996 }, {
2997 name: jsontest.Name("Slices/Interface"),
2998 in: []any{
2999 false, true,
3000 "hello", []byte("world"),
3001 int32(-32), namedInt64(-64),
3002 uint32(+32), namedUint64(+64),
3003 float32(32.32), namedFloat64(64.64),
3004 },
3005 want: `[false,true,"hello","d29ybGQ=",-32,-64,32,64,32.32,64.64]`,
3006 }, {
3007 name: jsontest.Name("Slices/Invalid/Channel"),
3008 in: [](chan string){nil},
3009 want: `[`,
3010 wantErr: EM(nil).withPos(`[`, "/0").withType(0, T[chan string]()),
3011 }, {
3012 name: jsontest.Name("Slices/RecursiveSlice"),
3013 in: recursiveSlice{
3014 nil,
3015 {},
3016 {nil},
3017 {nil, {}},
3018 },
3019 want: `[[],[],[[]],[[],[]]]`,
3020 }, {
3021 name: jsontest.Name("Slices/CyclicSlice"),
3022 in: func() recursiveSlice {
3023 s := recursiveSlice{{}}
3024 s[0] = s
3025 return s
3026 }(),
3027 want: strings.Repeat(`[`, startDetectingCyclesAfter) + `[`,
3028 wantErr: EM(internal.ErrCycle).withPos(strings.Repeat("[", startDetectingCyclesAfter+1), jsontext.Pointer(strings.Repeat("/0", startDetectingCyclesAfter+1))).withType(0, T[recursiveSlice]()),
3029 }, {
3030 name: jsontest.Name("Slices/NonCyclicSlice"),
3031 in: func() []any {
3032 v := []any{nil, nil}
3033 v[1] = v[:1]
3034 for i := 1000; i > 0; i-- {
3035 v = []any{v}
3036 }
3037 return v
3038 }(),
3039 want: strings.Repeat(`[`, startDetectingCyclesAfter) + `[null,[null]]` + strings.Repeat(`]`, startDetectingCyclesAfter),
3040 }, {
3041 name: jsontest.Name("Slices/IgnoreInvalidFormat"),
3042 opts: []Options{invalidFormatOption},
3043 in: []string{"hello", "goodbye"},
3044 want: `["hello","goodbye"]`,
3045 }, {
3046 name: jsontest.Name("Arrays/Empty"),
3047 in: [0]struct{}{},
3048 want: `[]`,
3049 }, {
3050 name: jsontest.Name("Arrays/Bool"),
3051 in: [2]bool{false, true},
3052 want: `[false,true]`,
3053 }, {
3054 name: jsontest.Name("Arrays/String"),
3055 in: [2]string{"hello", "goodbye"},
3056 want: `["hello","goodbye"]`,
3057 }, {
3058 name: jsontest.Name("Arrays/Bytes"),
3059 in: [2][]byte{[]byte("hello"), []byte("goodbye")},
3060 want: `["aGVsbG8=","Z29vZGJ5ZQ=="]`,
3061 }, {
3062 name: jsontest.Name("Arrays/Int"),
3063 in: [2]int64{math.MinInt64, math.MaxInt64},
3064 want: `[-9223372036854775808,9223372036854775807]`,
3065 }, {
3066 name: jsontest.Name("Arrays/Uint"),
3067 in: [2]uint64{0, math.MaxUint64},
3068 want: `[0,18446744073709551615]`,
3069 }, {
3070 name: jsontest.Name("Arrays/Float"),
3071 in: [2]float64{-math.MaxFloat64, +math.MaxFloat64},
3072 want: `[-1.7976931348623157e+308,1.7976931348623157e+308]`,
3073 }, {
3074 name: jsontest.Name("Arrays/Invalid/Channel"),
3075 in: new([1]chan string),
3076 want: `[`,
3077 wantErr: EM(nil).withPos(`[`, "/0").withType(0, T[chan string]()),
3078 }, {
3079 name: jsontest.Name("Arrays/IgnoreInvalidFormat"),
3080 opts: []Options{invalidFormatOption},
3081 in: [2]string{"hello", "goodbye"},
3082 want: `["hello","goodbye"]`,
3083 }, {
3084 name: jsontest.Name("Pointers/NilL0"),
3085 in: (*int)(nil),
3086 want: `null`,
3087 }, {
3088 name: jsontest.Name("Pointers/NilL1"),
3089 in: new(*int),
3090 want: `null`,
3091 }, {
3092 name: jsontest.Name("Pointers/Bool"),
3093 in: addr(addr(bool(true))),
3094 want: `true`,
3095 }, {
3096 name: jsontest.Name("Pointers/String"),
3097 in: addr(addr(string("string"))),
3098 want: `"string"`,
3099 }, {
3100 name: jsontest.Name("Pointers/Bytes"),
3101 in: addr(addr([]byte("bytes"))),
3102 want: `"Ynl0ZXM="`,
3103 }, {
3104 name: jsontest.Name("Pointers/Int"),
3105 in: addr(addr(int(-100))),
3106 want: `-100`,
3107 }, {
3108 name: jsontest.Name("Pointers/Uint"),
3109 in: addr(addr(uint(100))),
3110 want: `100`,
3111 }, {
3112 name: jsontest.Name("Pointers/Float"),
3113 in: addr(addr(float64(3.14159))),
3114 want: `3.14159`,
3115 }, {
3116 name: jsontest.Name("Pointers/CyclicPointer"),
3117 in: func() *recursivePointer {
3118 p := new(recursivePointer)
3119 p.P = p
3120 return p
3121 }(),
3122 want: strings.Repeat(`{"P":`, startDetectingCyclesAfter) + `{"P"`,
3123 wantErr: EM(internal.ErrCycle).withPos(strings.Repeat(`{"P":`, startDetectingCyclesAfter+1), jsontext.Pointer(strings.Repeat("/P", startDetectingCyclesAfter+1))).withType(0, T[*recursivePointer]()),
3124 }, {
3125 name: jsontest.Name("Pointers/IgnoreInvalidFormat"),
3126 opts: []Options{invalidFormatOption},
3127 in: addr(addr(bool(true))),
3128 want: `true`,
3129 }, {
3130 name: jsontest.Name("Interfaces/Nil/Empty"),
3131 in: [1]any{nil},
3132 want: `[null]`,
3133 }, {
3134 name: jsontest.Name("Interfaces/Nil/NonEmpty"),
3135 in: [1]io.Reader{nil},
3136 want: `[null]`,
3137 }, {
3138 name: jsontest.Name("Interfaces/IgnoreInvalidFormat"),
3139 opts: []Options{invalidFormatOption},
3140 in: [1]io.Reader{nil},
3141 want: `[null]`,
3142 }, {
3143 name: jsontest.Name("Interfaces/Any"),
3144 in: struct{ X any }{[]any{nil, false, "", 0.0, map[string]any{}, []any{}, [8]byte{}}},
3145 want: `{"X":[null,false,"",0,{},[],"AAAAAAAAAAA="]}`,
3146 }, {
3147 name: jsontest.Name("Interfaces/Any/Named"),
3148 in: struct{ X namedAny }{[]namedAny{nil, false, "", 0.0, map[string]namedAny{}, []namedAny{}, [8]byte{}}},
3149 want: `{"X":[null,false,"",0,{},[],"AAAAAAAAAAA="]}`,
3150 }, {
3151 name: jsontest.Name("Interfaces/Any/Stringified"),
3152 opts: []Options{StringifyNumbers(true)},
3153 in: struct{ X any }{0.0},
3154 want: `{"X":"0"}`,
3155 }, {
3156 name: jsontest.Name("Interfaces/Any/MarshalFunc/Any"),
3157 opts: []Options{
3158 WithMarshalers(MarshalFunc(func(v any) ([]byte, error) {
3159 return []byte(`"called"`), nil
3160 })),
3161 },
3162 in: struct{ X any }{[]any{nil, false, "", 0.0, map[string]any{}, []any{}}},
3163 want: `"called"`,
3164 }, {
3165 name: jsontest.Name("Interfaces/Any/MarshalFunc/Bool"),
3166 opts: []Options{
3167 WithMarshalers(MarshalFunc(func(v bool) ([]byte, error) {
3168 return []byte(`"called"`), nil
3169 })),
3170 },
3171 in: struct{ X any }{[]any{nil, false, "", 0.0, map[string]any{}, []any{}}},
3172 want: `{"X":[null,"called","",0,{},[]]}`,
3173 }, {
3174 name: jsontest.Name("Interfaces/Any/MarshalFunc/String"),
3175 opts: []Options{
3176 WithMarshalers(MarshalFunc(func(v string) ([]byte, error) {
3177 return []byte(`"called"`), nil
3178 })),
3179 },
3180 in: struct{ X any }{[]any{nil, false, "", 0.0, map[string]any{}, []any{}}},
3181 want: `{"X":[null,false,"called",0,{},[]]}`,
3182 }, {
3183 name: jsontest.Name("Interfaces/Any/MarshalFunc/Float64"),
3184 opts: []Options{
3185 WithMarshalers(MarshalFunc(func(v float64) ([]byte, error) {
3186 return []byte(`"called"`), nil
3187 })),
3188 },
3189 in: struct{ X any }{[]any{nil, false, "", 0.0, map[string]any{}, []any{}}},
3190 want: `{"X":[null,false,"","called",{},[]]}`,
3191 }, {
3192 name: jsontest.Name("Interfaces/Any/MarshalFunc/MapStringAny"),
3193 opts: []Options{
3194 WithMarshalers(MarshalFunc(func(v map[string]any) ([]byte, error) {
3195 return []byte(`"called"`), nil
3196 })),
3197 },
3198 in: struct{ X any }{[]any{nil, false, "", 0.0, map[string]any{}, []any{}}},
3199 want: `{"X":[null,false,"",0,"called",[]]}`,
3200 }, {
3201 name: jsontest.Name("Interfaces/Any/MarshalFunc/SliceAny"),
3202 opts: []Options{
3203 WithMarshalers(MarshalFunc(func(v []any) ([]byte, error) {
3204 return []byte(`"called"`), nil
3205 })),
3206 },
3207 in: struct{ X any }{[]any{nil, false, "", 0.0, map[string]any{}, []any{}}},
3208 want: `{"X":"called"}`,
3209 }, {
3210 name: jsontest.Name("Interfaces/Any/MarshalFunc/Bytes"),
3211 opts: []Options{
3212 WithMarshalers(MarshalFunc(func(v [8]byte) ([]byte, error) {
3213 return []byte(`"called"`), nil
3214 })),
3215 },
3216 in: struct{ X any }{[8]byte{}},
3217 want: `{"X":"called"}`,
3218 }, {
3219 name: jsontest.Name("Interfaces/Any/Maps/Nil"),
3220 in: struct{ X any }{map[string]any(nil)},
3221 want: `{"X":{}}`,
3222 }, {
3223 name: jsontest.Name("Interfaces/Any/Maps/Nil/FormatNilMapAsNull"),
3224 opts: []Options{FormatNilMapAsNull(true)},
3225 in: struct{ X any }{map[string]any(nil)},
3226 want: `{"X":null}`,
3227 }, {
3228 name: jsontest.Name("Interfaces/Any/Maps/Empty"),
3229 in: struct{ X any }{map[string]any{}},
3230 want: `{"X":{}}`,
3231 }, {
3232 name: jsontest.Name("Interfaces/Any/Maps/Empty/Multiline"),
3233 opts: []Options{jsontext.Multiline(true), jsontext.WithIndent("")},
3234 in: struct{ X any }{map[string]any{}},
3235 want: "{\n\"X\": {}\n}",
3236 }, {
3237 name: jsontest.Name("Interfaces/Any/Maps/NonEmpty"),
3238 in: struct{ X any }{map[string]any{"fizz": "buzz"}},
3239 want: `{"X":{"fizz":"buzz"}}`,
3240 }, {
3241 name: jsontest.Name("Interfaces/Any/Maps/Deterministic"),
3242 opts: []Options{Deterministic(true)},
3243 in: struct{ X any }{map[string]any{"alpha": "", "bravo": ""}},
3244 want: `{"X":{"alpha":"","bravo":""}}`,
3245 }, {
3246 name: jsontest.Name("Interfaces/Any/Maps/Deterministic+AllowInvalidUTF8+RejectDuplicateNames"),
3247 opts: []Options{Deterministic(true), jsontext.AllowInvalidUTF8(true), jsontext.AllowDuplicateNames(false)},
3248 in: struct{ X any }{map[string]any{"\xff": "", "\xfe": ""}},
3249 want: `{"X":{"�":""`,
3250 wantErr: newDuplicateNameError("/X", []byte(`"�"`), len64(`{"X":{"�":"",`)),
3251 }, {
3252 name: jsontest.Name("Interfaces/Any/Maps/Deterministic+AllowInvalidUTF8+AllowDuplicateNames"),
3253 opts: []Options{Deterministic(true), jsontext.AllowInvalidUTF8(true), jsontext.AllowDuplicateNames(true)},
3254 in: struct{ X any }{map[string]any{"\xff": "alpha", "\xfe": "bravo"}},
3255 want: `{"X":{"�":"bravo","�":"alpha"}}`,
3256 }, {
3257 name: jsontest.Name("Interfaces/Any/Maps/RejectInvalidUTF8"),
3258 in: struct{ X any }{map[string]any{"\xff": "", "\xfe": ""}},
3259 want: `{"X":{`,
3260 wantErr: newInvalidUTF8Error(len64(`{"X":{`), "/X"),
3261 }, {
3262 name: jsontest.Name("Interfaces/Any/Maps/AllowInvalidUTF8+RejectDuplicateNames"),
3263 opts: []Options{jsontext.AllowInvalidUTF8(true)},
3264 in: struct{ X any }{map[string]any{"\xff": "", "\xfe": ""}},
3265 want: `{"X":{"�":""`,
3266 wantErr: newDuplicateNameError("/X", []byte(`"�"`), len64(`{"X":{"�":"",`)),
3267 }, {
3268 name: jsontest.Name("Interfaces/Any/Maps/AllowInvalidUTF8+AllowDuplicateNames"),
3269 opts: []Options{jsontext.AllowInvalidUTF8(true), jsontext.AllowDuplicateNames(true)},
3270 in: struct{ X any }{map[string]any{"\xff": "", "\xfe": ""}},
3271 want: `{"X":{"�":"","�":""}}`,
3272 }, {
3273 name: jsontest.Name("Interfaces/Any/Maps/Cyclic"),
3274 in: func() any {
3275 m := map[string]any{}
3276 m[""] = m
3277 return struct{ X any }{m}
3278 }(),
3279 want: `{"X"` + strings.Repeat(`:{""`, startDetectingCyclesAfter),
3280 wantErr: EM(internal.ErrCycle).withPos(`{"X":`+strings.Repeat(`{"":`, startDetectingCyclesAfter), "/X"+jsontext.Pointer(strings.Repeat("/", startDetectingCyclesAfter))).withType(0, T[any]()),
3281 }, {
3282 name: jsontest.Name("Interfaces/Any/Slices/Nil"),
3283 in: struct{ X any }{[]any(nil)},
3284 want: `{"X":[]}`,
3285 }, {
3286 name: jsontest.Name("Interfaces/Any/Slices/Nil/FormatNilSliceAsNull"),
3287 opts: []Options{FormatNilSliceAsNull(true)},
3288 in: struct{ X any }{[]any(nil)},
3289 want: `{"X":null}`,
3290 }, {
3291 name: jsontest.Name("Interfaces/Any/Slices/Empty"),
3292 in: struct{ X any }{[]any{}},
3293 want: `{"X":[]}`,
3294 }, {
3295 name: jsontest.Name("Interfaces/Any/Slices/Empty/Multiline"),
3296 opts: []Options{jsontext.Multiline(true), jsontext.WithIndent("")},
3297 in: struct{ X any }{[]any{}},
3298 want: "{\n\"X\": []\n}",
3299 }, {
3300 name: jsontest.Name("Interfaces/Any/Slices/NonEmpty"),
3301 in: struct{ X any }{[]any{"fizz", "buzz"}},
3302 want: `{"X":["fizz","buzz"]}`,
3303 }, {
3304 name: jsontest.Name("Interfaces/Any/Slices/Cyclic"),
3305 in: func() any {
3306 s := make([]any, 1)
3307 s[0] = s
3308 return struct{ X any }{s}
3309 }(),
3310 want: `{"X":` + strings.Repeat(`[`, startDetectingCyclesAfter),
3311 wantErr: EM(internal.ErrCycle).withPos(`{"X":`+strings.Repeat(`[`, startDetectingCyclesAfter), "/X"+jsontext.Pointer(strings.Repeat("/0", startDetectingCyclesAfter))).withType(0, T[[]any]()),
3312 }, {
3313 name: jsontest.Name("Methods/NilPointer"),
3314 in: struct{ X *allMethods }{X: (*allMethods)(nil)},
3315 want: `{"X":null}`,
3316 }, {
3317
3318 name: jsontest.Name("Methods/NilInterface"),
3319 in: struct{ X MarshalerTo }{X: (*allMethods)(nil)},
3320 want: `{"X":null}`,
3321 }, {
3322 name: jsontest.Name("Methods/AllMethods"),
3323 in: struct{ X *allMethods }{X: &allMethods{method: "MarshalJSONTo", value: []byte(`"hello"`)}},
3324 want: `{"X":"hello"}`,
3325 }, {
3326 name: jsontest.Name("Methods/AllMethodsExceptJSONv2"),
3327 in: struct{ X *allMethodsExceptJSONv2 }{X: &allMethodsExceptJSONv2{allMethods: allMethods{method: "MarshalJSON", value: []byte(`"hello"`)}}},
3328 want: `{"X":"hello"}`,
3329 }, {
3330 name: jsontest.Name("Methods/AllMethodsExceptJSONv1"),
3331 in: struct{ X *allMethodsExceptJSONv1 }{X: &allMethodsExceptJSONv1{allMethods: allMethods{method: "MarshalJSONTo", value: []byte(`"hello"`)}}},
3332 want: `{"X":"hello"}`,
3333 }, {
3334 name: jsontest.Name("Methods/AllMethodsExceptText"),
3335 in: struct{ X *allMethodsExceptText }{X: &allMethodsExceptText{allMethods: allMethods{method: "MarshalJSONTo", value: []byte(`"hello"`)}}},
3336 want: `{"X":"hello"}`,
3337 }, {
3338 name: jsontest.Name("Methods/OnlyMethodJSONv2"),
3339 in: struct{ X *onlyMethodJSONv2 }{X: &onlyMethodJSONv2{allMethods: allMethods{method: "MarshalJSONTo", value: []byte(`"hello"`)}}},
3340 want: `{"X":"hello"}`,
3341 }, {
3342 name: jsontest.Name("Methods/OnlyMethodJSONv1"),
3343 in: struct{ X *onlyMethodJSONv1 }{X: &onlyMethodJSONv1{allMethods: allMethods{method: "MarshalJSON", value: []byte(`"hello"`)}}},
3344 want: `{"X":"hello"}`,
3345 }, {
3346 name: jsontest.Name("Methods/OnlyMethodText"),
3347 in: struct{ X *onlyMethodText }{X: &onlyMethodText{allMethods: allMethods{method: "MarshalText", value: []byte(`hello`)}}},
3348 want: `{"X":"hello"}`,
3349 }, {
3350 name: jsontest.Name("Methods/IP"),
3351 in: net.IPv4(192, 168, 0, 100),
3352 want: `"192.168.0.100"`,
3353 }, {
3354 name: jsontest.Name("Methods/NetIP"),
3355 in: struct {
3356 Addr netip.Addr
3357 AddrPort netip.AddrPort
3358 Prefix netip.Prefix
3359 }{
3360 Addr: netip.AddrFrom4([4]byte{1, 2, 3, 4}),
3361 AddrPort: netip.AddrPortFrom(netip.AddrFrom4([4]byte{1, 2, 3, 4}), 1234),
3362 Prefix: netip.PrefixFrom(netip.AddrFrom4([4]byte{1, 2, 3, 4}), 24),
3363 },
3364 want: `{"Addr":"1.2.3.4","AddrPort":"1.2.3.4:1234","Prefix":"1.2.3.4/24"}`,
3365 }, {
3366
3367 name: jsontest.Name("Methods/Anonymous"),
3368 in: struct{ X struct{ allMethods } }{X: struct{ allMethods }{allMethods{method: "MarshalJSONTo", value: []byte(`"hello"`)}}},
3369 want: `{"X":"hello"}`,
3370 }, {
3371
3372 name: jsontest.Name("Methods/Addressable"),
3373 in: struct {
3374 V allMethods
3375 M map[string]allMethods
3376 I any
3377 }{
3378 V: allMethods{method: "MarshalJSONTo", value: []byte(`"hello"`)},
3379 M: map[string]allMethods{"K": {method: "MarshalJSONTo", value: []byte(`"hello"`)}},
3380 I: allMethods{method: "MarshalJSONTo", value: []byte(`"hello"`)},
3381 },
3382 want: `{"V":"hello","M":{"K":"hello"},"I":"hello"}`,
3383 }, {
3384
3385 name: jsontest.Name("Methods/MapKey/JSONv2"),
3386 in: map[structMethodJSONv2]string{{"k1"}: "v1", {"k2"}: "v2"},
3387 want: `{"k1":"v1","k2":"v2"}`,
3388 canonicalize: true,
3389 }, {
3390
3391 name: jsontest.Name("Methods/MapKey/JSONv1"),
3392 in: map[structMethodJSONv1]string{{"k1"}: "v1", {"k2"}: "v2"},
3393 want: `{"k1":"v1","k2":"v2"}`,
3394 canonicalize: true,
3395 }, {
3396 name: jsontest.Name("Methods/MapKey/Text"),
3397 in: map[structMethodText]string{{"k1"}: "v1", {"k2"}: "v2"},
3398 want: `{"k1":"v1","k2":"v2"}`,
3399 canonicalize: true,
3400 }, {
3401 name: jsontest.Name("Methods/Invalid/JSONv2/Error"),
3402 in: marshalJSONv2Func(func(*jsontext.Encoder) error {
3403 return errSomeError
3404 }),
3405 wantErr: EM(errSomeError).withType(0, T[marshalJSONv2Func]()),
3406 }, {
3407 name: jsontest.Name("Methods/Invalid/JSONv2/TooFew"),
3408 in: marshalJSONv2Func(func(*jsontext.Encoder) error {
3409 return nil
3410 }),
3411 wantErr: EM(errNonSingularValue).withType(0, T[marshalJSONv2Func]()),
3412 }, {
3413 name: jsontest.Name("Methods/Invalid/JSONv2/TooMany"),
3414 in: marshalJSONv2Func(func(enc *jsontext.Encoder) error {
3415 enc.WriteToken(jsontext.Null)
3416 enc.WriteToken(jsontext.Null)
3417 return nil
3418 }),
3419 want: `nullnull`,
3420 wantErr: EM(errNonSingularValue).withPos(`nullnull`, "").withType(0, T[marshalJSONv2Func]()),
3421 }, {
3422 name: jsontest.Name("Methods/Invalid/JSONv2/SkipFunc"),
3423 in: marshalJSONv2Func(func(enc *jsontext.Encoder) error {
3424 return SkipFunc
3425 }),
3426 wantErr: EM(errors.New("marshal method cannot be skipped")).withType(0, T[marshalJSONv2Func]()),
3427 }, {
3428 name: jsontest.Name("Methods/Invalid/JSONv1/Error"),
3429 in: marshalJSONv1Func(func() ([]byte, error) {
3430 return nil, errSomeError
3431 }),
3432 wantErr: EM(errSomeError).withType(0, T[marshalJSONv1Func]()),
3433 }, {
3434 name: jsontest.Name("Methods/Invalid/JSONv1/Syntax"),
3435 in: marshalJSONv1Func(func() ([]byte, error) {
3436 return []byte("invalid"), nil
3437 }),
3438 wantErr: EM(newInvalidCharacterError("i", "at start of value", 0, "")).withType(0, T[marshalJSONv1Func]()),
3439 }, {
3440 name: jsontest.Name("Methods/Invalid/JSONv1/SkipFunc"),
3441 in: marshalJSONv1Func(func() ([]byte, error) {
3442 return nil, SkipFunc
3443 }),
3444 wantErr: EM(errors.New("marshal method cannot be skipped")).withType(0, T[marshalJSONv1Func]()),
3445 }, {
3446 name: jsontest.Name("Methods/AppendText"),
3447 in: appendTextFunc(func(b []byte) ([]byte, error) { return append(b, "hello"...), nil }),
3448 want: `"hello"`,
3449 }, {
3450 name: jsontest.Name("Methods/AppendText/Error"),
3451 in: appendTextFunc(func(b []byte) ([]byte, error) { return append(b, "hello"...), errSomeError }),
3452 wantErr: EM(errSomeError).withType(0, T[appendTextFunc]()),
3453 }, {
3454 name: jsontest.Name("Methods/AppendText/NeedEscape"),
3455 in: appendTextFunc(func(b []byte) ([]byte, error) { return append(b, `"`...), nil }),
3456 want: `"\""`,
3457 }, {
3458 name: jsontest.Name("Methods/AppendText/RejectInvalidUTF8"),
3459 in: appendTextFunc(func(b []byte) ([]byte, error) { return append(b, "\xde\xad\xbe\xef"...), nil }),
3460 wantErr: EM(newInvalidUTF8Error(0, "")).withType(0, T[appendTextFunc]()),
3461 }, {
3462 name: jsontest.Name("Methods/AppendText/AllowInvalidUTF8"),
3463 opts: []Options{jsontext.AllowInvalidUTF8(true)},
3464 in: appendTextFunc(func(b []byte) ([]byte, error) { return append(b, "\xde\xad\xbe\xef"...), nil }),
3465 want: "\"\xde\xad\ufffd\ufffd\"",
3466 }, {
3467 name: jsontest.Name("Methods/Invalid/Text/Error"),
3468 in: marshalTextFunc(func() ([]byte, error) {
3469 return nil, errSomeError
3470 }),
3471 wantErr: EM(errSomeError).withType(0, T[marshalTextFunc]()),
3472 }, {
3473 name: jsontest.Name("Methods/Text/RejectInvalidUTF8"),
3474 in: marshalTextFunc(func() ([]byte, error) {
3475 return []byte("\xde\xad\xbe\xef"), nil
3476 }),
3477 wantErr: EM(newInvalidUTF8Error(0, "")).withType(0, T[marshalTextFunc]()),
3478 }, {
3479 name: jsontest.Name("Methods/Text/AllowInvalidUTF8"),
3480 opts: []Options{jsontext.AllowInvalidUTF8(true)},
3481 in: marshalTextFunc(func() ([]byte, error) {
3482 return []byte("\xde\xad\xbe\xef"), nil
3483 }),
3484 want: "\"\xde\xad\ufffd\ufffd\"",
3485 }, {
3486 name: jsontest.Name("Methods/Invalid/Text/SkipFunc"),
3487 in: marshalTextFunc(func() ([]byte, error) {
3488 return nil, SkipFunc
3489 }),
3490 wantErr: EM(wrapSkipFunc(SkipFunc, "marshal method")).withType(0, T[marshalTextFunc]()),
3491 }, {
3492 name: jsontest.Name("Methods/Invalid/MapKey/JSONv2/Syntax"),
3493 in: map[any]string{
3494 addr(marshalJSONv2Func(func(enc *jsontext.Encoder) error {
3495 return enc.WriteToken(jsontext.Null)
3496 })): "invalid",
3497 },
3498 want: `{`,
3499 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[marshalJSONv2Func]()),
3500 }, {
3501 name: jsontest.Name("Methods/Invalid/MapKey/JSONv1/Syntax"),
3502 in: map[any]string{
3503 addr(marshalJSONv1Func(func() ([]byte, error) {
3504 return []byte(`null`), nil
3505 })): "invalid",
3506 },
3507 want: `{`,
3508 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[marshalJSONv1Func]()),
3509 }, {
3510 name: jsontest.Name("Functions/Bool/V1"),
3511 opts: []Options{
3512 WithMarshalers(MarshalFunc(func(bool) ([]byte, error) {
3513 return []byte(`"called"`), nil
3514 })),
3515 },
3516 in: true,
3517 want: `"called"`,
3518 }, {
3519 name: jsontest.Name("Functions/Bool/Empty"),
3520 opts: []Options{WithMarshalers(nil)},
3521 in: true,
3522 want: `true`,
3523 }, {
3524 name: jsontest.Name("Functions/NamedBool/V1/NoMatch"),
3525 opts: []Options{
3526 WithMarshalers(MarshalFunc(func(namedBool) ([]byte, error) {
3527 return nil, errMustNotCall
3528 })),
3529 },
3530 in: true,
3531 want: `true`,
3532 }, {
3533 name: jsontest.Name("Functions/NamedBool/V1/Match"),
3534 opts: []Options{
3535 WithMarshalers(MarshalFunc(func(namedBool) ([]byte, error) {
3536 return []byte(`"called"`), nil
3537 })),
3538 },
3539 in: namedBool(true),
3540 want: `"called"`,
3541 }, {
3542 name: jsontest.Name("Functions/PointerBool/V1/Match"),
3543 opts: []Options{
3544 WithMarshalers(MarshalFunc(func(v *bool) ([]byte, error) {
3545 _ = *v
3546 return []byte(`"called"`), nil
3547 })),
3548 },
3549 in: true,
3550 want: `"called"`,
3551 }, {
3552 name: jsontest.Name("Functions/Bool/V2"),
3553 opts: []Options{
3554 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
3555 return enc.WriteToken(jsontext.String("called"))
3556 })),
3557 },
3558 in: true,
3559 want: `"called"`,
3560 }, {
3561 name: jsontest.Name("Functions/NamedBool/V2/NoMatch"),
3562 opts: []Options{
3563 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v namedBool) error {
3564 return errMustNotCall
3565 })),
3566 },
3567 in: true,
3568 want: `true`,
3569 }, {
3570 name: jsontest.Name("Functions/NamedBool/V2/Match"),
3571 opts: []Options{
3572 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v namedBool) error {
3573 return enc.WriteToken(jsontext.String("called"))
3574 })),
3575 },
3576 in: namedBool(true),
3577 want: `"called"`,
3578 }, {
3579 name: jsontest.Name("Functions/PointerBool/V2/Match"),
3580 opts: []Options{
3581 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v *bool) error {
3582 _ = *v
3583 return enc.WriteToken(jsontext.String("called"))
3584 })),
3585 },
3586 in: true,
3587 want: `"called"`,
3588 }, {
3589 name: jsontest.Name("Functions/Bool/Empty1/NoMatch"),
3590 opts: []Options{
3591 WithMarshalers(new(Marshalers)),
3592 },
3593 in: true,
3594 want: `true`,
3595 }, {
3596 name: jsontest.Name("Functions/Bool/Empty2/NoMatch"),
3597 opts: []Options{
3598 WithMarshalers(JoinMarshalers()),
3599 },
3600 in: true,
3601 want: `true`,
3602 }, {
3603 name: jsontest.Name("Functions/Bool/V1/DirectError"),
3604 opts: []Options{
3605 WithMarshalers(MarshalFunc(func(bool) ([]byte, error) {
3606 return nil, errSomeError
3607 })),
3608 },
3609 in: true,
3610 wantErr: EM(errSomeError).withType(0, T[bool]()),
3611 }, {
3612 name: jsontest.Name("Functions/Bool/V1/SkipError"),
3613 opts: []Options{
3614 WithMarshalers(MarshalFunc(func(bool) ([]byte, error) {
3615 return nil, SkipFunc
3616 })),
3617 },
3618 in: true,
3619 wantErr: EM(wrapSkipFunc(SkipFunc, "marshal function of type func(T) ([]byte, error)")).withType(0, T[bool]()),
3620 }, {
3621 name: jsontest.Name("Functions/Bool/V1/InvalidValue"),
3622 opts: []Options{
3623 WithMarshalers(MarshalFunc(func(bool) ([]byte, error) {
3624 return []byte("invalid"), nil
3625 })),
3626 },
3627 in: true,
3628 wantErr: EM(newInvalidCharacterError("i", "at start of value", 0, "")).withType(0, T[bool]()),
3629 }, {
3630 name: jsontest.Name("Functions/Bool/V2/DirectError"),
3631 opts: []Options{
3632 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
3633 return errSomeError
3634 })),
3635 },
3636 in: true,
3637 wantErr: EM(errSomeError).withType(0, T[bool]()),
3638 }, {
3639 name: jsontest.Name("Functions/Bool/V2/TooFew"),
3640 opts: []Options{
3641 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
3642 return nil
3643 })),
3644 },
3645 in: true,
3646 wantErr: EM(errNonSingularValue).withType(0, T[bool]()),
3647 }, {
3648 name: jsontest.Name("Functions/Bool/V2/TooMany"),
3649 opts: []Options{
3650 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
3651 enc.WriteValue([]byte(`"hello"`))
3652 enc.WriteValue([]byte(`"world"`))
3653 return nil
3654 })),
3655 },
3656 in: true,
3657 want: `"hello""world"`,
3658 wantErr: EM(errNonSingularValue).withPos(`"hello""world"`, "").withType(0, T[bool]()),
3659 }, {
3660 name: jsontest.Name("Functions/Bool/V2/Skipped"),
3661 opts: []Options{
3662 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
3663 return SkipFunc
3664 })),
3665 },
3666 in: true,
3667 want: `true`,
3668 }, {
3669 name: jsontest.Name("Functions/Bool/V2/ProcessBeforeSkip"),
3670 opts: []Options{
3671 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
3672 enc.WriteValue([]byte(`"hello"`))
3673 return SkipFunc
3674 })),
3675 },
3676 in: true,
3677 want: `"hello"`,
3678 wantErr: EM(errSkipMutation).withPos(`"hello"`, "").withType(0, T[bool]()),
3679 }, {
3680 name: jsontest.Name("Functions/Bool/V2/WrappedSkipError"),
3681 opts: []Options{
3682 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
3683 return fmt.Errorf("wrap: %w", SkipFunc)
3684 })),
3685 },
3686 in: true,
3687 wantErr: EM(fmt.Errorf("wrap: %w", SkipFunc)).withType(0, T[bool]()),
3688 }, {
3689 name: jsontest.Name("Functions/Map/Key/NoCaseString/V1"),
3690 opts: []Options{
3691 WithMarshalers(MarshalFunc(func(v nocaseString) ([]byte, error) {
3692 return []byte(`"called"`), nil
3693 })),
3694 },
3695 in: map[nocaseString]string{"hello": "world"},
3696 want: `{"called":"world"}`,
3697 }, {
3698 name: jsontest.Name("Functions/Map/Key/PointerNoCaseString/V1"),
3699 opts: []Options{
3700 WithMarshalers(MarshalFunc(func(v *nocaseString) ([]byte, error) {
3701 _ = *v
3702 return []byte(`"called"`), nil
3703 })),
3704 },
3705 in: map[nocaseString]string{"hello": "world"},
3706 want: `{"called":"world"}`,
3707 }, {
3708 name: jsontest.Name("Functions/Map/Key/TextMarshaler/V1"),
3709 opts: []Options{
3710 WithMarshalers(MarshalFunc(func(v encoding.TextMarshaler) ([]byte, error) {
3711 _ = *v.(*nocaseString)
3712 return []byte(`"called"`), nil
3713 })),
3714 },
3715 in: map[nocaseString]string{"hello": "world"},
3716 want: `{"called":"world"}`,
3717 }, {
3718 name: jsontest.Name("Functions/Map/Key/NoCaseString/V1/InvalidValue"),
3719 opts: []Options{
3720 WithMarshalers(MarshalFunc(func(v nocaseString) ([]byte, error) {
3721 return []byte(`null`), nil
3722 })),
3723 },
3724 in: map[nocaseString]string{"hello": "world"},
3725 want: `{`,
3726 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[nocaseString]()),
3727 }, {
3728 name: jsontest.Name("Functions/Map/Key/NoCaseString/V2/InvalidKind"),
3729 opts: []Options{
3730 WithMarshalers(MarshalFunc(func(v nocaseString) ([]byte, error) {
3731 return []byte(`null`), nil
3732 })),
3733 },
3734 in: map[nocaseString]string{"hello": "world"},
3735 want: `{`,
3736 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[nocaseString]()),
3737 }, {
3738 name: jsontest.Name("Functions/Map/Key/String/V1/DuplicateName"),
3739 opts: []Options{
3740 WithMarshalers(MarshalFunc(func(v string) ([]byte, error) {
3741 return []byte(`"name"`), nil
3742 })),
3743 },
3744 in: map[string]string{"name1": "value", "name2": "value"},
3745 want: `{"name":"name"`,
3746 wantErr: EM(newDuplicateNameError("", []byte(`"name"`), len64(`{"name":"name",`))).
3747 withPos(`{"name":"name",`, "").withType(0, T[string]()),
3748 }, {
3749 name: jsontest.Name("Functions/Map/Key/NoCaseString/V2"),
3750 opts: []Options{
3751 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v nocaseString) error {
3752 return enc.WriteValue([]byte(`"called"`))
3753 })),
3754 },
3755 in: map[nocaseString]string{"hello": "world"},
3756 want: `{"called":"world"}`,
3757 }, {
3758 name: jsontest.Name("Functions/Map/Key/PointerNoCaseString/V2"),
3759 opts: []Options{
3760 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v *nocaseString) error {
3761 _ = *v
3762 return enc.WriteValue([]byte(`"called"`))
3763 })),
3764 },
3765 in: map[nocaseString]string{"hello": "world"},
3766 want: `{"called":"world"}`,
3767 }, {
3768 name: jsontest.Name("Functions/Map/Key/TextMarshaler/V2"),
3769 opts: []Options{
3770 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v encoding.TextMarshaler) error {
3771 _ = *v.(*nocaseString)
3772 return enc.WriteValue([]byte(`"called"`))
3773 })),
3774 },
3775 in: map[nocaseString]string{"hello": "world"},
3776 want: `{"called":"world"}`,
3777 }, {
3778 name: jsontest.Name("Functions/Map/Key/NoCaseString/V2/InvalidToken"),
3779 opts: []Options{
3780 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v nocaseString) error {
3781 return enc.WriteToken(jsontext.Null)
3782 })),
3783 },
3784 in: map[nocaseString]string{"hello": "world"},
3785 want: `{`,
3786 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[nocaseString]()),
3787 }, {
3788 name: jsontest.Name("Functions/Map/Key/NoCaseString/V2/InvalidValue"),
3789 opts: []Options{
3790 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v nocaseString) error {
3791 return enc.WriteValue([]byte(`null`))
3792 })),
3793 },
3794 in: map[nocaseString]string{"hello": "world"},
3795 want: `{`,
3796 wantErr: EM(newNonStringNameError(len64(`{`), "")).withPos(`{`, "").withType(0, T[nocaseString]()),
3797 }, {
3798 name: jsontest.Name("Functions/Map/Value/NoCaseString/V1"),
3799 opts: []Options{
3800 WithMarshalers(MarshalFunc(func(v nocaseString) ([]byte, error) {
3801 return []byte(`"called"`), nil
3802 })),
3803 },
3804 in: map[string]nocaseString{"hello": "world"},
3805 want: `{"hello":"called"}`,
3806 }, {
3807 name: jsontest.Name("Functions/Map/Value/PointerNoCaseString/V1"),
3808 opts: []Options{
3809 WithMarshalers(MarshalFunc(func(v *nocaseString) ([]byte, error) {
3810 _ = *v
3811 return []byte(`"called"`), nil
3812 })),
3813 },
3814 in: map[string]nocaseString{"hello": "world"},
3815 want: `{"hello":"called"}`,
3816 }, {
3817 name: jsontest.Name("Functions/Map/Value/TextMarshaler/V1"),
3818 opts: []Options{
3819 WithMarshalers(MarshalFunc(func(v encoding.TextMarshaler) ([]byte, error) {
3820 _ = *v.(*nocaseString)
3821 return []byte(`"called"`), nil
3822 })),
3823 },
3824 in: map[string]nocaseString{"hello": "world"},
3825 want: `{"hello":"called"}`,
3826 }, {
3827 name: jsontest.Name("Functions/Map/Value/NoCaseString/V2"),
3828 opts: []Options{
3829 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v nocaseString) error {
3830 return enc.WriteValue([]byte(`"called"`))
3831 })),
3832 },
3833 in: map[string]nocaseString{"hello": "world"},
3834 want: `{"hello":"called"}`,
3835 }, {
3836 name: jsontest.Name("Functions/Map/Value/PointerNoCaseString/V2"),
3837 opts: []Options{
3838 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v *nocaseString) error {
3839 _ = *v
3840 return enc.WriteValue([]byte(`"called"`))
3841 })),
3842 },
3843 in: map[string]nocaseString{"hello": "world"},
3844 want: `{"hello":"called"}`,
3845 }, {
3846 name: jsontest.Name("Functions/Map/Value/TextMarshaler/V2"),
3847 opts: []Options{
3848 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v encoding.TextMarshaler) error {
3849 _ = *v.(*nocaseString)
3850 return enc.WriteValue([]byte(`"called"`))
3851 })),
3852 },
3853 in: map[string]nocaseString{"hello": "world"},
3854 want: `{"hello":"called"}`,
3855 }, {
3856 name: jsontest.Name("Funtions/Struct/Fields"),
3857 opts: []Options{
3858 WithMarshalers(JoinMarshalers(
3859 MarshalFunc(func(v bool) ([]byte, error) {
3860 return []byte(`"called1"`), nil
3861 }),
3862 MarshalFunc(func(v *string) ([]byte, error) {
3863 return []byte(`"called2"`), nil
3864 }),
3865 MarshalToFunc(func(enc *jsontext.Encoder, v []byte) error {
3866 return enc.WriteValue([]byte(`"called3"`))
3867 }),
3868 MarshalToFunc(func(enc *jsontext.Encoder, v *int64) error {
3869 return enc.WriteValue([]byte(`"called4"`))
3870 }),
3871 )),
3872 },
3873 in: structScalars{},
3874 want: `{"Bool":"called1","String":"called2","Bytes":"called3","Int":"called4","Uint":0,"Float":0}`,
3875 }, {
3876 name: jsontest.Name("Functions/Struct/OmitEmpty"),
3877 opts: []Options{
3878 WithMarshalers(JoinMarshalers(
3879 MarshalFunc(func(v bool) ([]byte, error) {
3880 return []byte(`null`), nil
3881 }),
3882 MarshalFunc(func(v string) ([]byte, error) {
3883 return []byte(`"called1"`), nil
3884 }),
3885 MarshalFunc(func(v *stringMarshalNonEmpty) ([]byte, error) {
3886 return []byte(`""`), nil
3887 }),
3888 MarshalToFunc(func(enc *jsontext.Encoder, v bytesMarshalNonEmpty) error {
3889 return enc.WriteValue([]byte(`{}`))
3890 }),
3891 MarshalToFunc(func(enc *jsontext.Encoder, v *float64) error {
3892 return enc.WriteValue([]byte(`[]`))
3893 }),
3894 MarshalFunc(func(v mapMarshalNonEmpty) ([]byte, error) {
3895 return []byte(`"called2"`), nil
3896 }),
3897 MarshalFunc(func(v []string) ([]byte, error) {
3898 return []byte(`"called3"`), nil
3899 }),
3900 MarshalToFunc(func(enc *jsontext.Encoder, v *sliceMarshalNonEmpty) error {
3901 return enc.WriteValue([]byte(`"called4"`))
3902 }),
3903 )),
3904 },
3905 in: structOmitEmptyAll{},
3906 want: `{"String":"called1","MapNonEmpty":"called2","Slice":"called3","SliceNonEmpty":"called4"}`,
3907 }, {
3908 name: jsontest.Name("Functions/Struct/OmitZero"),
3909 opts: []Options{
3910 WithMarshalers(JoinMarshalers(
3911 MarshalFunc(func(v bool) ([]byte, error) {
3912 panic("should not be called")
3913 }),
3914 MarshalFunc(func(v *string) ([]byte, error) {
3915 panic("should not be called")
3916 }),
3917 MarshalToFunc(func(enc *jsontext.Encoder, v []byte) error {
3918 panic("should not be called")
3919 }),
3920 MarshalToFunc(func(enc *jsontext.Encoder, v *int64) error {
3921 panic("should not be called")
3922 }),
3923 )),
3924 },
3925 in: structOmitZeroAll{},
3926 want: `{}`,
3927 }, {
3928 name: jsontest.Name("Functions/Struct/Inlined"),
3929 opts: []Options{
3930 WithMarshalers(JoinMarshalers(
3931 MarshalFunc(func(v structInlinedL1) ([]byte, error) {
3932 panic("should not be called")
3933 }),
3934 MarshalToFunc(func(enc *jsontext.Encoder, v *StructEmbed2) error {
3935 panic("should not be called")
3936 }),
3937 )),
3938 },
3939 in: structInlined{},
3940 want: `{"D":""}`,
3941 }, {
3942 name: jsontest.Name("Functions/Slice/Elem"),
3943 opts: []Options{
3944 WithMarshalers(MarshalFunc(func(v bool) ([]byte, error) {
3945 return []byte(`"` + strconv.FormatBool(v) + `"`), nil
3946 })),
3947 },
3948 in: []bool{true, false},
3949 want: `["true","false"]`,
3950 }, {
3951 name: jsontest.Name("Functions/Array/Elem"),
3952 opts: []Options{
3953 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v *bool) error {
3954 return enc.WriteValue([]byte(`"` + strconv.FormatBool(*v) + `"`))
3955 })),
3956 },
3957 in: [2]bool{true, false},
3958 want: `["true","false"]`,
3959 }, {
3960 name: jsontest.Name("Functions/Pointer/Nil"),
3961 opts: []Options{
3962 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v *bool) error {
3963 panic("should not be called")
3964 })),
3965 },
3966 in: struct{ X *bool }{nil},
3967 want: `{"X":null}`,
3968 }, {
3969 name: jsontest.Name("Functions/Pointer/NonNil"),
3970 opts: []Options{
3971 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v *bool) error {
3972 return enc.WriteValue([]byte(`"called"`))
3973 })),
3974 },
3975 in: struct{ X *bool }{addr(false)},
3976 want: `{"X":"called"}`,
3977 }, {
3978 name: jsontest.Name("Functions/Interface/Nil"),
3979 opts: []Options{
3980 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v fmt.Stringer) error {
3981 panic("should not be called")
3982 })),
3983 },
3984 in: struct{ X fmt.Stringer }{nil},
3985 want: `{"X":null}`,
3986 }, {
3987 name: jsontest.Name("Functions/Interface/NonNil/MatchInterface"),
3988 opts: []Options{
3989 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v fmt.Stringer) error {
3990 return enc.WriteValue([]byte(`"called"`))
3991 })),
3992 },
3993 in: struct{ X fmt.Stringer }{valueStringer{}},
3994 want: `{"X":"called"}`,
3995 }, {
3996 name: jsontest.Name("Functions/Interface/NonNil/MatchConcrete"),
3997 opts: []Options{
3998 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v valueStringer) error {
3999 return enc.WriteValue([]byte(`"called"`))
4000 })),
4001 },
4002 in: struct{ X fmt.Stringer }{valueStringer{}},
4003 want: `{"X":"called"}`,
4004 }, {
4005 name: jsontest.Name("Functions/Interface/NonNil/MatchPointer"),
4006 opts: []Options{
4007 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, v *valueStringer) error {
4008 return enc.WriteValue([]byte(`"called"`))
4009 })),
4010 },
4011 in: struct{ X fmt.Stringer }{valueStringer{}},
4012 want: `{"X":"called"}`,
4013 }, {
4014 name: jsontest.Name("Functions/Interface/Any"),
4015 in: []any{
4016 nil,
4017 valueStringer{},
4018 (*valueStringer)(nil),
4019 addr(valueStringer{}),
4020 (**valueStringer)(nil),
4021 addr((*valueStringer)(nil)),
4022 addr(addr(valueStringer{})),
4023 pointerStringer{},
4024 (*pointerStringer)(nil),
4025 addr(pointerStringer{}),
4026 (**pointerStringer)(nil),
4027 addr((*pointerStringer)(nil)),
4028 addr(addr(pointerStringer{})),
4029 "LAST",
4030 },
4031 want: `[null,{},null,{},null,null,{},{},null,{},null,null,{},"LAST"]`,
4032 opts: []Options{
4033 WithMarshalers(func() *Marshalers {
4034 type P struct {
4035 D int
4036 N int64
4037 }
4038 type PV struct {
4039 P P
4040 V any
4041 }
4042
4043 var lastChecks []func() error
4044 checkLast := func() error {
4045 for _, fn := range lastChecks {
4046 if err := fn(); err != nil {
4047 return err
4048 }
4049 }
4050 return SkipFunc
4051 }
4052 makeValueChecker := func(name string, want []PV) func(e *jsontext.Encoder, v any) error {
4053 checkNext := func(e *jsontext.Encoder, v any) error {
4054 xe := export.Encoder(e)
4055 p := P{len(xe.Tokens.Stack), xe.Tokens.Last.Length()}
4056 rv := reflect.ValueOf(v)
4057 pv := PV{p, v}
4058 switch {
4059 case len(want) == 0:
4060 return fmt.Errorf("%s: %v: got more values than expected", name, p)
4061 case !rv.IsValid() || rv.Kind() != reflect.Pointer || rv.IsNil():
4062 return fmt.Errorf("%s: %v: got %#v, want non-nil pointer type", name, p, v)
4063 case !reflect.DeepEqual(pv, want[0]):
4064 return fmt.Errorf("%s:\n\tgot %#v\n\twant %#v", name, pv, want[0])
4065 default:
4066 want = want[1:]
4067 return SkipFunc
4068 }
4069 }
4070 lastChecks = append(lastChecks, func() error {
4071 if len(want) > 0 {
4072 return fmt.Errorf("%s: did not get enough values, want %d more", name, len(want))
4073 }
4074 return nil
4075 })
4076 return checkNext
4077 }
4078 makePositionChecker := func(name string, want []P) func(e *jsontext.Encoder, v any) error {
4079 checkNext := func(e *jsontext.Encoder, v any) error {
4080 xe := export.Encoder(e)
4081 p := P{len(xe.Tokens.Stack), xe.Tokens.Last.Length()}
4082 switch {
4083 case len(want) == 0:
4084 return fmt.Errorf("%s: %v: got more values than wanted", name, p)
4085 case p != want[0]:
4086 return fmt.Errorf("%s: got %v, want %v", name, p, want[0])
4087 default:
4088 want = want[1:]
4089 return SkipFunc
4090 }
4091 }
4092 lastChecks = append(lastChecks, func() error {
4093 if len(want) > 0 {
4094 return fmt.Errorf("%s: did not get enough values, want %d more", name, len(want))
4095 }
4096 return nil
4097 })
4098 return checkNext
4099 }
4100
4101 wantAny := []PV{
4102 {P{0, 0}, addr([]any{
4103 nil,
4104 valueStringer{},
4105 (*valueStringer)(nil),
4106 addr(valueStringer{}),
4107 (**valueStringer)(nil),
4108 addr((*valueStringer)(nil)),
4109 addr(addr(valueStringer{})),
4110 pointerStringer{},
4111 (*pointerStringer)(nil),
4112 addr(pointerStringer{}),
4113 (**pointerStringer)(nil),
4114 addr((*pointerStringer)(nil)),
4115 addr(addr(pointerStringer{})),
4116 "LAST",
4117 })},
4118 {P{1, 0}, addr(any(nil))},
4119 {P{1, 1}, addr(any(valueStringer{}))},
4120 {P{1, 1}, addr(valueStringer{})},
4121 {P{1, 2}, addr(any((*valueStringer)(nil)))},
4122 {P{1, 2}, addr((*valueStringer)(nil))},
4123 {P{1, 3}, addr(any(addr(valueStringer{})))},
4124 {P{1, 3}, addr(addr(valueStringer{}))},
4125 {P{1, 3}, addr(valueStringer{})},
4126 {P{1, 4}, addr(any((**valueStringer)(nil)))},
4127 {P{1, 4}, addr((**valueStringer)(nil))},
4128 {P{1, 5}, addr(any(addr((*valueStringer)(nil))))},
4129 {P{1, 5}, addr(addr((*valueStringer)(nil)))},
4130 {P{1, 5}, addr((*valueStringer)(nil))},
4131 {P{1, 6}, addr(any(addr(addr(valueStringer{}))))},
4132 {P{1, 6}, addr(addr(addr(valueStringer{})))},
4133 {P{1, 6}, addr(addr(valueStringer{}))},
4134 {P{1, 6}, addr(valueStringer{})},
4135 {P{1, 7}, addr(any(pointerStringer{}))},
4136 {P{1, 7}, addr(pointerStringer{})},
4137 {P{1, 8}, addr(any((*pointerStringer)(nil)))},
4138 {P{1, 8}, addr((*pointerStringer)(nil))},
4139 {P{1, 9}, addr(any(addr(pointerStringer{})))},
4140 {P{1, 9}, addr(addr(pointerStringer{}))},
4141 {P{1, 9}, addr(pointerStringer{})},
4142 {P{1, 10}, addr(any((**pointerStringer)(nil)))},
4143 {P{1, 10}, addr((**pointerStringer)(nil))},
4144 {P{1, 11}, addr(any(addr((*pointerStringer)(nil))))},
4145 {P{1, 11}, addr(addr((*pointerStringer)(nil)))},
4146 {P{1, 11}, addr((*pointerStringer)(nil))},
4147 {P{1, 12}, addr(any(addr(addr(pointerStringer{}))))},
4148 {P{1, 12}, addr(addr(addr(pointerStringer{})))},
4149 {P{1, 12}, addr(addr(pointerStringer{}))},
4150 {P{1, 12}, addr(pointerStringer{})},
4151 {P{1, 13}, addr(any("LAST"))},
4152 {P{1, 13}, addr("LAST")},
4153 }
4154 checkAny := makeValueChecker("any", wantAny)
4155 anyMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v any) error {
4156 return checkAny(enc, v)
4157 })
4158
4159 var wantPointerAny []PV
4160 for _, v := range wantAny {
4161 if _, ok := v.V.(*any); ok {
4162 wantPointerAny = append(wantPointerAny, v)
4163 }
4164 }
4165 checkPointerAny := makeValueChecker("*any", wantPointerAny)
4166 pointerAnyMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v *any) error {
4167 return checkPointerAny(enc, v)
4168 })
4169
4170 checkNamedAny := makeValueChecker("namedAny", wantAny)
4171 namedAnyMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v namedAny) error {
4172 return checkNamedAny(enc, v)
4173 })
4174
4175 checkPointerNamedAny := makeValueChecker("*namedAny", nil)
4176 pointerNamedAnyMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v *namedAny) error {
4177 return checkPointerNamedAny(enc, v)
4178 })
4179
4180 type stringer = fmt.Stringer
4181 var wantStringer []PV
4182 for _, v := range wantAny {
4183 if _, ok := v.V.(stringer); ok {
4184 wantStringer = append(wantStringer, v)
4185 }
4186 }
4187 checkStringer := makeValueChecker("stringer", wantStringer)
4188 stringerMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v stringer) error {
4189 return checkStringer(enc, v)
4190 })
4191
4192 checkPointerStringer := makeValueChecker("*stringer", nil)
4193 pointerStringerMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v *stringer) error {
4194 return checkPointerStringer(enc, v)
4195 })
4196
4197 wantValueStringer := []P{{1, 1}, {1, 3}, {1, 6}}
4198 checkValueValueStringer := makePositionChecker("valueStringer", wantValueStringer)
4199 valueValueStringerMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v valueStringer) error {
4200 return checkValueValueStringer(enc, v)
4201 })
4202
4203 checkPointerValueStringer := makePositionChecker("*valueStringer", wantValueStringer)
4204 pointerValueStringerMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v *valueStringer) error {
4205 return checkPointerValueStringer(enc, v)
4206 })
4207
4208 wantPointerStringer := []P{{1, 7}, {1, 9}, {1, 12}}
4209 checkValuePointerStringer := makePositionChecker("pointerStringer", wantPointerStringer)
4210 valuePointerStringerMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v pointerStringer) error {
4211 return checkValuePointerStringer(enc, v)
4212 })
4213
4214 checkPointerPointerStringer := makePositionChecker("*pointerStringer", wantPointerStringer)
4215 pointerPointerStringerMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v *pointerStringer) error {
4216 return checkPointerPointerStringer(enc, v)
4217 })
4218
4219 lastMarshaler := MarshalToFunc(func(enc *jsontext.Encoder, v string) error {
4220 return checkLast()
4221 })
4222
4223 return JoinMarshalers(
4224 anyMarshaler,
4225 pointerAnyMarshaler,
4226 namedAnyMarshaler,
4227 pointerNamedAnyMarshaler,
4228 stringerMarshaler,
4229 pointerStringerMarshaler,
4230 valueValueStringerMarshaler,
4231 pointerValueStringerMarshaler,
4232 valuePointerStringerMarshaler,
4233 pointerPointerStringerMarshaler,
4234 lastMarshaler,
4235 )
4236 }()),
4237 },
4238 }, {
4239 name: jsontest.Name("Functions/Precedence/V1First"),
4240 opts: []Options{
4241 WithMarshalers(JoinMarshalers(
4242 MarshalFunc(func(bool) ([]byte, error) {
4243 return []byte(`"called"`), nil
4244 }),
4245 MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
4246 panic("should not be called")
4247 }),
4248 )),
4249 },
4250 in: true,
4251 want: `"called"`,
4252 }, {
4253 name: jsontest.Name("Functions/Precedence/V2First"),
4254 opts: []Options{
4255 WithMarshalers(JoinMarshalers(
4256 MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
4257 return enc.WriteToken(jsontext.String("called"))
4258 }),
4259 MarshalFunc(func(bool) ([]byte, error) {
4260 panic("should not be called")
4261 }),
4262 )),
4263 },
4264 in: true,
4265 want: `"called"`,
4266 }, {
4267 name: jsontest.Name("Functions/Precedence/V2Skipped"),
4268 opts: []Options{
4269 WithMarshalers(JoinMarshalers(
4270 MarshalToFunc(func(enc *jsontext.Encoder, v bool) error {
4271 return SkipFunc
4272 }),
4273 MarshalFunc(func(bool) ([]byte, error) {
4274 return []byte(`"called"`), nil
4275 }),
4276 )),
4277 },
4278 in: true,
4279 want: `"called"`,
4280 }, {
4281 name: jsontest.Name("Functions/Precedence/NestedFirst"),
4282 opts: []Options{
4283 WithMarshalers(JoinMarshalers(
4284 JoinMarshalers(
4285 MarshalFunc(func(bool) ([]byte, error) {
4286 return []byte(`"called"`), nil
4287 }),
4288 ),
4289 MarshalFunc(func(bool) ([]byte, error) {
4290 panic("should not be called")
4291 }),
4292 )),
4293 },
4294 in: true,
4295 want: `"called"`,
4296 }, {
4297 name: jsontest.Name("Functions/Precedence/NestedLast"),
4298 opts: []Options{
4299 WithMarshalers(JoinMarshalers(
4300 MarshalFunc(func(bool) ([]byte, error) {
4301 return []byte(`"called"`), nil
4302 }),
4303 JoinMarshalers(
4304 MarshalFunc(func(bool) ([]byte, error) {
4305 panic("should not be called")
4306 }),
4307 ),
4308 )),
4309 },
4310 in: true,
4311 want: `"called"`,
4312 }, {
4313 name: jsontest.Name("Duration/Zero"),
4314 in: struct {
4315 D1 time.Duration
4316 D2 time.Duration `json:",format:nano"`
4317 }{0, 0},
4318 want: `{"D1":"0s","D2":0}`,
4319 }, {
4320 name: jsontest.Name("Duration/Positive"),
4321 in: struct {
4322 D1 time.Duration
4323 D2 time.Duration `json:",format:nano"`
4324 }{
4325 123456789123456789,
4326 123456789123456789,
4327 },
4328 want: `{"D1":"34293h33m9.123456789s","D2":123456789123456789}`,
4329 }, {
4330 name: jsontest.Name("Duration/Negative"),
4331 in: struct {
4332 D1 time.Duration
4333 D2 time.Duration `json:",format:nano"`
4334 }{
4335 -123456789123456789,
4336 -123456789123456789,
4337 },
4338 want: `{"D1":"-34293h33m9.123456789s","D2":-123456789123456789}`,
4339 }, {
4340 name: jsontest.Name("Duration/Nanos/String"),
4341 in: struct {
4342 D1 time.Duration `json:",string,format:nano"`
4343 D2 time.Duration `json:",string,format:nano"`
4344 D3 time.Duration `json:",string,format:nano"`
4345 }{
4346 math.MinInt64,
4347 0,
4348 math.MaxInt64,
4349 },
4350 want: `{"D1":"-9223372036854775808","D2":"0","D3":"9223372036854775807"}`,
4351 }, {
4352 name: jsontest.Name("Duration/Format/Invalid"),
4353 in: struct {
4354 D time.Duration `json:",format:invalid"`
4355 }{},
4356 want: `{"D"`,
4357 wantErr: EM(errInvalidFormatFlag).withPos(`{"D":`, "/D").withType(0, T[time.Duration]()),
4358 }, {
4359 name: jsontest.Name("Duration/IgnoreInvalidFormat"),
4360 opts: []Options{invalidFormatOption},
4361 in: time.Duration(0),
4362 want: `"0s"`,
4363 }, {
4364 name: jsontest.Name("Duration/Format"),
4365 opts: []Options{jsontext.Multiline(true)},
4366 in: structDurationFormat{
4367 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4368 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4369 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4370 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4371 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4372 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4373 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4374 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4375 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4376 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4377 },
4378 want: `{
4379 "D1": "12h34m56.078090012s",
4380 "D2": "12h34m56.078090012s",
4381 "D3": 45296.078090012,
4382 "D4": "45296.078090012",
4383 "D5": 45296078.090012,
4384 "D6": "45296078.090012",
4385 "D7": 45296078090.012,
4386 "D8": "45296078090.012",
4387 "D9": 45296078090012,
4388 "D10": "45296078090012"
4389 }`,
4390 }, {
4391 name: jsontest.Name("Duration/Format/Legacy"),
4392 opts: []Options{jsonflags.FormatTimeWithLegacySemantics | 1},
4393 in: structDurationFormat{
4394 D1: 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4395 D2: 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
4396 },
4397 want: `{"D1":45296078090012,"D2":"12h34m56.078090012s","D3":0,"D4":"0","D5":0,"D6":"0","D7":0,"D8":"0","D9":0,"D10":"0"}`,
4398 }, {
4399 name: jsontest.Name("Duration/MapKey"),
4400 in: map[time.Duration]string{time.Second: ""},
4401 want: `{"1s":""}`,
4402 }, {
4403 name: jsontest.Name("Duration/MapKey/Legacy"),
4404 opts: []Options{jsonflags.FormatTimeWithLegacySemantics | 1},
4405 in: map[time.Duration]string{time.Second: ""},
4406 want: `{"1000000000":""}`,
4407 }, {
4408 name: jsontest.Name("Time/Zero"),
4409 in: struct {
4410 T1 time.Time
4411 T2 time.Time `json:",format:RFC822"`
4412 T3 time.Time `json:",format:'2006-01-02'"`
4413 T4 time.Time `json:",omitzero"`
4414 T5 time.Time `json:",omitempty"`
4415 }{
4416 time.Time{},
4417 time.Time{},
4418 time.Time{},
4419
4420
4421 time.Date(1, 1, 1, 0, 0, 0, 0, time.FixedZone("UTC", 0)),
4422 time.Time{},
4423 },
4424 want: `{"T1":"0001-01-01T00:00:00Z","T2":"01 Jan 01 00:00 UTC","T3":"0001-01-01","T5":"0001-01-01T00:00:00Z"}`,
4425 }, {
4426 name: jsontest.Name("Time/Format"),
4427 opts: []Options{jsontext.Multiline(true)},
4428 in: structTimeFormat{
4429 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4430 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4431 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4432 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4433 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4434 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4435 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4436 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4437 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4438 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4439 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4440 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4441 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4442 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4443 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4444 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4445 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4446 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4447 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4448 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4449 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4450 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4451 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4452 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4453 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4454 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4455 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4456 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4457 time.Date(1234, 1, 2, 3, 4, 5, 6, time.UTC),
4458 },
4459 want: `{
4460 "T1": "1234-01-02T03:04:05.000000006Z",
4461 "T2": "Mon Jan 2 03:04:05 1234",
4462 "T3": "Mon Jan 2 03:04:05 UTC 1234",
4463 "T4": "Mon Jan 02 03:04:05 +0000 1234",
4464 "T5": "02 Jan 34 03:04 UTC",
4465 "T6": "02 Jan 34 03:04 +0000",
4466 "T7": "Monday, 02-Jan-34 03:04:05 UTC",
4467 "T8": "Mon, 02 Jan 1234 03:04:05 UTC",
4468 "T9": "Mon, 02 Jan 1234 03:04:05 +0000",
4469 "T10": "1234-01-02T03:04:05Z",
4470 "T11": "1234-01-02T03:04:05.000000006Z",
4471 "T12": "3:04AM",
4472 "T13": "Jan 2 03:04:05",
4473 "T14": "Jan 2 03:04:05.000",
4474 "T15": "Jan 2 03:04:05.000000",
4475 "T16": "Jan 2 03:04:05.000000006",
4476 "T17": "1234-01-02 03:04:05",
4477 "T18": "1234-01-02",
4478 "T19": "03:04:05",
4479 "T20": "1234-01-02",
4480 "T21": "\"weird\"1234",
4481 "T22": -23225777754.999999994,
4482 "T23": "-23225777754.999999994",
4483 "T24": -23225777754999.999994,
4484 "T25": "-23225777754999.999994",
4485 "T26": -23225777754999999.994,
4486 "T27": "-23225777754999999.994",
4487 "T28": -23225777754999999994,
4488 "T29": "-23225777754999999994"
4489 }`,
4490 }, {
4491 name: jsontest.Name("Time/Format/Invalid"),
4492 in: struct {
4493 T time.Time `json:",format:UndefinedConstant"`
4494 }{},
4495 want: `{"T"`,
4496 wantErr: EM(errors.New(`invalid format flag "UndefinedConstant"`)).withPos(`{"T":`, "/T").withType(0, timeTimeType),
4497 }, {
4498 name: jsontest.Name("Time/Format/YearOverflow"),
4499 in: struct {
4500 T1 time.Time
4501 T2 time.Time
4502 }{
4503 time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC).Add(-time.Second),
4504 time.Date(10000, 1, 1, 0, 0, 0, 0, time.UTC),
4505 },
4506 want: `{"T1":"9999-12-31T23:59:59Z","T2"`,
4507 wantErr: EM(errors.New(`year outside of range [0,9999]`)).withPos(`{"T1":"9999-12-31T23:59:59Z","T2":`, "/T2").withType(0, timeTimeType),
4508 }, {
4509 name: jsontest.Name("Time/Format/YearUnderflow"),
4510 in: struct {
4511 T1 time.Time
4512 T2 time.Time
4513 }{
4514 time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC),
4515 time.Date(0, 1, 1, 0, 0, 0, 0, time.UTC).Add(-time.Second),
4516 },
4517 want: `{"T1":"0000-01-01T00:00:00Z","T2"`,
4518 wantErr: EM(errors.New(`year outside of range [0,9999]`)).withPos(`{"T1":"0000-01-01T00:00:00Z","T2":`, "/T2").withType(0, timeTimeType),
4519 }, {
4520 name: jsontest.Name("Time/Format/YearUnderflow"),
4521 in: struct{ T time.Time }{time.Date(-998, 1, 1, 0, 0, 0, 0, time.UTC).Add(-time.Second)},
4522 want: `{"T"`,
4523 wantErr: EM(errors.New(`year outside of range [0,9999]`)).withPos(`{"T":`, "/T").withType(0, timeTimeType),
4524 }, {
4525 name: jsontest.Name("Time/Format/ZoneExact"),
4526 in: struct{ T time.Time }{time.Date(2020, 1, 1, 0, 0, 0, 0, time.FixedZone("", 23*60*60+59*60))},
4527 want: `{"T":"2020-01-01T00:00:00+23:59"}`,
4528 }, {
4529 name: jsontest.Name("Time/Format/ZoneHourOverflow"),
4530 in: struct{ T time.Time }{time.Date(2020, 1, 1, 0, 0, 0, 0, time.FixedZone("", 24*60*60))},
4531 want: `{"T"`,
4532 wantErr: EM(errors.New(`timezone hour outside of range [0,23]`)).withPos(`{"T":`, "/T").withType(0, timeTimeType),
4533 }, {
4534 name: jsontest.Name("Time/Format/ZoneHourOverflow"),
4535 in: struct{ T time.Time }{time.Date(2020, 1, 1, 0, 0, 0, 0, time.FixedZone("", 123*60*60))},
4536 want: `{"T"`,
4537 wantErr: EM(errors.New(`timezone hour outside of range [0,23]`)).withPos(`{"T":`, "/T").withType(0, timeTimeType),
4538 }, {
4539 name: jsontest.Name("Time/IgnoreInvalidFormat"),
4540 opts: []Options{invalidFormatOption},
4541 in: time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC),
4542 want: `"2000-01-01T00:00:00Z"`,
4543 }}
4544
4545 for _, tt := range tests {
4546 t.Run(tt.name.Name, func(t *testing.T) {
4547 var got []byte
4548 var gotErr error
4549 if tt.useWriter {
4550 bb := new(struct{ bytes.Buffer })
4551 gotErr = MarshalWrite(bb, tt.in, tt.opts...)
4552 got = bb.Bytes()
4553 } else {
4554 got, gotErr = Marshal(tt.in, tt.opts...)
4555 }
4556 if tt.canonicalize {
4557 (*jsontext.Value)(&got).Canonicalize()
4558 }
4559 if string(got) != tt.want {
4560 t.Errorf("%s: Marshal output mismatch:\ngot %s\nwant %s", tt.name.Where, got, tt.want)
4561 }
4562 if !reflect.DeepEqual(gotErr, tt.wantErr) {
4563 t.Errorf("%s: Marshal error mismatch:\ngot %v\nwant %v", tt.name.Where, gotErr, tt.wantErr)
4564 }
4565 })
4566 }
4567 }
4568
4569 func TestUnmarshal(t *testing.T) {
4570 tests := []struct {
4571 name jsontest.CaseName
4572 opts []Options
4573 inBuf string
4574 inVal any
4575 want any
4576 wantErr error
4577 }{{
4578 name: jsontest.Name("Nil"),
4579 inBuf: `null`,
4580 wantErr: EU(internal.ErrNonNilReference),
4581 }, {
4582 name: jsontest.Name("NilPointer"),
4583 inBuf: `null`,
4584 inVal: (*string)(nil),
4585 want: (*string)(nil),
4586 wantErr: EU(internal.ErrNonNilReference).withType(0, T[*string]()),
4587 }, {
4588 name: jsontest.Name("NonPointer"),
4589 inBuf: `null`,
4590 inVal: "unchanged",
4591 want: "unchanged",
4592 wantErr: EU(internal.ErrNonNilReference).withType(0, T[string]()),
4593 }, {
4594 name: jsontest.Name("Bools/TrailingJunk"),
4595 inBuf: `falsetrue`,
4596 inVal: addr(true),
4597 want: addr(false),
4598 wantErr: newInvalidCharacterError("t", "after top-level value", len64(`false`), ""),
4599 }, {
4600 name: jsontest.Name("Bools/Null"),
4601 inBuf: `null`,
4602 inVal: addr(true),
4603 want: addr(false),
4604 }, {
4605 name: jsontest.Name("Bools"),
4606 inBuf: `[null,false,true]`,
4607 inVal: new([]bool),
4608 want: addr([]bool{false, false, true}),
4609 }, {
4610 name: jsontest.Name("Bools/Named"),
4611 inBuf: `[null,false,true]`,
4612 inVal: new([]namedBool),
4613 want: addr([]namedBool{false, false, true}),
4614 }, {
4615 name: jsontest.Name("Bools/Invalid/StringifiedFalse"),
4616 opts: []Options{StringifyNumbers(true)},
4617 inBuf: `"false"`,
4618 inVal: addr(true),
4619 want: addr(true),
4620 wantErr: EU(nil).withType('"', boolType),
4621 }, {
4622 name: jsontest.Name("Bools/Invalid/StringifiedTrue"),
4623 opts: []Options{StringifyNumbers(true)},
4624 inBuf: `"true"`,
4625 inVal: addr(true),
4626 want: addr(true),
4627 wantErr: EU(nil).withType('"', boolType),
4628 }, {
4629 name: jsontest.Name("Bools/StringifiedBool/True"),
4630 opts: []Options{jsonflags.StringifyBoolsAndStrings | 1},
4631 inBuf: `"true"`,
4632 inVal: addr(false),
4633 want: addr(true),
4634 }, {
4635 name: jsontest.Name("Bools/StringifiedBool/False"),
4636 opts: []Options{jsonflags.StringifyBoolsAndStrings | 1},
4637 inBuf: `"false"`,
4638 inVal: addr(true),
4639 want: addr(false),
4640 }, {
4641 name: jsontest.Name("Bools/StringifiedBool/InvalidWhitespace"),
4642 opts: []Options{jsonflags.StringifyBoolsAndStrings | 1},
4643 inBuf: `"false "`,
4644 inVal: addr(true),
4645 want: addr(true),
4646 wantErr: EU(strconv.ErrSyntax).withVal(`"false "`).withType('"', boolType),
4647 }, {
4648 name: jsontest.Name("Bools/StringifiedBool/InvalidBool"),
4649 opts: []Options{jsonflags.StringifyBoolsAndStrings | 1},
4650 inBuf: `false`,
4651 inVal: addr(true),
4652 want: addr(true),
4653 wantErr: EU(nil).withType('f', boolType),
4654 }, {
4655 name: jsontest.Name("Bools/Invalid/Number"),
4656 inBuf: `0`,
4657 inVal: addr(true),
4658 want: addr(true),
4659 wantErr: EU(nil).withType('0', boolType),
4660 }, {
4661 name: jsontest.Name("Bools/Invalid/String"),
4662 inBuf: `""`,
4663 inVal: addr(true),
4664 want: addr(true),
4665 wantErr: EU(nil).withType('"', boolType),
4666 }, {
4667 name: jsontest.Name("Bools/Invalid/Object"),
4668 inBuf: `{}`,
4669 inVal: addr(true),
4670 want: addr(true),
4671 wantErr: EU(nil).withType('{', boolType),
4672 }, {
4673 name: jsontest.Name("Bools/Invalid/Array"),
4674 inBuf: `[]`,
4675 inVal: addr(true),
4676 want: addr(true),
4677 wantErr: EU(nil).withType('[', boolType),
4678 }, {
4679 name: jsontest.Name("Bools/IgnoreInvalidFormat"),
4680 opts: []Options{invalidFormatOption},
4681 inBuf: `false`,
4682 inVal: addr(true),
4683 want: addr(false),
4684 }, {
4685 name: jsontest.Name("Strings/Null"),
4686 inBuf: `null`,
4687 inVal: addr("something"),
4688 want: addr(""),
4689 }, {
4690 name: jsontest.Name("Strings"),
4691 inBuf: `[null,"","hello","世界"]`,
4692 inVal: new([]string),
4693 want: addr([]string{"", "", "hello", "世界"}),
4694 }, {
4695 name: jsontest.Name("Strings/Escaped"),
4696 inBuf: `[null,"","\u0068\u0065\u006c\u006c\u006f","\u4e16\u754c"]`,
4697 inVal: new([]string),
4698 want: addr([]string{"", "", "hello", "世界"}),
4699 }, {
4700 name: jsontest.Name("Strings/Named"),
4701 inBuf: `[null,"","hello","世界"]`,
4702 inVal: new([]namedString),
4703 want: addr([]namedString{"", "", "hello", "世界"}),
4704 }, {
4705 name: jsontest.Name("Strings/Invalid/False"),
4706 inBuf: `false`,
4707 inVal: addr("nochange"),
4708 want: addr("nochange"),
4709 wantErr: EU(nil).withType('f', stringType),
4710 }, {
4711 name: jsontest.Name("Strings/Invalid/True"),
4712 inBuf: `true`,
4713 inVal: addr("nochange"),
4714 want: addr("nochange"),
4715 wantErr: EU(nil).withType('t', stringType),
4716 }, {
4717 name: jsontest.Name("Strings/Invalid/Object"),
4718 inBuf: `{}`,
4719 inVal: addr("nochange"),
4720 want: addr("nochange"),
4721 wantErr: EU(nil).withType('{', stringType),
4722 }, {
4723 name: jsontest.Name("Strings/Invalid/Array"),
4724 inBuf: `[]`,
4725 inVal: addr("nochange"),
4726 want: addr("nochange"),
4727 wantErr: EU(nil).withType('[', stringType),
4728 }, {
4729 name: jsontest.Name("Strings/IgnoreInvalidFormat"),
4730 opts: []Options{invalidFormatOption},
4731 inBuf: `"hello"`,
4732 inVal: addr("goodbye"),
4733 want: addr("hello"),
4734 }, {
4735 name: jsontest.Name("Strings/StringifiedString"),
4736 opts: []Options{jsonflags.StringifyBoolsAndStrings | 1},
4737 inBuf: `"\"foo\""`,
4738 inVal: new(string),
4739 want: addr("foo"),
4740 }, {
4741 name: jsontest.Name("Strings/StringifiedString/InvalidWhitespace"),
4742 opts: []Options{jsonflags.StringifyBoolsAndStrings | 1},
4743 inBuf: `"\"foo\" "`,
4744 inVal: new(string),
4745 want: new(string),
4746 wantErr: EU(newInvalidCharacterError(" ", "after string value", 0, "")).withType('"', stringType),
4747 }, {
4748 name: jsontest.Name("Strings/StringifiedString/InvalidString"),
4749 opts: []Options{jsonflags.StringifyBoolsAndStrings | 1},
4750 inBuf: `""`,
4751 inVal: new(string),
4752 want: new(string),
4753 wantErr: EU(&jsontext.SyntacticError{Err: io.ErrUnexpectedEOF}).withType('"', stringType),
4754 }, {
4755 name: jsontest.Name("Bytes/Null"),
4756 inBuf: `null`,
4757 inVal: addr([]byte("something")),
4758 want: addr([]byte(nil)),
4759 }, {
4760 name: jsontest.Name("Bytes"),
4761 inBuf: `[null,"","AQ==","AQI=","AQID"]`,
4762 inVal: new([][]byte),
4763 want: addr([][]byte{nil, {}, {1}, {1, 2}, {1, 2, 3}}),
4764 }, {
4765 name: jsontest.Name("Bytes/Large"),
4766 inBuf: `"dGhlIHF1aWNrIGJyb3duIGZveCBqdW1wZWQgb3ZlciB0aGUgbGF6eSBkb2cgYW5kIGF0ZSB0aGUgaG9tZXdvcmsgdGhhdCBJIHNwZW50IHNvIG11Y2ggdGltZSBvbi4="`,
4767 inVal: new([]byte),
4768 want: addr([]byte("the quick brown fox jumped over the lazy dog and ate the homework that I spent so much time on.")),
4769 }, {
4770 name: jsontest.Name("Bytes/Reuse"),
4771 inBuf: `"AQID"`,
4772 inVal: addr([]byte("changed")),
4773 want: addr([]byte{1, 2, 3}),
4774 }, {
4775 name: jsontest.Name("Bytes/Escaped"),
4776 inBuf: `[null,"","\u0041\u0051\u003d\u003d","\u0041\u0051\u0049\u003d","\u0041\u0051\u0049\u0044"]`,
4777 inVal: new([][]byte),
4778 want: addr([][]byte{nil, {}, {1}, {1, 2}, {1, 2, 3}}),
4779 }, {
4780 name: jsontest.Name("Bytes/Named"),
4781 inBuf: `[null,"","AQ==","AQI=","AQID"]`,
4782 inVal: new([]namedBytes),
4783 want: addr([]namedBytes{nil, {}, {1}, {1, 2}, {1, 2, 3}}),
4784 }, {
4785 name: jsontest.Name("Bytes/NotStringified"),
4786 opts: []Options{StringifyNumbers(true)},
4787 inBuf: `[null,"","AQ==","AQI=","AQID"]`,
4788 inVal: new([][]byte),
4789 want: addr([][]byte{nil, {}, {1}, {1, 2}, {1, 2, 3}}),
4790 }, {
4791
4792
4793 name: jsontest.Name("Bytes/Invariant"),
4794 inBuf: `[null,[],[1],[1,2],[1,2,3]]`,
4795 inVal: new([][]namedByte),
4796 want: addr([][]namedByte{nil, {}, {1}, {1, 2}, {1, 2, 3}}),
4797 }, {
4798
4799
4800 name: jsontest.Name("Bytes/ByteArray"),
4801 inBuf: `"aGVsbG8="`,
4802 inVal: new([5]byte),
4803 want: addr([5]byte{'h', 'e', 'l', 'l', 'o'}),
4804 }, {
4805 name: jsontest.Name("Bytes/ByteArray0/Valid"),
4806 inBuf: `""`,
4807 inVal: new([0]byte),
4808 want: addr([0]byte{}),
4809 }, {
4810 name: jsontest.Name("Bytes/ByteArray0/Invalid"),
4811 inBuf: `"A"`,
4812 inVal: new([0]byte),
4813 want: addr([0]byte{}),
4814 wantErr: EU(func() error {
4815 _, err := base64.StdEncoding.Decode(make([]byte, 0), []byte("A"))
4816 return err
4817 }()).withType('"', T[[0]byte]()),
4818 }, {
4819 name: jsontest.Name("Bytes/ByteArray0/Overflow"),
4820 inBuf: `"AA=="`,
4821 inVal: new([0]byte),
4822 want: addr([0]byte{}),
4823 wantErr: EU(errors.New("decoded length of 1 mismatches array length of 0")).withType('"', T[[0]byte]()),
4824 }, {
4825 name: jsontest.Name("Bytes/ByteArray1/Valid"),
4826 inBuf: `"AQ=="`,
4827 inVal: new([1]byte),
4828 want: addr([1]byte{1}),
4829 }, {
4830 name: jsontest.Name("Bytes/ByteArray1/Invalid"),
4831 inBuf: `"$$=="`,
4832 inVal: new([1]byte),
4833 want: addr([1]byte{}),
4834 wantErr: EU(func() error {
4835 _, err := base64.StdEncoding.Decode(make([]byte, 1), []byte("$$=="))
4836 return err
4837 }()).withType('"', T[[1]byte]()),
4838 }, {
4839 name: jsontest.Name("Bytes/ByteArray1/Underflow"),
4840 inBuf: `""`,
4841 inVal: new([1]byte),
4842 want: addr([1]byte{}),
4843 wantErr: EU(errors.New("decoded length of 0 mismatches array length of 1")).withType('"', T[[1]byte]()),
4844 }, {
4845 name: jsontest.Name("Bytes/ByteArray1/Overflow"),
4846 inBuf: `"AQI="`,
4847 inVal: new([1]byte),
4848 want: addr([1]byte{1}),
4849 wantErr: EU(errors.New("decoded length of 2 mismatches array length of 1")).withType('"', T[[1]byte]()),
4850 }, {
4851 name: jsontest.Name("Bytes/ByteArray2/Valid"),
4852 inBuf: `"AQI="`,
4853 inVal: new([2]byte),
4854 want: addr([2]byte{1, 2}),
4855 }, {
4856 name: jsontest.Name("Bytes/ByteArray2/Invalid"),
4857 inBuf: `"$$$="`,
4858 inVal: new([2]byte),
4859 want: addr([2]byte{}),
4860 wantErr: EU(func() error {
4861 _, err := base64.StdEncoding.Decode(make([]byte, 2), []byte("$$$="))
4862 return err
4863 }()).withType('"', T[[2]byte]()),
4864 }, {
4865 name: jsontest.Name("Bytes/ByteArray2/Underflow"),
4866 inBuf: `"AQ=="`,
4867 inVal: new([2]byte),
4868 want: addr([2]byte{1, 0}),
4869 wantErr: EU(errors.New("decoded length of 1 mismatches array length of 2")).withType('"', T[[2]byte]()),
4870 }, {
4871 name: jsontest.Name("Bytes/ByteArray2/Underflow/Allowed"),
4872 opts: []Options{jsonflags.UnmarshalArrayFromAnyLength | 1},
4873 inBuf: `"AQ=="`,
4874 inVal: new([2]byte),
4875 want: addr([2]byte{1, 0}),
4876 }, {
4877 name: jsontest.Name("Bytes/ByteArray2/Overflow"),
4878 inBuf: `"AQID"`,
4879 inVal: new([2]byte),
4880 want: addr([2]byte{1, 2}),
4881 wantErr: EU(errors.New("decoded length of 3 mismatches array length of 2")).withType('"', T[[2]byte]()),
4882 }, {
4883 name: jsontest.Name("Bytes/ByteArray2/Overflow/Allowed"),
4884 opts: []Options{jsonflags.UnmarshalArrayFromAnyLength | 1},
4885 inBuf: `"AQID"`,
4886 inVal: new([2]byte),
4887 want: addr([2]byte{1, 2}),
4888 }, {
4889 name: jsontest.Name("Bytes/ByteArray3/Valid"),
4890 inBuf: `"AQID"`,
4891 inVal: new([3]byte),
4892 want: addr([3]byte{1, 2, 3}),
4893 }, {
4894 name: jsontest.Name("Bytes/ByteArray3/Invalid"),
4895 inBuf: `"$$$$"`,
4896 inVal: new([3]byte),
4897 want: addr([3]byte{}),
4898 wantErr: EU(func() error {
4899 _, err := base64.StdEncoding.Decode(make([]byte, 3), []byte("$$$$"))
4900 return err
4901 }()).withType('"', T[[3]byte]()),
4902 }, {
4903 name: jsontest.Name("Bytes/ByteArray3/Underflow"),
4904 inBuf: `"AQI="`,
4905 inVal: addr([3]byte{0xff, 0xff, 0xff}),
4906 want: addr([3]byte{1, 2, 0}),
4907 wantErr: EU(errors.New("decoded length of 2 mismatches array length of 3")).withType('"', T[[3]byte]()),
4908 }, {
4909 name: jsontest.Name("Bytes/ByteArray3/Overflow"),
4910 inBuf: `"AQIDAQ=="`,
4911 inVal: new([3]byte),
4912 want: addr([3]byte{1, 2, 3}),
4913 wantErr: EU(errors.New("decoded length of 4 mismatches array length of 3")).withType('"', T[[3]byte]()),
4914 }, {
4915 name: jsontest.Name("Bytes/ByteArray4/Valid"),
4916 inBuf: `"AQIDBA=="`,
4917 inVal: new([4]byte),
4918 want: addr([4]byte{1, 2, 3, 4}),
4919 }, {
4920 name: jsontest.Name("Bytes/ByteArray4/Invalid"),
4921 inBuf: `"$$$$$$=="`,
4922 inVal: new([4]byte),
4923 want: addr([4]byte{}),
4924 wantErr: EU(func() error {
4925 _, err := base64.StdEncoding.Decode(make([]byte, 4), []byte("$$$$$$=="))
4926 return err
4927 }()).withType('"', T[[4]byte]()),
4928 }, {
4929 name: jsontest.Name("Bytes/ByteArray4/Underflow"),
4930 inBuf: `"AQID"`,
4931 inVal: new([4]byte),
4932 want: addr([4]byte{1, 2, 3, 0}),
4933 wantErr: EU(errors.New("decoded length of 3 mismatches array length of 4")).withType('"', T[[4]byte]()),
4934 }, {
4935 name: jsontest.Name("Bytes/ByteArray4/Overflow"),
4936 inBuf: `"AQIDBAU="`,
4937 inVal: new([4]byte),
4938 want: addr([4]byte{1, 2, 3, 4}),
4939 wantErr: EU(errors.New("decoded length of 5 mismatches array length of 4")).withType('"', T[[4]byte]()),
4940 }, {
4941
4942
4943 name: jsontest.Name("Bytes/NamedByteArray"),
4944 inBuf: `[104,101,108,108,111]`,
4945 inVal: new([5]namedByte),
4946 want: addr([5]namedByte{'h', 'e', 'l', 'l', 'o'}),
4947 }, {
4948 name: jsontest.Name("Bytes/Valid/Denormalized"),
4949 inBuf: `"AR=="`,
4950 inVal: new([]byte),
4951 want: addr([]byte{1}),
4952 }, {
4953 name: jsontest.Name("Bytes/Invalid/Unpadded1"),
4954 inBuf: `"AQ="`,
4955 inVal: addr([]byte("nochange")),
4956 want: addr([]byte("nochange")),
4957 wantErr: EU(func() error {
4958 _, err := base64.StdEncoding.Decode(make([]byte, 0), []byte("AQ="))
4959 return err
4960 }()).withType('"', bytesType),
4961 }, {
4962 name: jsontest.Name("Bytes/Invalid/Unpadded2"),
4963 inBuf: `"AQ"`,
4964 inVal: addr([]byte("nochange")),
4965 want: addr([]byte("nochange")),
4966 wantErr: EU(func() error {
4967 _, err := base64.StdEncoding.Decode(make([]byte, 0), []byte("AQ"))
4968 return err
4969 }()).withType('"', bytesType),
4970 }, {
4971 name: jsontest.Name("Bytes/Invalid/Character"),
4972 inBuf: `"@@@@"`,
4973 inVal: addr([]byte("nochange")),
4974 want: addr([]byte("nochange")),
4975 wantErr: EU(func() error {
4976 _, err := base64.StdEncoding.Decode(make([]byte, 3), []byte("@@@@"))
4977 return err
4978 }()).withType('"', bytesType),
4979 }, {
4980 name: jsontest.Name("Bytes/Invalid/Bool"),
4981 inBuf: `true`,
4982 inVal: addr([]byte("nochange")),
4983 want: addr([]byte("nochange")),
4984 wantErr: EU(nil).withType('t', bytesType),
4985 }, {
4986 name: jsontest.Name("Bytes/Invalid/Number"),
4987 inBuf: `0`,
4988 inVal: addr([]byte("nochange")),
4989 want: addr([]byte("nochange")),
4990 wantErr: EU(nil).withType('0', bytesType),
4991 }, {
4992 name: jsontest.Name("Bytes/Invalid/Object"),
4993 inBuf: `{}`,
4994 inVal: addr([]byte("nochange")),
4995 want: addr([]byte("nochange")),
4996 wantErr: EU(nil).withType('{', bytesType),
4997 }, {
4998 name: jsontest.Name("Bytes/Invalid/Array"),
4999 inBuf: `[]`,
5000 inVal: addr([]byte("nochange")),
5001 want: addr([]byte("nochange")),
5002 wantErr: EU(nil).withType('[', bytesType),
5003 }, {
5004 name: jsontest.Name("Bytes/IgnoreInvalidFormat"),
5005 opts: []Options{invalidFormatOption},
5006 inBuf: `"aGVsbG8="`,
5007 inVal: new([]byte),
5008 want: addr([]byte("hello")),
5009 }, {
5010 name: jsontest.Name("Ints/Null"),
5011 inBuf: `null`,
5012 inVal: addr(int(1)),
5013 want: addr(int(0)),
5014 }, {
5015 name: jsontest.Name("Ints/Int"),
5016 inBuf: `1`,
5017 inVal: addr(int(0)),
5018 want: addr(int(1)),
5019 }, {
5020 name: jsontest.Name("Ints/Int8/MinOverflow"),
5021 inBuf: `-129`,
5022 inVal: addr(int8(-1)),
5023 want: addr(int8(-1)),
5024 wantErr: EU(strconv.ErrRange).withVal(`-129`).withType('0', T[int8]()),
5025 }, {
5026 name: jsontest.Name("Ints/Int8/Min"),
5027 inBuf: `-128`,
5028 inVal: addr(int8(0)),
5029 want: addr(int8(-128)),
5030 }, {
5031 name: jsontest.Name("Ints/Int8/Max"),
5032 inBuf: `127`,
5033 inVal: addr(int8(0)),
5034 want: addr(int8(127)),
5035 }, {
5036 name: jsontest.Name("Ints/Int8/MaxOverflow"),
5037 inBuf: `128`,
5038 inVal: addr(int8(-1)),
5039 want: addr(int8(-1)),
5040 wantErr: EU(strconv.ErrRange).withVal(`128`).withType('0', T[int8]()),
5041 }, {
5042 name: jsontest.Name("Ints/Int16/MinOverflow"),
5043 inBuf: `-32769`,
5044 inVal: addr(int16(-1)),
5045 want: addr(int16(-1)),
5046 wantErr: EU(strconv.ErrRange).withVal(`-32769`).withType('0', T[int16]()),
5047 }, {
5048 name: jsontest.Name("Ints/Int16/Min"),
5049 inBuf: `-32768`,
5050 inVal: addr(int16(0)),
5051 want: addr(int16(-32768)),
5052 }, {
5053 name: jsontest.Name("Ints/Int16/Max"),
5054 inBuf: `32767`,
5055 inVal: addr(int16(0)),
5056 want: addr(int16(32767)),
5057 }, {
5058 name: jsontest.Name("Ints/Int16/MaxOverflow"),
5059 inBuf: `32768`,
5060 inVal: addr(int16(-1)),
5061 want: addr(int16(-1)),
5062 wantErr: EU(strconv.ErrRange).withVal(`32768`).withType('0', T[int16]()),
5063 }, {
5064 name: jsontest.Name("Ints/Int32/MinOverflow"),
5065 inBuf: `-2147483649`,
5066 inVal: addr(int32(-1)),
5067 want: addr(int32(-1)),
5068 wantErr: EU(strconv.ErrRange).withVal(`-2147483649`).withType('0', T[int32]()),
5069 }, {
5070 name: jsontest.Name("Ints/Int32/Min"),
5071 inBuf: `-2147483648`,
5072 inVal: addr(int32(0)),
5073 want: addr(int32(-2147483648)),
5074 }, {
5075 name: jsontest.Name("Ints/Int32/Max"),
5076 inBuf: `2147483647`,
5077 inVal: addr(int32(0)),
5078 want: addr(int32(2147483647)),
5079 }, {
5080 name: jsontest.Name("Ints/Int32/MaxOverflow"),
5081 inBuf: `2147483648`,
5082 inVal: addr(int32(-1)),
5083 want: addr(int32(-1)),
5084 wantErr: EU(strconv.ErrRange).withVal(`2147483648`).withType('0', T[int32]()),
5085 }, {
5086 name: jsontest.Name("Ints/Int64/MinOverflow"),
5087 inBuf: `-9223372036854775809`,
5088 inVal: addr(int64(-1)),
5089 want: addr(int64(-1)),
5090 wantErr: EU(strconv.ErrRange).withVal(`-9223372036854775809`).withType('0', T[int64]()),
5091 }, {
5092 name: jsontest.Name("Ints/Int64/Min"),
5093 inBuf: `-9223372036854775808`,
5094 inVal: addr(int64(0)),
5095 want: addr(int64(-9223372036854775808)),
5096 }, {
5097 name: jsontest.Name("Ints/Int64/Max"),
5098 inBuf: `9223372036854775807`,
5099 inVal: addr(int64(0)),
5100 want: addr(int64(9223372036854775807)),
5101 }, {
5102 name: jsontest.Name("Ints/Int64/MaxOverflow"),
5103 inBuf: `9223372036854775808`,
5104 inVal: addr(int64(-1)),
5105 want: addr(int64(-1)),
5106 wantErr: EU(strconv.ErrRange).withVal(`9223372036854775808`).withType('0', T[int64]()),
5107 }, {
5108 name: jsontest.Name("Ints/Named"),
5109 inBuf: `-6464`,
5110 inVal: addr(namedInt64(0)),
5111 want: addr(namedInt64(-6464)),
5112 }, {
5113 name: jsontest.Name("Ints/Stringified"),
5114 opts: []Options{StringifyNumbers(true)},
5115 inBuf: `"-6464"`,
5116 inVal: new(int),
5117 want: addr(int(-6464)),
5118 }, {
5119 name: jsontest.Name("Ints/Stringified/Invalid"),
5120 opts: []Options{StringifyNumbers(true)},
5121 inBuf: `-6464`,
5122 inVal: new(int),
5123 want: new(int),
5124 wantErr: EU(nil).withType('0', T[int]()),
5125 }, {
5126 name: jsontest.Name("Ints/Stringified/LeadingZero"),
5127 opts: []Options{StringifyNumbers(true)},
5128 inBuf: `"00"`,
5129 inVal: addr(int(-1)),
5130 want: addr(int(-1)),
5131 wantErr: EU(strconv.ErrSyntax).withVal(`"00"`).withType('"', T[int]()),
5132 }, {
5133 name: jsontest.Name("Ints/Escaped"),
5134 opts: []Options{StringifyNumbers(true)},
5135 inBuf: `"\u002d\u0036\u0034\u0036\u0034"`,
5136 inVal: new(int),
5137 want: addr(int(-6464)),
5138 }, {
5139 name: jsontest.Name("Ints/Valid/NegativeZero"),
5140 inBuf: `-0`,
5141 inVal: addr(int(1)),
5142 want: addr(int(0)),
5143 }, {
5144 name: jsontest.Name("Ints/Invalid/Fraction"),
5145 inBuf: `1.0`,
5146 inVal: addr(int(-1)),
5147 want: addr(int(-1)),
5148 wantErr: EU(strconv.ErrSyntax).withVal(`1.0`).withType('0', T[int]()),
5149 }, {
5150 name: jsontest.Name("Ints/Invalid/Exponent"),
5151 inBuf: `1e0`,
5152 inVal: addr(int(-1)),
5153 want: addr(int(-1)),
5154 wantErr: EU(strconv.ErrSyntax).withVal(`1e0`).withType('0', T[int]()),
5155 }, {
5156 name: jsontest.Name("Ints/Invalid/StringifiedFraction"),
5157 opts: []Options{StringifyNumbers(true)},
5158 inBuf: `"1.0"`,
5159 inVal: addr(int(-1)),
5160 want: addr(int(-1)),
5161 wantErr: EU(strconv.ErrSyntax).withVal(`"1.0"`).withType('"', T[int]()),
5162 }, {
5163 name: jsontest.Name("Ints/Invalid/StringifiedExponent"),
5164 opts: []Options{StringifyNumbers(true)},
5165 inBuf: `"1e0"`,
5166 inVal: addr(int(-1)),
5167 want: addr(int(-1)),
5168 wantErr: EU(strconv.ErrSyntax).withVal(`"1e0"`).withType('"', T[int]()),
5169 }, {
5170 name: jsontest.Name("Ints/Invalid/Overflow"),
5171 inBuf: `100000000000000000000000000000`,
5172 inVal: addr(int(-1)),
5173 want: addr(int(-1)),
5174 wantErr: EU(strconv.ErrRange).withVal(`100000000000000000000000000000`).withType('0', T[int]()),
5175 }, {
5176 name: jsontest.Name("Ints/Invalid/OverflowSyntax"),
5177 opts: []Options{StringifyNumbers(true)},
5178 inBuf: `"100000000000000000000000000000x"`,
5179 inVal: addr(int(-1)),
5180 want: addr(int(-1)),
5181 wantErr: EU(strconv.ErrSyntax).withVal(`"100000000000000000000000000000x"`).withType('"', T[int]()),
5182 }, {
5183 name: jsontest.Name("Ints/Invalid/Whitespace"),
5184 opts: []Options{StringifyNumbers(true)},
5185 inBuf: `"0 "`,
5186 inVal: addr(int(-1)),
5187 want: addr(int(-1)),
5188 wantErr: EU(strconv.ErrSyntax).withVal(`"0 "`).withType('"', T[int]()),
5189 }, {
5190 name: jsontest.Name("Ints/Invalid/Bool"),
5191 inBuf: `true`,
5192 inVal: addr(int(-1)),
5193 want: addr(int(-1)),
5194 wantErr: EU(nil).withType('t', T[int]()),
5195 }, {
5196 name: jsontest.Name("Ints/Invalid/String"),
5197 inBuf: `"0"`,
5198 inVal: addr(int(-1)),
5199 want: addr(int(-1)),
5200 wantErr: EU(nil).withType('"', T[int]()),
5201 }, {
5202 name: jsontest.Name("Ints/Invalid/Object"),
5203 inBuf: `{}`,
5204 inVal: addr(int(-1)),
5205 want: addr(int(-1)),
5206 wantErr: EU(nil).withType('{', T[int]()),
5207 }, {
5208 name: jsontest.Name("Ints/Invalid/Array"),
5209 inBuf: `[]`,
5210 inVal: addr(int(-1)),
5211 want: addr(int(-1)),
5212 wantErr: EU(nil).withType('[', T[int]()),
5213 }, {
5214 name: jsontest.Name("Ints/IgnoreInvalidFormat"),
5215 opts: []Options{invalidFormatOption},
5216 inBuf: `1`,
5217 inVal: addr(int(0)),
5218 want: addr(int(1)),
5219 }, {
5220 name: jsontest.Name("Uints/Null"),
5221 inBuf: `null`,
5222 inVal: addr(uint(1)),
5223 want: addr(uint(0)),
5224 }, {
5225 name: jsontest.Name("Uints/Uint"),
5226 inBuf: `1`,
5227 inVal: addr(uint(0)),
5228 want: addr(uint(1)),
5229 }, {
5230 name: jsontest.Name("Uints/Uint8/Min"),
5231 inBuf: `0`,
5232 inVal: addr(uint8(1)),
5233 want: addr(uint8(0)),
5234 }, {
5235 name: jsontest.Name("Uints/Uint8/Max"),
5236 inBuf: `255`,
5237 inVal: addr(uint8(0)),
5238 want: addr(uint8(255)),
5239 }, {
5240 name: jsontest.Name("Uints/Uint8/MaxOverflow"),
5241 inBuf: `256`,
5242 inVal: addr(uint8(1)),
5243 want: addr(uint8(1)),
5244 wantErr: EU(strconv.ErrRange).withVal(`256`).withType('0', T[uint8]()),
5245 }, {
5246 name: jsontest.Name("Uints/Uint16/Min"),
5247 inBuf: `0`,
5248 inVal: addr(uint16(1)),
5249 want: addr(uint16(0)),
5250 }, {
5251 name: jsontest.Name("Uints/Uint16/Max"),
5252 inBuf: `65535`,
5253 inVal: addr(uint16(0)),
5254 want: addr(uint16(65535)),
5255 }, {
5256 name: jsontest.Name("Uints/Uint16/MaxOverflow"),
5257 inBuf: `65536`,
5258 inVal: addr(uint16(1)),
5259 want: addr(uint16(1)),
5260 wantErr: EU(strconv.ErrRange).withVal(`65536`).withType('0', T[uint16]()),
5261 }, {
5262 name: jsontest.Name("Uints/Uint32/Min"),
5263 inBuf: `0`,
5264 inVal: addr(uint32(1)),
5265 want: addr(uint32(0)),
5266 }, {
5267 name: jsontest.Name("Uints/Uint32/Max"),
5268 inBuf: `4294967295`,
5269 inVal: addr(uint32(0)),
5270 want: addr(uint32(4294967295)),
5271 }, {
5272 name: jsontest.Name("Uints/Uint32/MaxOverflow"),
5273 inBuf: `4294967296`,
5274 inVal: addr(uint32(1)),
5275 want: addr(uint32(1)),
5276 wantErr: EU(strconv.ErrRange).withVal(`4294967296`).withType('0', T[uint32]()),
5277 }, {
5278 name: jsontest.Name("Uints/Uint64/Min"),
5279 inBuf: `0`,
5280 inVal: addr(uint64(1)),
5281 want: addr(uint64(0)),
5282 }, {
5283 name: jsontest.Name("Uints/Uint64/Max"),
5284 inBuf: `18446744073709551615`,
5285 inVal: addr(uint64(0)),
5286 want: addr(uint64(18446744073709551615)),
5287 }, {
5288 name: jsontest.Name("Uints/Uint64/MaxOverflow"),
5289 inBuf: `18446744073709551616`,
5290 inVal: addr(uint64(1)),
5291 want: addr(uint64(1)),
5292 wantErr: EU(strconv.ErrRange).withVal(`18446744073709551616`).withType('0', T[uint64]()),
5293 }, {
5294 name: jsontest.Name("Uints/Uintptr"),
5295 inBuf: `1`,
5296 inVal: addr(uintptr(0)),
5297 want: addr(uintptr(1)),
5298 }, {
5299 name: jsontest.Name("Uints/Named"),
5300 inBuf: `6464`,
5301 inVal: addr(namedUint64(0)),
5302 want: addr(namedUint64(6464)),
5303 }, {
5304 name: jsontest.Name("Uints/Stringified"),
5305 opts: []Options{StringifyNumbers(true)},
5306 inBuf: `"6464"`,
5307 inVal: new(uint),
5308 want: addr(uint(6464)),
5309 }, {
5310 name: jsontest.Name("Uints/Stringified/Invalid"),
5311 opts: []Options{StringifyNumbers(true)},
5312 inBuf: `6464`,
5313 inVal: new(uint),
5314 want: new(uint),
5315 wantErr: EU(nil).withType('0', T[uint]()),
5316 }, {
5317 name: jsontest.Name("Uints/Stringified/LeadingZero"),
5318 opts: []Options{StringifyNumbers(true)},
5319 inBuf: `"00"`,
5320 inVal: addr(uint(1)),
5321 want: addr(uint(1)),
5322 wantErr: EU(strconv.ErrSyntax).withVal(`"00"`).withType('"', T[uint]()),
5323 }, {
5324 name: jsontest.Name("Uints/Escaped"),
5325 opts: []Options{StringifyNumbers(true)},
5326 inBuf: `"\u0036\u0034\u0036\u0034"`,
5327 inVal: new(uint),
5328 want: addr(uint(6464)),
5329 }, {
5330 name: jsontest.Name("Uints/Invalid/NegativeOne"),
5331 inBuf: `-1`,
5332 inVal: addr(uint(1)),
5333 want: addr(uint(1)),
5334 wantErr: EU(strconv.ErrSyntax).withVal(`-1`).withType('0', T[uint]()),
5335 }, {
5336 name: jsontest.Name("Uints/Invalid/NegativeZero"),
5337 inBuf: `-0`,
5338 inVal: addr(uint(1)),
5339 want: addr(uint(1)),
5340 wantErr: EU(strconv.ErrSyntax).withVal(`-0`).withType('0', T[uint]()),
5341 }, {
5342 name: jsontest.Name("Uints/Invalid/Fraction"),
5343 inBuf: `1.0`,
5344 inVal: addr(uint(10)),
5345 want: addr(uint(10)),
5346 wantErr: EU(strconv.ErrSyntax).withVal(`1.0`).withType('0', T[uint]()),
5347 }, {
5348 name: jsontest.Name("Uints/Invalid/Exponent"),
5349 inBuf: `1e0`,
5350 inVal: addr(uint(10)),
5351 want: addr(uint(10)),
5352 wantErr: EU(strconv.ErrSyntax).withVal(`1e0`).withType('0', T[uint]()),
5353 }, {
5354 name: jsontest.Name("Uints/Invalid/StringifiedFraction"),
5355 opts: []Options{StringifyNumbers(true)},
5356 inBuf: `"1.0"`,
5357 inVal: addr(uint(10)),
5358 want: addr(uint(10)),
5359 wantErr: EU(strconv.ErrSyntax).withVal(`"1.0"`).withType('"', T[uint]()),
5360 }, {
5361 name: jsontest.Name("Uints/Invalid/StringifiedExponent"),
5362 opts: []Options{StringifyNumbers(true)},
5363 inBuf: `"1e0"`,
5364 inVal: addr(uint(10)),
5365 want: addr(uint(10)),
5366 wantErr: EU(strconv.ErrSyntax).withVal(`"1e0"`).withType('"', T[uint]()),
5367 }, {
5368 name: jsontest.Name("Uints/Invalid/Overflow"),
5369 inBuf: `100000000000000000000000000000`,
5370 inVal: addr(uint(1)),
5371 want: addr(uint(1)),
5372 wantErr: EU(strconv.ErrRange).withVal(`100000000000000000000000000000`).withType('0', T[uint]()),
5373 }, {
5374 name: jsontest.Name("Uints/Invalid/OverflowSyntax"),
5375 opts: []Options{StringifyNumbers(true)},
5376 inBuf: `"100000000000000000000000000000x"`,
5377 inVal: addr(uint(1)),
5378 want: addr(uint(1)),
5379 wantErr: EU(strconv.ErrSyntax).withVal(`"100000000000000000000000000000x"`).withType('"', T[uint]()),
5380 }, {
5381 name: jsontest.Name("Uints/Invalid/Whitespace"),
5382 opts: []Options{StringifyNumbers(true)},
5383 inBuf: `"0 "`,
5384 inVal: addr(uint(1)),
5385 want: addr(uint(1)),
5386 wantErr: EU(strconv.ErrSyntax).withVal(`"0 "`).withType('"', T[uint]()),
5387 }, {
5388 name: jsontest.Name("Uints/Invalid/Bool"),
5389 inBuf: `true`,
5390 inVal: addr(uint(1)),
5391 want: addr(uint(1)),
5392 wantErr: EU(nil).withType('t', T[uint]()),
5393 }, {
5394 name: jsontest.Name("Uints/Invalid/String"),
5395 inBuf: `"0"`,
5396 inVal: addr(uint(1)),
5397 want: addr(uint(1)),
5398 wantErr: EU(nil).withType('"', T[uint]()),
5399 }, {
5400 name: jsontest.Name("Uints/Invalid/Object"),
5401 inBuf: `{}`,
5402 inVal: addr(uint(1)),
5403 want: addr(uint(1)),
5404 wantErr: EU(nil).withType('{', T[uint]()),
5405 }, {
5406 name: jsontest.Name("Uints/Invalid/Array"),
5407 inBuf: `[]`,
5408 inVal: addr(uint(1)),
5409 want: addr(uint(1)),
5410 wantErr: EU(nil).withType('[', T[uint]()),
5411 }, {
5412 name: jsontest.Name("Uints/IgnoreInvalidFormat"),
5413 opts: []Options{invalidFormatOption},
5414 inBuf: `1`,
5415 inVal: addr(uint(0)),
5416 want: addr(uint(1)),
5417 }, {
5418 name: jsontest.Name("Floats/Null"),
5419 inBuf: `null`,
5420 inVal: addr(float64(64.64)),
5421 want: addr(float64(0)),
5422 }, {
5423 name: jsontest.Name("Floats/Float32/Pi"),
5424 inBuf: `3.14159265358979323846264338327950288419716939937510582097494459`,
5425 inVal: addr(float32(32.32)),
5426 want: addr(float32(math.Pi)),
5427 }, {
5428 name: jsontest.Name("Floats/Float32/Underflow"),
5429 inBuf: `1e-1000`,
5430 inVal: addr(float32(32.32)),
5431 want: addr(float32(0)),
5432 }, {
5433 name: jsontest.Name("Floats/Float32/Overflow"),
5434 inBuf: `-1e1000`,
5435 inVal: addr(float32(32.32)),
5436 want: addr(float32(-math.MaxFloat32)),
5437 wantErr: EU(strconv.ErrRange).withVal(`-1e1000`).withType('0', T[float32]()),
5438 }, {
5439 name: jsontest.Name("Floats/Float64/Pi"),
5440 inBuf: `3.14159265358979323846264338327950288419716939937510582097494459`,
5441 inVal: addr(float64(64.64)),
5442 want: addr(float64(math.Pi)),
5443 }, {
5444 name: jsontest.Name("Floats/Float64/Underflow"),
5445 inBuf: `1e-1000`,
5446 inVal: addr(float64(64.64)),
5447 want: addr(float64(0)),
5448 }, {
5449 name: jsontest.Name("Floats/Float64/Overflow"),
5450 inBuf: `-1e1000`,
5451 inVal: addr(float64(64.64)),
5452 want: addr(float64(-math.MaxFloat64)),
5453 wantErr: EU(strconv.ErrRange).withVal(`-1e1000`).withType('0', T[float64]()),
5454 }, {
5455 name: jsontest.Name("Floats/Any/Overflow"),
5456 inBuf: `1e1000`,
5457 inVal: new(any),
5458 want: addr(any(float64(math.MaxFloat64))),
5459 wantErr: EU(strconv.ErrRange).withVal(`1e1000`).withType('0', T[float64]()),
5460 }, {
5461 name: jsontest.Name("Floats/Named"),
5462 inBuf: `64.64`,
5463 inVal: addr(namedFloat64(0)),
5464 want: addr(namedFloat64(64.64)),
5465 }, {
5466 name: jsontest.Name("Floats/Stringified"),
5467 opts: []Options{StringifyNumbers(true)},
5468 inBuf: `"64.64"`,
5469 inVal: new(float64),
5470 want: addr(float64(64.64)),
5471 }, {
5472 name: jsontest.Name("Floats/Stringified/Invalid"),
5473 opts: []Options{StringifyNumbers(true)},
5474 inBuf: `64.64`,
5475 inVal: new(float64),
5476 want: new(float64),
5477 wantErr: EU(nil).withType('0', T[float64]()),
5478 }, {
5479 name: jsontest.Name("Floats/Escaped"),
5480 opts: []Options{StringifyNumbers(true)},
5481 inBuf: `"\u0036\u0034\u002e\u0036\u0034"`,
5482 inVal: new(float64),
5483 want: addr(float64(64.64)),
5484 }, {
5485 name: jsontest.Name("Floats/Invalid/NaN"),
5486 opts: []Options{StringifyNumbers(true)},
5487 inBuf: `"NaN"`,
5488 inVal: addr(float64(64.64)),
5489 want: addr(float64(64.64)),
5490 wantErr: EU(strconv.ErrSyntax).withVal(`"NaN"`).withType('"', float64Type),
5491 }, {
5492 name: jsontest.Name("Floats/Invalid/Infinity"),
5493 opts: []Options{StringifyNumbers(true)},
5494 inBuf: `"Infinity"`,
5495 inVal: addr(float64(64.64)),
5496 want: addr(float64(64.64)),
5497 wantErr: EU(strconv.ErrSyntax).withVal(`"Infinity"`).withType('"', float64Type),
5498 }, {
5499 name: jsontest.Name("Floats/Invalid/Whitespace"),
5500 opts: []Options{StringifyNumbers(true)},
5501 inBuf: `"1 "`,
5502 inVal: addr(float64(64.64)),
5503 want: addr(float64(64.64)),
5504 wantErr: EU(strconv.ErrSyntax).withVal(`"1 "`).withType('"', float64Type),
5505 }, {
5506 name: jsontest.Name("Floats/Invalid/GoSyntax"),
5507 opts: []Options{StringifyNumbers(true)},
5508 inBuf: `"1p-2"`,
5509 inVal: addr(float64(64.64)),
5510 want: addr(float64(64.64)),
5511 wantErr: EU(strconv.ErrSyntax).withVal(`"1p-2"`).withType('"', float64Type),
5512 }, {
5513 name: jsontest.Name("Floats/Invalid/Bool"),
5514 inBuf: `true`,
5515 inVal: addr(float64(64.64)),
5516 want: addr(float64(64.64)),
5517 wantErr: EU(nil).withType('t', float64Type),
5518 }, {
5519 name: jsontest.Name("Floats/Invalid/String"),
5520 inBuf: `"0"`,
5521 inVal: addr(float64(64.64)),
5522 want: addr(float64(64.64)),
5523 wantErr: EU(nil).withType('"', float64Type),
5524 }, {
5525 name: jsontest.Name("Floats/Invalid/Object"),
5526 inBuf: `{}`,
5527 inVal: addr(float64(64.64)),
5528 want: addr(float64(64.64)),
5529 wantErr: EU(nil).withType('{', float64Type),
5530 }, {
5531 name: jsontest.Name("Floats/Invalid/Array"),
5532 inBuf: `[]`,
5533 inVal: addr(float64(64.64)),
5534 want: addr(float64(64.64)),
5535 wantErr: EU(nil).withType('[', float64Type),
5536 }, {
5537 name: jsontest.Name("Floats/IgnoreInvalidFormat"),
5538 opts: []Options{invalidFormatOption},
5539 inBuf: `1`,
5540 inVal: addr(float64(0)),
5541 want: addr(float64(1)),
5542 }, {
5543 name: jsontest.Name("Maps/Null"),
5544 inBuf: `null`,
5545 inVal: addr(map[string]string{"key": "value"}),
5546 want: new(map[string]string),
5547 }, {
5548 name: jsontest.Name("Maps/InvalidKey/Bool"),
5549 inBuf: `{"true":"false"}`,
5550 inVal: new(map[bool]bool),
5551 want: addr(make(map[bool]bool)),
5552 wantErr: EU(nil).withPos(`{`, "/true").withType('"', boolType),
5553 }, {
5554 name: jsontest.Name("Maps/InvalidKey/NamedBool"),
5555 inBuf: `{"true":"false"}`,
5556 inVal: new(map[namedBool]bool),
5557 want: addr(make(map[namedBool]bool)),
5558 wantErr: EU(nil).withPos(`{`, "/true").withType('"', T[namedBool]()),
5559 }, {
5560 name: jsontest.Name("Maps/InvalidKey/Array"),
5561 inBuf: `{"key":"value"}`,
5562 inVal: new(map[[1]string]string),
5563 want: addr(make(map[[1]string]string)),
5564 wantErr: EU(nil).withPos(`{`, "/key").withType('"', T[[1]string]()),
5565 }, {
5566 name: jsontest.Name("Maps/InvalidKey/Channel"),
5567 inBuf: `{"key":"value"}`,
5568 inVal: new(map[chan string]string),
5569 want: addr(make(map[chan string]string)),
5570 wantErr: EU(nil).withPos(`{`, "").withType(0, T[chan string]()),
5571 }, {
5572 name: jsontest.Name("Maps/ValidKey/Int"),
5573 inBuf: `{"0":0,"-1":1,"2":2,"-3":3}`,
5574 inVal: new(map[int]int),
5575 want: addr(map[int]int{0: 0, -1: 1, 2: 2, -3: 3}),
5576 }, {
5577 name: jsontest.Name("Maps/ValidKey/NamedInt"),
5578 inBuf: `{"0":0,"-1":1,"2":2,"-3":3}`,
5579 inVal: new(map[namedInt64]int),
5580 want: addr(map[namedInt64]int{0: 0, -1: 1, 2: 2, -3: 3}),
5581 }, {
5582 name: jsontest.Name("Maps/ValidKey/Uint"),
5583 inBuf: `{"0":0,"1":1,"2":2,"3":3}`,
5584 inVal: new(map[uint]uint),
5585 want: addr(map[uint]uint{0: 0, 1: 1, 2: 2, 3: 3}),
5586 }, {
5587 name: jsontest.Name("Maps/ValidKey/NamedUint"),
5588 inBuf: `{"0":0,"1":1,"2":2,"3":3}`,
5589 inVal: new(map[namedUint64]uint),
5590 want: addr(map[namedUint64]uint{0: 0, 1: 1, 2: 2, 3: 3}),
5591 }, {
5592 name: jsontest.Name("Maps/ValidKey/Float"),
5593 inBuf: `{"1.234":1.234,"12.34":12.34,"123.4":123.4}`,
5594 inVal: new(map[float64]float64),
5595 want: addr(map[float64]float64{1.234: 1.234, 12.34: 12.34, 123.4: 123.4}),
5596 }, {
5597 name: jsontest.Name("Maps/DuplicateName/Int"),
5598 inBuf: `{"0":1,"-0":-1}`,
5599 inVal: new(map[int]int),
5600 want: addr(map[int]int{0: 1}),
5601 wantErr: newDuplicateNameError("", []byte(`"-0"`), len64(`{"0":1,`)),
5602 }, {
5603 name: jsontest.Name("Maps/DuplicateName/Int/MergeWithLegacySemantics"),
5604 opts: []Options{jsonflags.MergeWithLegacySemantics | 1},
5605 inBuf: `{"0":1,"-0":-1}`,
5606 inVal: new(map[int]int),
5607 want: addr(map[int]int{0: 1}),
5608 wantErr: newDuplicateNameError("", []byte(`"-0"`), len64(`{"0":1,`)),
5609 }, {
5610 name: jsontest.Name("Maps/DuplicateName/Int/AllowDuplicateNames"),
5611 opts: []Options{jsontext.AllowDuplicateNames(true)},
5612 inBuf: `{"0":1,"-0":-1}`,
5613 inVal: new(map[int]int),
5614 want: addr(map[int]int{0: -1}),
5615 }, {
5616 name: jsontest.Name("Maps/DuplicateName/Int/OverwriteExisting"),
5617 inBuf: `{"-0":-1}`,
5618 inVal: addr(map[int]int{0: 1}),
5619 want: addr(map[int]int{0: -1}),
5620 }, {
5621 name: jsontest.Name("Maps/DuplicateName/Float"),
5622 inBuf: `{"1.0":"1.0","1":"1","1e0":"1e0"}`,
5623 inVal: new(map[float64]string),
5624 want: addr(map[float64]string{1: "1.0"}),
5625 wantErr: newDuplicateNameError("", []byte(`"1"`), len64(`{"1.0":"1.0",`)),
5626 }, {
5627 name: jsontest.Name("Maps/DuplicateName/Float/AllowDuplicateNames"),
5628 opts: []Options{jsontext.AllowDuplicateNames(true)},
5629 inBuf: `{"1.0":"1.0","1":"1","1e0":"1e0"}`,
5630 inVal: new(map[float64]string),
5631 want: addr(map[float64]string{1: "1e0"}),
5632 }, {
5633 name: jsontest.Name("Maps/DuplicateName/Float/OverwriteExisting"),
5634 inBuf: `{"1.0":"1.0"}`,
5635 inVal: addr(map[float64]string{1: "1"}),
5636 want: addr(map[float64]string{1: "1.0"}),
5637 }, {
5638 name: jsontest.Name("Maps/DuplicateName/NoCaseString"),
5639 inBuf: `{"hello":"hello","HELLO":"HELLO"}`,
5640 inVal: new(map[nocaseString]string),
5641 want: addr(map[nocaseString]string{"hello": "hello"}),
5642 wantErr: newDuplicateNameError("", []byte(`"HELLO"`), len64(`{"hello":"hello",`)),
5643 }, {
5644 name: jsontest.Name("Maps/DuplicateName/NoCaseString/AllowDuplicateNames"),
5645 opts: []Options{jsontext.AllowDuplicateNames(true)},
5646 inBuf: `{"hello":"hello","HELLO":"HELLO"}`,
5647 inVal: new(map[nocaseString]string),
5648 want: addr(map[nocaseString]string{"hello": "HELLO"}),
5649 }, {
5650 name: jsontest.Name("Maps/DuplicateName/NoCaseString/OverwriteExisting"),
5651 opts: []Options{jsontext.AllowDuplicateNames(true)},
5652 inBuf: `{"HELLO":"HELLO"}`,
5653 inVal: addr(map[nocaseString]string{"hello": "hello"}),
5654 want: addr(map[nocaseString]string{"hello": "HELLO"}),
5655 }, {
5656 name: jsontest.Name("Maps/ValidKey/Interface"),
5657 inBuf: `{"false":"false","true":"true","string":"string","0":"0","[]":"[]","{}":"{}"}`,
5658 inVal: new(map[any]string),
5659 want: addr(map[any]string{
5660 "false": "false",
5661 "true": "true",
5662 "string": "string",
5663 "0": "0",
5664 "[]": "[]",
5665 "{}": "{}",
5666 }),
5667 }, {
5668 name: jsontest.Name("Maps/InvalidValue/Channel"),
5669 inBuf: `{"key":"value"}`,
5670 inVal: new(map[string]chan string),
5671 want: addr(map[string]chan string{
5672 "key": nil,
5673 }),
5674 wantErr: EU(nil).withPos(`{"key":`, "/key").withType(0, T[chan string]()),
5675 }, {
5676 name: jsontest.Name("Maps/RecursiveMap"),
5677 inBuf: `{"buzz":{},"fizz":{"bar":{},"foo":{}}}`,
5678 inVal: new(recursiveMap),
5679 want: addr(recursiveMap{
5680 "fizz": {
5681 "foo": {},
5682 "bar": {},
5683 },
5684 "buzz": {},
5685 }),
5686 }, {
5687
5688
5689
5690 name: jsontest.Name("Maps/Merge"),
5691 opts: []Options{jsontext.AllowDuplicateNames(true)},
5692 inBuf: `{"k1":{"k2":"v2"},"k2":{"k1":"v1"},"k2":{"k2":"v2"}}`,
5693 inVal: addr(map[string]map[string]string{
5694 "k1": {"k1": "v1"},
5695 }),
5696 want: addr(map[string]map[string]string{
5697 "k1": {"k1": "v1", "k2": "v2"},
5698 "k2": {"k1": "v1", "k2": "v2"},
5699 }),
5700 }, {
5701 name: jsontest.Name("Maps/Invalid/Bool"),
5702 inBuf: `true`,
5703 inVal: addr(map[string]string{"key": "value"}),
5704 want: addr(map[string]string{"key": "value"}),
5705 wantErr: EU(nil).withType('t', T[map[string]string]()),
5706 }, {
5707 name: jsontest.Name("Maps/Invalid/String"),
5708 inBuf: `""`,
5709 inVal: addr(map[string]string{"key": "value"}),
5710 want: addr(map[string]string{"key": "value"}),
5711 wantErr: EU(nil).withType('"', T[map[string]string]()),
5712 }, {
5713 name: jsontest.Name("Maps/Invalid/Number"),
5714 inBuf: `0`,
5715 inVal: addr(map[string]string{"key": "value"}),
5716 want: addr(map[string]string{"key": "value"}),
5717 wantErr: EU(nil).withType('0', T[map[string]string]()),
5718 }, {
5719 name: jsontest.Name("Maps/Invalid/Array"),
5720 inBuf: `[]`,
5721 inVal: addr(map[string]string{"key": "value"}),
5722 want: addr(map[string]string{"key": "value"}),
5723 wantErr: EU(nil).withType('[', T[map[string]string]()),
5724 }, {
5725 name: jsontest.Name("Maps/IgnoreInvalidFormat"),
5726 opts: []Options{invalidFormatOption},
5727 inBuf: `{"hello":"goodbye"}`,
5728 inVal: addr(map[string]string{}),
5729 want: addr(map[string]string{"hello": "goodbye"}),
5730 }, {
5731 name: jsontest.Name("Structs/Null"),
5732 inBuf: `null`,
5733 inVal: addr(structAll{String: "something"}),
5734 want: addr(structAll{}),
5735 }, {
5736 name: jsontest.Name("Structs/Empty"),
5737 inBuf: `{}`,
5738 inVal: addr(structAll{
5739 String: "hello",
5740 Map: map[string]string{},
5741 Slice: []string{},
5742 }),
5743 want: addr(structAll{
5744 String: "hello",
5745 Map: map[string]string{},
5746 Slice: []string{},
5747 }),
5748 }, {
5749 name: jsontest.Name("Structs/Normal"),
5750 inBuf: `{
5751 "Bool": true,
5752 "String": "hello",
5753 "Bytes": "AQID",
5754 "Int": -64,
5755 "Uint": 64,
5756 "Float": 3.14159,
5757 "Map": {"key": "value"},
5758 "StructScalars": {
5759 "Bool": true,
5760 "String": "hello",
5761 "Bytes": "AQID",
5762 "Int": -64,
5763 "Uint": 64,
5764 "Float": 3.14159
5765 },
5766 "StructMaps": {
5767 "MapBool": {"": true},
5768 "MapString": {"": "hello"},
5769 "MapBytes": {"": "AQID"},
5770 "MapInt": {"": -64},
5771 "MapUint": {"": 64},
5772 "MapFloat": {"": 3.14159}
5773 },
5774 "StructSlices": {
5775 "SliceBool": [true],
5776 "SliceString": ["hello"],
5777 "SliceBytes": ["AQID"],
5778 "SliceInt": [-64],
5779 "SliceUint": [64],
5780 "SliceFloat": [3.14159]
5781 },
5782 "Slice": ["fizz","buzz"],
5783 "Array": ["goodbye"],
5784 "Pointer": {},
5785 "Interface": null
5786 }`,
5787 inVal: new(structAll),
5788 want: addr(structAll{
5789 Bool: true,
5790 String: "hello",
5791 Bytes: []byte{1, 2, 3},
5792 Int: -64,
5793 Uint: +64,
5794 Float: 3.14159,
5795 Map: map[string]string{"key": "value"},
5796 StructScalars: structScalars{
5797 Bool: true,
5798 String: "hello",
5799 Bytes: []byte{1, 2, 3},
5800 Int: -64,
5801 Uint: +64,
5802 Float: 3.14159,
5803 },
5804 StructMaps: structMaps{
5805 MapBool: map[string]bool{"": true},
5806 MapString: map[string]string{"": "hello"},
5807 MapBytes: map[string][]byte{"": {1, 2, 3}},
5808 MapInt: map[string]int64{"": -64},
5809 MapUint: map[string]uint64{"": +64},
5810 MapFloat: map[string]float64{"": 3.14159},
5811 },
5812 StructSlices: structSlices{
5813 SliceBool: []bool{true},
5814 SliceString: []string{"hello"},
5815 SliceBytes: [][]byte{{1, 2, 3}},
5816 SliceInt: []int64{-64},
5817 SliceUint: []uint64{+64},
5818 SliceFloat: []float64{3.14159},
5819 },
5820 Slice: []string{"fizz", "buzz"},
5821 Array: [1]string{"goodbye"},
5822 Pointer: new(structAll),
5823 }),
5824 }, {
5825 name: jsontest.Name("Structs/Merge"),
5826 inBuf: `{
5827 "Bool": false,
5828 "String": "goodbye",
5829 "Int": -64,
5830 "Float": 3.14159,
5831 "Map": {"k2": "v2"},
5832 "StructScalars": {
5833 "Bool": true,
5834 "String": "hello",
5835 "Bytes": "AQID",
5836 "Int": -64
5837 },
5838 "StructMaps": {
5839 "MapBool": {"": true},
5840 "MapString": {"": "hello"},
5841 "MapBytes": {"": "AQID"},
5842 "MapInt": {"": -64},
5843 "MapUint": {"": 64},
5844 "MapFloat": {"": 3.14159}
5845 },
5846 "StructSlices": {
5847 "SliceString": ["hello"],
5848 "SliceBytes": ["AQID"],
5849 "SliceInt": [-64],
5850 "SliceUint": [64]
5851 },
5852 "Slice": ["fizz","buzz"],
5853 "Array": ["goodbye"],
5854 "Pointer": {},
5855 "Interface": {"k2":"v2"}
5856 }`,
5857 inVal: addr(structAll{
5858 Bool: true,
5859 String: "hello",
5860 Bytes: []byte{1, 2, 3},
5861 Uint: +64,
5862 Float: math.NaN(),
5863 Map: map[string]string{"k1": "v1"},
5864 StructScalars: structScalars{
5865 String: "hello",
5866 Bytes: make([]byte, 2, 4),
5867 Uint: +64,
5868 Float: 3.14159,
5869 },
5870 StructMaps: structMaps{
5871 MapBool: map[string]bool{"": false},
5872 MapBytes: map[string][]byte{"": {}},
5873 MapInt: map[string]int64{"": 123},
5874 MapFloat: map[string]float64{"": math.Inf(+1)},
5875 },
5876 StructSlices: structSlices{
5877 SliceBool: []bool{true},
5878 SliceBytes: [][]byte{nil, nil},
5879 SliceInt: []int64{-123},
5880 SliceUint: []uint64{+123},
5881 SliceFloat: []float64{3.14159},
5882 },
5883 Slice: []string{"buzz", "fizz", "gizz"},
5884 Array: [1]string{"hello"},
5885 Pointer: new(structAll),
5886 Interface: map[string]string{"k1": "v1"},
5887 }),
5888 want: addr(structAll{
5889 Bool: false,
5890 String: "goodbye",
5891 Bytes: []byte{1, 2, 3},
5892 Int: -64,
5893 Uint: +64,
5894 Float: 3.14159,
5895 Map: map[string]string{"k1": "v1", "k2": "v2"},
5896 StructScalars: structScalars{
5897 Bool: true,
5898 String: "hello",
5899 Bytes: []byte{1, 2, 3},
5900 Int: -64,
5901 Uint: +64,
5902 Float: 3.14159,
5903 },
5904 StructMaps: structMaps{
5905 MapBool: map[string]bool{"": true},
5906 MapString: map[string]string{"": "hello"},
5907 MapBytes: map[string][]byte{"": {1, 2, 3}},
5908 MapInt: map[string]int64{"": -64},
5909 MapUint: map[string]uint64{"": +64},
5910 MapFloat: map[string]float64{"": 3.14159},
5911 },
5912 StructSlices: structSlices{
5913 SliceBool: []bool{true},
5914 SliceString: []string{"hello"},
5915 SliceBytes: [][]byte{{1, 2, 3}},
5916 SliceInt: []int64{-64},
5917 SliceUint: []uint64{+64},
5918 SliceFloat: []float64{3.14159},
5919 },
5920 Slice: []string{"fizz", "buzz"},
5921 Array: [1]string{"goodbye"},
5922 Pointer: new(structAll),
5923 Interface: map[string]string{"k1": "v1", "k2": "v2"},
5924 }),
5925 }, {
5926 name: jsontest.Name("Structs/Stringified/Normal"),
5927 inBuf: `{
5928 "Bool": true,
5929 "String": "hello",
5930 "Bytes": "AQID",
5931 "Int": "-64",
5932 "Uint": "64",
5933 "Float": "3.14159",
5934 "Map": {"key": "value"},
5935 "StructScalars": {
5936 "Bool": true,
5937 "String": "hello",
5938 "Bytes": "AQID",
5939 "Int": "-64",
5940 "Uint": "64",
5941 "Float": "3.14159"
5942 },
5943 "StructMaps": {
5944 "MapBool": {"": true},
5945 "MapString": {"": "hello"},
5946 "MapBytes": {"": "AQID"},
5947 "MapInt": {"": "-64"},
5948 "MapUint": {"": "64"},
5949 "MapFloat": {"": "3.14159"}
5950 },
5951 "StructSlices": {
5952 "SliceBool": [true],
5953 "SliceString": ["hello"],
5954 "SliceBytes": ["AQID"],
5955 "SliceInt": ["-64"],
5956 "SliceUint": ["64"],
5957 "SliceFloat": ["3.14159"]
5958 },
5959 "Slice": ["fizz","buzz"],
5960 "Array": ["goodbye"],
5961 "Pointer": {},
5962 "Interface": null
5963 }`,
5964 inVal: new(structStringifiedAll),
5965 want: addr(structStringifiedAll{
5966 Bool: true,
5967 String: "hello",
5968 Bytes: []byte{1, 2, 3},
5969 Int: -64,
5970 Uint: +64,
5971 Float: 3.14159,
5972 Map: map[string]string{"key": "value"},
5973 StructScalars: structScalars{
5974 Bool: true,
5975 String: "hello",
5976 Bytes: []byte{1, 2, 3},
5977 Int: -64,
5978 Uint: +64,
5979 Float: 3.14159,
5980 },
5981 StructMaps: structMaps{
5982 MapBool: map[string]bool{"": true},
5983 MapString: map[string]string{"": "hello"},
5984 MapBytes: map[string][]byte{"": {1, 2, 3}},
5985 MapInt: map[string]int64{"": -64},
5986 MapUint: map[string]uint64{"": +64},
5987 MapFloat: map[string]float64{"": 3.14159},
5988 },
5989 StructSlices: structSlices{
5990 SliceBool: []bool{true},
5991 SliceString: []string{"hello"},
5992 SliceBytes: [][]byte{{1, 2, 3}},
5993 SliceInt: []int64{-64},
5994 SliceUint: []uint64{+64},
5995 SliceFloat: []float64{3.14159},
5996 },
5997 Slice: []string{"fizz", "buzz"},
5998 Array: [1]string{"goodbye"},
5999 Pointer: new(structStringifiedAll),
6000 }),
6001 }, {
6002 name: jsontest.Name("Structs/Stringified/String"),
6003 inBuf: `{
6004 "Bool": true,
6005 "String": "hello",
6006 "Bytes": "AQID",
6007 "Int": "-64",
6008 "Uint": "64",
6009 "Float": "3.14159",
6010 "Map": {"key": "value"},
6011 "StructScalars": {
6012 "Bool": true,
6013 "String": "hello",
6014 "Bytes": "AQID",
6015 "Int": "-64",
6016 "Uint": "64",
6017 "Float": "3.14159"
6018 },
6019 "StructMaps": {
6020 "MapBool": {"": true},
6021 "MapString": {"": "hello"},
6022 "MapBytes": {"": "AQID"},
6023 "MapInt": {"": "-64"},
6024 "MapUint": {"": "64"},
6025 "MapFloat": {"": "3.14159"}
6026 },
6027 "StructSlices": {
6028 "SliceBool": [true],
6029 "SliceString": ["hello"],
6030 "SliceBytes": ["AQID"],
6031 "SliceInt": ["-64"],
6032 "SliceUint": ["64"],
6033 "SliceFloat": ["3.14159"]
6034 },
6035 "Slice": ["fizz","buzz"],
6036 "Array": ["goodbye"],
6037 "Pointer": {},
6038 "Interface": null
6039 }`,
6040 inVal: new(structStringifiedAll),
6041 want: addr(structStringifiedAll{
6042 Bool: true,
6043 String: "hello",
6044 Bytes: []byte{1, 2, 3},
6045 Int: -64,
6046 Uint: +64,
6047 Float: 3.14159,
6048 Map: map[string]string{"key": "value"},
6049 StructScalars: structScalars{
6050 Bool: true,
6051 String: "hello",
6052 Bytes: []byte{1, 2, 3},
6053 Int: -64,
6054 Uint: +64,
6055 Float: 3.14159,
6056 },
6057 StructMaps: structMaps{
6058 MapBool: map[string]bool{"": true},
6059 MapString: map[string]string{"": "hello"},
6060 MapBytes: map[string][]byte{"": {1, 2, 3}},
6061 MapInt: map[string]int64{"": -64},
6062 MapUint: map[string]uint64{"": +64},
6063 MapFloat: map[string]float64{"": 3.14159},
6064 },
6065 StructSlices: structSlices{
6066 SliceBool: []bool{true},
6067 SliceString: []string{"hello"},
6068 SliceBytes: [][]byte{{1, 2, 3}},
6069 SliceInt: []int64{-64},
6070 SliceUint: []uint64{+64},
6071 SliceFloat: []float64{3.14159},
6072 },
6073 Slice: []string{"fizz", "buzz"},
6074 Array: [1]string{"goodbye"},
6075 Pointer: new(structStringifiedAll),
6076 }),
6077 }, {
6078 name: jsontest.Name("Structs/Stringified/InvalidEmpty"),
6079 inBuf: `{"Int":""}`,
6080 inVal: new(structStringifiedAll),
6081 want: new(structStringifiedAll),
6082 wantErr: EU(strconv.ErrSyntax).withVal(`""`).withPos(`{"Int":`, "/Int").withType('"', T[int64]()),
6083 }, {
6084 name: jsontest.Name("Structs/LegacyStringified"),
6085 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6086 inBuf: `{
6087 "Bool": "true",
6088 "String": "\"hello\"",
6089 "Bytes": "AQID",
6090 "Int": "-64",
6091 "Uint": "64",
6092 "Float": "3.14159",
6093 "Map": {"key": "value"},
6094 "StructScalars": {
6095 "Bool": true,
6096 "String": "hello",
6097 "Bytes": "AQID",
6098 "Int": -64,
6099 "Uint": 64,
6100 "Float": 3.14159
6101 },
6102 "StructMaps": {
6103 "MapBool": {"": true},
6104 "MapString": {"": "hello"},
6105 "MapBytes": {"": "AQID"},
6106 "MapInt": {"": -64},
6107 "MapUint": {"": 64},
6108 "MapFloat": {"": 3.14159}
6109 },
6110 "StructSlices": {
6111 "SliceBool": [true],
6112 "SliceString": ["hello"],
6113 "SliceBytes": ["AQID"],
6114 "SliceInt": [-64],
6115 "SliceUint": [64],
6116 "SliceFloat": [3.14159]
6117 },
6118 "Slice": ["fizz", "buzz"],
6119 "Array": ["goodbye"]
6120 }`,
6121 inVal: new(structStringifiedAll),
6122 want: addr(structStringifiedAll{
6123 Bool: true,
6124 String: "hello",
6125 Bytes: []byte{1, 2, 3},
6126 Int: -64,
6127 Uint: +64,
6128 Float: 3.14159,
6129 Map: map[string]string{"key": "value"},
6130 StructScalars: structScalars{
6131 Bool: true,
6132 String: "hello",
6133 Bytes: []byte{1, 2, 3},
6134 Int: -64,
6135 Uint: +64,
6136 Float: 3.14159,
6137 },
6138 StructMaps: structMaps{
6139 MapBool: map[string]bool{"": true},
6140 MapString: map[string]string{"": "hello"},
6141 MapBytes: map[string][]byte{"": {1, 2, 3}},
6142 MapInt: map[string]int64{"": -64},
6143 MapUint: map[string]uint64{"": +64},
6144 MapFloat: map[string]float64{"": 3.14159},
6145 },
6146 StructSlices: structSlices{
6147 SliceBool: []bool{true},
6148 SliceString: []string{"hello"},
6149 SliceBytes: [][]byte{{1, 2, 3}},
6150 SliceInt: []int64{-64},
6151 SliceUint: []uint64{+64},
6152 SliceFloat: []float64{3.14159},
6153 },
6154 Slice: []string{"fizz", "buzz"},
6155 Array: [1]string{"goodbye"},
6156 }),
6157 }, {
6158 name: jsontest.Name("Structs/LegacyStringified/InvalidBool"),
6159 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6160 inBuf: `{"Bool": true}`,
6161 inVal: new(structStringifiedAll),
6162 wantErr: EU(nil).withPos(`{"Bool": `, "/Bool").withType('t', T[bool]()),
6163 }, {
6164 name: jsontest.Name("Structs/LegacyStringified/InvalidString"),
6165 opts: []Options{jsonflags.StringifyWithLegacySemantics | 1},
6166 inBuf: `{"String": "string"}`,
6167 inVal: new(structStringifiedAll),
6168 wantErr: EU(newInvalidCharacterError("s", "at start of string (expecting '\"')", 0, "")).
6169 withPos(`{"String": `, "/String").withType('"', T[string]()),
6170 }, {
6171 name: jsontest.Name("Structs/Format/Bytes"),
6172 inBuf: `{
6173 "Base16": "0123456789abcdef",
6174 "Base32": "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
6175 "Base32Hex": "0123456789ABCDEFGHIJKLMNOPQRSTUV",
6176 "Base64": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",
6177 "Base64URL": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
6178 "Array": [1, 2, 3, 4]
6179 }`,
6180 inVal: new(structFormatBytes),
6181 want: addr(structFormatBytes{
6182 Base16: []byte("\x01\x23\x45\x67\x89\xab\xcd\xef"),
6183 Base32: []byte("\x00D2\x14\xc7BT\xb65τe:V\xd7\xc6u\xbew\xdf"),
6184 Base32Hex: []byte("\x00D2\x14\xc7BT\xb65τe:V\xd7\xc6u\xbew\xdf"),
6185 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߿"),
6186 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߿"),
6187 Array: []byte{1, 2, 3, 4},
6188 }),
6189 }, {
6190 name: jsontest.Name("Structs/Format/ArrayBytes"),
6191 inBuf: `{
6192 "Base16": "01020304",
6193 "Base32": "AEBAGBA=",
6194 "Base32Hex": "0410610=",
6195 "Base64": "AQIDBA==",
6196 "Base64URL": "AQIDBA==",
6197 "Array": [1, 2, 3, 4],
6198 "Default": "AQIDBA=="
6199 }`,
6200 inVal: new(structFormatArrayBytes),
6201 want: addr(structFormatArrayBytes{
6202 Base16: [4]byte{1, 2, 3, 4},
6203 Base32: [4]byte{1, 2, 3, 4},
6204 Base32Hex: [4]byte{1, 2, 3, 4},
6205 Base64: [4]byte{1, 2, 3, 4},
6206 Base64URL: [4]byte{1, 2, 3, 4},
6207 Array: [4]byte{1, 2, 3, 4},
6208 Default: [4]byte{1, 2, 3, 4},
6209 }),
6210 }, {
6211 name: jsontest.Name("Structs/Format/ArrayBytes/Legacy"),
6212 opts: []Options{jsonflags.FormatBytesWithLegacySemantics | 1},
6213 inBuf: `{
6214 "Base16": "01020304",
6215 "Base32": "AEBAGBA=",
6216 "Base32Hex": "0410610=",
6217 "Base64": "AQIDBA==",
6218 "Base64URL": "AQIDBA==",
6219 "Array": [1, 2, 3, 4],
6220 "Default": [1, 2, 3, 4]
6221 }`,
6222 inVal: new(structFormatArrayBytes),
6223 want: addr(structFormatArrayBytes{
6224 Base16: [4]byte{1, 2, 3, 4},
6225 Base32: [4]byte{1, 2, 3, 4},
6226 Base32Hex: [4]byte{1, 2, 3, 4},
6227 Base64: [4]byte{1, 2, 3, 4},
6228 Base64URL: [4]byte{1, 2, 3, 4},
6229 Array: [4]byte{1, 2, 3, 4},
6230 Default: [4]byte{1, 2, 3, 4},
6231 }),
6232 }, {
6233 name: jsontest.Name("Structs/Format/Bytes/Array"),
6234 opts: []Options{
6235 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *byte) error {
6236 if string(b) == "true" {
6237 *v = 1
6238 } else {
6239 *v = 0
6240 }
6241 return nil
6242 })),
6243 },
6244 inBuf: `{"Array":[false,true,false,true,false,true]}`,
6245 inVal: new(struct {
6246 Array []byte `json:",format:array"`
6247 }),
6248 want: addr(struct {
6249 Array []byte `json:",format:array"`
6250 }{
6251 Array: []byte{0, 1, 0, 1, 0, 1},
6252 }),
6253 }, {
6254 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base16/WrongKind"),
6255 inBuf: `{"Base16": [1,2,3,4]}`,
6256 inVal: new(structFormatBytes),
6257 wantErr: EU(nil).withPos(`{"Base16": `, "/Base16").withType('[', T[[]byte]()),
6258 }, {
6259 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base16/AllPadding"),
6260 inBuf: `{"Base16": "===="}`,
6261 inVal: new(structFormatBytes),
6262 wantErr: EU(func() error {
6263 _, err := hex.Decode(make([]byte, 2), []byte("====="))
6264 return err
6265 }()).withPos(`{"Base16": `, "/Base16").withType('"', T[[]byte]()),
6266 }, {
6267 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base16/EvenPadding"),
6268 inBuf: `{"Base16": "0123456789abcdef="}`,
6269 inVal: new(structFormatBytes),
6270 wantErr: EU(func() error {
6271 _, err := hex.Decode(make([]byte, 8), []byte("0123456789abcdef="))
6272 return err
6273 }()).withPos(`{"Base16": `, "/Base16").withType('"', T[[]byte]()),
6274 }, {
6275 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base16/OddPadding"),
6276 inBuf: `{"Base16": "0123456789abcdef0="}`,
6277 inVal: new(structFormatBytes),
6278 wantErr: EU(func() error {
6279 _, err := hex.Decode(make([]byte, 9), []byte("0123456789abcdef0="))
6280 return err
6281 }()).withPos(`{"Base16": `, "/Base16").withType('"', T[[]byte]()),
6282 }, {
6283 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base16/NonAlphabet/LineFeed"),
6284 inBuf: `{"Base16": "aa\naa"}`,
6285 inVal: new(structFormatBytes),
6286 wantErr: EU(func() error {
6287 _, err := hex.Decode(make([]byte, 9), []byte("aa\naa"))
6288 return err
6289 }()).withPos(`{"Base16": `, "/Base16").withType('"', T[[]byte]()),
6290 }, {
6291 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base16/NonAlphabet/CarriageReturn"),
6292 inBuf: `{"Base16": "aa\raa"}`,
6293 inVal: new(structFormatBytes),
6294 wantErr: EU(func() error {
6295 _, err := hex.Decode(make([]byte, 9), []byte("aa\raa"))
6296 return err
6297 }()).withPos(`{"Base16": `, "/Base16").withType('"', T[[]byte]()),
6298 }, {
6299 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base16/NonAlphabet/Space"),
6300 inBuf: `{"Base16": "aa aa"}`,
6301 inVal: new(structFormatBytes),
6302 wantErr: EU(func() error {
6303 _, err := hex.Decode(make([]byte, 9), []byte("aa aa"))
6304 return err
6305 }()).withPos(`{"Base16": `, "/Base16").withType('"', T[[]byte]()),
6306 }, {
6307 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base32/Padding"),
6308 inBuf: `[
6309 {"Base32": "NA======"},
6310 {"Base32": "NBSQ===="},
6311 {"Base32": "NBSWY==="},
6312 {"Base32": "NBSWY3A="},
6313 {"Base32": "NBSWY3DP"}
6314 ]`,
6315 inVal: new([]structFormatBytes),
6316 want: addr([]structFormatBytes{
6317 {Base32: []byte("h")},
6318 {Base32: []byte("he")},
6319 {Base32: []byte("hel")},
6320 {Base32: []byte("hell")},
6321 {Base32: []byte("hello")},
6322 }),
6323 }, {
6324 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base32/Invalid/NoPadding"),
6325 inBuf: `[
6326 {"Base32": "NA"},
6327 {"Base32": "NBSQ"},
6328 {"Base32": "NBSWY"},
6329 {"Base32": "NBSWY3A"},
6330 {"Base32": "NBSWY3DP"}
6331 ]`,
6332 inVal: new([]structFormatBytes),
6333 wantErr: EU(func() error {
6334 _, err := base32.StdEncoding.Decode(make([]byte, 1), []byte("NA"))
6335 return err
6336 }()).withPos(`[`+"\n\t\t\t\t"+`{"Base32": `, "/0/Base32").withType('"', T[[]byte]()),
6337 }, {
6338 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base32/WrongAlphabet"),
6339 inBuf: `{"Base32": "0123456789ABCDEFGHIJKLMNOPQRSTUV"}`,
6340 inVal: new(structFormatBytes),
6341 wantErr: EU(func() error {
6342 _, err := base32.StdEncoding.Decode(make([]byte, 20), []byte("0123456789ABCDEFGHIJKLMNOPQRSTUV"))
6343 return err
6344 }()).withPos(`{"Base32": `, "/Base32").withType('"', T[[]byte]()),
6345 }, {
6346 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base32Hex/WrongAlphabet"),
6347 inBuf: `{"Base32Hex": "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"}`,
6348 inVal: new(structFormatBytes),
6349 wantErr: EU(func() error {
6350 _, err := base32.HexEncoding.Decode(make([]byte, 20), []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"))
6351 return err
6352 }()).withPos(`{"Base32Hex": `, "/Base32Hex").withType('"', T[[]byte]()),
6353 }, {
6354 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base32/NonAlphabet/LineFeed"),
6355 inBuf: `{"Base32": "AAAA\nAAAA"}`,
6356 inVal: new(structFormatBytes),
6357 wantErr: EU(errors.New("illegal character '\\n' at offset 4")).withPos(`{"Base32": `, "/Base32").withType('"', T[[]byte]()),
6358 }, {
6359 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base32/NonAlphabet/CarriageReturn"),
6360 inBuf: `{"Base32": "AAAA\rAAAA"}`,
6361 inVal: new(structFormatBytes),
6362 wantErr: EU(errors.New("illegal character '\\r' at offset 4")).withPos(`{"Base32": `, "/Base32").withType('"', T[[]byte]()),
6363 }, {
6364 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base32/NonAlphabet/Space"),
6365 inBuf: `{"Base32": "AAAA AAAA"}`,
6366 inVal: new(structFormatBytes),
6367 wantErr: EU(base32.CorruptInputError(4)).withPos(`{"Base32": `, "/Base32").withType('"', T[[]byte]()),
6368 }, {
6369 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base64/WrongAlphabet"),
6370 inBuf: `{"Base64": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"}`,
6371 inVal: new(structFormatBytes),
6372 wantErr: EU(func() error {
6373 _, err := base64.StdEncoding.Decode(make([]byte, 48), []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"))
6374 return err
6375 }()).withPos(`{"Base64": `, "/Base64").withType('"', T[[]byte]()),
6376 }, {
6377 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base64URL/WrongAlphabet"),
6378 inBuf: `{"Base64URL": "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"}`,
6379 inVal: new(structFormatBytes),
6380 wantErr: EU(func() error {
6381 _, err := base64.URLEncoding.Decode(make([]byte, 48), []byte("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"))
6382 return err
6383 }()).withPos(`{"Base64URL": `, "/Base64URL").withType('"', T[[]byte]()),
6384 }, {
6385 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base64/NonAlphabet/LineFeed"),
6386 inBuf: `{"Base64": "aa=\n="}`,
6387 inVal: new(structFormatBytes),
6388 wantErr: EU(errors.New("illegal character '\\n' at offset 3")).withPos(`{"Base64": `, "/Base64").withType('"', T[[]byte]()),
6389 }, {
6390 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base64/NonAlphabet/CarriageReturn"),
6391 inBuf: `{"Base64": "aa=\r="}`,
6392 inVal: new(structFormatBytes),
6393 wantErr: EU(errors.New("illegal character '\\r' at offset 3")).withPos(`{"Base64": `, "/Base64").withType('"', T[[]byte]()),
6394 }, {
6395 name: jsontest.Name("Structs/Format/Bytes/Base64/NonAlphabet/Ignored"),
6396 opts: []Options{jsonflags.FormatBytesWithLegacySemantics | 1},
6397 inBuf: `{"Base64": "aa=\r\n="}`,
6398 inVal: new(structFormatBytes),
6399 want: &structFormatBytes{Base64: []byte{105}},
6400 }, {
6401 name: jsontest.Name("Structs/Format/Bytes/Invalid/Base64/NonAlphabet/Space"),
6402 inBuf: `{"Base64": "aa= ="}`,
6403 inVal: new(structFormatBytes),
6404 wantErr: EU(base64.CorruptInputError(2)).withPos(`{"Base64": `, "/Base64").withType('"', T[[]byte]()),
6405 }, {
6406 name: jsontest.Name("Structs/Format/Floats"),
6407 inBuf: `[
6408 {"NonFinite": 3.141592653589793, "PointerNonFinite": 3.141592653589793},
6409 {"NonFinite": "-Infinity", "PointerNonFinite": "-Infinity"},
6410 {"NonFinite": "Infinity", "PointerNonFinite": "Infinity"}
6411 ]`,
6412 inVal: new([]structFormatFloats),
6413 want: addr([]structFormatFloats{
6414 {NonFinite: math.Pi, PointerNonFinite: addr(math.Pi)},
6415 {NonFinite: math.Inf(-1), PointerNonFinite: addr(math.Inf(-1))},
6416 {NonFinite: math.Inf(+1), PointerNonFinite: addr(math.Inf(+1))},
6417 }),
6418 }, {
6419 name: jsontest.Name("Structs/Format/Floats/NaN"),
6420 inBuf: `{"NonFinite": "NaN"}`,
6421 inVal: new(structFormatFloats),
6422
6423 }, {
6424 name: jsontest.Name("Structs/Format/Floats/Invalid/NaN"),
6425 inBuf: `{"NonFinite": "nan"}`,
6426 inVal: new(structFormatFloats),
6427 wantErr: EU(nil).withPos(`{"NonFinite": `, "/NonFinite").withType('"', T[float64]()),
6428 }, {
6429 name: jsontest.Name("Structs/Format/Floats/Invalid/PositiveInfinity"),
6430 inBuf: `{"NonFinite": "+Infinity"}`,
6431 inVal: new(structFormatFloats),
6432 wantErr: EU(nil).withPos(`{"NonFinite": `, "/NonFinite").withType('"', T[float64]()),
6433 }, {
6434 name: jsontest.Name("Structs/Format/Floats/Invalid/NegativeInfinitySpace"),
6435 inBuf: `{"NonFinite": "-Infinity "}`,
6436 inVal: new(structFormatFloats),
6437 wantErr: EU(nil).withPos(`{"NonFinite": `, "/NonFinite").withType('"', T[float64]()),
6438 }, {
6439 name: jsontest.Name("Structs/Format/Maps"),
6440 inBuf: `[
6441 {"EmitNull": null, "PointerEmitNull": null, "EmitEmpty": null, "PointerEmitEmpty": null, "EmitDefault": null, "PointerEmitDefault": null},
6442 {"EmitNull": {}, "PointerEmitNull": {}, "EmitEmpty": {}, "PointerEmitEmpty": {}, "EmitDefault": {}, "PointerEmitDefault": {}},
6443 {"EmitNull": {"k": "v"}, "PointerEmitNull": {"k": "v"}, "EmitEmpty": {"k": "v"}, "PointerEmitEmpty": {"k": "v"}, "EmitDefault": {"k": "v"}, "PointerEmitDefault": {"k": "v"}}
6444 ]`,
6445 inVal: new([]structFormatMaps),
6446 want: addr([]structFormatMaps{{
6447 EmitNull: map[string]string(nil), PointerEmitNull: (*map[string]string)(nil),
6448 EmitEmpty: map[string]string(nil), PointerEmitEmpty: (*map[string]string)(nil),
6449 EmitDefault: map[string]string(nil), PointerEmitDefault: (*map[string]string)(nil),
6450 }, {
6451 EmitNull: map[string]string{}, PointerEmitNull: addr(map[string]string{}),
6452 EmitEmpty: map[string]string{}, PointerEmitEmpty: addr(map[string]string{}),
6453 EmitDefault: map[string]string{}, PointerEmitDefault: addr(map[string]string{}),
6454 }, {
6455 EmitNull: map[string]string{"k": "v"}, PointerEmitNull: addr(map[string]string{"k": "v"}),
6456 EmitEmpty: map[string]string{"k": "v"}, PointerEmitEmpty: addr(map[string]string{"k": "v"}),
6457 EmitDefault: map[string]string{"k": "v"}, PointerEmitDefault: addr(map[string]string{"k": "v"}),
6458 }}),
6459 }, {
6460 name: jsontest.Name("Structs/Format/Slices"),
6461 inBuf: `[
6462 {"EmitNull": null, "PointerEmitNull": null, "EmitEmpty": null, "PointerEmitEmpty": null, "EmitDefault": null, "PointerEmitDefault": null},
6463 {"EmitNull": [], "PointerEmitNull": [], "EmitEmpty": [], "PointerEmitEmpty": [], "EmitDefault": [], "PointerEmitDefault": []},
6464 {"EmitNull": ["v"], "PointerEmitNull": ["v"], "EmitEmpty": ["v"], "PointerEmitEmpty": ["v"], "EmitDefault": ["v"], "PointerEmitDefault": ["v"]}
6465 ]`,
6466 inVal: new([]structFormatSlices),
6467 want: addr([]structFormatSlices{{
6468 EmitNull: []string(nil), PointerEmitNull: (*[]string)(nil),
6469 EmitEmpty: []string(nil), PointerEmitEmpty: (*[]string)(nil),
6470 EmitDefault: []string(nil), PointerEmitDefault: (*[]string)(nil),
6471 }, {
6472 EmitNull: []string{}, PointerEmitNull: addr([]string{}),
6473 EmitEmpty: []string{}, PointerEmitEmpty: addr([]string{}),
6474 EmitDefault: []string{}, PointerEmitDefault: addr([]string{}),
6475 }, {
6476 EmitNull: []string{"v"}, PointerEmitNull: addr([]string{"v"}),
6477 EmitEmpty: []string{"v"}, PointerEmitEmpty: addr([]string{"v"}),
6478 EmitDefault: []string{"v"}, PointerEmitDefault: addr([]string{"v"}),
6479 }}),
6480 }, {
6481 name: jsontest.Name("Structs/Format/Invalid/Bool"),
6482 inBuf: `{"Bool":true}`,
6483 inVal: new(structFormatInvalid),
6484 wantErr: EU(errInvalidFormatFlag).withPos(`{"Bool":`, "/Bool").withType(0, T[bool]()),
6485 }, {
6486 name: jsontest.Name("Structs/Format/Invalid/String"),
6487 inBuf: `{"String": "string"}`,
6488 inVal: new(structFormatInvalid),
6489 wantErr: EU(errInvalidFormatFlag).withPos(`{"String": `, "/String").withType(0, T[string]()),
6490 }, {
6491 name: jsontest.Name("Structs/Format/Invalid/Bytes"),
6492 inBuf: `{"Bytes": "bytes"}`,
6493 inVal: new(structFormatInvalid),
6494 wantErr: EU(errInvalidFormatFlag).withPos(`{"Bytes": `, "/Bytes").withType(0, T[[]byte]()),
6495 }, {
6496 name: jsontest.Name("Structs/Format/Invalid/Int"),
6497 inBuf: `{"Int": 1}`,
6498 inVal: new(structFormatInvalid),
6499 wantErr: EU(errInvalidFormatFlag).withPos(`{"Int": `, "/Int").withType(0, T[int64]()),
6500 }, {
6501 name: jsontest.Name("Structs/Format/Invalid/Uint"),
6502 inBuf: `{"Uint": 1}`,
6503 inVal: new(structFormatInvalid),
6504 wantErr: EU(errInvalidFormatFlag).withPos(`{"Uint": `, "/Uint").withType(0, T[uint64]()),
6505 }, {
6506 name: jsontest.Name("Structs/Format/Invalid/Float"),
6507 inBuf: `{"Float" : 1}`,
6508 inVal: new(structFormatInvalid),
6509 wantErr: EU(errInvalidFormatFlag).withPos(`{"Float" : `, "/Float").withType(0, T[float64]()),
6510 }, {
6511 name: jsontest.Name("Structs/Format/Invalid/Map"),
6512 inBuf: `{"Map":{}}`,
6513 inVal: new(structFormatInvalid),
6514 wantErr: EU(errInvalidFormatFlag).withPos(`{"Map":`, "/Map").withType(0, T[map[string]string]()),
6515 }, {
6516 name: jsontest.Name("Structs/Format/Invalid/Struct"),
6517 inBuf: `{"Struct": {}}`,
6518 inVal: new(structFormatInvalid),
6519 wantErr: EU(errInvalidFormatFlag).withPos(`{"Struct": `, "/Struct").withType(0, T[structAll]()),
6520 }, {
6521 name: jsontest.Name("Structs/Format/Invalid/Slice"),
6522 inBuf: `{"Slice": {}}`,
6523 inVal: new(structFormatInvalid),
6524 wantErr: EU(errInvalidFormatFlag).withPos(`{"Slice": `, "/Slice").withType(0, T[[]string]()),
6525 }, {
6526 name: jsontest.Name("Structs/Format/Invalid/Array"),
6527 inBuf: `{"Array": []}`,
6528 inVal: new(structFormatInvalid),
6529 wantErr: EU(errInvalidFormatFlag).withPos(`{"Array": `, "/Array").withType(0, T[[1]string]()),
6530 }, {
6531 name: jsontest.Name("Structs/Format/Invalid/Interface"),
6532 inBuf: `{"Interface": "anything"}`,
6533 inVal: new(structFormatInvalid),
6534 wantErr: EU(errInvalidFormatFlag).withPos(`{"Interface": `, "/Interface").withType(0, T[any]()),
6535 }, {
6536 name: jsontest.Name("Structs/Inline/Zero"),
6537 inBuf: `{"D":""}`,
6538 inVal: new(structInlined),
6539 want: new(structInlined),
6540 }, {
6541 name: jsontest.Name("Structs/Inline/Alloc"),
6542 inBuf: `{"E":"","F":"","G":"","A":"","B":"","D":""}`,
6543 inVal: new(structInlined),
6544 want: addr(structInlined{
6545 X: structInlinedL1{
6546 X: &structInlinedL2{},
6547 StructEmbed1: StructEmbed1{},
6548 },
6549 StructEmbed2: &StructEmbed2{},
6550 }),
6551 }, {
6552 name: jsontest.Name("Structs/Inline/NonZero"),
6553 inBuf: `{"E":"E3","F":"F3","G":"G3","A":"A1","B":"B1","D":"D2"}`,
6554 inVal: new(structInlined),
6555 want: addr(structInlined{
6556 X: structInlinedL1{
6557 X: &structInlinedL2{A: "A1", B: "B1" },
6558 StructEmbed1: StructEmbed1{ D: "D2" },
6559 },
6560 StructEmbed2: &StructEmbed2{E: "E3", F: "F3", G: "G3"},
6561 }),
6562 }, {
6563 name: jsontest.Name("Structs/Inline/Merge"),
6564 inBuf: `{"E":"E3","F":"F3","G":"G3","A":"A1","B":"B1","D":"D2"}`,
6565 inVal: addr(structInlined{
6566 X: structInlinedL1{
6567 X: &structInlinedL2{B: "##", C: "C1"},
6568 StructEmbed1: StructEmbed1{C: "C2", E: "E2"},
6569 },
6570 StructEmbed2: &StructEmbed2{E: "##", G: "G3"},
6571 }),
6572 want: addr(structInlined{
6573 X: structInlinedL1{
6574 X: &structInlinedL2{A: "A1", B: "B1", C: "C1"},
6575 StructEmbed1: StructEmbed1{C: "C2", D: "D2", E: "E2"},
6576 },
6577 StructEmbed2: &StructEmbed2{E: "E3", F: "F3", G: "G3"},
6578 }),
6579 }, {
6580 name: jsontest.Name("Structs/InlinedFallback/TextValue/Noop"),
6581 inBuf: `{"A":1,"B":2}`,
6582 inVal: new(structInlineTextValue),
6583 want: addr(structInlineTextValue{A: 1, X: jsontext.Value(nil), B: 2}),
6584 }, {
6585 name: jsontest.Name("Structs/InlinedFallback/TextValue/MergeN1/Nil"),
6586 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6587 inVal: new(structInlineTextValue),
6588 want: addr(structInlineTextValue{A: 1, X: jsontext.Value(`{"fizz":"buzz"}`), B: 2}),
6589 }, {
6590 name: jsontest.Name("Structs/InlinedFallback/TextValue/MergeN1/Empty"),
6591 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6592 inVal: addr(structInlineTextValue{X: jsontext.Value{}}),
6593 want: addr(structInlineTextValue{A: 1, X: jsontext.Value(`{"fizz":"buzz"}`), B: 2}),
6594 }, {
6595 name: jsontest.Name("Structs/InlinedFallback/TextValue/MergeN1/Whitespace"),
6596 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6597 inVal: addr(structInlineTextValue{X: jsontext.Value("\n\r\t ")}),
6598 want: addr(structInlineTextValue{A: 1, X: jsontext.Value("")}),
6599 wantErr: EU(errRawInlinedNotObject).withPos(`{"A":1,`, "/fizz").withType('"', T[jsontext.Value]()),
6600 }, {
6601 name: jsontest.Name("Structs/InlinedFallback/TextValue/MergeN1/Null"),
6602 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6603 inVal: addr(structInlineTextValue{X: jsontext.Value("null")}),
6604 want: addr(structInlineTextValue{A: 1, X: jsontext.Value("null")}),
6605 wantErr: EU(errRawInlinedNotObject).withPos(`{"A":1,`, "/fizz").withType('"', T[jsontext.Value]()),
6606 }, {
6607 name: jsontest.Name("Structs/InlinedFallback/TextValue/MergeN1/ObjectN0"),
6608 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6609 inVal: addr(structInlineTextValue{X: jsontext.Value(` { } `)}),
6610 want: addr(structInlineTextValue{A: 1, X: jsontext.Value(` {"fizz":"buzz"}`), B: 2}),
6611 }, {
6612 name: jsontest.Name("Structs/InlinedFallback/TextValue/MergeN2/ObjectN1"),
6613 inBuf: `{"A":1,"fizz":"buzz","B":2,"foo": [ 1 , 2 , 3 ]}`,
6614 inVal: addr(structInlineTextValue{X: jsontext.Value(` { "fizz" : "buzz" } `)}),
6615 want: addr(structInlineTextValue{A: 1, X: jsontext.Value(` { "fizz" : "buzz","fizz":"buzz","foo":[ 1 , 2 , 3 ]}`), B: 2}),
6616 }, {
6617 name: jsontest.Name("Structs/InlinedFallback/TextValue/Merge/EndObject"),
6618 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6619 inVal: addr(structInlineTextValue{X: jsontext.Value(` } `)}),
6620
6621
6622 want: addr(structInlineTextValue{A: 1, X: jsontext.Value(`,"fizz":"buzz"}`), B: 2}),
6623 }, {
6624 name: jsontest.Name("Structs/InlinedFallback/TextValue/MergeInvalidValue"),
6625 inBuf: `{"A":1,"fizz":nil,"B":2}`,
6626 inVal: new(structInlineTextValue),
6627 want: addr(structInlineTextValue{A: 1, X: jsontext.Value(`{"fizz":`)}),
6628 wantErr: newInvalidCharacterError("i", "in literal null (expecting 'u')", len64(`{"A":1,"fizz":n`), "/fizz"),
6629 }, {
6630 name: jsontest.Name("Structs/InlinedFallback/TextValue/CaseSensitive"),
6631 inBuf: `{"A":1,"fizz":"buzz","B":2,"a":3}`,
6632 inVal: new(structInlineTextValue),
6633 want: addr(structInlineTextValue{A: 1, X: jsontext.Value(`{"fizz":"buzz","a":3}`), B: 2}),
6634 }, {
6635 name: jsontest.Name("Structs/InlinedFallback/TextValue/RejectDuplicateNames"),
6636 opts: []Options{jsontext.AllowDuplicateNames(false)},
6637 inBuf: `{"A":1,"fizz":"buzz","B":2,"fizz":"buzz"}`,
6638 inVal: new(structInlineTextValue),
6639 want: addr(structInlineTextValue{A: 1, X: jsontext.Value(`{"fizz":"buzz"}`), B: 2}),
6640 wantErr: newDuplicateNameError("", []byte(`"fizz"`), len64(`{"A":1,"fizz":"buzz","B":2,`)),
6641 }, {
6642 name: jsontest.Name("Structs/InlinedFallback/TextValue/AllowDuplicateNames"),
6643 opts: []Options{jsontext.AllowDuplicateNames(true)},
6644 inBuf: `{"A":1,"fizz":"buzz","B":2,"fizz":"buzz"}`,
6645 inVal: new(structInlineTextValue),
6646 want: addr(structInlineTextValue{A: 1, X: jsontext.Value(`{"fizz":"buzz","fizz":"buzz"}`), B: 2}),
6647 }, {
6648 name: jsontest.Name("Structs/InlinedFallback/TextValue/Nested/Noop"),
6649 inBuf: `{}`,
6650 inVal: new(structInlinePointerInlineTextValue),
6651 want: new(structInlinePointerInlineTextValue),
6652 }, {
6653 name: jsontest.Name("Structs/InlinedFallback/TextValue/Nested/Alloc"),
6654 inBuf: `{"A":1,"fizz":"buzz"}`,
6655 inVal: new(structInlinePointerInlineTextValue),
6656 want: addr(structInlinePointerInlineTextValue{
6657 X: &struct {
6658 A int
6659 X jsontext.Value `json:",inline"`
6660 }{A: 1, X: jsontext.Value(`{"fizz":"buzz"}`)},
6661 }),
6662 }, {
6663 name: jsontest.Name("Structs/InlinedFallback/TextValue/Nested/Merge"),
6664 inBuf: `{"fizz":"buzz"}`,
6665 inVal: addr(structInlinePointerInlineTextValue{
6666 X: &struct {
6667 A int
6668 X jsontext.Value `json:",inline"`
6669 }{A: 1},
6670 }),
6671 want: addr(structInlinePointerInlineTextValue{
6672 X: &struct {
6673 A int
6674 X jsontext.Value `json:",inline"`
6675 }{A: 1, X: jsontext.Value(`{"fizz":"buzz"}`)},
6676 }),
6677 }, {
6678 name: jsontest.Name("Structs/InlinedFallback/PointerTextValue/Noop"),
6679 inBuf: `{"A":1,"B":2}`,
6680 inVal: new(structInlinePointerTextValue),
6681 want: addr(structInlinePointerTextValue{A: 1, X: nil, B: 2}),
6682 }, {
6683 name: jsontest.Name("Structs/InlinedFallback/PointerTextValue/Alloc"),
6684 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6685 inVal: new(structInlinePointerTextValue),
6686 want: addr(structInlinePointerTextValue{A: 1, X: addr(jsontext.Value(`{"fizz":"buzz"}`)), B: 2}),
6687 }, {
6688 name: jsontest.Name("Structs/InlinedFallback/PointerTextValue/Merge"),
6689 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6690 inVal: addr(structInlinePointerTextValue{X: addr(jsontext.Value(`{"fizz":"buzz"}`))}),
6691 want: addr(structInlinePointerTextValue{A: 1, X: addr(jsontext.Value(`{"fizz":"buzz","fizz":"buzz"}`)), B: 2}),
6692 }, {
6693 name: jsontest.Name("Structs/InlinedFallback/PointerTextValue/Nested/Nil"),
6694 inBuf: `{"fizz":"buzz"}`,
6695 inVal: new(structInlineInlinePointerTextValue),
6696 want: addr(structInlineInlinePointerTextValue{
6697 X: struct {
6698 X *jsontext.Value `json:",inline"`
6699 }{X: addr(jsontext.Value(`{"fizz":"buzz"}`))},
6700 }),
6701 }, {
6702 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/Noop"),
6703 inBuf: `{"A":1,"B":2}`,
6704 inVal: new(structInlineMapStringAny),
6705 want: addr(structInlineMapStringAny{A: 1, X: nil, B: 2}),
6706 }, {
6707 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/MergeN1/Nil"),
6708 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6709 inVal: new(structInlineMapStringAny),
6710 want: addr(structInlineMapStringAny{A: 1, X: jsonObject{"fizz": "buzz"}, B: 2}),
6711 }, {
6712 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/MergeN1/Empty"),
6713 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6714 inVal: addr(structInlineMapStringAny{X: jsonObject{}}),
6715 want: addr(structInlineMapStringAny{A: 1, X: jsonObject{"fizz": "buzz"}, B: 2}),
6716 }, {
6717 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/MergeN1/ObjectN1"),
6718 inBuf: `{"A":1,"fizz":{"charlie":"DELTA","echo":"foxtrot"},"B":2}`,
6719 inVal: addr(structInlineMapStringAny{X: jsonObject{"fizz": jsonObject{
6720 "alpha": "bravo",
6721 "charlie": "delta",
6722 }}}),
6723 want: addr(structInlineMapStringAny{A: 1, X: jsonObject{"fizz": jsonObject{
6724 "alpha": "bravo",
6725 "charlie": "DELTA",
6726 "echo": "foxtrot",
6727 }}, B: 2}),
6728 }, {
6729 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/MergeN2/ObjectN1"),
6730 inBuf: `{"A":1,"fizz":"buzz","B":2,"foo": [ 1 , 2 , 3 ]}`,
6731 inVal: addr(structInlineMapStringAny{X: jsonObject{"fizz": "wuzz"}}),
6732 want: addr(structInlineMapStringAny{A: 1, X: jsonObject{"fizz": "buzz", "foo": jsonArray{1.0, 2.0, 3.0}}, B: 2}),
6733 }, {
6734 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/MergeInvalidValue"),
6735 inBuf: `{"A":1,"fizz":nil,"B":2}`,
6736 inVal: new(structInlineMapStringAny),
6737 want: addr(structInlineMapStringAny{A: 1, X: jsonObject{"fizz": nil}}),
6738 wantErr: newInvalidCharacterError("i", "in literal null (expecting 'u')", len64(`{"A":1,"fizz":n`), "/fizz"),
6739 }, {
6740 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/MergeInvalidValue/Existing"),
6741 inBuf: `{"A":1,"fizz":nil,"B":2}`,
6742 inVal: addr(structInlineMapStringAny{A: 1, X: jsonObject{"fizz": true}}),
6743 want: addr(structInlineMapStringAny{A: 1, X: jsonObject{"fizz": true}}),
6744 wantErr: newInvalidCharacterError("i", "in literal null (expecting 'u')", len64(`{"A":1,"fizz":n`), "/fizz"),
6745 }, {
6746 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/CaseSensitive"),
6747 inBuf: `{"A":1,"fizz":"buzz","B":2,"a":3}`,
6748 inVal: new(structInlineMapStringAny),
6749 want: addr(structInlineMapStringAny{A: 1, X: jsonObject{"fizz": "buzz", "a": 3.0}, B: 2}),
6750 }, {
6751 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/RejectDuplicateNames"),
6752 opts: []Options{jsontext.AllowDuplicateNames(false)},
6753 inBuf: `{"A":1,"fizz":"buzz","B":2,"fizz":"buzz"}`,
6754 inVal: new(structInlineMapStringAny),
6755 want: addr(structInlineMapStringAny{A: 1, X: jsonObject{"fizz": "buzz"}, B: 2}),
6756 wantErr: newDuplicateNameError("", []byte(`"fizz"`), len64(`{"A":1,"fizz":"buzz","B":2,`)),
6757 }, {
6758 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/AllowDuplicateNames"),
6759 opts: []Options{jsontext.AllowDuplicateNames(true)},
6760 inBuf: `{"A":1,"fizz":{"one":1,"two":-2},"B":2,"fizz":{"two":2,"three":3}}`,
6761 inVal: new(structInlineMapStringAny),
6762 want: addr(structInlineMapStringAny{A: 1, X: jsonObject{"fizz": jsonObject{"one": 1.0, "two": 2.0, "three": 3.0}}, B: 2}),
6763 }, {
6764 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/Nested/Noop"),
6765 inBuf: `{}`,
6766 inVal: new(structInlinePointerInlineMapStringAny),
6767 want: new(structInlinePointerInlineMapStringAny),
6768 }, {
6769 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/Nested/Alloc"),
6770 inBuf: `{"A":1,"fizz":"buzz"}`,
6771 inVal: new(structInlinePointerInlineMapStringAny),
6772 want: addr(structInlinePointerInlineMapStringAny{
6773 X: &struct {
6774 A int
6775 X jsonObject `json:",inline"`
6776 }{A: 1, X: jsonObject{"fizz": "buzz"}},
6777 }),
6778 }, {
6779 name: jsontest.Name("Structs/InlinedFallback/MapStringAny/Nested/Merge"),
6780 inBuf: `{"fizz":"buzz"}`,
6781 inVal: addr(structInlinePointerInlineMapStringAny{
6782 X: &struct {
6783 A int
6784 X jsonObject `json:",inline"`
6785 }{A: 1},
6786 }),
6787 want: addr(structInlinePointerInlineMapStringAny{
6788 X: &struct {
6789 A int
6790 X jsonObject `json:",inline"`
6791 }{A: 1, X: jsonObject{"fizz": "buzz"}},
6792 }),
6793 }, {
6794 name: jsontest.Name("Structs/InlinedFallback/MapStringInt/UnmarshalFunc"),
6795 opts: []Options{
6796 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *any) error {
6797 var err error
6798 *v, err = strconv.ParseFloat(string(bytes.Trim(b, `"`)), 64)
6799 return err
6800 })),
6801 },
6802 inBuf: `{"D":"1.1","E":"2.2","F":"3.3"}`,
6803 inVal: new(structInlineMapStringAny),
6804 want: addr(structInlineMapStringAny{X: jsonObject{"D": 1.1, "E": 2.2, "F": 3.3}}),
6805 }, {
6806 name: jsontest.Name("Structs/InlinedFallback/PointerMapStringAny/Noop"),
6807 inBuf: `{"A":1,"B":2}`,
6808 inVal: new(structInlinePointerMapStringAny),
6809 want: addr(structInlinePointerMapStringAny{A: 1, X: nil, B: 2}),
6810 }, {
6811 name: jsontest.Name("Structs/InlinedFallback/PointerMapStringAny/Alloc"),
6812 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6813 inVal: new(structInlinePointerMapStringAny),
6814 want: addr(structInlinePointerMapStringAny{A: 1, X: addr(jsonObject{"fizz": "buzz"}), B: 2}),
6815 }, {
6816 name: jsontest.Name("Structs/InlinedFallback/PointerMapStringAny/Merge"),
6817 inBuf: `{"A":1,"fizz":"wuzz","B":2}`,
6818 inVal: addr(structInlinePointerMapStringAny{X: addr(jsonObject{"fizz": "buzz"})}),
6819 want: addr(structInlinePointerMapStringAny{A: 1, X: addr(jsonObject{"fizz": "wuzz"}), B: 2}),
6820 }, {
6821 name: jsontest.Name("Structs/InlinedFallback/PointerMapStringAny/Nested/Nil"),
6822 inBuf: `{"fizz":"buzz"}`,
6823 inVal: new(structInlineInlinePointerMapStringAny),
6824 want: addr(structInlineInlinePointerMapStringAny{
6825 X: struct {
6826 X *jsonObject `json:",inline"`
6827 }{X: addr(jsonObject{"fizz": "buzz"})},
6828 }),
6829 }, {
6830 name: jsontest.Name("Structs/InlinedFallback/MapStringInt"),
6831 inBuf: `{"zero": 0, "one": 1, "two": 2}`,
6832 inVal: new(structInlineMapStringInt),
6833 want: addr(structInlineMapStringInt{
6834 X: map[string]int{"zero": 0, "one": 1, "two": 2},
6835 }),
6836 }, {
6837 name: jsontest.Name("Structs/InlinedFallback/MapStringInt/Null"),
6838 inBuf: `{"zero": 0, "one": null, "two": 2}`,
6839 inVal: new(structInlineMapStringInt),
6840 want: addr(structInlineMapStringInt{
6841 X: map[string]int{"zero": 0, "one": 0, "two": 2},
6842 }),
6843 }, {
6844 name: jsontest.Name("Structs/InlinedFallback/MapStringInt/Invalid"),
6845 inBuf: `{"zero": 0, "one": {}, "two": 2}`,
6846 inVal: new(structInlineMapStringInt),
6847 want: addr(structInlineMapStringInt{
6848 X: map[string]int{"zero": 0, "one": 0},
6849 }),
6850 wantErr: EU(nil).withPos(`{"zero": 0, "one": `, "/one").withType('{', T[int]()),
6851 }, {
6852 name: jsontest.Name("Structs/InlinedFallback/MapStringInt/StringifiedNumbers"),
6853 opts: []Options{StringifyNumbers(true)},
6854 inBuf: `{"zero": "0", "one": "1", "two": "2"}`,
6855 inVal: new(structInlineMapStringInt),
6856 want: addr(structInlineMapStringInt{
6857 X: map[string]int{"zero": 0, "one": 1, "two": 2},
6858 }),
6859 }, {
6860 name: jsontest.Name("Structs/InlinedFallback/MapStringInt/UnmarshalFunc"),
6861 opts: []Options{
6862 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *int) error {
6863 i, err := strconv.ParseInt(string(bytes.Trim(b, `"`)), 10, 64)
6864 if err != nil {
6865 return err
6866 }
6867 *v = int(i)
6868 return nil
6869 })),
6870 },
6871 inBuf: `{"zero": "0", "one": "1", "two": "2"}`,
6872 inVal: new(structInlineMapStringInt),
6873 want: addr(structInlineMapStringInt{
6874 X: map[string]int{"zero": 0, "one": 1, "two": 2},
6875 }),
6876 }, {
6877 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringInt"),
6878 inBuf: `{"zero": 0, "one": 1, "two": 2}`,
6879 inVal: new(structInlineMapNamedStringInt),
6880 want: addr(structInlineMapNamedStringInt{
6881 X: map[namedString]int{"zero": 0, "one": 1, "two": 2},
6882 }),
6883 }, {
6884 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringInt/Null"),
6885 inBuf: `{"zero": 0, "one": null, "two": 2}`,
6886 inVal: new(structInlineMapNamedStringInt),
6887 want: addr(structInlineMapNamedStringInt{
6888 X: map[namedString]int{"zero": 0, "one": 0, "two": 2},
6889 }),
6890 }, {
6891 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringInt/Invalid"),
6892 inBuf: `{"zero": 0, "one": {}, "two": 2}`,
6893 inVal: new(structInlineMapNamedStringInt),
6894 want: addr(structInlineMapNamedStringInt{
6895 X: map[namedString]int{"zero": 0, "one": 0},
6896 }),
6897 wantErr: EU(nil).withPos(`{"zero": 0, "one": `, "/one").withType('{', T[int]()),
6898 }, {
6899 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringInt/StringifiedNumbers"),
6900 opts: []Options{StringifyNumbers(true)},
6901 inBuf: `{"zero": "0", "one": 1, "two": "2"}`,
6902 inVal: new(structInlineMapNamedStringInt),
6903 want: addr(structInlineMapNamedStringInt{
6904 X: map[namedString]int{"zero": 0, "one": 0},
6905 }),
6906 wantErr: EU(nil).withPos(`{"zero": "0", "one": `, "/one").withType('0', T[int]()),
6907 }, {
6908 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringInt/UnmarshalFunc"),
6909 opts: []Options{
6910 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *int) error {
6911 i, err := strconv.ParseInt(string(bytes.Trim(b, `"`)), 10, 64)
6912 if err != nil {
6913 return err
6914 }
6915 *v = int(i)
6916 return nil
6917 })),
6918 },
6919 inBuf: `{"zero": "0", "one": "1", "two": "2"}`,
6920 inVal: new(structInlineMapNamedStringInt),
6921 want: addr(structInlineMapNamedStringInt{
6922 X: map[namedString]int{"zero": 0, "one": 1, "two": 2},
6923 }),
6924 }, {
6925 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/Noop"),
6926 inBuf: `{"A":1,"B":2}`,
6927 inVal: new(structInlineMapNamedStringAny),
6928 want: addr(structInlineMapNamedStringAny{A: 1, X: nil, B: 2}),
6929 }, {
6930 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/MergeN1/Nil"),
6931 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6932 inVal: new(structInlineMapNamedStringAny),
6933 want: addr(structInlineMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": "buzz"}, B: 2}),
6934 }, {
6935 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/MergeN1/Empty"),
6936 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6937 inVal: addr(structInlineMapNamedStringAny{X: map[namedString]any{}}),
6938 want: addr(structInlineMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": "buzz"}, B: 2}),
6939 }, {
6940 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/MergeN1/ObjectN1"),
6941 inBuf: `{"A":1,"fizz":{"charlie":"DELTA","echo":"foxtrot"},"B":2}`,
6942 inVal: addr(structInlineMapNamedStringAny{X: map[namedString]any{"fizz": jsonObject{
6943 "alpha": "bravo",
6944 "charlie": "delta",
6945 }}}),
6946 want: addr(structInlineMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": jsonObject{
6947 "alpha": "bravo",
6948 "charlie": "DELTA",
6949 "echo": "foxtrot",
6950 }}, B: 2}),
6951 }, {
6952 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/MergeN2/ObjectN1"),
6953 inBuf: `{"A":1,"fizz":"buzz","B":2,"foo": [ 1 , 2 , 3 ]}`,
6954 inVal: addr(structInlineMapNamedStringAny{X: map[namedString]any{"fizz": "wuzz"}}),
6955 want: addr(structInlineMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": "buzz", "foo": jsonArray{1.0, 2.0, 3.0}}, B: 2}),
6956 }, {
6957 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/MergeInvalidValue"),
6958 inBuf: `{"A":1,"fizz":nil,"B":2}`,
6959 inVal: new(structInlineMapNamedStringAny),
6960 want: addr(structInlineMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": nil}}),
6961 wantErr: newInvalidCharacterError("i", "in literal null (expecting 'u')", len64(`{"A":1,"fizz":n`), "/fizz"),
6962 }, {
6963 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/MergeInvalidValue/Existing"),
6964 inBuf: `{"A":1,"fizz":nil,"B":2}`,
6965 inVal: addr(structInlineMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": true}}),
6966 want: addr(structInlineMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": true}}),
6967 wantErr: newInvalidCharacterError("i", "in literal null (expecting 'u')", len64(`{"A":1,"fizz":n`), "/fizz"),
6968 }, {
6969 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/CaseSensitive"),
6970 inBuf: `{"A":1,"fizz":"buzz","B":2,"a":3}`,
6971 inVal: new(structInlineMapNamedStringAny),
6972 want: addr(structInlineMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": "buzz", "a": 3.0}, B: 2}),
6973 }, {
6974 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/RejectDuplicateNames"),
6975 opts: []Options{jsontext.AllowDuplicateNames(false)},
6976 inBuf: `{"A":1,"fizz":"buzz","B":2,"fizz":"buzz"}`,
6977 inVal: new(structInlineMapNamedStringAny),
6978 want: addr(structInlineMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": "buzz"}, B: 2}),
6979 wantErr: newDuplicateNameError("", []byte(`"fizz"`), len64(`{"A":1,"fizz":"buzz","B":2,`)),
6980 }, {
6981 name: jsontest.Name("Structs/InlinedFallback/MapNamedStringAny/AllowDuplicateNames"),
6982 opts: []Options{jsontext.AllowDuplicateNames(true)},
6983 inBuf: `{"A":1,"fizz":{"one":1,"two":-2},"B":2,"fizz":{"two":2,"three":3}}`,
6984 inVal: new(structInlineMapNamedStringAny),
6985 want: addr(structInlineMapNamedStringAny{A: 1, X: map[namedString]any{"fizz": map[string]any{"one": 1.0, "two": 2.0, "three": 3.0}}, B: 2}),
6986 }, {
6987 name: jsontest.Name("Structs/InlinedFallback/RejectUnknownMembers"),
6988 opts: []Options{RejectUnknownMembers(true)},
6989 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
6990 inVal: new(structInlineTextValue),
6991
6992 want: addr(structInlineTextValue{
6993 A: 1,
6994 X: jsontext.Value(`{"fizz":"buzz"}`),
6995 B: 2,
6996 }),
6997 }, {
6998 name: jsontest.Name("Structs/UnknownFallback/RejectUnknownMembers"),
6999 opts: []Options{RejectUnknownMembers(true)},
7000 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
7001 inVal: new(structUnknownTextValue),
7002 want: addr(structUnknownTextValue{A: 1}),
7003 wantErr: EU(ErrUnknownName).withPos(`{"A":1,`, "/fizz").withType('"', T[structUnknownTextValue]()),
7004 }, {
7005 name: jsontest.Name("Structs/UnknownFallback"),
7006 inBuf: `{"A":1,"fizz":"buzz","B":2}`,
7007 inVal: new(structUnknownTextValue),
7008 want: addr(structUnknownTextValue{
7009 A: 1,
7010 X: jsontext.Value(`{"fizz":"buzz"}`),
7011 B: 2,
7012 }),
7013 }, {
7014 name: jsontest.Name("Structs/UnknownIgnored"),
7015 opts: []Options{RejectUnknownMembers(false)},
7016 inBuf: `{"unknown":"fizzbuzz"}`,
7017 inVal: new(structAll),
7018 want: new(structAll),
7019 }, {
7020 name: jsontest.Name("Structs/RejectUnknownMembers"),
7021 opts: []Options{RejectUnknownMembers(true)},
7022 inBuf: `{"unknown":"fizzbuzz"}`,
7023 inVal: new(structAll),
7024 want: new(structAll),
7025 wantErr: EU(ErrUnknownName).withPos(`{`, "/unknown").withType('"', T[structAll]()),
7026 }, {
7027 name: jsontest.Name("Structs/UnexportedIgnored"),
7028 inBuf: `{"ignored":"unused"}`,
7029 inVal: new(structUnexportedIgnored),
7030 want: new(structUnexportedIgnored),
7031 }, {
7032 name: jsontest.Name("Structs/IgnoredUnexportedEmbedded"),
7033 inBuf: `{"namedString":"unused"}`,
7034 inVal: new(structIgnoredUnexportedEmbedded),
7035 want: new(structIgnoredUnexportedEmbedded),
7036 }, {
7037 name: jsontest.Name("Structs/WeirdNames"),
7038 inBuf: `{"":"empty",",":"comma","\"":"quote"}`,
7039 inVal: new(structWeirdNames),
7040 want: addr(structWeirdNames{Empty: "empty", Comma: "comma", Quote: "quote"}),
7041 }, {
7042 name: jsontest.Name("Structs/NoCase/Exact"),
7043 inBuf: `{"Aaa":"Aaa","AA_A":"AA_A","AaA":"AaA","AAa":"AAa","AAA":"AAA"}`,
7044 inVal: new(structNoCase),
7045 want: addr(structNoCase{AaA: "AaA", AAa: "AAa", Aaa: "Aaa", AAA: "AAA", AA_A: "AA_A"}),
7046 }, {
7047 name: jsontest.Name("Structs/NoCase/CaseInsensitiveDefault"),
7048 inBuf: `{"aa_a":"aa_a"}`,
7049 inVal: new(structNoCase),
7050 want: addr(structNoCase{AaA: "aa_a"}),
7051 }, {
7052 name: jsontest.Name("Structs/NoCase/MatchCaseSensitiveDelimiter"),
7053 opts: []Options{jsonflags.MatchCaseSensitiveDelimiter | 1},
7054 inBuf: `{"aa_a":"aa_a"}`,
7055 inVal: new(structNoCase),
7056 want: addr(structNoCase{}),
7057 }, {
7058 name: jsontest.Name("Structs/NoCase/MatchCaseInsensitiveNames+MatchCaseSensitiveDelimiter"),
7059 opts: []Options{MatchCaseInsensitiveNames(true), jsonflags.MatchCaseSensitiveDelimiter | 1},
7060 inBuf: `{"aa_a":"aa_a"}`,
7061 inVal: new(structNoCase),
7062 want: addr(structNoCase{AA_A: "aa_a"}),
7063 }, {
7064 name: jsontest.Name("Structs/NoCase/Merge/AllowDuplicateNames"),
7065 opts: []Options{jsontext.AllowDuplicateNames(true)},
7066 inBuf: `{"AaA":"AaA","aaa":"aaa","aAa":"aAa"}`,
7067 inVal: new(structNoCase),
7068 want: addr(structNoCase{AaA: "aAa"}),
7069 }, {
7070 name: jsontest.Name("Structs/NoCase/Merge/RejectDuplicateNames"),
7071 opts: []Options{jsontext.AllowDuplicateNames(false)},
7072 inBuf: `{"AaA":"AaA","aaa":"aaa"}`,
7073 inVal: new(structNoCase),
7074 want: addr(structNoCase{AaA: "AaA"}),
7075 wantErr: newDuplicateNameError("", []byte(`"aaa"`), len64(`{"AaA":"AaA",`)),
7076 }, {
7077 name: jsontest.Name("Structs/CaseSensitive"),
7078 inBuf: `{"BOOL": true, "STRING": "hello", "BYTES": "AQID", "INT": -64, "UINT": 64, "FLOAT": 3.14159}`,
7079 inVal: new(structScalars),
7080 want: addr(structScalars{}),
7081 }, {
7082 name: jsontest.Name("Structs/DuplicateName/NoCase/ExactDifferent"),
7083 inBuf: `{"AAA":"AAA","AaA":"AaA","AAa":"AAa","Aaa":"Aaa"}`,
7084 inVal: addr(structNoCaseInlineTextValue{}),
7085 want: addr(structNoCaseInlineTextValue{AAA: "AAA", AaA: "AaA", AAa: "AAa", Aaa: "Aaa"}),
7086 }, {
7087 name: jsontest.Name("Structs/DuplicateName/NoCase/ExactConflict"),
7088 inBuf: `{"AAA":"AAA","AAA":"AAA"}`,
7089 inVal: addr(structNoCaseInlineTextValue{}),
7090 want: addr(structNoCaseInlineTextValue{AAA: "AAA"}),
7091 wantErr: newDuplicateNameError("", []byte(`"AAA"`), len64(`{"AAA":"AAA",`)),
7092 }, {
7093 name: jsontest.Name("Structs/DuplicateName/NoCase/OverwriteExact"),
7094 inBuf: `{"AAA":"after"}`,
7095 inVal: addr(structNoCaseInlineTextValue{AAA: "before"}),
7096 want: addr(structNoCaseInlineTextValue{AAA: "after"}),
7097 }, {
7098 name: jsontest.Name("Structs/DuplicateName/NoCase/NoCaseConflict"),
7099 inBuf: `{"aaa":"aaa","aaA":"aaA"}`,
7100 inVal: addr(structNoCaseInlineTextValue{}),
7101 want: addr(structNoCaseInlineTextValue{AaA: "aaa"}),
7102 wantErr: newDuplicateNameError("", []byte(`"aaA"`), len64(`{"aaa":"aaa",`)),
7103 }, {
7104 name: jsontest.Name("Structs/DuplicateName/NoCase/OverwriteNoCase"),
7105 inBuf: `{"aaa":"aaa","aaA":"aaA"}`,
7106 inVal: addr(structNoCaseInlineTextValue{}),
7107 want: addr(structNoCaseInlineTextValue{AaA: "aaa"}),
7108 wantErr: newDuplicateNameError("", []byte(`"aaA"`), len64(`{"aaa":"aaa",`)),
7109 }, {
7110 name: jsontest.Name("Structs/DuplicateName/Inline/Unknown"),
7111 inBuf: `{"unknown":""}`,
7112 inVal: addr(structNoCaseInlineTextValue{}),
7113 want: addr(structNoCaseInlineTextValue{X: jsontext.Value(`{"unknown":""}`)}),
7114 }, {
7115 name: jsontest.Name("Structs/DuplicateName/Inline/UnknownMerge"),
7116 inBuf: `{"unknown":""}`,
7117 inVal: addr(structNoCaseInlineTextValue{X: jsontext.Value(`{"unknown":""}`)}),
7118 want: addr(structNoCaseInlineTextValue{X: jsontext.Value(`{"unknown":"","unknown":""}`)}),
7119 }, {
7120 name: jsontest.Name("Structs/DuplicateName/Inline/NoCaseOkay"),
7121 inBuf: `{"b":"","B":""}`,
7122 inVal: addr(structNoCaseInlineTextValue{}),
7123 want: addr(structNoCaseInlineTextValue{X: jsontext.Value(`{"b":"","B":""}`)}),
7124 }, {
7125 name: jsontest.Name("Structs/DuplicateName/Inline/ExactConflict"),
7126 inBuf: `{"b":"","b":""}`,
7127 inVal: addr(structNoCaseInlineTextValue{}),
7128 want: addr(structNoCaseInlineTextValue{X: jsontext.Value(`{"b":""}`)}),
7129 wantErr: newDuplicateNameError("", []byte(`"b"`), len64(`{"b":"",`)),
7130 }, {
7131 name: jsontest.Name("Structs/Invalid/ErrUnexpectedEOF"),
7132 inBuf: ``,
7133 inVal: addr(structAll{}),
7134 want: addr(structAll{}),
7135 wantErr: io.ErrUnexpectedEOF,
7136 }, {
7137 name: jsontest.Name("Structs/Invalid/NestedErrUnexpectedEOF"),
7138 inBuf: `{"Pointer":`,
7139 inVal: addr(structAll{}),
7140 want: addr(structAll{Pointer: new(structAll)}),
7141 wantErr: &jsontext.SyntacticError{ByteOffset: len64(`{"Pointer":`), JSONPointer: "/Pointer", Err: io.ErrUnexpectedEOF},
7142 }, {
7143 name: jsontest.Name("Structs/Invalid/Conflicting"),
7144 inBuf: `{}`,
7145 inVal: addr(structConflicting{}),
7146 want: addr(structConflicting{}),
7147 wantErr: EU(errors.New(`Go struct fields A and B conflict over JSON object name "conflict"`)).withType('{', T[structConflicting]()),
7148 }, {
7149 name: jsontest.Name("Structs/Invalid/NoneExported"),
7150 inBuf: ` {}`,
7151 inVal: addr(structNoneExported{}),
7152 want: addr(structNoneExported{}),
7153 wantErr: EU(errNoExportedFields).withPos(` `, "").withType('{', T[structNoneExported]()),
7154 }, {
7155 name: jsontest.Name("Structs/Invalid/MalformedTag"),
7156 inBuf: `{}`,
7157 inVal: addr(structMalformedTag{}),
7158 want: addr(structMalformedTag{}),
7159 wantErr: EU(errors.New("Go struct field Malformed has malformed `json` tag: invalid character '\"' at start of option (expecting Unicode letter or single quote)")).withType('{', T[structMalformedTag]()),
7160 }, {
7161 name: jsontest.Name("Structs/Invalid/UnexportedTag"),
7162 inBuf: `{}`,
7163 inVal: addr(structUnexportedTag{}),
7164 want: addr(structUnexportedTag{}),
7165 wantErr: EU(errors.New("unexported Go struct field unexported cannot have non-ignored `json:\"name\"` tag")).withType('{', T[structUnexportedTag]()),
7166 }, {
7167 name: jsontest.Name("Structs/Invalid/ExportedEmbedded"),
7168 inBuf: `{"NamedString":"hello"}`,
7169 inVal: addr(structExportedEmbedded{}),
7170 want: addr(structExportedEmbedded{}),
7171 wantErr: EU(errors.New("embedded Go struct field NamedString of non-struct type must be explicitly given a JSON name")).withType('{', T[structExportedEmbedded]()),
7172 }, {
7173 name: jsontest.Name("Structs/Valid/ExportedEmbedded"),
7174 opts: []Options{jsonflags.ReportErrorsWithLegacySemantics | 1},
7175 inBuf: `{"NamedString":"hello"}`,
7176 inVal: addr(structExportedEmbedded{}),
7177 want: addr(structExportedEmbedded{"hello"}),
7178 }, {
7179 name: jsontest.Name("Structs/Valid/ExportedEmbeddedTag"),
7180 inBuf: `{"name":"hello"}`,
7181 inVal: addr(structExportedEmbeddedTag{}),
7182 want: addr(structExportedEmbeddedTag{"hello"}),
7183 }, {
7184 name: jsontest.Name("Structs/Invalid/UnexportedEmbedded"),
7185 inBuf: `{}`,
7186 inVal: addr(structUnexportedEmbedded{}),
7187 want: addr(structUnexportedEmbedded{}),
7188 wantErr: EU(errors.New("embedded Go struct field namedString of non-struct type must be explicitly given a JSON name")).withType('{', T[structUnexportedEmbedded]()),
7189 }, {
7190 name: jsontest.Name("Structs/UnexportedEmbeddedStruct"),
7191 inBuf: `{"Bool":true,"FizzBuzz":5,"Addr":"192.168.0.1"}`,
7192 inVal: addr(structUnexportedEmbeddedStruct{}),
7193 want: addr(structUnexportedEmbeddedStruct{structOmitZeroAll{Bool: true}, 5, structNestedAddr{netip.AddrFrom4([4]byte{192, 168, 0, 1})}}),
7194 }, {
7195 name: jsontest.Name("Structs/UnexportedEmbeddedStructPointer/Nil"),
7196 inBuf: `{"Bool":true,"FizzBuzz":5}`,
7197 inVal: addr(structUnexportedEmbeddedStructPointer{}),
7198 wantErr: EU(errNilField).withPos(`{"Bool":`, "/Bool").withType(0, T[structUnexportedEmbeddedStructPointer]()),
7199 }, {
7200 name: jsontest.Name("Structs/UnexportedEmbeddedStructPointer/Nil"),
7201 inBuf: `{"FizzBuzz":5,"Addr":"192.168.0.1"}`,
7202 inVal: addr(structUnexportedEmbeddedStructPointer{}),
7203 wantErr: EU(errNilField).withPos(`{"FizzBuzz":5,"Addr":`, "/Addr").withType(0, T[structUnexportedEmbeddedStructPointer]()),
7204 }, {
7205 name: jsontest.Name("Structs/UnexportedEmbeddedStructPointer/Nil"),
7206 inBuf: `{"Bool":true,"FizzBuzz":10,"Addr":"192.168.0.1"}`,
7207 inVal: addr(structUnexportedEmbeddedStructPointer{&structOmitZeroAll{Int: 5}, 5, &structNestedAddr{netip.AddrFrom4([4]byte{127, 0, 0, 1})}}),
7208 want: addr(structUnexportedEmbeddedStructPointer{&structOmitZeroAll{Bool: true, Int: 5}, 10, &structNestedAddr{netip.AddrFrom4([4]byte{192, 168, 0, 1})}}),
7209 }, {
7210 name: jsontest.Name("Structs/Unknown"),
7211 inBuf: `{
7212 "object0": {},
7213 "object1": {"key1": "value"},
7214 "object2": {"key1": "value", "key2": "value"},
7215 "objects": {"":{"":{"":{}}}},
7216 "array0": [],
7217 "array1": ["value1"],
7218 "array2": ["value1", "value2"],
7219 "array": [[[]]],
7220 "scalars": [null, false, true, "string", 12.345]
7221 }`,
7222 inVal: addr(struct{}{}),
7223 want: addr(struct{}{}),
7224 }, {
7225 name: jsontest.Name("Structs/IgnoreInvalidFormat"),
7226 opts: []Options{invalidFormatOption},
7227 inBuf: `{"Field":"Value"}`,
7228 inVal: addr(struct{ Field string }{}),
7229 want: addr(struct{ Field string }{"Value"}),
7230 }, {
7231 name: jsontest.Name("Slices/Null"),
7232 inBuf: `null`,
7233 inVal: addr([]string{"something"}),
7234 want: addr([]string(nil)),
7235 }, {
7236 name: jsontest.Name("Slices/Bool"),
7237 inBuf: `[true,false]`,
7238 inVal: new([]bool),
7239 want: addr([]bool{true, false}),
7240 }, {
7241 name: jsontest.Name("Slices/String"),
7242 inBuf: `["hello","goodbye"]`,
7243 inVal: new([]string),
7244 want: addr([]string{"hello", "goodbye"}),
7245 }, {
7246 name: jsontest.Name("Slices/Bytes"),
7247 inBuf: `["aGVsbG8=","Z29vZGJ5ZQ=="]`,
7248 inVal: new([][]byte),
7249 want: addr([][]byte{[]byte("hello"), []byte("goodbye")}),
7250 }, {
7251 name: jsontest.Name("Slices/Int"),
7252 inBuf: `[-2,-1,0,1,2]`,
7253 inVal: new([]int),
7254 want: addr([]int{-2, -1, 0, 1, 2}),
7255 }, {
7256 name: jsontest.Name("Slices/Uint"),
7257 inBuf: `[0,1,2,3,4]`,
7258 inVal: new([]uint),
7259 want: addr([]uint{0, 1, 2, 3, 4}),
7260 }, {
7261 name: jsontest.Name("Slices/Float"),
7262 inBuf: `[3.14159,12.34]`,
7263 inVal: new([]float64),
7264 want: addr([]float64{3.14159, 12.34}),
7265 }, {
7266
7267
7268
7269 name: jsontest.Name("Slices/Merge"),
7270 inBuf: `[{"k3":"v3"},{"k4":"v4"}]`,
7271 inVal: addr([]map[string]string{{"k1": "v1"}, {"k2": "v2"}}[:1]),
7272 want: addr([]map[string]string{{"k3": "v3"}, {"k4": "v4"}}),
7273 }, {
7274 name: jsontest.Name("Slices/Invalid/Channel"),
7275 inBuf: `["hello"]`,
7276 inVal: new([]chan string),
7277 want: addr([]chan string{nil}),
7278 wantErr: EU(nil).withPos(`[`, "/0").withType(0, T[chan string]()),
7279 }, {
7280 name: jsontest.Name("Slices/RecursiveSlice"),
7281 inBuf: `[[],[],[[]],[[],[]]]`,
7282 inVal: new(recursiveSlice),
7283 want: addr(recursiveSlice{
7284 {},
7285 {},
7286 {{}},
7287 {{}, {}},
7288 }),
7289 }, {
7290 name: jsontest.Name("Slices/Invalid/Bool"),
7291 inBuf: `true`,
7292 inVal: addr([]string{"nochange"}),
7293 want: addr([]string{"nochange"}),
7294 wantErr: EU(nil).withType('t', T[[]string]()),
7295 }, {
7296 name: jsontest.Name("Slices/Invalid/String"),
7297 inBuf: `""`,
7298 inVal: addr([]string{"nochange"}),
7299 want: addr([]string{"nochange"}),
7300 wantErr: EU(nil).withType('"', T[[]string]()),
7301 }, {
7302 name: jsontest.Name("Slices/Invalid/Number"),
7303 inBuf: `0`,
7304 inVal: addr([]string{"nochange"}),
7305 want: addr([]string{"nochange"}),
7306 wantErr: EU(nil).withType('0', T[[]string]()),
7307 }, {
7308 name: jsontest.Name("Slices/Invalid/Object"),
7309 inBuf: `{}`,
7310 inVal: addr([]string{"nochange"}),
7311 want: addr([]string{"nochange"}),
7312 wantErr: EU(nil).withType('{', T[[]string]()),
7313 }, {
7314 name: jsontest.Name("Slices/IgnoreInvalidFormat"),
7315 opts: []Options{invalidFormatOption},
7316 inBuf: `[false,true]`,
7317 inVal: addr([]bool{true, false}),
7318 want: addr([]bool{false, true}),
7319 }, {
7320 name: jsontest.Name("Arrays/Null"),
7321 inBuf: `null`,
7322 inVal: addr([1]string{"something"}),
7323 want: addr([1]string{}),
7324 }, {
7325 name: jsontest.Name("Arrays/Bool"),
7326 inBuf: `[true,false]`,
7327 inVal: new([2]bool),
7328 want: addr([2]bool{true, false}),
7329 }, {
7330 name: jsontest.Name("Arrays/String"),
7331 inBuf: `["hello","goodbye"]`,
7332 inVal: new([2]string),
7333 want: addr([2]string{"hello", "goodbye"}),
7334 }, {
7335 name: jsontest.Name("Arrays/Bytes"),
7336 inBuf: `["aGVsbG8=","Z29vZGJ5ZQ=="]`,
7337 inVal: new([2][]byte),
7338 want: addr([2][]byte{[]byte("hello"), []byte("goodbye")}),
7339 }, {
7340 name: jsontest.Name("Arrays/Int"),
7341 inBuf: `[-2,-1,0,1,2]`,
7342 inVal: new([5]int),
7343 want: addr([5]int{-2, -1, 0, 1, 2}),
7344 }, {
7345 name: jsontest.Name("Arrays/Uint"),
7346 inBuf: `[0,1,2,3,4]`,
7347 inVal: new([5]uint),
7348 want: addr([5]uint{0, 1, 2, 3, 4}),
7349 }, {
7350 name: jsontest.Name("Arrays/Float"),
7351 inBuf: `[3.14159,12.34]`,
7352 inVal: new([2]float64),
7353 want: addr([2]float64{3.14159, 12.34}),
7354 }, {
7355
7356
7357 name: jsontest.Name("Arrays/Merge"),
7358 inBuf: `[{"k3":"v3"},{"k4":"v4"}]`,
7359 inVal: addr([2]map[string]string{{"k1": "v1"}, {"k2": "v2"}}),
7360 want: addr([2]map[string]string{{"k3": "v3"}, {"k4": "v4"}}),
7361 }, {
7362 name: jsontest.Name("Arrays/Invalid/Channel"),
7363 inBuf: `["hello"]`,
7364 inVal: new([1]chan string),
7365 want: new([1]chan string),
7366 wantErr: EU(nil).withPos(`[`, "/0").withType(0, T[chan string]()),
7367 }, {
7368 name: jsontest.Name("Arrays/Invalid/Underflow"),
7369 inBuf: `{"F":[ ]}`,
7370 inVal: new(struct{ F [1]string }),
7371 want: addr(struct{ F [1]string }{}),
7372 wantErr: EU(errArrayUnderflow).withPos(`{"F":[ `, "/F").withType(']', T[[1]string]()),
7373 }, {
7374 name: jsontest.Name("Arrays/Invalid/Underflow/UnmarshalArrayFromAnyLength"),
7375 opts: []Options{jsonflags.UnmarshalArrayFromAnyLength | 1},
7376 inBuf: `[-1,-2]`,
7377 inVal: addr([4]int{1, 2, 3, 4}),
7378 want: addr([4]int{-1, -2, 0, 0}),
7379 }, {
7380 name: jsontest.Name("Arrays/Invalid/Overflow"),
7381 inBuf: `["1","2"]`,
7382 inVal: new([1]string),
7383 want: addr([1]string{"1"}),
7384 wantErr: EU(errArrayOverflow).withPos(`["1","2"`, "").withType(']', T[[1]string]()),
7385 }, {
7386 name: jsontest.Name("Arrays/Invalid/Overflow/UnmarshalArrayFromAnyLength"),
7387 opts: []Options{jsonflags.UnmarshalArrayFromAnyLength | 1},
7388 inBuf: `[-1,-2,-3,-4,-5,-6]`,
7389 inVal: addr([4]int{1, 2, 3, 4}),
7390 want: addr([4]int{-1, -2, -3, -4}),
7391 }, {
7392 name: jsontest.Name("Arrays/Invalid/Bool"),
7393 inBuf: `true`,
7394 inVal: addr([1]string{"nochange"}),
7395 want: addr([1]string{"nochange"}),
7396 wantErr: EU(nil).withType('t', T[[1]string]()),
7397 }, {
7398 name: jsontest.Name("Arrays/Invalid/String"),
7399 inBuf: `""`,
7400 inVal: addr([1]string{"nochange"}),
7401 want: addr([1]string{"nochange"}),
7402 wantErr: EU(nil).withType('"', T[[1]string]()),
7403 }, {
7404 name: jsontest.Name("Arrays/Invalid/Number"),
7405 inBuf: `0`,
7406 inVal: addr([1]string{"nochange"}),
7407 want: addr([1]string{"nochange"}),
7408 wantErr: EU(nil).withType('0', T[[1]string]()),
7409 }, {
7410 name: jsontest.Name("Arrays/Invalid/Object"),
7411 inBuf: `{}`,
7412 inVal: addr([1]string{"nochange"}),
7413 want: addr([1]string{"nochange"}),
7414 wantErr: EU(nil).withType('{', T[[1]string]()),
7415 }, {
7416 name: jsontest.Name("Arrays/IgnoreInvalidFormat"),
7417 opts: []Options{invalidFormatOption},
7418 inBuf: `[false,true]`,
7419 inVal: addr([2]bool{true, false}),
7420 want: addr([2]bool{false, true}),
7421 }, {
7422 name: jsontest.Name("Pointers/NullL0"),
7423 inBuf: `null`,
7424 inVal: new(*string),
7425 want: addr((*string)(nil)),
7426 }, {
7427 name: jsontest.Name("Pointers/NullL1"),
7428 inBuf: `null`,
7429 inVal: addr(new(*string)),
7430 want: addr((**string)(nil)),
7431 }, {
7432 name: jsontest.Name("Pointers/Bool"),
7433 inBuf: `true`,
7434 inVal: addr(new(bool)),
7435 want: addr(addr(true)),
7436 }, {
7437 name: jsontest.Name("Pointers/String"),
7438 inBuf: `"hello"`,
7439 inVal: addr(new(string)),
7440 want: addr(addr("hello")),
7441 }, {
7442 name: jsontest.Name("Pointers/Bytes"),
7443 inBuf: `"aGVsbG8="`,
7444 inVal: addr(new([]byte)),
7445 want: addr(addr([]byte("hello"))),
7446 }, {
7447 name: jsontest.Name("Pointers/Int"),
7448 inBuf: `-123`,
7449 inVal: addr(new(int)),
7450 want: addr(addr(int(-123))),
7451 }, {
7452 name: jsontest.Name("Pointers/Uint"),
7453 inBuf: `123`,
7454 inVal: addr(new(int)),
7455 want: addr(addr(int(123))),
7456 }, {
7457 name: jsontest.Name("Pointers/Float"),
7458 inBuf: `123.456`,
7459 inVal: addr(new(float64)),
7460 want: addr(addr(float64(123.456))),
7461 }, {
7462 name: jsontest.Name("Pointers/Allocate"),
7463 inBuf: `"hello"`,
7464 inVal: addr((*string)(nil)),
7465 want: addr(addr("hello")),
7466 }, {
7467 name: jsontest.Name("Points/IgnoreInvalidFormat"),
7468 opts: []Options{invalidFormatOption},
7469 inBuf: `true`,
7470 inVal: addr(new(bool)),
7471 want: addr(addr(true)),
7472 }, {
7473 name: jsontest.Name("Interfaces/Empty/Null"),
7474 inBuf: `null`,
7475 inVal: new(any),
7476 want: new(any),
7477 }, {
7478 name: jsontest.Name("Interfaces/NonEmpty/Null"),
7479 inBuf: `null`,
7480 inVal: new(io.Reader),
7481 want: new(io.Reader),
7482 }, {
7483 name: jsontest.Name("Interfaces/NonEmpty/Invalid"),
7484 inBuf: `"hello"`,
7485 inVal: new(io.Reader),
7486 want: new(io.Reader),
7487 wantErr: EU(errNilInterface).withType(0, T[io.Reader]()),
7488 }, {
7489 name: jsontest.Name("Interfaces/Empty/False"),
7490 inBuf: `false`,
7491 inVal: new(any),
7492 want: func() any {
7493 var vi any = false
7494 return &vi
7495 }(),
7496 }, {
7497 name: jsontest.Name("Interfaces/Empty/True"),
7498 inBuf: `true`,
7499 inVal: new(any),
7500 want: func() any {
7501 var vi any = true
7502 return &vi
7503 }(),
7504 }, {
7505 name: jsontest.Name("Interfaces/Empty/String"),
7506 inBuf: `"string"`,
7507 inVal: new(any),
7508 want: func() any {
7509 var vi any = "string"
7510 return &vi
7511 }(),
7512 }, {
7513 name: jsontest.Name("Interfaces/Empty/Number"),
7514 inBuf: `3.14159`,
7515 inVal: new(any),
7516 want: func() any {
7517 var vi any = 3.14159
7518 return &vi
7519 }(),
7520 }, {
7521 name: jsontest.Name("Interfaces/Empty/Object"),
7522 inBuf: `{"k":"v"}`,
7523 inVal: new(any),
7524 want: func() any {
7525 var vi any = map[string]any{"k": "v"}
7526 return &vi
7527 }(),
7528 }, {
7529 name: jsontest.Name("Interfaces/Empty/Array"),
7530 inBuf: `["v"]`,
7531 inVal: new(any),
7532 want: func() any {
7533 var vi any = []any{"v"}
7534 return &vi
7535 }(),
7536 }, {
7537 name: jsontest.Name("Interfaces/NamedAny/String"),
7538 inBuf: `"string"`,
7539 inVal: new(namedAny),
7540 want: func() namedAny {
7541 var vi namedAny = "string"
7542 return &vi
7543 }(),
7544 }, {
7545 name: jsontest.Name("Interfaces/Invalid"),
7546 inBuf: `]`,
7547 inVal: new(any),
7548 want: new(any),
7549 wantErr: newInvalidCharacterError("]", "at start of value", 0, ""),
7550 }, {
7551
7552
7553
7554
7555 name: jsontest.Name("Interfaces/Merge/Map"),
7556 inBuf: `{"k2":"v2"}`,
7557 inVal: func() any {
7558 var vi any = map[string]string{"k1": "v1"}
7559 return &vi
7560 }(),
7561 want: func() any {
7562 var vi any = map[string]string{"k1": "v1", "k2": "v2"}
7563 return &vi
7564 }(),
7565 }, {
7566 name: jsontest.Name("Interfaces/Merge/Struct"),
7567 inBuf: `{"Array":["goodbye"]}`,
7568 inVal: func() any {
7569 var vi any = structAll{String: "hello"}
7570 return &vi
7571 }(),
7572 want: func() any {
7573 var vi any = structAll{String: "hello", Array: [1]string{"goodbye"}}
7574 return &vi
7575 }(),
7576 }, {
7577 name: jsontest.Name("Interfaces/Merge/NamedInt"),
7578 inBuf: `64`,
7579 inVal: func() any {
7580 var vi any = namedInt64(-64)
7581 return &vi
7582 }(),
7583 want: func() any {
7584 var vi any = namedInt64(+64)
7585 return &vi
7586 }(),
7587 }, {
7588 name: jsontest.Name("Interfaces/IgnoreInvalidFormat"),
7589 opts: []Options{invalidFormatOption},
7590 inBuf: `true`,
7591 inVal: new(any),
7592 want: func() any {
7593 var vi any = true
7594 return &vi
7595 }(),
7596 }, {
7597 name: jsontest.Name("Interfaces/Any"),
7598 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7599 inVal: new(struct{ X any }),
7600 want: addr(struct{ X any }{[]any{nil, false, true, "", 0.0, map[string]any{}, []any{}}}),
7601 }, {
7602 name: jsontest.Name("Interfaces/Any/Named"),
7603 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7604 inVal: new(struct{ X namedAny }),
7605 want: addr(struct{ X namedAny }{[]any{nil, false, true, "", 0.0, map[string]any{}, []any{}}}),
7606 }, {
7607 name: jsontest.Name("Interfaces/Any/Stringified"),
7608 opts: []Options{StringifyNumbers(true)},
7609 inBuf: `{"X":"0"}`,
7610 inVal: new(struct{ X any }),
7611 want: addr(struct{ X any }{"0"}),
7612 }, {
7613 name: jsontest.Name("Interfaces/Any/UnmarshalFunc/Any"),
7614 opts: []Options{
7615 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *any) error {
7616 *v = "called"
7617 return nil
7618 })),
7619 },
7620 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7621 inVal: new(struct{ X any }),
7622 want: addr(struct{ X any }{"called"}),
7623 }, {
7624 name: jsontest.Name("Interfaces/Any/UnmarshalFunc/Bool"),
7625 opts: []Options{
7626 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *bool) error {
7627 *v = string(b) != "true"
7628 return nil
7629 })),
7630 },
7631 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7632 inVal: new(struct{ X any }),
7633 want: addr(struct{ X any }{[]any{nil, true, false, "", 0.0, map[string]any{}, []any{}}}),
7634 }, {
7635 name: jsontest.Name("Interfaces/Any/UnmarshalFunc/String"),
7636 opts: []Options{
7637 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *string) error {
7638 *v = "called"
7639 return nil
7640 })),
7641 },
7642 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7643 inVal: new(struct{ X any }),
7644 want: addr(struct{ X any }{[]any{nil, false, true, "called", 0.0, map[string]any{}, []any{}}}),
7645 }, {
7646 name: jsontest.Name("Interfaces/Any/UnmarshalFunc/Float64"),
7647 opts: []Options{
7648 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *float64) error {
7649 *v = 3.14159
7650 return nil
7651 })),
7652 },
7653 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7654 inVal: new(struct{ X any }),
7655 want: addr(struct{ X any }{[]any{nil, false, true, "", 3.14159, map[string]any{}, []any{}}}),
7656 }, {
7657 name: jsontest.Name("Interfaces/Any/UnmarshalFunc/MapStringAny"),
7658 opts: []Options{
7659 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *map[string]any) error {
7660 *v = map[string]any{"called": nil}
7661 return nil
7662 })),
7663 },
7664 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7665 inVal: new(struct{ X any }),
7666 want: addr(struct{ X any }{[]any{nil, false, true, "", 0.0, map[string]any{"called": nil}, []any{}}}),
7667 }, {
7668 name: jsontest.Name("Interfaces/Any/UnmarshalFunc/SliceAny"),
7669 opts: []Options{
7670 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *[]any) error {
7671 *v = []any{"called"}
7672 return nil
7673 })),
7674 },
7675 inBuf: `{"X":[null,false,true,"",0,{},[]]}`,
7676 inVal: new(struct{ X any }),
7677 want: addr(struct{ X any }{[]any{"called"}}),
7678 }, {
7679 name: jsontest.Name("Interfaces/Any/Maps/NonEmpty"),
7680 inBuf: `{"X":{"fizz":"buzz"}}`,
7681 inVal: new(struct{ X any }),
7682 want: addr(struct{ X any }{map[string]any{"fizz": "buzz"}}),
7683 }, {
7684 name: jsontest.Name("Interfaces/Any/Maps/RejectDuplicateNames"),
7685 inBuf: `{"X":{"fizz":"buzz","fizz":true}}`,
7686 inVal: new(struct{ X any }),
7687 want: addr(struct{ X any }{map[string]any{"fizz": "buzz"}}),
7688 wantErr: newDuplicateNameError("/X", []byte(`"fizz"`), len64(`{"X":{"fizz":"buzz",`)),
7689 }, {
7690 name: jsontest.Name("Interfaces/Any/Maps/AllowDuplicateNames"),
7691 opts: []Options{jsontext.AllowDuplicateNames(true)},
7692 inBuf: `{"X":{"fizz":"buzz","fizz":true}}`,
7693 inVal: new(struct{ X any }),
7694 want: addr(struct{ X any }{map[string]any{"fizz": "buzz"}}),
7695 wantErr: EU(nil).withPos(`{"X":{"fizz":"buzz","fizz":`, "/X/fizz").withType('t', T[string]()),
7696 }, {
7697 name: jsontest.Name("Interfaces/Any/Slices/NonEmpty"),
7698 inBuf: `{"X":["fizz","buzz"]}`,
7699 inVal: new(struct{ X any }),
7700 want: addr(struct{ X any }{[]any{"fizz", "buzz"}}),
7701 }, {
7702 name: jsontest.Name("Methods/NilPointer/Null"),
7703 inBuf: `{"X":null}`,
7704 inVal: addr(struct{ X *allMethods }{X: (*allMethods)(nil)}),
7705 want: addr(struct{ X *allMethods }{X: (*allMethods)(nil)}),
7706 }, {
7707 name: jsontest.Name("Methods/NilPointer/Value"),
7708 inBuf: `{"X":"value"}`,
7709 inVal: addr(struct{ X *allMethods }{X: (*allMethods)(nil)}),
7710 want: addr(struct{ X *allMethods }{X: &allMethods{method: "UnmarshalJSONFrom", value: []byte(`"value"`)}}),
7711 }, {
7712 name: jsontest.Name("Methods/NilInterface/Null"),
7713 inBuf: `{"X":null}`,
7714 inVal: addr(struct{ X MarshalerTo }{X: (*allMethods)(nil)}),
7715 want: addr(struct{ X MarshalerTo }{X: nil}),
7716 }, {
7717 name: jsontest.Name("Methods/NilInterface/Value"),
7718 inBuf: `{"X":"value"}`,
7719 inVal: addr(struct{ X MarshalerTo }{X: (*allMethods)(nil)}),
7720 want: addr(struct{ X MarshalerTo }{X: &allMethods{method: "UnmarshalJSONFrom", value: []byte(`"value"`)}}),
7721 }, {
7722 name: jsontest.Name("Methods/AllMethods"),
7723 inBuf: `{"X":"hello"}`,
7724 inVal: new(struct{ X *allMethods }),
7725 want: addr(struct{ X *allMethods }{X: &allMethods{method: "UnmarshalJSONFrom", value: []byte(`"hello"`)}}),
7726 }, {
7727 name: jsontest.Name("Methods/AllMethodsExceptJSONv2"),
7728 inBuf: `{"X":"hello"}`,
7729 inVal: new(struct{ X *allMethodsExceptJSONv2 }),
7730 want: addr(struct{ X *allMethodsExceptJSONv2 }{X: &allMethodsExceptJSONv2{allMethods: allMethods{method: "UnmarshalJSON", value: []byte(`"hello"`)}}}),
7731 }, {
7732 name: jsontest.Name("Methods/AllMethodsExceptJSONv1"),
7733 inBuf: `{"X":"hello"}`,
7734 inVal: new(struct{ X *allMethodsExceptJSONv1 }),
7735 want: addr(struct{ X *allMethodsExceptJSONv1 }{X: &allMethodsExceptJSONv1{allMethods: allMethods{method: "UnmarshalJSONFrom", value: []byte(`"hello"`)}}}),
7736 }, {
7737 name: jsontest.Name("Methods/AllMethodsExceptText"),
7738 inBuf: `{"X":"hello"}`,
7739 inVal: new(struct{ X *allMethodsExceptText }),
7740 want: addr(struct{ X *allMethodsExceptText }{X: &allMethodsExceptText{allMethods: allMethods{method: "UnmarshalJSONFrom", value: []byte(`"hello"`)}}}),
7741 }, {
7742 name: jsontest.Name("Methods/OnlyMethodJSONv2"),
7743 inBuf: `{"X":"hello"}`,
7744 inVal: new(struct{ X *onlyMethodJSONv2 }),
7745 want: addr(struct{ X *onlyMethodJSONv2 }{X: &onlyMethodJSONv2{allMethods: allMethods{method: "UnmarshalJSONFrom", value: []byte(`"hello"`)}}}),
7746 }, {
7747 name: jsontest.Name("Methods/OnlyMethodJSONv1"),
7748 inBuf: `{"X":"hello"}`,
7749 inVal: new(struct{ X *onlyMethodJSONv1 }),
7750 want: addr(struct{ X *onlyMethodJSONv1 }{X: &onlyMethodJSONv1{allMethods: allMethods{method: "UnmarshalJSON", value: []byte(`"hello"`)}}}),
7751 }, {
7752 name: jsontest.Name("Methods/OnlyMethodText"),
7753 inBuf: `{"X":"hello"}`,
7754 inVal: new(struct{ X *onlyMethodText }),
7755 want: addr(struct{ X *onlyMethodText }{X: &onlyMethodText{allMethods: allMethods{method: "UnmarshalText", value: []byte(`hello`)}}}),
7756 }, {
7757 name: jsontest.Name("Methods/Text/Null"),
7758 inBuf: `{"X":null}`,
7759 inVal: addr(struct{ X unmarshalTextFunc }{unmarshalTextFunc(func(b []byte) error {
7760 return errMustNotCall
7761 })}),
7762 want: addr(struct{ X unmarshalTextFunc }{nil}),
7763 }, {
7764 name: jsontest.Name("Methods/IP"),
7765 inBuf: `"192.168.0.100"`,
7766 inVal: new(net.IP),
7767 want: addr(net.IPv4(192, 168, 0, 100)),
7768 }, {
7769
7770 name: jsontest.Name("Methods/Anonymous"),
7771 inBuf: `{"X":"hello"}`,
7772 inVal: new(struct{ X struct{ allMethods } }),
7773 want: addr(struct{ X struct{ allMethods } }{X: struct{ allMethods }{allMethods{method: "UnmarshalJSONFrom", value: []byte(`"hello"`)}}}),
7774 }, {
7775
7776 name: jsontest.Name("Methods/Addressable"),
7777 inBuf: `{"V":"hello","M":{"K":"hello"},"I":"hello"}`,
7778 inVal: addr(struct {
7779 V allMethods
7780 M map[string]allMethods
7781 I any
7782 }{
7783 I: allMethods{},
7784 }),
7785 want: addr(struct {
7786 V allMethods
7787 M map[string]allMethods
7788 I any
7789 }{
7790 V: allMethods{method: "UnmarshalJSONFrom", value: []byte(`"hello"`)},
7791 M: map[string]allMethods{"K": {method: "UnmarshalJSONFrom", value: []byte(`"hello"`)}},
7792 I: allMethods{method: "UnmarshalJSONFrom", value: []byte(`"hello"`)},
7793 }),
7794 }, {
7795
7796 name: jsontest.Name("Methods/MapKey/JSONv2"),
7797 inBuf: `{"k1":"v1b","k2":"v2"}`,
7798 inVal: addr(map[structMethodJSONv2]string{{"k1"}: "v1a", {"k3"}: "v3"}),
7799 want: addr(map[structMethodJSONv2]string{{"k1"}: "v1b", {"k2"}: "v2", {"k3"}: "v3"}),
7800 }, {
7801
7802 name: jsontest.Name("Methods/MapKey/JSONv1"),
7803 inBuf: `{"k1":"v1b","k2":"v2"}`,
7804 inVal: addr(map[structMethodJSONv1]string{{"k1"}: "v1a", {"k3"}: "v3"}),
7805 want: addr(map[structMethodJSONv1]string{{"k1"}: "v1b", {"k2"}: "v2", {"k3"}: "v3"}),
7806 }, {
7807 name: jsontest.Name("Methods/MapKey/Text"),
7808 inBuf: `{"k1":"v1b","k2":"v2"}`,
7809 inVal: addr(map[structMethodText]string{{"k1"}: "v1a", {"k3"}: "v3"}),
7810 want: addr(map[structMethodText]string{{"k1"}: "v1b", {"k2"}: "v2", {"k3"}: "v3"}),
7811 }, {
7812 name: jsontest.Name("Methods/Invalid/JSONv2/Error"),
7813 inBuf: `{}`,
7814 inVal: addr(unmarshalJSONv2Func(func(*jsontext.Decoder) error {
7815 return errSomeError
7816 })),
7817 wantErr: EU(errSomeError).withType(0, T[unmarshalJSONv2Func]()),
7818 }, {
7819 name: jsontest.Name("Methods/Invalid/JSONv2/TooFew"),
7820 inVal: addr(unmarshalJSONv2Func(func(*jsontext.Decoder) error {
7821 return nil
7822 })),
7823 wantErr: EU(errNonSingularValue).withType(0, T[unmarshalJSONv2Func]()),
7824 }, {
7825 name: jsontest.Name("Methods/Invalid/JSONv2/TooMany"),
7826 inBuf: `{}{}`,
7827 inVal: addr(unmarshalJSONv2Func(func(dec *jsontext.Decoder) error {
7828 dec.ReadValue()
7829 dec.ReadValue()
7830 return nil
7831 })),
7832 wantErr: EU(errNonSingularValue).withPos(`{}`, "").withType(0, T[unmarshalJSONv2Func]()),
7833 }, {
7834 name: jsontest.Name("Methods/Invalid/JSONv2/SkipFunc"),
7835 inBuf: `{}`,
7836 inVal: addr(unmarshalJSONv2Func(func(*jsontext.Decoder) error {
7837 return SkipFunc
7838 })),
7839 wantErr: EU(wrapSkipFunc(SkipFunc, "unmarshal method")).withType(0, T[unmarshalJSONv2Func]()),
7840 }, {
7841 name: jsontest.Name("Methods/Invalid/JSONv1/Error"),
7842 inBuf: `{}`,
7843 inVal: addr(unmarshalJSONv1Func(func([]byte) error {
7844 return errSomeError
7845 })),
7846 wantErr: EU(errSomeError).withType('{', T[unmarshalJSONv1Func]()),
7847 }, {
7848 name: jsontest.Name("Methods/Invalid/JSONv1/SkipFunc"),
7849 inBuf: `{}`,
7850 inVal: addr(unmarshalJSONv1Func(func([]byte) error {
7851 return SkipFunc
7852 })),
7853 wantErr: EU(wrapSkipFunc(SkipFunc, "unmarshal method")).withType('{', T[unmarshalJSONv1Func]()),
7854 }, {
7855 name: jsontest.Name("Methods/Invalid/Text/Error"),
7856 inBuf: `"value"`,
7857 inVal: addr(unmarshalTextFunc(func([]byte) error {
7858 return errSomeError
7859 })),
7860 wantErr: EU(errSomeError).withType('"', T[unmarshalTextFunc]()),
7861 }, {
7862 name: jsontest.Name("Methods/Invalid/Text/Syntax"),
7863 inBuf: `{}`,
7864 inVal: addr(unmarshalTextFunc(func([]byte) error {
7865 panic("should not be called")
7866 })),
7867 wantErr: EU(errNonStringValue).withType('{', T[unmarshalTextFunc]()),
7868 }, {
7869 name: jsontest.Name("Methods/Invalid/Text/SkipFunc"),
7870 inBuf: `"value"`,
7871 inVal: addr(unmarshalTextFunc(func([]byte) error {
7872 return SkipFunc
7873 })),
7874 wantErr: EU(wrapSkipFunc(SkipFunc, "unmarshal method")).withType('"', T[unmarshalTextFunc]()),
7875 }, {
7876 name: jsontest.Name("Functions/String/V1"),
7877 opts: []Options{
7878 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *string) error {
7879 if string(b) != `""` {
7880 return fmt.Errorf("got %s, want %s", b, `""`)
7881 }
7882 *v = "called"
7883 return nil
7884 })),
7885 },
7886 inBuf: `""`,
7887 inVal: addr(""),
7888 want: addr("called"),
7889 }, {
7890 name: jsontest.Name("Functions/String/Empty"),
7891 opts: []Options{WithUnmarshalers(nil)},
7892 inBuf: `"hello"`,
7893 inVal: addr(""),
7894 want: addr("hello"),
7895 }, {
7896 name: jsontest.Name("Functions/NamedString/V1/NoMatch"),
7897 opts: []Options{
7898 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *namedString) error {
7899 panic("should not be called")
7900 })),
7901 },
7902 inBuf: `""`,
7903 inVal: addr(""),
7904 want: addr(""),
7905 }, {
7906 name: jsontest.Name("Functions/NamedString/V1/Match"),
7907 opts: []Options{
7908 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *namedString) error {
7909 if string(b) != `""` {
7910 return fmt.Errorf("got %s, want %s", b, `""`)
7911 }
7912 *v = "called"
7913 return nil
7914 })),
7915 },
7916 inBuf: `""`,
7917 inVal: addr(namedString("")),
7918 want: addr(namedString("called")),
7919 }, {
7920 name: jsontest.Name("Functions/String/V2"),
7921 opts: []Options{
7922 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
7923 switch b, err := dec.ReadValue(); {
7924 case err != nil:
7925 return err
7926 case string(b) != `""`:
7927 return fmt.Errorf("got %s, want %s", b, `""`)
7928 }
7929 *v = "called"
7930 return nil
7931 })),
7932 },
7933 inBuf: `""`,
7934 inVal: addr(""),
7935 want: addr("called"),
7936 }, {
7937 name: jsontest.Name("Functions/NamedString/V2/NoMatch"),
7938 opts: []Options{
7939 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *namedString) error {
7940 panic("should not be called")
7941 })),
7942 },
7943 inBuf: `""`,
7944 inVal: addr(""),
7945 want: addr(""),
7946 }, {
7947 name: jsontest.Name("Functions/NamedString/V2/Match"),
7948 opts: []Options{
7949 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *namedString) error {
7950 switch t, err := dec.ReadToken(); {
7951 case err != nil:
7952 return err
7953 case t.String() != ``:
7954 return fmt.Errorf("got %q, want %q", t, ``)
7955 }
7956 *v = "called"
7957 return nil
7958 })),
7959 },
7960 inBuf: `""`,
7961 inVal: addr(namedString("")),
7962 want: addr(namedString("called")),
7963 }, {
7964 name: jsontest.Name("Functions/String/Empty1/NoMatch"),
7965 opts: []Options{
7966 WithUnmarshalers(new(Unmarshalers)),
7967 },
7968 inBuf: `""`,
7969 inVal: addr(""),
7970 want: addr(""),
7971 }, {
7972 name: jsontest.Name("Functions/String/Empty2/NoMatch"),
7973 opts: []Options{
7974 WithUnmarshalers(JoinUnmarshalers()),
7975 },
7976 inBuf: `""`,
7977 inVal: addr(""),
7978 want: addr(""),
7979 }, {
7980 name: jsontest.Name("Functions/String/V1/DirectError"),
7981 opts: []Options{
7982 WithUnmarshalers(UnmarshalFunc(func([]byte, *string) error {
7983 return errSomeError
7984 })),
7985 },
7986 inBuf: `""`,
7987 inVal: addr(""),
7988 want: addr(""),
7989 wantErr: EU(errSomeError).withType('"', reflect.PointerTo(stringType)),
7990 }, {
7991 name: jsontest.Name("Functions/String/V1/SkipError"),
7992 opts: []Options{
7993 WithUnmarshalers(UnmarshalFunc(func([]byte, *string) error {
7994 return SkipFunc
7995 })),
7996 },
7997 inBuf: `""`,
7998 inVal: addr(""),
7999 want: addr(""),
8000 wantErr: EU(wrapSkipFunc(SkipFunc, "unmarshal function of type func([]byte, T) error")).withType('"', reflect.PointerTo(stringType)),
8001 }, {
8002 name: jsontest.Name("Functions/String/V2/DirectError"),
8003 opts: []Options{
8004 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8005 return errSomeError
8006 })),
8007 },
8008 inBuf: `""`,
8009 inVal: addr(""),
8010 want: addr(""),
8011 wantErr: EU(errSomeError).withType(0, reflect.PointerTo(stringType)),
8012 }, {
8013 name: jsontest.Name("Functions/String/V2/TooFew"),
8014 opts: []Options{
8015 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8016 return nil
8017 })),
8018 },
8019 inBuf: `""`,
8020 inVal: addr(""),
8021 want: addr(""),
8022 wantErr: EU(errNonSingularValue).withType(0, reflect.PointerTo(stringType)),
8023 }, {
8024 name: jsontest.Name("Functions/String/V2/TooMany"),
8025 opts: []Options{
8026 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8027 if _, err := dec.ReadValue(); err != nil {
8028 return err
8029 }
8030 if _, err := dec.ReadValue(); err != nil {
8031 return err
8032 }
8033 return nil
8034 })),
8035 },
8036 inBuf: `{"X":["",""]}`,
8037 inVal: addr(struct{ X []string }{}),
8038 want: addr(struct{ X []string }{[]string{""}}),
8039 wantErr: EU(errNonSingularValue).withPos(`{"X":["",`, "/X").withType(0, reflect.PointerTo(stringType)),
8040 }, {
8041 name: jsontest.Name("Functions/String/V2/Skipped"),
8042 opts: []Options{
8043 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8044 return SkipFunc
8045 })),
8046 },
8047 inBuf: `""`,
8048 inVal: addr(""),
8049 want: addr(""),
8050 }, {
8051 name: jsontest.Name("Functions/String/V2/ProcessBeforeSkip"),
8052 opts: []Options{
8053 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8054 if _, err := dec.ReadValue(); err != nil {
8055 return err
8056 }
8057 return SkipFunc
8058 })),
8059 },
8060 inBuf: `""`,
8061 inVal: addr(""),
8062 want: addr(""),
8063 wantErr: EU(errSkipMutation).withType(0, reflect.PointerTo(stringType)),
8064 }, {
8065 name: jsontest.Name("Functions/String/V2/WrappedSkipError"),
8066 opts: []Options{
8067 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8068 return fmt.Errorf("wrap: %w", SkipFunc)
8069 })),
8070 },
8071 inBuf: `""`,
8072 inVal: addr(""),
8073 want: addr(""),
8074 wantErr: EU(fmt.Errorf("wrap: %w", SkipFunc)).withType(0, reflect.PointerTo(stringType)),
8075 }, {
8076 name: jsontest.Name("Functions/Map/Key/NoCaseString/V1"),
8077 opts: []Options{
8078 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *nocaseString) error {
8079 if string(b) != `"hello"` {
8080 return fmt.Errorf("got %s, want %s", b, `"hello"`)
8081 }
8082 *v = "called"
8083 return nil
8084 })),
8085 },
8086 inBuf: `{"hello":"world"}`,
8087 inVal: addr(map[nocaseString]string{}),
8088 want: addr(map[nocaseString]string{"called": "world"}),
8089 }, {
8090 name: jsontest.Name("Functions/Map/Key/TextMarshaler/V1"),
8091 opts: []Options{
8092 WithUnmarshalers(UnmarshalFunc(func(b []byte, v encoding.TextMarshaler) error {
8093 if string(b) != `"hello"` {
8094 return fmt.Errorf("got %s, want %s", b, `"hello"`)
8095 }
8096 *v.(*nocaseString) = "called"
8097 return nil
8098 })),
8099 },
8100 inBuf: `{"hello":"world"}`,
8101 inVal: addr(map[nocaseString]string{}),
8102 want: addr(map[nocaseString]string{"called": "world"}),
8103 }, {
8104 name: jsontest.Name("Functions/Map/Key/NoCaseString/V2"),
8105 opts: []Options{
8106 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *nocaseString) error {
8107 switch t, err := dec.ReadToken(); {
8108 case err != nil:
8109 return err
8110 case t.String() != "hello":
8111 return fmt.Errorf("got %q, want %q", t, "hello")
8112 }
8113 *v = "called"
8114 return nil
8115 })),
8116 },
8117 inBuf: `{"hello":"world"}`,
8118 inVal: addr(map[nocaseString]string{}),
8119 want: addr(map[nocaseString]string{"called": "world"}),
8120 }, {
8121 name: jsontest.Name("Functions/Map/Key/TextMarshaler/V2"),
8122 opts: []Options{
8123 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v encoding.TextMarshaler) error {
8124 switch b, err := dec.ReadValue(); {
8125 case err != nil:
8126 return err
8127 case string(b) != `"hello"`:
8128 return fmt.Errorf("got %s, want %s", b, `"hello"`)
8129 }
8130 *v.(*nocaseString) = "called"
8131 return nil
8132 })),
8133 },
8134 inBuf: `{"hello":"world"}`,
8135 inVal: addr(map[nocaseString]string{}),
8136 want: addr(map[nocaseString]string{"called": "world"}),
8137 }, {
8138 name: jsontest.Name("Functions/Map/Key/String/V1/DuplicateName"),
8139 opts: []Options{
8140 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8141 if _, err := dec.ReadValue(); err != nil {
8142 return err
8143 }
8144 xd := export.Decoder(dec)
8145 *v = fmt.Sprintf("%d-%d", len(xd.Tokens.Stack), xd.Tokens.Last.Length())
8146 return nil
8147 })),
8148 },
8149 inBuf: `{"name":"value","name":"value"}`,
8150 inVal: addr(map[string]string{}),
8151 want: addr(map[string]string{"1-1": "1-2"}),
8152 wantErr: newDuplicateNameError("", []byte(`"name"`), len64(`{"name":"value",`)),
8153 }, {
8154 name: jsontest.Name("Functions/Map/Value/NoCaseString/V1"),
8155 opts: []Options{
8156 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *nocaseString) error {
8157 if string(b) != `"world"` {
8158 return fmt.Errorf("got %s, want %s", b, `"world"`)
8159 }
8160 *v = "called"
8161 return nil
8162 })),
8163 },
8164 inBuf: `{"hello":"world"}`,
8165 inVal: addr(map[string]nocaseString{}),
8166 want: addr(map[string]nocaseString{"hello": "called"}),
8167 }, {
8168 name: jsontest.Name("Functions/Map/Value/TextMarshaler/V1"),
8169 opts: []Options{
8170 WithUnmarshalers(UnmarshalFunc(func(b []byte, v encoding.TextMarshaler) error {
8171 if string(b) != `"world"` {
8172 return fmt.Errorf("got %s, want %s", b, `"world"`)
8173 }
8174 *v.(*nocaseString) = "called"
8175 return nil
8176 })),
8177 },
8178 inBuf: `{"hello":"world"}`,
8179 inVal: addr(map[string]nocaseString{}),
8180 want: addr(map[string]nocaseString{"hello": "called"}),
8181 }, {
8182 name: jsontest.Name("Functions/Map/Value/NoCaseString/V2"),
8183 opts: []Options{
8184 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *nocaseString) error {
8185 switch t, err := dec.ReadToken(); {
8186 case err != nil:
8187 return err
8188 case t.String() != "world":
8189 return fmt.Errorf("got %q, want %q", t, "world")
8190 }
8191 *v = "called"
8192 return nil
8193 })),
8194 },
8195 inBuf: `{"hello":"world"}`,
8196 inVal: addr(map[string]nocaseString{}),
8197 want: addr(map[string]nocaseString{"hello": "called"}),
8198 }, {
8199 name: jsontest.Name("Functions/Map/Value/TextMarshaler/V2"),
8200 opts: []Options{
8201 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v encoding.TextMarshaler) error {
8202 switch b, err := dec.ReadValue(); {
8203 case err != nil:
8204 return err
8205 case string(b) != `"world"`:
8206 return fmt.Errorf("got %s, want %s", b, `"world"`)
8207 }
8208 *v.(*nocaseString) = "called"
8209 return nil
8210 })),
8211 },
8212 inBuf: `{"hello":"world"}`,
8213 inVal: addr(map[string]nocaseString{}),
8214 want: addr(map[string]nocaseString{"hello": "called"}),
8215 }, {
8216 name: jsontest.Name("Funtions/Struct/Fields"),
8217 opts: []Options{
8218 WithUnmarshalers(JoinUnmarshalers(
8219 UnmarshalFunc(func(b []byte, v *bool) error {
8220 if string(b) != `"called1"` {
8221 return fmt.Errorf("got %s, want %s", b, `"called1"`)
8222 }
8223 *v = true
8224 return nil
8225 }),
8226 UnmarshalFunc(func(b []byte, v *string) error {
8227 if string(b) != `"called2"` {
8228 return fmt.Errorf("got %s, want %s", b, `"called2"`)
8229 }
8230 *v = "called2"
8231 return nil
8232 }),
8233 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *[]byte) error {
8234 switch t, err := dec.ReadToken(); {
8235 case err != nil:
8236 return err
8237 case t.String() != "called3":
8238 return fmt.Errorf("got %q, want %q", t, "called3")
8239 }
8240 *v = []byte("called3")
8241 return nil
8242 }),
8243 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *int64) error {
8244 switch b, err := dec.ReadValue(); {
8245 case err != nil:
8246 return err
8247 case string(b) != `"called4"`:
8248 return fmt.Errorf("got %s, want %s", b, `"called4"`)
8249 }
8250 *v = 123
8251 return nil
8252 }),
8253 )),
8254 },
8255 inBuf: `{"Bool":"called1","String":"called2","Bytes":"called3","Int":"called4","Uint":456,"Float":789}`,
8256 inVal: addr(structScalars{}),
8257 want: addr(structScalars{Bool: true, String: "called2", Bytes: []byte("called3"), Int: 123, Uint: 456, Float: 789}),
8258 }, {
8259 name: jsontest.Name("Functions/Struct/Inlined"),
8260 opts: []Options{
8261 WithUnmarshalers(JoinUnmarshalers(
8262 UnmarshalFunc(func([]byte, *structInlinedL1) error {
8263 panic("should not be called")
8264 }),
8265 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *StructEmbed2) error {
8266 panic("should not be called")
8267 }),
8268 )),
8269 },
8270 inBuf: `{"E":"E3","F":"F3","G":"G3","A":"A1","B":"B1","D":"D2"}`,
8271 inVal: new(structInlined),
8272 want: addr(structInlined{
8273 X: structInlinedL1{
8274 X: &structInlinedL2{A: "A1", B: "B1" },
8275 StructEmbed1: StructEmbed1{ D: "D2" },
8276 },
8277 StructEmbed2: &StructEmbed2{E: "E3", F: "F3", G: "G3"},
8278 }),
8279 }, {
8280 name: jsontest.Name("Functions/Slice/Elem"),
8281 opts: []Options{
8282 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *string) error {
8283 *v = strings.Trim(strings.ToUpper(string(b)), `"`)
8284 return nil
8285 })),
8286 },
8287 inBuf: `["hello","World"]`,
8288 inVal: addr([]string{}),
8289 want: addr([]string{"HELLO", "WORLD"}),
8290 }, {
8291 name: jsontest.Name("Functions/Array/Elem"),
8292 opts: []Options{
8293 WithUnmarshalers(UnmarshalFunc(func(b []byte, v *string) error {
8294 *v = strings.Trim(strings.ToUpper(string(b)), `"`)
8295 return nil
8296 })),
8297 },
8298 inBuf: `["hello","World"]`,
8299 inVal: addr([2]string{}),
8300 want: addr([2]string{"HELLO", "WORLD"}),
8301 }, {
8302 name: jsontest.Name("Functions/Pointer/Nil"),
8303 opts: []Options{
8304 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8305 t, err := dec.ReadToken()
8306 *v = strings.ToUpper(t.String())
8307 return err
8308 })),
8309 },
8310 inBuf: `{"X":"hello"}`,
8311 inVal: addr(struct{ X *string }{nil}),
8312 want: addr(struct{ X *string }{addr("HELLO")}),
8313 }, {
8314 name: jsontest.Name("Functions/Pointer/NonNil"),
8315 opts: []Options{
8316 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8317 t, err := dec.ReadToken()
8318 *v = strings.ToUpper(t.String())
8319 return err
8320 })),
8321 },
8322 inBuf: `{"X":"hello"}`,
8323 inVal: addr(struct{ X *string }{addr("")}),
8324 want: addr(struct{ X *string }{addr("HELLO")}),
8325 }, {
8326 name: jsontest.Name("Functions/Interface/Nil"),
8327 opts: []Options{
8328 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v fmt.Stringer) error {
8329 panic("should not be called")
8330 })),
8331 },
8332 inBuf: `{"X":"hello"}`,
8333 inVal: addr(struct{ X fmt.Stringer }{nil}),
8334 want: addr(struct{ X fmt.Stringer }{nil}),
8335 wantErr: EU(errNilInterface).withPos(`{"X":`, "/X").withType(0, T[fmt.Stringer]()),
8336 }, {
8337 name: jsontest.Name("Functions/Interface/NetIP"),
8338 opts: []Options{
8339 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *fmt.Stringer) error {
8340 *v = net.IP{}
8341 return SkipFunc
8342 })),
8343 },
8344 inBuf: `{"X":"1.1.1.1"}`,
8345 inVal: addr(struct{ X fmt.Stringer }{nil}),
8346 want: addr(struct{ X fmt.Stringer }{net.IPv4(1, 1, 1, 1)}),
8347 }, {
8348 name: jsontest.Name("Functions/Interface/NewPointerNetIP"),
8349 opts: []Options{
8350 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *fmt.Stringer) error {
8351 *v = new(net.IP)
8352 return SkipFunc
8353 })),
8354 },
8355 inBuf: `{"X":"1.1.1.1"}`,
8356 inVal: addr(struct{ X fmt.Stringer }{nil}),
8357 want: addr(struct{ X fmt.Stringer }{addr(net.IPv4(1, 1, 1, 1))}),
8358 }, {
8359 name: jsontest.Name("Functions/Interface/NilPointerNetIP"),
8360 opts: []Options{
8361 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, v *fmt.Stringer) error {
8362 *v = (*net.IP)(nil)
8363 return SkipFunc
8364 })),
8365 },
8366 inBuf: `{"X":"1.1.1.1"}`,
8367 inVal: addr(struct{ X fmt.Stringer }{nil}),
8368 want: addr(struct{ X fmt.Stringer }{addr(net.IPv4(1, 1, 1, 1))}),
8369 }, {
8370 name: jsontest.Name("Functions/Interface/NilPointerNetIP/Override"),
8371 opts: []Options{
8372 WithUnmarshalers(JoinUnmarshalers(
8373 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *fmt.Stringer) error {
8374 *v = (*net.IP)(nil)
8375 return SkipFunc
8376 }),
8377 UnmarshalFunc(func(b []byte, v *net.IP) error {
8378 b = bytes.ReplaceAll(b, []byte(`1`), []byte(`8`))
8379 return v.UnmarshalText(bytes.Trim(b, `"`))
8380 }),
8381 )),
8382 },
8383 inBuf: `{"X":"1.1.1.1"}`,
8384 inVal: addr(struct{ X fmt.Stringer }{nil}),
8385 want: addr(struct{ X fmt.Stringer }{addr(net.IPv4(8, 8, 8, 8))}),
8386 }, {
8387 name: jsontest.Name("Functions/Interface/Any"),
8388 inBuf: `[null,{},{},{},{},{},{},{},{},{},{},{},{},"LAST"]`,
8389 inVal: addr([...]any{
8390 nil,
8391 valueStringer{},
8392 (*valueStringer)(nil),
8393 addr(valueStringer{}),
8394 (**valueStringer)(nil),
8395 addr((*valueStringer)(nil)),
8396 addr(addr(valueStringer{})),
8397 pointerStringer{},
8398 (*pointerStringer)(nil),
8399 addr(pointerStringer{}),
8400 (**pointerStringer)(nil),
8401 addr((*pointerStringer)(nil)),
8402 addr(addr(pointerStringer{})),
8403 "LAST",
8404 }),
8405 opts: []Options{
8406 WithUnmarshalers(func() *Unmarshalers {
8407 type P struct {
8408 D int
8409 N int64
8410 }
8411 type PV struct {
8412 P P
8413 V any
8414 }
8415
8416 var lastChecks []func() error
8417 checkLast := func() error {
8418 for _, fn := range lastChecks {
8419 if err := fn(); err != nil {
8420 return err
8421 }
8422 }
8423 return SkipFunc
8424 }
8425 makeValueChecker := func(name string, want []PV) func(d *jsontext.Decoder, v any) error {
8426 checkNext := func(d *jsontext.Decoder, v any) error {
8427 xd := export.Decoder(d)
8428 p := P{len(xd.Tokens.Stack), xd.Tokens.Last.Length()}
8429 rv := reflect.ValueOf(v)
8430 pv := PV{p, v}
8431 switch {
8432 case len(want) == 0:
8433 return fmt.Errorf("%s: %v: got more values than expected", name, p)
8434 case !rv.IsValid() || rv.Kind() != reflect.Pointer || rv.IsNil():
8435 return fmt.Errorf("%s: %v: got %#v, want non-nil pointer type", name, p, v)
8436 case !reflect.DeepEqual(pv, want[0]):
8437 return fmt.Errorf("%s:\n\tgot %#v\n\twant %#v", name, pv, want[0])
8438 default:
8439 want = want[1:]
8440 return SkipFunc
8441 }
8442 }
8443 lastChecks = append(lastChecks, func() error {
8444 if len(want) > 0 {
8445 return fmt.Errorf("%s: did not get enough values, want %d more", name, len(want))
8446 }
8447 return nil
8448 })
8449 return checkNext
8450 }
8451 makePositionChecker := func(name string, want []P) func(d *jsontext.Decoder, v any) error {
8452 checkNext := func(d *jsontext.Decoder, v any) error {
8453 xd := export.Decoder(d)
8454 p := P{len(xd.Tokens.Stack), xd.Tokens.Last.Length()}
8455 switch {
8456 case len(want) == 0:
8457 return fmt.Errorf("%s: %v: got more values than wanted", name, p)
8458 case p != want[0]:
8459 return fmt.Errorf("%s: got %v, want %v", name, p, want[0])
8460 default:
8461 want = want[1:]
8462 return SkipFunc
8463 }
8464 }
8465 lastChecks = append(lastChecks, func() error {
8466 if len(want) > 0 {
8467 return fmt.Errorf("%s: did not get enough values, want %d more", name, len(want))
8468 }
8469 return nil
8470 })
8471 return checkNext
8472 }
8473
8474
8475
8476 wantAny := []PV{
8477 {P{1, 0}, addr(any(nil))},
8478 {P{1, 1}, addr(any(valueStringer{}))},
8479 {P{1, 1}, addr(valueStringer{})},
8480 {P{1, 2}, addr(any((*valueStringer)(nil)))},
8481 {P{1, 2}, addr((*valueStringer)(nil))},
8482 {P{1, 2}, addr(valueStringer{})},
8483 {P{1, 3}, addr(any(addr(valueStringer{})))},
8484 {P{1, 3}, addr(addr(valueStringer{}))},
8485 {P{1, 3}, addr(valueStringer{})},
8486 {P{1, 4}, addr(any((**valueStringer)(nil)))},
8487 {P{1, 4}, addr((**valueStringer)(nil))},
8488 {P{1, 4}, addr((*valueStringer)(nil))},
8489 {P{1, 4}, addr(valueStringer{})},
8490 {P{1, 5}, addr(any(addr((*valueStringer)(nil))))},
8491 {P{1, 5}, addr(addr((*valueStringer)(nil)))},
8492 {P{1, 5}, addr((*valueStringer)(nil))},
8493 {P{1, 5}, addr(valueStringer{})},
8494 {P{1, 6}, addr(any(addr(addr(valueStringer{}))))},
8495 {P{1, 6}, addr(addr(addr(valueStringer{})))},
8496 {P{1, 6}, addr(addr(valueStringer{}))},
8497 {P{1, 6}, addr(valueStringer{})},
8498 {P{1, 7}, addr(any(pointerStringer{}))},
8499 {P{1, 7}, addr(pointerStringer{})},
8500 {P{1, 8}, addr(any((*pointerStringer)(nil)))},
8501 {P{1, 8}, addr((*pointerStringer)(nil))},
8502 {P{1, 8}, addr(pointerStringer{})},
8503 {P{1, 9}, addr(any(addr(pointerStringer{})))},
8504 {P{1, 9}, addr(addr(pointerStringer{}))},
8505 {P{1, 9}, addr(pointerStringer{})},
8506 {P{1, 10}, addr(any((**pointerStringer)(nil)))},
8507 {P{1, 10}, addr((**pointerStringer)(nil))},
8508 {P{1, 10}, addr((*pointerStringer)(nil))},
8509 {P{1, 10}, addr(pointerStringer{})},
8510 {P{1, 11}, addr(any(addr((*pointerStringer)(nil))))},
8511 {P{1, 11}, addr(addr((*pointerStringer)(nil)))},
8512 {P{1, 11}, addr((*pointerStringer)(nil))},
8513 {P{1, 11}, addr(pointerStringer{})},
8514 {P{1, 12}, addr(any(addr(addr(pointerStringer{}))))},
8515 {P{1, 12}, addr(addr(addr(pointerStringer{})))},
8516 {P{1, 12}, addr(addr(pointerStringer{}))},
8517 {P{1, 12}, addr(pointerStringer{})},
8518 {P{1, 13}, addr(any("LAST"))},
8519 {P{1, 13}, addr("LAST")},
8520 }
8521 checkAny := makeValueChecker("any", wantAny)
8522 anyUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v any) error {
8523 return checkAny(dec, v)
8524 })
8525
8526 var wantPointerAny []PV
8527 for _, v := range wantAny {
8528 if _, ok := v.V.(*any); ok {
8529 wantPointerAny = append(wantPointerAny, v)
8530 }
8531 }
8532 checkPointerAny := makeValueChecker("*any", wantPointerAny)
8533 pointerAnyUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v *any) error {
8534 return checkPointerAny(dec, v)
8535 })
8536
8537 checkNamedAny := makeValueChecker("namedAny", wantAny)
8538 namedAnyUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v namedAny) error {
8539 return checkNamedAny(dec, v)
8540 })
8541
8542 checkPointerNamedAny := makeValueChecker("*namedAny", nil)
8543 pointerNamedAnyUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v *namedAny) error {
8544 return checkPointerNamedAny(dec, v)
8545 })
8546
8547 type stringer = fmt.Stringer
8548 var wantStringer []PV
8549 for _, v := range wantAny {
8550 if _, ok := v.V.(stringer); ok {
8551 wantStringer = append(wantStringer, v)
8552 }
8553 }
8554 checkStringer := makeValueChecker("stringer", wantStringer)
8555 stringerUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v stringer) error {
8556 return checkStringer(dec, v)
8557 })
8558
8559 checkPointerStringer := makeValueChecker("*stringer", nil)
8560 pointerStringerUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v *stringer) error {
8561 return checkPointerStringer(dec, v)
8562 })
8563
8564 wantValueStringer := []P{{1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {1, 6}}
8565 checkPointerValueStringer := makePositionChecker("*valueStringer", wantValueStringer)
8566 pointerValueStringerUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v *valueStringer) error {
8567 return checkPointerValueStringer(dec, v)
8568 })
8569
8570 wantPointerStringer := []P{{1, 7}, {1, 8}, {1, 9}, {1, 10}, {1, 11}, {1, 12}}
8571 checkPointerPointerStringer := makePositionChecker("*pointerStringer", wantPointerStringer)
8572 pointerPointerStringerUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v *pointerStringer) error {
8573 return checkPointerPointerStringer(dec, v)
8574 })
8575
8576 lastUnmarshaler := UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8577 return checkLast()
8578 })
8579
8580 return JoinUnmarshalers(
8581
8582
8583 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *[14]any) error {
8584 if _, err := dec.ReadToken(); err != nil {
8585 return err
8586 }
8587 for i := range len(*v) {
8588 if err := UnmarshalDecode(dec, &(*v)[i]); err != nil {
8589 return err
8590 }
8591 }
8592 if _, err := dec.ReadToken(); err != nil {
8593 return err
8594 }
8595 return nil
8596 }),
8597
8598 anyUnmarshaler,
8599 pointerAnyUnmarshaler,
8600 namedAnyUnmarshaler,
8601 pointerNamedAnyUnmarshaler,
8602 stringerUnmarshaler,
8603 pointerStringerUnmarshaler,
8604 pointerValueStringerUnmarshaler,
8605 pointerPointerStringerUnmarshaler,
8606 lastUnmarshaler,
8607 )
8608 }()),
8609 },
8610 }, {
8611 name: jsontest.Name("Functions/Precedence/V1First"),
8612 opts: []Options{
8613 WithUnmarshalers(JoinUnmarshalers(
8614 UnmarshalFunc(func(b []byte, v *string) error {
8615 if string(b) != `"called"` {
8616 return fmt.Errorf("got %s, want %s", b, `"called"`)
8617 }
8618 *v = "called"
8619 return nil
8620 }),
8621 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8622 panic("should not be called")
8623 }),
8624 )),
8625 },
8626 inBuf: `"called"`,
8627 inVal: addr(""),
8628 want: addr("called"),
8629 }, {
8630 name: jsontest.Name("Functions/Precedence/V2First"),
8631 opts: []Options{
8632 WithUnmarshalers(JoinUnmarshalers(
8633 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8634 switch t, err := dec.ReadToken(); {
8635 case err != nil:
8636 return err
8637 case t.String() != "called":
8638 return fmt.Errorf("got %q, want %q", t, "called")
8639 }
8640 *v = "called"
8641 return nil
8642 }),
8643 UnmarshalFunc(func([]byte, *string) error {
8644 panic("should not be called")
8645 }),
8646 )),
8647 },
8648 inBuf: `"called"`,
8649 inVal: addr(""),
8650 want: addr("called"),
8651 }, {
8652 name: jsontest.Name("Functions/Precedence/V2Skipped"),
8653 opts: []Options{
8654 WithUnmarshalers(JoinUnmarshalers(
8655 UnmarshalFromFunc(func(dec *jsontext.Decoder, v *string) error {
8656 return SkipFunc
8657 }),
8658 UnmarshalFunc(func(b []byte, v *string) error {
8659 if string(b) != `"called"` {
8660 return fmt.Errorf("got %s, want %s", b, `"called"`)
8661 }
8662 *v = "called"
8663 return nil
8664 }),
8665 )),
8666 },
8667 inBuf: `"called"`,
8668 inVal: addr(""),
8669 want: addr("called"),
8670 }, {
8671 name: jsontest.Name("Functions/Precedence/NestedFirst"),
8672 opts: []Options{
8673 WithUnmarshalers(JoinUnmarshalers(
8674 JoinUnmarshalers(
8675 UnmarshalFunc(func(b []byte, v *string) error {
8676 if string(b) != `"called"` {
8677 return fmt.Errorf("got %s, want %s", b, `"called"`)
8678 }
8679 *v = "called"
8680 return nil
8681 }),
8682 ),
8683 UnmarshalFunc(func([]byte, *string) error {
8684 panic("should not be called")
8685 }),
8686 )),
8687 },
8688 inBuf: `"called"`,
8689 inVal: addr(""),
8690 want: addr("called"),
8691 }, {
8692 name: jsontest.Name("Functions/Precedence/NestedLast"),
8693 opts: []Options{
8694 WithUnmarshalers(JoinUnmarshalers(
8695 UnmarshalFunc(func(b []byte, v *string) error {
8696 if string(b) != `"called"` {
8697 return fmt.Errorf("got %s, want %s", b, `"called"`)
8698 }
8699 *v = "called"
8700 return nil
8701 }),
8702 JoinUnmarshalers(
8703 UnmarshalFunc(func([]byte, *string) error {
8704 panic("should not be called")
8705 }),
8706 ),
8707 )),
8708 },
8709 inBuf: `"called"`,
8710 inVal: addr(""),
8711 want: addr("called"),
8712 }, {
8713 name: jsontest.Name("Duration/Null"),
8714 inBuf: `{"D1":null,"D2":null}`,
8715 inVal: addr(struct {
8716 D1 time.Duration
8717 D2 time.Duration `json:",format:nano"`
8718 }{1, 1}),
8719 want: addr(struct {
8720 D1 time.Duration
8721 D2 time.Duration `json:",format:nano"`
8722 }{0, 0}),
8723 }, {
8724 name: jsontest.Name("Duration/Zero"),
8725 inBuf: `{"D1":"0s","D2":0}`,
8726 inVal: addr(struct {
8727 D1 time.Duration
8728 D2 time.Duration `json:",format:nano"`
8729 }{1, 1}),
8730 want: addr(struct {
8731 D1 time.Duration
8732 D2 time.Duration `json:",format:nano"`
8733 }{0, 0}),
8734 }, {
8735 name: jsontest.Name("Duration/Positive"),
8736 inBuf: `{"D1":"34293h33m9.123456789s","D2":123456789123456789}`,
8737 inVal: new(struct {
8738 D1 time.Duration
8739 D2 time.Duration `json:",format:nano"`
8740 }),
8741 want: addr(struct {
8742 D1 time.Duration
8743 D2 time.Duration `json:",format:nano"`
8744 }{
8745 123456789123456789,
8746 123456789123456789,
8747 }),
8748 }, {
8749 name: jsontest.Name("Duration/Negative"),
8750 inBuf: `{"D1":"-34293h33m9.123456789s","D2":-123456789123456789}`,
8751 inVal: new(struct {
8752 D1 time.Duration
8753 D2 time.Duration `json:",format:nano"`
8754 }),
8755 want: addr(struct {
8756 D1 time.Duration
8757 D2 time.Duration `json:",format:nano"`
8758 }{
8759 -123456789123456789,
8760 -123456789123456789,
8761 }),
8762 }, {
8763 name: jsontest.Name("Duration/Nanos/String"),
8764 inBuf: `{"D":"12345"}`,
8765 inVal: addr(struct {
8766 D time.Duration `json:",string,format:nano"`
8767 }{1}),
8768 want: addr(struct {
8769 D time.Duration `json:",string,format:nano"`
8770 }{12345}),
8771 }, {
8772 name: jsontest.Name("Duration/Nanos/String/Invalid"),
8773 inBuf: `{"D":"+12345"}`,
8774 inVal: addr(struct {
8775 D time.Duration `json:",string,format:nano"`
8776 }{1}),
8777 want: addr(struct {
8778 D time.Duration `json:",string,format:nano"`
8779 }{1}),
8780 wantErr: EU(fmt.Errorf(`invalid duration "+12345": %w`, strconv.ErrSyntax)).withPos(`{"D":`, "/D").withType('"', timeDurationType),
8781 }, {
8782 name: jsontest.Name("Duration/Nanos/Mismatch"),
8783 inBuf: `{"D":"34293h33m9.123456789s"}`,
8784 inVal: addr(struct {
8785 D time.Duration `json:",format:nano"`
8786 }{1}),
8787 want: addr(struct {
8788 D time.Duration `json:",format:nano"`
8789 }{1}),
8790 wantErr: EU(nil).withPos(`{"D":`, "/D").withType('"', timeDurationType),
8791 }, {
8792 name: jsontest.Name("Duration/Nanos"),
8793 inBuf: `{"D":1.324}`,
8794 inVal: addr(struct {
8795 D time.Duration `json:",format:nano"`
8796 }{-1}),
8797 want: addr(struct {
8798 D time.Duration `json:",format:nano"`
8799 }{1}),
8800 }, {
8801 name: jsontest.Name("Duration/String/Mismatch"),
8802 inBuf: `{"D":-123456789123456789}`,
8803 inVal: addr(struct {
8804 D time.Duration
8805 }{1}),
8806 want: addr(struct {
8807 D time.Duration
8808 }{1}),
8809 wantErr: EU(nil).withPos(`{"D":`, "/D").withType('0', timeDurationType),
8810 }, {
8811 name: jsontest.Name("Duration/String/Invalid"),
8812 inBuf: `{"D":"5minkutes"}`,
8813 inVal: addr(struct {
8814 D time.Duration
8815 }{1}),
8816 want: addr(struct {
8817 D time.Duration
8818 }{1}),
8819 wantErr: EU(func() error {
8820 _, err := time.ParseDuration("5minkutes")
8821 return err
8822 }()).withPos(`{"D":`, "/D").withType('"', timeDurationType),
8823 }, {
8824 name: jsontest.Name("Duration/Syntax/Invalid"),
8825 inBuf: `{"D":x}`,
8826 inVal: addr(struct {
8827 D time.Duration
8828 }{1}),
8829 want: addr(struct {
8830 D time.Duration
8831 }{1}),
8832 wantErr: newInvalidCharacterError("x", "at start of value", len64(`{"D":`), "/D"),
8833 }, {
8834 name: jsontest.Name("Duration/Format/Invalid"),
8835 inBuf: `{"D":"0s"}`,
8836 inVal: addr(struct {
8837 D time.Duration `json:",format:invalid"`
8838 }{1}),
8839 want: addr(struct {
8840 D time.Duration `json:",format:invalid"`
8841 }{1}),
8842 wantErr: EU(errInvalidFormatFlag).withPos(`{"D":`, "/D").withType(0, timeDurationType),
8843 }, {
8844 name: jsontest.Name("Duration/Format/Legacy"),
8845 inBuf: `{"D1":45296078090012,"D2":"12h34m56.078090012s"}`,
8846 opts: []Options{jsonflags.FormatTimeWithLegacySemantics | 1},
8847 inVal: new(structDurationFormat),
8848 want: addr(structDurationFormat{
8849 D1: 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
8850 D2: 12*time.Hour + 34*time.Minute + 56*time.Second + 78*time.Millisecond + 90*time.Microsecond + 12*time.Nanosecond,
8851 }),
8852 }, {
8853 name: jsontest.Name("Duration/MapKey"),
8854 inBuf: `{"1s":""}`,
8855 inVal: new(map[time.Duration]string),
8856 want: addr(map[time.Duration]string{time.Second: ""}),
8857 }, {
8858 name: jsontest.Name("Duration/MapKey/Legacy"),
8859 opts: []Options{jsonflags.FormatTimeWithLegacySemantics | 1},
8860 inBuf: `{"1000000000":""}`,
8861 inVal: new(map[time.Duration]string),
8862 want: addr(map[time.Duration]string{time.Second: ""}),
8863 }, {
8864 name: jsontest.Name("Duration/IgnoreInvalidFormat"),
8865 opts: []Options{invalidFormatOption},
8866 inBuf: `"1s"`,
8867 inVal: addr(time.Duration(0)),
8868 want: addr(time.Second),
8869 }, {
8870 name: jsontest.Name("Time/Zero"),
8871 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"}`,
8872 inVal: new(struct {
8873 T1 time.Time
8874 T2 time.Time `json:",format:RFC822"`
8875 T3 time.Time `json:",format:'2006-01-02'"`
8876 T4 time.Time `json:",omitzero"`
8877 T5 time.Time `json:",omitempty"`
8878 }),
8879 want: addr(struct {
8880 T1 time.Time
8881 T2 time.Time `json:",format:RFC822"`
8882 T3 time.Time `json:",format:'2006-01-02'"`
8883 T4 time.Time `json:",omitzero"`
8884 T5 time.Time `json:",omitempty"`
8885 }{
8886 mustParseTime(time.RFC3339Nano, "0001-01-01T00:00:00Z"),
8887 mustParseTime(time.RFC822, "01 Jan 01 00:00 UTC"),
8888 mustParseTime("2006-01-02", "0001-01-01"),
8889 mustParseTime(time.RFC3339Nano, "0001-01-01T00:00:00Z"),
8890 mustParseTime(time.RFC3339Nano, "0001-01-01T00:00:00Z"),
8891 }),
8892 }, {
8893 name: jsontest.Name("Time/Format"),
8894 inBuf: `{
8895 "T1": "1234-01-02T03:04:05.000000006Z",
8896 "T2": "Mon Jan 2 03:04:05 1234",
8897 "T3": "Mon Jan 2 03:04:05 UTC 1234",
8898 "T4": "Mon Jan 02 03:04:05 +0000 1234",
8899 "T5": "02 Jan 34 03:04 UTC",
8900 "T6": "02 Jan 34 03:04 +0000",
8901 "T7": "Monday, 02-Jan-34 03:04:05 UTC",
8902 "T8": "Mon, 02 Jan 1234 03:04:05 UTC",
8903 "T9": "Mon, 02 Jan 1234 03:04:05 +0000",
8904 "T10": "1234-01-02T03:04:05Z",
8905 "T11": "1234-01-02T03:04:05.000000006Z",
8906 "T12": "3:04AM",
8907 "T13": "Jan 2 03:04:05",
8908 "T14": "Jan 2 03:04:05.000",
8909 "T15": "Jan 2 03:04:05.000000",
8910 "T16": "Jan 2 03:04:05.000000006",
8911 "T17": "1234-01-02 03:04:05",
8912 "T18": "1234-01-02",
8913 "T19": "03:04:05",
8914 "T20": "1234-01-02",
8915 "T21": "\"weird\"1234",
8916 "T22": -23225777754.999999994,
8917 "T23": "-23225777754.999999994",
8918 "T24": -23225777754999.999994,
8919 "T25": "-23225777754999.999994",
8920 "T26": -23225777754999999.994,
8921 "T27": "-23225777754999999.994",
8922 "T28": -23225777754999999994,
8923 "T29": "-23225777754999999994"
8924 }`,
8925 inVal: new(structTimeFormat),
8926 want: addr(structTimeFormat{
8927 mustParseTime(time.RFC3339Nano, "1234-01-02T03:04:05.000000006Z"),
8928 mustParseTime(time.ANSIC, "Mon Jan 2 03:04:05 1234"),
8929 mustParseTime(time.UnixDate, "Mon Jan 2 03:04:05 UTC 1234"),
8930 mustParseTime(time.RubyDate, "Mon Jan 02 03:04:05 +0000 1234"),
8931 mustParseTime(time.RFC822, "02 Jan 34 03:04 UTC"),
8932 mustParseTime(time.RFC822Z, "02 Jan 34 03:04 +0000"),
8933 mustParseTime(time.RFC850, "Monday, 02-Jan-34 03:04:05 UTC"),
8934 mustParseTime(time.RFC1123, "Mon, 02 Jan 1234 03:04:05 UTC"),
8935 mustParseTime(time.RFC1123Z, "Mon, 02 Jan 1234 03:04:05 +0000"),
8936 mustParseTime(time.RFC3339, "1234-01-02T03:04:05Z"),
8937 mustParseTime(time.RFC3339Nano, "1234-01-02T03:04:05.000000006Z"),
8938 mustParseTime(time.Kitchen, "3:04AM"),
8939 mustParseTime(time.Stamp, "Jan 2 03:04:05"),
8940 mustParseTime(time.StampMilli, "Jan 2 03:04:05.000"),
8941 mustParseTime(time.StampMicro, "Jan 2 03:04:05.000000"),
8942 mustParseTime(time.StampNano, "Jan 2 03:04:05.000000006"),
8943 mustParseTime(time.DateTime, "1234-01-02 03:04:05"),
8944 mustParseTime(time.DateOnly, "1234-01-02"),
8945 mustParseTime(time.TimeOnly, "03:04:05"),
8946 mustParseTime("2006-01-02", "1234-01-02"),
8947 mustParseTime(`\"weird\"2006`, `\"weird\"1234`),
8948 time.Unix(-23225777755, 6).UTC(),
8949 time.Unix(-23225777755, 6).UTC(),
8950 time.Unix(-23225777755, 6).UTC(),
8951 time.Unix(-23225777755, 6).UTC(),
8952 time.Unix(-23225777755, 6).UTC(),
8953 time.Unix(-23225777755, 6).UTC(),
8954 time.Unix(-23225777755, 6).UTC(),
8955 time.Unix(-23225777755, 6).UTC(),
8956 }),
8957 }, {
8958 name: jsontest.Name("Time/Format/UnixString/InvalidNumber"),
8959 inBuf: `{
8960 "T23": -23225777754.999999994,
8961 "T25": -23225777754999.999994,
8962 "T27": -23225777754999999.994,
8963 "T29": -23225777754999999994
8964 }`,
8965 inVal: new(structTimeFormat),
8966 want: new(structTimeFormat),
8967 wantErr: EU(nil).withPos(`{`+"\n\t\t\t"+`"T23": `, "/T23").withType('0', timeTimeType),
8968 }, {
8969 name: jsontest.Name("Time/Format/UnixString/InvalidString"),
8970 inBuf: `{
8971 "T22": "-23225777754.999999994",
8972 "T24": "-23225777754999.999994",
8973 "T26": "-23225777754999999.994",
8974 "T28": "-23225777754999999994"
8975 }`,
8976 inVal: new(structTimeFormat),
8977 want: new(structTimeFormat),
8978 wantErr: EU(nil).withPos(`{`+"\n\t\t\t"+`"T22": `, "/T22").withType('"', timeTimeType),
8979 }, {
8980 name: jsontest.Name("Time/Format/Null"),
8981 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}`,
8982 inVal: addr(structTimeFormat{
8983 mustParseTime(time.RFC3339Nano, "1234-01-02T03:04:05.000000006Z"),
8984 mustParseTime(time.ANSIC, "Mon Jan 2 03:04:05 1234"),
8985 mustParseTime(time.UnixDate, "Mon Jan 2 03:04:05 UTC 1234"),
8986 mustParseTime(time.RubyDate, "Mon Jan 02 03:04:05 +0000 1234"),
8987 mustParseTime(time.RFC822, "02 Jan 34 03:04 UTC"),
8988 mustParseTime(time.RFC822Z, "02 Jan 34 03:04 +0000"),
8989 mustParseTime(time.RFC850, "Monday, 02-Jan-34 03:04:05 UTC"),
8990 mustParseTime(time.RFC1123, "Mon, 02 Jan 1234 03:04:05 UTC"),
8991 mustParseTime(time.RFC1123Z, "Mon, 02 Jan 1234 03:04:05 +0000"),
8992 mustParseTime(time.RFC3339, "1234-01-02T03:04:05Z"),
8993 mustParseTime(time.RFC3339Nano, "1234-01-02T03:04:05.000000006Z"),
8994 mustParseTime(time.Kitchen, "3:04AM"),
8995 mustParseTime(time.Stamp, "Jan 2 03:04:05"),
8996 mustParseTime(time.StampMilli, "Jan 2 03:04:05.000"),
8997 mustParseTime(time.StampMicro, "Jan 2 03:04:05.000000"),
8998 mustParseTime(time.StampNano, "Jan 2 03:04:05.000000006"),
8999 mustParseTime(time.DateTime, "1234-01-02 03:04:05"),
9000 mustParseTime(time.DateOnly, "1234-01-02"),
9001 mustParseTime(time.TimeOnly, "03:04:05"),
9002 mustParseTime("2006-01-02", "1234-01-02"),
9003 mustParseTime(`\"weird\"2006`, `\"weird\"1234`),
9004 time.Unix(-23225777755, 6).UTC(),
9005 time.Unix(-23225777755, 6).UTC(),
9006 time.Unix(-23225777755, 6).UTC(),
9007 time.Unix(-23225777755, 6).UTC(),
9008 time.Unix(-23225777755, 6).UTC(),
9009 time.Unix(-23225777755, 6).UTC(),
9010 time.Unix(-23225777755, 6).UTC(),
9011 time.Unix(-23225777755, 6).UTC(),
9012 }),
9013 want: new(structTimeFormat),
9014 }, {
9015 name: jsontest.Name("Time/RFC3339/Mismatch"),
9016 inBuf: `{"T":1234}`,
9017 inVal: new(struct {
9018 T time.Time
9019 }),
9020 wantErr: EU(nil).withPos(`{"T":`, "/T").withType('0', timeTimeType),
9021 }, {
9022 name: jsontest.Name("Time/RFC3339/ParseError"),
9023 inBuf: `{"T":"2021-09-29T12:44:52"}`,
9024 inVal: new(struct {
9025 T time.Time
9026 }),
9027 wantErr: EU(func() error {
9028 _, err := time.Parse(time.RFC3339, "2021-09-29T12:44:52")
9029 return err
9030 }()).withPos(`{"T":`, "/T").withType('"', timeTimeType),
9031 }, {
9032 name: jsontest.Name("Time/Format/Invalid"),
9033 inBuf: `{"T":""}`,
9034 inVal: new(struct {
9035 T time.Time `json:",format:UndefinedConstant"`
9036 }),
9037 wantErr: EU(errors.New(`invalid format flag "UndefinedConstant"`)).withPos(`{"T":`, "/T").withType(0, timeTimeType),
9038 }, {
9039 name: jsontest.Name("Time/Format/SingleDigitHour"),
9040 inBuf: `{"T":"2000-01-01T1:12:34Z"}`,
9041 inVal: new(struct{ T time.Time }),
9042 wantErr: EU(newParseTimeError(time.RFC3339, "2000-01-01T1:12:34Z", "15", "1", "")).withPos(`{"T":`, "/T").withType('"', timeTimeType),
9043 }, {
9044 name: jsontest.Name("Time/Format/SubsecondComma"),
9045 inBuf: `{"T":"2000-01-01T00:00:00,000Z"}`,
9046 inVal: new(struct{ T time.Time }),
9047 wantErr: EU(newParseTimeError(time.RFC3339, "2000-01-01T00:00:00,000Z", ".", ",", "")).withPos(`{"T":`, "/T").withType('"', timeTimeType),
9048 }, {
9049 name: jsontest.Name("Time/Format/TimezoneHourOverflow"),
9050 inBuf: `{"T":"2000-01-01T00:00:00+24:00"}`,
9051 inVal: new(struct{ T time.Time }),
9052 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),
9053 }, {
9054 name: jsontest.Name("Time/Format/TimezoneMinuteOverflow"),
9055 inBuf: `{"T":"2000-01-01T00:00:00+00:60"}`,
9056 inVal: new(struct{ T time.Time }),
9057 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),
9058 }, {
9059 name: jsontest.Name("Time/Syntax/Invalid"),
9060 inBuf: `{"T":x}`,
9061 inVal: new(struct {
9062 T time.Time
9063 }),
9064 wantErr: newInvalidCharacterError("x", "at start of value", len64(`{"T":`), "/T"),
9065 }, {
9066 name: jsontest.Name("Time/IgnoreInvalidFormat"),
9067 opts: []Options{invalidFormatOption},
9068 inBuf: `"2000-01-01T00:00:00Z"`,
9069 inVal: addr(time.Time{}),
9070 want: addr(time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC)),
9071 }}
9072
9073 for _, tt := range tests {
9074 t.Run(tt.name.Name, func(t *testing.T) {
9075 got := tt.inVal
9076 gotErr := Unmarshal([]byte(tt.inBuf), got, tt.opts...)
9077 if !reflect.DeepEqual(got, tt.want) && tt.want != nil {
9078 t.Errorf("%s: Unmarshal output mismatch:\ngot %v\nwant %v", tt.name.Where, got, tt.want)
9079 }
9080 if !reflect.DeepEqual(gotErr, tt.wantErr) {
9081 t.Errorf("%s: Unmarshal error mismatch:\ngot %v\nwant %v", tt.name.Where, gotErr, tt.wantErr)
9082 }
9083 })
9084 }
9085 }
9086
9087 func TestMarshalInvalidNamespace(t *testing.T) {
9088 tests := []struct {
9089 name jsontest.CaseName
9090 val any
9091 }{
9092 {jsontest.Name("Map"), map[string]string{"X": "\xde\xad\xbe\xef"}},
9093 {jsontest.Name("Struct"), struct{ X string }{"\xde\xad\xbe\xef"}},
9094 }
9095 for _, tt := range tests {
9096 t.Run(tt.name.Name, func(t *testing.T) {
9097 enc := jsontext.NewEncoder(new(bytes.Buffer))
9098 if err := MarshalEncode(enc, tt.val); err == nil {
9099 t.Fatalf("%s: MarshalEncode error is nil, want non-nil", tt.name.Where)
9100 }
9101 for _, tok := range []jsontext.Token{
9102 jsontext.Null, jsontext.String(""), jsontext.Int(0), jsontext.BeginObject, jsontext.EndObject, jsontext.BeginArray, jsontext.EndArray,
9103 } {
9104 if err := enc.WriteToken(tok); err == nil {
9105 t.Fatalf("%s: WriteToken error is nil, want non-nil", tt.name.Where)
9106 }
9107 }
9108 for _, val := range []string{`null`, `""`, `0`, `{}`, `[]`} {
9109 if err := enc.WriteValue([]byte(val)); err == nil {
9110 t.Fatalf("%s: WriteToken error is nil, want non-nil", tt.name.Where)
9111 }
9112 }
9113 })
9114 }
9115 }
9116
9117 func TestUnmarshalInvalidNamespace(t *testing.T) {
9118 tests := []struct {
9119 name jsontest.CaseName
9120 val any
9121 }{
9122 {jsontest.Name("Map"), addr(map[string]int{})},
9123 {jsontest.Name("Struct"), addr(struct{ X int }{})},
9124 }
9125 for _, tt := range tests {
9126 t.Run(tt.name.Name, func(t *testing.T) {
9127 dec := jsontext.NewDecoder(strings.NewReader(`{"X":""}`))
9128 if err := UnmarshalDecode(dec, tt.val); err == nil {
9129 t.Fatalf("%s: UnmarshalDecode error is nil, want non-nil", tt.name.Where)
9130 }
9131 if _, err := dec.ReadToken(); err == nil {
9132 t.Fatalf("%s: ReadToken error is nil, want non-nil", tt.name.Where)
9133 }
9134 if _, err := dec.ReadValue(); err == nil {
9135 t.Fatalf("%s: ReadValue error is nil, want non-nil", tt.name.Where)
9136 }
9137 })
9138 }
9139 }
9140
9141 func TestUnmarshalReuse(t *testing.T) {
9142 t.Run("Bytes", func(t *testing.T) {
9143 in := make([]byte, 3)
9144 want := &in[0]
9145 if err := Unmarshal([]byte(`"AQID"`), &in); err != nil {
9146 t.Fatalf("Unmarshal error: %v", err)
9147 }
9148 got := &in[0]
9149 if got != want {
9150 t.Errorf("input buffer was not reused")
9151 }
9152 })
9153 t.Run("Slices", func(t *testing.T) {
9154 in := make([]int, 3)
9155 want := &in[0]
9156 if err := Unmarshal([]byte(`[0,1,2]`), &in); err != nil {
9157 t.Fatalf("Unmarshal error: %v", err)
9158 }
9159 got := &in[0]
9160 if got != want {
9161 t.Errorf("input slice was not reused")
9162 }
9163 })
9164 t.Run("Maps", func(t *testing.T) {
9165 in := make(map[string]string)
9166 want := reflect.ValueOf(in).Pointer()
9167 if err := Unmarshal([]byte(`{"key":"value"}`), &in); err != nil {
9168 t.Fatalf("Unmarshal error: %v", err)
9169 }
9170 got := reflect.ValueOf(in).Pointer()
9171 if got != want {
9172 t.Errorf("input map was not reused")
9173 }
9174 })
9175 t.Run("Pointers", func(t *testing.T) {
9176 in := addr(addr(addr("hello")))
9177 want := **in
9178 if err := Unmarshal([]byte(`"goodbye"`), &in); err != nil {
9179 t.Fatalf("Unmarshal error: %v", err)
9180 }
9181 got := **in
9182 if got != want {
9183 t.Errorf("input pointer was not reused")
9184 }
9185 })
9186 }
9187
9188 type ReaderFunc func([]byte) (int, error)
9189
9190 func (f ReaderFunc) Read(b []byte) (int, error) { return f(b) }
9191
9192 type WriterFunc func([]byte) (int, error)
9193
9194 func (f WriterFunc) Write(b []byte) (int, error) { return f(b) }
9195
9196 func TestCoderBufferGrowth(t *testing.T) {
9197
9198
9199 checkGrowth := func(ns []int) {
9200 t.Helper()
9201 var sumBytes, sumRates, numGrows float64
9202 prev := ns[0]
9203 for i := 1; i < len(ns)-1; i++ {
9204 n := ns[i]
9205 if n != prev {
9206 sumRates += float64(n) / float64(prev)
9207 numGrows++
9208 prev = n
9209 }
9210 if n > 1<<20 {
9211 t.Fatalf("single Read/Write too large: %d", n)
9212 }
9213 sumBytes += float64(n)
9214 }
9215 if mean := sumBytes / float64(len(ns)); mean < 1<<10 {
9216 t.Fatalf("average Read/Write too small: %0.1f", mean)
9217 }
9218 switch mean := sumRates / numGrows; {
9219 case mean < 1.25:
9220 t.Fatalf("average growth rate too slow: %0.3f", mean)
9221 case mean > 2.00:
9222 t.Fatalf("average growth rate too fast: %0.3f", mean)
9223 }
9224 }
9225
9226
9227
9228 bb := struct{ *bytes.Buffer }{new(bytes.Buffer)}
9229
9230 var writeSizes []int
9231 if err := MarshalWrite(WriterFunc(func(b []byte) (int, error) {
9232 n, err := bb.Write(b)
9233 writeSizes = append(writeSizes, n)
9234 return n, err
9235 }), make([]struct{}, 1e6)); err != nil {
9236 t.Fatalf("MarshalWrite error: %v", err)
9237 }
9238 checkGrowth(writeSizes)
9239
9240 var readSizes []int
9241 if err := UnmarshalRead(ReaderFunc(func(b []byte) (int, error) {
9242 n, err := bb.Read(b)
9243 readSizes = append(readSizes, n)
9244 return n, err
9245 }), new([]struct{})); err != nil {
9246 t.Fatalf("UnmarshalRead error: %v", err)
9247 }
9248 checkGrowth(readSizes)
9249 }
9250
9251 func TestUintSet(t *testing.T) {
9252 type operation any
9253 type has struct {
9254 in uint
9255 want bool
9256 }
9257 type insert struct {
9258 in uint
9259 want bool
9260 }
9261
9262
9263 ops := []operation{
9264 has{0, false},
9265 has{63, false},
9266 has{64, false},
9267 has{1234, false},
9268 insert{3, true},
9269 has{2, false},
9270 has{3, true},
9271 has{4, false},
9272 has{63, false},
9273 insert{3, false},
9274 insert{63, true},
9275 has{63, true},
9276 insert{64, true},
9277 insert{64, false},
9278 has{64, true},
9279 insert{3264, true},
9280 has{3264, true},
9281 insert{3, false},
9282 has{3, true},
9283 }
9284
9285 var us uintSet
9286 for i, op := range ops {
9287 switch op := op.(type) {
9288 case has:
9289 if got := us.has(op.in); got != op.want {
9290 t.Fatalf("%d: uintSet.has(%v) = %v, want %v", i, op.in, got, op.want)
9291 }
9292 case insert:
9293 if got := us.insert(op.in); got != op.want {
9294 t.Fatalf("%d: uintSet.insert(%v) = %v, want %v", i, op.in, got, op.want)
9295 }
9296 default:
9297 panic(fmt.Sprintf("unknown operation: %T", op))
9298 }
9299 }
9300 }
9301
9302 func TestUnmarshalDecodeOptions(t *testing.T) {
9303 var calledFuncs int
9304 var calledOptions Options
9305 in := strings.NewReader(strings.Repeat("\"\xde\xad\xbe\xef\"\n", 5))
9306 dec := jsontext.NewDecoder(in,
9307 jsontext.AllowInvalidUTF8(true),
9308 WithUnmarshalers(UnmarshalFromFunc(func(dec *jsontext.Decoder, _ any) error {
9309 opts := dec.Options()
9310 if v, _ := GetOption(opts, jsontext.AllowInvalidUTF8); !v {
9311 t.Errorf("nested Options.AllowInvalidUTF8 = false, want true")
9312 }
9313 calledFuncs++
9314 calledOptions = opts
9315 return SkipFunc
9316 })),
9317 )
9318
9319 if err := UnmarshalDecode(dec, new(string)); err != nil {
9320 t.Fatalf("UnmarshalDecode: %v", err)
9321 }
9322 if calledFuncs != 1 {
9323 t.Fatalf("calledFuncs = %d, want 1", calledFuncs)
9324 }
9325 if err := UnmarshalDecode(dec, new(string), calledOptions); err != nil {
9326 t.Fatalf("UnmarshalDecode: %v", err)
9327 }
9328 if calledFuncs != 2 {
9329 t.Fatalf("calledFuncs = %d, want 2", calledFuncs)
9330 }
9331 if err := UnmarshalDecode(dec, new(string),
9332 jsontext.AllowInvalidUTF8(false),
9333 WithUnmarshalers(nil),
9334 ); err != nil {
9335 t.Fatalf("UnmarshalDecode: %v", err)
9336 }
9337 if calledFuncs != 2 {
9338 t.Fatalf("calledFuncs = %d, want 2", calledFuncs)
9339 }
9340 if err := UnmarshalDecode(dec, new(string)); err != nil {
9341 t.Fatalf("UnmarshalDecode: %v", err)
9342 }
9343 if calledFuncs != 3 {
9344 t.Fatalf("calledFuncs = %d, want 3", calledFuncs)
9345 }
9346 if err := UnmarshalDecode(dec, new(string), JoinOptions(
9347 jsontext.AllowInvalidUTF8(false),
9348 WithUnmarshalers(UnmarshalFromFunc(func(_ *jsontext.Decoder, _ any) error {
9349 opts := dec.Options()
9350 if v, _ := GetOption(opts, jsontext.AllowInvalidUTF8); !v {
9351 t.Errorf("nested Options.AllowInvalidUTF8 = false, want true")
9352 }
9353 calledFuncs = math.MaxInt
9354 return SkipFunc
9355 })),
9356 )); err != nil {
9357 t.Fatalf("UnmarshalDecode: %v", err)
9358 }
9359 if calledFuncs != math.MaxInt {
9360 t.Fatalf("calledFuncs = %d, want %d", calledFuncs, math.MaxInt)
9361 }
9362
9363
9364
9365 opts := dec.Options()
9366 dec.Reset(in, jsontext.AllowInvalidUTF8(false), opts)
9367 if v, _ := GetOption(dec.Options(), jsontext.AllowInvalidUTF8); v == false {
9368 t.Errorf("Options.AllowInvalidUTF8 = false, want true")
9369 }
9370 }
9371
9372
9373
9374 func BenchmarkUnmarshalDecodeOptions(b *testing.B) {
9375 var i int
9376 in := new(bytes.Buffer)
9377 dec := jsontext.NewDecoder(in)
9378 makeBench := func(opts ...Options) func(*testing.B) {
9379 return func(b *testing.B) {
9380 for range b.N {
9381 in.WriteString("0 ")
9382 }
9383 dec.Reset(in)
9384 b.ResetTimer()
9385 for range b.N {
9386 UnmarshalDecode(dec, &i, opts...)
9387 }
9388 }
9389 }
9390 b.Run("None", makeBench())
9391 b.Run("Same", makeBench(&export.Decoder(dec).Struct))
9392 b.Run("New", makeBench(DefaultOptionsV2()))
9393 }
9394
9395 func TestMarshalEncodeOptions(t *testing.T) {
9396 var calledFuncs int
9397 var calledOptions Options
9398 out := new(bytes.Buffer)
9399 enc := jsontext.NewEncoder(
9400 out,
9401 jsontext.AllowInvalidUTF8(true),
9402 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, _ any) error {
9403 opts := enc.Options()
9404 if v, _ := GetOption(opts, jsontext.AllowInvalidUTF8); !v {
9405 t.Errorf("nested Options.AllowInvalidUTF8 = false, want true")
9406 }
9407 calledFuncs++
9408 calledOptions = opts
9409 return SkipFunc
9410 })),
9411 )
9412
9413 if err := MarshalEncode(enc, "\xde\xad\xbe\xef"); err != nil {
9414 t.Fatalf("MarshalEncode: %v", err)
9415 }
9416 if calledFuncs != 1 {
9417 t.Fatalf("calledFuncs = %d, want 1", calledFuncs)
9418 }
9419 if err := MarshalEncode(enc, "\xde\xad\xbe\xef", calledOptions); err != nil {
9420 t.Fatalf("MarshalEncode: %v", err)
9421 }
9422 if calledFuncs != 2 {
9423 t.Fatalf("calledFuncs = %d, want 2", calledFuncs)
9424 }
9425 if err := MarshalEncode(enc, "\xde\xad\xbe\xef",
9426 jsontext.AllowInvalidUTF8(false),
9427 WithMarshalers(nil),
9428 ); err != nil {
9429 t.Fatalf("MarshalEncode: %v", err)
9430 }
9431 if calledFuncs != 2 {
9432 t.Fatalf("calledFuncs = %d, want 2", calledFuncs)
9433 }
9434 if err := MarshalEncode(enc, "\xde\xad\xbe\xef"); err != nil {
9435 t.Fatalf("MarshalEncode: %v", err)
9436 }
9437 if calledFuncs != 3 {
9438 t.Fatalf("calledFuncs = %d, want 3", calledFuncs)
9439 }
9440 if err := MarshalEncode(enc, "\xde\xad\xbe\xef", JoinOptions(
9441 jsontext.AllowInvalidUTF8(false),
9442 WithMarshalers(MarshalToFunc(func(enc *jsontext.Encoder, _ any) error {
9443 opts := enc.Options()
9444 if v, _ := GetOption(opts, jsontext.AllowInvalidUTF8); !v {
9445 t.Errorf("nested Options.AllowInvalidUTF8 = false, want true")
9446 }
9447 calledFuncs = math.MaxInt
9448 return SkipFunc
9449 })),
9450 )); err != nil {
9451 t.Fatalf("MarshalEncode: %v", err)
9452 }
9453 if calledFuncs != math.MaxInt {
9454 t.Fatalf("calledFuncs = %d, want %d", calledFuncs, math.MaxInt)
9455 }
9456 if out.String() != strings.Repeat("\"\xde\xad\ufffd\ufffd\"\n", 5) {
9457 t.Fatalf("output mismatch:\n\tgot: %s\n\twant: %s", out.String(), strings.Repeat("\"\xde\xad\xbe\xef\"\n", 5))
9458 }
9459
9460
9461
9462 opts := enc.Options()
9463 enc.Reset(out, jsontext.AllowInvalidUTF8(false), opts)
9464 if v, _ := GetOption(enc.Options(), jsontext.AllowInvalidUTF8); v == false {
9465 t.Errorf("Options.AllowInvalidUTF8 = false, want true")
9466 }
9467 }
9468
9469
9470
9471 func BenchmarkMarshalEncodeOptions(b *testing.B) {
9472 var i int
9473 out := new(bytes.Buffer)
9474 enc := jsontext.NewEncoder(out)
9475 makeBench := func(opts ...Options) func(*testing.B) {
9476 return func(b *testing.B) {
9477 out.Reset()
9478 enc.Reset(out)
9479 b.ResetTimer()
9480 for range b.N {
9481 MarshalEncode(enc, &i, opts...)
9482 }
9483 }
9484 }
9485 b.Run("None", makeBench())
9486 b.Run("Same", makeBench(&export.Encoder(enc).Struct))
9487 b.Run("New", makeBench(DefaultOptionsV2()))
9488 }
9489
View as plain text