Skip to content
Snippets Groups Projects
decode_test.go 32.3 KiB
Newer Older
  • Learn to ignore specific revisions
  • // 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 (
    
    type T struct {
    	X string
    	Y int
    
    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 UseNumber
    var 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.
    
    Russ Cox's avatar
    Russ Cox committed
    type ustruct struct {
    	M unmarshaler
    }
    
    
    type unmarshalerText struct {
    	T bool
    }
    
    // needed for re-marshaling tests
    func (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}}
    
    Russ Cox's avatar
    Russ Cox committed
    	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
    }
    
    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 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{}
    }
    
    
    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}},
    
    
    	{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},
    
    
    	{
    		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
    		}`,
    		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},
    			},
    		},
    	},
    	{
    		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"`},
    }
    
    
    Russ Cox's avatar
    Russ Cox committed
    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,
    		},
    		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},
    		},
    	}
    	b, err := Marshal(top)
    	if err != nil {
    		t.Fatal(err)
    	}
    	want := "{\"Level0\":1,\"Level1b\":2,\"Level1c\":3,\"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}"
    	if string(b) != want {
    		t.Errorf("Wrong marshal result.\n got: %q\nwant: %q", b, want)
    	}
    }
    
    
    func TestUnmarshal(t *testing.T) {
    	for i, tt := range unmarshalTests {
    
    		in := []byte(tt.in)
    		if err := checkValid(in, &scan); err != nil {
    
    			if !reflect.DeepEqual(err, tt.err) {
    
    				t.Errorf("#%d: checkValid: %#v", i, err)
    
    				continue
    			}
    		}
    		if tt.ptr == nil {
    
    		// v = new(right-type)
    
    Russ Cox's avatar
    Russ Cox committed
    		v := reflect.New(reflect.TypeOf(tt.ptr).Elem())
    
    		dec := NewDecoder(bytes.NewReader(in))
    
    		if tt.useNumber {
    			dec.UseNumber()
    		}
    		if err := dec.Decode(v.Interface()); !reflect.DeepEqual(err, tt.err) {
    
    			t.Errorf("#%d: %v, want %v", i, err, tt.err)
    			continue
    		} else if err != nil {
    
    			continue
    		}
    		if !reflect.DeepEqual(v.Elem().Interface(), tt.out) {
    			t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out)
    			data, _ := Marshal(v.Elem().Interface())
    			println(string(data))
    			data, _ = Marshal(tt.out)
    			println(string(data))
    			continue
    		}
    
    
    		// Check round trip.
    		if tt.err == nil {
    			enc, err := Marshal(v.Interface())
    			if err != nil {
    				t.Errorf("#%d: error re-marshaling: %v", i, err)
    				continue
    			}
    			vv := reflect.New(reflect.TypeOf(tt.ptr).Elem())
    
    			dec = NewDecoder(bytes.NewReader(enc))
    
    			if tt.useNumber {
    				dec.UseNumber()
    			}
    			if err := dec.Decode(vv.Interface()); err != nil {
    
    				t.Errorf("#%d: error re-unmarshaling %#q: %v", i, enc, err)
    
    				continue
    			}
    			if !reflect.DeepEqual(v.Elem().Interface(), vv.Elem().Interface()) {
    				t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), vv.Elem().Interface())
    
    				t.Errorf("     In: %q", strings.Map(noSpace, string(in)))
    				t.Errorf("Marshal: %q", strings.Map(noSpace, string(enc)))
    
    func TestUnmarshalMarshal(t *testing.T) {
    
    	initBig()
    
    	var v interface{}
    	if err := Unmarshal(jsonBig, &v); err != nil {
    		t.Fatalf("Unmarshal: %v", err)
    	}
    	b, err := Marshal(v)
    	if err != nil {
    		t.Fatalf("Marshal: %v", err)
    	}
    
    	if !bytes.Equal(jsonBig, b) {
    
    		t.Errorf("Marshal jsonBig")
    		diff(t, b, jsonBig)
    		return
    	}
    
    var numberTests = []struct {
    	in       string
    	i        int64
    	intErr   string
    	f        float64
    	floatErr string
    }{
    	{in: "-1.23e1", intErr: "strconv.ParseInt: parsing \"-1.23e1\": invalid syntax", f: -1.23e1},
    	{in: "-12", i: -12, f: -12.0},
    	{in: "1e1000", intErr: "strconv.ParseInt: parsing \"1e1000\": invalid syntax", floatErr: "strconv.ParseFloat: parsing \"1e1000\": value out of range"},
    }
    
    // Independent of Decode, basic coverage of the accessors in Number
    func TestNumberAccessors(t *testing.T) {
    	for _, tt := range numberTests {
    		n := Number(tt.in)
    		if s := n.String(); s != tt.in {
    			t.Errorf("Number(%q).String() is %q", tt.in, s)
    		}
    		if i, err := n.Int64(); err == nil && tt.intErr == "" && i != tt.i {
    			t.Errorf("Number(%q).Int64() is %d", tt.in, i)
    		} else if (err == nil && tt.intErr != "") || (err != nil && err.Error() != tt.intErr) {
    			t.Errorf("Number(%q).Int64() wanted error %q but got: %v", tt.in, tt.intErr, err)
    		}
    		if f, err := n.Float64(); err == nil && tt.floatErr == "" && f != tt.f {
    			t.Errorf("Number(%q).Float64() is %g", tt.in, f)
    		} else if (err == nil && tt.floatErr != "") || (err != nil && err.Error() != tt.floatErr) {
    			t.Errorf("Number(%q).Float64() wanted error %q but got: %v", tt.in, tt.floatErr, err)
    		}
    	}
    }
    
    
    func TestLargeByteSlice(t *testing.T) {
    	s0 := make([]byte, 2000)
    	for i := range s0 {
    		s0[i] = byte(i)
    	}
    	b, err := Marshal(s0)
    	if err != nil {
    		t.Fatalf("Marshal: %v", err)
    	}
    	var s1 []byte
    	if err := Unmarshal(b, &s1); err != nil {
    		t.Fatalf("Unmarshal: %v", err)
    	}
    
    		t.Errorf("Marshal large byte slice")
    		diff(t, s0, s1)
    	}
    }
    
    
    type Xint struct {
    	X int
    }
    
    func TestUnmarshalInterface(t *testing.T) {
    	var xint Xint
    	var i interface{} = &xint
    	if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil {
    		t.Fatalf("Unmarshal: %v", err)
    	}
    	if xint.X != 1 {
    		t.Fatalf("Did not write to xint")
    	}
    }
    
    func TestUnmarshalPtrPtr(t *testing.T) {
    	var xint Xint
    	pxint := &xint
    	if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil {
    		t.Fatalf("Unmarshal: %v", err)
    	}
    	if xint.X != 1 {
    		t.Fatalf("Did not write to xint")
    	}
    }
    
    
    func TestEscape(t *testing.T) {
    
    	const input = `"foobar"<html>` + " [\u2028 \u2029]"
    	const expected = `"\"foobar\"\u003chtml\u003e [\u2028 \u2029]"`
    
    	b, err := Marshal(input)
    	if err != nil {
    		t.Fatalf("Marshal error: %v", err)
    	}
    	if s := string(b); s != expected {
    
    		t.Errorf("Encoding of [%s]:\n got [%s]\nwant [%s]", input, s, expected)
    
    // WrongString is a struct that's misusing the ,string modifier.
    type WrongString struct {
    	Message string `json:"result,string"`
    }
    
    type wrongStringTest struct {
    	in, err string
    }
    
    var wrongStringTests = []wrongStringTest{
    
    	{`{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`},
    	{`{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`},
    	{`{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`},
    
    	{`{"result":123}`, `json: invalid use of ,string struct tag, trying to unmarshal unquoted value into string`},
    
    }
    
    // If people misuse the ,string modifier, the error message should be
    // helpful, telling the user that they're doing it wrong.
    func TestErrorMessageFromMisusedString(t *testing.T) {
    	for n, tt := range wrongStringTests {
    		r := strings.NewReader(tt.in)
    		var s WrongString
    		err := NewDecoder(r).Decode(&s)
    		got := fmt.Sprintf("%v", err)
    		if got != tt.err {
    			t.Errorf("%d. got err = %q, want %q", n, got, tt.err)
    		}
    	}
    }
    
    
    func noSpace(c rune) rune {
    
    	if isSpace(c) {
    		return -1
    	}
    	return c
    
    type All struct {
    	Bool    bool
    	Int     int
    	Int8    int8
    	Int16   int16
    	Int32   int32
    	Int64   int64
    	Uint    uint
    	Uint8   uint8
    	Uint16  uint16
    	Uint32  uint32
    	Uint64  uint64
    	Uintptr uintptr
    	Float32 float32
    	Float64 float64
    
    	Foo  string `json:"bar"`
    	Foo2 string `json:"bar2,dummyopt"`
    
    	PBool    *bool
    	PInt     *int
    	PInt8    *int8
    	PInt16   *int16
    	PInt32   *int32
    	PInt64   *int64
    	PUint    *uint
    	PUint8   *uint8
    	PUint16  *uint16
    	PUint32  *uint32
    	PUint64  *uint64
    	PUintptr *uintptr
    	PFloat32 *float32
    	PFloat64 *float64
    
    	String  string
    	PString *string
    
    	Map   map[string]Small
    	MapP  map[string]*Small
    	PMap  *map[string]Small
    	PMapP *map[string]*Small
    
    	EmptyMap map[string]Small
    	NilMap   map[string]Small
    
    	Slice   []Small
    	SliceP  []*Small
    	PSlice  *[]Small
    	PSliceP *[]*Small
    
    	EmptySlice []Small
    	NilSlice   []Small
    
    	StringSlice []string
    	ByteSlice   []byte
    
    	Small   Small
    	PSmall  *Small
    	PPSmall **Small
    
    	Interface  interface{}
    	PInterface *interface{}
    
    type Small struct {
    	Tag string
    
    var allValue = All{
    	Bool:    true,
    	Int:     2,
    	Int8:    3,
    	Int16:   4,
    	Int32:   5,
    	Int64:   6,
    	Uint:    7,
    	Uint8:   8,
    	Uint16:  9,
    	Uint32:  10,
    	Uint64:  11,
    	Uintptr: 12,
    	Float32: 14.1,
    	Float64: 15.1,
    	Foo:     "foo",
    
    	String:  "16",
    	Map: map[string]Small{
    
    Robert Griesemer's avatar
    Robert Griesemer committed
    		"17": {Tag: "tag17"},
    		"18": {Tag: "tag18"},
    
    	},
    	MapP: map[string]*Small{
    
    Russ Cox's avatar
    Russ Cox committed
    		"19": {Tag: "tag19"},
    
    		"20": nil,
    	},
    	EmptyMap:    map[string]Small{},
    
    Robert Griesemer's avatar
    Robert Griesemer committed
    	Slice:       []Small{{Tag: "tag20"}, {Tag: "tag21"}},
    
    Russ Cox's avatar
    Russ Cox committed
    	SliceP:      []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}},
    
    	EmptySlice:  []Small{},
    	StringSlice: []string{"str24", "str25", "str26"},
    	ByteSlice:   []byte{27, 28, 29},
    	Small:       Small{Tag: "tag30"},
    	PSmall:      &Small{Tag: "tag31"},
    
    	Interface:   5.2,
    
    var pallValue = All{
    	PBool:      &allValue.Bool,
    	PInt:       &allValue.Int,
    	PInt8:      &allValue.Int8,
    	PInt16:     &allValue.Int16,
    	PInt32:     &allValue.Int32,
    	PInt64:     &allValue.Int64,
    	PUint:      &allValue.Uint,
    	PUint8:     &allValue.Uint8,
    	PUint16:    &allValue.Uint16,
    	PUint32:    &allValue.Uint32,
    	PUint64:    &allValue.Uint64,
    	PUintptr:   &allValue.Uintptr,
    	PFloat32:   &allValue.Float32,
    	PFloat64:   &allValue.Float64,
    	PString:    &allValue.String,
    	PMap:       &allValue.Map,
    	PMapP:      &allValue.MapP,
    	PSlice:     &allValue.Slice,
    	PSliceP:    &allValue.SliceP,
    	PPSmall:    &allValue.PSmall,
    	PInterface: &allValue.Interface,
    
    var allValueIndent = `{
    
    	"Bool": true,
    	"Int": 2,
    	"Int8": 3,
    	"Int16": 4,
    	"Int32": 5,
    	"Int64": 6,
    	"Uint": 7,
    	"Uint8": 8,
    	"Uint16": 9,
    	"Uint32": 10,
    	"Uint64": 11,
    	"Uintptr": 12,
    	"Float32": 14.1,
    	"Float64": 15.1,
    
    	"bar": "foo",
    
    	"PBool": null,
    	"PInt": null,
    	"PInt8": null,
    	"PInt16": null,
    	"PInt32": null,
    	"PInt64": null,
    	"PUint": null,
    	"PUint8": null,
    	"PUint16": null,
    	"PUint32": null,
    	"PUint64": null,
    	"PUintptr": null,
    	"PFloat32": null,
    	"PFloat64": null,
    	"String": "16",
    	"PString": null,
    	"Map": {
    
    			"Tag": "tag17"
    
    			"Tag": "tag18"
    
    			"Tag": "tag19"
    
    	"PMap": null,
    	"PMapP": null,
    	"EmptyMap": {},
    	"NilMap": null,
    	"Slice": [
    
    			"Tag": "tag20"
    
    			"Tag": "tag21"
    
    	"SliceP": [
    
    			"Tag": "tag22"
    
    			"Tag": "tag23"
    
    	"PSlice": null,
    	"PSliceP": null,
    	"EmptySlice": [],
    
    	"NilSlice": null,
    
    	"StringSlice": [
    
    		"str24",
    		"str25",
    		"str26"
    	],
    
    	"ByteSlice": "Gxwd",
    
    	"Small": {
    		"Tag": "tag30"
    
    	"PSmall": {
    		"Tag": "tag31"
    
    	"PPSmall": null,
    	"Interface": 5.2,
    	"PInterface": null
    
    }`
    
    var allValueCompact = strings.Map(noSpace, allValueIndent)
    
    var pallValueIndent = `{
    
    	"Bool": false,
    	"Int": 0,
    	"Int8": 0,
    	"Int16": 0,
    	"Int32": 0,
    	"Int64": 0,
    	"Uint": 0,
    	"Uint8": 0,
    	"Uint16": 0,
    	"Uint32": 0,
    	"Uint64": 0,
    	"Uintptr": 0,
    	"Float32": 0,
    	"Float64": 0,
    
    	"PBool": true,
    	"PInt": 2,
    	"PInt8": 3,
    	"PInt16": 4,
    	"PInt32": 5,
    	"PInt64": 6,
    	"PUint": 7,
    	"PUint8": 8,
    	"PUint16": 9,
    	"PUint32": 10,
    	"PUint64": 11,
    	"PUintptr": 12,
    	"PFloat32": 14.1,
    	"PFloat64": 15.1,
    	"String": "",
    	"PString": "16",
    	"Map": null,
    	"MapP": null,
    	"PMap": {
    
    			"Tag": "tag17"
    
    			"Tag": "tag18"
    
    			"Tag": "tag19"
    
    	"EmptyMap": null,
    	"NilMap": null,
    
    	"Slice": null,
    	"SliceP": null,
    
    	"PSlice": [
    
    			"Tag": "tag20"