aboutsummaryrefslogtreecommitdiff
path: root/src/encoding/json/decode_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/encoding/json/decode_test.go')
-rw-r--r--src/encoding/json/decode_test.go97
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)
+ }
+ }
+}