| // 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) | |
| } | |
| } | |
| // C implements Marshaler and returns unescaped JSON. | |
| type C int | |
| func (C) MarshalJSON() ([]byte, error) { | |
| return []byte(`"<&>"`), nil | |
| } | |
| func TestMarshalerEscaping(t *testing.T) { | |
| var c C | |
| const want = `"\u003c\u0026\u003e"` | |
| b, err := Marshal(c) | |
| if err != nil { | |
| t.Fatalf("Marshal: %v", err) | |
| } | |
| if got := string(b); got != want { | |
| t.Errorf("got %q, want %q", got, want) | |
| } | |
| } |