package json_test import ( "bytes" "context" "encoding" stdjson "encoding/json" "errors" "fmt" "io" "log" "math" "math/big" "reflect" "regexp" "strconv" "strings" "testing" "time" "github.com/goccy/go-json" ) type recursiveT struct { A *recursiveT `json:"a,omitempty"` B *recursiveU `json:"b,omitempty"` C *recursiveU `json:"c,omitempty"` D string `json:"d,omitempty"` } type recursiveU struct { T *recursiveT `json:"t,omitempty"` } func Test_Marshal(t *testing.T) { t.Run("int", func(t *testing.T) { bytes, err := json.Marshal(-10) assertErr(t, err) assertEq(t, "int", `-10`, string(bytes)) }) t.Run("int8", func(t *testing.T) { bytes, err := json.Marshal(int8(-11)) assertErr(t, err) assertEq(t, "int8", `-11`, string(bytes)) }) t.Run("int16", func(t *testing.T) { bytes, err := json.Marshal(int16(-12)) assertErr(t, err) assertEq(t, "int16", `-12`, string(bytes)) }) t.Run("int32", func(t *testing.T) { bytes, err := json.Marshal(int32(-13)) assertErr(t, err) assertEq(t, "int32", `-13`, string(bytes)) }) t.Run("int64", func(t *testing.T) { bytes, err := json.Marshal(int64(-14)) assertErr(t, err) assertEq(t, "int64", `-14`, string(bytes)) }) t.Run("uint", func(t *testing.T) { bytes, err := json.Marshal(uint(10)) assertErr(t, err) assertEq(t, "uint", `10`, string(bytes)) }) t.Run("uint8", func(t *testing.T) { bytes, err := json.Marshal(uint8(11)) assertErr(t, err) assertEq(t, "uint8", `11`, string(bytes)) }) t.Run("uint16", func(t *testing.T) { bytes, err := json.Marshal(uint16(12)) assertErr(t, err) assertEq(t, "uint16", `12`, string(bytes)) }) t.Run("uint32", func(t *testing.T) { bytes, err := json.Marshal(uint32(13)) assertErr(t, err) assertEq(t, "uint32", `13`, string(bytes)) }) t.Run("uint64", func(t *testing.T) { bytes, err := json.Marshal(uint64(14)) assertErr(t, err) assertEq(t, "uint64", `14`, string(bytes)) }) t.Run("float32", func(t *testing.T) { bytes, err := json.Marshal(float32(3.14)) assertErr(t, err) assertEq(t, "float32", `3.14`, string(bytes)) }) t.Run("float64", func(t *testing.T) { bytes, err := json.Marshal(float64(3.14)) assertErr(t, err) assertEq(t, "float64", `3.14`, string(bytes)) }) t.Run("bool", func(t *testing.T) { bytes, err := json.Marshal(true) assertErr(t, err) assertEq(t, "bool", `true`, string(bytes)) }) t.Run("string", func(t *testing.T) { bytes, err := json.Marshal("hello world") assertErr(t, err) assertEq(t, "string", `"hello world"`, string(bytes)) }) t.Run("struct", func(t *testing.T) { bytes, err := json.Marshal(struct { A int `json:"a"` B uint `json:"b"` C string `json:"c"` D int `json:"-"` // ignore field a int `json:"aa"` // private field }{ A: -1, B: 1, C: "hello world", }) assertErr(t, err) assertEq(t, "struct", `{"a":-1,"b":1,"c":"hello world"}`, string(bytes)) t.Run("null", func(t *testing.T) { type T struct { A *struct{} `json:"a"` } var v T bytes, err := json.Marshal(&v) assertErr(t, err) assertEq(t, "struct", `{"a":null}`, string(bytes)) }) t.Run("recursive", func(t *testing.T) { bytes, err := json.Marshal(recursiveT{ A: &recursiveT{ B: &recursiveU{ T: &recursiveT{ D: "hello", }, }, C: &recursiveU{ T: &recursiveT{ D: "world", }, }, }, }) assertErr(t, err) assertEq(t, "recursive", `{"a":{"b":{"t":{"d":"hello"}},"c":{"t":{"d":"world"}}}}`, string(bytes)) }) t.Run("embedded", func(t *testing.T) { type T struct { A string `json:"a"` } type U struct { *T B string `json:"b"` } type T2 struct { A string `json:"a,omitempty"` } type U2 struct { *T2 B string `json:"b,omitempty"` } t.Run("exists field", func(t *testing.T) { bytes, err := json.Marshal(&U{ T: &T{ A: "aaa", }, B: "bbb", }) assertErr(t, err) assertEq(t, "embedded", `{"a":"aaa","b":"bbb"}`, string(bytes)) t.Run("omitempty", func(t *testing.T) { bytes, err := json.Marshal(&U2{ T2: &T2{ A: "aaa", }, B: "bbb", }) assertErr(t, err) assertEq(t, "embedded", `{"a":"aaa","b":"bbb"}`, string(bytes)) }) }) t.Run("none field", func(t *testing.T) { bytes, err := json.Marshal(&U{ B: "bbb", }) assertErr(t, err) assertEq(t, "embedded", `{"b":"bbb"}`, string(bytes)) t.Run("omitempty", func(t *testing.T) { bytes, err := json.Marshal(&U2{ B: "bbb", }) assertErr(t, err) assertEq(t, "embedded", `{"b":"bbb"}`, string(bytes)) }) }) }) t.Run("embedded with tag", func(t *testing.T) { type T struct { A string `json:"a"` } type U struct { *T `json:"t"` B string `json:"b"` } type T2 struct { A string `json:"a,omitempty"` } type U2 struct { *T2 `json:"t,omitempty"` B string `json:"b,omitempty"` } t.Run("exists field", func(t *testing.T) { bytes, err := json.Marshal(&U{ T: &T{ A: "aaa", }, B: "bbb", }) assertErr(t, err) assertEq(t, "embedded", `{"t":{"a":"aaa"},"b":"bbb"}`, string(bytes)) t.Run("omitempty", func(t *testing.T) { bytes, err := json.Marshal(&U2{ T2: &T2{ A: "aaa", }, B: "bbb", }) assertErr(t, err) assertEq(t, "embedded", `{"t":{"a":"aaa"},"b":"bbb"}`, string(bytes)) }) }) t.Run("none field", func(t *testing.T) { bytes, err := json.Marshal(&U{ B: "bbb", }) assertErr(t, err) assertEq(t, "embedded", `{"t":null,"b":"bbb"}`, string(bytes)) t.Run("omitempty", func(t *testing.T) { bytes, err := json.Marshal(&U2{ B: "bbb", }) assertErr(t, err) assertEq(t, "embedded", `{"b":"bbb"}`, string(bytes)) }) }) }) t.Run("omitempty", func(t *testing.T) { type T struct { A int `json:",omitempty"` B int8 `json:",omitempty"` C int16 `json:",omitempty"` D int32 `json:",omitempty"` E int64 `json:",omitempty"` F uint `json:",omitempty"` G uint8 `json:",omitempty"` H uint16 `json:",omitempty"` I uint32 `json:",omitempty"` J uint64 `json:",omitempty"` K float32 `json:",omitempty"` L float64 `json:",omitempty"` O string `json:",omitempty"` P bool `json:",omitempty"` Q []int `json:",omitempty"` R map[string]interface{} `json:",omitempty"` S *struct{} `json:",omitempty"` T int `json:"t,omitempty"` } var v T v.T = 1 bytes, err := json.Marshal(&v) assertErr(t, err) assertEq(t, "struct", `{"t":1}`, string(bytes)) t.Run("int", func(t *testing.T) { var v struct { A int `json:"a,omitempty"` B int `json:"b"` } v.B = 1 bytes, err := json.Marshal(&v) assertErr(t, err) assertEq(t, "int", `{"b":1}`, string(bytes)) }) t.Run("int8", func(t *testing.T) { var v struct { A int `json:"a,omitempty"` B int8 `json:"b"` } v.B = 1 bytes, err := json.Marshal(&v) assertErr(t, err) assertEq(t, "int8", `{"b":1}`, string(bytes)) }) t.Run("int16", func(t *testing.T) { var v struct { A int `json:"a,omitempty"` B int16 `json:"b"` } v.B = 1 bytes, err := json.Marshal(&v) assertErr(t, err) assertEq(t, "int16", `{"b":1}`, string(bytes)) }) t.Run("int32", func(t *testing.T) { var v struct { A int `json:"a,omitempty"` B int32 `json:"b"` } v.B = 1 bytes, err := json.Marshal(&v) assertErr(t, err) assertEq(t, "int32", `{"b":1}`, string(bytes)) }) t.Run("int64", func(t *testing.T) { var v struct { A int `json:"a,omitempty"` B int64 `json:"b"` } v.B = 1 bytes, err := json.Marshal(&v) assertErr(t, err) assertEq(t, "int64", `{"b":1}`, string(bytes)) }) t.Run("string", func(t *testing.T) { var v struct { A int `json:"a,omitempty"` B string `json:"b"` } v.B = "b" bytes, err := json.Marshal(&v) assertErr(t, err) assertEq(t, "string", `{"b":"b"}`, string(bytes)) }) t.Run("float32", func(t *testing.T) { var v struct { A int `json:"a,omitempty"` B float32 `json:"b"` } v.B = 1.1 bytes, err := json.Marshal(&v) assertErr(t, err) assertEq(t, "float32", `{"b":1.1}`, string(bytes)) }) t.Run("float64", func(t *testing.T) { var v struct { A int `json:"a,omitempty"` B float64 `json:"b"` } v.B = 3.14 bytes, err := json.Marshal(&v) assertErr(t, err) assertEq(t, "float64", `{"b":3.14}`, string(bytes)) }) t.Run("slice", func(t *testing.T) { var v struct { A int `json:"a,omitempty"` B []int `json:"b"` } v.B = []int{1, 2, 3} bytes, err := json.Marshal(&v) assertErr(t, err) assertEq(t, "slice", `{"b":[1,2,3]}`, string(bytes)) }) t.Run("array", func(t *testing.T) { var v struct { A int `json:"a,omitempty"` B [2]int `json:"b"` } v.B = [2]int{1, 2} bytes, err := json.Marshal(&v) assertErr(t, err) assertEq(t, "array", `{"b":[1,2]}`, string(bytes)) }) t.Run("map", func(t *testing.T) { v := new(struct { A int `json:"a,omitempty"` B map[string]interface{} `json:"b"` }) v.B = map[string]interface{}{"c": 1} bytes, err := json.Marshal(v) assertErr(t, err) assertEq(t, "array", `{"b":{"c":1}}`, string(bytes)) }) }) t.Run("head_omitempty", func(t *testing.T) { type T struct { A *struct{} `json:"a,omitempty"` } var v T bytes, err := json.Marshal(&v) assertErr(t, err) assertEq(t, "struct", `{}`, string(bytes)) }) t.Run("pointer_head_omitempty", func(t *testing.T) { type V struct{} type U struct { B *V `json:"b,omitempty"` } type T struct { A *U `json:"a"` } bytes, err := json.Marshal(&T{A: &U{}}) assertErr(t, err) assertEq(t, "struct", `{"a":{}}`, string(bytes)) }) t.Run("head_int_omitempty", func(t *testing.T) { type T struct { A int `json:"a,omitempty"` } var v T bytes, err := json.Marshal(&v) assertErr(t, err) assertEq(t, "struct", `{}`, string(bytes)) }) }) t.Run("slice", func(t *testing.T) { t.Run("[]int", func(t *testing.T) { bytes, err := json.Marshal([]int{1, 2, 3, 4}) assertErr(t, err) assertEq(t, "[]int", `[1,2,3,4]`, string(bytes)) }) t.Run("[]interface{}", func(t *testing.T) { bytes, err := json.Marshal([]interface{}{1, 2.1, "hello"}) assertErr(t, err) assertEq(t, "[]interface{}", `[1,2.1,"hello"]`, string(bytes)) }) }) t.Run("array", func(t *testing.T) { bytes, err := json.Marshal([4]int{1, 2, 3, 4}) assertErr(t, err) assertEq(t, "array", `[1,2,3,4]`, string(bytes)) }) t.Run("map", func(t *testing.T) { t.Run("map[string]int", func(t *testing.T) { v := map[string]int{ "a": 1, "b": 2, "c": 3, "d": 4, } bytes, err := json.Marshal(v) assertErr(t, err) assertEq(t, "map", `{"a":1,"b":2,"c":3,"d":4}`, string(bytes)) b, err := json.MarshalWithOption(v, json.UnorderedMap()) assertErr(t, err) assertEq(t, "unordered map", len(`{"a":1,"b":2,"c":3,"d":4}`), len(string(b))) }) t.Run("map[string]interface{}", func(t *testing.T) { type T struct { A int } v := map[string]interface{}{ "a": 1, "b": 2.1, "c": &T{ A: 10, }, "d": 4, } bytes, err := json.Marshal(v) assertErr(t, err) assertEq(t, "map[string]interface{}", `{"a":1,"b":2.1,"c":{"A":10},"d":4}`, string(bytes)) }) }) } type mustErrTypeForDebug struct{} func (mustErrTypeForDebug) MarshalJSON() ([]byte, error) { panic("panic") return nil, fmt.Errorf("panic") } func TestDebugMode(t *testing.T) { defer func() { if err := recover(); err == nil { t.Fatal("expected error") } }() var buf bytes.Buffer json.MarshalWithOption(mustErrTypeForDebug{}, json.Debug(), json.DebugWith(&buf)) } func TestIssue116(t *testing.T) { t.Run("first", func(t *testing.T) { type Boo struct{ B string } type Struct struct { A int Boo *Boo } type Embedded struct { Struct } b, err := json.Marshal(Embedded{Struct: Struct{ A: 1, Boo: &Boo{B: "foo"}, }}) if err != nil { t.Fatal(err) } expected := `{"A":1,"Boo":{"B":"foo"}}` actual := string(b) if actual != expected { t.Fatalf("expected %s but got %s", expected, actual) } }) t.Run("second", func(t *testing.T) { type Boo struct{ B string } type Struct struct { A int B *Boo } type Embedded struct { Struct } b, err := json.Marshal(Embedded{Struct: Struct{ A: 1, B: &Boo{B: "foo"}, }}) if err != nil { t.Fatal(err) } actual := string(b) expected := `{"A":1,"B":{"B":"foo"}}` if actual != expected { t.Fatalf("expected %s but got %s", expected, actual) } }) } type marshalJSON struct{} func (*marshalJSON) MarshalJSON() ([]byte, error) { return []byte(`1`), nil } func Test_MarshalJSON(t *testing.T) { t.Run("*struct", func(t *testing.T) { bytes, err := json.Marshal(&marshalJSON{}) assertErr(t, err) assertEq(t, "MarshalJSON", "1", string(bytes)) }) t.Run("time", func(t *testing.T) { bytes, err := json.Marshal(time.Time{}) assertErr(t, err) assertEq(t, "MarshalJSON", `"0001-01-01T00:00:00Z"`, string(bytes)) }) } func Test_MarshalIndent(t *testing.T) { prefix := "-" indent := "\t" t.Run("struct", func(t *testing.T) { v := struct { A int `json:"a"` B uint `json:"b"` C string `json:"c"` D interface{} `json:"d"` X int `json:"-"` // ignore field a int `json:"aa"` // private field }{ A: -1, B: 1, C: "hello world", D: struct { E bool `json:"e"` }{ E: true, }, } expected, err := stdjson.MarshalIndent(v, prefix, indent) assertErr(t, err) got, err := json.MarshalIndent(v, prefix, indent) assertErr(t, err) assertEq(t, "struct", string(expected), string(got)) }) t.Run("slice", func(t *testing.T) { t.Run("[]int", func(t *testing.T) { bytes, err := json.MarshalIndent([]int{1, 2, 3, 4}, prefix, indent) assertErr(t, err) result := "[\n-\t1,\n-\t2,\n-\t3,\n-\t4\n-]" assertEq(t, "[]int", result, string(bytes)) }) t.Run("[]interface{}", func(t *testing.T) { bytes, err := json.MarshalIndent([]interface{}{1, 2.1, "hello"}, prefix, indent) assertErr(t, err) result := "[\n-\t1,\n-\t2.1,\n-\t\"hello\"\n-]" assertEq(t, "[]interface{}", result, string(bytes)) }) }) t.Run("array", func(t *testing.T) { bytes, err := json.MarshalIndent([4]int{1, 2, 3, 4}, prefix, indent) assertErr(t, err) result := "[\n-\t1,\n-\t2,\n-\t3,\n-\t4\n-]" assertEq(t, "array", result, string(bytes)) }) t.Run("map", func(t *testing.T) { t.Run("map[string]int", func(t *testing.T) { bytes, err := json.MarshalIndent(map[string]int{ "a": 1, "b": 2, "c": 3, "d": 4, }, prefix, indent) assertErr(t, err) result := "{\n-\t\"a\": 1,\n-\t\"b\": 2,\n-\t\"c\": 3,\n-\t\"d\": 4\n-}" assertEq(t, "map", result, string(bytes)) }) t.Run("map[string]interface{}", func(t *testing.T) { type T struct { E int F int } v := map[string]interface{}{ "a": 1, "b": 2.1, "c": &T{ E: 10, F: 11, }, "d": 4, } bytes, err := json.MarshalIndent(v, prefix, indent) assertErr(t, err) result := "{\n-\t\"a\": 1,\n-\t\"b\": 2.1,\n-\t\"c\": {\n-\t\t\"E\": 10,\n-\t\t\"F\": 11\n-\t},\n-\t\"d\": 4\n-}" assertEq(t, "map[string]interface{}", result, string(bytes)) }) }) } type StringTag struct { BoolStr bool `json:",string"` IntStr int64 `json:",string"` UintptrStr uintptr `json:",string"` StrStr string `json:",string"` NumberStr json.Number `json:",string"` } func TestRoundtripStringTag(t *testing.T) { tests := []struct { name string in StringTag want string // empty to just test that we roundtrip }{ { name: "AllTypes", in: StringTag{ BoolStr: true, IntStr: 42, UintptrStr: 44, StrStr: "xzbit", NumberStr: "46", }, want: `{ "BoolStr": "true", "IntStr": "42", "UintptrStr": "44", "StrStr": "\"xzbit\"", "NumberStr": "46" }`, }, { // See golang.org/issues/38173. name: "StringDoubleEscapes", in: StringTag{ StrStr: "\b\f\n\r\t\"\\", NumberStr: "0", // just to satisfy the roundtrip }, want: `{ "BoolStr": "false", "IntStr": "0", "UintptrStr": "0", "StrStr": "\"\\u0008\\u000c\\n\\r\\t\\\"\\\\\"", "NumberStr": "0" }`, }, } for _, test := range tests { t.Run(test.name, func(t *testing.T) { // Indent with a tab prefix to make the multi-line string // literals in the table nicer to read. got, err := json.MarshalIndent(&test.in, "\t\t\t", "\t") if err != nil { t.Fatal(err) } if got := string(got); got != test.want { t.Fatalf(" got: %s\nwant: %s\n", got, test.want) } // Verify that it round-trips. var s2 StringTag if err := json.Unmarshal(got, &s2); err != nil { t.Fatalf("Decode: %v", err) } if !reflect.DeepEqual(test.in, s2) { t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", test.in, string(got), s2) } }) } } // byte slices are special even if they're renamed types. type renamedByte byte type renamedByteSlice []byte type renamedRenamedByteSlice []renamedByte func TestEncodeRenamedByteSlice(t *testing.T) { s := renamedByteSlice("abc") result, err := json.Marshal(s) if err != nil { t.Fatal(err) } expect := `"YWJj"` if string(result) != expect { t.Errorf(" got %s want %s", result, expect) } r := renamedRenamedByteSlice("abc") result, err = json.Marshal(r) if err != nil { t.Fatal(err) } if string(result) != expect { t.Errorf(" got %s want %s", result, expect) } } func TestMarshalRawMessageValue(t *testing.T) { type ( T1 struct { M json.RawMessage `json:",omitempty"` } T2 struct { M *json.RawMessage `json:",omitempty"` } ) var ( rawNil = json.RawMessage(nil) rawEmpty = json.RawMessage([]byte{}) rawText = json.RawMessage([]byte(`"foo"`)) ) tests := []struct { in interface{} want string ok bool }{ // Test with nil RawMessage. {rawNil, "null", true}, {&rawNil, "null", true}, {[]interface{}{rawNil}, "[null]", true}, {&[]interface{}{rawNil}, "[null]", true}, {[]interface{}{&rawNil}, "[null]", true}, {&[]interface{}{&rawNil}, "[null]", true}, {struct{ M json.RawMessage }{rawNil}, `{"M":null}`, true}, {&struct{ M json.RawMessage }{rawNil}, `{"M":null}`, true}, {struct{ M *json.RawMessage }{&rawNil}, `{"M":null}`, true}, {&struct{ M *json.RawMessage }{&rawNil}, `{"M":null}`, true}, {map[string]interface{}{"M": rawNil}, `{"M":null}`, true}, {&map[string]interface{}{"M": rawNil}, `{"M":null}`, true}, {map[string]interface{}{"M": &rawNil}, `{"M":null}`, true}, {&map[string]interface{}{"M": &rawNil}, `{"M":null}`, true}, {T1{rawNil}, "{}", true}, {T2{&rawNil}, `{"M":null}`, true}, {&T1{rawNil}, "{}", true}, {&T2{&rawNil}, `{"M":null}`, true}, // Test with empty, but non-nil, RawMessage. {rawEmpty, "", false}, {&rawEmpty, "", false}, {[]interface{}{rawEmpty}, "", false}, {&[]interface{}{rawEmpty}, "", false}, {[]interface{}{&rawEmpty}, "", false}, {&[]interface{}{&rawEmpty}, "", false}, {struct{ X json.RawMessage }{rawEmpty}, "", false}, {&struct{ X json.RawMessage }{rawEmpty}, "", false}, {struct{ X *json.RawMessage }{&rawEmpty}, "", false}, {&struct{ X *json.RawMessage }{&rawEmpty}, "", false}, {map[string]interface{}{"nil": rawEmpty}, "", false}, {&map[string]interface{}{"nil": rawEmpty}, "", false}, {map[string]interface{}{"nil": &rawEmpty}, "", false}, {&map[string]interface{}{"nil": &rawEmpty}, "", false}, {T1{rawEmpty}, "{}", true}, {T2{&rawEmpty}, "", false}, {&T1{rawEmpty}, "{}", true}, {&T2{&rawEmpty}, "", false}, // Test with RawMessage with some text. // // The tests below marked with Issue6458 used to generate "ImZvbyI=" instead "foo". // This behavior was intentionally changed in Go 1.8. // See https://golang.org/issues/14493#issuecomment-255857318 {rawText, `"foo"`, true}, // Issue6458 {&rawText, `"foo"`, true}, {[]interface{}{rawText}, `["foo"]`, true}, // Issue6458 {&[]interface{}{rawText}, `["foo"]`, true}, // Issue6458 {[]interface{}{&rawText}, `["foo"]`, true}, {&[]interface{}{&rawText}, `["foo"]`, true}, {struct{ M json.RawMessage }{rawText}, `{"M":"foo"}`, true}, // Issue6458 {&struct{ M json.RawMessage }{rawText}, `{"M":"foo"}`, true}, {struct{ M *json.RawMessage }{&rawText}, `{"M":"foo"}`, true}, {&struct{ M *json.RawMessage }{&rawText}, `{"M":"foo"}`, true}, {map[string]interface{}{"M": rawText}, `{"M":"foo"}`, true}, // Issue6458 {&map[string]interface{}{"M": rawText}, `{"M":"foo"}`, true}, // Issue6458 {map[string]interface{}{"M": &rawText}, `{"M":"foo"}`, true}, {&map[string]interface{}{"M": &rawText}, `{"M":"foo"}`, true}, {T1{rawText}, `{"M":"foo"}`, true}, // Issue6458 {T2{&rawText}, `{"M":"foo"}`, true}, {&T1{rawText}, `{"M":"foo"}`, true}, {&T2{&rawText}, `{"M":"foo"}`, true}, } for i, tt := range tests { b, err := json.Marshal(tt.in) if ok := (err == nil); ok != tt.ok { if err != nil { t.Errorf("test %d, unexpected failure: %v", i, err) } else { t.Errorf("test %d, unexpected success", i) } } if got := string(b); got != tt.want { t.Errorf("test %d, Marshal(%#v) = %q, want %q", i, tt.in, got, tt.want) } } } type marshalerError struct{} func (*marshalerError) MarshalJSON() ([]byte, error) { return nil, errors.New("unexpected error") } func Test_MarshalerError(t *testing.T) { var v marshalerError _, err := json.Marshal(&v) expect := `json: error calling MarshalJSON for type *json_test.marshalerError: unexpected error` assertEq(t, "marshaler error", expect, fmt.Sprint(err)) } // Ref has Marshaler and Unmarshaler methods with pointer receiver. type Ref int func (*Ref) MarshalJSON() ([]byte, error) { return []byte(`"ref"`), nil } func (r *Ref) UnmarshalJSON([]byte) error { *r = 12 return nil } // Val has Marshaler methods with value receiver. type Val int func (Val) MarshalJSON() ([]byte, error) { return []byte(`"val"`), nil } // RefText has Marshaler and Unmarshaler methods with pointer receiver. type RefText int func (*RefText) MarshalText() ([]byte, error) { return []byte(`"ref"`), nil } func (r *RefText) UnmarshalText([]byte) error { *r = 13 return nil } // ValText has Marshaler methods with value receiver. type ValText int func (ValText) MarshalText() ([]byte, error) { return []byte(`"val"`), nil } func TestRefValMarshal(t *testing.T) { var s = struct { R0 Ref R1 *Ref R2 RefText R3 *RefText V0 Val V1 *Val V2 ValText V3 *ValText }{ R0: 12, R1: new(Ref), R2: 14, R3: new(RefText), V0: 13, V1: new(Val), V2: 15, V3: new(ValText), } const want = `{"R0":"ref","R1":"ref","R2":"\"ref\"","R3":"\"ref\"","V0":"val","V1":"val","V2":"\"val\"","V3":"\"val\""}` b, err := json.Marshal(&s) if err != nil { t.Fatalf("Marshal: %v", err) } if got := string(b); got != want { t.Errorf("got %q, want %q", got, want) } } // C implements Marshaler and returns unescaped JSON. type C int func (C) MarshalJSON() ([]byte, error) { return []byte(`"<&>"`), nil } // CText implements Marshaler and returns unescaped text. type CText int func (CText) MarshalText() ([]byte, error) { return []byte(`"<&>"`), nil } func TestMarshalerEscaping(t *testing.T) { var c C want := `"\u003c\u0026\u003e"` b, err := json.Marshal(c) if err != nil { t.Fatalf("Marshal(c): %v", err) } if got := string(b); got != want { t.Errorf("Marshal(c) = %#q, want %#q", got, want) } var ct CText want = `"\"\u003c\u0026\u003e\""` b, err = json.Marshal(ct) if err != nil { t.Fatalf("Marshal(ct): %v", err) } if got := string(b); got != want { t.Errorf("Marshal(ct) = %#q, want %#q", got, want) } } type marshalPanic struct{} func (marshalPanic) MarshalJSON() ([]byte, error) { panic(0xdead) } func TestMarshalPanic(t *testing.T) { defer func() { if got := recover(); !reflect.DeepEqual(got, 0xdead) { t.Errorf("panic() = (%T)(%v), want 0xdead", got, got) } }() json.Marshal(&marshalPanic{}) t.Error("Marshal should have panicked") } func TestMarshalUncommonFieldNames(t *testing.T) { v := struct { A0, À, Aβ int }{} b, err := json.Marshal(v) if err != nil { t.Fatal("Marshal:", err) } want := `{"A0":0,"À":0,"Aβ":0}` got := string(b) if got != want { t.Fatalf("Marshal: got %s want %s", got, want) } } func TestMarshalerError(t *testing.T) { s := "test variable" st := reflect.TypeOf(s) errText := "json: test error" tests := []struct { err *json.MarshalerError want string }{ { json.NewMarshalerError(st, fmt.Errorf(errText), ""), "json: error calling MarshalJSON for type " + st.String() + ": " + errText, }, { json.NewMarshalerError(st, fmt.Errorf(errText), "TestMarshalerError"), "json: error calling TestMarshalerError for type " + st.String() + ": " + errText, }, } for i, tt := range tests { got := tt.err.Error() if got != tt.want { t.Errorf("MarshalerError test %d, got: %s, want: %s", i, got, tt.want) } } } 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 } func TestTextMarshalerMapKeysAreSorted(t *testing.T) { data := map[unmarshalerText]int{ {"x", "y"}: 1, {"y", "x"}: 2, {"a", "z"}: 3, {"z", "a"}: 4, } b, err := json.Marshal(data) if err != nil { t.Fatalf("Failed to Marshal text.Marshaler: %v", err) } const want = `{"a:z":3,"x:y":1,"y:x":2,"z:a":4}` if string(b) != want { t.Errorf("Marshal map with text.Marshaler keys: got %#q, want %#q", b, want) } b, err = stdjson.Marshal(data) if err != nil { t.Fatalf("Failed to std Marshal text.Marshaler: %v", err) } if string(b) != want { t.Errorf("std Marshal map with text.Marshaler keys: got %#q, want %#q", b, want) } } // https://golang.org/issue/33675 func TestNilMarshalerTextMapKey(t *testing.T) { v := map[*unmarshalerText]int{ (*unmarshalerText)(nil): 1, {"A", "B"}: 2, } b, err := json.Marshal(v) if err != nil { t.Fatalf("Failed to Marshal *text.Marshaler: %v", err) } const want = `{"":1,"A:B":2}` if string(b) != want { t.Errorf("Marshal map with *text.Marshaler keys: got %#q, want %#q", b, want) } } var re = regexp.MustCompile // syntactic checks on form of marshaled floating point numbers. var badFloatREs = []*regexp.Regexp{ re(`p`), // no binary exponential notation re(`^\+`), // no leading + sign re(`^-?0[^.]`), // no unnecessary leading zeros re(`^-?\.`), // leading zero required before decimal point re(`\.(e|$)`), // no trailing decimal re(`\.[0-9]+0(e|$)`), // no trailing zero in fraction re(`^-?(0|[0-9]{2,})\..*e`), // exponential notation must have normalized mantissa re(`e[0-9]`), // positive exponent must be signed //re(`e[+-]0`), // exponent must not have leading zeros re(`e-[1-6]$`), // not tiny enough for exponential notation re(`e+(.|1.|20)$`), // not big enough for exponential notation re(`^-?0\.0000000`), // too tiny, should use exponential notation re(`^-?[0-9]{22}`), // too big, should use exponential notation re(`[1-9][0-9]{16}[1-9]`), // too many significant digits in integer re(`[1-9][0-9.]{17}[1-9]`), // too many significant digits in decimal // below here for float32 only re(`[1-9][0-9]{8}[1-9]`), // too many significant digits in integer re(`[1-9][0-9.]{9}[1-9]`), // too many significant digits in decimal } func TestMarshalFloat(t *testing.T) { //t.Parallel() nfail := 0 test := func(f float64, bits int) { vf := interface{}(f) if bits == 32 { f = float64(float32(f)) // round vf = float32(f) } bout, err := json.Marshal(vf) if err != nil { t.Errorf("Marshal(%T(%g)): %v", vf, vf, err) nfail++ return } out := string(bout) // result must convert back to the same float g, err := strconv.ParseFloat(out, bits) if err != nil { t.Errorf("Marshal(%T(%g)) = %q, cannot parse back: %v", vf, vf, out, err) nfail++ return } if f != g || fmt.Sprint(f) != fmt.Sprint(g) { // fmt.Sprint handles ±0 t.Errorf("Marshal(%T(%g)) = %q (is %g, not %g)", vf, vf, out, float32(g), vf) nfail++ return } bad := badFloatREs if bits == 64 { bad = bad[:len(bad)-2] } for _, re := range bad { if re.MatchString(out) { t.Errorf("Marshal(%T(%g)) = %q, must not match /%s/", vf, vf, out, re) nfail++ return } } } var ( bigger = math.Inf(+1) smaller = math.Inf(-1) ) var digits = "1.2345678901234567890123" for i := len(digits); i >= 2; i-- { if testing.Short() && i < len(digits)-4 { break } for exp := -30; exp <= 30; exp++ { for _, sign := range "+-" { for bits := 32; bits <= 64; bits += 32 { s := fmt.Sprintf("%c%se%d", sign, digits[:i], exp) f, err := strconv.ParseFloat(s, bits) if err != nil { log.Fatal(err) } next := math.Nextafter if bits == 32 { next = func(g, h float64) float64 { return float64(math.Nextafter32(float32(g), float32(h))) } } test(f, bits) test(next(f, bigger), bits) test(next(f, smaller), bits) if nfail > 50 { t.Fatalf("stopping test early") } } } } } test(0, 64) test(math.Copysign(0, -1), 64) test(0, 32) test(math.Copysign(0, -1), 32) } var encodeStringTests = []struct { in string out string }{ {"\x00", `"\u0000"`}, {"\x01", `"\u0001"`}, {"\x02", `"\u0002"`}, {"\x03", `"\u0003"`}, {"\x04", `"\u0004"`}, {"\x05", `"\u0005"`}, {"\x06", `"\u0006"`}, {"\x07", `"\u0007"`}, {"\x08", `"\u0008"`}, {"\x09", `"\t"`}, {"\x0a", `"\n"`}, {"\x0b", `"\u000b"`}, {"\x0c", `"\u000c"`}, {"\x0d", `"\r"`}, {"\x0e", `"\u000e"`}, {"\x0f", `"\u000f"`}, {"\x10", `"\u0010"`}, {"\x11", `"\u0011"`}, {"\x12", `"\u0012"`}, {"\x13", `"\u0013"`}, {"\x14", `"\u0014"`}, {"\x15", `"\u0015"`}, {"\x16", `"\u0016"`}, {"\x17", `"\u0017"`}, {"\x18", `"\u0018"`}, {"\x19", `"\u0019"`}, {"\x1a", `"\u001a"`}, {"\x1b", `"\u001b"`}, {"\x1c", `"\u001c"`}, {"\x1d", `"\u001d"`}, {"\x1e", `"\u001e"`}, {"\x1f", `"\u001f"`}, } func TestEncodeString(t *testing.T) { for _, tt := range encodeStringTests { b, err := json.Marshal(tt.in) if err != nil { t.Errorf("Marshal(%q): %v", tt.in, err) continue } out := string(b) if out != tt.out { t.Errorf("Marshal(%q) = %#q, want %#q", tt.in, out, tt.out) } } } type jsonbyte byte func (b jsonbyte) MarshalJSON() ([]byte, error) { return tenc(`{"JB":%d}`, b) } type textbyte byte func (b textbyte) MarshalText() ([]byte, error) { return tenc(`TB:%d`, b) } type jsonint int func (i jsonint) MarshalJSON() ([]byte, error) { return tenc(`{"JI":%d}`, i) } type textint int func (i textint) MarshalText() ([]byte, error) { return tenc(`TI:%d`, i) } func tenc(format string, a ...interface{}) ([]byte, error) { var buf bytes.Buffer fmt.Fprintf(&buf, format, a...) return buf.Bytes(), nil } // Issue 13783 func TestEncodeBytekind(t *testing.T) { testdata := []struct { data interface{} want string }{ {byte(7), "7"}, {jsonbyte(7), `{"JB":7}`}, {textbyte(4), `"TB:4"`}, {jsonint(5), `{"JI":5}`}, {textint(1), `"TI:1"`}, {[]byte{0, 1}, `"AAE="`}, {[]jsonbyte{0, 1}, `[{"JB":0},{"JB":1}]`}, {[][]jsonbyte{{0, 1}, {3}}, `[[{"JB":0},{"JB":1}],[{"JB":3}]]`}, {[]textbyte{2, 3}, `["TB:2","TB:3"]`}, {[]jsonint{5, 4}, `[{"JI":5},{"JI":4}]`}, {[]textint{9, 3}, `["TI:9","TI:3"]`}, {[]int{9, 3}, `[9,3]`}, } for i, d := range testdata { js, err := json.Marshal(d.data) if err != nil { t.Error(err) continue } got, want := string(js), d.want if got != want { t.Errorf("%d: got %s, want %s", i, got, want) } } } // golang.org/issue/8582 func TestEncodePointerString(t *testing.T) { type stringPointer struct { N *int64 `json:"n,string"` } var n int64 = 42 b, err := json.Marshal(stringPointer{N: &n}) if err != nil { t.Fatalf("Marshal: %v", err) } if got, want := string(b), `{"n":"42"}`; got != want { t.Errorf("Marshal = %s, want %s", got, want) } var back stringPointer err = json.Unmarshal(b, &back) if err != nil { t.Fatalf("Unmarshal: %v", err) } if back.N == nil { t.Fatalf("Unmarshaled nil N field") } if *back.N != 42 { t.Fatalf("*N = %d; want 42", *back.N) } } type SamePointerNoCycle struct { Ptr1, Ptr2 *SamePointerNoCycle } var samePointerNoCycle = &SamePointerNoCycle{} type PointerCycle struct { Ptr *PointerCycle } var pointerCycle = &PointerCycle{} type PointerCycleIndirect struct { Ptrs []interface{} } var pointerCycleIndirect = &PointerCycleIndirect{} func init() { ptr := &SamePointerNoCycle{} samePointerNoCycle.Ptr1 = ptr samePointerNoCycle.Ptr2 = ptr pointerCycle.Ptr = pointerCycle pointerCycleIndirect.Ptrs = []interface{}{pointerCycleIndirect} } func TestSamePointerNoCycle(t *testing.T) { if _, err := json.Marshal(samePointerNoCycle); err != nil { t.Fatalf("unexpected error: %v", err) } } var unsupportedValues = []interface{}{ math.NaN(), math.Inf(-1), math.Inf(1), pointerCycle, pointerCycleIndirect, } func TestUnsupportedValues(t *testing.T) { for _, v := range unsupportedValues { if _, err := json.Marshal(v); err != nil { if _, ok := err.(*json.UnsupportedValueError); !ok { t.Errorf("for %v, got %T want UnsupportedValueError", v, err) } } else { t.Errorf("for %v, expected error", v) } } } func TestIssue10281(t *testing.T) { type Foo struct { N json.Number } x := Foo{json.Number(`invalid`)} b, err := json.Marshal(&x) if err == nil { t.Errorf("Marshal(&x) = %#q; want error", b) } } func TestHTMLEscape(t *testing.T) { var b, want bytes.Buffer m := `{"M":"foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `"}` want.Write([]byte(`{"M":"\u003chtml\u003efoo \u0026\u2028 \u2029\u003c/html\u003e"}`)) json.HTMLEscape(&b, []byte(m)) if !bytes.Equal(b.Bytes(), want.Bytes()) { t.Errorf("HTMLEscape(&b, []byte(m)) = %s; want %s", b.Bytes(), want.Bytes()) } } type BugA struct { S string } type BugB struct { BugA S string } type BugC struct { S string } // Legal Go: We never use the repeated embedded field (S). type BugX struct { A int BugA BugB } // golang.org/issue/16042. // Even if a nil interface value is passed in, as long as // it implements Marshaler, it should be marshaled. type nilJSONMarshaler string func (nm *nilJSONMarshaler) MarshalJSON() ([]byte, error) { if nm == nil { return json.Marshal("0zenil0") } return json.Marshal("zenil:" + string(*nm)) } // golang.org/issue/34235. // Even if a nil interface value is passed in, as long as // it implements encoding.TextMarshaler, it should be marshaled. type nilTextMarshaler string func (nm *nilTextMarshaler) MarshalText() ([]byte, error) { if nm == nil { return []byte("0zenil0"), nil } return []byte("zenil:" + string(*nm)), nil } // See golang.org/issue/16042 and golang.org/issue/34235. func TestNilMarshal(t *testing.T) { testCases := []struct { v interface{} want string }{ {v: nil, want: `null`}, {v: new(float64), want: `0`}, {v: []interface{}(nil), want: `null`}, {v: []string(nil), want: `null`}, {v: map[string]string(nil), want: `null`}, {v: []byte(nil), want: `null`}, {v: struct{ M string }{"gopher"}, want: `{"M":"gopher"}`}, {v: struct{ M json.Marshaler }{}, want: `{"M":null}`}, {v: struct{ M json.Marshaler }{(*nilJSONMarshaler)(nil)}, want: `{"M":"0zenil0"}`}, {v: struct{ M interface{} }{(*nilJSONMarshaler)(nil)}, want: `{"M":null}`}, {v: struct{ M encoding.TextMarshaler }{}, want: `{"M":null}`}, {v: struct{ M encoding.TextMarshaler }{(*nilTextMarshaler)(nil)}, want: `{"M":"0zenil0"}`}, {v: struct{ M interface{} }{(*nilTextMarshaler)(nil)}, want: `{"M":null}`}, } for i, tt := range testCases { out, err := json.Marshal(tt.v) if err != nil || string(out) != tt.want { t.Errorf("%d: Marshal(%#v) = %#q, %#v, want %#q, nil", i, tt.v, out, err, tt.want) continue } } } // Issue 5245. func TestEmbeddedBug(t *testing.T) { v := BugB{ BugA{"A"}, "B", } b, err := json.Marshal(v) if err != nil { t.Fatal("Marshal:", err) } want := `{"S":"B"}` got := string(b) if got != want { t.Fatalf("Marshal: got %s want %s", got, want) } // Now check that the duplicate field, S, does not appear. x := BugX{ A: 23, } b, err = json.Marshal(x) if err != nil { t.Fatal("Marshal:", err) } want = `{"A":23}` got = string(b) if got != want { t.Fatalf("Marshal: got %s want %s", got, want) } } type BugD struct { // Same as BugA after tagging. XXX string `json:"S"` } // BugD's tagged S field should dominate BugA's. type BugY struct { BugA BugD } // Test that a field with a tag dominates untagged fields. func TestTaggedFieldDominates(t *testing.T) { v := BugY{ BugA{"BugA"}, BugD{"BugD"}, } b, err := json.Marshal(v) if err != nil { t.Fatal("Marshal:", err) } want := `{"S":"BugD"}` got := string(b) if got != want { t.Fatalf("Marshal: got %s want %s", got, want) } } // There are no tags here, so S should not appear. type BugZ struct { BugA BugC BugY // Contains a tagged S field through BugD; should not dominate. } func TestDuplicatedFieldDisappears(t *testing.T) { v := BugZ{ BugA{"BugA"}, BugC{"BugC"}, BugY{ BugA{"nested BugA"}, BugD{"nested BugD"}, }, } b, err := json.Marshal(v) if err != nil { t.Fatal("Marshal:", err) } want := `{}` got := string(b) if got != want { t.Fatalf("Marshal: got %s want %s", got, want) } } func TestAnonymousFields(t *testing.T) { tests := []struct { label string // Test name makeInput func() interface{} // Function to create input value want string // Expected JSON output }{{ // Both S1 and S2 have a field named X. From the perspective of S, // it is ambiguous which one X refers to. // This should not serialize either field. label: "AmbiguousField", makeInput: func() interface{} { type ( S1 struct{ x, X int } S2 struct{ x, X int } S struct { S1 S2 } ) return S{S1{1, 2}, S2{3, 4}} }, want: `{}`, }, { label: "DominantField", // Both S1 and S2 have a field named X, but since S has an X field as // well, it takes precedence over S1.X and S2.X. makeInput: func() interface{} { type ( S1 struct{ x, X int } S2 struct{ x, X int } S struct { S1 S2 x, X int } ) return S{S1{1, 2}, S2{3, 4}, 5, 6} }, want: `{"X":6}`, }, { // Unexported embedded field of non-struct type should not be serialized. label: "UnexportedEmbeddedInt", makeInput: func() interface{} { type ( myInt int S struct{ myInt } ) return S{5} }, want: `{}`, }, { // Exported embedded field of non-struct type should be serialized. label: "ExportedEmbeddedInt", makeInput: func() interface{} { type ( MyInt int S struct{ MyInt } ) return S{5} }, want: `{"MyInt":5}`, }, { // Unexported embedded field of pointer to non-struct type // should not be serialized. label: "UnexportedEmbeddedIntPointer", makeInput: func() interface{} { type ( myInt int S struct{ *myInt } ) s := S{new(myInt)} *s.myInt = 5 return s }, want: `{}`, }, { // Exported embedded field of pointer to non-struct type // should be serialized. label: "ExportedEmbeddedIntPointer", makeInput: func() interface{} { type ( MyInt int S struct{ *MyInt } ) s := S{new(MyInt)} *s.MyInt = 5 return s }, want: `{"MyInt":5}`, }, { // Exported fields of embedded structs should have their // exported fields be serialized regardless of whether the struct types // themselves are exported. label: "EmbeddedStruct", makeInput: func() interface{} { type ( s1 struct{ x, X int } S2 struct{ y, Y int } S struct { s1 S2 } ) return S{s1{1, 2}, S2{3, 4}} }, want: `{"X":2,"Y":4}`, }, { // Exported fields of pointers to embedded structs should have their // exported fields be serialized regardless of whether the struct types // themselves are exported. label: "EmbeddedStructPointer", makeInput: func() interface{} { type ( s1 struct{ x, X int } S2 struct{ y, Y int } S struct { *s1 *S2 } ) return S{&s1{1, 2}, &S2{3, 4}} }, want: `{"X":2,"Y":4}`, }, { // Exported fields on embedded unexported structs at multiple levels // of nesting should still be serialized. label: "NestedStructAndInts", makeInput: func() interface{} { type ( MyInt1 int MyInt2 int myInt int s2 struct { MyInt2 myInt } s1 struct { MyInt1 myInt s2 } S struct { s1 myInt } ) return S{s1{1, 2, s2{3, 4}}, 6} }, want: `{"MyInt1":1,"MyInt2":3}`, }, { // If an anonymous struct pointer field is nil, we should ignore // the embedded fields behind it. Not properly doing so may // result in the wrong output or reflect panics. label: "EmbeddedFieldBehindNilPointer", makeInput: func() interface{} { type ( S2 struct{ Field string } S struct{ *S2 } ) return S{} }, want: `{}`, }} for i, tt := range tests { t.Run(tt.label, func(t *testing.T) { b, err := json.Marshal(tt.makeInput()) if err != nil { t.Fatalf("%d: Marshal() = %v, want nil error", i, err) } if string(b) != tt.want { t.Fatalf("%d: Marshal() = %q, want %q", i, b, tt.want) } }) } } type Optionals struct { Sr string `json:"sr"` So string `json:"so,omitempty"` Sw string `json:"-"` Ir int `json:"omitempty"` // actually named omitempty, not an option Io int `json:"io,omitempty"` Slr []string `json:"slr,random"` Slo []string `json:"slo,omitempty"` Mr map[string]interface{} `json:"mr"` Mo map[string]interface{} `json:",omitempty"` Fr float64 `json:"fr"` Fo float64 `json:"fo,omitempty"` Br bool `json:"br"` Bo bool `json:"bo,omitempty"` Ur uint `json:"ur"` Uo uint `json:"uo,omitempty"` Str struct{} `json:"str"` Sto struct{} `json:"sto,omitempty"` } var optionalsExpected = `{ "sr": "", "omitempty": 0, "slr": null, "mr": {}, "fr": 0, "br": false, "ur": 0, "str": {}, "sto": {} }` func TestOmitEmpty(t *testing.T) { var o Optionals o.Sw = "something" o.Mr = map[string]interface{}{} o.Mo = map[string]interface{}{} got, err := json.MarshalIndent(&o, "", " ") if err != nil { t.Fatal(err) } if got := string(got); got != optionalsExpected { t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected) } } type testNullStr string func (v *testNullStr) MarshalJSON() ([]byte, error) { if *v == "" { return []byte("null"), nil } return []byte(*v), nil } func TestIssue147(t *testing.T) { type T struct { Field1 string `json:"field1"` Field2 testNullStr `json:"field2,omitempty"` } got, err := json.Marshal(T{ Field1: "a", Field2: "b", }) if err != nil { t.Fatal(err) } expect, _ := stdjson.Marshal(T{ Field1: "a", Field2: "b", }) if !bytes.Equal(expect, got) { t.Fatalf("expect %q but got %q", string(expect), string(got)) } } type testIssue144 struct { name string number int64 } func (v *testIssue144) MarshalJSON() ([]byte, error) { if v.name != "" { return json.Marshal(v.name) } return json.Marshal(v.number) } func TestIssue144(t *testing.T) { type Embeded struct { Field *testIssue144 `json:"field,omitempty"` } type T struct { Embeded } { v := T{ Embeded: Embeded{Field: &testIssue144{name: "hoge"}}, } got, err := json.Marshal(v) if err != nil { t.Fatal(err) } expect, _ := stdjson.Marshal(v) if !bytes.Equal(expect, got) { t.Fatalf("expect %q but got %q", string(expect), string(got)) } } { v := &T{ Embeded: Embeded{Field: &testIssue144{name: "hoge"}}, } got, err := json.Marshal(v) if err != nil { t.Fatal(err) } expect, _ := stdjson.Marshal(v) if !bytes.Equal(expect, got) { t.Fatalf("expect %q but got %q", string(expect), string(got)) } } } func TestIssue118(t *testing.T) { type data struct { Columns []string `json:"columns"` Rows1 [][]string `json:"rows1"` Rows2 [][]string `json:"rows2"` } v := data{Columns: []string{"1", "2", "3"}} got, err := json.MarshalIndent(v, "", " ") if err != nil { t.Fatal(err) } expect, _ := stdjson.MarshalIndent(v, "", " ") if !bytes.Equal(expect, got) { t.Fatalf("expect %q but got %q", string(expect), string(got)) } } func TestIssue104(t *testing.T) { type A struct { Field1 string Field2 int Field3 float64 } type T struct { Field A } got, err := json.Marshal(T{}) if err != nil { t.Fatal(err) } expect, _ := stdjson.Marshal(T{}) if !bytes.Equal(expect, got) { t.Fatalf("expect %q but got %q", string(expect), string(got)) } } func TestIssue179(t *testing.T) { data := ` { "t": { "t1": false, "t2": 0, "t3": "", "t4": [], "t5": null, "t6": null } }` type T struct { X struct { T1 bool `json:"t1,omitempty"` T2 float64 `json:"t2,omitempty"` T3 string `json:"t3,omitempty"` T4 []string `json:"t4,omitempty"` T5 *struct{} `json:"t5,omitempty"` T6 interface{} `json:"t6,omitempty"` } `json:"x"` } var v T if err := stdjson.Unmarshal([]byte(data), &v); err != nil { t.Fatal(err) } var v2 T if err := json.Unmarshal([]byte(data), &v2); err != nil { t.Fatal(err) } if !reflect.DeepEqual(v, v2) { t.Fatalf("failed to decode: expected %v got %v", v, v2) } b1, err := stdjson.Marshal(v) if err != nil { t.Fatal(err) } b2, err := json.Marshal(v2) if err != nil { t.Fatal(err) } if !bytes.Equal(b1, b2) { t.Fatalf("failed to equal encoded result: expected %q but got %q", b1, b2) } } func TestIssue180(t *testing.T) { v := struct { T struct { T1 bool `json:"t1"` T2 float64 `json:"t2"` T3 string `json:"t3"` T4 []string `json:"t4"` T5 *struct{} `json:"t5"` T6 interface{} `json:"t6"` T7 [][]string `json:"t7"` } `json:"t"` }{ T: struct { T1 bool `json:"t1"` T2 float64 `json:"t2"` T3 string `json:"t3"` T4 []string `json:"t4"` T5 *struct{} `json:"t5"` T6 interface{} `json:"t6"` T7 [][]string `json:"t7"` }{ T4: []string{}, T7: [][]string{ []string{""}, []string{"hello", "world"}, []string{}, }, }, } b1, err := stdjson.MarshalIndent(v, "", "\t") if err != nil { t.Fatal(err) } b2, err := json.MarshalIndent(v, "", "\t") if err != nil { t.Fatal(err) } if !bytes.Equal(b1, b2) { t.Fatalf("failed to equal encoded result: expected %s but got %s", string(b1), string(b2)) } } func TestIssue235(t *testing.T) { type TaskMessage struct { Type string Payload map[string]interface{} UniqueKey string } msg := TaskMessage{ Payload: map[string]interface{}{ "sent_at": map[string]interface{}{ "Time": "0001-01-01T00:00:00Z", "Valid": false, }, }, } if _, err := json.Marshal(msg); err != nil { t.Fatal(err) } } func TestEncodeMapKeyTypeInterface(t *testing.T) { if _, err := json.Marshal(map[interface{}]interface{}{"a": 1}); err == nil { t.Fatal("expected error") } } type marshalContextKey struct{} type marshalContextStructType struct{} func (t *marshalContextStructType) MarshalJSON(ctx context.Context) ([]byte, error) { v := ctx.Value(marshalContextKey{}) s, ok := v.(string) if !ok { return nil, fmt.Errorf("failed to propagate parent context.Context") } if s != "hello" { return nil, fmt.Errorf("failed to propagate parent context.Context") } return []byte(`"success"`), nil } func TestEncodeContextOption(t *testing.T) { t.Run("MarshalContext", func(t *testing.T) { ctx := context.WithValue(context.Background(), marshalContextKey{}, "hello") b, err := json.MarshalContext(ctx, &marshalContextStructType{}) if err != nil { t.Fatal(err) } if string(b) != `"success"` { t.Fatal("failed to encode with MarshalerContext") } }) t.Run("EncodeContext", func(t *testing.T) { ctx := context.WithValue(context.Background(), marshalContextKey{}, "hello") buf := bytes.NewBuffer([]byte{}) if err := json.NewEncoder(buf).EncodeContext(ctx, &marshalContextStructType{}); err != nil { t.Fatal(err) } if buf.String() != "\"success\"\n" { t.Fatal("failed to encode with EncodeContext") } }) } func TestInterfaceWithPointer(t *testing.T) { var ( ivalue int = 10 uvalue uint = 20 svalue string = "value" bvalue bool = true fvalue float32 = 3.14 nvalue json.Number = "1.23" structv = struct{ A int }{A: 10} slice = []int{1, 2, 3, 4} array = [4]int{1, 2, 3, 4} mapvalue = map[string]int{"a": 1} ) data := map[string]interface{}{ "ivalue": ivalue, "uvalue": uvalue, "svalue": svalue, "bvalue": bvalue, "fvalue": fvalue, "nvalue": nvalue, "struct": structv, "slice": slice, "array": array, "map": mapvalue, "pivalue": &ivalue, "puvalue": &uvalue, "psvalue": &svalue, "pbvalue": &bvalue, "pfvalue": &fvalue, "pnvalue": &nvalue, "pstruct": &structv, "pslice": &slice, "parray": &array, "pmap": &mapvalue, } expected, err := stdjson.Marshal(data) if err != nil { t.Fatal(err) } actual, err := json.Marshal(data) if err != nil { t.Fatal(err) } assertEq(t, "interface{}", string(expected), string(actual)) } func TestIssue263(t *testing.T) { type Foo struct { A []string `json:"a"` B int `json:"b"` } type MyStruct struct { Foo *Foo `json:"foo,omitempty"` } s := MyStruct{ Foo: &Foo{ A: []string{"ls -lah"}, B: 0, }, } expected, err := stdjson.Marshal(s) if err != nil { t.Fatal(err) } actual, err := json.Marshal(s) if err != nil { t.Fatal(err) } if !bytes.Equal(expected, actual) { t.Fatalf("expected:[%s] but got:[%s]", string(expected), string(actual)) } } func TestEmbeddedNotFirstField(t *testing.T) { type Embedded struct { Has bool `json:"has"` } type T struct { X int `json:"is"` Embedded `json:"child"` } p := T{X: 10, Embedded: Embedded{Has: true}} expected, err := stdjson.Marshal(&p) if err != nil { t.Fatal(err) } got, err := json.Marshal(&p) if err != nil { t.Fatal(err) } if !bytes.Equal(expected, got) { t.Fatalf("failed to encode embedded structure. expected = %q but got %q", expected, got) } } type implementedMethodIface interface { M() } type implementedIfaceType struct { A int B string } func (implementedIfaceType) M() {} func TestImplementedMethodInterfaceType(t *testing.T) { data := []implementedIfaceType{implementedIfaceType{}} expected, err := stdjson.Marshal(data) if err != nil { t.Fatal(err) } got, err := json.Marshal(data) if err != nil { t.Fatal(err) } if !bytes.Equal(expected, got) { t.Fatalf("failed to encode implemented method interface type. expected:[%q] but got:[%q]", expected, got) } } func TestEmptyStructInterface(t *testing.T) { expected, err := stdjson.Marshal([]interface{}{struct{}{}}) if err != nil { t.Fatal(err) } got, err := json.Marshal([]interface{}{struct{}{}}) if err != nil { t.Fatal(err) } if !bytes.Equal(expected, got) { t.Fatalf("failed to encode empty struct interface. expected:[%q] but got:[%q]", expected, got) } } func TestIssue290(t *testing.T) { type Issue290 interface { A() } var a struct { A Issue290 } expected, err := stdjson.Marshal(a) if err != nil { t.Fatal(err) } got, err := json.Marshal(a) if err != nil { t.Fatal(err) } if !bytes.Equal(expected, got) { t.Fatalf("failed to encode non empty interface. expected = %q but got %q", expected, got) } } func TestIssue299(t *testing.T) { t.Run("conflict second field", func(t *testing.T) { type Embedded struct { ID string `json:"id"` Name map[string]string `json:"name"` } type Container struct { Embedded Name string `json:"name"` } c := &Container{ Embedded: Embedded{ ID: "1", Name: map[string]string{"en": "Hello", "es": "Hola"}, }, Name: "Hi", } expected, _ := stdjson.Marshal(c) got, err := json.Marshal(c) if err != nil { t.Fatal(err) } if !bytes.Equal(expected, got) { t.Fatalf("expected %q but got %q", expected, got) } }) t.Run("conflict map field", func(t *testing.T) { type Embedded struct { Name map[string]string `json:"name"` } type Container struct { Embedded Name string `json:"name"` } c := &Container{ Embedded: Embedded{ Name: map[string]string{"en": "Hello", "es": "Hola"}, }, Name: "Hi", } expected, _ := stdjson.Marshal(c) got, err := json.Marshal(c) if err != nil { t.Fatal(err) } if !bytes.Equal(expected, got) { t.Fatalf("expected %q but got %q", expected, got) } }) t.Run("conflict slice field", func(t *testing.T) { type Embedded struct { Name []string `json:"name"` } type Container struct { Embedded Name string `json:"name"` } c := &Container{ Embedded: Embedded{ Name: []string{"Hello"}, }, Name: "Hi", } expected, _ := stdjson.Marshal(c) got, err := json.Marshal(c) if err != nil { t.Fatal(err) } if !bytes.Equal(expected, got) { t.Fatalf("expected %q but got %q", expected, got) } }) } func TestRecursivePtrHead(t *testing.T) { type User struct { Account *string `json:"account"` Password *string `json:"password"` Nickname *string `json:"nickname"` Address *string `json:"address,omitempty"` Friends []*User `json:"friends,omitempty"` } user1Account, user1Password, user1Nickname := "abcdef", "123456", "user1" user1 := &User{ Account: &user1Account, Password: &user1Password, Nickname: &user1Nickname, Address: nil, } user2Account, user2Password, user2Nickname := "ghijkl", "123456", "user2" user2 := &User{ Account: &user2Account, Password: &user2Password, Nickname: &user2Nickname, Address: nil, } user1.Friends = []*User{user2} expected, err := stdjson.Marshal(user1) if err != nil { t.Fatal(err) } got, err := json.Marshal(user1) if err != nil { t.Fatal(err) } if !bytes.Equal(expected, got) { t.Fatalf("failed to encode. expected %q but got %q", expected, got) } } func TestMarshalIndent(t *testing.T) { v := map[string]map[string]interface{}{ "a": { "b": "1", "c": map[string]interface{}{ "d": "1", }, }, } expected, err := stdjson.MarshalIndent(v, "", " ") if err != nil { t.Fatal(err) } got, err := json.MarshalIndent(v, "", " ") if err != nil { t.Fatal(err) } if !bytes.Equal(expected, got) { t.Fatalf("expected: %q but got %q", expected, got) } } type issue318Embedded struct { _ [64]byte } type issue318 struct { issue318Embedded `json:"-"` ID issue318MarshalText `json:"id,omitempty"` } type issue318MarshalText struct { ID string } func (i issue318MarshalText) MarshalText() ([]byte, error) { return []byte(i.ID), nil } func TestIssue318(t *testing.T) { v := issue318{ ID: issue318MarshalText{ID: "1"}, } b, err := json.Marshal(v) if err != nil { t.Fatal(err) } expected := `{"id":"1"}` if string(b) != expected { t.Fatalf("failed to encode. expected %s but got %s", expected, string(b)) } } type emptyStringMarshaler struct { Value stringMarshaler `json:"value,omitempty"` } type stringMarshaler string func (s stringMarshaler) MarshalJSON() ([]byte, error) { return []byte(`"` + s + `"`), nil } func TestEmptyStringMarshaler(t *testing.T) { value := emptyStringMarshaler{} expected, err := stdjson.Marshal(value) assertErr(t, err) got, err := json.Marshal(value) assertErr(t, err) assertEq(t, "struct", string(expected), string(got)) } func TestIssue324(t *testing.T) { type T struct { FieldA *string `json:"fieldA,omitempty"` FieldB *string `json:"fieldB,omitempty"` FieldC *bool `json:"fieldC"` FieldD []string `json:"fieldD,omitempty"` } v := &struct { Code string `json:"code"` *T }{ T: &T{}, } var sv = "Test Field" v.Code = "Test" v.T.FieldB = &sv expected, err := stdjson.Marshal(v) if err != nil { t.Fatal(err) } got, err := json.Marshal(v) if err != nil { t.Fatal(err) } if !bytes.Equal(expected, got) { t.Fatalf("failed to encode. expected %q but got %q", expected, got) } } func TestIssue339(t *testing.T) { type T1 struct { *big.Int } type T2 struct { T1 T1 `json:"T1"` } v := T2{T1{Int: big.NewInt(10000)}} b, err := json.Marshal(&v) assertErr(t, err) got := string(b) expected := `{"T1":10000}` if got != expected { t.Errorf("unexpected result: %v != %v", got, expected) } } func TestIssue376(t *testing.T) { type Container struct { V interface{} `json:"value"` } type MapOnly struct { Map map[string]int64 `json:"map"` } b, err := json.Marshal(Container{MapOnly{}}) if err != nil { t.Fatal(err) } got := string(b) expected := `{"value":{"map":null}}` if got != expected { t.Errorf("unexpected result: %v != %v", got, expected) } } type Issue370 struct { String string Valid bool } func (i *Issue370) MarshalJSON() ([]byte, error) { if !i.Valid { return json.Marshal(nil) } return json.Marshal(i.String) } func TestIssue370(t *testing.T) { v := []struct { V Issue370 }{ {V: Issue370{String: "test", Valid: true}}, } b, err := json.Marshal(v) if err != nil { t.Fatal(err) } got := string(b) expected := `[{"V":"test"}]` if got != expected { t.Errorf("unexpected result: %v != %v", got, expected) } } func TestIssue374(t *testing.T) { r := io.MultiReader(strings.NewReader(strings.Repeat(" ", 505)+`"\u`), strings.NewReader(`0000"`)) var v interface{} if err := json.NewDecoder(r).Decode(&v); err != nil { t.Fatal(err) } got := v.(string) expected := "\u0000" if got != expected { t.Errorf("unexpected result: %q != %q", got, expected) } } func TestIssue381(t *testing.T) { var v struct { Field0 bool Field1 bool Field2 bool Field3 bool Field4 bool Field5 bool Field6 bool Field7 bool Field8 bool Field9 bool Field10 bool Field11 bool Field12 bool Field13 bool Field14 bool Field15 bool Field16 bool Field17 bool Field18 bool Field19 bool Field20 bool Field21 bool Field22 bool Field23 bool Field24 bool Field25 bool Field26 bool Field27 bool Field28 bool Field29 bool Field30 bool Field31 bool Field32 bool Field33 bool Field34 bool Field35 bool Field36 bool Field37 bool Field38 bool Field39 bool Field40 bool Field41 bool Field42 bool Field43 bool Field44 bool Field45 bool Field46 bool Field47 bool Field48 bool Field49 bool Field50 bool Field51 bool Field52 bool Field53 bool Field54 bool Field55 bool Field56 bool Field57 bool Field58 bool Field59 bool Field60 bool Field61 bool Field62 bool Field63 bool Field64 bool Field65 bool Field66 bool Field67 bool Field68 bool Field69 bool Field70 bool Field71 bool Field72 bool Field73 bool Field74 bool Field75 bool Field76 bool Field77 bool Field78 bool Field79 bool Field80 bool Field81 bool Field82 bool Field83 bool Field84 bool Field85 bool Field86 bool Field87 bool Field88 bool Field89 bool Field90 bool Field91 bool Field92 bool Field93 bool Field94 bool Field95 bool Field96 bool Field97 bool Field98 bool Field99 bool } // test encoder cache issue, not related to encoder b, err := json.Marshal(v) if err != nil { t.Errorf("failed to marshal %s", err.Error()) t.FailNow() } std, err := stdjson.Marshal(v) if err != nil { t.Errorf("failed to marshal with encoding/json %s", err.Error()) t.FailNow() } if !bytes.Equal(std, b) { t.Errorf("encoding result not equal to encoding/json") t.FailNow() } } func TestIssue386(t *testing.T) { raw := `{"date": null, "platform": "\u6f2b\u753b", "images": {"small": "https://lain.bgm.tv/pic/cover/s/d2/a1/80048_jp.jpg", "grid": "https://lain.bgm.tv/pic/cover/g/d2/a1/80048_jp.jpg", "large": "https://lain.bgm.tv/pic/cover/l/d2/a1/80048_jp.jpg", "medium": "https://lain.bgm.tv/pic/cover/m/d2/a1/80048_jp.jpg", "common": "https://lain.bgm.tv/pic/cover/c/d2/a1/80048_jp.jpg"}, "summary": "\u5929\u624d\u8a2d\u8a08\u58eb\u30fb\u5929\u5bae\uff08\u3042\u307e\u307f\u3084\uff09\u3092\u62b1\u3048\u308b\u6751\u96e8\u7dcf\u5408\u4f01\u753b\u306f\u3001\u771f\u6c34\u5efa\u8a2d\u3068\u63d0\u643a\u3057\u3066\u300c\u3055\u304d\u305f\u307e\u30a2\u30ea\u30fc\u30ca\u300d\u306e\u30b3\u30f3\u30da\u306b\u512a\u52dd\u3059\u308b\u3053\u3068\u306b\u8ced\u3051\u3066\u3044\u305f\u3002\u3057\u304b\u3057\u3001\u73fe\u77e5\u4e8b\u306e\u6d25\u5730\u7530\uff08\u3064\u3061\u3060\uff09\u306f\u5927\u65e5\u5efa\u8a2d\u306b\u512a\u52dd\u3055\u305b\u3088\u3046\u3068\u6697\u8e8d\u3059\u308b\u3002\u305d\u308c\u306f\u73fe\u77e5\u4e8b\u306e\u6d25\u5730\u7530\u3068\u526f\u77e5\u4e8b\u306e\u592a\u7530\uff08\u304a\u304a\u305f\uff09\u306e\u653f\u6cbb\u751f\u547d\u3092\u5de6\u53f3\u3059\u308b\u4e89\u3044\u3068\u306a\u308a\u2026\u2026!?\u3000\u305d\u3057\u3066\u516c\u5171\u4e8b\u696d\u306b\u6e26\u5dfb\u304f\u6df1\u3044\u95c7\u306b\u842c\u7530\u9280\u6b21\u90ce\uff08\u307e\u3093\u3060\u30fb\u304e\u3093\u3058\u308d\u3046\uff09\u306f\u2026\u2026!?", "name": "\u30df\u30ca\u30df\u306e\u5e1d\u738b (48)"}` var a struct { Date *string `json:"date"` Platform *string `json:"platform"` Summary string `json:"summary"` Name string `json:"name"` } err := json.NewDecoder(strings.NewReader(raw)).Decode(&a) if err != nil { t.Error(err) } } type customMapKey string func (b customMapKey) MarshalJSON() ([]byte, error) { return []byte("[]"), nil } func TestCustomMarshalForMapKey(t *testing.T) { m := map[customMapKey]string{customMapKey("skipcustom"): "test"} expected, err := stdjson.Marshal(m) assertErr(t, err) got, err := json.Marshal(m) assertErr(t, err) assertEq(t, "custom map key", string(expected), string(got)) }