| // 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" | 
 | 	"fmt" | 
 | 	"math" | 
 | 	"reflect" | 
 | 	"testing" | 
 | 	"unicode" | 
 | ) | 
 |  | 
 | 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 := 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.NewReader(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 | 
 | } | 
 |  | 
 | // 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 := 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 := 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 = 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 IntType int | 
 |  | 
 | type MyStruct struct { | 
 | 	IntType | 
 | } | 
 |  | 
 | func TestAnonymousNonstruct(t *testing.T) { | 
 | 	var i IntType = 11 | 
 | 	a := MyStruct{i} | 
 | 	const want = `{"IntType":11}` | 
 |  | 
 | 	b, err := Marshal(a) | 
 | 	if err != nil { | 
 | 		t.Fatalf("Marshal: %v", err) | 
 | 	} | 
 | 	if got := string(b); got != want { | 
 | 		t.Errorf("got %q, want %q", got, want) | 
 | 	} | 
 | } | 
 |  | 
 | 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 | 
 | } | 
 |  | 
 | // Issue 5245. | 
 | func TestEmbeddedBug(t *testing.T) { | 
 | 	v := BugB{ | 
 | 		BugA{"A"}, | 
 | 		"B", | 
 | 	} | 
 | 	b, err := 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 = 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 := 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 := 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 TestStringBytes(t *testing.T) { | 
 | 	// Test that encodeState.stringBytes and encodeState.string use the same encoding. | 
 | 	es := &encodeState{} | 
 | 	var r []rune | 
 | 	for i := '\u0000'; i <= unicode.MaxRune; i++ { | 
 | 		r = append(r, i) | 
 | 	} | 
 | 	s := string(r) + "\xff\xff\xffhello" // some invalid UTF-8 too | 
 | 	es.string(s) | 
 |  | 
 | 	esBytes := &encodeState{} | 
 | 	esBytes.stringBytes([]byte(s)) | 
 |  | 
 | 	enc := es.Buffer.String() | 
 | 	encBytes := esBytes.Buffer.String() | 
 | 	if enc != encBytes { | 
 | 		i := 0 | 
 | 		for i < len(enc) && i < len(encBytes) && enc[i] == encBytes[i] { | 
 | 			i++ | 
 | 		} | 
 | 		enc = enc[i:] | 
 | 		encBytes = encBytes[i:] | 
 | 		i = 0 | 
 | 		for i < len(enc) && i < len(encBytes) && enc[len(enc)-i-1] == encBytes[len(encBytes)-i-1] { | 
 | 			i++ | 
 | 		} | 
 | 		enc = enc[:len(enc)-i] | 
 | 		encBytes = encBytes[:len(encBytes)-i] | 
 |  | 
 | 		if len(enc) > 20 { | 
 | 			enc = enc[:20] + "..." | 
 | 		} | 
 | 		if len(encBytes) > 20 { | 
 | 			encBytes = encBytes[:20] + "..." | 
 | 		} | 
 |  | 
 | 		t.Errorf("encodings differ at %#q vs %#q", enc, encBytes) | 
 | 	} | 
 | } | 
 |  | 
 | func TestIssue6458(t *testing.T) { | 
 | 	type Foo struct { | 
 | 		M RawMessage | 
 | 	} | 
 | 	x := Foo{RawMessage(`"foo"`)} | 
 |  | 
 | 	b, err := Marshal(&x) | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 | 	if want := `{"M":"foo"}`; string(b) != want { | 
 | 		t.Errorf("Marshal(&x) = %#q; want %#q", b, want) | 
 | 	} | 
 |  | 
 | 	b, err = Marshal(x) | 
 | 	if err != nil { | 
 | 		t.Fatal(err) | 
 | 	} | 
 |  | 
 | 	if want := `{"M":"ImZvbyI="}`; string(b) != want { | 
 | 		t.Errorf("Marshal(x) = %#q; want %#q", b, want) | 
 | 	} | 
 | } | 
 |  | 
 | func TestIssue10281(t *testing.T) { | 
 | 	type Foo struct { | 
 | 		N Number | 
 | 	} | 
 | 	x := Foo{Number(`invalid`)} | 
 |  | 
 | 	b, err := 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":"<html>foo &` + "\xe2\x80\xa8 \xe2\x80\xa9" + `</html>"}` | 
 | 	want.Write([]byte(`{"M":"\u003chtml\u003efoo \u0026\u2028 \u2029\u003c/html\u003e"}`)) | 
 | 	HTMLEscape(&b, []byte(m)) | 
 | 	if !bytes.Equal(b.Bytes(), want.Bytes()) { | 
 | 		t.Errorf("HTMLEscape(&b, []byte(m)) = %s; want %s", b.Bytes(), want.Bytes()) | 
 | 	} | 
 | } | 
 |  | 
 | // golang.org/issue/8582 | 
 | func TestEncodePointerString(t *testing.T) { | 
 | 	type stringPointer struct { | 
 | 		N *int64 `json:"n,string"` | 
 | 	} | 
 | 	var n int64 = 42 | 
 | 	b, err := 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 = Unmarshal(b, &back) | 
 | 	if err != nil { | 
 | 		t.Fatalf("Unmarshal: %v", err) | 
 | 	} | 
 | 	if back.N == nil { | 
 | 		t.Fatalf("Unmarshalled nil N field") | 
 | 	} | 
 | 	if *back.N != 42 { | 
 | 		t.Fatalf("*N = %d; want 42", *back.N) | 
 | 	} | 
 | } | 
 |  | 
 | 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 := 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 _, d := range testdata { | 
 | 		js, err := Marshal(d.data) | 
 | 		if err != nil { | 
 | 			t.Error(err) | 
 | 			continue | 
 | 		} | 
 | 		got, want := string(js), d.want | 
 | 		if got != want { | 
 | 			t.Errorf("got %s, want %s", got, want) | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | func TestTextMarshalerMapKeysAreSorted(t *testing.T) { | 
 | 	b, err := Marshal(map[unmarshalerText]int{ | 
 | 		{"x", "y"}: 1, | 
 | 		{"y", "x"}: 2, | 
 | 		{"a", "z"}: 3, | 
 | 		{"z", "a"}: 4, | 
 | 	}) | 
 | 	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) | 
 | 	} | 
 | } |