Commit dc368086 authored by Daniel Martí's avatar Daniel Martí

encoding/json: more tests to cover decoding edge cases

The overall coverage of the json package goes up from 90.8% to 91.3%.

While at it, apply two minor code simplifications found while inspecting
the HTML coverage report.

Change-Id: I0fba968afeedc813b1385e4bde72d93b878854d7
Reviewed-on: https://go-review.googlesource.com/134735
Run-TryBot: Daniel Martí <mvdan@mvdan.cc>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent 023dbb18
...@@ -24,6 +24,7 @@ runtime/asm_ARCHSUFF.s: [GOARCH] gcWriteBarrier: function gcWriteBarrier missing ...@@ -24,6 +24,7 @@ runtime/asm_ARCHSUFF.s: [GOARCH] gcWriteBarrier: function gcWriteBarrier missing
// in bad situations that vet can also detect statically. // in bad situations that vet can also detect statically.
encoding/json/decode_test.go: struct field m has json tag but is not exported encoding/json/decode_test.go: struct field m has json tag but is not exported
encoding/json/decode_test.go: struct field m2 has json tag but is not exported encoding/json/decode_test.go: struct field m2 has json tag but is not exported
encoding/json/decode_test.go: struct field s has json tag but is not exported
encoding/json/tagkey_test.go: struct field tag `:"BadFormat"` not compatible with reflect.StructTag.Get: bad syntax for struct tag key encoding/json/tagkey_test.go: struct field tag `:"BadFormat"` not compatible with reflect.StructTag.Get: bad syntax for struct tag key
runtime/testdata/testprog/deadlock.go: unreachable code runtime/testdata/testprog/deadlock.go: unreachable code
runtime/testdata/testprog/deadlock.go: unreachable code runtime/testdata/testprog/deadlock.go: unreachable code
......
...@@ -533,8 +533,7 @@ func (d *decodeState) array(v reflect.Value) error { ...@@ -533,8 +533,7 @@ func (d *decodeState) array(v reflect.Value) error {
d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)}) d.saveError(&UnmarshalTypeError{Value: "array", Type: v.Type(), Offset: int64(d.off)})
d.skip() d.skip()
return nil return nil
case reflect.Array: case reflect.Array, reflect.Slice:
case reflect.Slice:
break break
} }
...@@ -871,18 +870,16 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool ...@@ -871,18 +870,16 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
if item[0] != '"' { if item[0] != '"' {
if fromQuoted { if fromQuoted {
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())) d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
} else { return nil
var val string }
switch item[0] { val := "number"
case 'n': switch item[0] {
val = "null" case 'n':
case 't', 'f': val = "null"
val = "bool" case 't', 'f':
default: val = "bool"
val = "number"
}
d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())})
} }
d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())})
return nil return nil
} }
s, ok := unquoteBytes(item) s, ok := unquoteBytes(item)
......
...@@ -445,6 +445,7 @@ var unmarshalTests = []unmarshalTest{ ...@@ -445,6 +445,7 @@ var unmarshalTests = []unmarshalTest{
{in: `{"X": "foo", "Y"}`, err: &SyntaxError{"invalid character '}' after object key", 17}}, {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: `[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: `{"X":12x}`, err: &SyntaxError{"invalid character 'x' after object key:value pair", 8}, useNumber: true},
{in: `[2, 3`, err: &SyntaxError{msg: "unexpected end of JSON input", Offset: 5}},
// raw value errors // raw value errors
{in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}}, {in: "\x01 42", err: &SyntaxError{"invalid character '\\x01' looking for beginning of value", 1}},
...@@ -460,6 +461,7 @@ var unmarshalTests = []unmarshalTest{ ...@@ -460,6 +461,7 @@ var unmarshalTests = []unmarshalTest{
{in: `[1, 2, 3]`, ptr: new([3]int), out: [3]int{1, 2, 3}}, {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([1]int), out: [1]int{1}},
{in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}}, {in: `[1, 2, 3]`, ptr: new([5]int), out: [5]int{1, 2, 3, 0, 0}},
{in: `[1, 2, 3]`, ptr: new(MustNotUnmarshalJSON), err: errors.New("MustNotUnmarshalJSON was used")},
// empty array to interface test // empty array to interface test
{in: `[]`, ptr: new([]interface{}), out: []interface{}{}}, {in: `[]`, ptr: new([]interface{}), out: []interface{}{}},
...@@ -826,6 +828,7 @@ var unmarshalTests = []unmarshalTest{ ...@@ -826,6 +828,7 @@ var unmarshalTests = []unmarshalTest{
{in: `{"B": "False"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "False" into bool`)}, {in: `{"B": "False"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "False" into bool`)},
{in: `{"B": "null"}`, ptr: new(B), out: B{false}}, {in: `{"B": "null"}`, ptr: new(B), out: B{false}},
{in: `{"B": "nul"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "nul" into bool`)}, {in: `{"B": "nul"}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal "nul" into bool`)},
{in: `{"B": [2, 3]}`, ptr: new(B), err: errors.New(`json: invalid use of ,string struct tag, trying to unmarshal unquoted value into bool`)},
// additional tests for disallowUnknownFields // additional tests for disallowUnknownFields
{ {
...@@ -894,6 +897,18 @@ var unmarshalTests = []unmarshalTest{ ...@@ -894,6 +897,18 @@ var unmarshalTests = []unmarshalTest{
ptr: new(mapStringToStringData), ptr: new(mapStringToStringData),
err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 21, Struct: "mapStringToStringData", Field: "data"}, err: &UnmarshalTypeError{Value: "number", Type: reflect.TypeOf(""), Offset: 21, Struct: "mapStringToStringData", Field: "data"},
}, },
// trying to decode JSON arrays or objects via TextUnmarshaler
{
in: `[1, 2, 3]`,
ptr: new(MustNotUnmarshalText),
err: &UnmarshalTypeError{Value: "array", Type: reflect.TypeOf(&MustNotUnmarshalText{}), Offset: 1},
},
{
in: `{"foo": "bar"}`,
ptr: new(MustNotUnmarshalText),
err: &UnmarshalTypeError{Value: "object", Type: reflect.TypeOf(&MustNotUnmarshalText{}), Offset: 1},
},
} }
func TestMarshal(t *testing.T) { func TestMarshal(t *testing.T) {
...@@ -1955,10 +1970,12 @@ type unexportedFields struct { ...@@ -1955,10 +1970,12 @@ type unexportedFields struct {
Name string Name string
m map[string]interface{} `json:"-"` m map[string]interface{} `json:"-"`
m2 map[string]interface{} `json:"abcd"` m2 map[string]interface{} `json:"abcd"`
s []int `json:"-"`
} }
func TestUnmarshalUnexported(t *testing.T) { func TestUnmarshalUnexported(t *testing.T) {
input := `{"Name": "Bob", "m": {"x": 123}, "m2": {"y": 456}, "abcd": {"z": 789}}` input := `{"Name": "Bob", "m": {"x": 123}, "m2": {"y": 456}, "abcd": {"z": 789}, "s": [2, 3]}`
want := &unexportedFields{Name: "Bob"} want := &unexportedFields{Name: "Bob"}
out := &unexportedFields{} out := &unexportedFields{}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment