1// Copyright 2021 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
5package reflect_test
6
7import (
8	. "reflect"
9	"testing"
10)
11
12type structField struct {
13	name  string
14	index []int
15}
16
17var fieldsTests = []struct {
18	testName string
19	val      interface{}
20	expect   []structField
21}{{
22	testName: "SimpleStruct",
23	val: struct {
24		A int
25		B string
26		C bool
27	}{},
28	expect: []structField{{
29		name:  "A",
30		index: []int{0},
31	}, {
32		name:  "B",
33		index: []int{1},
34	}, {
35		name:  "C",
36		index: []int{2},
37	}},
38}, {
39	testName: "NonEmbeddedStructMember",
40	val: struct {
41		A struct {
42			X int
43		}
44	}{},
45	expect: []structField{{
46		name:  "A",
47		index: []int{0},
48	}},
49}, {
50	testName: "EmbeddedExportedStruct",
51	val: struct {
52		SFG
53	}{},
54	expect: []structField{{
55		name:  "SFG",
56		index: []int{0},
57	}, {
58		name:  "F",
59		index: []int{0, 0},
60	}, {
61		name:  "G",
62		index: []int{0, 1},
63	}},
64}, {
65	testName: "EmbeddedUnexportedStruct",
66	val: struct {
67		sFG
68	}{},
69	expect: []structField{{
70		name:  "sFG",
71		index: []int{0},
72	}, {
73		name:  "F",
74		index: []int{0, 0},
75	}, {
76		name:  "G",
77		index: []int{0, 1},
78	}},
79}, {
80	testName: "TwoEmbeddedStructsWithCancellingMembers",
81	val: struct {
82		SFG
83		SF
84	}{},
85	expect: []structField{{
86		name:  "SFG",
87		index: []int{0},
88	}, {
89		name:  "G",
90		index: []int{0, 1},
91	}, {
92		name:  "SF",
93		index: []int{1},
94	}},
95}, {
96	testName: "EmbeddedStructsWithSameFieldsAtDifferentDepths",
97	val: struct {
98		SFGH3
99		SG1
100		SFG2
101		SF2
102		L int
103	}{},
104	expect: []structField{{
105		name:  "SFGH3",
106		index: []int{0},
107	}, {
108		name:  "SFGH2",
109		index: []int{0, 0},
110	}, {
111		name:  "SFGH1",
112		index: []int{0, 0, 0},
113	}, {
114		name:  "SFGH",
115		index: []int{0, 0, 0, 0},
116	}, {
117		name:  "H",
118		index: []int{0, 0, 0, 0, 2},
119	}, {
120		name:  "SG1",
121		index: []int{1},
122	}, {
123		name:  "SG",
124		index: []int{1, 0},
125	}, {
126		name:  "G",
127		index: []int{1, 0, 0},
128	}, {
129		name:  "SFG2",
130		index: []int{2},
131	}, {
132		name:  "SFG1",
133		index: []int{2, 0},
134	}, {
135		name:  "SFG",
136		index: []int{2, 0, 0},
137	}, {
138		name:  "SF2",
139		index: []int{3},
140	}, {
141		name:  "SF1",
142		index: []int{3, 0},
143	}, {
144		name:  "SF",
145		index: []int{3, 0, 0},
146	}, {
147		name:  "L",
148		index: []int{4},
149	}},
150}, {
151	testName: "EmbeddedPointerStruct",
152	val: struct {
153		*SF
154	}{},
155	expect: []structField{{
156		name:  "SF",
157		index: []int{0},
158	}, {
159		name:  "F",
160		index: []int{0, 0},
161	}},
162}, {
163	testName: "EmbeddedNotAPointer",
164	val: struct {
165		M
166	}{},
167	expect: []structField{{
168		name:  "M",
169		index: []int{0},
170	}},
171}, {
172	testName: "RecursiveEmbedding",
173	val:      Rec1{},
174	expect: []structField{{
175		name:  "Rec2",
176		index: []int{0},
177	}, {
178		name:  "F",
179		index: []int{0, 0},
180	}, {
181		name:  "Rec1",
182		index: []int{0, 1},
183	}},
184}, {
185	testName: "RecursiveEmbedding2",
186	val:      Rec2{},
187	expect: []structField{{
188		name:  "F",
189		index: []int{0},
190	}, {
191		name:  "Rec1",
192		index: []int{1},
193	}, {
194		name:  "Rec2",
195		index: []int{1, 0},
196	}},
197}, {
198	testName: "RecursiveEmbedding3",
199	val:      RS3{},
200	expect: []structField{{
201		name:  "RS2",
202		index: []int{0},
203	}, {
204		name:  "RS1",
205		index: []int{1},
206	}, {
207		name:  "i",
208		index: []int{1, 0},
209	}},
210}}
211
212type SFG struct {
213	F int
214	G int
215}
216
217type SFG1 struct {
218	SFG
219}
220
221type SFG2 struct {
222	SFG1
223}
224
225type SFGH struct {
226	F int
227	G int
228	H int
229}
230
231type SFGH1 struct {
232	SFGH
233}
234
235type SFGH2 struct {
236	SFGH1
237}
238
239type SFGH3 struct {
240	SFGH2
241}
242
243type SF struct {
244	F int
245}
246
247type SF1 struct {
248	SF
249}
250
251type SF2 struct {
252	SF1
253}
254
255type SG struct {
256	G int
257}
258
259type SG1 struct {
260	SG
261}
262
263type sFG struct {
264	F int
265	G int
266}
267
268type RS1 struct {
269	i int
270}
271
272type RS2 struct {
273	RS1
274}
275
276type RS3 struct {
277	RS2
278	RS1
279}
280
281type M map[string]interface{}
282
283type Rec1 struct {
284	*Rec2
285}
286
287type Rec2 struct {
288	F string
289	*Rec1
290}
291
292func TestFields(t *testing.T) {
293	for _, test := range fieldsTests {
294		test := test
295		t.Run(test.testName, func(t *testing.T) {
296			typ := TypeOf(test.val)
297			fields := VisibleFields(typ)
298			if got, want := len(fields), len(test.expect); got != want {
299				t.Fatalf("unexpected field count; got %d want %d", got, want)
300			}
301
302			for j, field := range fields {
303				expect := test.expect[j]
304				t.Logf("field %d: %s", j, expect.name)
305				gotField := typ.FieldByIndex(field.Index)
306				// Unfortunately, FieldByIndex does not return
307				// a field with the same index that we passed in,
308				// so we set it to the expected value so that
309				// it can be compared later with the result of FieldByName.
310				gotField.Index = field.Index
311				expectField := typ.FieldByIndex(expect.index)
312				// ditto.
313				expectField.Index = expect.index
314				if !DeepEqual(gotField, expectField) {
315					t.Fatalf("unexpected field result\ngot %#v\nwant %#v", gotField, expectField)
316				}
317
318				// Sanity check that we can actually access the field by the
319				// expected name.
320				gotField1, ok := typ.FieldByName(expect.name)
321				if !ok {
322					t.Fatalf("field %q not accessible by name", expect.name)
323				}
324				if !DeepEqual(gotField1, expectField) {
325					t.Fatalf("unexpected FieldByName result; got %#v want %#v", gotField1, expectField)
326				}
327			}
328		})
329	}
330}
331