1486 lines · 33.2 KB · Go
RawDownload
// 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"	"fmt"	"image"	"net"	"reflect"	"strings"	"testing"	"time") type T struct {	X string	Y int	Z int `json:"-"`} type U struct {	Alphabet string `json:"alpha"`} type V struct {	F1 interface{}	F2 int32	F3 Number} // ifaceNumAsFloat64/ifaceNumAsNumber are used to test unmarshaling with and// without UseNumbervar ifaceNumAsFloat64 = map[string]interface{}{	"k1": float64(1),	"k2": "s",	"k3": []interface{}{float64(1), float64(2.0), float64(3e-3)},	"k4": map[string]interface{}{"kk1": "s", "kk2": float64(2)},} var ifaceNumAsNumber = map[string]interface{}{	"k1": Number("1"),	"k2": "s",	"k3": []interface{}{Number("1"), Number("2.0"), Number("3e-3")},	"k4": map[string]interface{}{"kk1": "s", "kk2": Number("2")},} type tx struct {	x int} // 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 {	T bool} // needed for re-marshaling testsfunc (u *unmarshalerText) MarshalText() ([]byte, error) {	return []byte(""), nil} func (u *unmarshalerText) UnmarshalText(b []byte) error {	*u = unmarshalerText{true} // All we need to see that UnmarshalText is called.	return nil} var _ encoding.TextUnmarshaler = (*unmarshalerText)(nil) type ustructText struct {	M unmarshalerText} var (	um0, um1 unmarshaler // target2 of unmarshaling	ump      = &um1	umtrue   = unmarshaler{true}	umslice  = []unmarshaler{{true}}	umslicep = new([]unmarshaler)	umstruct = ustruct{unmarshaler{true}} 	um0T, um1T unmarshalerText // target2 of unmarshaling	umpT       = &um1T	umtrueT    = unmarshalerText{true}	umsliceT   = []unmarshalerText{{true}}	umslicepT  = new([]unmarshalerText)	umstructT  = ustructText{unmarshalerText{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 unmarshalTest struct {	in        string	ptr       interface{}	out       interface{}	err       error	useNumber bool} type Ambig struct {	// Given "hello", the first match should win.	First  int `json:"HELLO"`	Second int `json:"Hello"`} type XYZ struct {	X interface{}	Y interface{}	Z interface{}} func sliceAddr(x []int) *[]int                 { return &x }func mapAddr(x map[string]int) *map[string]int { return &x } var unmarshalTests = []unmarshalTest{	// basic types	{in: `true`, ptr: new(bool), out: true},	{in: `1`, ptr: new(int), out: 1},	{in: `1.2`, ptr: new(float64), out: 1.2},	{in: `-5`, ptr: new(int16), out: int16(-5)},	{in: `2`, ptr: new(Number), out: Number("2"), useNumber: true},	{in: `2`, ptr: new(Number), out: Number("2")},	{in: `2`, ptr: new(interface{}), out: float64(2.0)},	{in: `2`, ptr: new(interface{}), out: Number("2"), useNumber: true},	{in: `"a\u1234"`, ptr: new(string), out: "a\u1234"},	{in: `"http:\/\/"`, ptr: new(string), out: "http://"},	{in: `"g-clef: \uD834\uDD1E"`, ptr: new(string), out: "g-clef: \U0001D11E"},	{in: `"invalid: \uD834x\uDD1E"`, ptr: new(string), out: "invalid: \uFFFDx\uFFFD"},	{in: "null", ptr: new(interface{}), out: nil},	{in: `{"X": [1,2,3], "Y": 4}`, ptr: new(T), out: T{Y: 4}, err: &UnmarshalTypeError{"array", reflect.TypeOf(""), 7}},	{in: `{"x": 1}`, ptr: new(tx), out: tx{}},	{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: float64(1), F2: int32(2), F3: Number("3")}},	{in: `{"F1":1,"F2":2,"F3":3}`, ptr: new(V), out: V{F1: Number("1"), F2: int32(2), F3: Number("3")}, useNumber: true},	{in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsFloat64},	{in: `{"k1":1,"k2":"s","k3":[1,2.0,3e-3],"k4":{"kk1":"s","kk2":2}}`, ptr: new(interface{}), out: ifaceNumAsNumber, useNumber: true}, 	// raw values with whitespace	{in: "\n true ", ptr: new(bool), out: true},	{in: "\t 1 ", ptr: new(int), out: 1},	{in: "\r 1.2 ", ptr: new(float64), out: 1.2},	{in: "\t -5 \n", ptr: new(int16), out: int16(-5)},	{in: "\t \"a\\u1234\" \n", ptr: new(string), out: "a\u1234"}, 	// Z has a "-" tag.	{in: `{"Y": 1, "Z": 2}`, ptr: new(T), out: T{Y: 1}}, 	{in: `{"alpha": "abc", "alphabet": "xyz"}`, ptr: new(U), out: U{Alphabet: "abc"}},	{in: `{"alpha": "abc"}`, ptr: new(U), out: U{Alphabet: "abc"}},	{in: `{"alphabet": "xyz"}`, ptr: new(U), out: U{}}, 	// syntax errors	{in: `{"X": "foo", "Y"}`, err: &SyntaxError{"invalid character '}' after object key", 17}},	{in: `[1, 2, 3+]`, err: &SyntaxError{"invalid character '+' after array element", 9}},	{in: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true}, 	// raw value errors	{in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},	{in: " 42 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 5}},	{in: "\x01 true", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},	{in: " false \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 8}},	{in: "\x01 1.2", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},	{in: " 3.4 \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 6}},	{in: "\x01 \"string\"", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},	{in: " \"string\" \x01", err: &SyntaxError{"invalid character '\\x01' after top-level value", 11}}, 	// array tests	{in: `[1, 2, 3]`, ptr: new([3]int), out: [3]int{1, 2, 3}},	{in: `[1, 2, 3]`, ptr: new([1]int), out: [1]int{1}},	{in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}}, 	// empty array to interface test	{in: `[]`, ptr: new([]interface{}), out: []interface{}{}},	{in: `null`, ptr: new([]interface{}), out: []interface{}(nil)},	{in: `{"T":[]}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": []interface{}{}}},	{in: `{"T":null}`, ptr: new(map[string]interface{}), out: map[string]interface{}{"T": interface{}(nil)}}, 	// composite tests	{in: allValueIndent, ptr: new(All), out: allValue},	{in: allValueCompact, ptr: new(All), out: allValue},	{in: allValueIndent, ptr: new(*All), out: &allValue},	{in: allValueCompact, ptr: new(*All), out: &allValue},	{in: pallValueIndent, ptr: new(All), out: pallValue},	{in: pallValueCompact, ptr: new(All), out: pallValue},	{in: pallValueIndent, ptr: new(*All), out: &pallValue},	{in: pallValueCompact, ptr: new(*All), out: &pallValue}, 	// unmarshal interface test	{in: `{"T":false}`, ptr: &um0, out: umtrue}, // use "false" so test will fail if custom unmarshaler is not called	{in: `{"T":false}`, ptr: &ump, out: &umtrue},	{in: `[{"T":false}]`, ptr: &umslice, out: umslice},	{in: `[{"T":false}]`, ptr: &umslicep, out: &umslice},	{in: `{"M":{"T":false}}`, ptr: &umstruct, out: umstruct}, 	// UnmarshalText interface test	{in: `"X"`, ptr: &um0T, out: umtrueT}, // use "false" so test will fail if custom unmarshaler is not called	{in: `"X"`, ptr: &umpT, out: &umtrueT},	{in: `["X"]`, ptr: &umsliceT, out: umsliceT},	{in: `["X"]`, ptr: &umslicepT, out: &umsliceT},	{in: `{"M":"X"}`, ptr: &umstructT, out: umstructT}, 	// Overwriting of data.	// This is different from package xml, but it's what we've always done.	// Now documented and tested.	{in: `[2]`, ptr: sliceAddr([]int{1}), out: []int{2}},	{in: `{"key": 2}`, ptr: mapAddr(map[string]int{"old": 0, "key": 1}), out: map[string]int{"key": 2}}, 	{		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,			},		},	},	{		in:  `{"hello": 1}`,		ptr: new(Ambig),		out: Ambig{First: 1},	}, 	{		in:  `{"X": 1,"Y":2}`,		ptr: new(S5),		out: S5{S8: S8{S9: S9{Y: 2}}},	},	{		in:  `{"X": 1,"Y":2}`,		ptr: new(S10),		out: S10{S13: S13{S8: S8{S9: S9{Y: 2}}}},	}, 	// invalid UTF-8 is coerced to valid UTF-8.	{		in:  "\"hello\xffworld\"",		ptr: new(string),		out: "hello\ufffdworld",	},	{		in:  "\"hello\xc2\xc2world\"",		ptr: new(string),		out: "hello\ufffd\ufffdworld",	},	{		in:  "\"hello\xc2\xffworld\"",		ptr: new(string),		out: "hello\ufffd\ufffdworld",	},	{		in:  "\"hello\\ud800world\"",		ptr: new(string),		out: "hello\ufffdworld",	},	{		in:  "\"hello\\ud800\\ud800world\"",		ptr: new(string),		out: "hello\ufffd\ufffdworld",	},	{		in:  "\"hello\\ud800\\ud800world\"",		ptr: new(string),		out: "hello\ufffd\ufffdworld",	},	{		in:  "\"hello\xed\xa0\x80\xed\xb0\x80world\"",		ptr: new(string),		out: "hello\ufffd\ufffd\ufffd\ufffd\ufffd\ufffdworld",	}, 	// issue 8305	{		in:  `{"2009-11-10T23:00:00Z": "hello world"}`,		ptr: &map[time.Time]string{},		err: &UnmarshalTypeError{"object", reflect.TypeOf(map[time.Time]string{}), 1},	},} func TestMarshal(t *testing.T) {	b, err := Marshal(allValue)	if err != nil {		t.Fatalf("Marshal allValue: %v", err)	}	if string(b) != allValueCompact {		t.Errorf("Marshal allValueCompact")		diff(t, b, []byte(allValueCompact))		return	} 	b, err = Marshal(pallValue)	if err != nil {		t.Fatalf("Marshal pallValue: %v", err)	}	if string(b) != pallValueCompact {		t.Errorf("Marshal pallValueCompact")		diff(t, b, []byte(pallValueCompact))		return	}} var badUTF8 = []struct {	in, out string}{	{"hello\xffworld", `"hello\ufffdworld"`},	{"", `""`},	{"\xff", `"\ufffd"`},	{"\xff\xff", `"\ufffd\ufffd"`},	{"a\xffb", `"a\ufffdb"`},	{"\xe6\x97\xa5\xe6\x9c\xac\xff\xaa\x9e", `"日本\ufffd\ufffd\ufffd"`},} func TestMarshalBadUTF8(t *testing.T) {	for _, tt := range badUTF8 {		b, err := Marshal(tt.in)		if string(b) != tt.out || err != nil {			t.Errorf("Marshal(%q) = %#q, %v, want %#q, nil", tt.in, b, err, tt.out)		}	}} func TestMarshalNumberZeroVal(t *testing.T) {	var n Number	out, err := Marshal(n)	if err != nil {		t.Fatal(err)	}	outStr := string(out)	if outStr != "0" {		t.Fatalf("Invalid zero val for Number: %q", outStr)	}} func TestMarshalEmbeds(t *testing.T) {	top := &Top{		Level0: 1,		Embed0: Embed0{			Level1b: 2,			Level1c: 3,		},		Embed0a: &Embed0a{			Level1a: 5,			Level1b: 6,

Lines 1–500 of 1486.