// 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. package json import ( "bytes" "math" "reflect" "testing" ) 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"` } var optionalsExpected = `{ "sr": "", "omitempty": 0, "slr": null, "mr": {} }` func TestOmitEmpty(t *testing.T) { var o Optionals o.Sw = "something" o.Mr = map[string]interface{}{} o.Mo = map[string]interface{}{} got, err := MarshalIndent(&o, "", " ") if err != nil { t.Fatal(err) } if got := string(got); got != optionalsExpected { t.Errorf(" got: %s\nwant: %s\n", got, optionalsExpected) } } type StringTag struct { BoolStr bool `json:",string"` IntStr int64 `json:",string"` StrStr string `json:",string"` } var stringTagExpected = `{ "BoolStr": "true", "IntStr": "42", "StrStr": "\"xzbit\"" }` func TestStringTag(t *testing.T) { var s StringTag s.BoolStr = true s.IntStr = 42 s.StrStr = "xzbit" got, err := MarshalIndent(&s, "", " ") if err != nil { t.Fatal(err) } if got := string(got); got != stringTagExpected { t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected) } // Verify that it round-trips. var s2 StringTag err = NewDecoder(bytes.NewBuffer(got)).Decode(&s2) if err != nil { t.Fatalf("Decode: %v", err) } if !reflect.DeepEqual(s, s2) { t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, 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 := 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 = Marshal(r) if err != nil { t.Fatal(err) } if string(result) != expect { t.Errorf(" got %s want %s", result, expect) } } var unsupportedValues = []interface{}{ math.NaN(), math.Inf(-1), math.Inf(1), } func TestUnsupportedValues(t *testing.T) { for _, v := range unsupportedValues { if _, err := Marshal(v); err != nil { if _, ok := err.(*UnsupportedValueError); !ok { t.Errorf("for %v, got %T want UnsupportedValueError", v, err) } } else { t.Errorf("for %v, expected error", v) } } } // 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 } func TestRefValMarshal(t *testing.T) { var s = struct { R0 Ref R1 *Ref V0 Val V1 *Val }{ R0: 12, R1: new(Ref), V0: 13, V1: new(Val), } const want = `{"R0":"ref","R1":"ref","V0":"val","V1":"val"}` b, err := Marshal(&s) if err != nil { t.Fatalf("Marshal: %v", err) } if got := string(b); got != want { t.Errorf("got %q, want %q", got, want) } }