277 lines
5.4 KiB
Go
277 lines
5.4 KiB
Go
package generate
|
|
|
|
import (
|
|
"fmt"
|
|
"go/format"
|
|
"sort"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/vektah/gqlparser"
|
|
"github.com/vektah/gqlparser/ast"
|
|
)
|
|
|
|
func gofmt(src string) (string, error) {
|
|
src = strings.TrimSpace(src)
|
|
formatted, err := format.Source([]byte(src))
|
|
if err != nil {
|
|
return src, err
|
|
}
|
|
return string(formatted), nil
|
|
}
|
|
|
|
var schemaText = `
|
|
enum Role {
|
|
STUDENT
|
|
TEACHER
|
|
}
|
|
|
|
input UserQueryInput {
|
|
email: String
|
|
name: String
|
|
id: ID
|
|
role: Role
|
|
}
|
|
|
|
type AuthMethod {
|
|
provider: String
|
|
email: String
|
|
}
|
|
|
|
type User {
|
|
id: ID!
|
|
roles: [Role!]
|
|
name: String
|
|
emails: [String!]!
|
|
emailsOrNull: [String!]
|
|
emailsWithNulls: [String]!
|
|
emailsWithNullsOrNull: [String]
|
|
authMethods: [AuthMethod!]!
|
|
}
|
|
|
|
type Query {
|
|
user: User
|
|
}
|
|
`
|
|
|
|
func TestTypeForOperation(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
operation string
|
|
expectedGoType string
|
|
}{{
|
|
"SimpleQuery",
|
|
`{ user { id } }`,
|
|
`type Response struct{
|
|
User *struct {
|
|
Id string ` + "`json:\"id\"`" + `
|
|
} ` + "`json:\"user\"`" + `
|
|
}`,
|
|
}, {
|
|
"QueryWithAlias",
|
|
`{ User: user { ID: id } }`,
|
|
`type Response struct{
|
|
User *struct {
|
|
ID string
|
|
}
|
|
}`,
|
|
// Here on out, we use aliases, just because aliases are a lot less
|
|
// annoying to write in Go strings than Go struct tags.
|
|
}, {
|
|
"QueryWithDoubleAlias",
|
|
`{
|
|
User: user {
|
|
ID: id
|
|
AlsoID: id
|
|
}
|
|
}`,
|
|
`type Response struct{
|
|
User *struct {
|
|
ID string
|
|
AlsoID string
|
|
}
|
|
}`,
|
|
}, {
|
|
"QueryWithSlices",
|
|
`{
|
|
User: user {
|
|
Emails: emails
|
|
EmailsOrNull: emailsOrNull
|
|
EmailsWithNulls: emailsWithNulls
|
|
EmailsWithNullsOrNull: emailsWithNullsOrNull
|
|
}
|
|
}`,
|
|
`type Response struct{
|
|
User *struct {
|
|
Emails []string
|
|
EmailsOrNull []string
|
|
EmailsWithNulls []*string
|
|
EmailsWithNullsOrNull []*string
|
|
}
|
|
}`,
|
|
}, {
|
|
"QueryWithStructs",
|
|
`{
|
|
User: user {
|
|
AuthMethods: authMethods {
|
|
Provider: provider
|
|
Email: email
|
|
}
|
|
}
|
|
}`,
|
|
`type Response struct{
|
|
User *struct {
|
|
AuthMethods []struct {
|
|
Provider *string
|
|
Email *string
|
|
}
|
|
}
|
|
}`,
|
|
}, {
|
|
"QueryWithEnums",
|
|
`{
|
|
User: user {
|
|
Roles: roles
|
|
}
|
|
}`,
|
|
`type Response struct{
|
|
User *struct {
|
|
Roles []role
|
|
}
|
|
}
|
|
|
|
type role string
|
|
const (
|
|
studentRole role = "STUDENT"
|
|
teacherRole role = "TEACHER"
|
|
)`,
|
|
}}
|
|
|
|
for _, test := range tests {
|
|
test := test
|
|
t.Run(test.name, func(t *testing.T) {
|
|
expectedGoType, err := gofmt(test.expectedGoType)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
schema, graphqlError := gqlparser.LoadSchema(
|
|
&ast.Source{Name: "test schema", Input: schemaText})
|
|
if graphqlError != nil {
|
|
t.Fatal(graphqlError)
|
|
}
|
|
|
|
queryDoc, graphqlListError := gqlparser.LoadQuery(schema, test.operation)
|
|
if graphqlListError != nil {
|
|
t.Fatal(graphqlListError)
|
|
}
|
|
|
|
if len(queryDoc.Operations) != 1 {
|
|
t.Fatalf("got %v operations, want 1", len(queryDoc.Operations))
|
|
}
|
|
|
|
g := newGenerator("test_package", schema)
|
|
_, err = g.getTypeForOperation(queryDoc.Operations[0])
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
// gofmt before comparing.
|
|
goType, err := gofmt(g.Types())
|
|
if err != nil {
|
|
t.Error(err)
|
|
}
|
|
|
|
if goType != expectedGoType {
|
|
t.Errorf("got:\n%v\nwant:\n%v\n", goType, expectedGoType)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
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\"`" + `
|
|
}`,
|
|
},
|
|
}}
|
|
|
|
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("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)
|
|
}
|
|
})
|
|
}
|
|
}
|