diff options
Diffstat (limited to 'src/encoding/json/decode_test.go')
| -rw-r--r-- | src/encoding/json/decode_test.go | 97 |
1 files changed, 78 insertions, 19 deletions
diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go index 27ceee471a..34b7ec6d97 100644 --- a/src/encoding/json/decode_test.go +++ b/src/encoding/json/decode_test.go @@ -195,11 +195,6 @@ type embed struct { Q int } -type Issue21357 struct { - *embed - R int -} - type Loop struct { Loop1 int `json:",omitempty"` Loop2 int `json:",omitempty"` @@ -871,20 +866,6 @@ var unmarshalTests = []unmarshalTest{ err: fmt.Errorf("json: unknown field \"extra\""), disallowUnknownFields: true, }, - - // Issue 21357. - // Ignore any embedded fields that are pointers to unexported structs. - { - in: `{"Q":1,"R":2}`, - ptr: new(Issue21357), - out: Issue21357{R: 2}, - }, - { - in: `{"Q":1,"R":2}`, - ptr: new(Issue21357), - err: fmt.Errorf("json: unknown field \"Q\""), - disallowUnknownFields: true, - }, } func TestMarshal(t *testing.T) { @@ -2107,3 +2088,81 @@ func TestInvalidStringOption(t *testing.T) { t.Fatalf("Unmarshal: %v", err) } } + +// Test unmarshal behavior with regards to embedded pointers to unexported structs. +// If unallocated, this returns an error because unmarshal cannot set the field. +// Issue 21357. +func TestUnmarshalEmbeddedPointerUnexported(t *testing.T) { + type ( + embed1 struct{ Q int } + embed2 struct{ Q int } + embed3 struct { + Q int64 `json:",string"` + } + S1 struct { + *embed1 + R int + } + S2 struct { + *embed1 + Q int + } + S3 struct { + embed1 + R int + } + S4 struct { + *embed1 + embed2 + } + S5 struct { + *embed3 + R int + } + ) + + tests := []struct { + in string + ptr interface{} + out interface{} + err error + }{{ + // Error since we cannot set S1.embed1, but still able to set S1.R. + in: `{"R":2,"Q":1}`, + ptr: new(S1), + out: &S1{R: 2}, + err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed1"), + }, { + // The top level Q field takes precedence. + in: `{"Q":1}`, + ptr: new(S2), + out: &S2{Q: 1}, + }, { + // No issue with non-pointer variant. + in: `{"R":2,"Q":1}`, + ptr: new(S3), + out: &S3{embed1: embed1{Q: 1}, R: 2}, + }, { + // No error since both embedded structs have field R, which annihilate each other. + // Thus, no attempt is made at setting S4.embed1. + in: `{"R":2}`, + ptr: new(S4), + out: new(S4), + }, { + // Error since we cannot set S5.embed1, but still able to set S5.R. + in: `{"R":2,"Q":1}`, + ptr: new(S5), + out: &S5{R: 2}, + err: fmt.Errorf("json: cannot set embedded pointer to unexported struct: json.embed3"), + }} + + for i, tt := range tests { + err := Unmarshal([]byte(tt.in), tt.ptr) + if !reflect.DeepEqual(err, tt.err) { + t.Errorf("#%d: %v, want %v", i, err, tt.err) + } + if !reflect.DeepEqual(tt.ptr, tt.out) { + t.Errorf("#%d: mismatch\ngot: %#+v\nwant: %#+v", i, tt.ptr, tt.out) + } + } +} |
