Skip to content

Commit

Permalink
Merge pull request #258 from SteveRuble/fix/only-used-models-slices
Browse files Browse the repository at this point in the history
fix: onlyUsedModels now detects slice elements
  • Loading branch information
Yamashou authored Dec 23, 2024
2 parents d41b2ca + 9248c4f commit 8973cc0
Show file tree
Hide file tree
Showing 9 changed files with 304 additions and 3 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,7 @@
/.idea/

coverage.out
.vscode/
.vscode/

# Actual files output by the end-to-end tests
generator/testdata/**/actual
15 changes: 15 additions & 0 deletions TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,18 @@ or the following to see the result in your browser
```shell script
go tool cover -html=coverage.out
```


# End-to-End Testing

The `generator` package contains tests which
run the full generator pipeline
and support assertions on the generated code.

To create such a test,
copy one of the directories in `generator/testdata`
and modify the files to express your test case,
then run the tests with `go test ./generator/testdata/...`.
The test will check that the generated code compiles
and that the generated code matches the files in the
`expected` directory.
138 changes: 138 additions & 0 deletions generator/generator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
package generator_test

import (
"context"
"github.com/Yamashou/gqlgenc/config"
"github.com/Yamashou/gqlgenc/generator"
"github.com/stretchr/testify/suite"
"golang.org/x/tools/go/packages"
"os"
"path/filepath"
"testing"
)

type Suite struct {
suite.Suite
}

func TestSuite(t *testing.T) {
suite.Run(t, new(Suite))
}

const (
expected = "expected"
actual = "actual"
)

func (s *Suite) TestGenerator_withTestData() {

dirs := s.getTestDirs()

for _, dir := range dirs {
s.Run(dir, func() {

// temporary change working directory
s.useDirForTest(filepath.Join("testdata", dir))

// load config
cfg, err := config.LoadConfig("./gqlgenc.yml")
s.Require().NoError(err)

// disable unnecessary validations
cfg.GQLConfig.SkipValidation = true
cfg.GQLConfig.SkipModTidy = true

// generate code
err = generator.Generate(context.Background(), cfg)
s.Require().NoError(err)

// load all files
expectedFiles := s.loadFiles(expected)
actualFiles := s.loadFiles(actual)

s.Require().NotEmpty(actualFiles, "no actual files found")

// verify that generated code compiles
pkgs, err := packages.Load(&packages.Config{Mode: packages.NeedTypes}, "./"+actual)
s.Require().NoError(err)
s.Require().Len(pkgs, 1)
s.Empty(pkgs[0].Errors)

// reset expected files if there are no expected files,
// allowing reset of expected files by removing them
if len(expectedFiles) == 0 {
for path, content := range actualFiles {
s.T().Logf("resetting expected file %s", path)
expectedPath := filepath.Join(expected, path)
_ = os.MkdirAll(filepath.Dir(expectedPath), 0700)
err = os.WriteFile(expectedPath, []byte(content), 0644)
s.Require().NoError(err)
}
return
}

// compare expected and actual files
for path, expectedContent := range expectedFiles {
actualContent, ok := actualFiles[path]
if s.True(ok, "expected file %s not found", path) {
s.Equal(expectedContent, actualContent)
}
}
})
}
}

// useDir changes the current working directory to the given directory
// and returns a function that can be used to restore the original
// working directory.
func (s *Suite) useDirForTest(dir string) {
wd, err := os.Getwd()
s.Require().NoError(err)
err = os.Chdir(dir)
s.Require().NoError(err)

// cleanup actual directory
_ = os.RemoveAll(filepath.Join(dir, actual))

s.T().Cleanup(func() {
s.Require().NoError(os.Chdir(wd))
})
}

func (s *Suite) loadFiles(dir string) map[string]string {
files := make(map[string]string)
if _, err := os.Stat(dir); os.IsNotExist(err) {
return files
}
err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if info.IsDir() {
return nil
}
content, err := os.ReadFile(path)
if err != nil {
return err
}
rel, err := filepath.Rel(dir, path)
if err != nil {
return err

}
files[rel] = string(content)
return nil
})
s.Require().NoError(err)
return files
}

func (s *Suite) getTestDirs() []string {
dirs, err := os.ReadDir("testdata")
s.Require().NoError(err)
var testDirs []string
for _, dir := range dirs {
if !dir.IsDir() {
continue
}
testDirs = append(testDirs, dir.Name())
}
return testDirs
}
80 changes: 80 additions & 0 deletions generator/testdata/only_used_models/expected/client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions generator/testdata/only_used_models/expected/models_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions generator/testdata/only_used_models/gqlgenc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
model:
filename: ./actual/models_gen.go
package: generated
client:
filename: ./actual/client.go
package: generated
schema:
- ./schemas/*.graphql
query:
- "./queries/*.graphql"
generate:
clientV2: true
onlyUsedModels: true
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mutation CreateMany($todos: NewTodos!) {
createTodos(input: $todos) {
todos {
id
}
}
}
26 changes: 26 additions & 0 deletions generator/testdata/only_used_models/schemas/schema.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
type Query {
todos: [Todo!]!
}

input NewTodo {
text: String!
userId: String!
}

input NewTodos {
todos: [NewTodo!]!
}

type Mutation {
createTodos(input: NewTodos!): TodoPage
}

type Todo {
id: ID!
text: String!
userId: String!
}

type TodoPage {
todos: [Todo!]!
}
11 changes: 9 additions & 2 deletions querydocument/query_document.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,16 @@ func collectInputObjectFieldsWithCycle(def *ast.Definition, schema *ast.Schema,
for _, field := range def.Fields {
var typeName string
// リスト型の要素型まで辿る
for field.Type != nil && field.Type.NamedType != "" {
switch {
case field.Type == nil:
// No type, nothing to do
continue
case field.Type.Elem != nil:
// Handle slices
typeName = field.Type.Elem.NamedType
case field.Type.NamedType != "":
// Handle scalar named types
typeName = field.Type.NamedType
break
}

if typeName != "" {
Expand Down

0 comments on commit 8973cc0

Please sign in to comment.