Skip to content
Snippets Groups Projects
decode_test.go 17.9 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 unmarshalling 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
    }
    
    
    Russ Cox's avatar
    Russ Cox committed
    var txType = reflect.TypeOf((*tx)(nil)).Elem()
    
    // 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
    }
    
    
    Russ Cox's avatar
    Russ Cox committed
    type ustruct struct {
    	M unmarshaler
    }
    
    
    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}}
    
    type unmarshalTest struct {
    
    	in        string
    	ptr       interface{}
    	out       interface{}
    	err       error
    	useNumber bool
    
    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("")}},
    	{in: `{"x": 1}`, ptr: new(tx), out: tx{}, err: &UnmarshalFieldError{"x", txType, txType.Field(0)}},
    
    	{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},
    
    	// 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},
    
    	{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}},
    
    	// 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},
    
    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
    	}
    
    Russ Cox's avatar
    Russ Cox committed
    func TestMarshalBadUTF8(t *testing.T) {
    	s := "hello\xffworld"
    	b, err := Marshal(s)
    	if err == nil {
    		t.Fatal("Marshal bad UTF8: no error")
    	}
    	if len(b) != 0 {
    		t.Fatal("Marshal returned data")
    	}
    	if _, ok := err.(*InvalidUTF8Error); !ok {
    
    Rob Pike's avatar
    Rob Pike committed
    		t.Fatalf("Marshal did not return InvalidUTF8Error: %T %v", err, err)
    
    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 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 {
    
    			continue
    		}
    		// v = new(right-type)
    
    Russ Cox's avatar
    Russ Cox committed
    		v := reflect.New(reflect.TypeOf(tt.ptr).Elem())
    
    		dec := NewDecoder(bytes.NewBuffer(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
    		}
    		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.NewBuffer(enc))
    			if tt.useNumber {
    				dec.UseNumber()
    			}
    			if err := dec.Decode(vv.Interface()); err != nil {
    
    				t.Errorf("#%d: error re-unmarshaling: %v", i, 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())
    				continue
    			}
    		}
    
    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.Compare(jsonBig, b) != 0 {
    		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)
    	}
    	if bytes.Compare(s0, s1) != 0 {
    		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>`
    	const expected = `"\"foobar\"\u003chtml\u003e"`
    	b, err := Marshal(input)
    	if err != nil {
    		t.Fatalf("Marshal error: %v", err)
    	}
    	if s := string(b); s != expected {
    		t.Errorf("Encoding of [%s] was [%s], want [%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`},
    
    }
    
    // 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"
    
    			"Tag": "tag21"
    
    	"PSliceP": [
    
    			"Tag": "tag22"
    
    			"Tag": "tag23"
    
    	"EmptySlice": null,
    	"NilSlice": null,
    	"StringSlice": null,
    	"ByteSlice": null,
    
    	"Small": {
    		"Tag": ""
    
    	"PSmall": null,
    	"PPSmall": {
    		"Tag": "tag31"
    
    	"Interface": null,
    	"PInterface": 5.2
    
    }`
    
    var pallValueCompact = strings.Map(noSpace, pallValueIndent)
    
    
    func TestRefUnmarshal(t *testing.T) {
    	type S struct {
    		// Ref is defined in encode_test.go.
    		R0 Ref
    		R1 *Ref
    	}
    	want := S{
    		R0: 12,
    		R1: new(Ref),
    	}
    	*want.R1 = 12
    
    	var got S
    	if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref"}`), &got); err != nil {
    		t.Fatalf("Unmarshal: %v", err)
    	}
    	if !reflect.DeepEqual(got, want) {
    		t.Errorf("got %+v, want %+v", got, want)
    	}
    }
    
    
    // Test that anonymous fields are ignored.
    // We may assign meaning to them later.
    func TestAnonymous(t *testing.T) {
    	type S struct {
    		T
    		N int
    	}
    
    	data, err := Marshal(new(S))
    	if err != nil {
    		t.Fatalf("Marshal: %v", err)
    	}
    	want := `{"N":0}`
    	if string(data) != want {
    		t.Fatalf("Marshal = %#q, want %#q", string(data), want)
    	}
    
    	var s S
    	if err := Unmarshal([]byte(`{"T": 1, "T": {"Y": 1}, "N": 2}`), &s); err != nil {
    		t.Fatalf("Unmarshal: %v", err)
    	}
    	if s.N != 2 {
    		t.Fatal("Unmarshal: did not set N")
    	}
    	if s.T.Y != 0 {
    		t.Fatal("Unmarshal: did set T.Y")
    	}
    }
    
    
    // Test that the empty string doesn't panic decoding when ,string is specified
    // Issue 3450
    func TestEmptyString(t *testing.T) {
    	type T2 struct {
    		Number1 int `json:",string"`
    		Number2 int `json:",string"`
    	}
    	data := `{"Number1":"1", "Number2":""}`
    	dec := NewDecoder(strings.NewReader(data))
    	var t2 T2
    	err := dec.Decode(&t2)
    	if err == nil {
    		t.Fatal("Decode: did not return error")
    	}
    	if t2.Number1 != 1 {
    		t.Fatal("Decode: did not set Number1")
    	}
    }
    
    
    func intp(x int) *int {
    	p := new(int)
    	*p = x
    	return p
    }
    
    func intpp(x *int) **int {
    	pp := new(*int)
    	*pp = x
    	return pp
    }
    
    var interfaceSetTests = []struct {
    	pre  interface{}
    	json string
    	post interface{}
    }{
    	{"foo", `"bar"`, "bar"},
    	{"foo", `2`, 2.0},
    	{"foo", `true`, true},
    	{"foo", `null`, nil},
    
    	{nil, `null`, nil},
    	{new(int), `null`, nil},
    	{(*int)(nil), `null`, nil},
    	{new(*int), `null`, new(*int)},
    	{(**int)(nil), `null`, nil},
    	{intp(1), `null`, nil},
    	{intpp(nil), `null`, intpp(nil)},
    	{intpp(intp(1)), `null`, intpp(nil)},
    }
    
    func TestInterfaceSet(t *testing.T) {
    	for _, tt := range interfaceSetTests {
    		b := struct{ X interface{} }{tt.pre}
    		blob := `{"X":` + tt.json + `}`
    		if err := Unmarshal([]byte(blob), &b); err != nil {
    			t.Errorf("Unmarshal %#q: %v", blob, err)
    			continue
    		}
    		if !reflect.DeepEqual(b.X, tt.post) {
    			t.Errorf("Unmarshal %#q into %#v: X=%#v, want %#v", blob, tt.pre, b.X, tt.post)
    		}
    	}
    }