github.com/qiniu/dyn@v1.3.0/text/internal/encoding/json/decode_test.go (about)

     1  // Copyright 2010 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package json
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"reflect"
    11  	"strings"
    12  	"testing"
    13  )
    14  
    15  type T struct {
    16  	X string
    17  	Y int
    18  	Z int `json:"-"`
    19  }
    20  
    21  type tx struct {
    22  	x int
    23  }
    24  
    25  var txType = reflect.TypeOf((*tx)(nil)).Elem()
    26  
    27  // A type that can unmarshal itself.
    28  
    29  type unmarshaler struct {
    30  	T bool
    31  }
    32  
    33  func (u *unmarshaler) UnmarshalJSON(b []byte) error {
    34  	*u = unmarshaler{true} // All we need to see that UnmarshalJson is called.
    35  	return nil
    36  }
    37  
    38  type ustruct struct {
    39  	M unmarshaler
    40  }
    41  
    42  var (
    43  	um0, um1 unmarshaler // target2 of unmarshaling
    44  	ump      = &um1
    45  	umtrue   = unmarshaler{true}
    46  	umslice  = []unmarshaler{{true}}
    47  	umslicep = new([]unmarshaler)
    48  	umstruct = ustruct{unmarshaler{true}}
    49  )
    50  
    51  type unmarshalTest struct {
    52  	in  string
    53  	ptr interface{}
    54  	out interface{}
    55  	err error
    56  }
    57  
    58  var unmarshalTests = []unmarshalTest{
    59  	// basic types
    60  	{`true`, new(bool), true, nil},
    61  	{`1`, new(int), 1, nil},
    62  	{`1.2`, new(float64), 1.2, nil},
    63  	{`-5`, new(int16), int16(-5), nil},
    64  	{`"a\u1234"`, new(string), "a\u1234", nil},
    65  	{`"http:\/\/"`, new(string), "http://", nil},
    66  	{`"g-clef: \uD834\uDD1E"`, new(string), "g-clef: \U0001D11E", nil},
    67  	{`"invalid: \uD834x\uDD1E"`, new(string), "invalid: \uFFFDx\uFFFD", nil},
    68  	{"null", new(interface{}), nil, nil},
    69  	{`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array", reflect.TypeOf("")}},
    70  	{`{"x": 1}`, new(tx), tx{}, &UnmarshalFieldError{"x", txType, txType.Field(0)}},
    71  
    72  	// Z has a "-" tag.
    73  	{`{"Y": 1, "Z": 2}`, new(T), T{Y: 1}, nil},
    74  
    75  	// syntax errors
    76  	{`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
    77  	{`[1, 2, 3+]`, nil, nil, &SyntaxError{"invalid character '+' after array element", 9}},
    78  
    79  	// array tests
    80  	{`[1, 2, 3]`, new([3]int), [3]int{1, 2, 3}, nil},
    81  	{`[1, 2, 3]`, new([1]int), [1]int{1}, nil},
    82  	{`[1, 2, 3]`, new([5]int), [5]int{1, 2, 3, 0, 0}, nil},
    83  
    84  	// composite tests
    85  	{allValueIndent, new(All), allValue, nil},
    86  	{allValueCompact, new(All), allValue, nil},
    87  	{allValueIndent, new(*All), &allValue, nil},
    88  	{allValueCompact, new(*All), &allValue, nil},
    89  	{pallValueIndent, new(All), pallValue, nil},
    90  	{pallValueCompact, new(All), pallValue, nil},
    91  	{pallValueIndent, new(*All), &pallValue, nil},
    92  	{pallValueCompact, new(*All), &pallValue, nil},
    93  
    94  	// unmarshal interface test
    95  	{`{"T":false}`, &um0, umtrue, nil}, // use "false" so test will fail if custom unmarshaler is not called
    96  	{`{"T":false}`, &ump, &umtrue, nil},
    97  	{`[{"T":false}]`, &umslice, umslice, nil},
    98  	{`[{"T":false}]`, &umslicep, &umslice, nil},
    99  	{`{"M":{"T":false}}`, &umstruct, umstruct, nil},
   100  }
   101  
   102  func TestMarshal(t *testing.T) {
   103  	b, err := Marshal(allValue)
   104  	if err != nil {
   105  		t.Fatalf("Marshal allValue: %v", err)
   106  	}
   107  	if string(b) != allValueCompact {
   108  		t.Errorf("Marshal allValueCompact")
   109  		diff(t, b, []byte(allValueCompact))
   110  		return
   111  	}
   112  
   113  	b, err = Marshal(pallValue)
   114  	if err != nil {
   115  		t.Fatalf("Marshal pallValue: %v", err)
   116  	}
   117  	if string(b) != pallValueCompact {
   118  		t.Errorf("Marshal pallValueCompact")
   119  		diff(t, b, []byte(pallValueCompact))
   120  		return
   121  	}
   122  }
   123  
   124  func TestMarshalBadUTF8(t *testing.T) {
   125  	s := "hello\xffworld"
   126  	b, err := Marshal(s)
   127  	if err != nil {
   128  		t.Fatal("Marshal bad UTF8: no error")
   129  	}
   130  	if string(b) != `""` {
   131  		t.Fatal("Marshal returned data")
   132  	}
   133  	// if _, ok := err.(*InvalidUTF8Error); !ok {
   134  	// 	t.Fatalf("Marshal did not return InvalidUTF8Error: %T %v", err, err)
   135  	// }
   136  }
   137  
   138  func TestUnmarshal(t *testing.T) {
   139  	for i, tt := range unmarshalTests {
   140  		var scan scanner
   141  		in := []byte(tt.in)
   142  		if err := checkValid(in, &scan); err != nil {
   143  			if !reflect.DeepEqual(err, tt.err) {
   144  				t.Errorf("#%d: checkValid: %#v", i, err)
   145  				continue
   146  			}
   147  		}
   148  		if tt.ptr == nil {
   149  			continue
   150  		}
   151  		// v = new(right-type)
   152  		v := reflect.New(reflect.TypeOf(tt.ptr).Elem())
   153  		if err := Unmarshal([]byte(in), v.Interface()); !reflect.DeepEqual(err, tt.err) {
   154  			t.Errorf("#%d: %v want %v", i, err, tt.err)
   155  			continue
   156  		}
   157  		if !reflect.DeepEqual(v.Elem().Interface(), tt.out) {
   158  			t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out)
   159  			data, _ := Marshal(v.Elem().Interface())
   160  			println(string(data))
   161  			data, _ = Marshal(tt.out)
   162  			println(string(data))
   163  			continue
   164  		}
   165  	}
   166  }
   167  
   168  func TestUnmarshalMarshal(t *testing.T) {
   169  	initBig()
   170  	var v interface{}
   171  	if err := Unmarshal(jsonBig, &v); err != nil {
   172  		t.Fatalf("Unmarshal: %v", err)
   173  	}
   174  	b, err := Marshal(v)
   175  	if err != nil {
   176  		t.Fatalf("Marshal: %v", err)
   177  	}
   178  	if bytes.Compare(jsonBig, b) != 0 {
   179  		t.Errorf("Marshal jsonBig")
   180  		diff(t, b, jsonBig)
   181  		return
   182  	}
   183  }
   184  
   185  func TestLargeByteSlice(t *testing.T) {
   186  	s0 := make([]byte, 2000)
   187  	for i := range s0 {
   188  		s0[i] = byte(i)
   189  	}
   190  	b, err := Marshal(s0)
   191  	if err != nil {
   192  		t.Fatalf("Marshal: %v", err)
   193  	}
   194  	var s1 []byte
   195  	if err := Unmarshal(b, &s1); err != nil {
   196  		t.Fatalf("Unmarshal: %v", err)
   197  	}
   198  	if bytes.Compare(s0, s1) != 0 {
   199  		t.Errorf("Marshal large byte slice")
   200  		diff(t, s0, s1)
   201  	}
   202  }
   203  
   204  type Xint struct {
   205  	X int
   206  }
   207  
   208  func TestUnmarshalInterface(t *testing.T) {
   209  	var xint Xint
   210  	var i interface{} = &xint
   211  	if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil {
   212  		t.Fatalf("Unmarshal: %v", err)
   213  	}
   214  	if xint.X != 1 {
   215  		t.Fatalf("Did not write to xint")
   216  	}
   217  }
   218  
   219  func TestUnmarshalPtrPtr(t *testing.T) {
   220  	var xint Xint
   221  	pxint := &xint
   222  	if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil {
   223  		t.Fatalf("Unmarshal: %v", err)
   224  	}
   225  	if xint.X != 1 {
   226  		t.Fatalf("Did not write to xint")
   227  	}
   228  }
   229  
   230  func TestEscape(t *testing.T) {
   231  	const input = `"foobar"<html>`
   232  	const expected = `"\"foobar\"\u003chtml\u003e"`
   233  	b, err := Marshal(input)
   234  	if err != nil {
   235  		t.Fatalf("Marshal error: %v", err)
   236  	}
   237  	if s := string(b); s != expected {
   238  		t.Errorf("Encoding of [%s] was [%s], want [%s]", input, s, expected)
   239  	}
   240  }
   241  
   242  // WrongString is a struct that's misusing the ,string modifier.
   243  type WrongString struct {
   244  	Message string `json:"result,string"`
   245  }
   246  
   247  type wrongStringTest struct {
   248  	in, err string
   249  }
   250  
   251  var wrongStringTests = []wrongStringTest{
   252  	{`{"result":"x"}`, `json: invalid use of ,string struct tag, trying to unmarshal "x" into string`},
   253  	{`{"result":"foo"}`, `json: invalid use of ,string struct tag, trying to unmarshal "foo" into string`},
   254  	{`{"result":"123"}`, `json: invalid use of ,string struct tag, trying to unmarshal "123" into string`},
   255  }
   256  
   257  // If people misuse the ,string modifier, the error message should be
   258  // helpful, telling the user that they're doing it wrong.
   259  func TestErrorMessageFromMisusedString(t *testing.T) {
   260  	for n, tt := range wrongStringTests {
   261  		r := strings.NewReader(tt.in)
   262  		var s WrongString
   263  		err := NewDecoder(r).Decode(&s)
   264  		got := fmt.Sprintf("%v", err)
   265  		if got != tt.err {
   266  			t.Errorf("%d. got err = %q, want %q", n, got, tt.err)
   267  		}
   268  	}
   269  }
   270  
   271  func noSpace(c rune) rune {
   272  	if isSpace(c) {
   273  		return -1
   274  	}
   275  	return c
   276  }
   277  
   278  type All struct {
   279  	Bool    bool
   280  	Int     int
   281  	Int8    int8
   282  	Int16   int16
   283  	Int32   int32
   284  	Int64   int64
   285  	Uint    uint
   286  	Uint8   uint8
   287  	Uint16  uint16
   288  	Uint32  uint32
   289  	Uint64  uint64
   290  	Uintptr uintptr
   291  	Float32 float32
   292  	Float64 float64
   293  
   294  	Foo  string `json:"bar"`
   295  	Foo2 string `json:"bar2,dummyopt"`
   296  
   297  	IntStr int64 `json:",string"`
   298  
   299  	PBool    *bool
   300  	PInt     *int
   301  	PInt8    *int8
   302  	PInt16   *int16
   303  	PInt32   *int32
   304  	PInt64   *int64
   305  	PUint    *uint
   306  	PUint8   *uint8
   307  	PUint16  *uint16
   308  	PUint32  *uint32
   309  	PUint64  *uint64
   310  	PUintptr *uintptr
   311  	PFloat32 *float32
   312  	PFloat64 *float64
   313  
   314  	String  string
   315  	PString *string
   316  
   317  	Map   map[string]Small
   318  	MapP  map[string]*Small
   319  	PMap  *map[string]Small
   320  	PMapP *map[string]*Small
   321  
   322  	EmptyMap map[string]Small
   323  	NilMap   map[string]Small
   324  
   325  	Slice   []Small
   326  	SliceP  []*Small
   327  	PSlice  *[]Small
   328  	PSliceP *[]*Small
   329  
   330  	EmptySlice []Small
   331  	NilSlice   []Small
   332  
   333  	StringSlice []string
   334  	ByteSlice   []byte
   335  
   336  	Small   Small
   337  	PSmall  *Small
   338  	PPSmall **Small
   339  
   340  	Interface  interface{}
   341  	PInterface *interface{}
   342  
   343  	unexported int
   344  }
   345  
   346  type Small struct {
   347  	Tag string
   348  }
   349  
   350  var allValue = All{
   351  	Bool:    true,
   352  	Int:     2,
   353  	Int8:    3,
   354  	Int16:   4,
   355  	Int32:   5,
   356  	Int64:   6,
   357  	Uint:    7,
   358  	Uint8:   8,
   359  	Uint16:  9,
   360  	Uint32:  10,
   361  	Uint64:  11,
   362  	Uintptr: 12,
   363  	Float32: 14.1,
   364  	Float64: 15.1,
   365  	Foo:     "foo",
   366  	Foo2:    "foo2",
   367  	IntStr:  42,
   368  	String:  "16",
   369  	Map: map[string]Small{
   370  		"17": {Tag: "tag17"},
   371  		"18": {Tag: "tag18"},
   372  	},
   373  	MapP: map[string]*Small{
   374  		"19": {Tag: "tag19"},
   375  		"20": nil,
   376  	},
   377  	EmptyMap:    map[string]Small{},
   378  	Slice:       []Small{{Tag: "tag20"}, {Tag: "tag21"}},
   379  	SliceP:      []*Small{{Tag: "tag22"}, nil, {Tag: "tag23"}},
   380  	EmptySlice:  []Small{},
   381  	StringSlice: []string{"str24", "str25", "str26"},
   382  	ByteSlice:   []byte{27, 28, 29},
   383  	Small:       Small{Tag: "tag30"},
   384  	PSmall:      &Small{Tag: "tag31"},
   385  	Interface:   5.2,
   386  }
   387  
   388  var pallValue = All{
   389  	PBool:      &allValue.Bool,
   390  	PInt:       &allValue.Int,
   391  	PInt8:      &allValue.Int8,
   392  	PInt16:     &allValue.Int16,
   393  	PInt32:     &allValue.Int32,
   394  	PInt64:     &allValue.Int64,
   395  	PUint:      &allValue.Uint,
   396  	PUint8:     &allValue.Uint8,
   397  	PUint16:    &allValue.Uint16,
   398  	PUint32:    &allValue.Uint32,
   399  	PUint64:    &allValue.Uint64,
   400  	PUintptr:   &allValue.Uintptr,
   401  	PFloat32:   &allValue.Float32,
   402  	PFloat64:   &allValue.Float64,
   403  	PString:    &allValue.String,
   404  	PMap:       &allValue.Map,
   405  	PMapP:      &allValue.MapP,
   406  	PSlice:     &allValue.Slice,
   407  	PSliceP:    &allValue.SliceP,
   408  	PPSmall:    &allValue.PSmall,
   409  	PInterface: &allValue.Interface,
   410  }
   411  
   412  var allValueIndent = `{
   413  	"Bool": true,
   414  	"Int": 2,
   415  	"Int8": 3,
   416  	"Int16": 4,
   417  	"Int32": 5,
   418  	"Int64": 6,
   419  	"Uint": 7,
   420  	"Uint8": 8,
   421  	"Uint16": 9,
   422  	"Uint32": 10,
   423  	"Uint64": 11,
   424  	"Uintptr": 12,
   425  	"Float32": 14.1,
   426  	"Float64": 15.1,
   427  	"bar": "foo",
   428  	"bar2": "foo2",
   429  	"IntStr": "42",
   430  	"PBool": null,
   431  	"PInt": null,
   432  	"PInt8": null,
   433  	"PInt16": null,
   434  	"PInt32": null,
   435  	"PInt64": null,
   436  	"PUint": null,
   437  	"PUint8": null,
   438  	"PUint16": null,
   439  	"PUint32": null,
   440  	"PUint64": null,
   441  	"PUintptr": null,
   442  	"PFloat32": null,
   443  	"PFloat64": null,
   444  	"String": "16",
   445  	"PString": null,
   446  	"Map": {
   447  		"17": {
   448  			"Tag": "tag17"
   449  		},
   450  		"18": {
   451  			"Tag": "tag18"
   452  		}
   453  	},
   454  	"MapP": {
   455  		"19": {
   456  			"Tag": "tag19"
   457  		},
   458  		"20": null
   459  	},
   460  	"PMap": null,
   461  	"PMapP": null,
   462  	"EmptyMap": {},
   463  	"NilMap": null,
   464  	"Slice": [
   465  		{
   466  			"Tag": "tag20"
   467  		},
   468  		{
   469  			"Tag": "tag21"
   470  		}
   471  	],
   472  	"SliceP": [
   473  		{
   474  			"Tag": "tag22"
   475  		},
   476  		null,
   477  		{
   478  			"Tag": "tag23"
   479  		}
   480  	],
   481  	"PSlice": null,
   482  	"PSliceP": null,
   483  	"EmptySlice": [],
   484  	"NilSlice": null,
   485  	"StringSlice": [
   486  		"str24",
   487  		"str25",
   488  		"str26"
   489  	],
   490  	"ByteSlice": "Gxwd",
   491  	"Small": {
   492  		"Tag": "tag30"
   493  	},
   494  	"PSmall": {
   495  		"Tag": "tag31"
   496  	},
   497  	"PPSmall": null,
   498  	"Interface": 5.2,
   499  	"PInterface": null
   500  }`
   501  
   502  var allValueCompact = strings.Map(noSpace, allValueIndent)
   503  
   504  var pallValueIndent = `{
   505  	"Bool": false,
   506  	"Int": 0,
   507  	"Int8": 0,
   508  	"Int16": 0,
   509  	"Int32": 0,
   510  	"Int64": 0,
   511  	"Uint": 0,
   512  	"Uint8": 0,
   513  	"Uint16": 0,
   514  	"Uint32": 0,
   515  	"Uint64": 0,
   516  	"Uintptr": 0,
   517  	"Float32": 0,
   518  	"Float64": 0,
   519  	"bar": "",
   520  	"bar2": "",
   521          "IntStr": "0",
   522  	"PBool": true,
   523  	"PInt": 2,
   524  	"PInt8": 3,
   525  	"PInt16": 4,
   526  	"PInt32": 5,
   527  	"PInt64": 6,
   528  	"PUint": 7,
   529  	"PUint8": 8,
   530  	"PUint16": 9,
   531  	"PUint32": 10,
   532  	"PUint64": 11,
   533  	"PUintptr": 12,
   534  	"PFloat32": 14.1,
   535  	"PFloat64": 15.1,
   536  	"String": "",
   537  	"PString": "16",
   538  	"Map": null,
   539  	"MapP": null,
   540  	"PMap": {
   541  		"17": {
   542  			"Tag": "tag17"
   543  		},
   544  		"18": {
   545  			"Tag": "tag18"
   546  		}
   547  	},
   548  	"PMapP": {
   549  		"19": {
   550  			"Tag": "tag19"
   551  		},
   552  		"20": null
   553  	},
   554  	"EmptyMap": null,
   555  	"NilMap": null,
   556  	"Slice": null,
   557  	"SliceP": null,
   558  	"PSlice": [
   559  		{
   560  			"Tag": "tag20"
   561  		},
   562  		{
   563  			"Tag": "tag21"
   564  		}
   565  	],
   566  	"PSliceP": [
   567  		{
   568  			"Tag": "tag22"
   569  		},
   570  		null,
   571  		{
   572  			"Tag": "tag23"
   573  		}
   574  	],
   575  	"EmptySlice": null,
   576  	"NilSlice": null,
   577  	"StringSlice": null,
   578  	"ByteSlice": null,
   579  	"Small": {
   580  		"Tag": ""
   581  	},
   582  	"PSmall": null,
   583  	"PPSmall": {
   584  		"Tag": "tag31"
   585  	},
   586  	"Interface": null,
   587  	"PInterface": 5.2
   588  }`
   589  
   590  var pallValueCompact = strings.Map(noSpace, pallValueIndent)
   591  
   592  func TestRefUnmarshal(t *testing.T) {
   593  	type S struct {
   594  		// Ref is defined in encode_test.go.
   595  		R0 Ref
   596  		R1 *Ref
   597  	}
   598  	want := S{
   599  		R0: 12,
   600  		R1: new(Ref),
   601  	}
   602  	*want.R1 = 12
   603  
   604  	var got S
   605  	if err := Unmarshal([]byte(`{"R0":"ref","R1":"ref"}`), &got); err != nil {
   606  		t.Fatalf("Unmarshal: %v", err)
   607  	}
   608  	if !reflect.DeepEqual(got, want) {
   609  		t.Errorf("got %+v, want %+v", got, want)
   610  	}
   611  }
   612  
   613  // Test that anonymous fields are ignored.
   614  // We may assign meaning to them later.
   615  func TestAnonymous(t *testing.T) {
   616  	type S struct {
   617  		T
   618  		N int
   619  	}
   620  
   621  	data, err := Marshal(new(S))
   622  	if err != nil {
   623  		t.Fatalf("Marshal: %v", err)
   624  	}
   625  	want := `{"N":0}`
   626  	if string(data) != want {
   627  		t.Fatalf("Marshal = %#q, want %#q", string(data), want)
   628  	}
   629  
   630  	var s S
   631  	if err := Unmarshal([]byte(`{"T": 1, "T": {"Y": 1}, "N": 2}`), &s); err != nil {
   632  		t.Fatalf("Unmarshal: %v", err)
   633  	}
   634  	if s.N != 2 {
   635  		t.Fatal("Unmarshal: did not set N")
   636  	}
   637  	if s.T.Y != 0 {
   638  		t.Fatal("Unmarshal: did set T.Y")
   639  	}
   640  }
   641  
   642  // Test that the empty string doesn't panic decoding when ,string is specified
   643  // Issue 3450
   644  func TestEmptyString(t *testing.T) {
   645  	type T2 struct {
   646  		Number1 int `json:",string"`
   647  		Number2 int `json:",string"`
   648  	}
   649  	data := `{"Number1":"1", "Number2":""}`
   650  	dec := NewDecoder(strings.NewReader(data))
   651  	var t2 T2
   652  	err := dec.Decode(&t2)
   653  	if err == nil {
   654  		t.Fatal("Decode: did not return error")
   655  	}
   656  	if t2.Number1 != 1 {
   657  		t.Fatal("Decode: did not set Number1")
   658  	}
   659  }
   660  
   661  func intp(x int) *int {
   662  	p := new(int)
   663  	*p = x
   664  	return p
   665  }
   666  
   667  func intpp(x *int) **int {
   668  	pp := new(*int)
   669  	*pp = x
   670  	return pp
   671  }
   672  
   673  var interfaceSetTests = []struct {
   674  	pre  interface{}
   675  	json string
   676  	post interface{}
   677  }{
   678  	{"foo", `"bar"`, "bar"},
   679  	{"foo", `2`, 2.0},
   680  	{"foo", `true`, true},
   681  	{"foo", `null`, nil},
   682  
   683  	{nil, `null`, nil},
   684  	{new(int), `null`, nil},
   685  	{(*int)(nil), `null`, nil},
   686  	{new(*int), `null`, new(*int)},
   687  	{(**int)(nil), `null`, nil},
   688  	{intp(1), `null`, nil},
   689  	{intpp(nil), `null`, intpp(nil)},
   690  	{intpp(intp(1)), `null`, intpp(nil)},
   691  }
   692  
   693  func TestInterfaceSet(t *testing.T) {
   694  	for _, tt := range interfaceSetTests {
   695  		b := struct{ X interface{} }{tt.pre}
   696  		blob := `{"X":` + tt.json + `}`
   697  		if err := Unmarshal([]byte(blob), &b); err != nil {
   698  			t.Errorf("Unmarshal %#q: %v", blob, err)
   699  			continue
   700  		}
   701  		if !reflect.DeepEqual(b.X, tt.post) {
   702  			t.Errorf("Unmarshal %#q into %#v: X=%#v, want %#v", blob, tt.pre, b.X, tt.post)
   703  		}
   704  	}
   705  }