Black Lives Matter. Support the Equal Justice Initiative.

Source file src/reflect/visiblefields_test.go

Documentation: reflect

     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  
     5  package reflect_test
     6  
     7  import (
     8  	. "reflect"
     9  	"testing"
    10  )
    11  
    12  type structField struct {
    13  	name  string
    14  	index []int
    15  }
    16  
    17  var 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  
   212  type SFG struct {
   213  	F int
   214  	G int
   215  }
   216  
   217  type SFG1 struct {
   218  	SFG
   219  }
   220  
   221  type SFG2 struct {
   222  	SFG1
   223  }
   224  
   225  type SFGH struct {
   226  	F int
   227  	G int
   228  	H int
   229  }
   230  
   231  type SFGH1 struct {
   232  	SFGH
   233  }
   234  
   235  type SFGH2 struct {
   236  	SFGH1
   237  }
   238  
   239  type SFGH3 struct {
   240  	SFGH2
   241  }
   242  
   243  type SF struct {
   244  	F int
   245  }
   246  
   247  type SF1 struct {
   248  	SF
   249  }
   250  
   251  type SF2 struct {
   252  	SF1
   253  }
   254  
   255  type SG struct {
   256  	G int
   257  }
   258  
   259  type SG1 struct {
   260  	SG
   261  }
   262  
   263  type sFG struct {
   264  	F int
   265  	G int
   266  }
   267  
   268  type RS1 struct {
   269  	i int
   270  }
   271  
   272  type RS2 struct {
   273  	RS1
   274  }
   275  
   276  type RS3 struct {
   277  	RS2
   278  	RS1
   279  }
   280  
   281  type M map[string]interface{}
   282  
   283  type Rec1 struct {
   284  	*Rec2
   285  }
   286  
   287  type Rec2 struct {
   288  	F string
   289  	*Rec1
   290  }
   291  
   292  func 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  

View as plain text