...

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