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