summaryrefslogtreecommitdiffstats
path: root/src/reflect/visiblefields_test.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 13:16:40 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 13:16:40 +0000
commit47ab3d4a42e9ab51c465c4322d2ec233f6324e6b (patch)
treea61a0ffd83f4a3def4b36e5c8e99630c559aa723 /src/reflect/visiblefields_test.go
parentInitial commit. (diff)
downloadgolang-1.18-upstream.tar.xz
golang-1.18-upstream.zip
Adding upstream version 1.18.10.upstream/1.18.10upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/reflect/visiblefields_test.go')
-rw-r--r--src/reflect/visiblefields_test.go349
1 files changed, 349 insertions, 0 deletions
diff --git a/src/reflect/visiblefields_test.go b/src/reflect/visiblefields_test.go
new file mode 100644
index 0000000..fdedc21
--- /dev/null
+++ b/src/reflect/visiblefields_test.go
@@ -0,0 +1,349 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package reflect_test
+
+import (
+ . "reflect"
+ "strings"
+ "testing"
+)
+
+type structField struct {
+ name string
+ index []int
+}
+
+var fieldsTests = []struct {
+ testName string
+ val any
+ expect []structField
+}{{
+ testName: "SimpleStruct",
+ val: struct {
+ A int
+ B string
+ C bool
+ }{},
+ expect: []structField{{
+ name: "A",
+ index: []int{0},
+ }, {
+ name: "B",
+ index: []int{1},
+ }, {
+ name: "C",
+ index: []int{2},
+ }},
+}, {
+ testName: "NonEmbeddedStructMember",
+ val: struct {
+ A struct {
+ X int
+ }
+ }{},
+ expect: []structField{{
+ name: "A",
+ index: []int{0},
+ }},
+}, {
+ testName: "EmbeddedExportedStruct",
+ val: struct {
+ SFG
+ }{},
+ expect: []structField{{
+ name: "SFG",
+ index: []int{0},
+ }, {
+ name: "F",
+ index: []int{0, 0},
+ }, {
+ name: "G",
+ index: []int{0, 1},
+ }},
+}, {
+ testName: "EmbeddedUnexportedStruct",
+ val: struct {
+ sFG
+ }{},
+ expect: []structField{{
+ name: "sFG",
+ index: []int{0},
+ }, {
+ name: "F",
+ index: []int{0, 0},
+ }, {
+ name: "G",
+ index: []int{0, 1},
+ }},
+}, {
+ testName: "TwoEmbeddedStructsWithCancellingMembers",
+ val: struct {
+ SFG
+ SF
+ }{},
+ expect: []structField{{
+ name: "SFG",
+ index: []int{0},
+ }, {
+ name: "G",
+ index: []int{0, 1},
+ }, {
+ name: "SF",
+ index: []int{1},
+ }},
+}, {
+ testName: "EmbeddedStructsWithSameFieldsAtDifferentDepths",
+ val: struct {
+ SFGH3
+ SG1
+ SFG2
+ SF2
+ L int
+ }{},
+ expect: []structField{{
+ name: "SFGH3",
+ index: []int{0},
+ }, {
+ name: "SFGH2",
+ index: []int{0, 0},
+ }, {
+ name: "SFGH1",
+ index: []int{0, 0, 0},
+ }, {
+ name: "SFGH",
+ index: []int{0, 0, 0, 0},
+ }, {
+ name: "H",
+ index: []int{0, 0, 0, 0, 2},
+ }, {
+ name: "SG1",
+ index: []int{1},
+ }, {
+ name: "SG",
+ index: []int{1, 0},
+ }, {
+ name: "G",
+ index: []int{1, 0, 0},
+ }, {
+ name: "SFG2",
+ index: []int{2},
+ }, {
+ name: "SFG1",
+ index: []int{2, 0},
+ }, {
+ name: "SFG",
+ index: []int{2, 0, 0},
+ }, {
+ name: "SF2",
+ index: []int{3},
+ }, {
+ name: "SF1",
+ index: []int{3, 0},
+ }, {
+ name: "SF",
+ index: []int{3, 0, 0},
+ }, {
+ name: "L",
+ index: []int{4},
+ }},
+}, {
+ testName: "EmbeddedPointerStruct",
+ val: struct {
+ *SF
+ }{},
+ expect: []structField{{
+ name: "SF",
+ index: []int{0},
+ }, {
+ name: "F",
+ index: []int{0, 0},
+ }},
+}, {
+ testName: "EmbeddedNotAPointer",
+ val: struct {
+ M
+ }{},
+ expect: []structField{{
+ name: "M",
+ index: []int{0},
+ }},
+}, {
+ testName: "RecursiveEmbedding",
+ val: Rec1{},
+ expect: []structField{{
+ name: "Rec2",
+ index: []int{0},
+ }, {
+ name: "F",
+ index: []int{0, 0},
+ }, {
+ name: "Rec1",
+ index: []int{0, 1},
+ }},
+}, {
+ testName: "RecursiveEmbedding2",
+ val: Rec2{},
+ expect: []structField{{
+ name: "F",
+ index: []int{0},
+ }, {
+ name: "Rec1",
+ index: []int{1},
+ }, {
+ name: "Rec2",
+ index: []int{1, 0},
+ }},
+}, {
+ testName: "RecursiveEmbedding3",
+ val: RS3{},
+ expect: []structField{{
+ name: "RS2",
+ index: []int{0},
+ }, {
+ name: "RS1",
+ index: []int{1},
+ }, {
+ name: "i",
+ index: []int{1, 0},
+ }},
+}}
+
+type SFG struct {
+ F int
+ G int
+}
+
+type SFG1 struct {
+ SFG
+}
+
+type SFG2 struct {
+ SFG1
+}
+
+type SFGH struct {
+ F int
+ G int
+ H int
+}
+
+type SFGH1 struct {
+ SFGH
+}
+
+type SFGH2 struct {
+ SFGH1
+}
+
+type SFGH3 struct {
+ SFGH2
+}
+
+type SF struct {
+ F int
+}
+
+type SF1 struct {
+ SF
+}
+
+type SF2 struct {
+ SF1
+}
+
+type SG struct {
+ G int
+}
+
+type SG1 struct {
+ SG
+}
+
+type sFG struct {
+ F int
+ G int
+}
+
+type RS1 struct {
+ i int
+}
+
+type RS2 struct {
+ RS1
+}
+
+type RS3 struct {
+ RS2
+ RS1
+}
+
+type M map[string]any
+
+type Rec1 struct {
+ *Rec2
+}
+
+type Rec2 struct {
+ F string
+ *Rec1
+}
+
+func TestFields(t *testing.T) {
+ for _, test := range fieldsTests {
+ test := test
+ t.Run(test.testName, func(t *testing.T) {
+ typ := TypeOf(test.val)
+ fields := VisibleFields(typ)
+ if got, want := len(fields), len(test.expect); got != want {
+ t.Fatalf("unexpected field count; got %d want %d", got, want)
+ }
+
+ for j, field := range fields {
+ expect := test.expect[j]
+ t.Logf("field %d: %s", j, expect.name)
+ gotField := typ.FieldByIndex(field.Index)
+ // Unfortunately, FieldByIndex does not return
+ // a field with the same index that we passed in,
+ // so we set it to the expected value so that
+ // it can be compared later with the result of FieldByName.
+ gotField.Index = field.Index
+ expectField := typ.FieldByIndex(expect.index)
+ // ditto.
+ expectField.Index = expect.index
+ if !DeepEqual(gotField, expectField) {
+ t.Fatalf("unexpected field result\ngot %#v\nwant %#v", gotField, expectField)
+ }
+
+ // Sanity check that we can actually access the field by the
+ // expected name.
+ gotField1, ok := typ.FieldByName(expect.name)
+ if !ok {
+ t.Fatalf("field %q not accessible by name", expect.name)
+ }
+ if !DeepEqual(gotField1, expectField) {
+ t.Fatalf("unexpected FieldByName result; got %#v want %#v", gotField1, expectField)
+ }
+ }
+ })
+ }
+}
+
+// Must not panic with nil embedded pointer.
+func TestFieldByIndexErr(t *testing.T) {
+ type A struct {
+ S string
+ }
+ type B struct {
+ *A
+ }
+ v := ValueOf(B{})
+ _, err := v.FieldByIndexErr([]int{0, 0})
+ if err == nil {
+ t.Fatal("expected error")
+ }
+ if !strings.Contains(err.Error(), "embedded struct field A") {
+ t.Fatal(err)
+ }
+}