diff --git a/internal/3rdparty/json/bench_test.go b/internal/3rdparty/json/bench_test.go deleted file mode 100644 index 817ccd6..0000000 --- a/internal/3rdparty/json/bench_test.go +++ /dev/null @@ -1,583 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Large data benchmark. -// The JSON data is a summary of agl's changes in the -// go, webkit, and chromium open source projects. -// We benchmark converting between the JSON form -// and in-memory data structures. - -package json - -import ( - "bytes" - "compress/gzip" - "fmt" - "io" - "os" - "reflect" - "regexp" - "runtime" - "strings" - "sync" - "testing" -) - -type codeResponse struct { - Tree *codeNode `json:"tree"` - Username string `json:"username"` -} - -type codeNode struct { - Name string `json:"name"` - Kids []*codeNode `json:"kids"` - CLWeight float64 `json:"cl_weight"` - Touches int `json:"touches"` - MinT int64 `json:"min_t"` - MaxT int64 `json:"max_t"` - MeanT int64 `json:"mean_t"` -} - -var codeJSON []byte -var codeStruct codeResponse - -func codeInit() { - f, err := os.Open("testdata/code.json.gz") - if err != nil { - panic(err) - } - defer f.Close() - gz, err := gzip.NewReader(f) - if err != nil { - panic(err) - } - data, err := io.ReadAll(gz) - if err != nil { - panic(err) - } - - codeJSON = data - - if err := Unmarshal(codeJSON, &codeStruct); err != nil { - panic("unmarshal code.json: " + err.Error()) - } - - if data, err = Marshal(&codeStruct); err != nil { - panic("marshal code.json: " + err.Error()) - } - - if !bytes.Equal(data, codeJSON) { - println("different lengths", len(data), len(codeJSON)) - for i := 0; i < len(data) && i < len(codeJSON); i++ { - if data[i] != codeJSON[i] { - println("re-marshal: changed at byte", i) - println("orig: ", string(codeJSON[i-10:i+10])) - println("new: ", string(data[i-10:i+10])) - break - } - } - panic("re-marshal code.json: different result") - } -} - -func BenchmarkCodeEncoder(b *testing.B) { - b.ReportAllocs() - if codeJSON == nil { - b.StopTimer() - codeInit() - b.StartTimer() - } - b.RunParallel(func(pb *testing.PB) { - enc := NewEncoder(io.Discard) - for pb.Next() { - if err := enc.Encode(&codeStruct); err != nil { - b.Fatalf("Encode error: %v", err) - } - } - }) - b.SetBytes(int64(len(codeJSON))) -} - -func BenchmarkCodeEncoderError(b *testing.B) { - b.ReportAllocs() - if codeJSON == nil { - b.StopTimer() - codeInit() - b.StartTimer() - } - - // Trigger an error in Marshal with cyclic data. - type Dummy struct { - Name string - Next *Dummy - } - dummy := Dummy{Name: "Dummy"} - dummy.Next = &dummy - - b.RunParallel(func(pb *testing.PB) { - enc := NewEncoder(io.Discard) - for pb.Next() { - if err := enc.Encode(&codeStruct); err != nil { - b.Fatalf("Encode error: %v", err) - } - if _, err := Marshal(dummy); err == nil { - b.Fatal("Marshal error: got nil, want non-nil") - } - } - }) - b.SetBytes(int64(len(codeJSON))) -} - -func BenchmarkCodeMarshal(b *testing.B) { - b.ReportAllocs() - if codeJSON == nil { - b.StopTimer() - codeInit() - b.StartTimer() - } - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - if _, err := Marshal(&codeStruct); err != nil { - b.Fatalf("Marshal error: %v", err) - } - } - }) - b.SetBytes(int64(len(codeJSON))) -} - -func BenchmarkCodeMarshalError(b *testing.B) { - b.ReportAllocs() - if codeJSON == nil { - b.StopTimer() - codeInit() - b.StartTimer() - } - - // Trigger an error in Marshal with cyclic data. - type Dummy struct { - Name string - Next *Dummy - } - dummy := Dummy{Name: "Dummy"} - dummy.Next = &dummy - - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - if _, err := Marshal(&codeStruct); err != nil { - b.Fatalf("Marshal error: %v", err) - } - if _, err := Marshal(dummy); err == nil { - b.Fatal("Marshal error: got nil, want non-nil") - } - } - }) - b.SetBytes(int64(len(codeJSON))) -} - -func benchMarshalBytes(n int) func(*testing.B) { - sample := []byte("hello world") - // Use a struct pointer, to avoid an allocation when passing it as an - // interface parameter to Marshal. - v := &struct { - Bytes []byte - }{ - bytes.Repeat(sample, (n/len(sample))+1)[:n], - } - return func(b *testing.B) { - for i := 0; i < b.N; i++ { - if _, err := Marshal(v); err != nil { - b.Fatalf("Marshal error: %v", err) - } - } - } -} - -func benchMarshalBytesError(n int) func(*testing.B) { - sample := []byte("hello world") - // Use a struct pointer, to avoid an allocation when passing it as an - // interface parameter to Marshal. - v := &struct { - Bytes []byte - }{ - bytes.Repeat(sample, (n/len(sample))+1)[:n], - } - - // Trigger an error in Marshal with cyclic data. - type Dummy struct { - Name string - Next *Dummy - } - dummy := Dummy{Name: "Dummy"} - dummy.Next = &dummy - - return func(b *testing.B) { - for i := 0; i < b.N; i++ { - if _, err := Marshal(v); err != nil { - b.Fatalf("Marshal error: %v", err) - } - if _, err := Marshal(dummy); err == nil { - b.Fatal("Marshal error: got nil, want non-nil") - } - } - } -} - -func BenchmarkMarshalBytes(b *testing.B) { - b.ReportAllocs() - // 32 fits within encodeState.scratch. - b.Run("32", benchMarshalBytes(32)) - // 256 doesn't fit in encodeState.scratch, but is small enough to - // allocate and avoid the slower base64.NewEncoder. - b.Run("256", benchMarshalBytes(256)) - // 4096 is large enough that we want to avoid allocating for it. - b.Run("4096", benchMarshalBytes(4096)) -} - -func BenchmarkMarshalBytesError(b *testing.B) { - b.ReportAllocs() - // 32 fits within encodeState.scratch. - b.Run("32", benchMarshalBytesError(32)) - // 256 doesn't fit in encodeState.scratch, but is small enough to - // allocate and avoid the slower base64.NewEncoder. - b.Run("256", benchMarshalBytesError(256)) - // 4096 is large enough that we want to avoid allocating for it. - b.Run("4096", benchMarshalBytesError(4096)) -} - -func BenchmarkMarshalMap(b *testing.B) { - b.ReportAllocs() - m := map[string]int{ - "key3": 3, - "key2": 2, - "key1": 1, - } - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - if _, err := Marshal(m); err != nil { - b.Fatal("Marshal:", err) - } - } - }) -} - -func BenchmarkCodeDecoder(b *testing.B) { - b.ReportAllocs() - if codeJSON == nil { - b.StopTimer() - codeInit() - b.StartTimer() - } - b.RunParallel(func(pb *testing.PB) { - var buf bytes.Buffer - dec := NewDecoder(&buf) - var r codeResponse - for pb.Next() { - buf.Write(codeJSON) - // hide EOF - buf.WriteByte('\n') - buf.WriteByte('\n') - buf.WriteByte('\n') - if err := dec.Decode(&r); err != nil { - b.Fatalf("Decode error: %v", err) - } - } - }) - b.SetBytes(int64(len(codeJSON))) -} - -func BenchmarkUnicodeDecoder(b *testing.B) { - b.ReportAllocs() - j := []byte(`"\uD83D\uDE01"`) - b.SetBytes(int64(len(j))) - r := bytes.NewReader(j) - dec := NewDecoder(r) - var out string - b.ResetTimer() - for i := 0; i < b.N; i++ { - if err := dec.Decode(&out); err != nil { - b.Fatalf("Decode error: %v", err) - } - r.Seek(0, 0) - } -} - -func BenchmarkDecoderStream(b *testing.B) { - b.ReportAllocs() - b.StopTimer() - var buf bytes.Buffer - dec := NewDecoder(&buf) - buf.WriteString(`"` + strings.Repeat("x", 1000000) + `"` + "\n\n\n") - var x any - if err := dec.Decode(&x); err != nil { - b.Fatalf("Decode error: %v", err) - } - ones := strings.Repeat(" 1\n", 300000) + "\n\n\n" - b.StartTimer() - for i := 0; i < b.N; i++ { - if i%300000 == 0 { - buf.WriteString(ones) - } - x = nil - switch err := dec.Decode(&x); { - case err != nil: - b.Fatalf("Decode error: %v", err) - case x != 1.0: - b.Fatalf("Decode: got %v want 1.0", i) - } - } -} - -func BenchmarkCodeUnmarshal(b *testing.B) { - b.ReportAllocs() - if codeJSON == nil { - b.StopTimer() - codeInit() - b.StartTimer() - } - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - var r codeResponse - if err := Unmarshal(codeJSON, &r); err != nil { - b.Fatalf("Unmarshal error: %v", err) - } - } - }) - b.SetBytes(int64(len(codeJSON))) -} - -func BenchmarkCodeUnmarshalReuse(b *testing.B) { - b.ReportAllocs() - if codeJSON == nil { - b.StopTimer() - codeInit() - b.StartTimer() - } - b.RunParallel(func(pb *testing.PB) { - var r codeResponse - for pb.Next() { - if err := Unmarshal(codeJSON, &r); err != nil { - b.Fatalf("Unmarshal error: %v", err) - } - } - }) - b.SetBytes(int64(len(codeJSON))) -} - -func BenchmarkUnmarshalString(b *testing.B) { - b.ReportAllocs() - data := []byte(`"hello, world"`) - b.RunParallel(func(pb *testing.PB) { - var s string - for pb.Next() { - if err := Unmarshal(data, &s); err != nil { - b.Fatalf("Unmarshal error: %v", err) - } - } - }) -} - -func BenchmarkUnmarshalFloat64(b *testing.B) { - b.ReportAllocs() - data := []byte(`3.14`) - b.RunParallel(func(pb *testing.PB) { - var f float64 - for pb.Next() { - if err := Unmarshal(data, &f); err != nil { - b.Fatalf("Unmarshal error: %v", err) - } - } - }) -} - -func BenchmarkUnmarshalInt64(b *testing.B) { - b.ReportAllocs() - data := []byte(`3`) - b.RunParallel(func(pb *testing.PB) { - var x int64 - for pb.Next() { - if err := Unmarshal(data, &x); err != nil { - b.Fatalf("Unmarshal error: %v", err) - } - } - }) -} - -func BenchmarkUnmarshalMap(b *testing.B) { - b.ReportAllocs() - data := []byte(`{"key1":"value1","key2":"value2","key3":"value3"}`) - b.RunParallel(func(pb *testing.PB) { - x := make(map[string]string, 3) - for pb.Next() { - if err := Unmarshal(data, &x); err != nil { - b.Fatalf("Unmarshal error: %v", err) - } - } - }) -} - -func BenchmarkIssue10335(b *testing.B) { - b.ReportAllocs() - j := []byte(`{"a":{ }}`) - b.RunParallel(func(pb *testing.PB) { - var s struct{} - for pb.Next() { - if err := Unmarshal(j, &s); err != nil { - b.Fatalf("Unmarshal error: %v", err) - } - } - }) -} - -func BenchmarkIssue34127(b *testing.B) { - b.ReportAllocs() - j := struct { - Bar string `json:"bar,string"` - }{ - Bar: `foobar`, - } - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - if _, err := Marshal(&j); err != nil { - b.Fatalf("Marshal error: %v", err) - } - } - }) -} - -func BenchmarkUnmapped(b *testing.B) { - b.ReportAllocs() - j := []byte(`{"s": "hello", "y": 2, "o": {"x": 0}, "a": [1, 99, {"x": 1}]}`) - b.RunParallel(func(pb *testing.PB) { - var s struct{} - for pb.Next() { - if err := Unmarshal(j, &s); err != nil { - b.Fatalf("Unmarshal error: %v", err) - } - } - }) -} - -func BenchmarkTypeFieldsCache(b *testing.B) { - b.ReportAllocs() - var maxTypes int = 1e6 - //if testenv.Builder() != "" { - // maxTypes = 1e3 // restrict cache sizes on builders - //} - - // Dynamically generate many new types. - types := make([]reflect.Type, maxTypes) - fs := []reflect.StructField{{ - Type: reflect.TypeFor[string](), - Index: []int{0}, - }} - for i := range types { - fs[0].Name = fmt.Sprintf("TypeFieldsCache%d", i) - types[i] = reflect.StructOf(fs) - } - - // clearClear clears the cache. Other JSON operations, must not be running. - clearCache := func() { - fieldCache = sync.Map{} - } - - // MissTypes tests the performance of repeated cache misses. - // This measures the time to rebuild a cache of size nt. - for nt := 1; nt <= maxTypes; nt *= 10 { - ts := types[:nt] - b.Run(fmt.Sprintf("MissTypes%d", nt), func(b *testing.B) { - nc := runtime.GOMAXPROCS(0) - for i := 0; i < b.N; i++ { - clearCache() - var wg sync.WaitGroup - for j := 0; j < nc; j++ { - wg.Add(1) - go func(j int) { - for _, t := range ts[(j*len(ts))/nc : ((j+1)*len(ts))/nc] { - cachedTypeFields(t) - } - wg.Done() - }(j) - } - wg.Wait() - } - }) - } - - // HitTypes tests the performance of repeated cache hits. - // This measures the average time of each cache lookup. - for nt := 1; nt <= maxTypes; nt *= 10 { - // Pre-warm a cache of size nt. - clearCache() - for _, t := range types[:nt] { - cachedTypeFields(t) - } - b.Run(fmt.Sprintf("HitTypes%d", nt), func(b *testing.B) { - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - cachedTypeFields(types[0]) - } - }) - }) - } -} - -func BenchmarkEncodeMarshaler(b *testing.B) { - b.ReportAllocs() - - m := struct { - A int - B RawMessage - }{} - - b.RunParallel(func(pb *testing.PB) { - enc := NewEncoder(io.Discard) - - for pb.Next() { - if err := enc.Encode(&m); err != nil { - b.Fatalf("Encode error: %v", err) - } - } - }) -} - -func BenchmarkEncoderEncode(b *testing.B) { - b.ReportAllocs() - type T struct { - X, Y string - } - v := &T{"foo", "bar"} - b.RunParallel(func(pb *testing.PB) { - for pb.Next() { - if err := NewEncoder(io.Discard).Encode(v); err != nil { - b.Fatalf("Encode error: %v", err) - } - } - }) -} - -func BenchmarkNumberIsValid(b *testing.B) { - s := "-61657.61667E+61673" - for i := 0; i < b.N; i++ { - isValidNumber(s) - } -} - -func BenchmarkNumberIsValidRegexp(b *testing.B) { - var jsonNumberRegexp = regexp.MustCompile(`^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?$`) - s := "-61657.61667E+61673" - for i := 0; i < b.N; i++ { - jsonNumberRegexp.MatchString(s) - } -} - -func BenchmarkUnmarshalNumber(b *testing.B) { - b.ReportAllocs() - data := []byte(`"-61657.61667E+61673"`) - var number Number - for i := 0; i < b.N; i++ { - if err := Unmarshal(data, &number); err != nil { - b.Fatal("Unmarshal:", err) - } - } -} diff --git a/internal/3rdparty/json/decode.go b/internal/3rdparty/json/decode.go deleted file mode 100644 index 1dd249a..0000000 --- a/internal/3rdparty/json/decode.go +++ /dev/null @@ -1,1362 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Represents JSON data structure using native Go types: booleans, floats, -// strings, arrays, and maps. - -package json - -import ( - "bytes" - "encoding" - "encoding/base64" - hex2 "encoding/hex" - "fmt" - "github.com/go-jet/jet/v2/internal/utils/datetime" - "reflect" - "strconv" - "strings" - "time" - "unicode" - "unicode/utf16" - "unicode/utf8" - _ "unsafe" // for linkname -) - -// Unmarshal parses the JSON-encoded data and stores the result -// in the value pointed to by v. If v is nil or not a pointer, -// Unmarshal returns an [InvalidUnmarshalError]. -// -// Unmarshal uses the inverse of the encodings that -// [Marshal] uses, allocating maps, slices, and pointers as necessary, -// with the following additional rules: -// -// To unmarshal JSON into a pointer, Unmarshal first handles the case of -// the JSON being the JSON literal null. In that case, Unmarshal sets -// the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into -// the value pointed at by the pointer. If the pointer is nil, Unmarshal -// allocates a new value for it to point to. -// -// To unmarshal JSON into a value implementing [Unmarshaler], -// Unmarshal calls that value's [Unmarshaler.UnmarshalJSON] method, including -// when the input is a JSON null. -// Otherwise, if the value implements [encoding.TextUnmarshaler] -// and the input is a JSON quoted string, Unmarshal calls -// [encoding.TextUnmarshaler.UnmarshalText] with the unquoted form of the string. -// -// To unmarshal JSON into a struct, Unmarshal matches incoming object -// keys to the keys used by [Marshal] (either the struct field name or its tag), -// preferring an exact match but also accepting a case-insensitive match. By -// default, object keys which don't have a corresponding struct field are -// ignored (see [Decoder.DisallowUnknownFields] for an alternative). -// -// To unmarshal JSON into an interface value, -// Unmarshal stores one of these in the interface value: -// -// - bool, for JSON booleans -// - float64, for JSON numbers -// - string, for JSON strings -// - []interface{}, for JSON arrays -// - map[string]interface{}, for JSON objects -// - nil for JSON null -// -// To unmarshal a JSON array into a slice, Unmarshal resets the slice length -// to zero and then appends each element to the slice. -// As a special case, to unmarshal an empty JSON array into a slice, -// Unmarshal replaces the slice with a new empty slice. -// -// To unmarshal a JSON array into a Go array, Unmarshal decodes -// JSON array elements into corresponding Go array elements. -// If the Go array is smaller than the JSON array, -// the additional JSON array elements are discarded. -// If the JSON array is smaller than the Go array, -// the additional Go array elements are set to zero values. -// -// To unmarshal a JSON object into a map, Unmarshal first establishes a map to -// use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal -// reuses the existing map, keeping existing entries. Unmarshal then stores -// key-value pairs from the JSON object into the map. The map's key type must -// either be any string type, an integer, or implement [encoding.TextUnmarshaler]. -// -// If the JSON-encoded data contain a syntax error, Unmarshal returns a [SyntaxError]. -// -// If a JSON value is not appropriate for a given target type, -// or if a JSON number overflows the target type, Unmarshal -// skips that field and completes the unmarshaling as best it can. -// If no more serious errors are encountered, Unmarshal returns -// an [UnmarshalTypeError] describing the earliest such error. In any -// case, it's not guaranteed that all the remaining fields following -// the problematic one will be unmarshaled into the target object. -// -// The JSON null value unmarshals into an interface, map, pointer, or slice -// by setting that Go value to nil. Because null is often used in JSON to mean -// “not present,” unmarshaling a JSON null into any other Go type has no effect -// on the value and produces no error. -// -// When unmarshaling quoted strings, invalid UTF-8 or -// invalid UTF-16 surrogate pairs are not treated as an error. -// Instead, they are replaced by the Unicode replacement -// character U+FFFD. -func Unmarshal(data []byte, v any) error { - // Check for well-formedness. - // Avoids filling out half a data structure - // before discovering a JSON syntax error. - var d decodeState - err := checkValid(data, &d.scan) - if err != nil { - return err - } - - d.init(data) - return d.unmarshal(v) -} - -// Unmarshaler is the interface implemented by types -// that can unmarshal a JSON description of themselves. -// The input can be assumed to be a valid encoding of -// a JSON value. UnmarshalJSON must copy the JSON data -// if it wishes to retain the data after returning. -// -// By convention, to approximate the behavior of [Unmarshal] itself, -// Unmarshalers implement UnmarshalJSON([]byte("null")) as a no-op. -type Unmarshaler interface { - UnmarshalJSON([]byte) error -} - -// An UnmarshalTypeError describes a JSON value that was -// not appropriate for a value of a specific Go type. -type UnmarshalTypeError struct { - Value string // description of JSON value - "bool", "array", "number -5" - Type reflect.Type // type of Go value it could not be assigned to - Offset int64 // error occurred after reading Offset bytes - Struct string // name of the struct type containing the field - Field string // the full path from root node to the field -} - -func (e *UnmarshalTypeError) Error() string { - if e.Struct != "" || e.Field != "" { - return "json: cannot unmarshal " + e.Value + " into Go struct field " + e.Struct + "." + e.Field + " of type " + e.Type.String() - } - return "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String() -} - -// An UnmarshalFieldError describes a JSON object key that -// led to an unexported (and therefore unwritable) struct field. -// -// Deprecated: No longer used; kept for compatibility. -type UnmarshalFieldError struct { - Key string - Type reflect.Type - Field reflect.StructField -} - -func (e *UnmarshalFieldError) Error() string { - return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String() -} - -// An InvalidUnmarshalError describes an invalid argument passed to [Unmarshal]. -// (The argument to [Unmarshal] must be a non-nil pointer.) -type InvalidUnmarshalError struct { - Type reflect.Type -} - -func (e *InvalidUnmarshalError) Error() string { - if e.Type == nil { - return "json: Unmarshal(nil)" - } - - if e.Type.Kind() != reflect.Pointer { - return "json: Unmarshal(non-pointer " + e.Type.String() + ")" - } - return "json: Unmarshal(nil " + e.Type.String() + ")" -} - -func (d *decodeState) unmarshal(v any) error { - rv := reflect.ValueOf(v) - if rv.Kind() != reflect.Pointer || rv.IsNil() { - return &InvalidUnmarshalError{reflect.TypeOf(v)} - } - - d.scan.reset() - d.scanWhile(scanSkipSpace) - // We decode rv not rv.Elem because the Unmarshaler interface - // test must be applied at the top level of the value. - err := d.value(rv) - if err != nil { - return d.addErrorContext(err) - } - return d.savedError -} - -// A Number represents a JSON number literal. -type Number string - -// String returns the literal text of the number. -func (n Number) String() string { return string(n) } - -// Float64 returns the number as a float64. -func (n Number) Float64() (float64, error) { - return strconv.ParseFloat(string(n), 64) -} - -// Int64 returns the number as an int64. -func (n Number) Int64() (int64, error) { - return strconv.ParseInt(string(n), 10, 64) -} - -// An errorContext provides context for type errors during decoding. -type errorContext struct { - Struct reflect.Type - FieldStack []string -} - -// decodeState represents the state while decoding a JSON value. -type decodeState struct { - data []byte - off int // next read offset in data - opcode int // last read result - scan scanner - errorContext *errorContext - savedError error - useNumber bool - disallowUnknownFields bool -} - -// readIndex returns the position of the last byte read. -func (d *decodeState) readIndex() int { - return d.off - 1 -} - -// phasePanicMsg is used as a panic message when we end up with something that -// shouldn't happen. It can indicate a bug in the JSON decoder, or that -// something is editing the data slice while the decoder executes. -const phasePanicMsg = "JSON decoder out of sync - data changing underfoot?" - -func (d *decodeState) init(data []byte) *decodeState { - d.data = data - d.off = 0 - d.savedError = nil - if d.errorContext != nil { - d.errorContext.Struct = nil - // Reuse the allocated space for the FieldStack slice. - d.errorContext.FieldStack = d.errorContext.FieldStack[:0] - } - return d -} - -// saveError saves the first err it is called with, -// for reporting at the end of the unmarshal. -func (d *decodeState) saveError(err error) { - if d.savedError == nil { - d.savedError = d.addErrorContext(err) - } -} - -// addErrorContext returns a new error enhanced with information from d.errorContext -func (d *decodeState) addErrorContext(err error) error { - if d.errorContext != nil && (d.errorContext.Struct != nil || len(d.errorContext.FieldStack) > 0) { - switch err := err.(type) { - case *UnmarshalTypeError: - err.Struct = d.errorContext.Struct.Name() - err.Field = strings.Join(d.errorContext.FieldStack, ".") - } - } - return err -} - -// skip scans to the end of what was started. -func (d *decodeState) skip() { - s, data, i := &d.scan, d.data, d.off - depth := len(s.parseState) - for { - op := s.step(s, data[i]) - i++ - if len(s.parseState) < depth { - d.off = i - d.opcode = op - return - } - } -} - -// scanNext processes the byte at d.data[d.off]. -func (d *decodeState) scanNext() { - if d.off < len(d.data) { - d.opcode = d.scan.step(&d.scan, d.data[d.off]) - d.off++ - } else { - d.opcode = d.scan.eof() - d.off = len(d.data) + 1 // mark processed EOF with len+1 - } -} - -// scanWhile processes bytes in d.data[d.off:] until it -// receives a scan code not equal to op. -func (d *decodeState) scanWhile(op int) { - s, data, i := &d.scan, d.data, d.off - for i < len(data) { - newOp := s.step(s, data[i]) - i++ - if newOp != op { - d.opcode = newOp - d.off = i - return - } - } - - d.off = len(data) + 1 // mark processed EOF with len+1 - d.opcode = d.scan.eof() -} - -// rescanLiteral is similar to scanWhile(scanContinue), but it specialises the -// common case where we're decoding a literal. The decoder scans the input -// twice, once for syntax errors and to check the length of the value, and the -// second to perform the decoding. -// -// Only in the second step do we use decodeState to tokenize literals, so we -// know there aren't any syntax errors. We can take advantage of that knowledge, -// and scan a literal's bytes much more quickly. -func (d *decodeState) rescanLiteral() { - data, i := d.data, d.off -Switch: - switch data[i-1] { - case '"': // string - for ; i < len(data); i++ { - switch data[i] { - case '\\': - i++ // escaped char - case '"': - i++ // tokenize the closing quote too - break Switch - } - } - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': // number - for ; i < len(data); i++ { - switch data[i] { - case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - '.', 'e', 'E', '+', '-': - default: - break Switch - } - } - case 't': // true - i += len("rue") - case 'f': // false - i += len("alse") - case 'n': // null - i += len("ull") - } - if i < len(data) { - d.opcode = stateEndValue(&d.scan, data[i]) - } else { - d.opcode = scanEnd - } - d.off = i + 1 -} - -// value consumes a JSON value from d.data[d.off-1:], decoding into v, and -// reads the following byte ahead. If v is invalid, the value is discarded. -// The first byte of the value has been read already. -func (d *decodeState) value(v reflect.Value) error { - switch d.opcode { - default: - panic(phasePanicMsg) - - case scanBeginArray: - if v.IsValid() { - if err := d.array(v); err != nil { - return err - } - } else { - d.skip() - } - d.scanNext() - - case scanBeginObject: - if v.IsValid() { - if err := d.object(v); err != nil { - return err - } - } else { - d.skip() - } - d.scanNext() - - case scanBeginLiteral: - // All bytes inside literal return scanContinue op code. - start := d.readIndex() - d.rescanLiteral() - - if v.IsValid() { - if err := d.literalStore(d.data[start:d.readIndex()], v, false); err != nil { - return err - } - } - } - return nil -} - -type unquotedValue struct{} - -// valueQuoted is like value but decodes a -// quoted string literal or literal null into an interface value. -// If it finds anything other than a quoted string literal or null, -// valueQuoted returns unquotedValue{}. -func (d *decodeState) valueQuoted() any { - switch d.opcode { - default: - panic(phasePanicMsg) - - case scanBeginArray, scanBeginObject: - d.skip() - d.scanNext() - - case scanBeginLiteral: - v := d.literalInterface() - switch v.(type) { - case nil, string: - return v - } - } - return unquotedValue{} -} - -// indirect walks down v allocating pointers as needed, -// until it gets to a non-pointer. -// If it encounters an Unmarshaler, indirect stops and returns that. -// If decodingNull is true, indirect stops at the first settable pointer so it -// can be set to nil. -func indirect(v reflect.Value, decodingNull bool) (Unmarshaler, encoding.TextUnmarshaler, reflect.Value) { - // Issue #24153 indicates that it is generally not a guaranteed property - // that you may round-trip a reflect.Value by calling Value.Addr().Elem() - // and expect the value to still be settable for values derived from - // unexported embedded struct fields. - // - // The logic below effectively does this when it first addresses the value - // (to satisfy possible pointer methods) and continues to dereference - // subsequent pointers as necessary. - // - // After the first round-trip, we set v back to the original value to - // preserve the original RW flags contained in reflect.Value. - v0 := v - haveAddr := false - - // If v is a named type and is addressable, - // start with its address, so that if the type has pointer methods, - // we find them. - if v.Kind() != reflect.Pointer && v.Type().Name() != "" && v.CanAddr() { - haveAddr = true - v = v.Addr() - } - for { - // Load value from interface, but only if the result will be - // usefully addressable. - if v.Kind() == reflect.Interface && !v.IsNil() { - e := v.Elem() - if e.Kind() == reflect.Pointer && !e.IsNil() && (!decodingNull || e.Elem().Kind() == reflect.Pointer) { - haveAddr = false - v = e - continue - } - } - - if v.Kind() != reflect.Pointer { - break - } - - if decodingNull && v.CanSet() { - break - } - - // Prevent infinite loop if v is an interface pointing to its own address: - // var v interface{} - // v = &v - if v.Elem().Kind() == reflect.Interface && v.Elem().Elem() == v { - v = v.Elem() - break - } - if v.IsNil() { - v.Set(reflect.New(v.Type().Elem())) - } - if v.Type().NumMethod() > 0 && v.CanInterface() { - if u, ok := v.Interface().(Unmarshaler); ok { - return u, nil, reflect.Value{} - } - if !decodingNull { - if u, ok := v.Interface().(encoding.TextUnmarshaler); ok { - return nil, u, reflect.Value{} - } - } - } - - if haveAddr { - v = v0 // restore original value after round-trip Value.Addr().Elem() - haveAddr = false - } else { - v = v.Elem() - } - } - return nil, nil, v -} - -// array consumes an array from d.data[d.off-1:], decoding into v. -// The first byte of the array ('[') has been read already. -func (d *decodeState) array(v reflect.Value) error { - // Check for unmarshaler. - u, ut, pv := indirect(v, false) - if u != nil { - start := d.readIndex() - d.skip() - return u.UnmarshalJSON(d.data[start:d.off]) - } - if ut != nil { - d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) - d.skip() - return nil - } - v = pv - - // Check type of target. - switch v.Kind() { - case reflect.Interface: - if v.NumMethod() == 0 { - // Decoding into nil interface? Switch to non-reflect code. - ai := d.arrayInterface() - v.Set(reflect.ValueOf(ai)) - return nil - } - // Otherwise it's invalid. - fallthrough - default: - d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) - d.skip() - return nil - case reflect.Array, reflect.Slice: - break - } - - i := 0 - for { - // Look ahead for ] - can only happen on first iteration. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndArray { - break - } - - // Expand slice length, growing the slice if necessary. - if v.Kind() == reflect.Slice { - if i >= v.Cap() { - v.Grow(1) - } - if i >= v.Len() { - v.SetLen(i + 1) - } - } - - if i < v.Len() { - // Decode into element. - if err := d.value(v.Index(i)); err != nil { - return err - } - } else { - // Ran out of fixed array: skip. - if err := d.value(reflect.Value{}); err != nil { - return err - } - } - i++ - - // Next token must be , or ]. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndArray { - break - } - if d.opcode != scanArrayValue { - panic(phasePanicMsg) - } - } - - if i < v.Len() { - if v.Kind() == reflect.Array { - for ; i < v.Len(); i++ { - v.Index(i).SetZero() // zero remainder of array - } - } else { - v.SetLen(i) // truncate the slice - } - } - if i == 0 && v.Kind() == reflect.Slice { - v.Set(reflect.MakeSlice(v.Type(), 0, 0)) - } - return nil -} - -var nullLiteral = []byte("null") -var textUnmarshalerType = reflect.TypeFor[encoding.TextUnmarshaler]() - -// object consumes an object from d.data[d.off-1:], decoding into v. -// The first byte ('{') of the object has been read already. -func (d *decodeState) object(v reflect.Value) error { - // Check for unmarshaler. - u, ut, pv := indirect(v, false) - if u != nil { - start := d.readIndex() - d.skip() - return u.UnmarshalJSON(d.data[start:d.off]) - } - if ut != nil { - d.saveError(&UnmarshalTypeError{Value: "object", Type: v.Type(), Offset: int64(d.off)}) - d.skip() - return nil - } - v = pv - t := v.Type() - - // Decoding into nil interface? Switch to non-reflect code. - if v.Kind() == reflect.Interface && v.NumMethod() == 0 { - oi := d.objectInterface() - v.Set(reflect.ValueOf(oi)) - return nil - } - - var fields structFields - - // Check type of target: - // struct or - // map[T1]T2 where T1 is string, an integer type, - // or an encoding.TextUnmarshaler - switch v.Kind() { - case reflect.Map: - // Map key must either have string kind, have an integer kind, - // or be an encoding.TextUnmarshaler. - switch t.Key().Kind() { - case reflect.String, - reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - default: - if !reflect.PointerTo(t.Key()).Implements(textUnmarshalerType) { - d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) - d.skip() - return nil - } - } - if v.IsNil() { - v.Set(reflect.MakeMap(t)) - } - case reflect.Struct: - fields = cachedTypeFields(t) - // ok - default: - d.saveError(&UnmarshalTypeError{Value: "object", Type: t, Offset: int64(d.off)}) - d.skip() - return nil - } - - var mapElem reflect.Value - var origErrorContext errorContext - if d.errorContext != nil { - origErrorContext = *d.errorContext - } - - for { - // Read opening " of string key or closing }. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndObject { - // closing } - can only happen on first iteration. - break - } - if d.opcode != scanBeginLiteral { - panic(phasePanicMsg) - } - - // Read key. - start := d.readIndex() - d.rescanLiteral() - item := d.data[start:d.readIndex()] - key, ok := unquoteBytes(item) - if !ok { - panic(phasePanicMsg) - } - - // Figure out field corresponding to key. - var subv reflect.Value - destring := false // whether the value is wrapped in a string to be decoded first - - if v.Kind() == reflect.Map { - elemType := t.Elem() - if !mapElem.IsValid() { - mapElem = reflect.New(elemType).Elem() - } else { - mapElem.SetZero() - } - subv = mapElem - } else { - f := fields.byExactName[string(key)] - if f == nil { - f = fields.byFoldedName[string(foldName(key))] - } - if f != nil { - subv = v - destring = f.quoted - for _, i := range f.index { - if subv.Kind() == reflect.Pointer { - if subv.IsNil() { - // If a struct embeds a pointer to an unexported type, - // it is not possible to set a newly allocated value - // since the field is unexported. - // - // See https://golang.org/issue/21357 - if !subv.CanSet() { - d.saveError(fmt.Errorf("json: cannot set embedded pointer to unexported struct: %v", subv.Type().Elem())) - // Invalidate subv to ensure d.value(subv) skips over - // the JSON value without assigning it to subv. - subv = reflect.Value{} - destring = false - break - } - subv.Set(reflect.New(subv.Type().Elem())) - } - subv = subv.Elem() - } - subv = subv.Field(i) - } - if d.errorContext == nil { - d.errorContext = new(errorContext) - } - d.errorContext.FieldStack = append(d.errorContext.FieldStack, f.name) - d.errorContext.Struct = t - } else if d.disallowUnknownFields { - d.saveError(fmt.Errorf("json: unknown field %q", key)) - } - } - - // Read : before value. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode != scanObjectKey { - panic(phasePanicMsg) - } - d.scanWhile(scanSkipSpace) - - if destring { - switch qv := d.valueQuoted().(type) { - case nil: - if err := d.literalStore(nullLiteral, subv, false); err != nil { - return err - } - case string: - if err := d.literalStore([]byte(qv), subv, true); err != nil { - return err - } - default: - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal unquoted value into %v", subv.Type())) - } - } else { - if err := d.value(subv); err != nil { - return err - } - } - - // Write value back to map; - // if using struct, subv points into struct already. - if v.Kind() == reflect.Map { - kt := t.Key() - var kv reflect.Value - if reflect.PointerTo(kt).Implements(textUnmarshalerType) { - kv = reflect.New(kt) - if err := d.literalStore(item, kv, true); err != nil { - return err - } - kv = kv.Elem() - } else { - switch kt.Kind() { - case reflect.String: - kv = reflect.New(kt).Elem() - kv.SetString(string(key)) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - s := string(key) - n, err := strconv.ParseInt(s, 10, 64) - if err != nil || kt.OverflowInt(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) - break - } - kv = reflect.New(kt).Elem() - kv.SetInt(n) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - s := string(key) - n, err := strconv.ParseUint(s, 10, 64) - if err != nil || kt.OverflowUint(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + s, Type: kt, Offset: int64(start + 1)}) - break - } - kv = reflect.New(kt).Elem() - kv.SetUint(n) - default: - panic("json: Unexpected key type") // should never occur - } - } - if kv.IsValid() { - v.SetMapIndex(kv, subv) - } - } - - // Next token must be , or }. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.errorContext != nil { - // Reset errorContext to its original state. - // Keep the same underlying array for FieldStack, to reuse the - // space and avoid unnecessary allocs. - d.errorContext.FieldStack = d.errorContext.FieldStack[:len(origErrorContext.FieldStack)] - d.errorContext.Struct = origErrorContext.Struct - } - if d.opcode == scanEndObject { - break - } - if d.opcode != scanObjectValue { - panic(phasePanicMsg) - } - } - return nil -} - -// convertNumber converts the number literal s to a float64 or a Number -// depending on the setting of d.useNumber. -func (d *decodeState) convertNumber(s string) (any, error) { - if d.useNumber { - return Number(s), nil - } - f, err := strconv.ParseFloat(s, 64) - if err != nil { - return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeFor[float64](), Offset: int64(d.off)} - } - return f, nil -} - -var numberType = reflect.TypeFor[Number]() - -// literalStore decodes a literal stored in item into v. -// -// fromQuoted indicates whether this literal came from unwrapping a -// string from the ",string" struct tag option. this is used only to -// produce more helpful error messages. -func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) error { - // Check for unmarshaler. - if len(item) == 0 { - // Empty string given. - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - return nil - } - isNull := item[0] == 'n' // null - u, ut, pv := indirect(v, isNull) - if u != nil { - err := u.UnmarshalJSON(item) - - if err != nil { - if t, ok := u.(*time.Time); ok { - - if len(item) < 2 || item[0] != '"' || item[len(item)-1] != '"' { - d.saveError(fmt.Errorf("Time.UnmarshalJSON: input is not a JSON string")) - return nil - } - item = item[len(`"`) : len(item)-len(`"`)] - - tt, parsed := datetime.TryParseAsTime(item, []string{ - time.RFC3339Nano, - "2006-01-02 15:04:05.999999", // go-sql-driver/mysql - "15:04:05-07", // pgx - "15:04:05.999999", // pgx - }) - - if !parsed { - d.saveError(fmt.Errorf("json: invalid time, trying to unmarshal %q into %v", item, v.Type())) - return nil - } - - *t = tt - return nil - } - - return err - } - - return nil - } - if ut != nil { - if item[0] != '"' { - if fromQuoted { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - return nil - } - val := "number" - switch item[0] { - case 'n': - val = "null" - case 't', 'f': - val = "bool" - } - d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())}) - return nil - } - s, ok := unquoteBytes(item) - if !ok { - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - panic(phasePanicMsg) - } - return ut.UnmarshalText(s) - } - - v = pv - - switch c := item[0]; c { - case 'n': // null - // The main parser checks that only true and false can reach here, - // but if this was a quoted string input, it could be anything. - if fromQuoted && string(item) != "null" { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - break - } - switch v.Kind() { - case reflect.Interface, reflect.Pointer, reflect.Map, reflect.Slice: - v.SetZero() - // otherwise, ignore null for primitives/string - } - case 't', 'f': // true, false - value := item[0] == 't' - // The main parser checks that only true and false can reach here, - // but if this was a quoted string input, it could be anything. - if fromQuoted && string(item) != "true" && string(item) != "false" { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - break - } - switch v.Kind() { - default: - if fromQuoted { - d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) - } else { - d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) - } - case reflect.Bool: - v.SetBool(value) - case reflect.Interface: - if v.NumMethod() == 0 { - v.Set(reflect.ValueOf(value)) - } else { - d.saveError(&UnmarshalTypeError{Value: "bool", Type: v.Type(), Offset: int64(d.readIndex())}) - } - } - - case '"': // string - s, ok := unquoteBytes(item) - if !ok { - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - panic(phasePanicMsg) - } - switch v.Kind() { - default: - d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) - case reflect.Slice: - if v.Type().Elem().Kind() != reflect.Uint8 { - d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - - if bytes.HasPrefix(s, []byte("\\x")) { - s = s[2:] - b := make([]byte, hex2.DecodedLen(len(s))) - n, err := hex2.Decode(b, s) - if err != nil { - d.saveError(err) - break - } - v.SetBytes(b[:n]) - } else { - if bytes.HasPrefix(s, []byte("base64")) { - s = s[bytes.LastIndexByte(s, ':')+1:] - } - - b := make([]byte, base64.StdEncoding.DecodedLen(len(s))) - n, err := base64.StdEncoding.Decode(b, s) - if err != nil { - d.saveError(err) - break - } - v.SetBytes(b[:n]) - } - - case reflect.String: - t := string(s) - if v.Type() == numberType && !isValidNumber(t) { - return fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", item) - } - v.SetString(t) - case reflect.Interface: - if v.NumMethod() == 0 { - v.Set(reflect.ValueOf(string(s))) - } else { - d.saveError(&UnmarshalTypeError{Value: "string", Type: v.Type(), Offset: int64(d.readIndex())}) - } - } - - default: // number - if c != '-' && (c < '0' || c > '9') { - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - panic(phasePanicMsg) - } - switch v.Kind() { - default: - if v.Kind() == reflect.String && v.Type() == numberType { - // s must be a valid number, because it's - // already been tokenized. - v.SetString(string(item)) - break - } - if fromQuoted { - return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()) - } - d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) - case reflect.Bool: - itemVal := string(item) - - if itemVal != "1" && itemVal != "0" { - d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.SetBool(itemVal == "1") - - case reflect.Interface: - n, err := d.convertNumber(string(item)) - if err != nil { - d.saveError(err) - break - } - if v.NumMethod() != 0 { - d.saveError(&UnmarshalTypeError{Value: "number", Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.Set(reflect.ValueOf(n)) - - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - n, err := strconv.ParseInt(string(item), 10, 64) - if err != nil || v.OverflowInt(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.SetInt(n) - - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - n, err := strconv.ParseUint(string(item), 10, 64) - if err != nil || v.OverflowUint(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.SetUint(n) - - case reflect.Float32, reflect.Float64: - n, err := strconv.ParseFloat(string(item), v.Type().Bits()) - if err != nil || v.OverflowFloat(n) { - d.saveError(&UnmarshalTypeError{Value: "number " + string(item), Type: v.Type(), Offset: int64(d.readIndex())}) - break - } - v.SetFloat(n) - } - } - return nil -} - -// The xxxInterface routines build up a value to be stored -// in an empty interface. They are not strictly necessary, -// but they avoid the weight of reflection in this common case. - -// valueInterface is like value but returns interface{} -func (d *decodeState) valueInterface() (val any) { - switch d.opcode { - default: - panic(phasePanicMsg) - case scanBeginArray: - val = d.arrayInterface() - d.scanNext() - case scanBeginObject: - val = d.objectInterface() - d.scanNext() - case scanBeginLiteral: - val = d.literalInterface() - } - return -} - -// arrayInterface is like array but returns []interface{}. -func (d *decodeState) arrayInterface() []any { - var v = make([]any, 0) - for { - // Look ahead for ] - can only happen on first iteration. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndArray { - break - } - - v = append(v, d.valueInterface()) - - // Next token must be , or ]. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndArray { - break - } - if d.opcode != scanArrayValue { - panic(phasePanicMsg) - } - } - return v -} - -// objectInterface is like object but returns map[string]interface{}. -func (d *decodeState) objectInterface() map[string]any { - m := make(map[string]any) - for { - // Read opening " of string key or closing }. - d.scanWhile(scanSkipSpace) - if d.opcode == scanEndObject { - // closing } - can only happen on first iteration. - break - } - if d.opcode != scanBeginLiteral { - panic(phasePanicMsg) - } - - // Read string key. - start := d.readIndex() - d.rescanLiteral() - item := d.data[start:d.readIndex()] - key, ok := unquote(item) - if !ok { - panic(phasePanicMsg) - } - - // Read : before value. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode != scanObjectKey { - panic(phasePanicMsg) - } - d.scanWhile(scanSkipSpace) - - // Read value. - m[key] = d.valueInterface() - - // Next token must be , or }. - if d.opcode == scanSkipSpace { - d.scanWhile(scanSkipSpace) - } - if d.opcode == scanEndObject { - break - } - if d.opcode != scanObjectValue { - panic(phasePanicMsg) - } - } - return m -} - -// literalInterface consumes and returns a literal from d.data[d.off-1:] and -// it reads the following byte ahead. The first byte of the literal has been -// read already (that's how the caller knows it's a literal). -func (d *decodeState) literalInterface() any { - // All bytes inside literal return scanContinue op code. - start := d.readIndex() - d.rescanLiteral() - - item := d.data[start:d.readIndex()] - - switch c := item[0]; c { - case 'n': // null - return nil - - case 't', 'f': // true, false - return c == 't' - - case '"': // string - s, ok := unquote(item) - if !ok { - panic(phasePanicMsg) - } - return s - - default: // number - if c != '-' && (c < '0' || c > '9') { - panic(phasePanicMsg) - } - n, err := d.convertNumber(string(item)) - if err != nil { - d.saveError(err) - } - return n - } -} - -// getu4 decodes \uXXXX from the beginning of s, returning the hex value, -// or it returns -1. -func getu4(s []byte) rune { - if len(s) < 6 || s[0] != '\\' || s[1] != 'u' { - return -1 - } - var r rune - for _, c := range s[2:6] { - switch { - case '0' <= c && c <= '9': - c = c - '0' - case 'a' <= c && c <= 'f': - c = c - 'a' + 10 - case 'A' <= c && c <= 'F': - c = c - 'A' + 10 - default: - return -1 - } - r = r*16 + rune(c) - } - return r -} - -// unquote converts a quoted JSON string literal s into an actual string t. -// The rules are different than for Go, so cannot use strconv.Unquote. -func unquote(s []byte) (t string, ok bool) { - s, ok = unquoteBytes(s) - t = string(s) - return -} - -// unquoteBytes should be an internal detail, -// but widely used packages access it using linkname. -// Notable members of the hall of shame include: -// - github.com/bytedance/sonic -// -// Do not remove or change the type signature. -// See go.dev/issue/67401. -// -//go:linkname unquoteBytes -func unquoteBytes(s []byte) (t []byte, ok bool) { - if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' { - return - } - s = s[1 : len(s)-1] - - // Check for unusual characters. If there are none, - // then no unquoting is needed, so return a slice of the - // original bytes. - r := 0 - for r < len(s) { - c := s[r] - if c == '\\' || c == '"' || c < ' ' { - break - } - if c < utf8.RuneSelf { - r++ - continue - } - rr, size := utf8.DecodeRune(s[r:]) - if rr == utf8.RuneError && size == 1 { - break - } - r += size - } - if r == len(s) { - return s, true - } - - b := make([]byte, len(s)+2*utf8.UTFMax) - w := copy(b, s[0:r]) - for r < len(s) { - // Out of room? Can only happen if s is full of - // malformed UTF-8 and we're replacing each - // byte with RuneError. - if w >= len(b)-2*utf8.UTFMax { - nb := make([]byte, (len(b)+utf8.UTFMax)*2) - copy(nb, b[0:w]) - b = nb - } - switch c := s[r]; { - case c == '\\': - r++ - if r >= len(s) { - return - } - switch s[r] { - default: - return - case '"', '\\', '/', '\'': - b[w] = s[r] - r++ - w++ - case 'b': - b[w] = '\b' - r++ - w++ - case 'f': - b[w] = '\f' - r++ - w++ - case 'n': - b[w] = '\n' - r++ - w++ - case 'r': - b[w] = '\r' - r++ - w++ - case 't': - b[w] = '\t' - r++ - w++ - case 'u': - r-- - rr := getu4(s[r:]) - if rr < 0 { - return - } - r += 6 - if utf16.IsSurrogate(rr) { - rr1 := getu4(s[r:]) - if dec := utf16.DecodeRune(rr, rr1); dec != unicode.ReplacementChar { - // A valid pair; consume. - r += 6 - w += utf8.EncodeRune(b[w:], dec) - break - } - // Invalid surrogate; fall back to replacement rune. - rr = unicode.ReplacementChar - } - w += utf8.EncodeRune(b[w:], rr) - } - - // Quote, control characters are invalid. - case c == '"', c < ' ': - return - - // ASCII - case c < utf8.RuneSelf: - b[w] = c - r++ - w++ - - // Coerce to well-formed UTF-8. - default: - rr, size := utf8.DecodeRune(s[r:]) - r += size - w += utf8.EncodeRune(b[w:], rr) - } - } - return b[0:w], true -} diff --git a/internal/3rdparty/json/decode_test.go b/internal/3rdparty/json/decode_test.go deleted file mode 100644 index f5b4467..0000000 --- a/internal/3rdparty/json/decode_test.go +++ /dev/null @@ -1,2621 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package json - -import ( - "bytes" - "encoding" - "errors" - "fmt" - "image" - "math" - "math/big" - "net" - "reflect" - "slices" - "strconv" - "strings" - "testing" - "time" -) - -type T struct { - X string - Y int - Z int `json:"-"` -} - -type U struct { - Alphabet string `json:"alpha"` -} - -type V struct { - F1 any - F2 int32 - F3 Number - F4 *VOuter -} - -type VOuter struct { - V V -} - -type W struct { - S SS -} - -type P struct { - PP PP -} - -type PP struct { - T T - Ts []T -} - -type SS string - -func (*SS) UnmarshalJSON(data []byte) error { - return &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[SS]()} -} - -// ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and -// without UseNumber -var ifaceNumAsFloat64 = map[string]any{ - "k1": float64(1), - "k2": "s", - "k3": []any{float64(1), float64(2.0), float64(3e-3)}, - "k4": map[string]any{"kk1": "s", "kk2": float64(2)}, -} - -var ifaceNumAsNumber = map[string]any{ - "k1": Number("1"), - "k2": "s", - "k3": []any{Number("1"), Number("2.0"), Number("3e-3")}, - "k4": map[string]any{"kk1": "s", "kk2": Number("2")}, -} - -type tx struct { - x int -} - -type u8 uint8 - -// A type that can unmarshal itself. - -type unmarshaler struct { - T bool -} - -func (u *unmarshaler) UnmarshalJSON(b []byte) error { - *u = unmarshaler{true} // All we need to see that UnmarshalJSON is called. - return nil -} - -type ustruct struct { - M unmarshaler -} - -type unmarshalerText struct { - A, B string -} - -// needed for re-marshaling tests -func (u unmarshalerText) MarshalText() ([]byte, error) { - return []byte(u.A + ":" + u.B), nil -} - -func (u *unmarshalerText) UnmarshalText(b []byte) error { - pos := bytes.IndexByte(b, ':') - if pos == -1 { - return errors.New("missing separator") - } - u.A, u.B = string(b[:pos]), string(b[pos+1:]) - return nil -} - -var _ encoding.TextUnmarshaler = (*unmarshalerText)(nil) - -type ustructText struct { - M unmarshalerText -} - -// u8marshal is an integer type that can marshal/unmarshal itself. -type u8marshal uint8 - -func (u8 u8marshal) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf("u%d", u8)), nil -} - -var errMissingU8Prefix = errors.New("missing 'u' prefix") - -func (u8 *u8marshal) UnmarshalText(b []byte) error { - if !bytes.HasPrefix(b, []byte{'u'}) { - return errMissingU8Prefix - } - n, err := strconv.Atoi(string(b[1:])) - if err != nil { - return err - } - *u8 = u8marshal(n) - return nil -} - -var _ encoding.TextUnmarshaler = (*u8marshal)(nil) - -var ( - umtrue = unmarshaler{true} - umslice = []unmarshaler{{true}} - umstruct = ustruct{unmarshaler{true}} - - umtrueXY = unmarshalerText{"x", "y"} - umsliceXY = []unmarshalerText{{"x", "y"}} - umstructXY = ustructText{unmarshalerText{"x", "y"}} - - ummapXY = map[unmarshalerText]bool{{"x", "y"}: true} -) - -// Test data structures for anonymous fields. - -type Point struct { - Z int -} - -type Top struct { - Level0 int - Embed0 - *Embed0a - *Embed0b `json:"e,omitempty"` // treated as named - Embed0c `json:"-"` // ignored - Loop - Embed0p // has Point with X, Y, used - Embed0q // has Point with Z, used - embed // contains exported field -} - -type Embed0 struct { - Level1a int // overridden by Embed0a's Level1a with json tag - Level1b int // used because Embed0a's Level1b is renamed - Level1c int // used because Embed0a's Level1c is ignored - Level1d int // annihilated by Embed0a's Level1d - Level1e int `json:"x"` // annihilated by Embed0a.Level1e -} - -type Embed0a struct { - Level1a int `json:"Level1a,omitempty"` - Level1b int `json:"LEVEL1B,omitempty"` - Level1c int `json:"-"` - Level1d int // annihilated by Embed0's Level1d - Level1f int `json:"x"` // annihilated by Embed0's Level1e -} - -type Embed0b Embed0 - -type Embed0c Embed0 - -type Embed0p struct { - image.Point -} - -type Embed0q struct { - Point -} - -type embed struct { - Q int -} - -type Loop struct { - Loop1 int `json:",omitempty"` - Loop2 int `json:",omitempty"` - *Loop -} - -// From reflect test: -// The X in S6 and S7 annihilate, but they also block the X in S8.S9. -type S5 struct { - S6 - S7 - S8 -} - -type S6 struct { - X int -} - -type S7 S6 - -type S8 struct { - S9 -} - -type S9 struct { - X int - Y int -} - -// From reflect test: -// The X in S11.S6 and S12.S6 annihilate, but they also block the X in S13.S8.S9. -type S10 struct { - S11 - S12 - S13 -} - -type S11 struct { - S6 -} - -type S12 struct { - S6 -} - -type S13 struct { - S8 -} - -type Ambig struct { - // Given "hello", the first match should win. - First int `json:"HELLO"` - Second int `json:"Hello"` -} - -type XYZ struct { - X any - Y any - Z any -} - -type unexportedWithMethods struct{} - -func (unexportedWithMethods) F() {} - -type byteWithMarshalJSON byte - -func (b byteWithMarshalJSON) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf(`"Z%.2x"`, byte(b))), nil -} - -func (b *byteWithMarshalJSON) UnmarshalJSON(data []byte) error { - if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' { - return fmt.Errorf("bad quoted string") - } - i, err := strconv.ParseInt(string(data[2:4]), 16, 8) - if err != nil { - return fmt.Errorf("bad hex") - } - *b = byteWithMarshalJSON(i) - return nil -} - -type byteWithPtrMarshalJSON byte - -func (b *byteWithPtrMarshalJSON) MarshalJSON() ([]byte, error) { - return byteWithMarshalJSON(*b).MarshalJSON() -} - -func (b *byteWithPtrMarshalJSON) UnmarshalJSON(data []byte) error { - return (*byteWithMarshalJSON)(b).UnmarshalJSON(data) -} - -type byteWithMarshalText byte - -func (b byteWithMarshalText) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf(`Z%.2x`, byte(b))), nil -} - -func (b *byteWithMarshalText) UnmarshalText(data []byte) error { - if len(data) != 3 || data[0] != 'Z' { - return fmt.Errorf("bad quoted string") - } - i, err := strconv.ParseInt(string(data[1:3]), 16, 8) - if err != nil { - return fmt.Errorf("bad hex") - } - *b = byteWithMarshalText(i) - return nil -} - -type byteWithPtrMarshalText byte - -func (b *byteWithPtrMarshalText) MarshalText() ([]byte, error) { - return byteWithMarshalText(*b).MarshalText() -} - -func (b *byteWithPtrMarshalText) UnmarshalText(data []byte) error { - return (*byteWithMarshalText)(b).UnmarshalText(data) -} - -type intWithMarshalJSON int - -func (b intWithMarshalJSON) MarshalJSON() ([]byte, error) { - return []byte(fmt.Sprintf(`"Z%.2x"`, int(b))), nil -} - -func (b *intWithMarshalJSON) UnmarshalJSON(data []byte) error { - if len(data) != 5 || data[0] != '"' || data[1] != 'Z' || data[4] != '"' { - return fmt.Errorf("bad quoted string") - } - i, err := strconv.ParseInt(string(data[2:4]), 16, 8) - if err != nil { - return fmt.Errorf("bad hex") - } - *b = intWithMarshalJSON(i) - return nil -} - -type intWithPtrMarshalJSON int - -func (b *intWithPtrMarshalJSON) MarshalJSON() ([]byte, error) { - return intWithMarshalJSON(*b).MarshalJSON() -} - -func (b *intWithPtrMarshalJSON) UnmarshalJSON(data []byte) error { - return (*intWithMarshalJSON)(b).UnmarshalJSON(data) -} - -type intWithMarshalText int - -func (b intWithMarshalText) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf(`Z%.2x`, int(b))), nil -} - -func (b *intWithMarshalText) UnmarshalText(data []byte) error { - if len(data) != 3 || data[0] != 'Z' { - return fmt.Errorf("bad quoted string") - } - i, err := strconv.ParseInt(string(data[1:3]), 16, 8) - if err != nil { - return fmt.Errorf("bad hex") - } - *b = intWithMarshalText(i) - return nil -} - -type intWithPtrMarshalText int - -func (b *intWithPtrMarshalText) MarshalText() ([]byte, error) { - return intWithMarshalText(*b).MarshalText() -} - -func (b *intWithPtrMarshalText) UnmarshalText(data []byte) error { - return (*intWithMarshalText)(b).UnmarshalText(data) -} - -type mapStringToStringData struct { - Data map[string]string `json:"data"` -} - -type B struct { - B bool `json:",string"` -} - -type DoublePtr struct { - I **int - J **int -} - -var unmarshalTests = []struct { - CaseName - in string - ptr any // new(type) - out any - err error - useNumber bool - golden bool - disallowUnknownFields bool -}{ - // basic types - {CaseName: Name(""), in: `true`, ptr: new(bool), out: true}, - {CaseName: Name(""), in: `1`, ptr: new(int), out: 1}, - {CaseName: Name(""), in: `1.2`, ptr: new(float64), out: 1.2}, - {CaseName: Name(""), in: `-5`, ptr: new(int16), out: int16(-5)}, - {CaseName: Name(""), in: `2`, ptr: new(Number), out: Number("2"), useNumber: true}, - {CaseName: Name(""), in: `2`, ptr: new(Number), out: Number("2")}, - {CaseName: Name(""), in: `2`, ptr: new(any), out: float64(2.0)}, - {CaseName: Name(""), in: `2`, ptr: new(any), out: Number("2"), useNumber: true}, - {CaseName: Name(""), in: `"a\u1234"`, ptr: new(string), out: "a\u1234"}, - {CaseName: Name(""), in: `"http:\/\/"`, ptr: new(string), out: "http://"}, - {CaseName: Name(""), in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"}, - {CaseName: Name(""), in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"}, - {CaseName: Name(""), in: "null", ptr: new(any), out: nil}, - {CaseName: Name(""), in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeFor[string](), 7, "T", "X"}}, - {CaseName: Name(""), in: `{"X": 23}`, ptr: new(T), out: T{}, err: &UnmarshalTypeError{"number", reflect.TypeFor[string](), 8, "T", "X"}}, - {CaseName: Name(""), in: `{"x": 1}`, ptr: new(tx), out: tx{}}, - {CaseName: Name(""), in: `{"x": 1}`, ptr: new(tx), out: tx{}}, - {CaseName: Name(""), in: `{"x": 1}`, ptr: new(tx), err: fmt.Errorf("json: unknown field \"x\""), disallowUnknownFields: true}, - {CaseName: Name(""), in: `{"S": 23}`, ptr: new(W), out: W{}, err: &UnmarshalTypeError{"number", reflect.TypeFor[SS](), 0, "W", "S"}}, - {CaseName: Name(""), in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}}, - {CaseName: Name(""), in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true}, - {CaseName: Name(""), in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(any), out: ifaceNumAsFloat64}, - {CaseName: Name(""), in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(any), out: ifaceNumAsNumber, useNumber: true}, - - // raw values with whitespace - {CaseName: Name(""), in: "\n true ", ptr: new(bool), out: true}, - {CaseName: Name(""), in: "\t 1 ", ptr: new(int), out: 1}, - {CaseName: Name(""), in: "\r 1.2 ", ptr: new(float64), out: 1.2}, - {CaseName: Name(""), in: "\t -5 \n", ptr: new(int16), out: int16(-5)}, - {CaseName: Name(""), in: "\t \"a\\u1234\" \n", ptr: new(string), out: "a\u1234"}, - - // Z has a "-" tag. - {CaseName: Name(""), in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}}, - {CaseName: Name(""), in: `{"Y": 1, "Z": 2}`, ptr: new(T), err: fmt.Errorf("json: unknown field \"Z\""), disallowUnknownFields: true}, - - {CaseName: Name(""), in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}}, - {CaseName: Name(""), in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true}, - {CaseName: Name(""), in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}}, - {CaseName: Name(""), in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}}, - {CaseName: Name(""), in: `{"alphabet": "xyz"}`, ptr: new(U), err: fmt.Errorf("json: unknown field \"alphabet\""), disallowUnknownFields: true}, - - // syntax errors - {CaseName: Name(""), in: `{"X": "foo", "Y"}`, err: &SyntaxError{"invalid character '}' after object key", 17}}, - {CaseName: Name(""), in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array element", 9}}, - {CaseName: Name(""), in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true}, - {CaseName: Name(""), in: `[2, 3`, err: &SyntaxError{msg: "unexpected end of JSON input", Offset: 5}}, - {CaseName: Name(""), in: `{"F3": -}`, ptr: new(V), out: V{F3: Number("-")}, err: &SyntaxError{msg: "invalid character '}' in numeric literal", Offset: 9}}, - - // raw value errors - {CaseName: Name(""), in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, - {CaseName: Name(""), in: " 42 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 5}}, - {CaseName: Name(""), in: "\x01 true", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, - {CaseName: Name(""), in: " false \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 8}}, - {CaseName: Name(""), in: "\x01 1.2", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, - {CaseName: Name(""), in: " 3.4 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 6}}, - {CaseName: Name(""), in: "\x01 \"string\"", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, - {CaseName: Name(""), in: " \"string\" \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 11}}, - - // array tests - {CaseName: Name(""), in: `[1, 2, 3]`, ptr: new([3]int), out: [3]int{1, 2, 3}}, - {CaseName: Name(""), in: `[1, 2, 3]`, ptr: new([1]int), out: [1]int{1}}, - {CaseName: Name(""), in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}}, - {CaseName: Name(""), in: `[1, 2, 3]`, ptr: new(MustNotUnmarshalJSON), err: errors.New("MustNotUnmarshalJSON was used")}, - - // empty array to interface test - {CaseName: Name(""), in: `[]`, ptr: new([]any), out: []any{}}, - {CaseName: Name(""), in: `null`, ptr: new([]any), out: []any(nil)}, - {CaseName: Name(""), in: `{"T":[]}`, ptr: new(map[string]any), out: map[string]any{"T": []any{}}}, - {CaseName: Name(""), in: `{"T":null}`, ptr: new(map[string]any), out: map[string]any{"T": any(nil)}}, - - // composite tests - {CaseName: Name(""), in: allValueIndent, ptr: new(All), out: allValue}, - {CaseName: Name(""), in: allValueCompact, ptr: new(All), out: allValue}, - {CaseName: Name(""), in: allValueIndent, ptr: new(*All), out: &allValue}, - {CaseName: Name(""), in: allValueCompact, ptr: new(*All), out: &allValue}, - {CaseName: Name(""), in: pallValueIndent, ptr: new(All), out: pallValue}, - {CaseName: Name(""), in: pallValueCompact, ptr: new(All), out: pallValue}, - {CaseName: Name(""), in: pallValueIndent, ptr: new(*All), out: &pallValue}, - {CaseName: Name(""), in: pallValueCompact, ptr: new(*All), out: &pallValue}, - - // unmarshal interface test - {CaseName: Name(""), in: `{"T":false}`, ptr: new(unmarshaler), out: umtrue}, // use "false" so test will fail if custom unmarshaler is not called - {CaseName: Name(""), in: `{"T":false}`, ptr: new(*unmarshaler), out: &umtrue}, - {CaseName: Name(""), in: `[{"T":false}]`, ptr: new([]unmarshaler), out: umslice}, - {CaseName: Name(""), in: `[{"T":false}]`, ptr: new(*[]unmarshaler), out: &umslice}, - {CaseName: Name(""), in: `{"M":{"T":"x:y"}}`, ptr: new(ustruct), out: umstruct}, - - // UnmarshalText interface test - {CaseName: Name(""), in: `"x:y"`, ptr: new(unmarshalerText), out: umtrueXY}, - {CaseName: Name(""), in: `"x:y"`, ptr: new(*unmarshalerText), out: &umtrueXY}, - {CaseName: Name(""), in: `["x:y"]`, ptr: new([]unmarshalerText), out: umsliceXY}, - {CaseName: Name(""), in: `["x:y"]`, ptr: new(*[]unmarshalerText), out: &umsliceXY}, - {CaseName: Name(""), in: `{"M":"x:y"}`, ptr: new(ustructText), out: umstructXY}, - - // integer-keyed map test - { - CaseName: Name(""), - in: `{"-1":"a","0":"b","1":"c"}`, - ptr: new(map[int]string), - out: map[int]string{-1: "a", 0: "b", 1: "c"}, - }, - { - CaseName: Name(""), - in: `{"0":"a","10":"c","9":"b"}`, - ptr: new(map[u8]string), - out: map[u8]string{0: "a", 9: "b", 10: "c"}, - }, - { - CaseName: Name(""), - in: `{"-9223372036854775808":"min","9223372036854775807":"max"}`, - ptr: new(map[int64]string), - out: map[int64]string{math.MinInt64: "min", math.MaxInt64: "max"}, - }, - { - CaseName: Name(""), - in: `{"18446744073709551615":"max"}`, - ptr: new(map[uint64]string), - out: map[uint64]string{math.MaxUint64: "max"}, - }, - { - CaseName: Name(""), - in: `{"0":false,"10":true}`, - ptr: new(map[uintptr]bool), - out: map[uintptr]bool{0: false, 10: true}, - }, - - // Check that MarshalText and UnmarshalText take precedence - // over default integer handling in map keys. - { - CaseName: Name(""), - in: `{"u2":4}`, - ptr: new(map[u8marshal]int), - out: map[u8marshal]int{2: 4}, - }, - { - CaseName: Name(""), - in: `{"2":4}`, - ptr: new(map[u8marshal]int), - err: errMissingU8Prefix, - }, - - // integer-keyed map errors - { - CaseName: Name(""), - in: `{"abc":"abc"}`, - ptr: new(map[int]string), - err: &UnmarshalTypeError{Value: "number abc", Type: reflect.TypeFor[int](), Offset: 2}, - }, - { - CaseName: Name(""), - in: `{"256":"abc"}`, - ptr: new(map[uint8]string), - err: &UnmarshalTypeError{Value: "number 256", Type: reflect.TypeFor[uint8](), Offset: 2}, - }, - { - CaseName: Name(""), - in: `{"128":"abc"}`, - ptr: new(map[int8]string), - err: &UnmarshalTypeError{Value: "number 128", Type: reflect.TypeFor[int8](), Offset: 2}, - }, - { - CaseName: Name(""), - in: `{"-1":"abc"}`, - ptr: new(map[uint8]string), - err: &UnmarshalTypeError{Value: "number -1", Type: reflect.TypeFor[uint8](), Offset: 2}, - }, - { - CaseName: Name(""), - in: `{"F":{"a":2,"3":4}}`, - ptr: new(map[string]map[int]int), - err: &UnmarshalTypeError{Value: "number a", Type: reflect.TypeFor[int](), Offset: 7}, - }, - { - CaseName: Name(""), - in: `{"F":{"a":2,"3":4}}`, - ptr: new(map[string]map[uint]int), - err: &UnmarshalTypeError{Value: "number a", Type: reflect.TypeFor[uint](), Offset: 7}, - }, - - // Map keys can be encoding.TextUnmarshalers. - {CaseName: Name(""), in: `{"x:y":true}`, ptr: new(map[unmarshalerText]bool), out: ummapXY}, - // If multiple values for the same key exists, only the most recent value is used. - {CaseName: Name(""), in: `{"x:y":false,"x:y":true}`, ptr: new(map[unmarshalerText]bool), out: ummapXY}, - - { - CaseName: Name(""), - in: `{ - "Level0": 1, - "Level1b": 2, - "Level1c": 3, - "x": 4, - "Level1a": 5, - "LEVEL1B": 6, - "e": { - "Level1a": 8, - "Level1b": 9, - "Level1c": 10, - "Level1d": 11, - "x": 12 - }, - "Loop1": 13, - "Loop2": 14, - "X": 15, - "Y": 16, - "Z": 17, - "Q": 18 - }`, - ptr: new(Top), - out: Top{ - Level0: 1, - Embed0: Embed0{ - Level1b: 2, - Level1c: 3, - }, - Embed0a: &Embed0a{ - Level1a: 5, - Level1b: 6, - }, - Embed0b: &Embed0b{ - Level1a: 8, - Level1b: 9, - Level1c: 10, - Level1d: 11, - Level1e: 12, - }, - Loop: Loop{ - Loop1: 13, - Loop2: 14, - }, - Embed0p: Embed0p{ - Point: image.Point{X: 15, Y: 16}, - }, - Embed0q: Embed0q{ - Point: Point{Z: 17}, - }, - embed: embed{ - Q: 18, - }, - }, - }, - { - CaseName: Name(""), - in: `{"hello": 1}`, - ptr: new(Ambig), - out: Ambig{First: 1}, - }, - - { - CaseName: Name(""), - in: `{"X": 1,"Y":2}`, - ptr: new(S5), - out: S5{S8: S8{S9: S9{Y: 2}}}, - }, - { - CaseName: Name(""), - in: `{"X": 1,"Y":2}`, - ptr: new(S5), - err: fmt.Errorf("json: unknown field \"X\""), - disallowUnknownFields: true, - }, - { - CaseName: Name(""), - in: `{"X": 1,"Y":2}`, - ptr: new(S10), - out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}}, - }, - { - CaseName: Name(""), - in: `{"X": 1,"Y":2}`, - ptr: new(S10), - err: fmt.Errorf("json: unknown field \"X\""), - disallowUnknownFields: true, - }, - { - CaseName: Name(""), - in: `{"I": 0, "I": null, "J": null}`, - ptr: new(DoublePtr), - out: DoublePtr{I: nil, J: nil}, - }, - - // invalid UTF-8 is coerced to valid UTF-8. - { - CaseName: Name(""), - in: "\"hello\xffworld\"", - ptr: new(string), - out: "hello\ufffdworld", - }, - { - CaseName: Name(""), - in: "\"hello\xc2\xc2world\"", - ptr: new(string), - out: "hello\ufffd\ufffdworld", - }, - { - CaseName: Name(""), - in: "\"hello\xc2\xffworld\"", - ptr: new(string), - out: "hello\ufffd\ufffdworld", - }, - { - CaseName: Name(""), - in: "\"hello\\ud800world\"", - ptr: new(string), - out: "hello\ufffdworld", - }, - { - CaseName: Name(""), - in: "\"hello\\ud800\\ud800world\"", - ptr: new(string), - out: "hello\ufffd\ufffdworld", - }, - { - CaseName: Name(""), - in: "\"hello\\ud800\\ud800world\"", - ptr: new(string), - out: "hello\ufffd\ufffdworld", - }, - { - CaseName: Name(""), - in: "\"hello\xed\xa0\x80\xed\xb0\x80world\"", - ptr: new(string), - out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld", - }, - - // Used to be issue 8305, but time.Time implements encoding.TextUnmarshaler so this works now. - { - CaseName: Name(""), - in: `{"2009-11-10T23:00:00Z": "hello world"}`, - ptr: new(map[time.Time]string), - out: map[time.Time]string{time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC): "hello world"}, - }, - - // issue 8305 - { - CaseName: Name(""), - in: `{"2009-11-10T23:00:00Z": "hello world"}`, - ptr: new(map[Point]string), - err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeFor[map[Point]string](), Offset: 1}, - }, - { - CaseName: Name(""), - in: `{"asdf": "hello world"}`, - ptr: new(map[unmarshaler]string), - err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeFor[map[unmarshaler]string](), Offset: 1}, - }, - - // related to issue 13783. - // Go 1.7 changed marshaling a slice of typed byte to use the methods on the byte type, - // similar to marshaling a slice of typed int. - // These tests check that, assuming the byte type also has valid decoding methods, - // either the old base64 string encoding or the new per-element encoding can be - // successfully unmarshaled. The custom unmarshalers were accessible in earlier - // versions of Go, even though the custom marshaler was not. - { - CaseName: Name(""), - in: `"AQID"`, - ptr: new([]byteWithMarshalJSON), - out: []byteWithMarshalJSON{1, 2, 3}, - }, - { - CaseName: Name(""), - in: `["Z01","Z02","Z03"]`, - ptr: new([]byteWithMarshalJSON), - out: []byteWithMarshalJSON{1, 2, 3}, - golden: true, - }, - { - CaseName: Name(""), - in: `"AQID"`, - ptr: new([]byteWithMarshalText), - out: []byteWithMarshalText{1, 2, 3}, - }, - { - CaseName: Name(""), - in: `["Z01","Z02","Z03"]`, - ptr: new([]byteWithMarshalText), - out: []byteWithMarshalText{1, 2, 3}, - golden: true, - }, - { - CaseName: Name(""), - in: `"AQID"`, - ptr: new([]byteWithPtrMarshalJSON), - out: []byteWithPtrMarshalJSON{1, 2, 3}, - }, - { - CaseName: Name(""), - in: `["Z01","Z02","Z03"]`, - ptr: new([]byteWithPtrMarshalJSON), - out: []byteWithPtrMarshalJSON{1, 2, 3}, - golden: true, - }, - { - CaseName: Name(""), - in: `"AQID"`, - ptr: new([]byteWithPtrMarshalText), - out: []byteWithPtrMarshalText{1, 2, 3}, - }, - { - CaseName: Name(""), - in: `["Z01","Z02","Z03"]`, - ptr: new([]byteWithPtrMarshalText), - out: []byteWithPtrMarshalText{1, 2, 3}, - golden: true, - }, - - // ints work with the marshaler but not the base64 []byte case - { - CaseName: Name(""), - in: `["Z01","Z02","Z03"]`, - ptr: new([]intWithMarshalJSON), - out: []intWithMarshalJSON{1, 2, 3}, - golden: true, - }, - { - CaseName: Name(""), - in: `["Z01","Z02","Z03"]`, - ptr: new([]intWithMarshalText), - out: []intWithMarshalText{1, 2, 3}, - golden: true, - }, - { - CaseName: Name(""), - in: `["Z01","Z02","Z03"]`, - ptr: new([]intWithPtrMarshalJSON), - out: []intWithPtrMarshalJSON{1, 2, 3}, - golden: true, - }, - { - CaseName: Name(""), - in: `["Z01","Z02","Z03"]`, - ptr: new([]intWithPtrMarshalText), - out: []intWithPtrMarshalText{1, 2, 3}, - golden: true, - }, - - {CaseName: Name(""), in: `0.000001`, ptr: new(float64), out: 0.000001, golden: true}, - {CaseName: Name(""), in: `1e-7`, ptr: new(float64), out: 1e-7, golden: true}, - {CaseName: Name(""), in: `100000000000000000000`, ptr: new(float64), out: 100000000000000000000.0, golden: true}, - {CaseName: Name(""), in: `1e+21`, ptr: new(float64), out: 1e21, golden: true}, - {CaseName: Name(""), in: `-0.000001`, ptr: new(float64), out: -0.000001, golden: true}, - {CaseName: Name(""), in: `-1e-7`, ptr: new(float64), out: -1e-7, golden: true}, - {CaseName: Name(""), in: `-100000000000000000000`, ptr: new(float64), out: -100000000000000000000.0, golden: true}, - {CaseName: Name(""), in: `-1e+21`, ptr: new(float64), out: -1e21, golden: true}, - {CaseName: Name(""), in: `999999999999999900000`, ptr: new(float64), out: 999999999999999900000.0, golden: true}, - {CaseName: Name(""), in: `9007199254740992`, ptr: new(float64), out: 9007199254740992.0, golden: true}, - {CaseName: Name(""), in: `9007199254740993`, ptr: new(float64), out: 9007199254740992.0, golden: false}, - - { - CaseName: Name(""), - in: `{"V": {"F2": "hello"}}`, - ptr: new(VOuter), - err: &UnmarshalTypeError{ - Value: "string", - Struct: "V", - Field: "V.F2", - Type: reflect.TypeFor[int32](), - Offset: 20, - }, - }, - { - CaseName: Name(""), - in: `{"V": {"F4": {}, "F2": "hello"}}`, - ptr: new(VOuter), - err: &UnmarshalTypeError{ - Value: "string", - Struct: "V", - Field: "V.F2", - Type: reflect.TypeFor[int32](), - Offset: 30, - }, - }, - - // issue 15146. - // invalid inputs in wrongStringTests below. - {CaseName: Name(""), in: `{"B":"true"}`, ptr: new(B), out: B{true}, golden: true}, - {CaseName: Name(""), in: `{"B":"false"}`, ptr: new(B), out: B{false}, golden: true}, - {CaseName: Name(""), in: `{"B": "maybe"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "maybe" into bool`)}, - {CaseName: Name(""), in: `{"B": "tru"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "tru" into bool`)}, - {CaseName: Name(""), in: `{"B": "False"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "False" into bool`)}, - {CaseName: Name(""), in: `{"B": "null"}`, ptr: new(B), out: B{false}}, - {CaseName: Name(""), in: `{"B": "nul"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "nul" into bool`)}, - {CaseName: Name(""), in: `{"B": [2, 3]}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal unquoted value into bool`)}, - - // additional tests for disallowUnknownFields - { - CaseName: Name(""), - in: `{ - "Level0": 1, - "Level1b": 2, - "Level1c": 3, - "x": 4, - "Level1a": 5, - "LEVEL1B": 6, - "e": { - "Level1a": 8, - "Level1b": 9, - "Level1c": 10, - "Level1d": 11, - "x": 12 - }, - "Loop1": 13, - "Loop2": 14, - "X": 15, - "Y": 16, - "Z": 17, - "Q": 18, - "extra": true - }`, - ptr: new(Top), - err: fmt.Errorf("json: unknown field \"extra\""), - disallowUnknownFields: true, - }, - { - CaseName: Name(""), - in: `{ - "Level0": 1, - "Level1b": 2, - "Level1c": 3, - "x": 4, - "Level1a": 5, - "LEVEL1B": 6, - "e": { - "Level1a": 8, - "Level1b": 9, - "Level1c": 10, - "Level1d": 11, - "x": 12, - "extra": null - }, - "Loop1": 13, - "Loop2": 14, - "X": 15, - "Y": 16, - "Z": 17, - "Q": 18 - }`, - ptr: new(Top), - err: fmt.Errorf("json: unknown field \"extra\""), - disallowUnknownFields: true, - }, - // issue 26444 - // UnmarshalTypeError without field & struct values - { - CaseName: Name(""), - in: `{"data":{"test1": "bob", "test2": 123}}`, - ptr: new(mapStringToStringData), - err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[string](), Offset: 37, Struct: "mapStringToStringData", Field: "data"}, - }, - { - CaseName: Name(""), - in: `{"data":{"test1": 123, "test2": "bob"}}`, - ptr: new(mapStringToStringData), - err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeFor[string](), Offset: 21, Struct: "mapStringToStringData", Field: "data"}, - }, - - // trying to decode JSON arrays or objects via TextUnmarshaler - { - CaseName: Name(""), - in: `[1, 2, 3]`, - ptr: new(MustNotUnmarshalText), - err: &UnmarshalTypeError{Value: "array", Type: reflect.TypeFor[*MustNotUnmarshalText](), Offset: 1}, - }, - { - CaseName: Name(""), - in: `{"foo": "bar"}`, - ptr: new(MustNotUnmarshalText), - err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeFor[*MustNotUnmarshalText](), Offset: 1}, - }, - // #22369 - { - CaseName: Name(""), - in: `{"PP": {"T": {"Y": "bad-type"}}}`, - ptr: new(P), - err: &UnmarshalTypeError{ - Value: "string", - Struct: "T", - Field: "PP.T.Y", - Type: reflect.TypeFor[int](), - Offset: 29, - }, - }, - { - CaseName: Name(""), - in: `{"Ts": [{"Y": 1}, {"Y": 2}, {"Y": "bad-type"}]}`, - ptr: new(PP), - err: &UnmarshalTypeError{ - Value: "string", - Struct: "T", - Field: "Ts.Y", - Type: reflect.TypeFor[int](), - Offset: 29, - }, - }, - // #14702 - { - CaseName: Name(""), - in: `invalid`, - ptr: new(Number), - err: &SyntaxError{ - msg: "invalid character 'i' looking for beginning of value", - Offset: 1, - }, - }, - { - CaseName: Name(""), - in: `"invalid"`, - ptr: new(Number), - err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`), - }, - { - CaseName: Name(""), - in: `{"A":"invalid"}`, - ptr: new(struct{ A Number }), - err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`), - }, - { - CaseName: Name(""), - in: `{"A":"invalid"}`, - ptr: new(struct { - A Number `json:",string"` - }), - err: fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into json.Number", `invalid`), - }, - { - CaseName: Name(""), - in: `{"A":"invalid"}`, - ptr: new(map[string]Number), - err: fmt.Errorf("json: invalid number literal, trying to unmarshal %q into Number", `"invalid"`), - }, -} - -func TestMarshal(t *testing.T) { - b, err := Marshal(allValue) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - if string(b) != allValueCompact { - t.Errorf("Marshal:") - diff(t, b, []byte(allValueCompact)) - return - } - - b, err = Marshal(pallValue) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - if string(b) != pallValueCompact { - t.Errorf("Marshal:") - diff(t, b, []byte(pallValueCompact)) - return - } -} - -func TestMarshalInvalidUTF8(t *testing.T) { - tests := []struct { - CaseName - in string - want string - }{ - {Name(""), "hello\xffworld", `"hello\ufffdworld"`}, - {Name(""), "", `""`}, - {Name(""), "\xff", `"\ufffd"`}, - {Name(""), "\xff\xff", `"\ufffd\ufffd"`}, - {Name(""), "a\xffb", `"a\ufffdb"`}, - {Name(""), "\xe6\x97\xa5\xe6\x9c\xac\xff\xaa\x9e", `"日本\ufffd\ufffd\ufffd"`}, - } - for _, tt := range tests { - t.Run(tt.Name, func(t *testing.T) { - got, err := Marshal(tt.in) - if string(got) != tt.want || err != nil { - t.Errorf("%s: Marshal(%q):\n\tgot: (%q, %v)\n\twant: (%q, nil)", tt.Where, tt.in, got, err, tt.want) - } - }) - } -} - -func TestMarshalNumberZeroVal(t *testing.T) { - var n Number - out, err := Marshal(n) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - got := string(out) - if got != "0" { - t.Fatalf("Marshal: got %s, want 0", got) - } -} - -func TestMarshalEmbeds(t *testing.T) { - top := &Top{ - Level0: 1, - Embed0: Embed0{ - Level1b: 2, - Level1c: 3, - }, - Embed0a: &Embed0a{ - Level1a: 5, - Level1b: 6, - }, - Embed0b: &Embed0b{ - Level1a: 8, - Level1b: 9, - Level1c: 10, - Level1d: 11, - Level1e: 12, - }, - Loop: Loop{ - Loop1: 13, - Loop2: 14, - }, - Embed0p: Embed0p{ - Point: image.Point{X: 15, Y: 16}, - }, - Embed0q: Embed0q{ - Point: Point{Z: 17}, - }, - embed: embed{ - Q: 18, - }, - } - got, err := Marshal(top) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - want := "{\"Level0\":1,\"Level1b\":2,\"Level1c\":3,\"Level1a\":5,\"LEVEL1B\":6,\"e\":{\"Level1a\":8,\"Level1b\":9,\"Level1c\":10,\"Level1d\":11,\"x\":12},\"Loop1\":13,\"Loop2\":14,\"X\":15,\"Y\":16,\"Z\":17,\"Q\":18}" - if string(got) != want { - t.Errorf("Marshal:\n\tgot: %s\n\twant: %s", got, want) - } -} - -func equalError(a, b error) bool { - if a == nil || b == nil { - return a == nil && b == nil - } - return a.Error() == b.Error() -} - -func TestUnmarshal(t *testing.T) { - for _, tt := range unmarshalTests { - t.Run(tt.Name, func(t *testing.T) { - in := []byte(tt.in) - var scan scanner - if err := checkValid(in, &scan); err != nil { - if !equalError(err, tt.err) { - t.Fatalf("%s: checkValid error: %#v", tt.Where, err) - } - } - if tt.ptr == nil { - return - } - - typ := reflect.TypeOf(tt.ptr) - if typ.Kind() != reflect.Pointer { - t.Fatalf("%s: unmarshalTest.ptr %T is not a pointer type", tt.Where, tt.ptr) - } - typ = typ.Elem() - - // v = new(right-type) - v := reflect.New(typ) - - if !reflect.DeepEqual(tt.ptr, v.Interface()) { - // There's no reason for ptr to point to non-zero data, - // as we decode into new(right-type), so the data is - // discarded. - // This can easily mean tests that silently don't test - // what they should. To test decoding into existing - // data, see TestPrefilled. - t.Fatalf("%s: unmarshalTest.ptr %#v is not a pointer to a zero value", tt.Where, tt.ptr) - } - - dec := NewDecoder(bytes.NewReader(in)) - if tt.useNumber { - dec.UseNumber() - } - if tt.disallowUnknownFields { - dec.DisallowUnknownFields() - } - if err := dec.Decode(v.Interface()); !equalError(err, tt.err) { - t.Fatalf("%s: Decode error:\n\tgot: %v\n\twant: %v", tt.Where, err, tt.err) - } else if err != nil { - return - } - if got := v.Elem().Interface(); !reflect.DeepEqual(got, tt.out) { - gotJSON, _ := Marshal(got) - wantJSON, _ := Marshal(tt.out) - t.Fatalf("%s: Decode:\n\tgot: %#+v\n\twant: %#+v\n\n\tgotJSON: %s\n\twantJSON: %s", tt.Where, got, tt.out, gotJSON, wantJSON) - } - - // Check round trip also decodes correctly. - if tt.err == nil { - enc, err := Marshal(v.Interface()) - if err != nil { - t.Fatalf("%s: Marshal error after roundtrip: %v", tt.Where, err) - } - if tt.golden && !bytes.Equal(enc, in) { - t.Errorf("%s: Marshal:\n\tgot: %s\n\twant: %s", tt.Where, enc, in) - } - vv := reflect.New(reflect.TypeOf(tt.ptr).Elem()) - dec = NewDecoder(bytes.NewReader(enc)) - if tt.useNumber { - dec.UseNumber() - } - if err := dec.Decode(vv.Interface()); err != nil { - t.Fatalf("%s: Decode(%#q) error after roundtrip: %v", tt.Where, enc, err) - } - if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().Interface()) { - t.Fatalf("%s: Decode:\n\tgot: %#+v\n\twant: %#+v\n\n\tgotJSON: %s\n\twantJSON: %s", - tt.Where, v.Elem().Interface(), vv.Elem().Interface(), - stripWhitespace(string(enc)), stripWhitespace(string(in))) - } - } - }) - } -} - -func TestUnmarshalMarshal(t *testing.T) { - initBig() - var v any - if err := Unmarshal(jsonBig, &v); err != nil { - t.Fatalf("Unmarshal error: %v", err) - } - b, err := Marshal(v) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - if !bytes.Equal(jsonBig, b) { - t.Errorf("Marshal:") - diff(t, b, jsonBig) - return - } -} - -// Independent of Decode, basic coverage of the accessors in Number -func TestNumberAccessors(t *testing.T) { - tests := []struct { - CaseName - in string - i int64 - intErr string - f float64 - floatErr string - }{ - {CaseName: Name(""), in: "-1.23e1", intErr: "strconv.ParseInt: parsing \"-1.23e1\": invalid syntax", f: -1.23e1}, - {CaseName: Name(""), in: "-12", i: -12, f: -12.0}, - {CaseName: Name(""), in: "1e1000", intErr: "strconv.ParseInt: parsing \"1e1000\": invalid syntax", floatErr: "strconv.ParseFloat: parsing \"1e1000\": value out of range"}, - } - for _, tt := range tests { - t.Run(tt.Name, func(t *testing.T) { - n := Number(tt.in) - if got := n.String(); got != tt.in { - t.Errorf("%s: Number(%q).String() = %s, want %s", tt.Where, tt.in, got, tt.in) - } - if i, err := n.Int64(); err == nil && tt.intErr == "" && i != tt.i { - t.Errorf("%s: Number(%q).Int64() = %d, want %d", tt.Where, tt.in, i, tt.i) - } else if (err == nil && tt.intErr != "") || (err != nil && err.Error() != tt.intErr) { - t.Errorf("%s: Number(%q).Int64() error:\n\tgot: %v\n\twant: %v", tt.Where, tt.in, err, tt.intErr) - } - if f, err := n.Float64(); err == nil && tt.floatErr == "" && f != tt.f { - t.Errorf("%s: Number(%q).Float64() = %g, want %g", tt.Where, tt.in, f, tt.f) - } else if (err == nil && tt.floatErr != "") || (err != nil && err.Error() != tt.floatErr) { - t.Errorf("%s: Number(%q).Float64() error:\n\tgot %v\n\twant: %v", tt.Where, tt.in, err, tt.floatErr) - } - }) - } -} - -func TestLargeByteSlice(t *testing.T) { - s0 := make([]byte, 2000) - for i := range s0 { - s0[i] = byte(i) - } - b, err := Marshal(s0) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - var s1 []byte - if err := Unmarshal(b, &s1); err != nil { - t.Fatalf("Unmarshal error: %v", err) - } - if !bytes.Equal(s0, s1) { - t.Errorf("Marshal:") - diff(t, s0, s1) - } -} - -type Xint struct { - X int -} - -func TestUnmarshalInterface(t *testing.T) { - var xint Xint - var i any = &xint - if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil { - t.Fatalf("Unmarshal error: %v", err) - } - if xint.X != 1 { - t.Fatalf("xint.X = %d, want 1", xint.X) - } -} - -func TestUnmarshalPtrPtr(t *testing.T) { - var xint Xint - pxint := &xint - if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil { - t.Fatalf("Unmarshal: %v", err) - } - if xint.X != 1 { - t.Fatalf("xint.X = %d, want 1", xint.X) - } -} - -func TestEscape(t *testing.T) { - const input = `"foobar"` + " [\u2028 \u2029]" - const want = `"\"foobar\"\u003chtml\u003e [\u2028 \u2029]"` - got, err := Marshal(input) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - if string(got) != want { - t.Errorf("Marshal(%#q):\n\tgot: %s\n\twant: %s", input, got, want) - } -} - -// If people misuse the ,string modifier, the error message should be -// helpful, telling the user that they're doing it wrong. -func TestErrorMessageFromMisusedString(t *testing.T) { - // WrongString is a struct that's misusing the ,string modifier. - type WrongString struct { - Message string `json:"result,string"` - } - tests := []struct { - CaseName - in, err string - }{ - {Name(""), `{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`}, - {Name(""), `{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`}, - {Name(""), `{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`}, - {Name(""), `{"result":123}`, `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into string`}, - {Name(""), `{"result":"\""}`, `json: invalid use of ,string struct tag, trying to unmarshal "\"" into string`}, - {Name(""), `{"result":"\"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "\"foo" into string`}, - } - for _, tt := range tests { - t.Run(tt.Name, func(t *testing.T) { - r := strings.NewReader(tt.in) - var s WrongString - err := NewDecoder(r).Decode(&s) - got := fmt.Sprintf("%v", err) - if got != tt.err { - t.Errorf("%s: Decode error:\n\tgot: %s\n\twant: %s", tt.Where, got, tt.err) - } - }) - } -} - -type All struct { - Bool bool - Int int - Int8 int8 - Int16 int16 - Int32 int32 - Int64 int64 - Uint uint - Uint8 uint8 - Uint16 uint16 - Uint32 uint32 - Uint64 uint64 - Uintptr uintptr - Float32 float32 - Float64 float64 - - Foo string `json:"bar"` - Foo2 string `json:"bar2,dummyopt"` - - IntStr int64 `json:",string"` - UintptrStr uintptr `json:",string"` - - PBool *bool - PInt *int - PInt8 *int8 - PInt16 *int16 - PInt32 *int32 - PInt64 *int64 - PUint *uint - PUint8 *uint8 - PUint16 *uint16 - PUint32 *uint32 - PUint64 *uint64 - PUintptr *uintptr - PFloat32 *float32 - PFloat64 *float64 - - String string - PString *string - - Map map[string]Small - MapP map[string]*Small - PMap *map[string]Small - PMapP *map[string]*Small - - EmptyMap map[string]Small - NilMap map[string]Small - - Slice []Small - SliceP []*Small - PSlice *[]Small - PSliceP *[]*Small - - EmptySlice []Small - NilSlice []Small - - StringSlice []string - ByteSlice []byte - - Small Small - PSmall *Small - PPSmall **Small - - Interface any - PInterface *any - - unexported int -} - -type Small struct { - Tag string -} - -var allValue = All{ - Bool: true, - Int: 2, - Int8: 3, - Int16: 4, - Int32: 5, - Int64: 6, - Uint: 7, - Uint8: 8, - Uint16: 9, - Uint32: 10, - Uint64: 11, - Uintptr: 12, - Float32: 14.1, - Float64: 15.1, - Foo: "foo", - Foo2: "foo2", - IntStr: 42, - UintptrStr: 44, - String: "16", - Map: map[string]Small{ - "17": {Tag: "tag17"}, - "18": {Tag: "tag18"}, - }, - MapP: map[string]*Small{ - "19": {Tag: "tag19"}, - "20": nil, - }, - EmptyMap: map[string]Small{}, - Slice: []Small{{Tag: "tag20"}, {Tag: "tag21"}}, - SliceP: []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}}, - EmptySlice: []Small{}, - StringSlice: []string{"str24", "str25", "str26"}, - ByteSlice: []byte{27, 28, 29}, - Small: Small{Tag: "tag30"}, - PSmall: &Small{Tag: "tag31"}, - Interface: 5.2, -} - -var pallValue = All{ - PBool: &allValue.Bool, - PInt: &allValue.Int, - PInt8: &allValue.Int8, - PInt16: &allValue.Int16, - PInt32: &allValue.Int32, - PInt64: &allValue.Int64, - PUint: &allValue.Uint, - PUint8: &allValue.Uint8, - PUint16: &allValue.Uint16, - PUint32: &allValue.Uint32, - PUint64: &allValue.Uint64, - PUintptr: &allValue.Uintptr, - PFloat32: &allValue.Float32, - PFloat64: &allValue.Float64, - PString: &allValue.String, - PMap: &allValue.Map, - PMapP: &allValue.MapP, - PSlice: &allValue.Slice, - PSliceP: &allValue.SliceP, - PPSmall: &allValue.PSmall, - PInterface: &allValue.Interface, -} - -var allValueIndent = `{ - "Bool": true, - "Int": 2, - "Int8": 3, - "Int16": 4, - "Int32": 5, - "Int64": 6, - "Uint": 7, - "Uint8": 8, - "Uint16": 9, - "Uint32": 10, - "Uint64": 11, - "Uintptr": 12, - "Float32": 14.1, - "Float64": 15.1, - "bar": "foo", - "bar2": "foo2", - "IntStr": "42", - "UintptrStr": "44", - "PBool": null, - "PInt": null, - "PInt8": null, - "PInt16": null, - "PInt32": null, - "PInt64": null, - "PUint": null, - "PUint8": null, - "PUint16": null, - "PUint32": null, - "PUint64": null, - "PUintptr": null, - "PFloat32": null, - "PFloat64": null, - "String": "16", - "PString": null, - "Map": { - "17": { - "Tag": "tag17" - }, - "18": { - "Tag": "tag18" - } - }, - "MapP": { - "19": { - "Tag": "tag19" - }, - "20": null - }, - "PMap": null, - "PMapP": null, - "EmptyMap": {}, - "NilMap": null, - "Slice": [ - { - "Tag": "tag20" - }, - { - "Tag": "tag21" - } - ], - "SliceP": [ - { - "Tag": "tag22" - }, - null, - { - "Tag": "tag23" - } - ], - "PSlice": null, - "PSliceP": null, - "EmptySlice": [], - "NilSlice": null, - "StringSlice": [ - "str24", - "str25", - "str26" - ], - "ByteSlice": "Gxwd", - "Small": { - "Tag": "tag30" - }, - "PSmall": { - "Tag": "tag31" - }, - "PPSmall": null, - "Interface": 5.2, - "PInterface": null -}` - -var allValueCompact = stripWhitespace(allValueIndent) - -var pallValueIndent = `{ - "Bool": false, - "Int": 0, - "Int8": 0, - "Int16": 0, - "Int32": 0, - "Int64": 0, - "Uint": 0, - "Uint8": 0, - "Uint16": 0, - "Uint32": 0, - "Uint64": 0, - "Uintptr": 0, - "Float32": 0, - "Float64": 0, - "bar": "", - "bar2": "", - "IntStr": "0", - "UintptrStr": "0", - "PBool": true, - "PInt": 2, - "PInt8": 3, - "PInt16": 4, - "PInt32": 5, - "PInt64": 6, - "PUint": 7, - "PUint8": 8, - "PUint16": 9, - "PUint32": 10, - "PUint64": 11, - "PUintptr": 12, - "PFloat32": 14.1, - "PFloat64": 15.1, - "String": "", - "PString": "16", - "Map": null, - "MapP": null, - "PMap": { - "17": { - "Tag": "tag17" - }, - "18": { - "Tag": "tag18" - } - }, - "PMapP": { - "19": { - "Tag": "tag19" - }, - "20": null - }, - "EmptyMap": null, - "NilMap": null, - "Slice": null, - "SliceP": null, - "PSlice": [ - { - "Tag": "tag20" - }, - { - "Tag": "tag21" - } - ], - "PSliceP": [ - { - "Tag": "tag22" - }, - null, - { - "Tag": "tag23" - } - ], - "EmptySlice": null, - "NilSlice": null, - "StringSlice": null, - "ByteSlice": null, - "Small": { - "Tag": "" - }, - "PSmall": null, - "PPSmall": { - "Tag": "tag31" - }, - "Interface": null, - "PInterface": 5.2 -}` - -var pallValueCompact = stripWhitespace(pallValueIndent) - -func TestRefUnmarshal(t *testing.T) { - type S struct { - // Ref is defined in encode_test.go. - R0 Ref - R1 *Ref - R2 RefText - R3 *RefText - } - want := S{ - R0: 12, - R1: new(Ref), - R2: 13, - R3: new(RefText), - } - *want.R1 = 12 - *want.R3 = 13 - - var got S - if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref","R2":"ref","R3":"ref"}`), &got); err != nil { - t.Fatalf("Unmarshal error: %v", err) - } - if !reflect.DeepEqual(got, want) { - t.Errorf("Unmarsha:\n\tgot: %+v\n\twant: %+v", got, want) - } -} - -// Test that the empty string doesn't panic decoding when ,string is specified -// Issue 3450 -func TestEmptyString(t *testing.T) { - type T2 struct { - Number1 int `json:",string"` - Number2 int `json:",string"` - } - data := `{"Number1":"1", "Number2":""}` - dec := NewDecoder(strings.NewReader(data)) - var got T2 - switch err := dec.Decode(&got); { - case err == nil: - t.Fatalf("Decode error: got nil, want non-nil") - case got.Number1 != 1: - t.Fatalf("Decode: got.Number1 = %d, want 1", got.Number1) - } -} - -// Test that a null for ,string is not replaced with the previous quoted string (issue 7046). -// It should also not be an error (issue 2540, issue 8587). -func TestNullString(t *testing.T) { - type T struct { - A int `json:",string"` - B int `json:",string"` - C *int `json:",string"` - } - data := []byte(`{"A": "1", "B": null, "C": null}`) - var s T - s.B = 1 - s.C = new(int) - *s.C = 2 - switch err := Unmarshal(data, &s); { - case err != nil: - t.Fatalf("Unmarshal error: %v", err) - case s.B != 1: - t.Fatalf("Unmarshal: s.B = %d, want 1", s.B) - case s.C != nil: - t.Fatalf("Unmarshal: s.C = %d, want non-nil", s.C) - } -} - -func intp(x int) *int { - p := new(int) - *p = x - return p -} - -func intpp(x *int) **int { - pp := new(*int) - *pp = x - return pp -} - -func TestInterfaceSet(t *testing.T) { - tests := []struct { - CaseName - pre any - json string - post any - }{ - {Name(""), "foo", `"bar"`, "bar"}, - {Name(""), "foo", `2`, 2.0}, - {Name(""), "foo", `true`, true}, - {Name(""), "foo", `null`, nil}, - - {Name(""), nil, `null`, nil}, - {Name(""), new(int), `null`, nil}, - {Name(""), (*int)(nil), `null`, nil}, - {Name(""), new(*int), `null`, new(*int)}, - {Name(""), (**int)(nil), `null`, nil}, - {Name(""), intp(1), `null`, nil}, - {Name(""), intpp(nil), `null`, intpp(nil)}, - {Name(""), intpp(intp(1)), `null`, intpp(nil)}, - } - for _, tt := range tests { - t.Run(tt.Name, func(t *testing.T) { - b := struct{ X any }{tt.pre} - blob := `{"X":` + tt.json + `}` - if err := Unmarshal([]byte(blob), &b); err != nil { - t.Fatalf("%s: Unmarshal(%#q) error: %v", tt.Where, blob, err) - } - if !reflect.DeepEqual(b.X, tt.post) { - t.Errorf("%s: Unmarshal(%#q):\n\tpre.X: %#v\n\tgot.X: %#v\n\twant.X: %#v", tt.Where, blob, tt.pre, b.X, tt.post) - } - }) - } -} - -type NullTest struct { - Bool bool - Int int - Int8 int8 - Int16 int16 - Int32 int32 - Int64 int64 - Uint uint - Uint8 uint8 - Uint16 uint16 - Uint32 uint32 - Uint64 uint64 - Float32 float32 - Float64 float64 - String string - PBool *bool - Map map[string]string - Slice []string - Interface any - - PRaw *RawMessage - PTime *time.Time - PBigInt *big.Int - PText *MustNotUnmarshalText - PBuffer *bytes.Buffer // has methods, just not relevant ones - PStruct *struct{} - - Raw RawMessage - Time time.Time - BigInt big.Int - Text MustNotUnmarshalText - Buffer bytes.Buffer - Struct struct{} -} - -// JSON null values should be ignored for primitives and string values instead of resulting in an error. -// Issue 2540 -func TestUnmarshalNulls(t *testing.T) { - // Unmarshal docs: - // The JSON null value unmarshals into an interface, map, pointer, or slice - // by setting that Go value to nil. Because null is often used in JSON to mean - // ``not present,'' unmarshaling a JSON null into any other Go type has no effect - // on the value and produces no error. - - jsonData := []byte(`{ - "Bool" : null, - "Int" : null, - "Int8" : null, - "Int16" : null, - "Int32" : null, - "Int64" : null, - "Uint" : null, - "Uint8" : null, - "Uint16" : null, - "Uint32" : null, - "Uint64" : null, - "Float32" : null, - "Float64" : null, - "String" : null, - "PBool": null, - "Map": null, - "Slice": null, - "Interface": null, - "PRaw": null, - "PTime": null, - "PBigInt": null, - "PText": null, - "PBuffer": null, - "PStruct": null, - "Raw": null, - "Time": null, - "BigInt": null, - "Text": null, - "Buffer": null, - "Struct": null - }`) - nulls := NullTest{ - Bool: true, - Int: 2, - Int8: 3, - Int16: 4, - Int32: 5, - Int64: 6, - Uint: 7, - Uint8: 8, - Uint16: 9, - Uint32: 10, - Uint64: 11, - Float32: 12.1, - Float64: 13.1, - String: "14", - PBool: new(bool), - Map: map[string]string{}, - Slice: []string{}, - Interface: new(MustNotUnmarshalJSON), - PRaw: new(RawMessage), - PTime: new(time.Time), - PBigInt: new(big.Int), - PText: new(MustNotUnmarshalText), - PStruct: new(struct{}), - PBuffer: new(bytes.Buffer), - Raw: RawMessage("123"), - Time: time.Unix(123456789, 0), - BigInt: *big.NewInt(123), - } - - before := nulls.Time.String() - - err := Unmarshal(jsonData, &nulls) - if err != nil { - t.Errorf("Unmarshal of null values failed: %v", err) - } - if !nulls.Bool || nulls.Int != 2 || nulls.Int8 != 3 || nulls.Int16 != 4 || nulls.Int32 != 5 || nulls.Int64 != 6 || - nulls.Uint != 7 || nulls.Uint8 != 8 || nulls.Uint16 != 9 || nulls.Uint32 != 10 || nulls.Uint64 != 11 || - nulls.Float32 != 12.1 || nulls.Float64 != 13.1 || nulls.String != "14" { - t.Errorf("Unmarshal of null values affected primitives") - } - - if nulls.PBool != nil { - t.Errorf("Unmarshal of null did not clear nulls.PBool") - } - if nulls.Map != nil { - t.Errorf("Unmarshal of null did not clear nulls.Map") - } - if nulls.Slice != nil { - t.Errorf("Unmarshal of null did not clear nulls.Slice") - } - if nulls.Interface != nil { - t.Errorf("Unmarshal of null did not clear nulls.Interface") - } - if nulls.PRaw != nil { - t.Errorf("Unmarshal of null did not clear nulls.PRaw") - } - if nulls.PTime != nil { - t.Errorf("Unmarshal of null did not clear nulls.PTime") - } - if nulls.PBigInt != nil { - t.Errorf("Unmarshal of null did not clear nulls.PBigInt") - } - if nulls.PText != nil { - t.Errorf("Unmarshal of null did not clear nulls.PText") - } - if nulls.PBuffer != nil { - t.Errorf("Unmarshal of null did not clear nulls.PBuffer") - } - if nulls.PStruct != nil { - t.Errorf("Unmarshal of null did not clear nulls.PStruct") - } - - if string(nulls.Raw) != "null" { - t.Errorf("Unmarshal of RawMessage null did not record null: %v", string(nulls.Raw)) - } - if nulls.Time.String() != before { - t.Errorf("Unmarshal of time.Time null set time to %v", nulls.Time.String()) - } - if nulls.BigInt.String() != "123" { - t.Errorf("Unmarshal of big.Int null set int to %v", nulls.BigInt.String()) - } -} - -type MustNotUnmarshalJSON struct{} - -func (x MustNotUnmarshalJSON) UnmarshalJSON(data []byte) error { - return errors.New("MustNotUnmarshalJSON was used") -} - -type MustNotUnmarshalText struct{} - -func (x MustNotUnmarshalText) UnmarshalText(text []byte) error { - return errors.New("MustNotUnmarshalText was used") -} - -func TestStringKind(t *testing.T) { - type stringKind string - want := map[stringKind]int{"foo": 42} - data, err := Marshal(want) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - var got map[stringKind]int - err = Unmarshal(data, &got) - if err != nil { - t.Fatalf("Unmarshal error: %v", err) - } - if !reflect.DeepEqual(got, want) { - t.Fatalf("Marshal/Unmarshal mismatch:\n\tgot: %v\n\twant: %v", got, want) - } -} - -// Custom types with []byte as underlying type could not be marshaled -// and then unmarshaled. -// Issue 8962. -func TestByteKind(t *testing.T) { - type byteKind []byte - want := byteKind("hello") - data, err := Marshal(want) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - var got byteKind - err = Unmarshal(data, &got) - if err != nil { - t.Fatalf("Unmarshal error: %v", err) - } - if !slices.Equal(got, want) { - t.Fatalf("Marshal/Unmarshal mismatch:\n\tgot: %v\n\twant: %v", got, want) - } -} - -// The fix for issue 8962 introduced a regression. -// Issue 12921. -func TestSliceOfCustomByte(t *testing.T) { - type Uint8 uint8 - want := []Uint8("hello") - data, err := Marshal(want) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - var got []Uint8 - err = Unmarshal(data, &got) - if err != nil { - t.Fatalf("Unmarshal error: %v", err) - } - if !slices.Equal(got, want) { - t.Fatalf("Marshal/Unmarshal mismatch:\n\tgot: %v\n\twant: %v", got, want) - } -} - -func TestUnmarshalTypeError(t *testing.T) { - tests := []struct { - CaseName - dest any - in string - }{ - {Name(""), new(string), `{"user": "name"}`}, // issue 4628. - {Name(""), new(error), `{}`}, // issue 4222 - {Name(""), new(error), `[]`}, - {Name(""), new(error), `""`}, - {Name(""), new(error), `123`}, - {Name(""), new(error), `true`}, - } - for _, tt := range tests { - t.Run(tt.Name, func(t *testing.T) { - err := Unmarshal([]byte(tt.in), tt.dest) - if _, ok := err.(*UnmarshalTypeError); !ok { - t.Errorf("%s: Unmarshal(%#q, %T):\n\tgot: %T\n\twant: %T", - tt.Where, tt.in, tt.dest, err, new(UnmarshalTypeError)) - } - }) - } -} - -func TestUnmarshalSyntax(t *testing.T) { - var x any - tests := []struct { - CaseName - in string - }{ - {Name(""), "tru"}, - {Name(""), "fals"}, - {Name(""), "nul"}, - {Name(""), "123e"}, - {Name(""), `"hello`}, - {Name(""), `[1,2,3`}, - {Name(""), `{"key":1`}, - {Name(""), `{"key":1,`}, - } - for _, tt := range tests { - t.Run(tt.Name, func(t *testing.T) { - err := Unmarshal([]byte(tt.in), &x) - if _, ok := err.(*SyntaxError); !ok { - t.Errorf("%s: Unmarshal(%#q, any):\n\tgot: %T\n\twant: %T", - tt.Where, tt.in, err, new(SyntaxError)) - } - }) - } -} - -// Test handling of unexported fields that should be ignored. -// Issue 4660 -type unexportedFields struct { - Name string - m map[string]any `json:"-"` - m2 map[string]any `json:"abcd"` - - s []int `json:"-"` -} - -func TestUnmarshalUnexported(t *testing.T) { - input := `{"Name": "Bob", "m": {"x": 123}, "m2": {"y": 456}, "abcd": {"z": 789}, "s": [2, 3]}` - want := &unexportedFields{Name: "Bob"} - - out := &unexportedFields{} - err := Unmarshal([]byte(input), out) - if err != nil { - t.Errorf("Unmarshal error: %v", err) - } - if !reflect.DeepEqual(out, want) { - t.Errorf("Unmarshal:\n\tgot: %+v\n\twant: %+v", out, want) - } -} - -// Time3339 is a time.Time which encodes to and from JSON -// as an RFC 3339 time in UTC. -type Time3339 time.Time - -func (t *Time3339) UnmarshalJSON(b []byte) error { - if len(b) < 2 || b[0] != '"' || b[len(b)-1] != '"' { - return fmt.Errorf("types: failed to unmarshal non-string value %q as an RFC 3339 time", b) - } - tm, err := time.Parse(time.RFC3339, string(b[1:len(b)-1])) - if err != nil { - return err - } - *t = Time3339(tm) - return nil -} - -func TestUnmarshalJSONLiteralError(t *testing.T) { - var t3 Time3339 - switch err := Unmarshal([]byte(`"0000-00-00T00:00:00Z"`), &t3); { - case err == nil: - t.Fatalf("Unmarshal error: got nil, want non-nil") - case !strings.Contains(err.Error(), "range"): - t.Errorf("Unmarshal error:\n\tgot: %v\n\twant: out of range", err) - } -} - -// Test that extra object elements in an array do not result in a -// "data changing underfoot" error. -// Issue 3717 -func TestSkipArrayObjects(t *testing.T) { - json := `[{}]` - var dest [0]any - - err := Unmarshal([]byte(json), &dest) - if err != nil { - t.Errorf("Unmarshal error: %v", err) - } -} - -// Test semantics of pre-filled data, such as struct fields, map elements, -// slices, and arrays. -// Issues 4900 and 8837, among others. -func TestPrefilled(t *testing.T) { - // Values here change, cannot reuse table across runs. - tests := []struct { - CaseName - in string - ptr any - out any - }{{ - CaseName: Name(""), - in: `{"X": 1, "Y": 2}`, - ptr: &XYZ{X: float32(3), Y: int16(4), Z: 1.5}, - out: &XYZ{X: float64(1), Y: float64(2), Z: 1.5}, - }, { - CaseName: Name(""), - in: `{"X": 1, "Y": 2}`, - ptr: &map[string]any{"X": float32(3), "Y": int16(4), "Z": 1.5}, - out: &map[string]any{"X": float64(1), "Y": float64(2), "Z": 1.5}, - }, { - CaseName: Name(""), - in: `[2]`, - ptr: &[]int{1}, - out: &[]int{2}, - }, { - CaseName: Name(""), - in: `[2, 3]`, - ptr: &[]int{1}, - out: &[]int{2, 3}, - }, { - CaseName: Name(""), - in: `[2, 3]`, - ptr: &[...]int{1}, - out: &[...]int{2}, - }, { - CaseName: Name(""), - in: `[3]`, - ptr: &[...]int{1, 2}, - out: &[...]int{3, 0}, - }} - for _, tt := range tests { - t.Run(tt.Name, func(t *testing.T) { - ptrstr := fmt.Sprintf("%v", tt.ptr) - err := Unmarshal([]byte(tt.in), tt.ptr) // tt.ptr edited here - if err != nil { - t.Errorf("%s: Unmarshal error: %v", tt.Where, err) - } - if !reflect.DeepEqual(tt.ptr, tt.out) { - t.Errorf("%s: Unmarshal(%#q, %T):\n\tgot: %v\n\twant: %v", tt.Where, tt.in, ptrstr, tt.ptr, tt.out) - } - }) - } -} - -func TestInvalidUnmarshal(t *testing.T) { - buf := []byte(`{"a":"1"}`) - tests := []struct { - CaseName - v any - want string - }{ - {Name(""), nil, "json: Unmarshal(nil)"}, - {Name(""), struct{}{}, "json: Unmarshal(non-pointer struct {})"}, - {Name(""), (*int)(nil), "json: Unmarshal(nil *int)"}, - } - for _, tt := range tests { - t.Run(tt.Name, func(t *testing.T) { - err := Unmarshal(buf, tt.v) - if err == nil { - t.Fatalf("%s: Unmarshal error: got nil, want non-nil", tt.Where) - } - if got := err.Error(); got != tt.want { - t.Errorf("%s: Unmarshal error:\n\tgot: %s\n\twant: %s", tt.Where, got, tt.want) - } - }) - } -} - -func TestInvalidUnmarshalText(t *testing.T) { - buf := []byte(`123`) - tests := []struct { - CaseName - v any - want string - }{ - {Name(""), nil, "json: Unmarshal(nil)"}, - {Name(""), struct{}{}, "json: Unmarshal(non-pointer struct {})"}, - {Name(""), (*int)(nil), "json: Unmarshal(nil *int)"}, - {Name(""), new(net.IP), "json: cannot unmarshal number into Go value of type *net.IP"}, - } - for _, tt := range tests { - t.Run(tt.Name, func(t *testing.T) { - err := Unmarshal(buf, tt.v) - if err == nil { - t.Fatalf("%s: Unmarshal error: got nil, want non-nil", tt.Where) - } - if got := err.Error(); got != tt.want { - t.Errorf("%s: Unmarshal error:\n\tgot: %s\n\twant: %s", tt.Where, got, tt.want) - } - }) - } -} - -// Test that string option is ignored for invalid types. -// Issue 9812. -func TestInvalidStringOption(t *testing.T) { - num := 0 - item := struct { - T time.Time `json:",string"` - M map[string]string `json:",string"` - S []string `json:",string"` - A [1]string `json:",string"` - I any `json:",string"` - P *int `json:",string"` - }{M: make(map[string]string), S: make([]string, 0), I: num, P: &num} - - data, err := Marshal(item) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - - err = Unmarshal(data, &item) - if err != nil { - t.Fatalf("Unmarshal error: %v", err) - } -} - -// Test unmarshal behavior with regards to embedded unexported structs. -// -// (Issue 21357) If the embedded struct is a pointer and is unallocated, -// this returns an error because unmarshal cannot set the field. -// -// (Issue 24152) If the embedded struct is given an explicit name, -// ensure that the normal unmarshal logic does not panic in reflect. -// -// (Issue 28145) If the embedded struct is given an explicit name and has -// exported methods, don't cause a panic trying to get its value. -func TestUnmarshalEmbeddedUnexported(t *testing.T) { - type ( - embed1 struct{ Q int } - embed2 struct{ Q int } - embed3 struct { - Q int64 `json:",string"` - } - S1 struct { - *embed1 - R int - } - S2 struct { - *embed1 - Q int - } - S3 struct { - embed1 - R int - } - S4 struct { - *embed1 - embed2 - } - S5 struct { - *embed3 - R int - } - S6 struct { - embed1 `json:"embed1"` - } - S7 struct { - embed1 `json:"embed1"` - embed2 - } - S8 struct { - embed1 `json:"embed1"` - embed2 `json:"embed2"` - Q int - } - S9 struct { - unexportedWithMethods `json:"embed"` - } - ) - - tests := []struct { - CaseName - in string - ptr any - out any - err error - }{{ - // Error since we cannot set S1.embed1, but still able to set S1.R. - CaseName: Name(""), - in: `{"R":2,"Q":1}`, - ptr: new(S1), - out: &S1{R: 2}, - err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed1"), - }, { - // The top level Q field takes precedence. - CaseName: Name(""), - in: `{"Q":1}`, - ptr: new(S2), - out: &S2{Q: 1}, - }, { - // No issue with non-pointer variant. - CaseName: Name(""), - in: `{"R":2,"Q":1}`, - ptr: new(S3), - out: &S3{embed1: embed1{Q: 1}, R: 2}, - }, { - // No error since both embedded structs have field R, which annihilate each other. - // Thus, no attempt is made at setting S4.embed1. - CaseName: Name(""), - in: `{"R":2}`, - ptr: new(S4), - out: new(S4), - }, { - // Error since we cannot set S5.embed1, but still able to set S5.R. - CaseName: Name(""), - in: `{"R":2,"Q":1}`, - ptr: new(S5), - out: &S5{R: 2}, - err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed3"), - }, { - // Issue 24152, ensure decodeState.indirect does not panic. - CaseName: Name(""), - in: `{"embed1": {"Q": 1}}`, - ptr: new(S6), - out: &S6{embed1{1}}, - }, { - // Issue 24153, check that we can still set forwarded fields even in - // the presence of a name conflict. - // - // This relies on obscure behavior of reflect where it is possible - // to set a forwarded exported field on an unexported embedded struct - // even though there is a name conflict, even when it would have been - // impossible to do so according to Go visibility rules. - // Go forbids this because it is ambiguous whether S7.Q refers to - // S7.embed1.Q or S7.embed2.Q. Since embed1 and embed2 are unexported, - // it should be impossible for an external package to set either Q. - // - // It is probably okay for a future reflect change to break this. - CaseName: Name(""), - in: `{"embed1": {"Q": 1}, "Q": 2}`, - ptr: new(S7), - out: &S7{embed1{1}, embed2{2}}, - }, { - // Issue 24153, similar to the S7 case. - CaseName: Name(""), - in: `{"embed1": {"Q": 1}, "embed2": {"Q": 2}, "Q": 3}`, - ptr: new(S8), - out: &S8{embed1{1}, embed2{2}, 3}, - }, { - // Issue 228145, similar to the cases above. - CaseName: Name(""), - in: `{"embed": {}}`, - ptr: new(S9), - out: &S9{}, - }} - for _, tt := range tests { - t.Run(tt.Name, func(t *testing.T) { - err := Unmarshal([]byte(tt.in), tt.ptr) - if !equalError(err, tt.err) { - t.Errorf("%s: Unmarshal error:\n\tgot: %v\n\twant: %v", tt.Where, err, tt.err) - } - if !reflect.DeepEqual(tt.ptr, tt.out) { - t.Errorf("%s: Unmarshal:\n\tgot: %#+v\n\twant: %#+v", tt.Where, tt.ptr, tt.out) - } - }) - } -} - -func TestUnmarshalErrorAfterMultipleJSON(t *testing.T) { - tests := []struct { - CaseName - in string - err error - }{{ - CaseName: Name(""), - in: `1 false null :`, - err: &SyntaxError{"invalid character ':' looking for beginning of value", 14}, - }, { - CaseName: Name(""), - in: `1 [] [,]`, - err: &SyntaxError{"invalid character ',' looking for beginning of value", 7}, - }, { - CaseName: Name(""), - in: `1 [] [true:]`, - err: &SyntaxError{"invalid character ':' after array element", 11}, - }, { - CaseName: Name(""), - in: `1 {} {"x"=}`, - err: &SyntaxError{"invalid character '=' after object key", 14}, - }, { - CaseName: Name(""), - in: `falsetruenul#`, - err: &SyntaxError{"invalid character '#' in literal null (expecting 'l')", 13}, - }} - for _, tt := range tests { - t.Run(tt.Name, func(t *testing.T) { - dec := NewDecoder(strings.NewReader(tt.in)) - var err error - for err == nil { - var v any - err = dec.Decode(&v) - } - if !reflect.DeepEqual(err, tt.err) { - t.Errorf("%s: Decode error:\n\tgot: %v\n\twant: %v", tt.Where, err, tt.err) - } - }) - } -} - -type unmarshalPanic struct{} - -func (unmarshalPanic) UnmarshalJSON([]byte) error { panic(0xdead) } - -func TestUnmarshalPanic(t *testing.T) { - defer func() { - if got := recover(); !reflect.DeepEqual(got, 0xdead) { - t.Errorf("panic() = (%T)(%v), want 0xdead", got, got) - } - }() - Unmarshal([]byte("{}"), &unmarshalPanic{}) - t.Fatalf("Unmarshal should have panicked") -} - -// The decoder used to hang if decoding into an interface pointing to its own address. -// See golang.org/issues/31740. -func TestUnmarshalRecursivePointer(t *testing.T) { - var v any - v = &v - data := []byte(`{"a": "b"}`) - - if err := Unmarshal(data, v); err != nil { - t.Fatalf("Unmarshal error: %v", err) - } -} - -type textUnmarshalerString string - -func (m *textUnmarshalerString) UnmarshalText(text []byte) error { - *m = textUnmarshalerString(strings.ToLower(string(text))) - return nil -} - -// Test unmarshal to a map, where the map key is a user defined type. -// See golang.org/issues/34437. -func TestUnmarshalMapWithTextUnmarshalerStringKey(t *testing.T) { - var p map[textUnmarshalerString]string - if err := Unmarshal([]byte(`{"FOO": "1"}`), &p); err != nil { - t.Fatalf("Unmarshal error: %v", err) - } - - if _, ok := p["foo"]; !ok { - t.Errorf(`key "foo" missing in map: %v`, p) - } -} - -func TestUnmarshalRescanLiteralMangledUnquote(t *testing.T) { - // See golang.org/issues/38105. - var p map[textUnmarshalerString]string - if err := Unmarshal([]byte(`{"开源":"12345开源"}`), &p); err != nil { - t.Fatalf("Unmarshal error: %v", err) - } - if _, ok := p["开源"]; !ok { - t.Errorf(`key "开源" missing in map: %v`, p) - } - - // See golang.org/issues/38126. - type T struct { - F1 string `json:"F1,string"` - } - wantT := T{"aaa\tbbb"} - - b, err := Marshal(wantT) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - var gotT T - if err := Unmarshal(b, &gotT); err != nil { - t.Fatalf("Unmarshal error: %v", err) - } - if gotT != wantT { - t.Errorf("Marshal/Unmarshal roundtrip:\n\tgot: %q\n\twant: %q", gotT, wantT) - } - - // See golang.org/issues/39555. - input := map[textUnmarshalerString]string{"FOO": "", `"`: ""} - - encoded, err := Marshal(input) - if err != nil { - t.Fatalf("Marshal error: %v", err) - } - var got map[textUnmarshalerString]string - if err := Unmarshal(encoded, &got); err != nil { - t.Fatalf("Unmarshal error: %v", err) - } - want := map[textUnmarshalerString]string{"foo": "", `"`: ""} - if !reflect.DeepEqual(got, want) { - t.Errorf("Marshal/Unmarshal roundtrip:\n\tgot: %q\n\twant: %q", gotT, wantT) - } -} - -func TestUnmarshalMaxDepth(t *testing.T) { - tests := []struct { - CaseName - data string - errMaxDepth bool - }{{ - CaseName: Name("ArrayUnderMaxNestingDepth"), - data: `{"a":` + strings.Repeat(`[`, 10000-1) + strings.Repeat(`]`, 10000-1) + `}`, - errMaxDepth: false, - }, { - CaseName: Name("ArrayOverMaxNestingDepth"), - data: `{"a":` + strings.Repeat(`[`, 10000) + strings.Repeat(`]`, 10000) + `}`, - errMaxDepth: true, - }, { - CaseName: Name("ArrayOverStackDepth"), - data: `{"a":` + strings.Repeat(`[`, 3000000) + strings.Repeat(`]`, 3000000) + `}`, - errMaxDepth: true, - }, { - CaseName: Name("ObjectUnderMaxNestingDepth"), - data: `{"a":` + strings.Repeat(`{"a":`, 10000-1) + `0` + strings.Repeat(`}`, 10000-1) + `}`, - errMaxDepth: false, - }, { - CaseName: Name("ObjectOverMaxNestingDepth"), - data: `{"a":` + strings.Repeat(`{"a":`, 10000) + `0` + strings.Repeat(`}`, 10000) + `}`, - errMaxDepth: true, - }, { - CaseName: Name("ObjectOverStackDepth"), - data: `{"a":` + strings.Repeat(`{"a":`, 3000000) + `0` + strings.Repeat(`}`, 3000000) + `}`, - errMaxDepth: true, - }} - - targets := []struct { - CaseName - newValue func() any - }{{ - CaseName: Name("unstructured"), - newValue: func() any { - var v any - return &v - }, - }, { - CaseName: Name("typed named field"), - newValue: func() any { - v := struct { - A any `json:"a"` - }{} - return &v - }, - }, { - CaseName: Name("typed missing field"), - newValue: func() any { - v := struct { - B any `json:"b"` - }{} - return &v - }, - }, { - CaseName: Name("custom unmarshaler"), - newValue: func() any { - v := unmarshaler{} - return &v - }, - }} - - for _, tt := range tests { - for _, target := range targets { - t.Run(target.Name+"-"+tt.Name, func(t *testing.T) { - err := Unmarshal([]byte(tt.data), target.newValue()) - if !tt.errMaxDepth { - if err != nil { - t.Errorf("%s: %s: Unmarshal error: %v", tt.Where, target.Where, err) - } - } else { - if err == nil || !strings.Contains(err.Error(), "exceeded max depth") { - t.Errorf("%s: %s: Unmarshal error:\n\tgot: %v\n\twant: exceeded max depth", tt.Where, target.Where, err) - } - } - }) - } - } -} diff --git a/internal/3rdparty/json/encode.go b/internal/3rdparty/json/encode.go deleted file mode 100644 index 7bee1a6..0000000 --- a/internal/3rdparty/json/encode.go +++ /dev/null @@ -1,1286 +0,0 @@ -// Copyright 2010 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package json implements encoding and decoding of JSON as defined in -// RFC 7159. The mapping between JSON and Go values is described -// in the documentation for the Marshal and Unmarshal functions. -// -// See "JSON and Go" for an introduction to this package: -// https://golang.org/doc/articles/json_and_go.html -package json - -import ( - "bytes" - "cmp" - "encoding" - "encoding/base64" - "fmt" - "math" - "reflect" - "slices" - "strconv" - "strings" - "sync" - "unicode" - "unicode/utf8" - _ "unsafe" // for linkname -) - -// Marshal returns the JSON encoding of v. -// -// Marshal traverses the value v recursively. -// If an encountered value implements [Marshaler] -// and is not a nil pointer, Marshal calls [Marshaler.MarshalJSON] -// to produce JSON. If no [Marshaler.MarshalJSON] method is present but the -// value implements [encoding.TextMarshaler] instead, Marshal calls -// [encoding.TextMarshaler.MarshalText] and encodes the result as a JSON string. -// The nil pointer exception is not strictly necessary -// but mimics a similar, necessary exception in the behavior of -// [Unmarshaler.UnmarshalJSON]. -// -// Otherwise, Marshal uses the following type-dependent default encodings: -// -// Boolean values encode as JSON booleans. -// -// Floating point, integer, and [Number] values encode as JSON numbers. -// NaN and +/-Inf values will return an [UnsupportedValueError]. -// -// String values encode as JSON strings coerced to valid UTF-8, -// replacing invalid bytes with the Unicode replacement rune. -// So that the JSON will be safe to embed inside HTML