move everything into snapshot-based testing; update it a bit

This commit is contained in:
Ben Kraft
2020-07-16 13:34:31 -07:00
parent cf7136ca65
commit 036d39622d
10 changed files with 176 additions and 199 deletions
+85
View File
@@ -0,0 +1,85 @@
package generate
import (
"errors"
"fmt"
"go/format"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
)
const dataDir = "testdata"
func readFile(t *testing.T, filename string, allowNotExist bool) string {
t.Helper()
data, err := ioutil.ReadFile(filepath.Join(dataDir, filename))
if err != nil {
if allowNotExist && errors.Is(err, os.ErrNotExist) {
return ""
}
t.Fatal(err)
}
return string(data)
}
func gofmt(src string) (string, error) {
src = strings.TrimSpace(src)
formatted, err := format.Source([]byte(src))
if err != nil {
return src, fmt.Errorf("go parse error: %w", err)
}
return string(formatted), nil
}
func TestGenerate(t *testing.T) {
// This test uses the schema, queries, and expected-output in ./testdata.
// The schema is in schema.graphql. The queries are in TestName.graphql;
// the test asserts that the output of the generator for that query is
// matches TestName.graphql.go. To update the expected output, run the
// tests with UPDATE_SNAPSHOTS=1 (they will still fail, but also do the
// update, so you can see which updates were made).
update := (os.Getenv("UPDATE_SNAPSHOTS") == "1")
files, err := ioutil.ReadDir(dataDir)
if err != nil {
t.Fatal(err)
}
for _, file := range files {
graphqlFilename := file.Name()
if graphqlFilename == "schema.graphql" || !strings.HasSuffix(graphqlFilename, ".graphql") {
continue
}
goFilename := graphqlFilename + ".go"
t.Run(graphqlFilename, func(t *testing.T) {
expectedGoCode, err := gofmt(readFile(t, goFilename, update))
if err != nil {
t.Fatal(err)
}
goCode, err := Generate(&Config{
Schema: filepath.Join("testdata", "schema.graphql"),
Queries: filepath.Join("testdata", graphqlFilename),
Package: "test",
})
if err != nil {
t.Fatal(err)
}
if string(goCode) != expectedGoCode {
t.Errorf("got:\n%v\nwant:\n%v\n", string(goCode), expectedGoCode)
if update {
t.Log("Updating testdata dir to match")
err = ioutil.WriteFile(filepath.Join(dataDir, goFilename), goCode, 0644)
if err != nil {
t.Errorf("Unable to update testdata dir: %v", err)
}
}
}
})
}
}
+5
View File
@@ -0,0 +1,5 @@
query InputObjectQuery($query: UserQueryInput) {
user(query: $query) {
id
}
}
@@ -8,7 +8,7 @@ import (
"github.com/Khan/genql/graphql"
)
type QueryWithInputResponse struct {
type InputObjectQueryResponse struct {
User *User `json:"user"`
}
@@ -24,20 +24,21 @@ type User struct {
}
type UserQueryInput struct {
Email *string `json:"email"`
Name *string `json:"name"`
Id *string `json:"id"`
Role *Role `json:"role"`
Email *string `json:"email"`
Name *string `json:"name"`
Id *string `json:"id"`
Role *Role `json:"role"`
Names []*string `json:"names"`
}
func QueryWithInput(client *graphql.Client, query *UserQueryInput) (*QueryWithInputResponse, error) {
func InputObjectQuery(client *graphql.Client, query *UserQueryInput) (*InputObjectQueryResponse, error) {
variables := map[string]interface{}{
"query": query,
}
var retval QueryWithInputResponse
var retval InputObjectQueryResponse
err := client.MakeRequest(context.Background(), `
query QueryWithInput ($query: UserQueryInput) {
query InputObjectQuery ($query: UserQueryInput) {
user(query: $query) {
id
}
+5
View File
@@ -0,0 +1,5 @@
query ListInputQuery($names: [String]) {
user(query: {names: $names}) {
id
}
}
+33
View File
@@ -0,0 +1,33 @@
package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"github.com/Khan/genql/graphql"
)
type ListInputQueryResponse struct {
User *User `json:"user"`
}
type User struct {
Id string `json:"id"`
}
func ListInputQuery(client *graphql.Client, names []*string) (*ListInputQueryResponse, error) {
variables := map[string]interface{}{
"names": names,
}
var retval ListInputQueryResponse
err := client.MakeRequest(context.Background(), `
query ListInputQuery ($names: [String]) {
user(query: {names:$names}) {
id
}
}
`, &retval, variables)
return &retval, err
}
-5
View File
@@ -1,5 +0,0 @@
query QueryWithInput($query: UserQueryInput) {
user(query: $query) {
id
}
}
+5
View File
@@ -0,0 +1,5 @@
query SimpleInputQuery($name: String!) {
user(query: {name: $name}) {
id
}
}
+33
View File
@@ -0,0 +1,33 @@
package test
// Code generated by github.com/Khan/genql, DO NOT EDIT.
import (
"context"
"github.com/Khan/genql/graphql"
)
type SimpleInputQueryResponse struct {
User *User `json:"user"`
}
type User struct {
Id string `json:"id"`
}
func SimpleInputQuery(client *graphql.Client, name string) (*SimpleInputQueryResponse, error) {
variables := map[string]interface{}{
"name": name,
}
var retval SimpleInputQueryResponse
err := client.MakeRequest(context.Background(), `
query SimpleInputQuery ($name: String!) {
user(query: {name:$name}) {
id
}
}
`, &retval, variables)
return &retval, err
}
+1
View File
@@ -8,6 +8,7 @@ input UserQueryInput {
name: String
id: ID
role: Role
names: [String]
}
type AuthMethod {
-186
View File
@@ -1,186 +0,0 @@
package generate
import (
"errors"
"fmt"
"go/format"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"
"testing"
"github.com/vektah/gqlparser"
"github.com/vektah/gqlparser/ast"
)
const dataDir = "testdata"
func readFile(t *testing.T, filename string, allowNotExist bool) string {
t.Helper()
data, err := ioutil.ReadFile(filepath.Join(dataDir, filename))
if err != nil {
if allowNotExist && errors.Is(err, os.ErrNotExist) {
return ""
}
t.Fatal(err)
}
return string(data)
}
func gofmt(src string) (string, error) {
src = strings.TrimSpace(src)
formatted, err := format.Source([]byte(src))
if err != nil {
return src, fmt.Errorf("go parse error: %w", err)
}
return string(formatted), nil
}
func TestTypeForOperation(t *testing.T) {
// This test uses the schema, queries, and expected-output in ./testdata.
// The schema is in schema.graphql. The queries are in TestName.graphql;
// the test asserts that such queries, when run through the type-generator,
// produce the types in TestName.go (the name of the overall response type
// will be Response).
//
// Change update on the next line to true to update all the expected output
// files to match current output.
// TODO(benkraft): Make this a flag or something.
update := false
files, err := ioutil.ReadDir(dataDir)
if err != nil {
t.Fatal(err)
}
for _, file := range files {
graphqlFilename := file.Name()
if graphqlFilename == "schema.graphql" || !strings.HasSuffix(graphqlFilename, ".graphql") {
continue
}
goFilename := graphqlFilename + ".go"
t.Run(graphqlFilename, func(t *testing.T) {
expectedGoCode, err := gofmt(readFile(t, goFilename, update))
if err != nil {
t.Fatal(err)
}
goCode, err := Generate(&Config{
Schema: filepath.Join("testdata", "schema.graphql"),
Queries: filepath.Join("testdata", graphqlFilename),
Package: "test",
})
if err != nil {
t.Fatal(err)
}
if string(goCode) != expectedGoCode {
t.Errorf("got:\n%v\nwant:\n%v\n", string(goCode), expectedGoCode)
if update {
t.Log("Updating testdata dir to match")
err = ioutil.WriteFile(filepath.Join(dataDir, goFilename), goCode, 0644)
if err != nil {
t.Errorf("Unable to update testdata dir: %v", err)
}
}
}
})
}
if update {
// This is an error to ensure we don't commit update := true
t.Error("Updated testdata dir")
}
}
// TODO(benkraft): Figure out how to do this with testdata-files
func TestTypeForInputType(t *testing.T) {
tests := []struct {
name string
graphQLType string
expectedGoType string
otherTypes []string
}{{
`RequiredBuiltin`,
`String!`,
`string`,
nil,
}, {
`ListOfBuiltin`,
`[String]`,
`[]*string`,
nil,
}, {
`DefinedType`,
`UserQueryInput`,
`*UserQueryInput`,
[]string{
`type Role string
const (
StudentRole Role = "STUDENT"
TeacherRole Role = "TEACHER"
)`,
`type UserQueryInput struct {
Email *string ` + "`json:\"email\"`" + `
Name *string ` + "`json:\"name\"`" + `
Id *string ` + "`json:\"id\"`" + `
Role *Role ` + "`json:\"role\"`" + `
}`,
},
}}
schemaText := readFile(t, "schema.graphql", false)
for _, test := range tests {
test := test
t.Run(test.name, func(t *testing.T) {
sort.Strings(test.otherTypes) // To match generator.Types()
expectedGoCode := fmt.Sprintf(
"type Input %s\n\n%s", test.expectedGoType,
strings.Join(test.otherTypes, "\n\n"))
expectedGoCode, err := gofmt(expectedGoCode)
if err != nil {
t.Fatal(err)
}
extraSchemaText := fmt.Sprintf(
"extend type Query { testQuery(var: %s): User }", test.graphQLType)
schema, graphqlError := gqlparser.LoadSchema(
&ast.Source{Name: "test schema", Input: schemaText},
&ast.Source{Name: "test schema extension", Input: extraSchemaText},
)
if graphqlError != nil {
t.Fatal(graphqlError)
}
operation := fmt.Sprintf(
"query($var: %s) { testQuery(var: $var) { id } }", test.graphQLType)
queryDoc, graphqlListError := gqlparser.LoadQuery(schema, operation)
if graphqlListError != nil {
t.Fatal(graphqlListError)
}
g := newGenerator(&Config{Package: "test_package"}, schema)
goType, err := g.getTypeForInputType(
queryDoc.Operations[0].VariableDefinitions[0].Type)
if err != nil {
t.Error(err)
}
goCode := fmt.Sprintf("type Input %s\n\n%s", goType, g.Types())
// gofmt before comparing.
goCode, err = gofmt(goCode)
if err != nil {
t.Error(err)
}
if goCode != expectedGoCode {
t.Errorf("got:\n%v\nwant:\n%v\n", goCode, expectedGoCode)
}
})
}
}