github.com/animeshon/gqlgen@v0.13.1-0.20210304133704-3a770431bb6d/codegen/field_test.go (about) 1 package codegen 2 3 import ( 4 "go/ast" 5 "go/importer" 6 "go/parser" 7 "go/token" 8 "go/types" 9 "testing" 10 11 "github.com/animeshon/gqlgen/codegen/config" 12 "github.com/stretchr/testify/require" 13 ) 14 15 func TestFindField(t *testing.T) { 16 input := ` 17 package test 18 19 type Std struct { 20 Name string 21 Value int 22 } 23 type Anon struct { 24 Name string 25 Tags 26 } 27 type Tags struct { 28 Bar string ` + "`" + `gqlgen:"foo"` + "`" + ` 29 Foo int ` + "`" + `gqlgen:"bar"` + "`" + ` 30 } 31 type Amb struct { 32 Bar string ` + "`" + `gqlgen:"foo"` + "`" + ` 33 Foo int ` + "`" + `gqlgen:"foo"` + "`" + ` 34 } 35 type Embed struct { 36 Std 37 Test string 38 } 39 ` 40 scope, err := parseScope(input, "test") 41 require.NoError(t, err) 42 43 std := scope.Lookup("Std").Type().(*types.Named) 44 anon := scope.Lookup("Anon").Type().(*types.Named) 45 tags := scope.Lookup("Tags").Type().(*types.Named) 46 amb := scope.Lookup("Amb").Type().(*types.Named) 47 embed := scope.Lookup("Embed").Type().(*types.Named) 48 49 tests := []struct { 50 Name string 51 Named *types.Named 52 Field string 53 Tag string 54 Expected string 55 ShouldError bool 56 }{ 57 {"Finds a field by name with no tag", std, "name", "", "Name", false}, 58 {"Finds a field by name when passed tag but tag not used", std, "name", "gqlgen", "Name", false}, 59 {"Ignores tags when not passed a tag", tags, "foo", "", "Foo", false}, 60 {"Picks field with tag over field name when passed a tag", tags, "foo", "gqlgen", "Bar", false}, 61 {"Errors when ambigious", amb, "foo", "gqlgen", "", true}, 62 {"Finds a field that is in embedded struct", anon, "bar", "", "Bar", false}, 63 {"Finds field that is not in embedded struct", embed, "test", "", "Test", false}, 64 } 65 66 for _, tt := range tests { 67 b := builder{Config: &config.Config{StructTag: tt.Tag}} 68 target, err := b.findBindTarget(tt.Named, tt.Field) 69 if tt.ShouldError { 70 require.Nil(t, target, tt.Name) 71 require.Error(t, err, tt.Name) 72 } else { 73 require.NoError(t, err, tt.Name) 74 require.Equal(t, tt.Expected, target.Name(), tt.Name) 75 } 76 } 77 } 78 79 func parseScope(input interface{}, packageName string) (*types.Scope, error) { 80 // test setup to parse the types 81 fset := token.NewFileSet() 82 f, err := parser.ParseFile(fset, "test.go", input, 0) 83 if err != nil { 84 return nil, err 85 } 86 87 conf := types.Config{Importer: importer.Default()} 88 pkg, err := conf.Check(packageName, fset, []*ast.File{f}, nil) 89 if err != nil { 90 return nil, err 91 } 92 93 return pkg.Scope(), nil 94 } 95 96 func TestEqualFieldName(t *testing.T) { 97 tt := []struct { 98 Name string 99 Source string 100 Target string 101 Expected bool 102 }{ 103 {Name: "words with same case", Source: "test", Target: "test", Expected: true}, 104 {Name: "words different case", Source: "test", Target: "tEsT", Expected: true}, 105 {Name: "different words", Source: "foo", Target: "bar", Expected: false}, 106 {Name: "separated with underscore", Source: "the_test", Target: "TheTest", Expected: true}, 107 {Name: "empty values", Source: "", Target: "", Expected: true}, 108 } 109 110 for _, tc := range tt { 111 t.Run(tc.Name, func(t *testing.T) { 112 result := equalFieldName(tc.Source, tc.Target) 113 require.Equal(t, tc.Expected, result) 114 }) 115 } 116 }