github.com/kerryoscer/gqlgen@v0.17.29/codegen/config/config_test.go (about)

     1  package config
     2  
     3  import (
     4  	"errors"
     5  	"io/fs"
     6  	"os"
     7  	"path/filepath"
     8  	"runtime"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  	"github.com/vektah/gqlparser/v2/ast"
    14  
    15  	"github.com/kerryoscer/gqlgen/internal/code"
    16  )
    17  
    18  func TestLoadConfig(t *testing.T) {
    19  	t.Run("config does not exist", func(t *testing.T) {
    20  		_, err := LoadConfig("doesnotexist.yml")
    21  		require.Error(t, err)
    22  	})
    23  
    24  	t.Run("malformed config", func(t *testing.T) {
    25  		_, err := LoadConfig("testdata/cfg/malformedconfig.yml")
    26  		require.EqualError(t, err, "unable to parse config: yaml: unmarshal errors:\n  line 1: cannot unmarshal !!str `asdf` into config.Config")
    27  	})
    28  
    29  	t.Run("unknown keys", func(t *testing.T) {
    30  		_, err := LoadConfig("testdata/cfg/unknownkeys.yml")
    31  		require.EqualError(t, err, "unable to parse config: yaml: unmarshal errors:\n  line 2: field unknown not found in type config.Config")
    32  	})
    33  
    34  	t.Run("globbed filenames", func(t *testing.T) {
    35  		c, err := LoadConfig("testdata/cfg/glob.yml")
    36  		require.NoError(t, err)
    37  
    38  		if runtime.GOOS == "windows" {
    39  			require.Equal(t, c.SchemaFilename[0], `testdata\cfg\glob\bar\bar with spaces.graphql`)
    40  			require.Equal(t, c.SchemaFilename[1], `testdata\cfg\glob\foo\foo.graphql`)
    41  		} else {
    42  			require.Equal(t, c.SchemaFilename[0], "testdata/cfg/glob/bar/bar with spaces.graphql")
    43  			require.Equal(t, c.SchemaFilename[1], "testdata/cfg/glob/foo/foo.graphql")
    44  		}
    45  	})
    46  
    47  	t.Run("unwalkable path", func(t *testing.T) {
    48  		_, err := LoadConfig("testdata/cfg/unwalkable.yml")
    49  		if runtime.GOOS == "windows" {
    50  			require.EqualError(t, err, "failed to walk schema at root not_walkable/: CreateFile not_walkable/: The system cannot find the file specified.")
    51  		} else {
    52  			require.EqualError(t, err, "failed to walk schema at root not_walkable/: lstat not_walkable/: no such file or directory")
    53  		}
    54  	})
    55  }
    56  
    57  func TestLoadConfigFromDefaultLocation(t *testing.T) {
    58  	testDir, err := os.Getwd()
    59  	require.NoError(t, err)
    60  	var cfg *Config
    61  
    62  	t.Run("will find closest match", func(t *testing.T) {
    63  		err = os.Chdir(filepath.Join(testDir, "testdata", "cfg", "subdir"))
    64  		require.NoError(t, err)
    65  
    66  		cfg, err = LoadConfigFromDefaultLocations()
    67  		require.NoError(t, err)
    68  		require.Equal(t, StringList{"inner"}, cfg.SchemaFilename)
    69  	})
    70  
    71  	t.Run("will find config in parent dirs", func(t *testing.T) {
    72  		err = os.Chdir(filepath.Join(testDir, "testdata", "cfg", "otherdir"))
    73  		require.NoError(t, err)
    74  
    75  		cfg, err = LoadConfigFromDefaultLocations()
    76  		require.NoError(t, err)
    77  		require.Equal(t, StringList{"outer"}, cfg.SchemaFilename)
    78  	})
    79  
    80  	t.Run("will return error if config doesn't exist", func(t *testing.T) {
    81  		err = os.Chdir(testDir)
    82  		require.NoError(t, err)
    83  
    84  		cfg, err = LoadConfigFromDefaultLocations()
    85  		require.True(t, errors.Is(err, fs.ErrNotExist))
    86  	})
    87  }
    88  
    89  func TestLoadDefaultConfig(t *testing.T) {
    90  	testDir, err := os.Getwd()
    91  	require.NoError(t, err)
    92  	var cfg *Config
    93  
    94  	t.Run("will find the schema", func(t *testing.T) {
    95  		err = os.Chdir(filepath.Join(testDir, "testdata", "defaultconfig"))
    96  		require.NoError(t, err)
    97  
    98  		cfg, err = LoadDefaultConfig()
    99  		require.NoError(t, err)
   100  		require.NotEmpty(t, cfg.Sources)
   101  	})
   102  
   103  	t.Run("will return error if schema doesn't exist", func(t *testing.T) {
   104  		err = os.Chdir(testDir)
   105  		require.NoError(t, err)
   106  
   107  		cfg, err = LoadDefaultConfig()
   108  		require.True(t, errors.Is(err, fs.ErrNotExist))
   109  	})
   110  }
   111  
   112  func TestReferencedPackages(t *testing.T) {
   113  	t.Run("valid", func(t *testing.T) {
   114  		tm := TypeMap{
   115  			"Foo": {Model: StringList{"github.com/test.Foo"}},
   116  			"Bar": {Model: StringList{"github.com/test.Bar"}},
   117  			"Baz": {Model: StringList{"github.com/otherpkg.Baz"}},
   118  			"Map": {Model: StringList{"map[string]interface{}"}},
   119  			"SkipResolver": {
   120  				Fields: map[string]TypeMapField{
   121  					"field": {Resolver: false},
   122  				},
   123  			},
   124  		}
   125  
   126  		pkgs := tm.ReferencedPackages()
   127  
   128  		assert.Equal(t, []string{"github.com/test", "github.com/otherpkg"}, pkgs)
   129  	})
   130  }
   131  
   132  func TestConfigCheck(t *testing.T) {
   133  	for _, execLayout := range []ExecLayout{ExecLayoutSingleFile, ExecLayoutFollowSchema} {
   134  		t.Run(string(execLayout), func(t *testing.T) {
   135  			t.Run("invalid config format due to conflicting package names", func(t *testing.T) {
   136  				config := Config{
   137  					Exec:  ExecConfig{Layout: execLayout, Filename: "generated/exec.go", DirName: "generated", Package: "graphql"},
   138  					Model: PackageConfig{Filename: "generated/models.go"},
   139  				}
   140  
   141  				require.EqualError(t, config.check(), "exec and model define the same import path (github.com/99designs/gqlgen/codegen/config/generated) with different package names (graphql vs generated)")
   142  			})
   143  
   144  			t.Run("federation must be in exec package", func(t *testing.T) {
   145  				config := Config{
   146  					Exec:       ExecConfig{Layout: execLayout, Filename: "generated/exec.go", DirName: "generated"},
   147  					Federation: PackageConfig{Filename: "anotherpkg/federation.go"},
   148  				}
   149  
   150  				require.EqualError(t, config.check(), "federation and exec must be in the same package")
   151  			})
   152  
   153  			t.Run("federation must have same package name as exec", func(t *testing.T) {
   154  				config := Config{
   155  					Exec:       ExecConfig{Layout: execLayout, Filename: "generated/exec.go", DirName: "generated"},
   156  					Federation: PackageConfig{Filename: "generated/federation.go", Package: "federation"},
   157  				}
   158  
   159  				require.EqualError(t, config.check(), "exec and federation define the same import path (github.com/99designs/gqlgen/codegen/config/generated) with different package names (generated vs federation)")
   160  			})
   161  
   162  			t.Run("deprecated federated flag raises an error", func(t *testing.T) {
   163  				config := Config{
   164  					Exec:      ExecConfig{Layout: execLayout, Filename: "generated/exec.go", DirName: "generated"},
   165  					Federated: true,
   166  				}
   167  
   168  				require.EqualError(t, config.check(), "federated has been removed, instead use\nfederation:\n    filename: path/to/federated.go")
   169  			})
   170  		})
   171  	}
   172  }
   173  
   174  func TestAutobinding(t *testing.T) {
   175  	t.Run("valid paths", func(t *testing.T) {
   176  		cfg := Config{
   177  			Models: TypeMap{},
   178  			AutoBind: []string{
   179  				"github.com/kerryoscer/gqlgen/codegen/config/testdata/autobinding/chat",
   180  				"github.com/kerryoscer/gqlgen/codegen/config/testdata/autobinding/scalars/model",
   181  			},
   182  			Packages: &code.Packages{},
   183  		}
   184  
   185  		cfg.Schema = gqlparser.MustLoadSchema(&ast.Source{Name: "TestAutobinding.schema", Input: `
   186  			scalar Banned
   187  			type Message { id: ID }
   188  		`})
   189  
   190  		require.NoError(t, cfg.autobind())
   191  
   192  		require.Equal(t, "github.com/kerryoscer/gqlgen/codegen/config/testdata/autobinding/scalars/model.Banned", cfg.Models["Banned"].Model[0])
   193  		require.Equal(t, "github.com/kerryoscer/gqlgen/codegen/config/testdata/autobinding/chat.Message", cfg.Models["Message"].Model[0])
   194  	})
   195  
   196  	t.Run("with file path", func(t *testing.T) {
   197  		cfg := Config{
   198  			Models: TypeMap{},
   199  			AutoBind: []string{
   200  				"../chat",
   201  			},
   202  			Packages: &code.Packages{},
   203  		}
   204  
   205  		cfg.Schema = gqlparser.MustLoadSchema(&ast.Source{Name: "TestAutobinding.schema", Input: `
   206  			scalar Banned
   207  			type Message { id: ID }
   208  		`})
   209  
   210  		require.EqualError(t, cfg.autobind(), "unable to load ../chat - make sure you're using an import path to a package that exists")
   211  	})
   212  }