Skip to content

Commit

Permalink
add tests covering ResolverConfig
Browse files Browse the repository at this point in the history
  • Loading branch information
vektah committed Feb 3, 2020
1 parent f8e6196 commit 8a208af
Show file tree
Hide file tree
Showing 17 changed files with 420 additions and 100 deletions.
4 changes: 1 addition & 3 deletions cmd/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,7 @@ func initConfig(ctx *cli.Context) {
cfg = config.DefaultConfig()

cfg.Resolver = config.ResolverConfig{
PackageConfig: config.PackageConfig{
Type: "Resolver",
},
Type: "Resolver",
Layout: config.LayoutFollowSchema,
DirName: ".",
}
Expand Down
81 changes: 47 additions & 34 deletions codegen/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,31 +178,68 @@ func (a StringList) Has(file string) bool {
}

func (c *Config) Check() error {
filesMap := make(map[string]bool)
pkgConfigsByDir := make(map[string]*PackageConfig)
if c.Models == nil {
c.Models = TypeMap{}
}

type FilenamePackage struct {
Filename string
Package string
Declaree string
}

fileList := map[string][]FilenamePackage{}

if err := c.Models.Check(); err != nil {
return errors.Wrap(err, "config.models")
}
if err := c.Exec.Check(filesMap, pkgConfigsByDir); err != nil {
if err := c.Exec.Check(); err != nil {
return errors.Wrap(err, "config.exec")
}
fileList[c.Exec.ImportPath()] = append(fileList[c.Exec.ImportPath()], FilenamePackage{
Filename: c.Exec.Filename,
Package: c.Exec.Package,
Declaree: "exec",
})

if c.Model.IsDefined() {
if err := c.Model.Check(filesMap, pkgConfigsByDir); err != nil {
if err := c.Model.Check(); err != nil {
return errors.Wrap(err, "config.model")
}
fileList[c.Model.ImportPath()] = append(fileList[c.Model.ImportPath()], FilenamePackage{
Filename: c.Model.Filename,
Package: c.Model.Package,
Declaree: "model",
})
}
if c.Resolver.IsDefined() {
if err := c.Resolver.Check(filesMap, pkgConfigsByDir); err != nil {
if err := c.Resolver.Check(); err != nil {
return errors.Wrap(err, "config.resolver")
}
fileList[c.Resolver.ImportPath()] = append(fileList[c.Resolver.ImportPath()], FilenamePackage{
Filename: c.Resolver.Filename,
Package: c.Resolver.Package,
Declaree: "resolver",
})
}

for importPath, pkg := range fileList {
for _, file1 := range pkg {
for _, file2 := range pkg {
if file1.Package != file2.Package {
return fmt.Errorf("%s and %s define the same import path (%s) with different package names (%s vs %s)",
file1.Declaree,
file2.Declaree,
importPath,
file1.Package,
file2.Package,
)
}
}
}
}

return c.normalize()
}

func stripPath(path string) string {
return filepath.Base(path)
return nil
}

type TypeMap map[string]TypeMapEntry
Expand Down Expand Up @@ -302,30 +339,6 @@ func findCfgInDir(dir string) string {
return ""
}

func (c *Config) normalize() error {
if c.Model.IsDefined() {
if err := c.Model.normalize(); err != nil {
return errors.Wrap(err, "model")
}
}

if err := c.Exec.normalize(); err != nil {
return errors.Wrap(err, "exec")
}

if c.Resolver.IsDefined() {
if err := c.Resolver.normalize(); err != nil {
return errors.Wrap(err, "resolver")
}
}

if c.Models == nil {
c.Models = TypeMap{}
}

return nil
}

func (c *Config) Autobind(s *ast.Schema) error {
if len(c.AutoBind) == 0 {
return nil
Expand Down
5 changes: 1 addition & 4 deletions codegen/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,11 +110,8 @@ func TestConfigCheck(t *testing.T) {
config, err := LoadConfig("testdata/cfg/conflictedPackages.yml")
require.NoError(t, err)

err = config.normalize()
require.NoError(t, err)

err = config.Check()
require.EqualError(t, err, "config.model: filenames models.go and exec.go are in the same directory but have different package definitions (generated vs graphql)")
require.EqualError(t, err, "exec and model define the same import path (github.com/99designs/gqlgen/codegen/config/generated) with different package names (graphql vs generated)")
})
}

Expand Down
50 changes: 22 additions & 28 deletions codegen/config/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,55 +15,49 @@ type PackageConfig struct {
Type string `yaml:"type,omitempty"`
}

func (c *PackageConfig) normalize() error {
if c.Filename != "" {
c.Filename = abs(c.Filename)
}
// If Package is not set, first attempt to load the package at the output dir. If that fails
// fallback to just the base dir name of the output filename.
if c.Package == "" {
c.Package = code.NameForDir(c.Dir())
}

return nil
}

func (c *PackageConfig) ImportPath() string {
if !c.IsDefined() {
return ""
}
return code.ImportPathForDir(c.Dir())
}

func (c *PackageConfig) Dir() string {
if !c.IsDefined() {
return ""
}
return filepath.Dir(c.Filename)
}

func (c *PackageConfig) Pkg() *types.Package {
return types.NewPackage(c.ImportPath(), c.Dir())
if !c.IsDefined() {
return nil
}
return types.NewPackage(c.ImportPath(), c.Package)
}

func (c *PackageConfig) IsDefined() bool {
return c.Filename != ""
}

func (c *PackageConfig) Check(filesMap map[string]bool, pkgConfigsByDir map[string]*PackageConfig) error {
if err := c.normalize(); err != nil {
return err
}
func (c *PackageConfig) Check() error {
if strings.ContainsAny(c.Package, "./\\") {
return fmt.Errorf("package should be the output package name only, do not include the output filename")
}
if c.Filename != "" && !strings.HasSuffix(c.Filename, ".go") {
if c.Filename == "" {
return fmt.Errorf("filename must be specified")
}
if !strings.HasSuffix(c.Filename, ".go") {
return fmt.Errorf("filename should be path to a go source file")
}

_, fileFound := filesMap[c.Filename]
if fileFound {
return fmt.Errorf("filename %s defined more than once", c.Filename)
}
filesMap[c.Filename] = true
previous, inSameDir := pkgConfigsByDir[c.Dir()]
if inSameDir && c.Package != previous.Package {
return fmt.Errorf("filenames %s and %s are in the same directory but have different package definitions (%s vs %s)", stripPath(c.Filename), stripPath(previous.Filename), c.Package, previous.Package)
c.Filename = abs(c.Filename)

// If Package is not set, first attempt to load the package at the output dir. If that fails
// fallback to just the base dir name of the output filename.
if c.Package == "" {
c.Package = code.NameForDir(c.Dir())
}
pkgConfigsByDir[c.Dir()] = c

return nil
}
70 changes: 70 additions & 0 deletions codegen/config/package_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package config

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestPackageConfig(t *testing.T) {
t.Run("when given just a filename", func(t *testing.T) {
p := PackageConfig{Filename: "testdata/example.go"}
require.True(t, p.IsDefined())

require.NoError(t, p.Check())

require.Equal(t, p.Package, "config_test_data")
require.Equal(t, "github.com/99designs/gqlgen/codegen/config/testdata", p.ImportPath())

require.Equal(t, "config_test_data", p.Pkg().Name())
require.Equal(t, "github.com/99designs/gqlgen/codegen/config/testdata", p.Pkg().Path())

require.Contains(t, p.Filename, "codegen/config/testdata/example.go")
require.Contains(t, p.Dir(), "codegen/config/testdata")
})

t.Run("when given both", func(t *testing.T) {
p := PackageConfig{Filename: "testdata/example.go", Package: "wololo"}
require.True(t, p.IsDefined())

require.NoError(t, p.Check())

require.Equal(t, p.Package, "wololo")
require.Equal(t, "github.com/99designs/gqlgen/codegen/config/testdata", p.ImportPath())

require.Equal(t, "wololo", p.Pkg().Name())
require.Equal(t, "github.com/99designs/gqlgen/codegen/config/testdata", p.Pkg().Path())

require.Contains(t, p.Filename, "codegen/config/testdata/example.go")
require.Contains(t, p.Dir(), "codegen/config/testdata")
})

t.Run("when given nothing", func(t *testing.T) {
p := PackageConfig{}
require.False(t, p.IsDefined())

require.EqualError(t, p.Check(), "filename must be specified")

require.Equal(t, "", p.Package)
require.Equal(t, "", p.ImportPath())

require.Nil(t, p.Pkg())

require.Equal(t, "", p.Filename)
require.Equal(t, "", p.Dir())
})

t.Run("when given invalid filename", func(t *testing.T) {
p := PackageConfig{Filename: "wololo.sql"}
require.True(t, p.IsDefined())

require.EqualError(t, p.Check(), "filename should be path to a go source file")
})

t.Run("when package includes a filename", func(t *testing.T) {
p := PackageConfig{Filename: "foo.go", Package: "foo/foo.go"}
require.True(t, p.IsDefined())

require.EqualError(t, p.Check(), "package should be the output package name only, do not include the output filename")
})
}
69 changes: 47 additions & 22 deletions codegen/config/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import (
"fmt"
"go/types"
"path/filepath"
"strings"

"github.com/99designs/gqlgen/internal/code"
)

type ResolverConfig struct {
PackageConfig `yaml:",inline"`
Layout ResolverLayout `yaml:"layout,omitempty"`
DirName string `yaml:"dir"`
Filename string `yaml:"filename,omitempty"`
Package string `yaml:"package,omitempty"`
Type string `yaml:"type,omitempty"`
Layout ResolverLayout `yaml:"layout,omitempty"`
DirName string `yaml:"dir"`
}

type ResolverLayout string
Expand All @@ -21,32 +24,58 @@ var (
LayoutFollowSchema ResolverLayout = "follow-schema"
)

func (r *ResolverConfig) Check(filesMap map[string]bool, pkgConfigsByDir map[string]*PackageConfig) error {
if r.DirName != "" {
r.DirName = abs(r.DirName)
func (r *ResolverConfig) Check() error {
if r.Layout == "" {
r.Layout = LayoutSingleFile
}

if r.Layout == "" {
r.Layout = "single-file"
switch r.Layout {
case LayoutSingleFile:
if r.Filename == "" {
return fmt.Errorf("filename must be specified with layout=%s", r.Layout)
}
if !strings.HasSuffix(r.Filename, ".go") {
return fmt.Errorf("filename should be path to a go source file with layout=%s", r.Layout)
}
r.Filename = abs(r.Filename)
case LayoutFollowSchema:
if r.DirName == "" {
return fmt.Errorf("dirname must be specified with layout=%s", r.Layout)
}
r.DirName = abs(r.DirName)
if r.Filename == "" {
r.Filename = filepath.Join(r.DirName, "resolver.go")
} else {
r.Filename = filepath.Join(r.DirName, r.Filename)
}
default:
return fmt.Errorf("invalid layout %s. must be %s or %s", r.Layout, LayoutSingleFile, LayoutFollowSchema)
}
if r.Layout != LayoutFollowSchema && r.Layout != LayoutSingleFile {
return fmt.Errorf("invalid layout %s. must be single-file or follow-schema", r.Layout)

if strings.ContainsAny(r.Package, "./\\") {
return fmt.Errorf("package should be the output package name only, do not include the output filename")
}

if r.Layout == "follow-schema" && r.DirName == "" {
return fmt.Errorf("must specify dir when using laout:follow-schema")
if r.Package == "" && r.Dir() != "" {
r.Package = code.NameForDir(r.Dir())
}

return r.PackageConfig.Check(filesMap, pkgConfigsByDir)
return nil
}

func (r *ResolverConfig) ImportPath() string {
if r.Dir() == "" {
return ""
}
return code.ImportPathForDir(r.Dir())
}

func (r *ResolverConfig) Dir() string {
switch r.Layout {
case LayoutSingleFile:
if r.Filename == "" {
return ""
}
return filepath.Dir(r.Filename)
case LayoutFollowSchema:
return r.DirName
Expand All @@ -56,16 +85,12 @@ func (r *ResolverConfig) Dir() string {
}

func (r *ResolverConfig) Pkg() *types.Package {
return types.NewPackage(r.ImportPath(), r.Dir())
if r.Dir() == "" {
return nil
}
return types.NewPackage(r.ImportPath(), r.Package)
}

func (r *ResolverConfig) IsDefined() bool {
switch r.Layout {
case LayoutSingleFile, "":
return r.Filename != ""
case LayoutFollowSchema:
return r.DirName != ""
default:
panic(fmt.Errorf("invalid layout %s", r.Layout))
}
return r.Filename != "" || r.DirName != ""
}
Loading

0 comments on commit 8a208af

Please sign in to comment.