summaryrefslogtreecommitdiffstats
path: root/dependencies/pkg/mod/github.com/jmoiron/sqlx@v1.3.5/reflectx/reflect_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'dependencies/pkg/mod/github.com/jmoiron/sqlx@v1.3.5/reflectx/reflect_test.go')
-rw-r--r--dependencies/pkg/mod/github.com/jmoiron/sqlx@v1.3.5/reflectx/reflect_test.go1013
1 files changed, 1013 insertions, 0 deletions
diff --git a/dependencies/pkg/mod/github.com/jmoiron/sqlx@v1.3.5/reflectx/reflect_test.go b/dependencies/pkg/mod/github.com/jmoiron/sqlx@v1.3.5/reflectx/reflect_test.go
new file mode 100644
index 0000000..e73af5b
--- /dev/null
+++ b/dependencies/pkg/mod/github.com/jmoiron/sqlx@v1.3.5/reflectx/reflect_test.go
@@ -0,0 +1,1013 @@
+package reflectx
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+)
+
+func ival(v reflect.Value) int {
+ return v.Interface().(int)
+}
+
+func TestBasic(t *testing.T) {
+ type Foo struct {
+ A int
+ B int
+ C int
+ }
+
+ f := Foo{1, 2, 3}
+ fv := reflect.ValueOf(f)
+ m := NewMapperFunc("", func(s string) string { return s })
+
+ v := m.FieldByName(fv, "A")
+ if ival(v) != f.A {
+ t.Errorf("Expecting %d, got %d", ival(v), f.A)
+ }
+ v = m.FieldByName(fv, "B")
+ if ival(v) != f.B {
+ t.Errorf("Expecting %d, got %d", f.B, ival(v))
+ }
+ v = m.FieldByName(fv, "C")
+ if ival(v) != f.C {
+ t.Errorf("Expecting %d, got %d", f.C, ival(v))
+ }
+}
+
+func TestBasicEmbedded(t *testing.T) {
+ type Foo struct {
+ A int
+ }
+
+ type Bar struct {
+ Foo // `db:""` is implied for an embedded struct
+ B int
+ C int `db:"-"`
+ }
+
+ type Baz struct {
+ A int
+ Bar `db:"Bar"`
+ }
+
+ m := NewMapperFunc("db", func(s string) string { return s })
+
+ z := Baz{}
+ z.A = 1
+ z.B = 2
+ z.C = 4
+ z.Bar.Foo.A = 3
+
+ zv := reflect.ValueOf(z)
+ fields := m.TypeMap(reflect.TypeOf(z))
+
+ if len(fields.Index) != 5 {
+ t.Errorf("Expecting 5 fields")
+ }
+
+ // for _, fi := range fields.Index {
+ // log.Println(fi)
+ // }
+
+ v := m.FieldByName(zv, "A")
+ if ival(v) != z.A {
+ t.Errorf("Expecting %d, got %d", z.A, ival(v))
+ }
+ v = m.FieldByName(zv, "Bar.B")
+ if ival(v) != z.Bar.B {
+ t.Errorf("Expecting %d, got %d", z.Bar.B, ival(v))
+ }
+ v = m.FieldByName(zv, "Bar.A")
+ if ival(v) != z.Bar.Foo.A {
+ t.Errorf("Expecting %d, got %d", z.Bar.Foo.A, ival(v))
+ }
+ v = m.FieldByName(zv, "Bar.C")
+ if _, ok := v.Interface().(int); ok {
+ t.Errorf("Expecting Bar.C to not exist")
+ }
+
+ fi := fields.GetByPath("Bar.C")
+ if fi != nil {
+ t.Errorf("Bar.C should not exist")
+ }
+}
+
+func TestEmbeddedSimple(t *testing.T) {
+ type UUID [16]byte
+ type MyID struct {
+ UUID
+ }
+ type Item struct {
+ ID MyID
+ }
+ z := Item{}
+
+ m := NewMapper("db")
+ m.TypeMap(reflect.TypeOf(z))
+}
+
+func TestBasicEmbeddedWithTags(t *testing.T) {
+ type Foo struct {
+ A int `db:"a"`
+ }
+
+ type Bar struct {
+ Foo // `db:""` is implied for an embedded struct
+ B int `db:"b"`
+ }
+
+ type Baz struct {
+ A int `db:"a"`
+ Bar // `db:""` is implied for an embedded struct
+ }
+
+ m := NewMapper("db")
+
+ z := Baz{}
+ z.A = 1
+ z.B = 2
+ z.Bar.Foo.A = 3
+
+ zv := reflect.ValueOf(z)
+ fields := m.TypeMap(reflect.TypeOf(z))
+
+ if len(fields.Index) != 5 {
+ t.Errorf("Expecting 5 fields")
+ }
+
+ // for _, fi := range fields.index {
+ // log.Println(fi)
+ // }
+
+ v := m.FieldByName(zv, "a")
+ if ival(v) != z.A { // the dominant field
+ t.Errorf("Expecting %d, got %d", z.A, ival(v))
+ }
+ v = m.FieldByName(zv, "b")
+ if ival(v) != z.B {
+ t.Errorf("Expecting %d, got %d", z.B, ival(v))
+ }
+}
+
+func TestBasicEmbeddedWithSameName(t *testing.T) {
+ type Foo struct {
+ A int `db:"a"`
+ Foo int `db:"Foo"` // Same name as the embedded struct
+ }
+
+ type FooExt struct {
+ Foo
+ B int `db:"b"`
+ }
+
+ m := NewMapper("db")
+
+ z := FooExt{}
+ z.A = 1
+ z.B = 2
+ z.Foo.Foo = 3
+
+ zv := reflect.ValueOf(z)
+ fields := m.TypeMap(reflect.TypeOf(z))
+
+ if len(fields.Index) != 4 {
+ t.Errorf("Expecting 3 fields, found %d", len(fields.Index))
+ }
+
+ v := m.FieldByName(zv, "a")
+ if ival(v) != z.A { // the dominant field
+ t.Errorf("Expecting %d, got %d", z.A, ival(v))
+ }
+ v = m.FieldByName(zv, "b")
+ if ival(v) != z.B {
+ t.Errorf("Expecting %d, got %d", z.B, ival(v))
+ }
+ v = m.FieldByName(zv, "Foo")
+ if ival(v) != z.Foo.Foo {
+ t.Errorf("Expecting %d, got %d", z.Foo.Foo, ival(v))
+ }
+}
+
+func TestFlatTags(t *testing.T) {
+ m := NewMapper("db")
+
+ type Asset struct {
+ Title string `db:"title"`
+ }
+ type Post struct {
+ Author string `db:"author,required"`
+ Asset Asset `db:""`
+ }
+ // Post columns: (author title)
+
+ post := Post{Author: "Joe", Asset: Asset{Title: "Hello"}}
+ pv := reflect.ValueOf(post)
+
+ v := m.FieldByName(pv, "author")
+ if v.Interface().(string) != post.Author {
+ t.Errorf("Expecting %s, got %s", post.Author, v.Interface().(string))
+ }
+ v = m.FieldByName(pv, "title")
+ if v.Interface().(string) != post.Asset.Title {
+ t.Errorf("Expecting %s, got %s", post.Asset.Title, v.Interface().(string))
+ }
+}
+
+func TestNestedStruct(t *testing.T) {
+ m := NewMapper("db")
+
+ type Details struct {
+ Active bool `db:"active"`
+ }
+ type Asset struct {
+ Title string `db:"title"`
+ Details Details `db:"details"`
+ }
+ type Post struct {
+ Author string `db:"author,required"`
+ Asset `db:"asset"`
+ }
+ // Post columns: (author asset.title asset.details.active)
+
+ post := Post{
+ Author: "Joe",
+ Asset: Asset{Title: "Hello", Details: Details{Active: true}},
+ }
+ pv := reflect.ValueOf(post)
+
+ v := m.FieldByName(pv, "author")
+ if v.Interface().(string) != post.Author {
+ t.Errorf("Expecting %s, got %s", post.Author, v.Interface().(string))
+ }
+ v = m.FieldByName(pv, "title")
+ if _, ok := v.Interface().(string); ok {
+ t.Errorf("Expecting field to not exist")
+ }
+ v = m.FieldByName(pv, "asset.title")
+ if v.Interface().(string) != post.Asset.Title {
+ t.Errorf("Expecting %s, got %s", post.Asset.Title, v.Interface().(string))
+ }
+ v = m.FieldByName(pv, "asset.details.active")
+ if v.Interface().(bool) != post.Asset.Details.Active {
+ t.Errorf("Expecting %v, got %v", post.Asset.Details.Active, v.Interface().(bool))
+ }
+}
+
+func TestInlineStruct(t *testing.T) {
+ m := NewMapperTagFunc("db", strings.ToLower, nil)
+
+ type Employee struct {
+ Name string
+ ID int
+ }
+ type Boss Employee
+ type person struct {
+ Employee `db:"employee"`
+ Boss `db:"boss"`
+ }
+ // employees columns: (employee.name employee.id boss.name boss.id)
+
+ em := person{Employee: Employee{Name: "Joe", ID: 2}, Boss: Boss{Name: "Dick", ID: 1}}
+ ev := reflect.ValueOf(em)
+
+ fields := m.TypeMap(reflect.TypeOf(em))
+ if len(fields.Index) != 6 {
+ t.Errorf("Expecting 6 fields")
+ }
+
+ v := m.FieldByName(ev, "employee.name")
+ if v.Interface().(string) != em.Employee.Name {
+ t.Errorf("Expecting %s, got %s", em.Employee.Name, v.Interface().(string))
+ }
+ v = m.FieldByName(ev, "boss.id")
+ if ival(v) != em.Boss.ID {
+ t.Errorf("Expecting %v, got %v", em.Boss.ID, ival(v))
+ }
+}
+
+func TestRecursiveStruct(t *testing.T) {
+ type Person struct {
+ Parent *Person
+ }
+ m := NewMapperFunc("db", strings.ToLower)
+ var p *Person
+ m.TypeMap(reflect.TypeOf(p))
+}
+
+func TestFieldsEmbedded(t *testing.T) {
+ m := NewMapper("db")
+
+ type Person struct {
+ Name string `db:"name,size=64"`
+ }
+ type Place struct {
+ Name string `db:"name"`
+ }
+ type Article struct {
+ Title string `db:"title"`
+ }
+ type PP struct {
+ Person `db:"person,required"`
+ Place `db:",someflag"`
+ Article `db:",required"`
+ }
+ // PP columns: (person.name name title)
+
+ pp := PP{}
+ pp.Person.Name = "Peter"
+ pp.Place.Name = "Toronto"
+ pp.Article.Title = "Best city ever"
+
+ fields := m.TypeMap(reflect.TypeOf(pp))
+ // for i, f := range fields {
+ // log.Println(i, f)
+ // }
+
+ ppv := reflect.ValueOf(pp)
+
+ v := m.FieldByName(ppv, "person.name")
+ if v.Interface().(string) != pp.Person.Name {
+ t.Errorf("Expecting %s, got %s", pp.Person.Name, v.Interface().(string))
+ }
+
+ v = m.FieldByName(ppv, "name")
+ if v.Interface().(string) != pp.Place.Name {
+ t.Errorf("Expecting %s, got %s", pp.Place.Name, v.Interface().(string))
+ }
+
+ v = m.FieldByName(ppv, "title")
+ if v.Interface().(string) != pp.Article.Title {
+ t.Errorf("Expecting %s, got %s", pp.Article.Title, v.Interface().(string))
+ }
+
+ fi := fields.GetByPath("person")
+ if _, ok := fi.Options["required"]; !ok {
+ t.Errorf("Expecting required option to be set")
+ }
+ if !fi.Embedded {
+ t.Errorf("Expecting field to be embedded")
+ }
+ if len(fi.Index) != 1 || fi.Index[0] != 0 {
+ t.Errorf("Expecting index to be [0]")
+ }
+
+ fi = fields.GetByPath("person.name")
+ if fi == nil {
+ t.Errorf("Expecting person.name to exist")
+ }
+ if fi.Path != "person.name" {
+ t.Errorf("Expecting %s, got %s", "person.name", fi.Path)
+ }
+ if fi.Options["size"] != "64" {
+ t.Errorf("Expecting %s, got %s", "64", fi.Options["size"])
+ }
+
+ fi = fields.GetByTraversal([]int{1, 0})
+ if fi == nil {
+ t.Errorf("Expecting traveral to exist")
+ }
+ if fi.Path != "name" {
+ t.Errorf("Expecting %s, got %s", "name", fi.Path)
+ }
+
+ fi = fields.GetByTraversal([]int{2})
+ if fi == nil {
+ t.Errorf("Expecting traversal to exist")
+ }
+ if _, ok := fi.Options["required"]; !ok {
+ t.Errorf("Expecting required option to be set")
+ }
+
+ trs := m.TraversalsByName(reflect.TypeOf(pp), []string{"person.name", "name", "title"})
+ if !reflect.DeepEqual(trs, [][]int{{0, 0}, {1, 0}, {2, 0}}) {
+ t.Errorf("Expecting traversal: %v", trs)
+ }
+}
+
+func TestPtrFields(t *testing.T) {
+ m := NewMapperTagFunc("db", strings.ToLower, nil)
+ type Asset struct {
+ Title string
+ }
+ type Post struct {
+ *Asset `db:"asset"`
+ Author string
+ }
+
+ post := &Post{Author: "Joe", Asset: &Asset{Title: "Hiyo"}}
+ pv := reflect.ValueOf(post)
+
+ fields := m.TypeMap(reflect.TypeOf(post))
+ if len(fields.Index) != 3 {
+ t.Errorf("Expecting 3 fields")
+ }
+
+ v := m.FieldByName(pv, "asset.title")
+ if v.Interface().(string) != post.Asset.Title {
+ t.Errorf("Expecting %s, got %s", post.Asset.Title, v.Interface().(string))
+ }
+ v = m.FieldByName(pv, "author")
+ if v.Interface().(string) != post.Author {
+ t.Errorf("Expecting %s, got %s", post.Author, v.Interface().(string))
+ }
+}
+
+func TestNamedPtrFields(t *testing.T) {
+ m := NewMapperTagFunc("db", strings.ToLower, nil)
+
+ type User struct {
+ Name string
+ }
+
+ type Asset struct {
+ Title string
+
+ Owner *User `db:"owner"`
+ }
+ type Post struct {
+ Author string
+
+ Asset1 *Asset `db:"asset1"`
+ Asset2 *Asset `db:"asset2"`
+ }
+
+ post := &Post{Author: "Joe", Asset1: &Asset{Title: "Hiyo", Owner: &User{"Username"}}} // Let Asset2 be nil
+ pv := reflect.ValueOf(post)
+
+ fields := m.TypeMap(reflect.TypeOf(post))
+ if len(fields.Index) != 9 {
+ t.Errorf("Expecting 9 fields")
+ }
+
+ v := m.FieldByName(pv, "asset1.title")
+ if v.Interface().(string) != post.Asset1.Title {
+ t.Errorf("Expecting %s, got %s", post.Asset1.Title, v.Interface().(string))
+ }
+ v = m.FieldByName(pv, "asset1.owner.name")
+ if v.Interface().(string) != post.Asset1.Owner.Name {
+ t.Errorf("Expecting %s, got %s", post.Asset1.Owner.Name, v.Interface().(string))
+ }
+ v = m.FieldByName(pv, "asset2.title")
+ if v.Interface().(string) != post.Asset2.Title {
+ t.Errorf("Expecting %s, got %s", post.Asset2.Title, v.Interface().(string))
+ }
+ v = m.FieldByName(pv, "asset2.owner.name")
+ if v.Interface().(string) != post.Asset2.Owner.Name {
+ t.Errorf("Expecting %s, got %s", post.Asset2.Owner.Name, v.Interface().(string))
+ }
+ v = m.FieldByName(pv, "author")
+ if v.Interface().(string) != post.Author {
+ t.Errorf("Expecting %s, got %s", post.Author, v.Interface().(string))
+ }
+}
+
+func TestFieldMap(t *testing.T) {
+ type Foo struct {
+ A int
+ B int
+ C int
+ }
+
+ f := Foo{1, 2, 3}
+ m := NewMapperFunc("db", strings.ToLower)
+
+ fm := m.FieldMap(reflect.ValueOf(f))
+
+ if len(fm) != 3 {
+ t.Errorf("Expecting %d keys, got %d", 3, len(fm))
+ }
+ if fm["a"].Interface().(int) != 1 {
+ t.Errorf("Expecting %d, got %d", 1, ival(fm["a"]))
+ }
+ if fm["b"].Interface().(int) != 2 {
+ t.Errorf("Expecting %d, got %d", 2, ival(fm["b"]))
+ }
+ if fm["c"].Interface().(int) != 3 {
+ t.Errorf("Expecting %d, got %d", 3, ival(fm["c"]))
+ }
+}
+
+func TestTagNameMapping(t *testing.T) {
+ type Strategy struct {
+ StrategyID string `protobuf:"bytes,1,opt,name=strategy_id" json:"strategy_id,omitempty"`
+ StrategyName string
+ }
+
+ m := NewMapperTagFunc("json", strings.ToUpper, func(value string) string {
+ if strings.Contains(value, ",") {
+ return strings.Split(value, ",")[0]
+ }
+ return value
+ })
+ strategy := Strategy{"1", "Alpah"}
+ mapping := m.TypeMap(reflect.TypeOf(strategy))
+
+ for _, key := range []string{"strategy_id", "STRATEGYNAME"} {
+ if fi := mapping.GetByPath(key); fi == nil {
+ t.Errorf("Expecting to find key %s in mapping but did not.", key)
+ }
+ }
+}
+
+func TestMapping(t *testing.T) {
+ type Person struct {
+ ID int
+ Name string
+ WearsGlasses bool `db:"wears_glasses"`
+ }
+
+ m := NewMapperFunc("db", strings.ToLower)
+ p := Person{1, "Jason", true}
+ mapping := m.TypeMap(reflect.TypeOf(p))
+
+ for _, key := range []string{"id", "name", "wears_glasses"} {
+ if fi := mapping.GetByPath(key); fi == nil {
+ t.Errorf("Expecting to find key %s in mapping but did not.", key)
+ }
+ }
+
+ type SportsPerson struct {
+ Weight int
+ Age int
+ Person
+ }
+ s := SportsPerson{Weight: 100, Age: 30, Person: p}
+ mapping = m.TypeMap(reflect.TypeOf(s))
+ for _, key := range []string{"id", "name", "wears_glasses", "weight", "age"} {
+ if fi := mapping.GetByPath(key); fi == nil {
+ t.Errorf("Expecting to find key %s in mapping but did not.", key)
+ }
+ }
+
+ type RugbyPlayer struct {
+ Position int
+ IsIntense bool `db:"is_intense"`
+ IsAllBlack bool `db:"-"`
+ SportsPerson
+ }
+ r := RugbyPlayer{12, true, false, s}
+ mapping = m.TypeMap(reflect.TypeOf(r))
+ for _, key := range []string{"id", "name", "wears_glasses", "weight", "age", "position", "is_intense"} {
+ if fi := mapping.GetByPath(key); fi == nil {
+ t.Errorf("Expecting to find key %s in mapping but did not.", key)
+ }
+ }
+
+ if fi := mapping.GetByPath("isallblack"); fi != nil {
+ t.Errorf("Expecting to ignore `IsAllBlack` field")
+ }
+}
+
+func TestGetByTraversal(t *testing.T) {
+ type C struct {
+ C0 int
+ C1 int
+ }
+ type B struct {
+ B0 string
+ B1 *C
+ }
+ type A struct {
+ A0 int
+ A1 B
+ }
+
+ testCases := []struct {
+ Index []int
+ ExpectedName string
+ ExpectNil bool
+ }{
+ {
+ Index: []int{0},
+ ExpectedName: "A0",
+ },
+ {
+ Index: []int{1, 0},
+ ExpectedName: "B0",
+ },
+ {
+ Index: []int{1, 1, 1},
+ ExpectedName: "C1",
+ },
+ {
+ Index: []int{3, 4, 5},
+ ExpectNil: true,
+ },
+ {
+ Index: []int{},
+ ExpectNil: true,
+ },
+ {
+ Index: nil,
+ ExpectNil: true,
+ },
+ }
+
+ m := NewMapperFunc("db", func(n string) string { return n })
+ tm := m.TypeMap(reflect.TypeOf(A{}))
+
+ for i, tc := range testCases {
+ fi := tm.GetByTraversal(tc.Index)
+ if tc.ExpectNil {
+ if fi != nil {
+ t.Errorf("%d: expected nil, got %v", i, fi)
+ }
+ continue
+ }
+
+ if fi == nil {
+ t.Errorf("%d: expected %s, got nil", i, tc.ExpectedName)
+ continue
+ }
+
+ if fi.Name != tc.ExpectedName {
+ t.Errorf("%d: expected %s, got %s", i, tc.ExpectedName, fi.Name)
+ }
+ }
+}
+
+// TestMapperMethodsByName tests Mapper methods FieldByName and TraversalsByName
+func TestMapperMethodsByName(t *testing.T) {
+ type C struct {
+ C0 string
+ C1 int
+ }
+ type B struct {
+ B0 *C `db:"B0"`
+ B1 C `db:"B1"`
+ B2 string `db:"B2"`
+ }
+ type A struct {
+ A0 *B `db:"A0"`
+ B `db:"A1"`
+ A2 int
+ a3 int
+ }
+
+ val := &A{
+ A0: &B{
+ B0: &C{C0: "0", C1: 1},
+ B1: C{C0: "2", C1: 3},
+ B2: "4",
+ },
+ B: B{
+ B0: nil,
+ B1: C{C0: "5", C1: 6},
+ B2: "7",
+ },
+ A2: 8,
+ }
+
+ testCases := []struct {
+ Name string
+ ExpectInvalid bool
+ ExpectedValue interface{}
+ ExpectedIndexes []int
+ }{
+ {
+ Name: "A0.B0.C0",
+ ExpectedValue: "0",
+ ExpectedIndexes: []int{0, 0, 0},
+ },
+ {
+ Name: "A0.B0.C1",
+ ExpectedValue: 1,
+ ExpectedIndexes: []int{0, 0, 1},
+ },
+ {
+ Name: "A0.B1.C0",
+ ExpectedValue: "2",
+ ExpectedIndexes: []int{0, 1, 0},
+ },
+ {
+ Name: "A0.B1.C1",
+ ExpectedValue: 3,
+ ExpectedIndexes: []int{0, 1, 1},
+ },
+ {
+ Name: "A0.B2",
+ ExpectedValue: "4",
+ ExpectedIndexes: []int{0, 2},
+ },
+ {
+ Name: "A1.B0.C0",
+ ExpectedValue: "",
+ ExpectedIndexes: []int{1, 0, 0},
+ },
+ {
+ Name: "A1.B0.C1",
+ ExpectedValue: 0,
+ ExpectedIndexes: []int{1, 0, 1},
+ },
+ {
+ Name: "A1.B1.C0",
+ ExpectedValue: "5",
+ ExpectedIndexes: []int{1, 1, 0},
+ },
+ {
+ Name: "A1.B1.C1",
+ ExpectedValue: 6,
+ ExpectedIndexes: []int{1, 1, 1},
+ },
+ {
+ Name: "A1.B2",
+ ExpectedValue: "7",
+ ExpectedIndexes: []int{1, 2},
+ },
+ {
+ Name: "A2",
+ ExpectedValue: 8,
+ ExpectedIndexes: []int{2},
+ },
+ {
+ Name: "XYZ",
+ ExpectInvalid: true,
+ ExpectedIndexes: []int{},
+ },
+ {
+ Name: "a3",
+ ExpectInvalid: true,
+ ExpectedIndexes: []int{},
+ },
+ }
+
+ // build the names array from the test cases
+ names := make([]string, len(testCases))
+ for i, tc := range testCases {
+ names[i] = tc.Name
+ }
+ m := NewMapperFunc("db", func(n string) string { return n })
+ v := reflect.ValueOf(val)
+ values := m.FieldsByName(v, names)
+ if len(values) != len(testCases) {
+ t.Errorf("expected %d values, got %d", len(testCases), len(values))
+ t.FailNow()
+ }
+ indexes := m.TraversalsByName(v.Type(), names)
+ if len(indexes) != len(testCases) {
+ t.Errorf("expected %d traversals, got %d", len(testCases), len(indexes))
+ t.FailNow()
+ }
+ for i, val := range values {
+ tc := testCases[i]
+ traversal := indexes[i]
+ if !reflect.DeepEqual(tc.ExpectedIndexes, traversal) {
+ t.Errorf("expected %v, got %v", tc.ExpectedIndexes, traversal)
+ t.FailNow()
+ }
+ val = reflect.Indirect(val)
+ if tc.ExpectInvalid {
+ if val.IsValid() {
+ t.Errorf("%d: expected zero value, got %v", i, val)
+ }
+ continue
+ }
+ if !val.IsValid() {
+ t.Errorf("%d: expected valid value, got %v", i, val)
+ continue
+ }
+ actualValue := reflect.Indirect(val).Interface()
+ if !reflect.DeepEqual(tc.ExpectedValue, actualValue) {
+ t.Errorf("%d: expected %v, got %v", i, tc.ExpectedValue, actualValue)
+ }
+ }
+}
+
+func TestFieldByIndexes(t *testing.T) {
+ type C struct {
+ C0 bool
+ C1 string
+ C2 int
+ C3 map[string]int
+ }
+ type B struct {
+ B1 C
+ B2 *C
+ }
+ type A struct {
+ A1 B
+ A2 *B
+ }
+ testCases := []struct {
+ value interface{}
+ indexes []int
+ expectedValue interface{}
+ readOnly bool
+ }{
+ {
+ value: A{
+ A1: B{B1: C{C0: true}},
+ },
+ indexes: []int{0, 0, 0},
+ expectedValue: true,
+ readOnly: true,
+ },
+ {
+ value: A{
+ A2: &B{B2: &C{C1: "answer"}},
+ },
+ indexes: []int{1, 1, 1},
+ expectedValue: "answer",
+ readOnly: true,
+ },
+ {
+ value: &A{},
+ indexes: []int{1, 1, 3},
+ expectedValue: map[string]int{},
+ },
+ }
+
+ for i, tc := range testCases {
+ checkResults := func(v reflect.Value) {
+ if tc.expectedValue == nil {
+ if !v.IsNil() {
+ t.Errorf("%d: expected nil, actual %v", i, v.Interface())
+ }
+ } else {
+ if !reflect.DeepEqual(tc.expectedValue, v.Interface()) {
+ t.Errorf("%d: expected %v, actual %v", i, tc.expectedValue, v.Interface())
+ }
+ }
+ }
+
+ checkResults(FieldByIndexes(reflect.ValueOf(tc.value), tc.indexes))
+ if tc.readOnly {
+ checkResults(FieldByIndexesReadOnly(reflect.ValueOf(tc.value), tc.indexes))
+ }
+ }
+}
+
+func TestMustBe(t *testing.T) {
+ typ := reflect.TypeOf(E1{})
+ mustBe(typ, reflect.Struct)
+
+ defer func() {
+ if r := recover(); r != nil {
+ valueErr, ok := r.(*reflect.ValueError)
+ if !ok {
+ t.Errorf("unexpected Method: %s", valueErr.Method)
+ t.Error("expected panic with *reflect.ValueError")
+ return
+ }
+ if valueErr.Method != "github.com/jmoiron/sqlx/reflectx.TestMustBe" {
+ }
+ if valueErr.Kind != reflect.String {
+ t.Errorf("unexpected Kind: %s", valueErr.Kind)
+ }
+ } else {
+ t.Error("expected panic")
+ }
+ }()
+
+ typ = reflect.TypeOf("string")
+ mustBe(typ, reflect.Struct)
+ t.Error("got here, didn't expect to")
+}
+
+type E1 struct {
+ A int
+}
+type E2 struct {
+ E1
+ B int
+}
+type E3 struct {
+ E2
+ C int
+}
+type E4 struct {
+ E3
+ D int
+}
+
+func BenchmarkFieldNameL1(b *testing.B) {
+ e4 := E4{D: 1}
+ for i := 0; i < b.N; i++ {
+ v := reflect.ValueOf(e4)
+ f := v.FieldByName("D")
+ if f.Interface().(int) != 1 {
+ b.Fatal("Wrong value.")
+ }
+ }
+}
+
+func BenchmarkFieldNameL4(b *testing.B) {
+ e4 := E4{}
+ e4.A = 1
+ for i := 0; i < b.N; i++ {
+ v := reflect.ValueOf(e4)
+ f := v.FieldByName("A")
+ if f.Interface().(int) != 1 {
+ b.Fatal("Wrong value.")
+ }
+ }
+}
+
+func BenchmarkFieldPosL1(b *testing.B) {
+ e4 := E4{D: 1}
+ for i := 0; i < b.N; i++ {
+ v := reflect.ValueOf(e4)
+ f := v.Field(1)
+ if f.Interface().(int) != 1 {
+ b.Fatal("Wrong value.")
+ }
+ }
+}
+
+func BenchmarkFieldPosL4(b *testing.B) {
+ e4 := E4{}
+ e4.A = 1
+ for i := 0; i < b.N; i++ {
+ v := reflect.ValueOf(e4)
+ f := v.Field(0)
+ f = f.Field(0)
+ f = f.Field(0)
+ f = f.Field(0)
+ if f.Interface().(int) != 1 {
+ b.Fatal("Wrong value.")
+ }
+ }
+}
+
+func BenchmarkFieldByIndexL4(b *testing.B) {
+ e4 := E4{}
+ e4.A = 1
+ idx := []int{0, 0, 0, 0}
+ for i := 0; i < b.N; i++ {
+ v := reflect.ValueOf(e4)
+ f := FieldByIndexes(v, idx)
+ if f.Interface().(int) != 1 {
+ b.Fatal("Wrong value.")
+ }
+ }
+}
+
+func BenchmarkTraversalsByName(b *testing.B) {
+ type A struct {
+ Value int
+ }
+
+ type B struct {
+ A A
+ }
+
+ type C struct {
+ B B
+ }
+
+ type D struct {
+ C C
+ }
+
+ m := NewMapper("")
+ t := reflect.TypeOf(D{})
+ names := []string{"C", "B", "A", "Value"}
+
+ b.ResetTimer()
+
+ for i := 0; i < b.N; i++ {
+ if l := len(m.TraversalsByName(t, names)); l != len(names) {
+ b.Errorf("expected %d values, got %d", len(names), l)
+ }
+ }
+}
+
+func BenchmarkTraversalsByNameFunc(b *testing.B) {
+ type A struct {
+ Z int
+ }
+
+ type B struct {
+ A A
+ }
+
+ type C struct {
+ B B
+ }
+
+ type D struct {
+ C C
+ }
+
+ m := NewMapper("")
+ t := reflect.TypeOf(D{})
+ names := []string{"C", "B", "A", "Z", "Y"}
+
+ b.ResetTimer()
+
+ for i := 0; i < b.N; i++ {
+ var l int
+
+ if err := m.TraversalsByNameFunc(t, names, func(_ int, _ []int) error {
+ l++
+ return nil
+ }); err != nil {
+ b.Errorf("unexpected error %s", err)
+ }
+
+ if l != len(names) {
+ b.Errorf("expected %d values, got %d", len(names), l)
+ }
+ }
+}