The Go Programming Language

Source file src/pkg/json/decode_test.go

     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		"os"
    10		"reflect"
    11		"strings"
    12		"testing"
    13	)
    14	
    15	type T struct {
    16		X string
    17		Y int
    18	}
    19	
    20	type tx struct {
    21		x int
    22	}
    23	
    24	var txType = reflect.TypeOf((*tx)(nil)).Elem()
    25	
    26	// A type that can unmarshal itself.
    27	
    28	type unmarshaler struct {
    29		T bool
    30	}
    31	
    32	func (u *unmarshaler) UnmarshalJSON(b []byte) os.Error {
    33		*u = unmarshaler{true} // All we need to see that UnmarshalJson is called.
    34		return nil
    35	}
    36	
    37	type ustruct struct {
    38		M unmarshaler
    39	}
    40	
    41	var (
    42		um0, um1 unmarshaler // target2 of unmarshaling
    43		ump      = &um1
    44		umtrue   = unmarshaler{true}
    45		umslice  = []unmarshaler{unmarshaler{true}}
    46		umslicep = new([]unmarshaler)
    47		umstruct = ustruct{unmarshaler{true}}
    48	)
    49	
    50	type unmarshalTest struct {
    51		in  string
    52		ptr interface{}
    53		out interface{}
    54		err os.Error
    55	}
    56	
    57	var unmarshalTests = []unmarshalTest{
    58		// basic types
    59		{`true`, new(bool), true, nil},
    60		{`1`, new(int), 1, nil},
    61		{`1.2`, new(float64), 1.2, nil},
    62		{`-5`, new(int16), int16(-5), nil},
    63		{`"a\u1234"`, new(string), "a\u1234", nil},
    64		{`"http:\/\/"`, new(string), "http://", nil},
    65		{`"g-clef: \uD834\uDD1E"`, new(string), "g-clef: \U0001D11E", nil},
    66		{`"invalid: \uD834x\uDD1E"`, new(string), "invalid: \uFFFDx\uFFFD", nil},
    67		{"null", new(interface{}), nil, nil},
    68		{`{"X": [1,2,3], "Y": 4}`, new(T), T{Y: 4}, &UnmarshalTypeError{"array", reflect.TypeOf("")}},
    69		{`{"x": 1}`, new(tx), tx{}, &UnmarshalFieldError{"x", txType, txType.Field(0)}},
    70	
    71		// syntax errors
    72		{`{"X": "foo", "Y"}`, nil, nil, &SyntaxError{"invalid character '}' after object key", 17}},
    73	
    74		// composite tests
    75		{allValueIndent, new(All), allValue, nil},
    76		{allValueCompact, new(All), allValue, nil},
    77		{allValueIndent, new(*All), &allValue, nil},
    78		{allValueCompact, new(*All), &allValue, nil},
    79		{pallValueIndent, new(All), pallValue, nil},
    80		{pallValueCompact, new(All), pallValue, nil},
    81		{pallValueIndent, new(*All), &pallValue, nil},
    82		{pallValueCompact, new(*All), &pallValue, nil},
    83	
    84		// unmarshal interface test
    85		{`{"T":false}`, &um0, umtrue, nil}, // use "false" so test will fail if custom unmarshaler is not called
    86		{`{"T":false}`, &ump, &umtrue, nil},
    87		{`[{"T":false}]`, &umslice, umslice, nil},
    88		{`[{"T":false}]`, &umslicep, &umslice, nil},
    89		{`{"M":{"T":false}}`, &umstruct, umstruct, nil},
    90	}
    91	
    92	func TestMarshal(t *testing.T) {
    93		b, err := Marshal(allValue)
    94		if err != nil {
    95			t.Fatalf("Marshal allValue: %v", err)
    96		}
    97		if string(b) != allValueCompact {
    98			t.Errorf("Marshal allValueCompact")
    99			diff(t, b, []byte(allValueCompact))
   100			return
   101		}
   102	
   103		b, err = Marshal(pallValue)
   104		if err != nil {
   105			t.Fatalf("Marshal pallValue: %v", err)
   106		}
   107		if string(b) != pallValueCompact {
   108			t.Errorf("Marshal pallValueCompact")
   109			diff(t, b, []byte(pallValueCompact))
   110			return
   111		}
   112	}
   113	
   114	func TestMarshalBadUTF8(t *testing.T) {
   115		s := "hello\xffworld"
   116		b, err := Marshal(s)
   117		if err == nil {
   118			t.Fatal("Marshal bad UTF8: no error")
   119		}
   120		if len(b) != 0 {
   121			t.Fatal("Marshal returned data")
   122		}
   123		if _, ok := err.(*InvalidUTF8Error); !ok {
   124			t.Fatalf("Marshal did not return InvalidUTF8Error: %T %v", err, err)
   125		}
   126	}
   127	
   128	func TestUnmarshal(t *testing.T) {
   129		for i, tt := range unmarshalTests {
   130			var scan scanner
   131			in := []byte(tt.in)
   132			if err := checkValid(in, &scan); err != nil {
   133				if !reflect.DeepEqual(err, tt.err) {
   134					t.Errorf("#%d: checkValid: %#v", i, err)
   135					continue
   136				}
   137			}
   138			if tt.ptr == nil {
   139				continue
   140			}
   141			// v = new(right-type)
   142			v := reflect.New(reflect.TypeOf(tt.ptr).Elem())
   143			if err := Unmarshal([]byte(in), v.Interface()); !reflect.DeepEqual(err, tt.err) {
   144				t.Errorf("#%d: %v want %v", i, err, tt.err)
   145				continue
   146			}
   147			if !reflect.DeepEqual(v.Elem().Interface(), tt.out) {
   148				t.Errorf("#%d: mismatch\nhave: %#+v\nwant: %#+v", i, v.Elem().Interface(), tt.out)
   149				data, _ := Marshal(v.Elem().Interface())
   150				println(string(data))
   151				data, _ = Marshal(tt.out)
   152				println(string(data))
   153				continue
   154			}
   155		}
   156	}
   157	
   158	func TestUnmarshalMarshal(t *testing.T) {
   159		initBig()
   160		var v interface{}
   161		if err := Unmarshal(jsonBig, &v); err != nil {
   162			t.Fatalf("Unmarshal: %v", err)
   163		}
   164		b, err := Marshal(v)
   165		if err != nil {
   166			t.Fatalf("Marshal: %v", err)
   167		}
   168		if bytes.Compare(jsonBig, b) != 0 {
   169			t.Errorf("Marshal jsonBig")
   170			diff(t, b, jsonBig)
   171			return
   172		}
   173	}
   174	
   175	func TestLargeByteSlice(t *testing.T) {
   176		s0 := make([]byte, 2000)
   177		for i := range s0 {
   178			s0[i] = byte(i)
   179		}
   180		b, err := Marshal(s0)
   181		if err != nil {
   182			t.Fatalf("Marshal: %v", err)
   183		}
   184		var s1 []byte
   185		if err := Unmarshal(b, &s1); err != nil {
   186			t.Fatalf("Unmarshal: %v", err)
   187		}
   188		if bytes.Compare(s0, s1) != 0 {
   189			t.Errorf("Marshal large byte slice")
   190			diff(t, s0, s1)
   191		}
   192	}
   193	
   194	type Xint struct {
   195		X int
   196	}
   197	
   198	func TestUnmarshalInterface(t *testing.T) {
   199		var xint Xint
   200		var i interface{} = &xint
   201		if err := Unmarshal([]byte(`{"X":1}`), &i); err != nil {
   202			t.Fatalf("Unmarshal: %v", err)
   203		}
   204		if xint.X != 1 {
   205			t.Fatalf("Did not write to xint")
   206		}
   207	}
   208	
   209	func TestUnmarshalPtrPtr(t *testing.T) {
   210		var xint Xint
   211		pxint := &xint
   212		if err := Unmarshal([]byte(`{"X":1}`), &pxint); err != nil {
   213			t.Fatalf("Unmarshal: %v", err)
   214		}
   215		if xint.X != 1 {
   216			t.Fatalf("Did not write to xint")
   217		}
   218	}
   219	
   220	func TestEscape(t *testing.T) {
   221		const input = `"foobar"<html>`
   222		const expected = `"\"foobar\"\u003chtml\u003e"`
   223		b, err := Marshal(input)
   224		if err != nil {
   225			t.Fatalf("Marshal error: %v", err)
   226		}
   227		if s := string(b); s != expected {
   228			t.Errorf("Encoding of [%s] was [%s], want [%s]", input, s, expected)
   229		}
   230	}
   231	
   232	func TestHTMLEscape(t *testing.T) {
   233		b, err := MarshalForHTML("foobarbaz<>&quux")
   234		if err != nil {
   235			t.Fatalf("MarshalForHTML error: %v", err)
   236		}
   237		if !bytes.Equal(b, []byte(`"foobarbaz\u003c\u003e\u0026quux"`)) {
   238			t.Fatalf("Unexpected encoding of \"<>&\": %s", b)
   239		}
   240	}
   241	
   242	func noSpace(c int) int {
   243		if isSpace(c) {
   244			return -1
   245		}
   246		return c
   247	}
   248	
   249	type All struct {
   250		Bool    bool
   251		Int     int
   252		Int8    int8
   253		Int16   int16
   254		Int32   int32
   255		Int64   int64
   256		Uint    uint
   257		Uint8   uint8
   258		Uint16  uint16
   259		Uint32  uint32
   260		Uint64  uint64
   261		Uintptr uintptr
   262		Float32 float32
   263		Float64 float64
   264	
   265		Foo  string `json:"bar"`
   266		Foo2 string `json:"bar2,dummyopt"`
   267	
   268		IntStr int64 `json:",string"`
   269	
   270		PBool    *bool
   271		PInt     *int
   272		PInt8    *int8
   273		PInt16   *int16
   274		PInt32   *int32
   275		PInt64   *int64
   276		PUint    *uint
   277		PUint8   *uint8
   278		PUint16  *uint16
   279		PUint32  *uint32
   280		PUint64  *uint64
   281		PUintptr *uintptr
   282		PFloat32 *float32
   283		PFloat64 *float64
   284	
   285		String  string
   286		PString *string
   287	
   288		Map   map[string]Small
   289		MapP  map[string]*Small
   290		PMap  *map[string]Small
   291		PMapP *map[string]*Small
   292	
   293		EmptyMap map[string]Small
   294		NilMap   map[string]Small
   295	
   296		Slice   []Small
   297		SliceP  []*Small
   298		PSlice  *[]Small
   299		PSliceP *[]*Small
   300	
   301		EmptySlice []Small
   302		NilSlice   []Small
   303	
   304		StringSlice []string
   305		ByteSlice   []byte
   306	
   307		Small   Small
   308		PSmall  *Small
   309		PPSmall **Small
   310	
   311		Interface  interface{}
   312		PInterface *interface{}
   313	
   314		unexported int
   315	}
   316	
   317	type Small struct {
   318		Tag string
   319	}
   320	
   321	var allValue = All{
   322		Bool:    true,
   323		Int:     2,
   324		Int8:    3,
   325		Int16:   4,
   326		Int32:   5,
   327		Int64:   6,
   328		Uint:    7,
   329		Uint8:   8,
   330		Uint16:  9,
   331		Uint32:  10,
   332		Uint64:  11,
   333		Uintptr: 12,
   334		Float32: 14.1,
   335		Float64: 15.1,
   336		Foo:     "foo",
   337		Foo2:    "foo2",
   338		IntStr:  42,
   339		String:  "16",
   340		Map: map[string]Small{
   341			"17": {Tag: "tag17"},
   342			"18": {Tag: "tag18"},
   343		},
   344		MapP: map[string]*Small{
   345			"19": &Small{Tag: "tag19"},
   346			"20": nil,
   347		},
   348		EmptyMap:    map[string]Small{},
   349		Slice:       []Small{{Tag: "tag20"}, {Tag: "tag21"}},
   350		SliceP:      []*Small{&Small{Tag: "tag22"}, nil, &Small{Tag: "tag23"}},
   351		EmptySlice:  []Small{},
   352		StringSlice: []string{"str24", "str25", "str26"},
   353		ByteSlice:   []byte{27, 28, 29},
   354		Small:       Small{Tag: "tag30"},
   355		PSmall:      &Small{Tag: "tag31"},
   356		Interface:   5.2,
   357	}
   358	
   359	var pallValue = All{
   360		PBool:      &allValue.Bool,
   361		PInt:       &allValue.Int,
   362		PInt8:      &allValue.Int8,
   363		PInt16:     &allValue.Int16,
   364		PInt32:     &allValue.Int32,
   365		PInt64:     &allValue.Int64,
   366		PUint:      &allValue.Uint,
   367		PUint8:     &allValue.Uint8,
   368		PUint16:    &allValue.Uint16,
   369		PUint32:    &allValue.Uint32,
   370		PUint64:    &allValue.Uint64,
   371		PUintptr:   &allValue.Uintptr,
   372		PFloat32:   &allValue.Float32,
   373		PFloat64:   &allValue.Float64,
   374		PString:    &allValue.String,
   375		PMap:       &allValue.Map,
   376		PMapP:      &allValue.MapP,
   377		PSlice:     &allValue.Slice,
   378		PSliceP:    &allValue.SliceP,
   379		PPSmall:    &allValue.PSmall,
   380		PInterface: &allValue.Interface,
   381	}
   382	
   383	var allValueIndent = `{
   384		"Bool": true,
   385		"Int": 2,
   386		"Int8": 3,
   387		"Int16": 4,
   388		"Int32": 5,
   389		"Int64": 6,
   390		"Uint": 7,
   391		"Uint8": 8,
   392		"Uint16": 9,
   393		"Uint32": 10,
   394		"Uint64": 11,
   395		"Uintptr": 12,
   396		"Float32": 14.1,
   397		"Float64": 15.1,
   398		"bar": "foo",
   399		"bar2": "foo2",
   400		"IntStr": "42",
   401		"PBool": null,
   402		"PInt": null,
   403		"PInt8": null,
   404		"PInt16": null,
   405		"PInt32": null,
   406		"PInt64": null,
   407		"PUint": null,
   408		"PUint8": null,
   409		"PUint16": null,
   410		"PUint32": null,
   411		"PUint64": null,
   412		"PUintptr": null,
   413		"PFloat32": null,
   414		"PFloat64": null,
   415		"String": "16",
   416		"PString": null,
   417		"Map": {
   418			"17": {
   419				"Tag": "tag17"
   420			},
   421			"18": {
   422				"Tag": "tag18"
   423			}
   424		},
   425		"MapP": {
   426			"19": {
   427				"Tag": "tag19"
   428			},
   429			"20": null
   430		},
   431		"PMap": null,
   432		"PMapP": null,
   433		"EmptyMap": {},
   434		"NilMap": null,
   435		"Slice": [
   436			{
   437				"Tag": "tag20"
   438			},
   439			{
   440				"Tag": "tag21"
   441			}
   442		],
   443		"SliceP": [
   444			{
   445				"Tag": "tag22"
   446			},
   447			null,
   448			{
   449				"Tag": "tag23"
   450			}
   451		],
   452		"PSlice": null,
   453		"PSliceP": null,
   454		"EmptySlice": [],
   455		"NilSlice": [],
   456		"StringSlice": [
   457			"str24",
   458			"str25",
   459			"str26"
   460		],
   461		"ByteSlice": "Gxwd",
   462		"Small": {
   463			"Tag": "tag30"
   464		},
   465		"PSmall": {
   466			"Tag": "tag31"
   467		},
   468		"PPSmall": null,
   469		"Interface": 5.2,
   470		"PInterface": null
   471	}`
   472	
   473	var allValueCompact = strings.Map(noSpace, allValueIndent)
   474	
   475	var pallValueIndent = `{
   476		"Bool": false,
   477		"Int": 0,
   478		"Int8": 0,
   479		"Int16": 0,
   480		"Int32": 0,
   481		"Int64": 0,
   482		"Uint": 0,
   483		"Uint8": 0,
   484		"Uint16": 0,
   485		"Uint32": 0,
   486		"Uint64": 0,
   487		"Uintptr": 0,
   488		"Float32": 0,
   489		"Float64": 0,
   490		"bar": "",
   491		"bar2": "",
   492	        "IntStr": "0",
   493		"PBool": true,
   494		"PInt": 2,
   495		"PInt8": 3,
   496		"PInt16": 4,
   497		"PInt32": 5,
   498		"PInt64": 6,
   499		"PUint": 7,
   500		"PUint8": 8,
   501		"PUint16": 9,
   502		"PUint32": 10,
   503		"PUint64": 11,
   504		"PUintptr": 12,
   505		"PFloat32": 14.1,
   506		"PFloat64": 15.1,
   507		"String": "",
   508		"PString": "16",
   509		"Map": null,
   510		"MapP": null,
   511		"PMap": {
   512			"17": {
   513				"Tag": "tag17"
   514			},
   515			"18": {
   516				"Tag": "tag18"
   517			}
   518		},
   519		"PMapP": {
   520			"19": {
   521				"Tag": "tag19"
   522			},
   523			"20": null
   524		},
   525		"EmptyMap": null,
   526		"NilMap": null,
   527		"Slice": [],
   528		"SliceP": [],
   529		"PSlice": [
   530			{
   531				"Tag": "tag20"
   532			},
   533			{
   534				"Tag": "tag21"
   535			}
   536		],
   537		"PSliceP": [
   538			{
   539				"Tag": "tag22"
   540			},
   541			null,
   542			{
   543				"Tag": "tag23"
   544			}
   545		],
   546		"EmptySlice": [],
   547		"NilSlice": [],
   548		"StringSlice": [],
   549		"ByteSlice": "",
   550		"Small": {
   551			"Tag": ""
   552		},
   553		"PSmall": null,
   554		"PPSmall": {
   555			"Tag": "tag31"
   556		},
   557		"Interface": null,
   558		"PInterface": 5.2
   559	}`
   560	
   561	var pallValueCompact = strings.Map(noSpace, pallValueIndent)

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.