From 651fac9d62640a1c5c8da0a7c05e73eb1ed11195 Mon Sep 17 00:00:00 2001 From: Fugiman Date: Sat, 7 Nov 2015 04:21:33 -0800 Subject: [PATCH 01/41] Fix declared but not used errors --- union_interface_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/union_interface_test.go b/union_interface_test.go index 9bdada91..f3d16132 100644 --- a/union_interface_test.go +++ b/union_interface_test.go @@ -497,8 +497,8 @@ func TestUnionIntersectionTypes_AllowsFragmentConditionsToBeAbstractTypes(t *tes } func TestUnionIntersectionTypes_GetsExecutionInfoInResolver(t *testing.T) { - var encounteredSchema *graphql.Schema - var encounteredRootValue interface{} + //var encounteredSchema *graphql.Schema + //var encounteredRootValue interface{} var personType2 *graphql.Object @@ -510,8 +510,8 @@ func TestUnionIntersectionTypes_GetsExecutionInfoInResolver(t *testing.T) { }, }, ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { - encounteredSchema = &info.Schema - encounteredRootValue = info.RootValue + //encounteredSchema = &info.Schema + //encounteredRootValue = info.RootValue return personType2 }, }) From 92795dfb2ea11c31d4161bdd2972dec66098db1c Mon Sep 17 00:00:00 2001 From: Fugiman Date: Sat, 7 Nov 2015 04:23:00 -0800 Subject: [PATCH 02/41] graphql.Graphql -> graphql.Do --- abstract_test.go | 8 ++++---- examples/hello-world/main.go | 2 +- examples/http/main.go | 2 +- graphql.go | 2 +- graphql_test.go | 4 ++-- introspection_test.go | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/abstract_test.go b/abstract_test.go index 7639ac75..ef44e830 100644 --- a/abstract_test.go +++ b/abstract_test.go @@ -145,7 +145,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { Errors: nil, } - result := graphql.Graphql(graphql.Params{ + result := graphql.Do(graphql.Params{ Schema: schema, RequestString: query, }) @@ -277,7 +277,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { Errors: nil, } - result := graphql.Graphql(graphql.Params{ + result := graphql.Do(graphql.Params{ Schema: schema, RequestString: query, }) @@ -445,7 +445,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { }, } - result := graphql.Graphql(graphql.Params{ + result := graphql.Do(graphql.Params{ Schema: schema, RequestString: query, }) @@ -600,7 +600,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { }, } - result := graphql.Graphql(graphql.Params{ + result := graphql.Do(graphql.Params{ Schema: schema, RequestString: query, }) diff --git a/examples/hello-world/main.go b/examples/hello-world/main.go index 5577ec30..c04e96e6 100644 --- a/examples/hello-world/main.go +++ b/examples/hello-world/main.go @@ -32,7 +32,7 @@ func main() { } ` params := graphql.Params{Schema: schema, RequestString: query} - r := graphql.Graphql(params) + r := graphql.Do(params) if len(r.Errors) > 0 { log.Fatalf("failed to execute graphql operation, errors: %+v", r.Errors) } diff --git a/examples/http/main.go b/examples/http/main.go index f1a811b2..d7b0d3dd 100644 --- a/examples/http/main.go +++ b/examples/http/main.go @@ -74,7 +74,7 @@ var schema, _ = graphql.NewSchema( ) func executeQuery(query string, schema graphql.Schema) *graphql.Result { - result := graphql.Graphql(graphql.Params{ + result := graphql.Do(graphql.Params{ Schema: schema, RequestString: query, }) diff --git a/graphql.go b/graphql.go index c3e1703f..1d84eb1d 100644 --- a/graphql.go +++ b/graphql.go @@ -14,7 +14,7 @@ type Params struct { OperationName string } -func Graphql(p Params) *Result { +func Do(p Params) *Result { source := source.NewSource(&source.Source{ Body: p.RequestString, Name: "GraphQL request", diff --git a/graphql_test.go b/graphql_test.go index 9de9bb6c..d6c8da43 100644 --- a/graphql_test.go +++ b/graphql_test.go @@ -82,7 +82,7 @@ func TestQuery(t *testing.T) { } func testGraphql(test T, p graphql.Params, t *testing.T) { - result := graphql.Graphql(p) + result := graphql.Do(p) if len(result.Errors) > 0 { t.Fatalf("wrong result, unexpected errors: %v", result.Errors) } @@ -119,7 +119,7 @@ func TestBasicGraphQLExample(t *testing.T) { "hello": "world", } - result := graphql.Graphql(graphql.Params{ + result := graphql.Do(graphql.Params{ Schema: schema, RequestString: query, }) diff --git a/introspection_test.go b/introspection_test.go index 5fb79042..647e74a8 100644 --- a/introspection_test.go +++ b/introspection_test.go @@ -11,7 +11,7 @@ import ( ) func g(t *testing.T, p graphql.Params) *graphql.Result { - return graphql.Graphql(p) + return graphql.Do(p) } func TestIntrospection_ExecutesAnIntrospectionQuery(t *testing.T) { From d7b412a3adc89312700398895c6461b495e0f073 Mon Sep 17 00:00:00 2001 From: Fugiman Date: Sat, 7 Nov 2015 04:25:48 -0800 Subject: [PATCH 03/41] graphql.FieldConfigMap -> graphql.Fields --- abstract_test.go | 32 +++++----- definition.go | 18 +++--- definition_test.go | 28 ++++---- directives_test.go | 2 +- enum_type_test.go | 4 +- examples/hello-world/main.go | 2 +- examples/http/main.go | 4 +- executor_schema_test.go | 8 +-- executor_test.go | 42 ++++++------ graphql_test.go | 2 +- introspection.go | 12 ++-- introspection_test.go | 20 +++--- lists_test.go | 2 +- mutations_test.go | 6 +- nonnull_test.go | 2 +- testutil/testutil.go | 8 +-- union_interface_test.go | 12 ++-- validation_test.go | 120 +++++++++++++++++------------------ variables_test.go | 2 +- 19 files changed, 163 insertions(+), 163 deletions(-) diff --git a/abstract_test.go b/abstract_test.go index ef44e830..4758bb45 100644 --- a/abstract_test.go +++ b/abstract_test.go @@ -28,7 +28,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { petType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "Pet", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, }, @@ -45,7 +45,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { _, ok := value.(*testDog) return ok }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { @@ -76,7 +76,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { _, ok := value.(*testCat) return ok }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { @@ -100,7 +100,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "pets": &graphql.FieldConfig{ Type: graphql.NewList(petType), Resolve: func(p graphql.GQLFRParams) interface{} { @@ -165,7 +165,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { _, ok := value.(*testDog) return ok }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { @@ -192,7 +192,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { _, ok := value.(*testCat) return ok }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { @@ -232,7 +232,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "pets": &graphql.FieldConfig{ Type: graphql.NewList(petType), Resolve: func(p graphql.GQLFRParams) interface{} { @@ -297,7 +297,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { var humanType *graphql.Object petType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "Pet", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, }, @@ -318,7 +318,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { humanType = graphql.NewObject(graphql.ObjectConfig{ Name: "Human", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { @@ -339,7 +339,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { _, ok := value.(*testDog) return ok }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { @@ -369,7 +369,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { _, ok := value.(*testCat) return ok }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { @@ -393,7 +393,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "pets": &graphql.FieldConfig{ Type: graphql.NewList(petType), Resolve: func(p graphql.GQLFRParams) interface{} { @@ -461,7 +461,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { humanType := graphql.NewObject(graphql.ObjectConfig{ Name: "Human", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { @@ -479,7 +479,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { _, ok := value.(*testDog) return ok }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { @@ -506,7 +506,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { _, ok := value.(*testCat) return ok }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { @@ -548,7 +548,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "pets": &graphql.FieldConfig{ Type: graphql.NewList(petType), Resolve: func(p graphql.GQLFRParams) interface{} { diff --git a/definition.go b/definition.go index 3eacbbd8..4e8c62ae 100644 --- a/definition.go +++ b/definition.go @@ -300,11 +300,11 @@ type IsTypeOfFn func(value interface{}, info ResolveInfo) bool type InterfacesThunk func() []*Interface type ObjectConfig struct { - Name string `json:"description"` - Interfaces interface{} `json:"interfaces"` - Fields FieldConfigMap `json:"fields"` - IsTypeOf IsTypeOfFn `json:"isTypeOf"` - Description string `json:"description"` + Name string `json:"description"` + Interfaces interface{} `json:"interfaces"` + Fields Fields `json:"fields"` + IsTypeOf IsTypeOfFn `json:"isTypeOf"` + Description string `json:"description"` } func NewObject(config ObjectConfig) *Object { @@ -418,7 +418,7 @@ func defineInterfaces(ttype *Object, interfaces []*Interface) ([]*Interface, err return ifaces, nil } -func defineFieldMap(ttype Named, fields FieldConfigMap) (FieldDefinitionMap, error) { +func defineFieldMap(ttype Named, fields Fields) (FieldDefinitionMap, error) { resultFieldMap := FieldDefinitionMap{} @@ -512,7 +512,7 @@ type ResolveInfo struct { VariableValues map[string]interface{} } -type FieldConfigMap map[string]*FieldConfig +type Fields map[string]*FieldConfig type FieldConfig struct { Name string `json:"name"` // used by graphlql-relay @@ -600,8 +600,8 @@ type Interface struct { err error } type InterfaceConfig struct { - Name string `json:"name"` - Fields FieldConfigMap `json:"fields"` + Name string `json:"name"` + Fields Fields `json:"fields"` ResolveType ResolveTypeFn Description string `json:"description"` } diff --git a/definition_test.go b/definition_test.go index f70f782d..60195f01 100644 --- a/definition_test.go +++ b/definition_test.go @@ -11,7 +11,7 @@ import ( var blogImage = graphql.NewObject(graphql.ObjectConfig{ Name: "Image", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "url": &graphql.FieldConfig{ Type: graphql.String, }, @@ -25,7 +25,7 @@ var blogImage = graphql.NewObject(graphql.ObjectConfig{ }) var blogAuthor = graphql.NewObject(graphql.ObjectConfig{ Name: "Author", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "id": &graphql.FieldConfig{ Type: graphql.String, }, @@ -48,7 +48,7 @@ var blogAuthor = graphql.NewObject(graphql.ObjectConfig{ }) var blogArticle = graphql.NewObject(graphql.ObjectConfig{ Name: "Article", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "id": &graphql.FieldConfig{ Type: graphql.String, }, @@ -68,7 +68,7 @@ var blogArticle = graphql.NewObject(graphql.ObjectConfig{ }) var blogQuery = graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "article": &graphql.FieldConfig{ Type: blogArticle, Args: graphql.FieldConfigArgument{ @@ -85,7 +85,7 @@ var blogQuery = graphql.NewObject(graphql.ObjectConfig{ var blogMutation = graphql.NewObject(graphql.ObjectConfig{ Name: "Mutation", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "writeArticle": &graphql.FieldConfig{ Type: blogArticle, }, @@ -246,7 +246,7 @@ func TestTypeSystem_DefinitionExample_IncludesNestedInputObjectsInTheMap(t *test }) someMutation := graphql.NewObject(graphql.ObjectConfig{ Name: "SomeMutation", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "mutateSomething": &graphql.FieldConfig{ Type: blogArticle, Args: graphql.FieldConfigArgument{ @@ -273,7 +273,7 @@ func TestTypeSystem_DefinitionExample_IncludesInterfacesSubTypesInTheTypeMap(t * someInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "SomeInterface", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.Int, }, @@ -282,7 +282,7 @@ func TestTypeSystem_DefinitionExample_IncludesInterfacesSubTypesInTheTypeMap(t * someSubType := graphql.NewObject(graphql.ObjectConfig{ Name: "SomeSubtype", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.Int, }, @@ -295,7 +295,7 @@ func TestTypeSystem_DefinitionExample_IncludesInterfacesSubTypesInTheTypeMap(t * schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "iface": &graphql.FieldConfig{ Type: someInterface, }, @@ -314,7 +314,7 @@ func TestTypeSystem_DefinitionExample_IncludesInterfacesThunkSubtypesInTheTypeMa someInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "SomeInterface", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.Int, }, @@ -323,7 +323,7 @@ func TestTypeSystem_DefinitionExample_IncludesInterfacesThunkSubtypesInTheTypeMa someSubType := graphql.NewObject(graphql.ObjectConfig{ Name: "SomeSubtype", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.Int, }, @@ -338,7 +338,7 @@ func TestTypeSystem_DefinitionExample_IncludesInterfacesThunkSubtypesInTheTypeMa schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "iface": &graphql.FieldConfig{ Type: someInterface, }, @@ -459,7 +459,7 @@ func TestTypeSystem_DefinitionExample_ProhibitsNilTypeInUnions(t *testing.T) { } } func TestTypeSystem_DefinitionExample_DoesNotMutatePassedFieldDefinitions(t *testing.T) { - fields := graphql.FieldConfigMap{ + fields := graphql.Fields{ "field1": &graphql.FieldConfig{ Type: graphql.String, }, @@ -484,7 +484,7 @@ func TestTypeSystem_DefinitionExample_DoesNotMutatePassedFieldDefinitions(t *tes t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(testObject1.GetFields(), testObject2.GetFields())) } - expectedFields := graphql.FieldConfigMap{ + expectedFields := graphql.Fields{ "field1": &graphql.FieldConfig{ Type: graphql.String, }, diff --git a/directives_test.go b/directives_test.go index 47f78fe9..b1b8f527 100644 --- a/directives_test.go +++ b/directives_test.go @@ -11,7 +11,7 @@ import ( var directivesTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "a": &graphql.FieldConfig{ Type: graphql.String, }, diff --git a/enum_type_test.go b/enum_type_test.go index bff0fe0e..ec87ca3c 100644 --- a/enum_type_test.go +++ b/enum_type_test.go @@ -25,7 +25,7 @@ var enumTypeTestColorType = graphql.NewEnum(graphql.EnumConfig{ }) var enumTypeTestQueryType = graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "colorEnum": &graphql.FieldConfig{ Type: enumTypeTestColorType, Args: graphql.FieldConfigArgument{ @@ -76,7 +76,7 @@ var enumTypeTestQueryType = graphql.NewObject(graphql.ObjectConfig{ }) var enumTypeTestMutationType = graphql.NewObject(graphql.ObjectConfig{ Name: "Mutation", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "favoriteEnum": &graphql.FieldConfig{ Type: enumTypeTestColorType, Args: graphql.FieldConfigArgument{ diff --git a/examples/hello-world/main.go b/examples/hello-world/main.go index c04e96e6..3f8f4a4a 100644 --- a/examples/hello-world/main.go +++ b/examples/hello-world/main.go @@ -10,7 +10,7 @@ import ( func main() { // Schema - fields := graphql.FieldConfigMap{ + fields := graphql.Fields{ "hello": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { diff --git a/examples/http/main.go b/examples/http/main.go index d7b0d3dd..1d64eb7f 100644 --- a/examples/http/main.go +++ b/examples/http/main.go @@ -25,7 +25,7 @@ var data map[string]user var userType = graphql.NewObject( graphql.ObjectConfig{ Name: "User", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "id": &graphql.FieldConfig{ Type: graphql.String, }, @@ -48,7 +48,7 @@ var userType = graphql.NewObject( var queryType = graphql.NewObject( graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "user": &graphql.FieldConfig{ Type: userType, Args: graphql.FieldConfigArgument{ diff --git a/executor_schema_test.go b/executor_schema_test.go index c17214c2..e14f7fa2 100644 --- a/executor_schema_test.go +++ b/executor_schema_test.go @@ -75,7 +75,7 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { blogImage := graphql.NewObject(graphql.ObjectConfig{ Name: "Image", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "url": &graphql.FieldConfig{ Type: graphql.String, }, @@ -89,7 +89,7 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { }) blogAuthor := graphql.NewObject(graphql.ObjectConfig{ Name: "Author", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "id": &graphql.FieldConfig{ Type: graphql.String, }, @@ -120,7 +120,7 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { }) blogArticle := graphql.NewObject(graphql.ObjectConfig{ Name: "Article", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "id": &graphql.FieldConfig{ Type: graphql.NewNonNull(graphql.String), }, @@ -148,7 +148,7 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { blogQuery := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "article": &graphql.FieldConfig{ Type: blogArticle, Args: graphql.FieldConfigArgument{ diff --git a/executor_test.go b/executor_test.go index a52b1c38..ca243cac 100644 --- a/executor_test.go +++ b/executor_test.go @@ -118,7 +118,7 @@ func TestExecutesArbitraryCode(t *testing.T) { } dataType := graphql.NewObject(graphql.ObjectConfig{ Name: "DataType", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "a": &graphql.FieldConfig{ Type: graphql.String, }, @@ -150,7 +150,7 @@ func TestExecutesArbitraryCode(t *testing.T) { }) deepDataType := graphql.NewObject(graphql.ObjectConfig{ Name: "DeepDataType", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "a": &graphql.FieldConfig{ Type: graphql.String, }, @@ -241,7 +241,7 @@ func TestMergesParallelFragments(t *testing.T) { typeObjectType := graphql.NewObject(graphql.ObjectConfig{ Name: "Type", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "a": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { @@ -309,7 +309,7 @@ func TestThreadsContextCorrectly(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "a": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { @@ -357,7 +357,7 @@ func TestCorrectlyThreadsArguments(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "b": &graphql.FieldConfig{ Args: graphql.FieldConfigArgument{ "numArg": &graphql.ArgumentConfig{ @@ -437,7 +437,7 @@ func TestNullsOutErrorSubtrees(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "sync": &graphql.FieldConfig{ Type: graphql.String, }, @@ -488,7 +488,7 @@ func TestUsesTheInlineOperationIfNoOperationIsProvided(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "a": &graphql.FieldConfig{ Type: graphql.String, }, @@ -533,7 +533,7 @@ func TestUsesTheOnlyOperationIfNoOperationIsProvided(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "a": &graphql.FieldConfig{ Type: graphql.String, }, @@ -579,7 +579,7 @@ func TestThrowsIfNoOperationIsProvidedWithMultipleOperations(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "a": &graphql.FieldConfig{ Type: graphql.String, }, @@ -628,7 +628,7 @@ func TestUsesTheQuerySchemaForQueries(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Q", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "a": &graphql.FieldConfig{ Type: graphql.String, }, @@ -636,7 +636,7 @@ func TestUsesTheQuerySchemaForQueries(t *testing.T) { }), Mutation: graphql.NewObject(graphql.ObjectConfig{ Name: "M", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "c": &graphql.FieldConfig{ Type: graphql.String, }, @@ -683,7 +683,7 @@ func TestUsesTheMutationSchemaForMutations(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Q", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "a": &graphql.FieldConfig{ Type: graphql.String, }, @@ -691,7 +691,7 @@ func TestUsesTheMutationSchemaForMutations(t *testing.T) { }), Mutation: graphql.NewObject(graphql.ObjectConfig{ Name: "M", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "c": &graphql.FieldConfig{ Type: graphql.String, }, @@ -753,7 +753,7 @@ func TestCorrectFieldOrderingDespiteExecutionOrder(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "a": &graphql.FieldConfig{ Type: graphql.String, }, @@ -831,7 +831,7 @@ func TestAvoidsRecursion(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "a": &graphql.FieldConfig{ Type: graphql.String, }, @@ -875,7 +875,7 @@ func TestDoesNotIncludeIllegalFieldsInOutput(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Q", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "a": &graphql.FieldConfig{ Type: graphql.String, }, @@ -883,7 +883,7 @@ func TestDoesNotIncludeIllegalFieldsInOutput(t *testing.T) { }), Mutation: graphql.NewObject(graphql.ObjectConfig{ Name: "M", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "c": &graphql.FieldConfig{ Type: graphql.String, }, @@ -924,7 +924,7 @@ func TestDoesNotIncludeArgumentsThatWereNotSet(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -1016,7 +1016,7 @@ func TestFailsWhenAnIsTypeOfCheckIsNotMet(t *testing.T) { } return false }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "value": &graphql.FieldConfig{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { @@ -1028,7 +1028,7 @@ func TestFailsWhenAnIsTypeOfCheckIsNotMet(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "specials": &graphql.FieldConfig{ Type: graphql.NewList(specialType), Resolve: func(p graphql.GQLFRParams) interface{} { @@ -1080,7 +1080,7 @@ func TestFailsToExecuteQueryContainingATypeDefinition(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "foo": &graphql.FieldConfig{ Type: graphql.String, }, diff --git a/graphql_test.go b/graphql_test.go index d6c8da43..d5000d27 100644 --- a/graphql_test.go +++ b/graphql_test.go @@ -101,7 +101,7 @@ func TestBasicGraphQLExample(t *testing.T) { schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "RootQueryType", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "hello": &graphql.FieldConfig{ Description: "Returns `world`", Type: graphql.String, diff --git a/introspection.go b/introspection.go index ce312682..92a15e23 100644 --- a/introspection.go +++ b/introspection.go @@ -83,7 +83,7 @@ func init() { // Note: some fields (for e.g "fields", "interfaces") are defined later due to cyclic reference __Type = NewObject(ObjectConfig{ Name: "__Type", - Fields: FieldConfigMap{ + Fields: Fields{ "kind": &FieldConfig{ Type: NewNonNull(__TypeKind), Resolve: func(p GQLFRParams) interface{} { @@ -125,7 +125,7 @@ func init() { __InputValue = NewObject(ObjectConfig{ Name: "__InputValue", - Fields: FieldConfigMap{ + Fields: Fields{ "name": &FieldConfig{ Type: NewNonNull(String), }, @@ -160,7 +160,7 @@ func init() { __Field = NewObject(ObjectConfig{ Name: "__Field", - Fields: FieldConfigMap{ + Fields: Fields{ "name": &FieldConfig{ Type: NewNonNull(String), }, @@ -196,7 +196,7 @@ func init() { __Directive = NewObject(ObjectConfig{ Name: "__Directive", - Fields: FieldConfigMap{ + Fields: Fields{ "name": &FieldConfig{ Type: NewNonNull(String), }, @@ -226,7 +226,7 @@ func init() { server. It exposes all available types and directives on the server, as well as the entry points for query and mutation operations.`, - Fields: FieldConfigMap{ + Fields: Fields{ "types": &FieldConfig{ Description: "A list of all types supported by this server.", Type: NewNonNull(NewList( @@ -283,7 +283,7 @@ mutation operations.`, __EnumValue = NewObject(ObjectConfig{ Name: "__EnumValue", - Fields: FieldConfigMap{ + Fields: Fields{ "name": &FieldConfig{ Type: NewNonNull(String), }, diff --git a/introspection_test.go b/introspection_test.go index 647e74a8..698143ec 100644 --- a/introspection_test.go +++ b/introspection_test.go @@ -18,7 +18,7 @@ func TestIntrospection_ExecutesAnIntrospectionQuery(t *testing.T) { emptySchema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "QueryRoot", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "onlyField": &graphql.FieldConfig{ Type: graphql.String, }, @@ -760,7 +760,7 @@ func TestIntrospection_ExecutesAnInputObject(t *testing.T) { }) testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -860,7 +860,7 @@ func TestIntrospection_SupportsThe__TypeRootField(t *testing.T) { testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "testField": &graphql.FieldConfig{ Type: graphql.String, }, @@ -898,7 +898,7 @@ func TestIntrospection_IdentifiesDeprecatedFields(t *testing.T) { testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "nonDeprecated": &graphql.FieldConfig{ Type: graphql.String, }, @@ -957,7 +957,7 @@ func TestIntrospection_RespectsTheIncludeDeprecatedParameterForFields(t *testing testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "nonDeprecated": &graphql.FieldConfig{ Type: graphql.String, }, @@ -1041,7 +1041,7 @@ func TestIntrospection_IdentifiesDeprecatedEnumValues(t *testing.T) { }) testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "testEnum": &graphql.FieldConfig{ Type: testEnum, }, @@ -1116,7 +1116,7 @@ func TestIntrospection_RespectsTheIncludeDeprecatedParameterForEnumValues(t *tes }) testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "testEnum": &graphql.FieldConfig{ Type: testEnum, }, @@ -1190,7 +1190,7 @@ func TestIntrospection_FailsAsExpectedOnThe__TypeRootFieldWithoutAnArg(t *testin testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "testField": &graphql.FieldConfig{ Type: graphql.String, }, @@ -1234,7 +1234,7 @@ func TestIntrospection_ExposesDescriptionsOnTypesAndFields(t *testing.T) { queryRoot := graphql.NewObject(graphql.ObjectConfig{ Name: "QueryRoot", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "onlyField": &graphql.FieldConfig{ Type: graphql.String, }, @@ -1300,7 +1300,7 @@ func TestIntrospection_ExposesDescriptionsOnEnums(t *testing.T) { queryRoot := graphql.NewObject(graphql.ObjectConfig{ Name: "QueryRoot", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "onlyField": &graphql.FieldConfig{ Type: graphql.String, }, diff --git a/lists_test.go b/lists_test.go index eab76a2f..5e102a6a 100644 --- a/lists_test.go +++ b/lists_test.go @@ -17,7 +17,7 @@ func checkList(t *testing.T, testType graphql.Type, testData interface{}, expect dataType := graphql.NewObject(graphql.ObjectConfig{ Name: "DataType", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "test": &graphql.FieldConfig{ Type: testType, }, diff --git a/mutations_test.go b/mutations_test.go index 91bf3d78..c6cdfd48 100644 --- a/mutations_test.go +++ b/mutations_test.go @@ -40,7 +40,7 @@ func (r *testRoot) PromiseAndFailToChangeTheNumber(newNumber int) *testNumberHol // numberHolderType creates a mapping to testNumberHolder var numberHolderType = graphql.NewObject(graphql.ObjectConfig{ Name: "NumberHolder", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "theNumber": &graphql.FieldConfig{ Type: graphql.Int, }, @@ -50,7 +50,7 @@ var numberHolderType = graphql.NewObject(graphql.ObjectConfig{ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "numberHolder": &graphql.FieldConfig{ Type: numberHolderType, }, @@ -58,7 +58,7 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ }), Mutation: graphql.NewObject(graphql.ObjectConfig{ Name: "Mutation", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "immediatelyChangeTheNumber": &graphql.FieldConfig{ Type: numberHolderType, Args: graphql.FieldConfigArgument{ diff --git a/nonnull_test.go b/nonnull_test.go index d561c238..20df50e0 100644 --- a/nonnull_test.go +++ b/nonnull_test.go @@ -48,7 +48,7 @@ var nullingData = map[string]interface{}{ var dataType = graphql.NewObject(graphql.ObjectConfig{ Name: "DataType", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "sync": &graphql.FieldConfig{ Type: graphql.String, }, diff --git a/testutil/testutil.go b/testutil/testutil.go index 64c7de91..f8a22daa 100644 --- a/testutil/testutil.go +++ b/testutil/testutil.go @@ -119,7 +119,7 @@ func init() { characterInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "Character", Description: "A character in the Star Wars Trilogy", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "id": &graphql.FieldConfig{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the character.", @@ -152,7 +152,7 @@ func init() { humanType = graphql.NewObject(graphql.ObjectConfig{ Name: "Human", Description: "A humanoid creature in the Star Wars universe.", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "id": &graphql.FieldConfig{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the human.", @@ -211,7 +211,7 @@ func init() { droidType = graphql.NewObject(graphql.ObjectConfig{ Name: "Droid", Description: "A mechanical creature in the Star Wars universe.", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "id": &graphql.FieldConfig{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the droid.", @@ -277,7 +277,7 @@ func init() { queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "hero": &graphql.FieldConfig{ Type: characterInterface, Args: graphql.FieldConfigArgument{ diff --git a/union_interface_test.go b/union_interface_test.go index f3d16132..2db9c390 100644 --- a/union_interface_test.go +++ b/union_interface_test.go @@ -30,7 +30,7 @@ type testPerson struct { var namedType = graphql.NewInterface(graphql.InterfaceConfig{ Name: "Named", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, }, @@ -41,7 +41,7 @@ var dogType = graphql.NewObject(graphql.ObjectConfig{ Interfaces: []*graphql.Interface{ namedType, }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, }, @@ -59,7 +59,7 @@ var catType = graphql.NewObject(graphql.ObjectConfig{ Interfaces: []*graphql.Interface{ namedType, }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, }, @@ -92,7 +92,7 @@ var personType = graphql.NewObject(graphql.ObjectConfig{ Interfaces: []*graphql.Interface{ namedType, }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, }, @@ -504,7 +504,7 @@ func TestUnionIntersectionTypes_GetsExecutionInfoInResolver(t *testing.T) { namedType2 := graphql.NewInterface(graphql.InterfaceConfig{ Name: "Named", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, }, @@ -521,7 +521,7 @@ func TestUnionIntersectionTypes_GetsExecutionInfoInResolver(t *testing.T) { Interfaces: []*graphql.Interface{ namedType2, }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "name": &graphql.FieldConfig{ Type: graphql.String, }, diff --git a/validation_test.go b/validation_test.go index 975148db..c71f0662 100644 --- a/validation_test.go +++ b/validation_test.go @@ -21,7 +21,7 @@ var someScalarType = graphql.NewScalar(graphql.ScalarConfig{ }) var someObjectType = graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -32,7 +32,7 @@ var objectWithIsTypeOf = graphql.NewObject(graphql.ObjectConfig{ IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { return true }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -52,7 +52,7 @@ var someInterfaceType = graphql.NewInterface(graphql.InterfaceConfig{ ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -107,7 +107,7 @@ func schemaWithFieldType(ttype graphql.Output) (graphql.Schema, error) { return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: ttype, }, @@ -119,7 +119,7 @@ func schemaWithInputObject(ttype graphql.Input) (graphql.Schema, error) { return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -136,7 +136,7 @@ func schemaWithObjectFieldOfType(fieldType graphql.Input) (graphql.Schema, error badObjectType := graphql.NewObject(graphql.ObjectConfig{ Name: "BadObject", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "badField": &graphql.FieldConfig{ Type: fieldType, }, @@ -145,7 +145,7 @@ func schemaWithObjectFieldOfType(fieldType graphql.Input) (graphql.Schema, error return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: badObjectType, }, @@ -158,7 +158,7 @@ func schemaWithObjectImplementingType(implementedType *graphql.Interface) (graph badObjectType := graphql.NewObject(graphql.ObjectConfig{ Name: "BadObject", Interfaces: []*graphql.Interface{implementedType}, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -167,7 +167,7 @@ func schemaWithObjectImplementingType(implementedType *graphql.Interface) (graph return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: badObjectType, }, @@ -187,7 +187,7 @@ func schemaWithUnionOfType(ttype *graphql.Object) (graphql.Schema, error) { return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: badObjectType, }, @@ -199,7 +199,7 @@ func schemaWithInterfaceFieldOfType(ttype graphql.Type) (graphql.Schema, error) badInterfaceType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "BadInterface", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "badField": &graphql.FieldConfig{ Type: ttype, }, @@ -208,7 +208,7 @@ func schemaWithInterfaceFieldOfType(ttype graphql.Type) (graphql.Schema, error) return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: badInterfaceType, }, @@ -220,7 +220,7 @@ func schemaWithArgOfType(ttype graphql.Type) (graphql.Schema, error) { badObject := graphql.NewObject(graphql.ObjectConfig{ Name: "BadObject", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "badField": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -234,7 +234,7 @@ func schemaWithArgOfType(ttype graphql.Type) (graphql.Schema, error) { return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: badObject, }, @@ -255,7 +255,7 @@ func schemaWithInputFieldOfType(ttype graphql.Type) (graphql.Schema, error) { return graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -280,7 +280,7 @@ func TestTypeSystem_SchemaMustHaveObjectRootTypes_AcceptsASchemaWhoseQueryTypeIs func TestTypeSystem_SchemaMustHaveObjectRootTypes_AcceptsASchemaWhoseQueryAndMutationTypesAreObjectType(t *testing.T) { mutationObject := graphql.NewObject(graphql.ObjectConfig{ Name: "Mutation", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "edit": &graphql.FieldConfig{ Type: graphql.String, }, @@ -312,7 +312,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichRedef }) queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "normal": &graphql.FieldConfig{ Type: graphql.String, }, @@ -333,7 +333,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichDefin a := graphql.NewObject(graphql.ObjectConfig{ Name: "SameName", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -341,7 +341,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichDefin }) b := graphql.NewObject(graphql.ObjectConfig{ Name: "SameName", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -349,7 +349,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichDefin }) queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "a": &graphql.FieldConfig{ Type: a, }, @@ -373,7 +373,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichHaveS ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -384,7 +384,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichHaveS Interfaces: []*graphql.Interface{ anotherInterface, }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -395,7 +395,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichHaveS Interfaces: []*graphql.Interface{ anotherInterface, }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -403,7 +403,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichHaveS }) queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "iface": &graphql.FieldConfig{ Type: anotherInterface, }, @@ -421,7 +421,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichHaveS func TestTypeSystem_ObjectsMustHaveFields_AcceptsAnObjectTypeWithFieldsObject(t *testing.T) { _, err := schemaWithFieldType(graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -444,7 +444,7 @@ func TestTypeSystem_ObjectsMustHaveFields_RejectsAnObjectTypeWithMissingFields(t func TestTypeSystem_ObjectsMustHaveFields_RejectsAnObjectTypeWithIncorrectlyNamedFields(t *testing.T) { badObject := graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "bad-name-with-dashes": &graphql.FieldConfig{ Type: graphql.String, }, @@ -459,7 +459,7 @@ func TestTypeSystem_ObjectsMustHaveFields_RejectsAnObjectTypeWithIncorrectlyName func TestTypeSystem_ObjectsMustHaveFields_RejectsAnObjectTypeWithEmptyFields(t *testing.T) { badObject := graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", - Fields: graphql.FieldConfigMap{}, + Fields: graphql.Fields{}, }) _, err := schemaWithFieldType(badObject) expectedError := `SomeObject fields must be an object with field names as keys or a function which return such an object.` @@ -471,7 +471,7 @@ func TestTypeSystem_ObjectsMustHaveFields_RejectsAnObjectTypeWithEmptyFields(t * func TestTypeSystem_FieldsArgsMustBeProperlyNamed_AcceptsFieldArgsWithValidNames(t *testing.T) { _, err := schemaWithFieldType(graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "goodField": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -489,7 +489,7 @@ func TestTypeSystem_FieldsArgsMustBeProperlyNamed_AcceptsFieldArgsWithValidNames func TestTypeSystem_FieldsArgsMustBeProperlyNamed_RejectsFieldArgWithInvalidNames(t *testing.T) { _, err := schemaWithFieldType(graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "badField": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -509,7 +509,7 @@ func TestTypeSystem_FieldsArgsMustBeProperlyNamed_RejectsFieldArgWithInvalidName func TestTypeSystem_FieldsArgsMustBeObjects_AcceptsAnObjectTypeWithFieldArgs(t *testing.T) { _, err := schemaWithFieldType(graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "goodField": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -531,7 +531,7 @@ func TestTypeSystem_ObjectInterfacesMustBeArray_AcceptsAnObjectTypeWithArrayInte ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -542,7 +542,7 @@ func TestTypeSystem_ObjectInterfacesMustBeArray_AcceptsAnObjectTypeWithArrayInte Interfaces: (graphql.InterfacesThunk)(func() []*graphql.Interface { return []*graphql.Interface{anotherInterfaceType} }), - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -559,7 +559,7 @@ func TestTypeSystem_ObjectInterfacesMustBeArray_AcceptsAnObjectTypeWithInterface ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -568,7 +568,7 @@ func TestTypeSystem_ObjectInterfacesMustBeArray_AcceptsAnObjectTypeWithInterface _, err := schemaWithFieldType(graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", Interfaces: []*graphql.Interface{anotherInterfaceType}, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -675,7 +675,7 @@ func TestTypeSystem_ObjectTypesMustBeAssertable_AcceptsAnObjectTypeWithAnIsTypeO IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { return true }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -693,7 +693,7 @@ func TestTypeSystem_InterfaceTypesMustBeResolvable_AcceptsAnInterfaceTypeDefinin ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -702,7 +702,7 @@ func TestTypeSystem_InterfaceTypesMustBeResolvable_AcceptsAnInterfaceTypeDefinin _, err := schemaWithFieldType(graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", Interfaces: []*graphql.Interface{anotherInterfaceType}, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -716,7 +716,7 @@ func TestTypeSystem_InterfaceTypesMustBeResolvable_AcceptsAnInterfaceWithImpleme anotherInterfaceType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -728,7 +728,7 @@ func TestTypeSystem_InterfaceTypesMustBeResolvable_AcceptsAnInterfaceWithImpleme IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { return true }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -746,7 +746,7 @@ func TestTypeSystem_InterfaceTypesMustBeResolvable_AcceptsAnInterfaceTypeDefinin ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -758,7 +758,7 @@ func TestTypeSystem_InterfaceTypesMustBeResolvable_AcceptsAnInterfaceTypeDefinin IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { return true }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -968,7 +968,7 @@ func TestTypeSystem_ObjectsCanOnlyImplementInterfaces_AcceptsAnObjectImplementin ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "f": &graphql.FieldConfig{ Type: graphql.String, }, @@ -1106,7 +1106,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWhi ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -1120,7 +1120,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWhi anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -1142,7 +1142,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWhi ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -1156,7 +1156,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWhi anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -1181,7 +1181,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWhi ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -1195,7 +1195,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWhi anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -1221,7 +1221,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectMis ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -1235,7 +1235,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectMis anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "anotherfield": &graphql.FieldConfig{ Type: graphql.String, }, @@ -1253,7 +1253,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWit ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -1267,7 +1267,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWit anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: someScalarType, Args: graphql.FieldConfigArgument{ @@ -1290,7 +1290,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectMis ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -1304,7 +1304,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectMis anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, }, @@ -1322,7 +1322,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWit ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -1336,7 +1336,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWit anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ @@ -1359,7 +1359,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWit ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.NewNonNull(graphql.NewList(graphql.String)), }, @@ -1368,7 +1368,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWit anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.NewNonNull(graphql.NewList(graphql.String)), }, @@ -1385,7 +1385,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWit ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { return nil }, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.String, }, @@ -1394,7 +1394,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWit anotherObject := graphql.NewObject(graphql.ObjectConfig{ Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "field": &graphql.FieldConfig{ Type: graphql.NewNonNull(graphql.String), }, diff --git a/variables_test.go b/variables_test.go index 85119e7b..f086ce17 100644 --- a/variables_test.go +++ b/variables_test.go @@ -67,7 +67,7 @@ func inputResolved(p graphql.GQLFRParams) interface{} { var testType *graphql.Object = graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", - Fields: graphql.FieldConfigMap{ + Fields: graphql.Fields{ "fieldWithObjectInput": &graphql.FieldConfig{ Type: graphql.String, Args: graphql.FieldConfigArgument{ From 7b2764e2069a67bb5583c628d3b67a7498715638 Mon Sep 17 00:00:00 2001 From: Fugiman Date: Sat, 7 Nov 2015 04:26:34 -0800 Subject: [PATCH 04/41] graphql.FieldConfig -> graphql.Field --- abstract_test.go | 48 +++++++------- definition.go | 8 +-- definition_test.go | 54 +++++++-------- directives_test.go | 4 +- enum_type_test.go | 6 +- examples/hello-world/main.go | 2 +- examples/http/main.go | 6 +- executor_schema_test.go | 32 ++++----- executor_test.go | 80 +++++++++++----------- graphql_test.go | 2 +- introspection.go | 78 +++++++++++----------- introspection_test.go | 24 +++---- lists_test.go | 4 +- mutations_test.go | 12 ++-- nonnull_test.go | 16 ++--- testutil/testutil.go | 34 +++++----- union_interface_test.go | 22 +++---- validation_test.go | 124 +++++++++++++++++------------------ variables_test.go | 16 ++--- 19 files changed, 286 insertions(+), 286 deletions(-) diff --git a/abstract_test.go b/abstract_test.go index 4758bb45..955c8675 100644 --- a/abstract_test.go +++ b/abstract_test.go @@ -29,7 +29,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { petType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "Pet", Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, }, }, @@ -46,7 +46,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { return ok }, Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { if dog, ok := p.Source.(*testDog); ok { @@ -55,7 +55,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { return nil }, }, - "woofs": &graphql.FieldConfig{ + "woofs": &graphql.Field{ Type: graphql.Boolean, Resolve: func(p graphql.GQLFRParams) interface{} { if dog, ok := p.Source.(*testDog); ok { @@ -77,7 +77,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { return ok }, Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { if cat, ok := p.Source.(*testCat); ok { @@ -86,7 +86,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { return nil }, }, - "meows": &graphql.FieldConfig{ + "meows": &graphql.Field{ Type: graphql.Boolean, Resolve: func(p graphql.GQLFRParams) interface{} { if cat, ok := p.Source.(*testCat); ok { @@ -101,7 +101,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "pets": &graphql.FieldConfig{ + "pets": &graphql.Field{ Type: graphql.NewList(petType), Resolve: func(p graphql.GQLFRParams) interface{} { return []interface{}{ @@ -166,7 +166,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { return ok }, Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { if dog, ok := p.Source.(*testDog); ok { @@ -175,7 +175,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { return nil }, }, - "woofs": &graphql.FieldConfig{ + "woofs": &graphql.Field{ Type: graphql.Boolean, Resolve: func(p graphql.GQLFRParams) interface{} { if dog, ok := p.Source.(*testDog); ok { @@ -193,7 +193,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { return ok }, Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { if cat, ok := p.Source.(*testCat); ok { @@ -202,7 +202,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { return nil }, }, - "meows": &graphql.FieldConfig{ + "meows": &graphql.Field{ Type: graphql.Boolean, Resolve: func(p graphql.GQLFRParams) interface{} { if cat, ok := p.Source.(*testCat); ok { @@ -233,7 +233,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "pets": &graphql.FieldConfig{ + "pets": &graphql.Field{ Type: graphql.NewList(petType), Resolve: func(p graphql.GQLFRParams) interface{} { return []interface{}{ @@ -298,7 +298,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { petType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "Pet", Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, }, }, @@ -319,7 +319,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { humanType = graphql.NewObject(graphql.ObjectConfig{ Name: "Human", Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { if human, ok := p.Source.(*testHuman); ok { @@ -340,7 +340,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { return ok }, Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { if dog, ok := p.Source.(*testDog); ok { @@ -349,7 +349,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { return nil }, }, - "woofs": &graphql.FieldConfig{ + "woofs": &graphql.Field{ Type: graphql.Boolean, Resolve: func(p graphql.GQLFRParams) interface{} { if dog, ok := p.Source.(*testDog); ok { @@ -370,7 +370,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { return ok }, Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { if cat, ok := p.Source.(*testCat); ok { @@ -379,7 +379,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { return nil }, }, - "meows": &graphql.FieldConfig{ + "meows": &graphql.Field{ Type: graphql.Boolean, Resolve: func(p graphql.GQLFRParams) interface{} { if cat, ok := p.Source.(*testCat); ok { @@ -394,7 +394,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "pets": &graphql.FieldConfig{ + "pets": &graphql.Field{ Type: graphql.NewList(petType), Resolve: func(p graphql.GQLFRParams) interface{} { return []interface{}{ @@ -462,7 +462,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { humanType := graphql.NewObject(graphql.ObjectConfig{ Name: "Human", Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { if human, ok := p.Source.(*testHuman); ok { @@ -480,7 +480,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { return ok }, Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { if dog, ok := p.Source.(*testDog); ok { @@ -489,7 +489,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { return nil }, }, - "woofs": &graphql.FieldConfig{ + "woofs": &graphql.Field{ Type: graphql.Boolean, Resolve: func(p graphql.GQLFRParams) interface{} { if dog, ok := p.Source.(*testDog); ok { @@ -507,7 +507,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { return ok }, Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { if cat, ok := p.Source.(*testCat); ok { @@ -516,7 +516,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { return nil }, }, - "meows": &graphql.FieldConfig{ + "meows": &graphql.Field{ Type: graphql.Boolean, Resolve: func(p graphql.GQLFRParams) interface{} { if cat, ok := p.Source.(*testCat); ok { @@ -549,7 +549,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "pets": &graphql.FieldConfig{ + "pets": &graphql.Field{ Type: graphql.NewList(petType), Resolve: func(p graphql.GQLFRParams) interface{} { return []interface{}{ diff --git a/definition.go b/definition.go index 4e8c62ae..98a6cf0c 100644 --- a/definition.go +++ b/definition.go @@ -343,7 +343,7 @@ func NewObject(config ObjectConfig) *Object { return objectType } -func (gt *Object) AddFieldConfig(fieldName string, fieldConfig *FieldConfig) { +func (gt *Object) AddFieldConfig(fieldName string, fieldConfig *Field) { if fieldName == "" || fieldConfig == nil { return } @@ -512,9 +512,9 @@ type ResolveInfo struct { VariableValues map[string]interface{} } -type Fields map[string]*FieldConfig +type Fields map[string]*Field -type FieldConfig struct { +type Field struct { Name string `json:"name"` // used by graphlql-relay Type Output `json:"type"` Args FieldConfigArgument `json:"args"` @@ -629,7 +629,7 @@ func NewInterface(config InterfaceConfig) *Interface { return it } -func (it *Interface) AddFieldConfig(fieldName string, fieldConfig *FieldConfig) { +func (it *Interface) AddFieldConfig(fieldName string, fieldConfig *Field) { if fieldName == "" || fieldConfig == nil { return } diff --git a/definition_test.go b/definition_test.go index 60195f01..c7cc4594 100644 --- a/definition_test.go +++ b/definition_test.go @@ -12,13 +12,13 @@ import ( var blogImage = graphql.NewObject(graphql.ObjectConfig{ Name: "Image", Fields: graphql.Fields{ - "url": &graphql.FieldConfig{ + "url": &graphql.Field{ Type: graphql.String, }, - "width": &graphql.FieldConfig{ + "width": &graphql.Field{ Type: graphql.Int, }, - "height": &graphql.FieldConfig{ + "height": &graphql.Field{ Type: graphql.Int, }, }, @@ -26,13 +26,13 @@ var blogImage = graphql.NewObject(graphql.ObjectConfig{ var blogAuthor = graphql.NewObject(graphql.ObjectConfig{ Name: "Author", Fields: graphql.Fields{ - "id": &graphql.FieldConfig{ + "id": &graphql.Field{ Type: graphql.String, }, - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, }, - "pic": &graphql.FieldConfig{ + "pic": &graphql.Field{ Type: blogImage, Args: graphql.FieldConfigArgument{ "width": &graphql.ArgumentConfig{ @@ -43,25 +43,25 @@ var blogAuthor = graphql.NewObject(graphql.ObjectConfig{ }, }, }, - "recentArticle": &graphql.FieldConfig{}, + "recentArticle": &graphql.Field{}, }, }) var blogArticle = graphql.NewObject(graphql.ObjectConfig{ Name: "Article", Fields: graphql.Fields{ - "id": &graphql.FieldConfig{ + "id": &graphql.Field{ Type: graphql.String, }, - "isPublished": &graphql.FieldConfig{ + "isPublished": &graphql.Field{ Type: graphql.Boolean, }, - "author": &graphql.FieldConfig{ + "author": &graphql.Field{ Type: blogAuthor, }, - "title": &graphql.FieldConfig{ + "title": &graphql.Field{ Type: graphql.String, }, - "body": &graphql.FieldConfig{ + "body": &graphql.Field{ Type: graphql.String, }, }, @@ -69,7 +69,7 @@ var blogArticle = graphql.NewObject(graphql.ObjectConfig{ var blogQuery = graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "article": &graphql.FieldConfig{ + "article": &graphql.Field{ Type: blogArticle, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ @@ -77,7 +77,7 @@ var blogQuery = graphql.NewObject(graphql.ObjectConfig{ }, }, }, - "feed": &graphql.FieldConfig{ + "feed": &graphql.Field{ Type: graphql.NewList(blogArticle), }, }, @@ -86,7 +86,7 @@ var blogQuery = graphql.NewObject(graphql.ObjectConfig{ var blogMutation = graphql.NewObject(graphql.ObjectConfig{ Name: "Mutation", Fields: graphql.Fields{ - "writeArticle": &graphql.FieldConfig{ + "writeArticle": &graphql.Field{ Type: blogArticle, }, }, @@ -118,7 +118,7 @@ var inputObjectType = graphql.NewInputObject(graphql.InputObjectConfig{ }) func init() { - blogAuthor.AddFieldConfig("recentArticle", &graphql.FieldConfig{ + blogAuthor.AddFieldConfig("recentArticle", &graphql.Field{ Type: blogArticle, }) } @@ -247,7 +247,7 @@ func TestTypeSystem_DefinitionExample_IncludesNestedInputObjectsInTheMap(t *test someMutation := graphql.NewObject(graphql.ObjectConfig{ Name: "SomeMutation", Fields: graphql.Fields{ - "mutateSomething": &graphql.FieldConfig{ + "mutateSomething": &graphql.Field{ Type: blogArticle, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -274,7 +274,7 @@ func TestTypeSystem_DefinitionExample_IncludesInterfacesSubTypesInTheTypeMap(t * someInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "SomeInterface", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.Int, }, }, @@ -283,7 +283,7 @@ func TestTypeSystem_DefinitionExample_IncludesInterfacesSubTypesInTheTypeMap(t * someSubType := graphql.NewObject(graphql.ObjectConfig{ Name: "SomeSubtype", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.Int, }, }, @@ -296,7 +296,7 @@ func TestTypeSystem_DefinitionExample_IncludesInterfacesSubTypesInTheTypeMap(t * Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "iface": &graphql.FieldConfig{ + "iface": &graphql.Field{ Type: someInterface, }, }, @@ -315,7 +315,7 @@ func TestTypeSystem_DefinitionExample_IncludesInterfacesThunkSubtypesInTheTypeMa someInterface := graphql.NewInterface(graphql.InterfaceConfig{ Name: "SomeInterface", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.Int, }, }, @@ -324,7 +324,7 @@ func TestTypeSystem_DefinitionExample_IncludesInterfacesThunkSubtypesInTheTypeMa someSubType := graphql.NewObject(graphql.ObjectConfig{ Name: "SomeSubtype", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.Int, }, }, @@ -339,7 +339,7 @@ func TestTypeSystem_DefinitionExample_IncludesInterfacesThunkSubtypesInTheTypeMa Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "iface": &graphql.FieldConfig{ + "iface": &graphql.Field{ Type: someInterface, }, }, @@ -460,10 +460,10 @@ func TestTypeSystem_DefinitionExample_ProhibitsNilTypeInUnions(t *testing.T) { } func TestTypeSystem_DefinitionExample_DoesNotMutatePassedFieldDefinitions(t *testing.T) { fields := graphql.Fields{ - "field1": &graphql.FieldConfig{ + "field1": &graphql.Field{ Type: graphql.String, }, - "field2": &graphql.FieldConfig{ + "field2": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ @@ -485,10 +485,10 @@ func TestTypeSystem_DefinitionExample_DoesNotMutatePassedFieldDefinitions(t *tes } expectedFields := graphql.Fields{ - "field1": &graphql.FieldConfig{ + "field1": &graphql.Field{ Type: graphql.String, }, - "field2": &graphql.FieldConfig{ + "field2": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ diff --git a/directives_test.go b/directives_test.go index b1b8f527..5c87aa5d 100644 --- a/directives_test.go +++ b/directives_test.go @@ -12,10 +12,10 @@ var directivesTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", Fields: graphql.Fields{ - "a": &graphql.FieldConfig{ + "a": &graphql.Field{ Type: graphql.String, }, - "b": &graphql.FieldConfig{ + "b": &graphql.Field{ Type: graphql.String, }, }, diff --git a/enum_type_test.go b/enum_type_test.go index ec87ca3c..47e6c338 100644 --- a/enum_type_test.go +++ b/enum_type_test.go @@ -26,7 +26,7 @@ var enumTypeTestColorType = graphql.NewEnum(graphql.EnumConfig{ var enumTypeTestQueryType = graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "colorEnum": &graphql.FieldConfig{ + "colorEnum": &graphql.Field{ Type: enumTypeTestColorType, Args: graphql.FieldConfigArgument{ "fromEnum": &graphql.ArgumentConfig{ @@ -52,7 +52,7 @@ var enumTypeTestQueryType = graphql.NewObject(graphql.ObjectConfig{ return nil }, }, - "colorInt": &graphql.FieldConfig{ + "colorInt": &graphql.Field{ Type: graphql.Int, Args: graphql.FieldConfigArgument{ "fromEnum": &graphql.ArgumentConfig{ @@ -77,7 +77,7 @@ var enumTypeTestQueryType = graphql.NewObject(graphql.ObjectConfig{ var enumTypeTestMutationType = graphql.NewObject(graphql.ObjectConfig{ Name: "Mutation", Fields: graphql.Fields{ - "favoriteEnum": &graphql.FieldConfig{ + "favoriteEnum": &graphql.Field{ Type: enumTypeTestColorType, Args: graphql.FieldConfigArgument{ "color": &graphql.ArgumentConfig{ diff --git a/examples/hello-world/main.go b/examples/hello-world/main.go index 3f8f4a4a..52115ef7 100644 --- a/examples/hello-world/main.go +++ b/examples/hello-world/main.go @@ -11,7 +11,7 @@ import ( func main() { // Schema fields := graphql.Fields{ - "hello": &graphql.FieldConfig{ + "hello": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { return "world" diff --git a/examples/http/main.go b/examples/http/main.go index 1d64eb7f..7788182b 100644 --- a/examples/http/main.go +++ b/examples/http/main.go @@ -26,10 +26,10 @@ var userType = graphql.NewObject( graphql.ObjectConfig{ Name: "User", Fields: graphql.Fields{ - "id": &graphql.FieldConfig{ + "id": &graphql.Field{ Type: graphql.String, }, - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, }, }, @@ -49,7 +49,7 @@ var queryType = graphql.NewObject( graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "user": &graphql.FieldConfig{ + "user": &graphql.Field{ Type: userType, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ diff --git a/executor_schema_test.go b/executor_schema_test.go index e14f7fa2..ca7a9560 100644 --- a/executor_schema_test.go +++ b/executor_schema_test.go @@ -76,13 +76,13 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { blogImage := graphql.NewObject(graphql.ObjectConfig{ Name: "Image", Fields: graphql.Fields{ - "url": &graphql.FieldConfig{ + "url": &graphql.Field{ Type: graphql.String, }, - "width": &graphql.FieldConfig{ + "width": &graphql.Field{ Type: graphql.Int, }, - "height": &graphql.FieldConfig{ + "height": &graphql.Field{ Type: graphql.Int, }, }, @@ -90,13 +90,13 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { blogAuthor := graphql.NewObject(graphql.ObjectConfig{ Name: "Author", Fields: graphql.Fields{ - "id": &graphql.FieldConfig{ + "id": &graphql.Field{ Type: graphql.String, }, - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, }, - "pic": &graphql.FieldConfig{ + "pic": &graphql.Field{ Type: blogImage, Args: graphql.FieldConfigArgument{ "width": &graphql.ArgumentConfig{ @@ -115,41 +115,41 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { return nil }, }, - "recentArticle": &graphql.FieldConfig{}, + "recentArticle": &graphql.Field{}, }, }) blogArticle := graphql.NewObject(graphql.ObjectConfig{ Name: "Article", Fields: graphql.Fields{ - "id": &graphql.FieldConfig{ + "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), }, - "isPublished": &graphql.FieldConfig{ + "isPublished": &graphql.Field{ Type: graphql.Boolean, }, - "author": &graphql.FieldConfig{ + "author": &graphql.Field{ Type: blogAuthor, }, - "title": &graphql.FieldConfig{ + "title": &graphql.Field{ Type: graphql.String, }, - "body": &graphql.FieldConfig{ + "body": &graphql.Field{ Type: graphql.String, }, - "keywords": &graphql.FieldConfig{ + "keywords": &graphql.Field{ Type: graphql.NewList(graphql.String), }, }, }) - blogAuthor.AddFieldConfig("recentArticle", &graphql.FieldConfig{ + blogAuthor.AddFieldConfig("recentArticle", &graphql.Field{ Type: blogArticle, }) blogQuery := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "article": &graphql.FieldConfig{ + "article": &graphql.Field{ Type: blogArticle, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ @@ -161,7 +161,7 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { return article(id) }, }, - "feed": &graphql.FieldConfig{ + "feed": &graphql.Field{ Type: graphql.NewList(blogArticle), Resolve: func(p graphql.GQLFRParams) interface{} { return []*testArticle{ diff --git a/executor_test.go b/executor_test.go index ca243cac..e2cddaef 100644 --- a/executor_test.go +++ b/executor_test.go @@ -119,25 +119,25 @@ func TestExecutesArbitraryCode(t *testing.T) { dataType := graphql.NewObject(graphql.ObjectConfig{ Name: "DataType", Fields: graphql.Fields{ - "a": &graphql.FieldConfig{ + "a": &graphql.Field{ Type: graphql.String, }, - "b": &graphql.FieldConfig{ + "b": &graphql.Field{ Type: graphql.String, }, - "c": &graphql.FieldConfig{ + "c": &graphql.Field{ Type: graphql.String, }, - "d": &graphql.FieldConfig{ + "d": &graphql.Field{ Type: graphql.String, }, - "e": &graphql.FieldConfig{ + "e": &graphql.Field{ Type: graphql.String, }, - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, - "pic": &graphql.FieldConfig{ + "pic": &graphql.Field{ Args: graphql.FieldConfigArgument{ "size": &graphql.ArgumentConfig{ Type: graphql.Int, @@ -151,16 +151,16 @@ func TestExecutesArbitraryCode(t *testing.T) { deepDataType := graphql.NewObject(graphql.ObjectConfig{ Name: "DeepDataType", Fields: graphql.Fields{ - "a": &graphql.FieldConfig{ + "a": &graphql.Field{ Type: graphql.String, }, - "b": &graphql.FieldConfig{ + "b": &graphql.Field{ Type: graphql.String, }, - "c": &graphql.FieldConfig{ + "c": &graphql.Field{ Type: graphql.NewList(graphql.String), }, - "deeper": &graphql.FieldConfig{ + "deeper": &graphql.Field{ Type: graphql.NewList(dataType), }, }, @@ -168,11 +168,11 @@ func TestExecutesArbitraryCode(t *testing.T) { // Exploring a way to have a Object within itself // in this case DataType has DeepDataType has DataType - dataType.AddFieldConfig("deep", &graphql.FieldConfig{ + dataType.AddFieldConfig("deep", &graphql.Field{ Type: deepDataType, }) // in this case DataType has DataType - dataType.AddFieldConfig("promise", &graphql.FieldConfig{ + dataType.AddFieldConfig("promise", &graphql.Field{ Type: dataType, }) @@ -242,19 +242,19 @@ func TestMergesParallelFragments(t *testing.T) { typeObjectType := graphql.NewObject(graphql.ObjectConfig{ Name: "Type", Fields: graphql.Fields{ - "a": &graphql.FieldConfig{ + "a": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { return "Apple" }, }, - "b": &graphql.FieldConfig{ + "b": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { return "Banana" }, }, - "c": &graphql.FieldConfig{ + "c": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { return "Cherry" @@ -262,7 +262,7 @@ func TestMergesParallelFragments(t *testing.T) { }, }, }) - deepTypeFieldConfig := &graphql.FieldConfig{ + deepTypeFieldConfig := &graphql.Field{ Type: typeObjectType, Resolve: func(p graphql.GQLFRParams) interface{} { return p.Source @@ -310,7 +310,7 @@ func TestThreadsContextCorrectly(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", Fields: graphql.Fields{ - "a": &graphql.FieldConfig{ + "a": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { resolvedContext = p.Source.(map[string]interface{}) @@ -358,7 +358,7 @@ func TestCorrectlyThreadsArguments(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", Fields: graphql.Fields{ - "b": &graphql.FieldConfig{ + "b": &graphql.Field{ Args: graphql.FieldConfigArgument{ "numArg": &graphql.ArgumentConfig{ Type: graphql.Int, @@ -438,10 +438,10 @@ func TestNullsOutErrorSubtrees(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", Fields: graphql.Fields{ - "sync": &graphql.FieldConfig{ + "sync": &graphql.Field{ Type: graphql.String, }, - "syncError": &graphql.FieldConfig{ + "syncError": &graphql.Field{ Type: graphql.String, }, }, @@ -489,7 +489,7 @@ func TestUsesTheInlineOperationIfNoOperationIsProvided(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", Fields: graphql.Fields{ - "a": &graphql.FieldConfig{ + "a": &graphql.Field{ Type: graphql.String, }, }, @@ -534,7 +534,7 @@ func TestUsesTheOnlyOperationIfNoOperationIsProvided(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", Fields: graphql.Fields{ - "a": &graphql.FieldConfig{ + "a": &graphql.Field{ Type: graphql.String, }, }, @@ -580,7 +580,7 @@ func TestThrowsIfNoOperationIsProvidedWithMultipleOperations(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", Fields: graphql.Fields{ - "a": &graphql.FieldConfig{ + "a": &graphql.Field{ Type: graphql.String, }, }, @@ -629,7 +629,7 @@ func TestUsesTheQuerySchemaForQueries(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Q", Fields: graphql.Fields{ - "a": &graphql.FieldConfig{ + "a": &graphql.Field{ Type: graphql.String, }, }, @@ -637,7 +637,7 @@ func TestUsesTheQuerySchemaForQueries(t *testing.T) { Mutation: graphql.NewObject(graphql.ObjectConfig{ Name: "M", Fields: graphql.Fields{ - "c": &graphql.FieldConfig{ + "c": &graphql.Field{ Type: graphql.String, }, }, @@ -684,7 +684,7 @@ func TestUsesTheMutationSchemaForMutations(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Q", Fields: graphql.Fields{ - "a": &graphql.FieldConfig{ + "a": &graphql.Field{ Type: graphql.String, }, }, @@ -692,7 +692,7 @@ func TestUsesTheMutationSchemaForMutations(t *testing.T) { Mutation: graphql.NewObject(graphql.ObjectConfig{ Name: "M", Fields: graphql.Fields{ - "c": &graphql.FieldConfig{ + "c": &graphql.Field{ Type: graphql.String, }, }, @@ -754,19 +754,19 @@ func TestCorrectFieldOrderingDespiteExecutionOrder(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", Fields: graphql.Fields{ - "a": &graphql.FieldConfig{ + "a": &graphql.Field{ Type: graphql.String, }, - "b": &graphql.FieldConfig{ + "b": &graphql.Field{ Type: graphql.String, }, - "c": &graphql.FieldConfig{ + "c": &graphql.Field{ Type: graphql.String, }, - "d": &graphql.FieldConfig{ + "d": &graphql.Field{ Type: graphql.String, }, - "e": &graphql.FieldConfig{ + "e": &graphql.Field{ Type: graphql.String, }, }, @@ -832,7 +832,7 @@ func TestAvoidsRecursion(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", Fields: graphql.Fields{ - "a": &graphql.FieldConfig{ + "a": &graphql.Field{ Type: graphql.String, }, }, @@ -876,7 +876,7 @@ func TestDoesNotIncludeIllegalFieldsInOutput(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Q", Fields: graphql.Fields{ - "a": &graphql.FieldConfig{ + "a": &graphql.Field{ Type: graphql.String, }, }, @@ -884,7 +884,7 @@ func TestDoesNotIncludeIllegalFieldsInOutput(t *testing.T) { Mutation: graphql.NewObject(graphql.ObjectConfig{ Name: "M", Fields: graphql.Fields{ - "c": &graphql.FieldConfig{ + "c": &graphql.Field{ Type: graphql.String, }, }, @@ -925,7 +925,7 @@ func TestDoesNotIncludeArgumentsThatWereNotSet(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Type", Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "a": &graphql.ArgumentConfig{ @@ -1017,7 +1017,7 @@ func TestFailsWhenAnIsTypeOfCheckIsNotMet(t *testing.T) { return false }, Fields: graphql.Fields{ - "value": &graphql.FieldConfig{ + "value": &graphql.Field{ Type: graphql.String, Resolve: func(p graphql.GQLFRParams) interface{} { return p.Source.(testSpecialType).Value @@ -1029,7 +1029,7 @@ func TestFailsWhenAnIsTypeOfCheckIsNotMet(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "specials": &graphql.FieldConfig{ + "specials": &graphql.Field{ Type: graphql.NewList(specialType), Resolve: func(p graphql.GQLFRParams) interface{} { return p.Source.(map[string]interface{})["specials"] @@ -1081,7 +1081,7 @@ func TestFailsToExecuteQueryContainingATypeDefinition(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "foo": &graphql.FieldConfig{ + "foo": &graphql.Field{ Type: graphql.String, }, }, diff --git a/graphql_test.go b/graphql_test.go index d5000d27..c0dd137e 100644 --- a/graphql_test.go +++ b/graphql_test.go @@ -102,7 +102,7 @@ func TestBasicGraphQLExample(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "RootQueryType", Fields: graphql.Fields{ - "hello": &graphql.FieldConfig{ + "hello": &graphql.Field{ Description: "Returns `world`", Type: graphql.String, Resolve: helloFieldResolved, diff --git a/introspection.go b/introspection.go index 92a15e23..69391a97 100644 --- a/introspection.go +++ b/introspection.go @@ -84,7 +84,7 @@ func init() { __Type = NewObject(ObjectConfig{ Name: "__Type", Fields: Fields{ - "kind": &FieldConfig{ + "kind": &Field{ Type: NewNonNull(__TypeKind), Resolve: func(p GQLFRParams) interface{} { switch p.Source.(type) { @@ -108,34 +108,34 @@ func init() { panic(fmt.Sprintf("Unknown kind of type: %v", p.Source)) }, }, - "name": &FieldConfig{ + "name": &Field{ Type: String, }, - "description": &FieldConfig{ + "description": &Field{ Type: String, }, - "fields": &FieldConfig{}, - "interfaces": &FieldConfig{}, - "possibleTypes": &FieldConfig{}, - "enumValues": &FieldConfig{}, - "inputFields": &FieldConfig{}, - "ofType": &FieldConfig{}, + "fields": &Field{}, + "interfaces": &Field{}, + "possibleTypes": &Field{}, + "enumValues": &Field{}, + "inputFields": &Field{}, + "ofType": &Field{}, }, }) __InputValue = NewObject(ObjectConfig{ Name: "__InputValue", Fields: Fields{ - "name": &FieldConfig{ + "name": &Field{ Type: NewNonNull(String), }, - "description": &FieldConfig{ + "description": &Field{ Type: String, }, - "type": &FieldConfig{ + "type": &Field{ Type: NewNonNull(__Type), }, - "defaultValue": &FieldConfig{ + "defaultValue": &Field{ Type: String, Resolve: func(p GQLFRParams) interface{} { if inputVal, ok := p.Source.(*Argument); ok { @@ -161,13 +161,13 @@ func init() { __Field = NewObject(ObjectConfig{ Name: "__Field", Fields: Fields{ - "name": &FieldConfig{ + "name": &Field{ Type: NewNonNull(String), }, - "description": &FieldConfig{ + "description": &Field{ Type: String, }, - "args": &FieldConfig{ + "args": &Field{ Type: NewNonNull(NewList(NewNonNull(__InputValue))), Resolve: func(p GQLFRParams) interface{} { if field, ok := p.Source.(*FieldDefinition); ok { @@ -176,10 +176,10 @@ func init() { return []interface{}{} }, }, - "type": &FieldConfig{ + "type": &Field{ Type: NewNonNull(__Type), }, - "isDeprecated": &FieldConfig{ + "isDeprecated": &Field{ Type: NewNonNull(Boolean), Resolve: func(p GQLFRParams) interface{} { if field, ok := p.Source.(*FieldDefinition); ok { @@ -188,7 +188,7 @@ func init() { return false }, }, - "deprecationReason": &FieldConfig{ + "deprecationReason": &Field{ Type: String, }, }, @@ -197,24 +197,24 @@ func init() { __Directive = NewObject(ObjectConfig{ Name: "__Directive", Fields: Fields{ - "name": &FieldConfig{ + "name": &Field{ Type: NewNonNull(String), }, - "description": &FieldConfig{ + "description": &Field{ Type: String, }, - "args": &FieldConfig{ + "args": &Field{ Type: NewNonNull(NewList( NewNonNull(__InputValue), )), }, - "onOperation": &FieldConfig{ + "onOperation": &Field{ Type: NewNonNull(Boolean), }, - "onFragment": &FieldConfig{ + "onFragment": &Field{ Type: NewNonNull(Boolean), }, - "onField": &FieldConfig{ + "onField": &Field{ Type: NewNonNull(Boolean), }, }, @@ -227,7 +227,7 @@ server. It exposes all available types and directives on the server, as well as the entry points for query and mutation operations.`, Fields: Fields{ - "types": &FieldConfig{ + "types": &Field{ Description: "A list of all types supported by this server.", Type: NewNonNull(NewList( NewNonNull(__Type), @@ -243,7 +243,7 @@ mutation operations.`, return []Type{} }, }, - "queryType": &FieldConfig{ + "queryType": &Field{ Description: "The type that query operations will be rooted at.", Type: NewNonNull(__Type), Resolve: func(p GQLFRParams) interface{} { @@ -253,7 +253,7 @@ mutation operations.`, return nil }, }, - "mutationType": &FieldConfig{ + "mutationType": &Field{ Description: `If this server supports mutation, the type that ` + `mutation operations will be rooted at.`, Type: __Type, @@ -266,7 +266,7 @@ mutation operations.`, return nil }, }, - "directives": &FieldConfig{ + "directives": &Field{ Description: `A list of all directives supported by this server.`, Type: NewNonNull(NewList( NewNonNull(__Directive), @@ -284,13 +284,13 @@ mutation operations.`, __EnumValue = NewObject(ObjectConfig{ Name: "__EnumValue", Fields: Fields{ - "name": &FieldConfig{ + "name": &Field{ Type: NewNonNull(String), }, - "description": &FieldConfig{ + "description": &Field{ Type: String, }, - "isDeprecated": &FieldConfig{ + "isDeprecated": &Field{ Type: NewNonNull(Boolean), Resolve: func(p GQLFRParams) interface{} { if field, ok := p.Source.(*EnumValueDefinition); ok { @@ -299,7 +299,7 @@ mutation operations.`, return false }, }, - "deprecationReason": &FieldConfig{ + "deprecationReason": &Field{ Type: String, }, }, @@ -307,7 +307,7 @@ mutation operations.`, // Again, adding field configs to __Type that have cyclic reference here // because golang don't like them too much during init/compile-time - __Type.AddFieldConfig("fields", &FieldConfig{ + __Type.AddFieldConfig("fields", &Field{ Type: NewList(NewNonNull(__Field)), Args: FieldConfigArgument{ "includeDeprecated": &ArgumentConfig{ @@ -346,7 +346,7 @@ mutation operations.`, return nil }, }) - __Type.AddFieldConfig("interfaces", &FieldConfig{ + __Type.AddFieldConfig("interfaces", &Field{ Type: NewList(NewNonNull(__Type)), Resolve: func(p GQLFRParams) interface{} { switch ttype := p.Source.(type) { @@ -356,7 +356,7 @@ mutation operations.`, return nil }, }) - __Type.AddFieldConfig("possibleTypes", &FieldConfig{ + __Type.AddFieldConfig("possibleTypes", &Field{ Type: NewList(NewNonNull(__Type)), Resolve: func(p GQLFRParams) interface{} { switch ttype := p.Source.(type) { @@ -368,7 +368,7 @@ mutation operations.`, return nil }, }) - __Type.AddFieldConfig("enumValues", &FieldConfig{ + __Type.AddFieldConfig("enumValues", &Field{ Type: NewList(NewNonNull(__EnumValue)), Args: FieldConfigArgument{ "includeDeprecated": &ArgumentConfig{ @@ -395,7 +395,7 @@ mutation operations.`, return nil }, }) - __Type.AddFieldConfig("inputFields", &FieldConfig{ + __Type.AddFieldConfig("inputFields", &Field{ Type: NewList(NewNonNull(__InputValue)), Resolve: func(p GQLFRParams) interface{} { switch ttype := p.Source.(type) { @@ -409,7 +409,7 @@ mutation operations.`, return nil }, }) - __Type.AddFieldConfig("ofType", &FieldConfig{ + __Type.AddFieldConfig("ofType", &Field{ Type: __Type, }) diff --git a/introspection_test.go b/introspection_test.go index 698143ec..ec739f72 100644 --- a/introspection_test.go +++ b/introspection_test.go @@ -19,7 +19,7 @@ func TestIntrospection_ExecutesAnIntrospectionQuery(t *testing.T) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "QueryRoot", Fields: graphql.Fields{ - "onlyField": &graphql.FieldConfig{ + "onlyField": &graphql.Field{ Type: graphql.String, }, }, @@ -761,7 +761,7 @@ func TestIntrospection_ExecutesAnInputObject(t *testing.T) { testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "complex": &graphql.ArgumentConfig{ @@ -861,7 +861,7 @@ func TestIntrospection_SupportsThe__TypeRootField(t *testing.T) { testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", Fields: graphql.Fields{ - "testField": &graphql.FieldConfig{ + "testField": &graphql.Field{ Type: graphql.String, }, }, @@ -899,10 +899,10 @@ func TestIntrospection_IdentifiesDeprecatedFields(t *testing.T) { testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", Fields: graphql.Fields{ - "nonDeprecated": &graphql.FieldConfig{ + "nonDeprecated": &graphql.Field{ Type: graphql.String, }, - "deprecated": &graphql.FieldConfig{ + "deprecated": &graphql.Field{ Type: graphql.String, DeprecationReason: "Removed in 1.0", }, @@ -958,10 +958,10 @@ func TestIntrospection_RespectsTheIncludeDeprecatedParameterForFields(t *testing testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", Fields: graphql.Fields{ - "nonDeprecated": &graphql.FieldConfig{ + "nonDeprecated": &graphql.Field{ Type: graphql.String, }, - "deprecated": &graphql.FieldConfig{ + "deprecated": &graphql.Field{ Type: graphql.String, DeprecationReason: "Removed in 1.0", }, @@ -1042,7 +1042,7 @@ func TestIntrospection_IdentifiesDeprecatedEnumValues(t *testing.T) { testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", Fields: graphql.Fields{ - "testEnum": &graphql.FieldConfig{ + "testEnum": &graphql.Field{ Type: testEnum, }, }, @@ -1117,7 +1117,7 @@ func TestIntrospection_RespectsTheIncludeDeprecatedParameterForEnumValues(t *tes testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", Fields: graphql.Fields{ - "testEnum": &graphql.FieldConfig{ + "testEnum": &graphql.Field{ Type: testEnum, }, }, @@ -1191,7 +1191,7 @@ func TestIntrospection_FailsAsExpectedOnThe__TypeRootFieldWithoutAnArg(t *testin testType := graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", Fields: graphql.Fields{ - "testField": &graphql.FieldConfig{ + "testField": &graphql.Field{ Type: graphql.String, }, }, @@ -1235,7 +1235,7 @@ func TestIntrospection_ExposesDescriptionsOnTypesAndFields(t *testing.T) { queryRoot := graphql.NewObject(graphql.ObjectConfig{ Name: "QueryRoot", Fields: graphql.Fields{ - "onlyField": &graphql.FieldConfig{ + "onlyField": &graphql.Field{ Type: graphql.String, }, }, @@ -1301,7 +1301,7 @@ func TestIntrospection_ExposesDescriptionsOnEnums(t *testing.T) { queryRoot := graphql.NewObject(graphql.ObjectConfig{ Name: "QueryRoot", Fields: graphql.Fields{ - "onlyField": &graphql.FieldConfig{ + "onlyField": &graphql.Field{ Type: graphql.String, }, }, diff --git a/lists_test.go b/lists_test.go index 5e102a6a..42ad3008 100644 --- a/lists_test.go +++ b/lists_test.go @@ -18,12 +18,12 @@ func checkList(t *testing.T, testType graphql.Type, testData interface{}, expect dataType := graphql.NewObject(graphql.ObjectConfig{ Name: "DataType", Fields: graphql.Fields{ - "test": &graphql.FieldConfig{ + "test": &graphql.Field{ Type: testType, }, }, }) - dataType.AddFieldConfig("nest", &graphql.FieldConfig{ + dataType.AddFieldConfig("nest", &graphql.Field{ Type: dataType, Resolve: func(p graphql.GQLFRParams) interface{} { return data diff --git a/mutations_test.go b/mutations_test.go index c6cdfd48..241f738e 100644 --- a/mutations_test.go +++ b/mutations_test.go @@ -41,7 +41,7 @@ func (r *testRoot) PromiseAndFailToChangeTheNumber(newNumber int) *testNumberHol var numberHolderType = graphql.NewObject(graphql.ObjectConfig{ Name: "NumberHolder", Fields: graphql.Fields{ - "theNumber": &graphql.FieldConfig{ + "theNumber": &graphql.Field{ Type: graphql.Int, }, }, @@ -51,7 +51,7 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "numberHolder": &graphql.FieldConfig{ + "numberHolder": &graphql.Field{ Type: numberHolderType, }, }, @@ -59,7 +59,7 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Mutation: graphql.NewObject(graphql.ObjectConfig{ Name: "Mutation", Fields: graphql.Fields{ - "immediatelyChangeTheNumber": &graphql.FieldConfig{ + "immediatelyChangeTheNumber": &graphql.Field{ Type: numberHolderType, Args: graphql.FieldConfigArgument{ "newNumber": &graphql.ArgumentConfig{ @@ -73,7 +73,7 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ return obj.ImmediatelyChangeTheNumber(newNumber) }, }, - "promiseToChangeTheNumber": &graphql.FieldConfig{ + "promiseToChangeTheNumber": &graphql.Field{ Type: numberHolderType, Args: graphql.FieldConfigArgument{ "newNumber": &graphql.ArgumentConfig{ @@ -87,7 +87,7 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ return obj.PromiseToChangeTheNumber(newNumber) }, }, - "failToChangeTheNumber": &graphql.FieldConfig{ + "failToChangeTheNumber": &graphql.Field{ Type: numberHolderType, Args: graphql.FieldConfigArgument{ "newNumber": &graphql.ArgumentConfig{ @@ -101,7 +101,7 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ return obj.FailToChangeTheNumber(newNumber) }, }, - "promiseAndFailToChangeTheNumber": &graphql.FieldConfig{ + "promiseAndFailToChangeTheNumber": &graphql.Field{ Type: numberHolderType, Args: graphql.FieldConfigArgument{ "newNumber": &graphql.ArgumentConfig{ diff --git a/nonnull_test.go b/nonnull_test.go index 20df50e0..4ee4d2b6 100644 --- a/nonnull_test.go +++ b/nonnull_test.go @@ -49,16 +49,16 @@ var nullingData = map[string]interface{}{ var dataType = graphql.NewObject(graphql.ObjectConfig{ Name: "DataType", Fields: graphql.Fields{ - "sync": &graphql.FieldConfig{ + "sync": &graphql.Field{ Type: graphql.String, }, - "nonNullSync": &graphql.FieldConfig{ + "nonNullSync": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), }, - "promise": &graphql.FieldConfig{ + "promise": &graphql.Field{ Type: graphql.String, }, - "nonNullPromise": &graphql.FieldConfig{ + "nonNullPromise": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), }, }, @@ -95,16 +95,16 @@ func init() { return nullingData } - dataType.AddFieldConfig("nest", &graphql.FieldConfig{ + dataType.AddFieldConfig("nest", &graphql.Field{ Type: dataType, }) - dataType.AddFieldConfig("nonNullNest", &graphql.FieldConfig{ + dataType.AddFieldConfig("nonNullNest", &graphql.Field{ Type: graphql.NewNonNull(dataType), }) - dataType.AddFieldConfig("promiseNest", &graphql.FieldConfig{ + dataType.AddFieldConfig("promiseNest", &graphql.Field{ Type: dataType, }) - dataType.AddFieldConfig("nonNullPromiseNest", &graphql.FieldConfig{ + dataType.AddFieldConfig("nonNullPromiseNest", &graphql.Field{ Type: graphql.NewNonNull(dataType), }) } diff --git a/testutil/testutil.go b/testutil/testutil.go index f8a22daa..7555ff24 100644 --- a/testutil/testutil.go +++ b/testutil/testutil.go @@ -120,15 +120,15 @@ func init() { Name: "Character", Description: "A character in the Star Wars Trilogy", Fields: graphql.Fields{ - "id": &graphql.FieldConfig{ + "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the character.", }, - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, Description: "The name of the character.", }, - "appearsIn": &graphql.FieldConfig{ + "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", }, @@ -144,7 +144,7 @@ func init() { return droidType }, }) - characterInterface.AddFieldConfig("friends", &graphql.FieldConfig{ + characterInterface.AddFieldConfig("friends", &graphql.Field{ Type: graphql.NewList(characterInterface), Description: "The friends of the character, or an empty list if they have none.", }) @@ -153,7 +153,7 @@ func init() { Name: "Human", Description: "A humanoid creature in the Star Wars universe.", Fields: graphql.Fields{ - "id": &graphql.FieldConfig{ + "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the human.", Resolve: func(p graphql.GQLFRParams) interface{} { @@ -163,7 +163,7 @@ func init() { return nil }, }, - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, Description: "The name of the human.", Resolve: func(p graphql.GQLFRParams) interface{} { @@ -173,7 +173,7 @@ func init() { return nil }, }, - "friends": &graphql.FieldConfig{ + "friends": &graphql.Field{ Type: graphql.NewList(characterInterface), Description: "The friends of the human, or an empty list if they have none.", Resolve: func(p graphql.GQLFRParams) interface{} { @@ -183,7 +183,7 @@ func init() { return []interface{}{} }, }, - "appearsIn": &graphql.FieldConfig{ + "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", Resolve: func(p graphql.GQLFRParams) interface{} { @@ -193,7 +193,7 @@ func init() { return nil }, }, - "homePlanet": &graphql.FieldConfig{ + "homePlanet": &graphql.Field{ Type: graphql.String, Description: "The home planet of the human, or null if unknown.", Resolve: func(p graphql.GQLFRParams) interface{} { @@ -212,7 +212,7 @@ func init() { Name: "Droid", Description: "A mechanical creature in the Star Wars universe.", Fields: graphql.Fields{ - "id": &graphql.FieldConfig{ + "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the droid.", Resolve: func(p graphql.GQLFRParams) interface{} { @@ -222,7 +222,7 @@ func init() { return nil }, }, - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, Description: "The name of the droid.", Resolve: func(p graphql.GQLFRParams) interface{} { @@ -232,7 +232,7 @@ func init() { return nil }, }, - "friends": &graphql.FieldConfig{ + "friends": &graphql.Field{ Type: graphql.NewList(characterInterface), Description: "The friends of the droid, or an empty list if they have none.", Resolve: func(p graphql.GQLFRParams) interface{} { @@ -249,7 +249,7 @@ func init() { return []interface{}{} }, }, - "appearsIn": &graphql.FieldConfig{ + "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", Resolve: func(p graphql.GQLFRParams) interface{} { @@ -259,7 +259,7 @@ func init() { return nil }, }, - "primaryFunction": &graphql.FieldConfig{ + "primaryFunction": &graphql.Field{ Type: graphql.String, Description: "The primary function of the droid.", Resolve: func(p graphql.GQLFRParams) interface{} { @@ -278,7 +278,7 @@ func init() { queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "hero": &graphql.FieldConfig{ + "hero": &graphql.Field{ Type: characterInterface, Args: graphql.FieldConfigArgument{ "episode": &graphql.ArgumentConfig{ @@ -291,7 +291,7 @@ func init() { return GetHero(p.Args["episode"]) }, }, - "human": &graphql.FieldConfig{ + "human": &graphql.Field{ Type: humanType, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ @@ -303,7 +303,7 @@ func init() { return GetHuman(p.Args["id"].(int)) }, }, - "droid": &graphql.FieldConfig{ + "droid": &graphql.Field{ Type: droidType, Args: graphql.FieldConfigArgument{ "id": &graphql.ArgumentConfig{ diff --git a/union_interface_test.go b/union_interface_test.go index 2db9c390..ce8ac8c2 100644 --- a/union_interface_test.go +++ b/union_interface_test.go @@ -31,7 +31,7 @@ type testPerson struct { var namedType = graphql.NewInterface(graphql.InterfaceConfig{ Name: "Named", Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, }, }, @@ -42,10 +42,10 @@ var dogType = graphql.NewObject(graphql.ObjectConfig{ namedType, }, Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, }, - "barks": &graphql.FieldConfig{ + "barks": &graphql.Field{ Type: graphql.Boolean, }, }, @@ -60,10 +60,10 @@ var catType = graphql.NewObject(graphql.ObjectConfig{ namedType, }, Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, }, - "meows": &graphql.FieldConfig{ + "meows": &graphql.Field{ Type: graphql.Boolean, }, }, @@ -93,13 +93,13 @@ var personType = graphql.NewObject(graphql.ObjectConfig{ namedType, }, Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, }, - "pets": &graphql.FieldConfig{ + "pets": &graphql.Field{ Type: graphql.NewList(petType), }, - "friends": &graphql.FieldConfig{ + "friends": &graphql.Field{ Type: graphql.NewList(namedType), }, }, @@ -505,7 +505,7 @@ func TestUnionIntersectionTypes_GetsExecutionInfoInResolver(t *testing.T) { namedType2 := graphql.NewInterface(graphql.InterfaceConfig{ Name: "Named", Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, }, }, @@ -522,10 +522,10 @@ func TestUnionIntersectionTypes_GetsExecutionInfoInResolver(t *testing.T) { namedType2, }, Fields: graphql.Fields{ - "name": &graphql.FieldConfig{ + "name": &graphql.Field{ Type: graphql.String, }, - "friends": &graphql.FieldConfig{ + "friends": &graphql.Field{ Type: graphql.NewList(namedType2), }, }, diff --git a/validation_test.go b/validation_test.go index c71f0662..cfbbf182 100644 --- a/validation_test.go +++ b/validation_test.go @@ -22,7 +22,7 @@ var someScalarType = graphql.NewScalar(graphql.ScalarConfig{ var someObjectType = graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -33,7 +33,7 @@ var objectWithIsTypeOf = graphql.NewObject(graphql.ObjectConfig{ return true }, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -53,7 +53,7 @@ var someInterfaceType = graphql.NewInterface(graphql.InterfaceConfig{ return nil }, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -108,7 +108,7 @@ func schemaWithFieldType(ttype graphql.Output) (graphql.Schema, error) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: ttype, }, }, @@ -120,7 +120,7 @@ func schemaWithInputObject(ttype graphql.Input) (graphql.Schema, error) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "args": &graphql.ArgumentConfig{ @@ -137,7 +137,7 @@ func schemaWithObjectFieldOfType(fieldType graphql.Input) (graphql.Schema, error badObjectType := graphql.NewObject(graphql.ObjectConfig{ Name: "BadObject", Fields: graphql.Fields{ - "badField": &graphql.FieldConfig{ + "badField": &graphql.Field{ Type: fieldType, }, }, @@ -146,7 +146,7 @@ func schemaWithObjectFieldOfType(fieldType graphql.Input) (graphql.Schema, error Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: badObjectType, }, }, @@ -159,7 +159,7 @@ func schemaWithObjectImplementingType(implementedType *graphql.Interface) (graph Name: "BadObject", Interfaces: []*graphql.Interface{implementedType}, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -168,7 +168,7 @@ func schemaWithObjectImplementingType(implementedType *graphql.Interface) (graph Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: badObjectType, }, }, @@ -188,7 +188,7 @@ func schemaWithUnionOfType(ttype *graphql.Object) (graphql.Schema, error) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: badObjectType, }, }, @@ -200,7 +200,7 @@ func schemaWithInterfaceFieldOfType(ttype graphql.Type) (graphql.Schema, error) badInterfaceType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "BadInterface", Fields: graphql.Fields{ - "badField": &graphql.FieldConfig{ + "badField": &graphql.Field{ Type: ttype, }, }, @@ -209,7 +209,7 @@ func schemaWithInterfaceFieldOfType(ttype graphql.Type) (graphql.Schema, error) Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: badInterfaceType, }, }, @@ -221,7 +221,7 @@ func schemaWithArgOfType(ttype graphql.Type) (graphql.Schema, error) { badObject := graphql.NewObject(graphql.ObjectConfig{ Name: "BadObject", Fields: graphql.Fields{ - "badField": &graphql.FieldConfig{ + "badField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "badArg": &graphql.ArgumentConfig{ @@ -235,7 +235,7 @@ func schemaWithArgOfType(ttype graphql.Type) (graphql.Schema, error) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: badObject, }, }, @@ -256,7 +256,7 @@ func schemaWithInputFieldOfType(ttype graphql.Type) (graphql.Schema, error) { Query: graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "badArg": &graphql.ArgumentConfig{ @@ -281,7 +281,7 @@ func TestTypeSystem_SchemaMustHaveObjectRootTypes_AcceptsASchemaWhoseQueryAndMut mutationObject := graphql.NewObject(graphql.ObjectConfig{ Name: "Mutation", Fields: graphql.Fields{ - "edit": &graphql.FieldConfig{ + "edit": &graphql.Field{ Type: graphql.String, }, }, @@ -313,10 +313,10 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichRedef queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "normal": &graphql.FieldConfig{ + "normal": &graphql.Field{ Type: graphql.String, }, - "fake": &graphql.FieldConfig{ + "fake": &graphql.Field{ Type: fakeString, }, }, @@ -334,7 +334,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichDefin a := graphql.NewObject(graphql.ObjectConfig{ Name: "SameName", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -342,7 +342,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichDefin b := graphql.NewObject(graphql.ObjectConfig{ Name: "SameName", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -350,10 +350,10 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichDefin queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "a": &graphql.FieldConfig{ + "a": &graphql.Field{ Type: a, }, - "b": &graphql.FieldConfig{ + "b": &graphql.Field{ Type: b, }, }, @@ -374,7 +374,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichHaveS return nil }, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -385,7 +385,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichHaveS anotherInterface, }, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -396,7 +396,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichHaveS anotherInterface, }, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -404,7 +404,7 @@ func TestTypeSystem_SchemaMustContainUniquelyNamedTypes_RejectsASchemaWhichHaveS queryType := graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ - "iface": &graphql.FieldConfig{ + "iface": &graphql.Field{ Type: anotherInterface, }, }, @@ -422,7 +422,7 @@ func TestTypeSystem_ObjectsMustHaveFields_AcceptsAnObjectTypeWithFieldsObject(t _, err := schemaWithFieldType(graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -445,7 +445,7 @@ func TestTypeSystem_ObjectsMustHaveFields_RejectsAnObjectTypeWithIncorrectlyName badObject := graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", Fields: graphql.Fields{ - "bad-name-with-dashes": &graphql.FieldConfig{ + "bad-name-with-dashes": &graphql.Field{ Type: graphql.String, }, }, @@ -472,7 +472,7 @@ func TestTypeSystem_FieldsArgsMustBeProperlyNamed_AcceptsFieldArgsWithValidNames _, err := schemaWithFieldType(graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", Fields: graphql.Fields{ - "goodField": &graphql.FieldConfig{ + "goodField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "goodArgs": &graphql.ArgumentConfig{ @@ -490,7 +490,7 @@ func TestTypeSystem_FieldsArgsMustBeProperlyNamed_RejectsFieldArgWithInvalidName _, err := schemaWithFieldType(graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", Fields: graphql.Fields{ - "badField": &graphql.FieldConfig{ + "badField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "bad-name-with-dashes": &graphql.ArgumentConfig{ @@ -510,7 +510,7 @@ func TestTypeSystem_FieldsArgsMustBeObjects_AcceptsAnObjectTypeWithFieldArgs(t * _, err := schemaWithFieldType(graphql.NewObject(graphql.ObjectConfig{ Name: "SomeObject", Fields: graphql.Fields{ - "goodField": &graphql.FieldConfig{ + "goodField": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "goodArgs": &graphql.ArgumentConfig{ @@ -532,7 +532,7 @@ func TestTypeSystem_ObjectInterfacesMustBeArray_AcceptsAnObjectTypeWithArrayInte return nil }, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -543,7 +543,7 @@ func TestTypeSystem_ObjectInterfacesMustBeArray_AcceptsAnObjectTypeWithArrayInte return []*graphql.Interface{anotherInterfaceType} }), Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -560,7 +560,7 @@ func TestTypeSystem_ObjectInterfacesMustBeArray_AcceptsAnObjectTypeWithInterface return nil }, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -569,7 +569,7 @@ func TestTypeSystem_ObjectInterfacesMustBeArray_AcceptsAnObjectTypeWithInterface Name: "SomeObject", Interfaces: []*graphql.Interface{anotherInterfaceType}, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -676,7 +676,7 @@ func TestTypeSystem_ObjectTypesMustBeAssertable_AcceptsAnObjectTypeWithAnIsTypeO return true }, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -694,7 +694,7 @@ func TestTypeSystem_InterfaceTypesMustBeResolvable_AcceptsAnInterfaceTypeDefinin return nil }, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -703,7 +703,7 @@ func TestTypeSystem_InterfaceTypesMustBeResolvable_AcceptsAnInterfaceTypeDefinin Name: "SomeObject", Interfaces: []*graphql.Interface{anotherInterfaceType}, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -717,7 +717,7 @@ func TestTypeSystem_InterfaceTypesMustBeResolvable_AcceptsAnInterfaceWithImpleme anotherInterfaceType := graphql.NewInterface(graphql.InterfaceConfig{ Name: "AnotherInterface", Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -729,7 +729,7 @@ func TestTypeSystem_InterfaceTypesMustBeResolvable_AcceptsAnInterfaceWithImpleme return true }, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -747,7 +747,7 @@ func TestTypeSystem_InterfaceTypesMustBeResolvable_AcceptsAnInterfaceTypeDefinin return nil }, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -759,7 +759,7 @@ func TestTypeSystem_InterfaceTypesMustBeResolvable_AcceptsAnInterfaceTypeDefinin return true }, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -969,7 +969,7 @@ func TestTypeSystem_ObjectsCanOnlyImplementInterfaces_AcceptsAnObjectImplementin return nil }, Fields: graphql.Fields{ - "f": &graphql.FieldConfig{ + "f": &graphql.Field{ Type: graphql.String, }, }, @@ -1107,7 +1107,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWhi return nil }, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -1121,7 +1121,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWhi Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -1143,7 +1143,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWhi return nil }, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -1157,7 +1157,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWhi Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -1165,7 +1165,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWhi }, }, }, - "anotherfield": &graphql.FieldConfig{ + "anotherfield": &graphql.Field{ Type: graphql.String, }, }, @@ -1182,7 +1182,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWhi return nil }, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -1196,7 +1196,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWhi Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -1222,7 +1222,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectMis return nil }, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -1236,7 +1236,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectMis Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ - "anotherfield": &graphql.FieldConfig{ + "anotherfield": &graphql.Field{ Type: graphql.String, }, }, @@ -1254,7 +1254,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWit return nil }, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -1268,7 +1268,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWit Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: someScalarType, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -1291,7 +1291,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectMis return nil }, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -1305,7 +1305,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectMis Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, }, }, @@ -1323,7 +1323,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWit return nil }, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -1337,7 +1337,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWit Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -1360,7 +1360,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWit return nil }, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.NewNonNull(graphql.NewList(graphql.String)), }, }, @@ -1369,7 +1369,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_AcceptsAnObjectWit Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.NewNonNull(graphql.NewList(graphql.String)), }, }, @@ -1386,7 +1386,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWit return nil }, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.String, }, }, @@ -1395,7 +1395,7 @@ func TestTypeSystem_ObjectsMustAdhereToInterfaceTheyImplement_RejectsAnObjectWit Name: "AnotherObject", Interfaces: []*graphql.Interface{anotherInterface}, Fields: graphql.Fields{ - "field": &graphql.FieldConfig{ + "field": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), }, }, diff --git a/variables_test.go b/variables_test.go index f086ce17..2d3318e6 100644 --- a/variables_test.go +++ b/variables_test.go @@ -68,7 +68,7 @@ func inputResolved(p graphql.GQLFRParams) interface{} { var testType *graphql.Object = graphql.NewObject(graphql.ObjectConfig{ Name: "TestType", Fields: graphql.Fields{ - "fieldWithObjectInput": &graphql.FieldConfig{ + "fieldWithObjectInput": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -77,7 +77,7 @@ var testType *graphql.Object = graphql.NewObject(graphql.ObjectConfig{ }, Resolve: inputResolved, }, - "fieldWithNullableStringInput": &graphql.FieldConfig{ + "fieldWithNullableStringInput": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -86,7 +86,7 @@ var testType *graphql.Object = graphql.NewObject(graphql.ObjectConfig{ }, Resolve: inputResolved, }, - "fieldWithNonNullableStringInput": &graphql.FieldConfig{ + "fieldWithNonNullableStringInput": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -95,7 +95,7 @@ var testType *graphql.Object = graphql.NewObject(graphql.ObjectConfig{ }, Resolve: inputResolved, }, - "fieldWithDefaultArgumentValue": &graphql.FieldConfig{ + "fieldWithDefaultArgumentValue": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -105,7 +105,7 @@ var testType *graphql.Object = graphql.NewObject(graphql.ObjectConfig{ }, Resolve: inputResolved, }, - "list": &graphql.FieldConfig{ + "list": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -114,7 +114,7 @@ var testType *graphql.Object = graphql.NewObject(graphql.ObjectConfig{ }, Resolve: inputResolved, }, - "nnList": &graphql.FieldConfig{ + "nnList": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -123,7 +123,7 @@ var testType *graphql.Object = graphql.NewObject(graphql.ObjectConfig{ }, Resolve: inputResolved, }, - "listNN": &graphql.FieldConfig{ + "listNN": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ @@ -132,7 +132,7 @@ var testType *graphql.Object = graphql.NewObject(graphql.ObjectConfig{ }, Resolve: inputResolved, }, - "nnListNN": &graphql.FieldConfig{ + "nnListNN": &graphql.Field{ Type: graphql.String, Args: graphql.FieldConfigArgument{ "input": &graphql.ArgumentConfig{ From 82fcb0fa85161bc179c5fdd0cfe9d6f73283ce94 Mon Sep 17 00:00:00 2001 From: Fugiman Date: Sat, 7 Nov 2015 04:27:43 -0800 Subject: [PATCH 05/41] graphql.GQLFRParams -> graphql.ResolveParams --- abstract_test.go | 44 ++++++++++++++++++------------------ definition.go | 4 ++-- enum_type_test.go | 6 ++--- examples/hello-world/main.go | 2 +- examples/http/main.go | 2 +- executor.go | 4 ++-- executor_schema_test.go | 6 ++--- executor_test.go | 20 ++++++++-------- graphql_test.go | 2 +- introspection.go | 34 ++++++++++++++-------------- introspection_test.go | 2 +- lists_test.go | 2 +- mutations_test.go | 8 +++---- testutil/testutil.go | 26 ++++++++++----------- variables_test.go | 2 +- 15 files changed, 82 insertions(+), 82 deletions(-) diff --git a/abstract_test.go b/abstract_test.go index 955c8675..d5d15ed2 100644 --- a/abstract_test.go +++ b/abstract_test.go @@ -48,7 +48,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if dog, ok := p.Source.(*testDog); ok { return dog.Name } @@ -57,7 +57,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { }, "woofs": &graphql.Field{ Type: graphql.Boolean, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if dog, ok := p.Source.(*testDog); ok { return dog.Woofs } @@ -79,7 +79,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if cat, ok := p.Source.(*testCat); ok { return cat.Name } @@ -88,7 +88,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { }, "meows": &graphql.Field{ Type: graphql.Boolean, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if cat, ok := p.Source.(*testCat); ok { return cat.Meows } @@ -103,7 +103,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { Fields: graphql.Fields{ "pets": &graphql.Field{ Type: graphql.NewList(petType), - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { return []interface{}{ &testDog{"Odie", true}, &testCat{"Garfield", false}, @@ -168,7 +168,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if dog, ok := p.Source.(*testDog); ok { return dog.Name } @@ -177,7 +177,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { }, "woofs": &graphql.Field{ Type: graphql.Boolean, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if dog, ok := p.Source.(*testDog); ok { return dog.Woofs } @@ -195,7 +195,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if cat, ok := p.Source.(*testCat); ok { return cat.Name } @@ -204,7 +204,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { }, "meows": &graphql.Field{ Type: graphql.Boolean, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if cat, ok := p.Source.(*testCat); ok { return cat.Meows } @@ -235,7 +235,7 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { Fields: graphql.Fields{ "pets": &graphql.Field{ Type: graphql.NewList(petType), - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { return []interface{}{ &testDog{"Odie", true}, &testCat{"Garfield", false}, @@ -321,7 +321,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if human, ok := p.Source.(*testHuman); ok { return human.Name } @@ -342,7 +342,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if dog, ok := p.Source.(*testDog); ok { return dog.Name } @@ -351,7 +351,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { }, "woofs": &graphql.Field{ Type: graphql.Boolean, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if dog, ok := p.Source.(*testDog); ok { return dog.Woofs } @@ -372,7 +372,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if cat, ok := p.Source.(*testCat); ok { return cat.Name } @@ -381,7 +381,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { }, "meows": &graphql.Field{ Type: graphql.Boolean, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if cat, ok := p.Source.(*testCat); ok { return cat.Meows } @@ -396,7 +396,7 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { Fields: graphql.Fields{ "pets": &graphql.Field{ Type: graphql.NewList(petType), - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { return []interface{}{ &testDog{"Odie", true}, &testCat{"Garfield", false}, @@ -464,7 +464,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if human, ok := p.Source.(*testHuman); ok { return human.Name } @@ -482,7 +482,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if dog, ok := p.Source.(*testDog); ok { return dog.Name } @@ -491,7 +491,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { }, "woofs": &graphql.Field{ Type: graphql.Boolean, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if dog, ok := p.Source.(*testDog); ok { return dog.Woofs } @@ -509,7 +509,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if cat, ok := p.Source.(*testCat); ok { return cat.Name } @@ -518,7 +518,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { }, "meows": &graphql.Field{ Type: graphql.Boolean, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if cat, ok := p.Source.(*testCat); ok { return cat.Meows } @@ -551,7 +551,7 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { Fields: graphql.Fields{ "pets": &graphql.Field{ Type: graphql.NewList(petType), - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { return []interface{}{ &testDog{"Odie", true}, &testCat{"Garfield", false}, diff --git a/definition.go b/definition.go index 98a6cf0c..da7bf645 100644 --- a/definition.go +++ b/definition.go @@ -490,7 +490,7 @@ func defineFieldMap(ttype Named, fields Fields) (FieldDefinitionMap, error) { } // TODO: clean up GQLFRParams fields -type GQLFRParams struct { +type ResolveParams struct { Source interface{} Args map[string]interface{} Info ResolveInfo @@ -498,7 +498,7 @@ type GQLFRParams struct { } // TODO: relook at FieldResolveFn params -type FieldResolveFn func(p GQLFRParams) interface{} +type FieldResolveFn func(p ResolveParams) interface{} type ResolveInfo struct { FieldName string diff --git a/enum_type_test.go b/enum_type_test.go index 47e6c338..1db322ce 100644 --- a/enum_type_test.go +++ b/enum_type_test.go @@ -39,7 +39,7 @@ var enumTypeTestQueryType = graphql.NewObject(graphql.ObjectConfig{ Type: graphql.String, }, }, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if fromInt, ok := p.Args["fromInt"]; ok { return fromInt } @@ -62,7 +62,7 @@ var enumTypeTestQueryType = graphql.NewObject(graphql.ObjectConfig{ Type: graphql.Int, }, }, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if fromInt, ok := p.Args["fromInt"]; ok { return fromInt } @@ -84,7 +84,7 @@ var enumTypeTestMutationType = graphql.NewObject(graphql.ObjectConfig{ Type: enumTypeTestColorType, }, }, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if color, ok := p.Args["color"]; ok { return color } diff --git a/examples/hello-world/main.go b/examples/hello-world/main.go index 52115ef7..dda06cd3 100644 --- a/examples/hello-world/main.go +++ b/examples/hello-world/main.go @@ -13,7 +13,7 @@ func main() { fields := graphql.Fields{ "hello": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { return "world" }, }, diff --git a/examples/http/main.go b/examples/http/main.go index 7788182b..579e8183 100644 --- a/examples/http/main.go +++ b/examples/http/main.go @@ -56,7 +56,7 @@ var queryType = graphql.NewObject( Type: graphql.String, }, }, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { idQuery, isOK := p.Args["id"].(string) if isOK { return data[idQuery] diff --git a/executor.go b/executor.go index 1b6eb339..e9b024b1 100644 --- a/executor.go +++ b/executor.go @@ -498,7 +498,7 @@ func resolveField(eCtx *ExecutionContext, parentType *Object, source interface{} // it is wrapped as a Error with locations. Log this error and return // null if allowed, otherwise throw the error so the parent field can handle // it. - result = resolveFn(GQLFRParams{ + result = resolveFn(ResolveParams{ Source: source, Args: args, Info: info, @@ -674,7 +674,7 @@ func completeValue(eCtx *ExecutionContext, returnType Type, fieldASTs []*ast.Fie } -func defaultResolveFn(p GQLFRParams) interface{} { +func defaultResolveFn(p ResolveParams) interface{} { // try to resolve p.Source as a struct first sourceVal := reflect.ValueOf(p.Source) if sourceVal.IsValid() && sourceVal.Type().Kind() == reflect.Ptr { diff --git a/executor_schema_test.go b/executor_schema_test.go index ca7a9560..a127310a 100644 --- a/executor_schema_test.go +++ b/executor_schema_test.go @@ -106,7 +106,7 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { Type: graphql.Int, }, }, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if author, ok := p.Source.(*testAuthor); ok { width := fmt.Sprintf("%v", p.Args["width"]) height := fmt.Sprintf("%v", p.Args["height"]) @@ -156,14 +156,14 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { Type: graphql.ID, }, }, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { id := p.Args["id"] return article(id) }, }, "feed": &graphql.Field{ Type: graphql.NewList(blogArticle), - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { return []*testArticle{ article(1), article(2), diff --git a/executor_test.go b/executor_test.go index e2cddaef..8707b9e9 100644 --- a/executor_test.go +++ b/executor_test.go @@ -103,7 +103,7 @@ func TestExecutesArbitraryCode(t *testing.T) { } // Schema Definitions - picResolverFn := func(p graphql.GQLFRParams) interface{} { + picResolverFn := func(p graphql.ResolveParams) interface{} { // get and type assert ResolveFn for this field picResolver, ok := p.Source.(map[string]interface{})["pic"].(func(size int) string) if !ok { @@ -244,19 +244,19 @@ func TestMergesParallelFragments(t *testing.T) { Fields: graphql.Fields{ "a": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { return "Apple" }, }, "b": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { return "Banana" }, }, "c": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { return "Cherry" }, }, @@ -264,7 +264,7 @@ func TestMergesParallelFragments(t *testing.T) { }) deepTypeFieldConfig := &graphql.Field{ Type: typeObjectType, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { return p.Source }, } @@ -312,7 +312,7 @@ func TestThreadsContextCorrectly(t *testing.T) { Fields: graphql.Fields{ "a": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { resolvedContext = p.Source.(map[string]interface{}) return resolvedContext }, @@ -368,7 +368,7 @@ func TestCorrectlyThreadsArguments(t *testing.T) { }, }, Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { resolvedArgs = p.Args return resolvedArgs }, @@ -944,7 +944,7 @@ func TestDoesNotIncludeArgumentsThatWereNotSet(t *testing.T) { Type: graphql.Int, }, }, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { args, _ := json.Marshal(p.Args) return string(args) }, @@ -1019,7 +1019,7 @@ func TestFailsWhenAnIsTypeOfCheckIsNotMet(t *testing.T) { Fields: graphql.Fields{ "value": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { return p.Source.(testSpecialType).Value }, }, @@ -1031,7 +1031,7 @@ func TestFailsWhenAnIsTypeOfCheckIsNotMet(t *testing.T) { Fields: graphql.Fields{ "specials": &graphql.Field{ Type: graphql.NewList(specialType), - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { return p.Source.(map[string]interface{})["specials"] }, }, diff --git a/graphql_test.go b/graphql_test.go index c0dd137e..fc0473d5 100644 --- a/graphql_test.go +++ b/graphql_test.go @@ -94,7 +94,7 @@ func testGraphql(test T, p graphql.Params, t *testing.T) { func TestBasicGraphQLExample(t *testing.T) { // taken from `graphql-js` README - helloFieldResolved := func(p graphql.GQLFRParams) interface{} { + helloFieldResolved := func(p graphql.ResolveParams) interface{} { return "world" } diff --git a/introspection.go b/introspection.go index 69391a97..d6613775 100644 --- a/introspection.go +++ b/introspection.go @@ -86,7 +86,7 @@ func init() { Fields: Fields{ "kind": &Field{ Type: NewNonNull(__TypeKind), - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { switch p.Source.(type) { case *Scalar: return TypeKindScalar @@ -137,7 +137,7 @@ func init() { }, "defaultValue": &Field{ Type: String, - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { if inputVal, ok := p.Source.(*Argument); ok { if inputVal.DefaultValue == nil { return nil @@ -169,7 +169,7 @@ func init() { }, "args": &Field{ Type: NewNonNull(NewList(NewNonNull(__InputValue))), - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { if field, ok := p.Source.(*FieldDefinition); ok { return field.Args } @@ -181,7 +181,7 @@ func init() { }, "isDeprecated": &Field{ Type: NewNonNull(Boolean), - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { if field, ok := p.Source.(*FieldDefinition); ok { return (field.DeprecationReason != "") } @@ -232,7 +232,7 @@ mutation operations.`, Type: NewNonNull(NewList( NewNonNull(__Type), )), - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { if schema, ok := p.Source.(Schema); ok { results := []Type{} for _, ttype := range schema.GetTypeMap() { @@ -246,7 +246,7 @@ mutation operations.`, "queryType": &Field{ Description: "The type that query operations will be rooted at.", Type: NewNonNull(__Type), - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { if schema, ok := p.Source.(Schema); ok { return schema.GetQueryType() } @@ -257,7 +257,7 @@ mutation operations.`, Description: `If this server supports mutation, the type that ` + `mutation operations will be rooted at.`, Type: __Type, - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { if schema, ok := p.Source.(Schema); ok { if schema.GetMutationType() != nil { return schema.GetMutationType() @@ -271,7 +271,7 @@ mutation operations.`, Type: NewNonNull(NewList( NewNonNull(__Directive), )), - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { if schema, ok := p.Source.(Schema); ok { return schema.GetDirectives() } @@ -292,7 +292,7 @@ mutation operations.`, }, "isDeprecated": &Field{ Type: NewNonNull(Boolean), - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { if field, ok := p.Source.(*EnumValueDefinition); ok { return (field.DeprecationReason != "") } @@ -315,7 +315,7 @@ mutation operations.`, DefaultValue: false, }, }, - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { includeDeprecated, _ := p.Args["includeDeprecated"].(bool) switch ttype := p.Source.(type) { case *Object: @@ -348,7 +348,7 @@ mutation operations.`, }) __Type.AddFieldConfig("interfaces", &Field{ Type: NewList(NewNonNull(__Type)), - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { switch ttype := p.Source.(type) { case *Object: return ttype.GetInterfaces() @@ -358,7 +358,7 @@ mutation operations.`, }) __Type.AddFieldConfig("possibleTypes", &Field{ Type: NewList(NewNonNull(__Type)), - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { switch ttype := p.Source.(type) { case *Interface: return ttype.GetPossibleTypes() @@ -376,7 +376,7 @@ mutation operations.`, DefaultValue: false, }, }, - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { includeDeprecated, _ := p.Args["includeDeprecated"].(bool) switch ttype := p.Source.(type) { case *Enum: @@ -397,7 +397,7 @@ mutation operations.`, }) __Type.AddFieldConfig("inputFields", &Field{ Type: NewList(NewNonNull(__InputValue)), - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { switch ttype := p.Source.(type) { case *InputObject: fields := []*InputObjectField{} @@ -423,7 +423,7 @@ mutation operations.`, Type: NewNonNull(__Schema), Description: "Access the current type schema of this server.", Args: []*Argument{}, - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { return p.Info.Schema }, } @@ -437,7 +437,7 @@ mutation operations.`, Type: NewNonNull(String), }, }, - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { name, ok := p.Args["name"].(string) if !ok { return nil @@ -451,7 +451,7 @@ mutation operations.`, Type: NewNonNull(String), Description: "The name of the current Object type at runtime.", Args: []*Argument{}, - Resolve: func(p GQLFRParams) interface{} { + Resolve: func(p ResolveParams) interface{} { return p.Info.ParentType.GetName() }, } diff --git a/introspection_test.go b/introspection_test.go index ec739f72..1d314e93 100644 --- a/introspection_test.go +++ b/introspection_test.go @@ -768,7 +768,7 @@ func TestIntrospection_ExecutesAnInputObject(t *testing.T) { Type: testInputObject, }, }, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { return p.Args["complex"] }, }, diff --git a/lists_test.go b/lists_test.go index 42ad3008..5dad96c3 100644 --- a/lists_test.go +++ b/lists_test.go @@ -25,7 +25,7 @@ func checkList(t *testing.T, testType graphql.Type, testData interface{}, expect }) dataType.AddFieldConfig("nest", &graphql.Field{ Type: dataType, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { return data }, }) diff --git a/mutations_test.go b/mutations_test.go index 241f738e..eb076dcb 100644 --- a/mutations_test.go +++ b/mutations_test.go @@ -66,7 +66,7 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Type: graphql.Int, }, }, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { newNumber := 0 obj, _ := p.Source.(*testRoot) newNumber, _ = p.Args["newNumber"].(int) @@ -80,7 +80,7 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Type: graphql.Int, }, }, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { newNumber := 0 obj, _ := p.Source.(*testRoot) newNumber, _ = p.Args["newNumber"].(int) @@ -94,7 +94,7 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Type: graphql.Int, }, }, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { newNumber := 0 obj, _ := p.Source.(*testRoot) newNumber, _ = p.Args["newNumber"].(int) @@ -108,7 +108,7 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Type: graphql.Int, }, }, - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { newNumber := 0 obj, _ := p.Source.(*testRoot) newNumber, _ = p.Args["newNumber"].(int) diff --git a/testutil/testutil.go b/testutil/testutil.go index 7555ff24..11c0fc06 100644 --- a/testutil/testutil.go +++ b/testutil/testutil.go @@ -156,7 +156,7 @@ func init() { "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the human.", - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if human, ok := p.Source.(StarWarsChar); ok { return human.Id } @@ -166,7 +166,7 @@ func init() { "name": &graphql.Field{ Type: graphql.String, Description: "The name of the human.", - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if human, ok := p.Source.(StarWarsChar); ok { return human.Name } @@ -176,7 +176,7 @@ func init() { "friends": &graphql.Field{ Type: graphql.NewList(characterInterface), Description: "The friends of the human, or an empty list if they have none.", - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if human, ok := p.Source.(StarWarsChar); ok { return human.Friends } @@ -186,7 +186,7 @@ func init() { "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if human, ok := p.Source.(StarWarsChar); ok { return human.AppearsIn } @@ -196,7 +196,7 @@ func init() { "homePlanet": &graphql.Field{ Type: graphql.String, Description: "The home planet of the human, or null if unknown.", - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if human, ok := p.Source.(StarWarsChar); ok { return human.HomePlanet } @@ -215,7 +215,7 @@ func init() { "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the droid.", - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if droid, ok := p.Source.(StarWarsChar); ok { return droid.Id } @@ -225,7 +225,7 @@ func init() { "name": &graphql.Field{ Type: graphql.String, Description: "The name of the droid.", - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if droid, ok := p.Source.(StarWarsChar); ok { return droid.Name } @@ -235,7 +235,7 @@ func init() { "friends": &graphql.Field{ Type: graphql.NewList(characterInterface), Description: "The friends of the droid, or an empty list if they have none.", - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if droid, ok := p.Source.(StarWarsChar); ok { friends := []map[string]interface{}{} for _, friend := range droid.Friends { @@ -252,7 +252,7 @@ func init() { "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if droid, ok := p.Source.(StarWarsChar); ok { return droid.AppearsIn } @@ -262,7 +262,7 @@ func init() { "primaryFunction": &graphql.Field{ Type: graphql.String, Description: "The primary function of the droid.", - Resolve: func(p graphql.GQLFRParams) interface{} { + Resolve: func(p graphql.ResolveParams) interface{} { if droid, ok := p.Source.(StarWarsChar); ok { return droid.PrimaryFunction } @@ -287,7 +287,7 @@ func init() { Type: episodeEnum, }, }, - Resolve: func(p graphql.GQLFRParams) (r interface{}) { + Resolve: func(p graphql.ResolveParams) (r interface{}) { return GetHero(p.Args["episode"]) }, }, @@ -299,7 +299,7 @@ func init() { Type: graphql.NewNonNull(graphql.String), }, }, - Resolve: func(p graphql.GQLFRParams) (r interface{}) { + Resolve: func(p graphql.ResolveParams) (r interface{}) { return GetHuman(p.Args["id"].(int)) }, }, @@ -311,7 +311,7 @@ func init() { Type: graphql.NewNonNull(graphql.String), }, }, - Resolve: func(p graphql.GQLFRParams) (r interface{}) { + Resolve: func(p graphql.ResolveParams) (r interface{}) { return GetDroid(p.Args["id"].(int)) }, }, diff --git a/variables_test.go b/variables_test.go index 2d3318e6..cc9126b0 100644 --- a/variables_test.go +++ b/variables_test.go @@ -53,7 +53,7 @@ var testInputObject *graphql.InputObject = graphql.NewInputObject(graphql.InputO }, }) -func inputResolved(p graphql.GQLFRParams) interface{} { +func inputResolved(p graphql.ResolveParams) interface{} { input, ok := p.Args["input"] if !ok { return nil From 8cfc77aae9a8cad6768f144805e5e43ba6a248da Mon Sep 17 00:00:00 2001 From: Fugiman Date: Sat, 7 Nov 2015 04:39:40 -0800 Subject: [PATCH 06/41] gqlerrors.GQLFormattedErrorSlice -> gqlerrors.FormattedErrors --- gqlerrors/sortutil.go | 8 ++++---- nonnull_test.go | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/gqlerrors/sortutil.go b/gqlerrors/sortutil.go index 342a93da..300a9407 100644 --- a/gqlerrors/sortutil.go +++ b/gqlerrors/sortutil.go @@ -2,17 +2,17 @@ package gqlerrors import "bytes" -type GQLFormattedErrorSlice []FormattedError +type FormattedErrors []FormattedError -func (errs GQLFormattedErrorSlice) Len() int { +func (errs FormattedErrors) Len() int { return len(errs) } -func (errs GQLFormattedErrorSlice) Swap(i, j int) { +func (errs FormattedErrors) Swap(i, j int) { errs[i], errs[j] = errs[j], errs[i] } -func (errs GQLFormattedErrorSlice) Less(i, j int) bool { +func (errs FormattedErrors) Less(i, j int) bool { mCompare := bytes.Compare([]byte(errs[i].Message), []byte(errs[j].Message)) lesserLine := errs[i].Locations[0].Line < errs[j].Locations[0].Line eqLine := errs[i].Locations[0].Line == errs[j].Locations[0].Line diff --git a/nonnull_test.go b/nonnull_test.go index 4ee4d2b6..b52c6829 100644 --- a/nonnull_test.go +++ b/nonnull_test.go @@ -494,8 +494,8 @@ func TestNonNull_NullsAComplexTreeOfNullableFieldsThatThrow(t *testing.T) { if !reflect.DeepEqual(expected.Data, result.Data) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected.Data, result.Data)) } - sort.Sort(gqlerrors.GQLFormattedErrorSlice(expected.Errors)) - sort.Sort(gqlerrors.GQLFormattedErrorSlice(result.Errors)) + sort.Sort(gqlerrors.FormattedErrors(expected.Errors)) + sort.Sort(gqlerrors.FormattedErrors(result.Errors)) if !reflect.DeepEqual(expected.Errors, result.Errors) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected.Errors, result.Errors)) } @@ -599,8 +599,8 @@ func TestNonNull_NullsTheFirstNullableObjectAfterAFieldThrowsInALongChainOfField if !reflect.DeepEqual(expected.Data, result.Data) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected.Data, result.Data)) } - sort.Sort(gqlerrors.GQLFormattedErrorSlice(expected.Errors)) - sort.Sort(gqlerrors.GQLFormattedErrorSlice(result.Errors)) + sort.Sort(gqlerrors.FormattedErrors(expected.Errors)) + sort.Sort(gqlerrors.FormattedErrors(result.Errors)) if !reflect.DeepEqual(expected.Errors, result.Errors) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected.Errors, result.Errors)) } @@ -997,8 +997,8 @@ func TestNonNull_NullsTheFirstNullableObjectAfterAFieldReturnsNullInALongChainOf if !reflect.DeepEqual(expected.Data, result.Data) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected.Data, result.Data)) } - sort.Sort(gqlerrors.GQLFormattedErrorSlice(expected.Errors)) - sort.Sort(gqlerrors.GQLFormattedErrorSlice(result.Errors)) + sort.Sort(gqlerrors.FormattedErrors(expected.Errors)) + sort.Sort(gqlerrors.FormattedErrors(result.Errors)) if !reflect.DeepEqual(expected.Errors, result.Errors) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected.Errors, result.Errors)) } From 1ef7c2635cc4ec04ba6f50da8594a3e0732392e5 Mon Sep 17 00:00:00 2001 From: Fugiman Date: Sat, 7 Nov 2015 16:01:14 -0800 Subject: [PATCH 07/41] Remove Get prefix from Type methods --- definition.go | 238 ++++++++++++++++++++++----------------------- definition_test.go | 60 ++++++------ directives.go | 8 +- executor.go | 14 +-- introspection.go | 32 +++--- schema.go | 52 +++++----- validation_test.go | 16 +-- values.go | 10 +- 8 files changed, 215 insertions(+), 215 deletions(-) diff --git a/definition.go b/definition.go index da7bf645..016c5a2b 100644 --- a/definition.go +++ b/definition.go @@ -11,10 +11,10 @@ import ( // These are all of the possible kinds of type Type interface { - GetName() string - GetDescription() string + Name() string + Description() string String() string - GetError() error + Error() error } var _ Type = (*Scalar)(nil) @@ -29,10 +29,10 @@ var _ Type = (*Argument)(nil) // These types may be used as input types for arguments and directives. type Input interface { - GetName() string - GetDescription() string + Name() string + Description() string String() string - GetError() error + Error() error } var _ Input = (*Scalar)(nil) @@ -77,10 +77,10 @@ func IsOutputType(ttype Type) bool { // These types may be used as output types as the result of fields. type Output interface { - GetName() string - GetDescription() string + Name() string + Description() string String() string - GetError() error + Error() error } var _ Output = (*Scalar)(nil) @@ -93,7 +93,7 @@ var _ Output = (*NonNull)(nil) // These types may describe the parent context of a selection set. type Composite interface { - GetName() string + Name() string } var _ Composite = (*Object)(nil) @@ -102,8 +102,8 @@ var _ Composite = (*Union)(nil) // These types may describe the parent context of a selection set. type Abstract interface { - GetObjectType(value interface{}, info ResolveInfo) *Object - GetPossibleTypes() []*Object + ObjectType(value interface{}, info ResolveInfo) *Object + PossibleTypes() []*Object IsPossibleType(ttype *Object) bool } @@ -156,8 +156,8 @@ func GetNamed(ttype Type) Named { * */ type Scalar struct { - Name string `json:"name"` - Description string `json:"description"` + name string `json:"name"` + description string `json:"description"` scalarConfig ScalarConfig err error @@ -187,8 +187,8 @@ func NewScalar(config ScalarConfig) *Scalar { return st } - st.Name = config.Name - st.Description = config.Description + st.name = config.Name + st.description = config.Description err = invariant( config.Serialize != nil, @@ -232,17 +232,17 @@ func (st *Scalar) ParseLiteral(valueAST ast.Value) interface{} { } return st.scalarConfig.ParseLiteral(valueAST) } -func (st *Scalar) GetName() string { - return st.Name +func (st *Scalar) Name() string { + return st.name } -func (st *Scalar) GetDescription() string { - return st.Description +func (st *Scalar) Description() string { + return st.description } func (st *Scalar) String() string { - return st.Name + return st.name } -func (st *Scalar) GetError() error { +func (st *Scalar) Error() error { return st.err } @@ -284,8 +284,8 @@ func (st *Scalar) GetError() error { * */ type Object struct { - Name string `json:"name"` - Description string `json:"description"` + name string `json:"name"` + description string `json:"description"` IsTypeOf IsTypeOfFn typeConfig ObjectConfig @@ -321,8 +321,8 @@ func NewObject(config ObjectConfig) *Object { return objectType } - objectType.Name = config.Name - objectType.Description = config.Description + objectType.name = config.Name + objectType.description = config.Description objectType.IsTypeOf = config.IsTypeOf objectType.typeConfig = config @@ -333,7 +333,7 @@ func NewObject(config ObjectConfig) *Object { implementations, but avoids an expensive "getPossibleTypes" implementation for Interface */ - interfaces := objectType.GetInterfaces() + interfaces := objectType.Interfaces() if interfaces == nil { return objectType } @@ -350,22 +350,22 @@ func (gt *Object) AddFieldConfig(fieldName string, fieldConfig *Field) { gt.typeConfig.Fields[fieldName] = fieldConfig } -func (gt *Object) GetName() string { - return gt.Name +func (gt *Object) Name() string { + return gt.name } -func (gt *Object) GetDescription() string { +func (gt *Object) Description() string { return "" } func (gt *Object) String() string { - return gt.Name + return gt.name } -func (gt *Object) GetFields() FieldDefinitionMap { +func (gt *Object) Fields() FieldDefinitionMap { fields, err := defineFieldMap(gt, gt.typeConfig.Fields) gt.err = err gt.fields = fields return gt.fields } -func (gt *Object) GetInterfaces() []*Interface { +func (gt *Object) Interfaces() []*Interface { var configInterfaces []*Interface switch gt.typeConfig.Interfaces.(type) { case InterfacesThunk: @@ -382,7 +382,7 @@ func (gt *Object) GetInterfaces() []*Interface { gt.interfaces = interfaces return gt.interfaces } -func (gt *Object) GetError() error { +func (gt *Object) Error() error { return gt.err } @@ -441,8 +441,8 @@ func defineFieldMap(ttype Named, fields Fields) (FieldDefinitionMap, error) { if err != nil { return resultFieldMap, err } - if field.Type.GetError() != nil { - return resultFieldMap, field.Type.GetError() + if field.Type.Error() != nil { + return resultFieldMap, field.Type.Error() } err = assertValidName(fieldName) if err != nil { @@ -477,8 +477,8 @@ func defineFieldMap(ttype Named, fields Fields) (FieldDefinitionMap, error) { return resultFieldMap, err } fieldArg := &Argument{ - Name: argName, - Description: arg.Description, + name: argName, + description: arg.Description, Type: arg.Type, DefaultValue: arg.DefaultValue, } @@ -549,23 +549,23 @@ type FieldArgument struct { } type Argument struct { - Name string `json:"name"` + name string `json:"name"` Type Input `json:"type"` DefaultValue interface{} `json:"defaultValue"` - Description string `json:"description"` + description string `json:"description"` } -func (st *Argument) GetName() string { - return st.Name +func (st *Argument) Name() string { + return st.name } -func (st *Argument) GetDescription() string { - return st.Description +func (st *Argument) Description() string { + return st.description } func (st *Argument) String() string { - return st.Name + return st.name } -func (st *Argument) GetError() error { +func (st *Argument) Error() error { return nil } @@ -588,8 +588,8 @@ func (st *Argument) GetError() error { * */ type Interface struct { - Name string `json:"name"` - Description string `json:"description"` + name string `json:"name"` + description string `json:"description"` ResolveType ResolveTypeFn typeConfig InterfaceConfig @@ -620,8 +620,8 @@ func NewInterface(config InterfaceConfig) *Interface { it.err = err return it } - it.Name = config.Name - it.Description = config.Description + it.name = config.Name + it.description = config.Description it.ResolveType = config.ResolveType it.typeConfig = config it.implementations = []*Object{} @@ -635,17 +635,17 @@ func (it *Interface) AddFieldConfig(fieldName string, fieldConfig *Field) { } it.typeConfig.Fields[fieldName] = fieldConfig } -func (it *Interface) GetName() string { - return it.Name +func (it *Interface) Name() string { + return it.name } -func (it *Interface) GetDescription() string { - return it.Description +func (it *Interface) Description() string { + return it.description } -func (it *Interface) GetFields() (fields FieldDefinitionMap) { +func (it *Interface) Fields() (fields FieldDefinitionMap) { it.fields, it.err = defineFieldMap(it, it.typeConfig.Fields) return it.fields } -func (it *Interface) GetPossibleTypes() []*Object { +func (it *Interface) PossibleTypes() []*Object { return it.implementations } func (it *Interface) IsPossibleType(ttype *Object) bool { @@ -654,34 +654,34 @@ func (it *Interface) IsPossibleType(ttype *Object) bool { } if len(it.possibleTypes) == 0 { possibleTypes := map[string]bool{} - for _, possibleType := range it.GetPossibleTypes() { + for _, possibleType := range it.PossibleTypes() { if possibleType == nil { continue } - possibleTypes[possibleType.Name] = true + possibleTypes[possibleType.name] = true } it.possibleTypes = possibleTypes } - if val, ok := it.possibleTypes[ttype.Name]; ok { + if val, ok := it.possibleTypes[ttype.name]; ok { return val } return false } -func (it *Interface) GetObjectType(value interface{}, info ResolveInfo) *Object { +func (it *Interface) ObjectType(value interface{}, info ResolveInfo) *Object { if it.ResolveType != nil { return it.ResolveType(value, info) } return getTypeOf(value, info, it) } func (it *Interface) String() string { - return it.Name + return it.name } -func (it *Interface) GetError() error { +func (it *Interface) Error() error { return it.err } func getTypeOf(value interface{}, info ResolveInfo, abstractType Abstract) *Object { - possibleTypes := abstractType.GetPossibleTypes() + possibleTypes := abstractType.PossibleTypes() for _, possibleType := range possibleTypes { if possibleType.IsTypeOf == nil { continue @@ -717,8 +717,8 @@ func getTypeOf(value interface{}, info ResolveInfo, abstractType Abstract) *Obje * */ type Union struct { - Name string `json:"name"` - Description string `json:"description"` + name string `json:"name"` + description string `json:"description"` ResolveType ResolveTypeFn typeConfig UnionConfig @@ -747,8 +747,8 @@ func NewUnion(config UnionConfig) *Union { objectType.err = err return objectType } - objectType.Name = config.Name - objectType.Description = config.Description + objectType.name = config.Name + objectType.description = config.Description objectType.ResolveType = config.ResolveType err = invariant( @@ -787,7 +787,7 @@ func NewUnion(config UnionConfig) *Union { return objectType } -func (ut *Union) GetPossibleTypes() []*Object { +func (ut *Union) PossibleTypes() []*Object { return ut.types } func (ut *Union) IsPossibleType(ttype *Object) bool { @@ -797,36 +797,36 @@ func (ut *Union) IsPossibleType(ttype *Object) bool { } if len(ut.possibleTypes) == 0 { possibleTypes := map[string]bool{} - for _, possibleType := range ut.GetPossibleTypes() { + for _, possibleType := range ut.PossibleTypes() { if possibleType == nil { continue } - possibleTypes[possibleType.Name] = true + possibleTypes[possibleType.name] = true } ut.possibleTypes = possibleTypes } - if val, ok := ut.possibleTypes[ttype.Name]; ok { + if val, ok := ut.possibleTypes[ttype.name]; ok { return val } return false } -func (ut *Union) GetObjectType(value interface{}, info ResolveInfo) *Object { +func (ut *Union) ObjectType(value interface{}, info ResolveInfo) *Object { if ut.ResolveType != nil { return ut.ResolveType(value, info) } return getTypeOf(value, info, ut) } func (ut *Union) String() string { - return ut.Name + return ut.name } -func (ut *Union) GetName() string { - return ut.Name +func (ut *Union) Name() string { + return ut.name } -func (ut *Union) GetDescription() string { - return ut.Description +func (ut *Union) Description() string { + return ut.description } -func (ut *Union) GetError() error { +func (ut *Union) Error() error { return ut.err } @@ -852,8 +852,8 @@ func (ut *Union) GetError() error { * will be used as it's internal value. */ type Enum struct { - Name string `json:"name"` - Description string `json:"description"` + name string `json:"name"` + description string `json:"description"` enumConfig EnumConfig values []*EnumValueDefinition @@ -890,8 +890,8 @@ func NewEnum(config EnumConfig) *Enum { return gt } - gt.Name = config.Name - gt.Description = config.Description + gt.name = config.Name + gt.description = config.Description gt.values, err = gt.defineEnumValues(config.Values) if err != nil { gt.err = err @@ -937,7 +937,7 @@ func (gt *Enum) defineEnumValues(valueMap EnumValueConfigMap) ([]*EnumValueDefin } return values, nil } -func (gt *Enum) GetValues() []*EnumValueDefinition { +func (gt *Enum) Values() []*EnumValueDefinition { return gt.values } func (gt *Enum) Serialize(value interface{}) interface{} { @@ -964,16 +964,16 @@ func (gt *Enum) ParseLiteral(valueAST ast.Value) interface{} { } return nil } -func (gt *Enum) GetName() string { - return gt.Name +func (gt *Enum) Name() string { + return gt.name } -func (gt *Enum) GetDescription() string { +func (gt *Enum) Description() string { return "" } func (gt *Enum) String() string { - return gt.Name + return gt.name } -func (gt *Enum) GetError() error { +func (gt *Enum) Error() error { return gt.err } func (gt *Enum) getValueLookup() map[interface{}]*EnumValueDefinition { @@ -981,7 +981,7 @@ func (gt *Enum) getValueLookup() map[interface{}]*EnumValueDefinition { return gt.valuesLookup } valuesLookup := map[interface{}]*EnumValueDefinition{} - for _, value := range gt.GetValues() { + for _, value := range gt.Values() { valuesLookup[value.Value] = value } gt.valuesLookup = valuesLookup @@ -993,7 +993,7 @@ func (gt *Enum) getNameLookup() map[string]*EnumValueDefinition { return gt.nameLookup } nameLookup := map[string]*EnumValueDefinition{} - for _, value := range gt.GetValues() { + for _, value := range gt.Values() { nameLookup[value.Name] = value } gt.nameLookup = nameLookup @@ -1021,8 +1021,8 @@ func (gt *Enum) getNameLookup() map[string]*EnumValueDefinition { * */ type InputObject struct { - Name string `json:"name"` - Description string `json:"description"` + name string `json:"name"` + description string `json:"description"` typeConfig InputObjectConfig fields InputObjectFieldMap @@ -1035,23 +1035,23 @@ type InputObjectFieldConfig struct { Description string `json:"description"` } type InputObjectField struct { - Name string `json:"name"` + name string `json:"name"` Type Input `json:"type"` DefaultValue interface{} `json:"defaultValue"` - Description string `json:"description"` + description string `json:"description"` } -func (st *InputObjectField) GetName() string { - return st.Name +func (st *InputObjectField) Name() string { + return st.name } -func (st *InputObjectField) GetDescription() string { - return st.Description +func (st *InputObjectField) Description() string { + return st.description } func (st *InputObjectField) String() string { - return st.Name + return st.name } -func (st *InputObjectField) GetError() error { +func (st *InputObjectField) Error() error { return nil } @@ -1073,8 +1073,8 @@ func NewInputObject(config InputObjectConfig) *InputObject { return gt } - gt.Name = config.Name - gt.Description = config.Description + gt.name = config.Name + gt.description = config.Description gt.typeConfig = config gt.fields = gt.defineFieldMap() return gt @@ -1116,27 +1116,27 @@ func (gt *InputObject) defineFieldMap() InputObjectFieldMap { return resultFieldMap } field := &InputObjectField{} - field.Name = fieldName + field.name = fieldName field.Type = fieldConfig.Type - field.Description = fieldConfig.Description + field.description = fieldConfig.Description field.DefaultValue = fieldConfig.DefaultValue resultFieldMap[fieldName] = field } return resultFieldMap } -func (gt *InputObject) GetFields() InputObjectFieldMap { +func (gt *InputObject) Fields() InputObjectFieldMap { return gt.fields } -func (gt *InputObject) GetName() string { - return gt.Name +func (gt *InputObject) Name() string { + return gt.name } -func (gt *InputObject) GetDescription() string { - return gt.Description +func (gt *InputObject) Description() string { + return gt.description } func (gt *InputObject) String() string { - return gt.Name + return gt.name } -func (gt *InputObject) GetError() error { +func (gt *InputObject) Error() error { return gt.err } @@ -1176,10 +1176,10 @@ func NewList(ofType Type) *List { gl.OfType = ofType return gl } -func (gl *List) GetName() string { +func (gl *List) Name() string { return fmt.Sprintf("%v", gl.OfType) } -func (gl *List) GetDescription() string { +func (gl *List) Description() string { return "" } func (gl *List) String() string { @@ -1188,7 +1188,7 @@ func (gl *List) String() string { } return "" } -func (gl *List) GetError() error { +func (gl *List) Error() error { return gl.err } @@ -1213,7 +1213,7 @@ func (gl *List) GetError() error { * Note: the enforcement of non-nullability occurs within the executor. */ type NonNull struct { - Name string `json:"name"` // added to conform with introspection for NonNull.Name = nil + name string `json:"name"` // added to conform with introspection for NonNull.Name = nil OfType Type `json:"ofType"` err error @@ -1231,19 +1231,19 @@ func NewNonNull(ofType Type) *NonNull { gl.OfType = ofType return gl } -func (gl *NonNull) GetName() string { +func (gl *NonNull) Name() string { return fmt.Sprintf("%v!", gl.OfType) } -func (gl *NonNull) GetDescription() string { +func (gl *NonNull) Description() string { return "" } func (gl *NonNull) String() string { if gl.OfType != nil { - return gl.GetName() + return gl.Name() } return "" } -func (gl *NonNull) GetError() error { +func (gl *NonNull) Error() error { return gl.err } diff --git a/definition_test.go b/definition_test.go index c7cc4594..97a361fa 100644 --- a/definition_test.go +++ b/definition_test.go @@ -131,11 +131,11 @@ func TestTypeSystem_DefinitionExample_DefinesAQueryOnlySchema(t *testing.T) { t.Fatalf("unexpected error, got: %v", err) } - if blogSchema.GetQueryType() != blogQuery { + if blogSchema.QueryType() != blogQuery { t.Fatalf("expected blogSchema.GetQueryType() == blogQuery") } - articleField, _ := blogQuery.GetFields()["article"] + articleField, _ := blogQuery.Fields()["article"] if articleField == nil { t.Fatalf("articleField is nil") } @@ -143,8 +143,8 @@ func TestTypeSystem_DefinitionExample_DefinesAQueryOnlySchema(t *testing.T) { if articleFieldType != blogArticle { t.Fatalf("articleFieldType expected to equal blogArticle, got: %v", articleField.Type) } - if articleFieldType.GetName() != "Article" { - t.Fatalf("articleFieldType.Name expected to equal `Article`, got: %v", articleField.Type.GetName()) + if articleFieldType.Name() != "Article" { + t.Fatalf("articleFieldType.Name expected to equal `Article`, got: %v", articleField.Type.Name()) } if articleField.Name != "article" { t.Fatalf("articleField.Name expected to equal `article`, got: %v", articleField.Name) @@ -155,7 +155,7 @@ func TestTypeSystem_DefinitionExample_DefinesAQueryOnlySchema(t *testing.T) { } // TODO: expose a Object.GetField(key string), instead of this ghetto way of accessing a field map? - titleField := articleFieldTypeObject.GetFields()["title"] + titleField := articleFieldTypeObject.Fields()["title"] if titleField == nil { t.Fatalf("titleField is nil") } @@ -165,11 +165,11 @@ func TestTypeSystem_DefinitionExample_DefinesAQueryOnlySchema(t *testing.T) { if titleField.Type != graphql.String { t.Fatalf("titleField.Type expected to equal graphql.String, got: %v", titleField.Type) } - if titleField.Type.GetName() != "String" { - t.Fatalf("titleField.Type.GetName() expected to equal `String`, got: %v", titleField.Type.GetName()) + if titleField.Type.Name() != "String" { + t.Fatalf("titleField.Type.GetName() expected to equal `String`, got: %v", titleField.Type.Name()) } - authorField := articleFieldTypeObject.GetFields()["author"] + authorField := articleFieldTypeObject.Fields()["author"] if authorField == nil { t.Fatalf("authorField is nil") } @@ -178,7 +178,7 @@ func TestTypeSystem_DefinitionExample_DefinesAQueryOnlySchema(t *testing.T) { t.Fatalf("expected authorField.Type to be Object`, got: %v", authorField) } - recentArticleField := authorFieldObject.GetFields()["recentArticle"] + recentArticleField := authorFieldObject.Fields()["recentArticle"] if recentArticleField == nil { t.Fatalf("recentArticleField is nil") } @@ -186,7 +186,7 @@ func TestTypeSystem_DefinitionExample_DefinesAQueryOnlySchema(t *testing.T) { t.Fatalf("recentArticleField.Type expected to equal blogArticle, got: %v", recentArticleField.Type) } - feedField := blogQuery.GetFields()["feed"] + feedField := blogQuery.Fields()["feed"] feedFieldList, ok := feedField.Type.(*graphql.List) if !ok { t.Fatalf("expected feedFieldList to be List`, got: %v", authorField) @@ -207,11 +207,11 @@ func TestTypeSystem_DefinitionExample_DefinesAMutationScheme(t *testing.T) { t.Fatalf("unexpected error, got: %v", err) } - if blogSchema.GetMutationType() != blogMutation { + if blogSchema.MutationType() != blogMutation { t.Fatalf("expected blogSchema.GetMutationType() == blogMutation") } - writeMutation, _ := blogMutation.GetFields()["writeArticle"] + writeMutation, _ := blogMutation.Fields()["writeArticle"] if writeMutation == nil { t.Fatalf("writeMutation is nil") } @@ -219,8 +219,8 @@ func TestTypeSystem_DefinitionExample_DefinesAMutationScheme(t *testing.T) { if writeMutationType != blogArticle { t.Fatalf("writeMutationType expected to equal blogArticle, got: %v", writeMutationType) } - if writeMutationType.GetName() != "Article" { - t.Fatalf("writeMutationType.Name expected to equal `Article`, got: %v", writeMutationType.GetName()) + if writeMutationType.Name() != "Article" { + t.Fatalf("writeMutationType.Name expected to equal `Article`, got: %v", writeMutationType.Name()) } if writeMutation.Name != "writeArticle" { t.Fatalf("writeMutation.Name expected to equal `writeArticle`, got: %v", writeMutation.Name) @@ -264,8 +264,8 @@ func TestTypeSystem_DefinitionExample_IncludesNestedInputObjectsInTheMap(t *test if err != nil { t.Fatalf("unexpected error, got: %v", err) } - if schema.GetType("NestedInputObject") != nestedInputObject { - t.Fatalf(`schema.GetType("NestedInputObject") expected to equal nestedInputObject, got: %v`, schema.GetType("NestedInputObject")) + if schema.Type("NestedInputObject") != nestedInputObject { + t.Fatalf(`schema.GetType("NestedInputObject") expected to equal nestedInputObject, got: %v`, schema.Type("NestedInputObject")) } } @@ -305,8 +305,8 @@ func TestTypeSystem_DefinitionExample_IncludesInterfacesSubTypesInTheTypeMap(t * if err != nil { t.Fatalf("unexpected error, got: %v", err) } - if schema.GetType("SomeSubtype") != someSubType { - t.Fatalf(`schema.GetType("SomeSubtype") expected to equal someSubType, got: %v`, schema.GetType("SomeSubtype")) + if schema.Type("SomeSubtype") != someSubType { + t.Fatalf(`schema.GetType("SomeSubtype") expected to equal someSubType, got: %v`, schema.Type("SomeSubtype")) } } @@ -348,8 +348,8 @@ func TestTypeSystem_DefinitionExample_IncludesInterfacesThunkSubtypesInTheTypeMa if err != nil { t.Fatalf("unexpected error, got: %v", err) } - if schema.GetType("SomeSubtype") != someSubType { - t.Fatalf(`schema.GetType("SomeSubtype") expected to equal someSubType, got: %v`, schema.GetType("SomeSubtype")) + if schema.Type("SomeSubtype") != someSubType { + t.Fatalf(`schema.GetType("SomeSubtype") expected to equal someSubType, got: %v`, schema.Type("SomeSubtype")) } } @@ -437,15 +437,15 @@ func TestTypeSystem_DefinitionExample_IdentifiesOutputTypes(t *testing.T) { func TestTypeSystem_DefinitionExample_ProhibitsNestingNonNullInsideNonNull(t *testing.T) { ttype := graphql.NewNonNull(graphql.NewNonNull(graphql.Int)) expected := `Can only create NonNull of a Nullable Type but got: Int!.` - if ttype.GetError().Error() != expected { - t.Fatalf(`expected %v , got: %v`, expected, ttype.GetError()) + if ttype.Error().Error() != expected { + t.Fatalf(`expected %v , got: %v`, expected, ttype.Error()) } } func TestTypeSystem_DefinitionExample_ProhibitsNilInNonNull(t *testing.T) { ttype := graphql.NewNonNull(nil) expected := `Can only create NonNull of a Nullable Type but got: .` - if ttype.GetError().Error() != expected { - t.Fatalf(`expected %v , got: %v`, expected, ttype.GetError()) + if ttype.Error().Error() != expected { + t.Fatalf(`expected %v , got: %v`, expected, ttype.Error()) } } func TestTypeSystem_DefinitionExample_ProhibitsNilTypeInUnions(t *testing.T) { @@ -454,8 +454,8 @@ func TestTypeSystem_DefinitionExample_ProhibitsNilTypeInUnions(t *testing.T) { Types: []*graphql.Object{nil}, }) expected := `BadUnion may only contain Object types, it cannot contain: .` - if ttype.GetError().Error() != expected { - t.Fatalf(`expected %v , got: %v`, expected, ttype.GetError()) + if ttype.Error().Error() != expected { + t.Fatalf(`expected %v , got: %v`, expected, ttype.Error()) } } func TestTypeSystem_DefinitionExample_DoesNotMutatePassedFieldDefinitions(t *testing.T) { @@ -480,8 +480,8 @@ func TestTypeSystem_DefinitionExample_DoesNotMutatePassedFieldDefinitions(t *tes Name: "Test2", Fields: fields, }) - if !reflect.DeepEqual(testObject1.GetFields(), testObject2.GetFields()) { - t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(testObject1.GetFields(), testObject2.GetFields())) + if !reflect.DeepEqual(testObject1.Fields(), testObject2.Fields()) { + t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(testObject1.Fields(), testObject2.Fields())) } expectedFields := graphql.Fields{ @@ -525,8 +525,8 @@ func TestTypeSystem_DefinitionExample_DoesNotMutatePassedFieldDefinitions(t *tes Name: "Test2", Fields: inputFields, }) - if !reflect.DeepEqual(testInputObject1.GetFields(), testInputObject2.GetFields()) { - t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(testInputObject1.GetFields(), testInputObject2.GetFields())) + if !reflect.DeepEqual(testInputObject1.Fields(), testInputObject2.Fields()) { + t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(testInputObject1.Fields(), testInputObject2.Fields())) } if !reflect.DeepEqual(inputFields, expectedInputFields) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expectedInputFields, fields)) diff --git a/directives.go b/directives.go index fbbcc18e..22c2fbea 100644 --- a/directives.go +++ b/directives.go @@ -36,9 +36,9 @@ var IncludeDirective *Directive = NewDirective(&Directive{ "the `if` argument is true.", Args: []*Argument{ &Argument{ - Name: "if", + name: "if", Type: NewNonNull(Boolean), - Description: "Included when true.", + description: "Included when true.", }, }, OnOperation: false, @@ -55,9 +55,9 @@ var SkipDirective *Directive = NewDirective(&Directive{ "argument is true.", Args: []*Argument{ &Argument{ - Name: "if", + name: "if", Type: NewNonNull(Boolean), - Description: "Skipped when true.", + description: "Skipped when true.", }, }, OnOperation: false, diff --git a/executor.go b/executor.go index e9b024b1..0e13f010 100644 --- a/executor.go +++ b/executor.go @@ -167,10 +167,10 @@ func getOperationRootType(schema Schema, operation ast.Definition) (*Object, err switch operation.GetOperation() { case "query": - return schema.GetQueryType(), nil + return schema.QueryType(), nil case "mutation": - mutationType := schema.GetMutationType() - if mutationType.Name == "" { + mutationType := schema.MutationType() + if mutationType.name == "" { return nil, errors.New("Schema is not configured for mutations") } return mutationType, nil @@ -622,7 +622,7 @@ func completeValue(eCtx *ExecutionContext, returnType Type, fieldASTs []*ast.Fie case *Object: objectType = returnType case Abstract: - objectType = returnType.GetObjectType(result, info) + objectType = returnType.ObjectType(result, info) if objectType != nil && !returnType.IsPossibleType(objectType) { panic(gqlerrors.NewFormattedError( fmt.Sprintf(`Runtime Object type "%v" is not a possible type `+ @@ -743,15 +743,15 @@ func getFieldDef(schema Schema, parentType *Object, fieldName string) *FieldDefi } if fieldName == SchemaMetaFieldDef.Name && - schema.GetQueryType() == parentType { + schema.QueryType() == parentType { return SchemaMetaFieldDef } if fieldName == TypeMetaFieldDef.Name && - schema.GetQueryType() == parentType { + schema.QueryType() == parentType { return TypeMetaFieldDef } if fieldName == TypeNameMetaFieldDef.Name { return TypeNameMetaFieldDef } - return parentType.GetFields()[fieldName] + return parentType.Fields()[fieldName] } diff --git a/introspection.go b/introspection.go index d6613775..e832d949 100644 --- a/introspection.go +++ b/introspection.go @@ -235,7 +235,7 @@ mutation operations.`, Resolve: func(p ResolveParams) interface{} { if schema, ok := p.Source.(Schema); ok { results := []Type{} - for _, ttype := range schema.GetTypeMap() { + for _, ttype := range schema.TypeMap() { results = append(results, ttype) } return results @@ -248,7 +248,7 @@ mutation operations.`, Type: NewNonNull(__Type), Resolve: func(p ResolveParams) interface{} { if schema, ok := p.Source.(Schema); ok { - return schema.GetQueryType() + return schema.QueryType() } return nil }, @@ -259,8 +259,8 @@ mutation operations.`, Type: __Type, Resolve: func(p ResolveParams) interface{} { if schema, ok := p.Source.(Schema); ok { - if schema.GetMutationType() != nil { - return schema.GetMutationType() + if schema.MutationType() != nil { + return schema.MutationType() } } return nil @@ -273,7 +273,7 @@ mutation operations.`, )), Resolve: func(p ResolveParams) interface{} { if schema, ok := p.Source.(Schema); ok { - return schema.GetDirectives() + return schema.Directives() } return nil }, @@ -323,7 +323,7 @@ mutation operations.`, return nil } fields := []*FieldDefinition{} - for _, field := range ttype.GetFields() { + for _, field := range ttype.Fields() { if !includeDeprecated && field.DeprecationReason != "" { continue } @@ -335,7 +335,7 @@ mutation operations.`, return nil } fields := []*FieldDefinition{} - for _, field := range ttype.GetFields() { + for _, field := range ttype.Fields() { if !includeDeprecated && field.DeprecationReason != "" { continue } @@ -351,7 +351,7 @@ mutation operations.`, Resolve: func(p ResolveParams) interface{} { switch ttype := p.Source.(type) { case *Object: - return ttype.GetInterfaces() + return ttype.Interfaces() } return nil }, @@ -361,9 +361,9 @@ mutation operations.`, Resolve: func(p ResolveParams) interface{} { switch ttype := p.Source.(type) { case *Interface: - return ttype.GetPossibleTypes() + return ttype.PossibleTypes() case *Union: - return ttype.GetPossibleTypes() + return ttype.PossibleTypes() } return nil }, @@ -381,10 +381,10 @@ mutation operations.`, switch ttype := p.Source.(type) { case *Enum: if includeDeprecated { - return ttype.GetValues() + return ttype.Values() } values := []*EnumValueDefinition{} - for _, value := range ttype.GetValues() { + for _, value := range ttype.Values() { if value.DeprecationReason != "" { continue } @@ -401,7 +401,7 @@ mutation operations.`, switch ttype := p.Source.(type) { case *InputObject: fields := []*InputObjectField{} - for _, field := range ttype.GetFields() { + for _, field := range ttype.Fields() { fields = append(fields, field) } return fields @@ -433,7 +433,7 @@ mutation operations.`, Description: "Request the type information of a single type.", Args: []*Argument{ &Argument{ - Name: "name", + name: "name", Type: NewNonNull(String), }, }, @@ -442,7 +442,7 @@ mutation operations.`, if !ok { return nil } - return p.Info.Schema.GetType(name) + return p.Info.Schema.Type(name) }, } @@ -452,7 +452,7 @@ mutation operations.`, Description: "The name of the current Object type at runtime.", Args: []*Argument{}, Resolve: func(p ResolveParams) interface{} { - return p.Info.ParentType.GetName() + return p.Info.ParentType.Name() }, } diff --git a/schema.go b/schema.go index dad5ebd6..f9526e5c 100644 --- a/schema.go +++ b/schema.go @@ -52,8 +52,8 @@ func NewSchema(config SchemaConfig) (Schema, error) { // Build type map now to detect any errors within this schema. typeMap := TypeMap{} objectTypes := []*Object{ - schema.GetQueryType(), - schema.GetMutationType(), + schema.QueryType(), + schema.MutationType(), __Type, __Schema, } @@ -74,7 +74,7 @@ func NewSchema(config SchemaConfig) (Schema, error) { for _, ttype := range typeMap { switch ttype := ttype.(type) { case *Object: - for _, iface := range ttype.GetInterfaces() { + for _, iface := range ttype.Interfaces() { err := assertObjectImplementsInterface(ttype, iface) if err != nil { return schema, err @@ -86,15 +86,15 @@ func NewSchema(config SchemaConfig) (Schema, error) { return schema, nil } -func (gq *Schema) GetQueryType() *Object { +func (gq *Schema) QueryType() *Object { return gq.schemaConfig.Query } -func (gq *Schema) GetMutationType() *Object { +func (gq *Schema) MutationType() *Object { return gq.schemaConfig.Mutation } -func (gq *Schema) GetDirectives() []*Directive { +func (gq *Schema) Directives() []*Directive { if len(gq.directives) == 0 { gq.directives = []*Directive{ IncludeDirective, @@ -104,17 +104,17 @@ func (gq *Schema) GetDirectives() []*Directive { return gq.directives } -func (gq *Schema) GetTypeMap() TypeMap { +func (gq *Schema) TypeMap() TypeMap { return gq.typeMap } -func (gq *Schema) GetType(name string) Type { - return gq.GetTypeMap()[name] +func (gq *Schema) Type(name string) Type { + return gq.TypeMap()[name] } func typeMapReducer(typeMap TypeMap, objectType Type) (TypeMap, error) { var err error - if objectType == nil || objectType.GetName() == "" { + if objectType == nil || objectType.Name() == "" { return typeMap, nil } @@ -133,25 +133,25 @@ func typeMapReducer(typeMap TypeMap, objectType Type) (TypeMap, error) { } } - if mappedObjectType, ok := typeMap[objectType.GetName()]; ok { + if mappedObjectType, ok := typeMap[objectType.Name()]; ok { err := invariant( mappedObjectType == objectType, - fmt.Sprintf(`Schema must contain unique named types but contains multiple types named "%v".`, objectType.GetName()), + fmt.Sprintf(`Schema must contain unique named types but contains multiple types named "%v".`, objectType.Name()), ) if err != nil { return typeMap, err } return typeMap, err } - if objectType.GetName() == "" { + if objectType.Name() == "" { return typeMap, nil } - typeMap[objectType.GetName()] = objectType + typeMap[objectType.Name()] = objectType switch objectType := objectType.(type) { case *Union: - types := objectType.GetPossibleTypes() + types := objectType.PossibleTypes() if objectType.err != nil { return typeMap, objectType.err } @@ -165,7 +165,7 @@ func typeMapReducer(typeMap TypeMap, objectType Type) (TypeMap, error) { } } case *Interface: - types := objectType.GetPossibleTypes() + types := objectType.PossibleTypes() if objectType.err != nil { return typeMap, objectType.err } @@ -179,7 +179,7 @@ func typeMapReducer(typeMap TypeMap, objectType Type) (TypeMap, error) { } } case *Object: - interfaces := objectType.GetInterfaces() + interfaces := objectType.Interfaces() if objectType.err != nil { return typeMap, objectType.err } @@ -196,7 +196,7 @@ func typeMapReducer(typeMap TypeMap, objectType Type) (TypeMap, error) { switch objectType := objectType.(type) { case *Object: - fieldMap := objectType.GetFields() + fieldMap := objectType.Fields() if objectType.err != nil { return typeMap, objectType.err } @@ -213,7 +213,7 @@ func typeMapReducer(typeMap TypeMap, objectType Type) (TypeMap, error) { } } case *Interface: - fieldMap := objectType.GetFields() + fieldMap := objectType.Fields() if objectType.err != nil { return typeMap, objectType.err } @@ -230,7 +230,7 @@ func typeMapReducer(typeMap TypeMap, objectType Type) (TypeMap, error) { } } case *InputObject: - fieldMap := objectType.GetFields() + fieldMap := objectType.Fields() if objectType.err != nil { return typeMap, objectType.err } @@ -245,8 +245,8 @@ func typeMapReducer(typeMap TypeMap, objectType Type) (TypeMap, error) { } func assertObjectImplementsInterface(object *Object, iface *Interface) error { - objectFieldMap := object.GetFields() - ifaceFieldMap := iface.GetFields() + objectFieldMap := object.Fields() + ifaceFieldMap := iface.Fields() // Assert each interface field is implemented. for fieldName, _ := range ifaceFieldMap { @@ -277,10 +277,10 @@ func assertObjectImplementsInterface(object *Object, iface *Interface) error { // Assert each interface field arg is implemented. for _, ifaceArg := range ifaceField.Args { - argName := ifaceArg.Name + argName := ifaceArg.name var objectArg *Argument for _, arg := range objectField.Args { - if arg.Name == argName { + if arg.name == argName { objectArg = arg break } @@ -314,10 +314,10 @@ func assertObjectImplementsInterface(object *Object, iface *Interface) error { } // Assert argument set invariance. for _, objectArg := range objectField.Args { - argName := objectArg.Name + argName := objectArg.name var ifaceArg *Argument for _, arg := range ifaceField.Args { - if arg.Name == argName { + if arg.name == argName { ifaceArg = arg break } diff --git a/validation_test.go b/validation_test.go index cfbbf182..42fde9cc 100644 --- a/validation_test.go +++ b/validation_test.go @@ -1060,16 +1060,16 @@ func TestTypeSystem_ListMustAcceptGraphQLTypes_AcceptsAnTypeAsItemTypeOfList(t * }) for _, ttype := range testTypes { result := graphql.NewList(ttype) - if result.GetError() != nil { - t.Fatalf(`unexpected error: %v for type "%v"`, result.GetError(), ttype) + if result.Error() != nil { + t.Fatalf(`unexpected error: %v for type "%v"`, result.Error(), ttype) } } } func TestTypeSystem_ListMustAcceptGraphQLTypes_RejectsANilTypeAsItemTypeOfList(t *testing.T) { result := graphql.NewList(nil) expectedError := `Can only create List of a Type but got: .` - if result.GetError() == nil || result.GetError().Error() != expectedError { - t.Fatalf("Expected error: %v, got %v", expectedError, result.GetError()) + if result.Error() == nil || result.Error().Error() != expectedError { + t.Fatalf("Expected error: %v, got %v", expectedError, result.Error()) } } @@ -1087,16 +1087,16 @@ func TestTypeSystem_NonNullMustAcceptGraphQLTypes_AcceptsAnTypeAsNullableTypeOfN } for _, ttype := range nullableTypes { result := graphql.NewNonNull(ttype) - if result.GetError() != nil { - t.Fatalf(`unexpected error: %v for type "%v"`, result.GetError(), ttype) + if result.Error() != nil { + t.Fatalf(`unexpected error: %v for type "%v"`, result.Error(), ttype) } } } func TestTypeSystem_NonNullMustAcceptGraphQLTypes_RejectsNilAsNonNullableType(t *testing.T) { result := graphql.NewNonNull(nil) expectedError := `Can only create NonNull of a Nullable Type but got: .` - if result.GetError() == nil || result.GetError().Error() != expectedError { - t.Fatalf("Expected error: %v, got %v", expectedError, result.GetError()) + if result.Error() == nil || result.Error().Error() != expectedError { + t.Fatalf("Expected error: %v, got %v", expectedError, result.Error()) } } diff --git a/values.go b/values.go index 880a5129..017b82dc 100644 --- a/values.go +++ b/values.go @@ -44,7 +44,7 @@ func getArgumentValues(argDefs []*Argument, argASTs []*ast.Argument, variableVar results := map[string]interface{}{} for _, argDef := range argDefs { - name := argDef.Name + name := argDef.name var valueAST ast.Value if argAST, ok := argASTMap[name]; ok { valueAST = argAST.Value @@ -147,7 +147,7 @@ func coerceValue(ttype Input, value interface{}) interface{} { } obj := map[string]interface{}{} - for fieldName, field := range ttype.GetFields() { + for fieldName, field := range ttype.Fields() { value, _ := valueMap[fieldName] fieldValue := coerceValue(field.Type, value) if isNullish(fieldValue) { @@ -197,7 +197,7 @@ func typeFromAST(schema Schema, inputTypeAST ast.Type) (Type, error) { if inputTypeAST.Name != nil { nameValue = inputTypeAST.Name.Value } - ttype := schema.GetType(nameValue) + ttype := schema.Type(nameValue) return ttype, nil default: return nil, invariant(inputTypeAST.GetKind() == kinds.Named, "Must be a named type.") @@ -243,7 +243,7 @@ func isValidInputValue(value interface{}, ttype Input) bool { if !ok { return false } - fields := ttype.GetFields() + fields := ttype.Fields() // Ensure every provided field is defined. for fieldName, _ := range valueMap { @@ -362,7 +362,7 @@ func valueFromAST(valueAST ast.Value, ttype Input, variables map[string]interfac } obj := map[string]interface{}{} - for fieldName, field := range ttype.GetFields() { + for fieldName, field := range ttype.Fields() { fieldAST, ok := fieldASTs[fieldName] if !ok || fieldAST == nil { continue From d770f8a912e780b34034423530e6bc663d638272 Mon Sep 17 00:00:00 2001 From: Fugiman Date: Sat, 7 Nov 2015 16:59:40 -0800 Subject: [PATCH 08/41] re-export name & description --- definition.go | 138 +++++++++++++++++++++++------------------------ directives.go | 12 ++--- executor.go | 2 +- introspection.go | 4 +- schema.go | 8 +-- values.go | 2 +- 6 files changed, 83 insertions(+), 83 deletions(-) diff --git a/definition.go b/definition.go index 016c5a2b..2fba7539 100644 --- a/definition.go +++ b/definition.go @@ -156,8 +156,8 @@ func GetNamed(ttype Type) Named { * */ type Scalar struct { - name string `json:"name"` - description string `json:"description"` + PrivateName string `json:"name"` + PrivateDescription string `json:"description"` scalarConfig ScalarConfig err error @@ -187,8 +187,8 @@ func NewScalar(config ScalarConfig) *Scalar { return st } - st.name = config.Name - st.description = config.Description + st.PrivateName = config.Name + st.PrivateDescription = config.Description err = invariant( config.Serialize != nil, @@ -233,14 +233,14 @@ func (st *Scalar) ParseLiteral(valueAST ast.Value) interface{} { return st.scalarConfig.ParseLiteral(valueAST) } func (st *Scalar) Name() string { - return st.name + return st.PrivateName } func (st *Scalar) Description() string { - return st.description + return st.PrivateDescription } func (st *Scalar) String() string { - return st.name + return st.PrivateName } func (st *Scalar) Error() error { return st.err @@ -284,9 +284,9 @@ func (st *Scalar) Error() error { * */ type Object struct { - name string `json:"name"` - description string `json:"description"` - IsTypeOf IsTypeOfFn + PrivateName string `json:"name"` + PrivateDescription string `json:"description"` + IsTypeOf IsTypeOfFn typeConfig ObjectConfig fields FieldDefinitionMap @@ -321,8 +321,8 @@ func NewObject(config ObjectConfig) *Object { return objectType } - objectType.name = config.Name - objectType.description = config.Description + objectType.PrivateName = config.Name + objectType.PrivateDescription = config.Description objectType.IsTypeOf = config.IsTypeOf objectType.typeConfig = config @@ -351,13 +351,13 @@ func (gt *Object) AddFieldConfig(fieldName string, fieldConfig *Field) { } func (gt *Object) Name() string { - return gt.name + return gt.PrivateName } func (gt *Object) Description() string { return "" } func (gt *Object) String() string { - return gt.name + return gt.PrivateName } func (gt *Object) Fields() FieldDefinitionMap { fields, err := defineFieldMap(gt, gt.typeConfig.Fields) @@ -477,10 +477,10 @@ func defineFieldMap(ttype Named, fields Fields) (FieldDefinitionMap, error) { return resultFieldMap, err } fieldArg := &Argument{ - name: argName, - description: arg.Description, - Type: arg.Type, - DefaultValue: arg.DefaultValue, + PrivateName: argName, + PrivateDescription: arg.Description, + Type: arg.Type, + DefaultValue: arg.DefaultValue, } fieldDef.Args = append(fieldDef.Args, fieldArg) } @@ -549,21 +549,21 @@ type FieldArgument struct { } type Argument struct { - name string `json:"name"` - Type Input `json:"type"` - DefaultValue interface{} `json:"defaultValue"` - description string `json:"description"` + PrivateName string `json:"name"` + Type Input `json:"type"` + DefaultValue interface{} `json:"defaultValue"` + PrivateDescription string `json:"description"` } func (st *Argument) Name() string { - return st.name + return st.PrivateName } func (st *Argument) Description() string { - return st.description + return st.PrivateDescription } func (st *Argument) String() string { - return st.name + return st.PrivateName } func (st *Argument) Error() error { return nil @@ -588,9 +588,9 @@ func (st *Argument) Error() error { * */ type Interface struct { - name string `json:"name"` - description string `json:"description"` - ResolveType ResolveTypeFn + PrivateName string `json:"name"` + PrivateDescription string `json:"description"` + ResolveType ResolveTypeFn typeConfig InterfaceConfig fields FieldDefinitionMap @@ -620,8 +620,8 @@ func NewInterface(config InterfaceConfig) *Interface { it.err = err return it } - it.name = config.Name - it.description = config.Description + it.PrivateName = config.Name + it.PrivateDescription = config.Description it.ResolveType = config.ResolveType it.typeConfig = config it.implementations = []*Object{} @@ -636,10 +636,10 @@ func (it *Interface) AddFieldConfig(fieldName string, fieldConfig *Field) { it.typeConfig.Fields[fieldName] = fieldConfig } func (it *Interface) Name() string { - return it.name + return it.PrivateName } func (it *Interface) Description() string { - return it.description + return it.PrivateDescription } func (it *Interface) Fields() (fields FieldDefinitionMap) { it.fields, it.err = defineFieldMap(it, it.typeConfig.Fields) @@ -658,11 +658,11 @@ func (it *Interface) IsPossibleType(ttype *Object) bool { if possibleType == nil { continue } - possibleTypes[possibleType.name] = true + possibleTypes[possibleType.PrivateName] = true } it.possibleTypes = possibleTypes } - if val, ok := it.possibleTypes[ttype.name]; ok { + if val, ok := it.possibleTypes[ttype.PrivateName]; ok { return val } return false @@ -674,7 +674,7 @@ func (it *Interface) ObjectType(value interface{}, info ResolveInfo) *Object { return getTypeOf(value, info, it) } func (it *Interface) String() string { - return it.name + return it.PrivateName } func (it *Interface) Error() error { return it.err @@ -717,9 +717,9 @@ func getTypeOf(value interface{}, info ResolveInfo, abstractType Abstract) *Obje * */ type Union struct { - name string `json:"name"` - description string `json:"description"` - ResolveType ResolveTypeFn + PrivateName string `json:"name"` + PrivateDescription string `json:"description"` + ResolveType ResolveTypeFn typeConfig UnionConfig types []*Object @@ -747,8 +747,8 @@ func NewUnion(config UnionConfig) *Union { objectType.err = err return objectType } - objectType.name = config.Name - objectType.description = config.Description + objectType.PrivateName = config.Name + objectType.PrivateDescription = config.Description objectType.ResolveType = config.ResolveType err = invariant( @@ -801,12 +801,12 @@ func (ut *Union) IsPossibleType(ttype *Object) bool { if possibleType == nil { continue } - possibleTypes[possibleType.name] = true + possibleTypes[possibleType.PrivateName] = true } ut.possibleTypes = possibleTypes } - if val, ok := ut.possibleTypes[ttype.name]; ok { + if val, ok := ut.possibleTypes[ttype.PrivateName]; ok { return val } return false @@ -818,13 +818,13 @@ func (ut *Union) ObjectType(value interface{}, info ResolveInfo) *Object { return getTypeOf(value, info, ut) } func (ut *Union) String() string { - return ut.name + return ut.PrivateName } func (ut *Union) Name() string { - return ut.name + return ut.PrivateName } func (ut *Union) Description() string { - return ut.description + return ut.PrivateDescription } func (ut *Union) Error() error { return ut.err @@ -852,8 +852,8 @@ func (ut *Union) Error() error { * will be used as it's internal value. */ type Enum struct { - name string `json:"name"` - description string `json:"description"` + PrivateName string `json:"name"` + PrivateDescription string `json:"description"` enumConfig EnumConfig values []*EnumValueDefinition @@ -890,8 +890,8 @@ func NewEnum(config EnumConfig) *Enum { return gt } - gt.name = config.Name - gt.description = config.Description + gt.PrivateName = config.Name + gt.PrivateDescription = config.Description gt.values, err = gt.defineEnumValues(config.Values) if err != nil { gt.err = err @@ -965,13 +965,13 @@ func (gt *Enum) ParseLiteral(valueAST ast.Value) interface{} { return nil } func (gt *Enum) Name() string { - return gt.name + return gt.PrivateName } func (gt *Enum) Description() string { return "" } func (gt *Enum) String() string { - return gt.name + return gt.PrivateName } func (gt *Enum) Error() error { return gt.err @@ -1021,8 +1021,8 @@ func (gt *Enum) getNameLookup() map[string]*EnumValueDefinition { * */ type InputObject struct { - name string `json:"name"` - description string `json:"description"` + PrivateName string `json:"name"` + PrivateDescription string `json:"description"` typeConfig InputObjectConfig fields InputObjectFieldMap @@ -1035,21 +1035,21 @@ type InputObjectFieldConfig struct { Description string `json:"description"` } type InputObjectField struct { - name string `json:"name"` - Type Input `json:"type"` - DefaultValue interface{} `json:"defaultValue"` - description string `json:"description"` + PrivateName string `json:"name"` + Type Input `json:"type"` + DefaultValue interface{} `json:"defaultValue"` + PrivateDescription string `json:"description"` } func (st *InputObjectField) Name() string { - return st.name + return st.PrivateName } func (st *InputObjectField) Description() string { - return st.description + return st.PrivateDescription } func (st *InputObjectField) String() string { - return st.name + return st.PrivateName } func (st *InputObjectField) Error() error { return nil @@ -1073,8 +1073,8 @@ func NewInputObject(config InputObjectConfig) *InputObject { return gt } - gt.name = config.Name - gt.description = config.Description + gt.PrivateName = config.Name + gt.PrivateDescription = config.Description gt.typeConfig = config gt.fields = gt.defineFieldMap() return gt @@ -1116,9 +1116,9 @@ func (gt *InputObject) defineFieldMap() InputObjectFieldMap { return resultFieldMap } field := &InputObjectField{} - field.name = fieldName + field.PrivateName = fieldName field.Type = fieldConfig.Type - field.description = fieldConfig.Description + field.PrivateDescription = fieldConfig.Description field.DefaultValue = fieldConfig.DefaultValue resultFieldMap[fieldName] = field } @@ -1128,13 +1128,13 @@ func (gt *InputObject) Fields() InputObjectFieldMap { return gt.fields } func (gt *InputObject) Name() string { - return gt.name + return gt.PrivateName } func (gt *InputObject) Description() string { - return gt.description + return gt.PrivateDescription } func (gt *InputObject) String() string { - return gt.name + return gt.PrivateName } func (gt *InputObject) Error() error { return gt.err @@ -1213,8 +1213,8 @@ func (gl *List) Error() error { * Note: the enforcement of non-nullability occurs within the executor. */ type NonNull struct { - name string `json:"name"` // added to conform with introspection for NonNull.Name = nil - OfType Type `json:"ofType"` + PrivateName string `json:"name"` // added to conform with introspection for NonNull.Name = nil + OfType Type `json:"ofType"` err error } diff --git a/directives.go b/directives.go index 22c2fbea..67a1aa0d 100644 --- a/directives.go +++ b/directives.go @@ -36,9 +36,9 @@ var IncludeDirective *Directive = NewDirective(&Directive{ "the `if` argument is true.", Args: []*Argument{ &Argument{ - name: "if", - Type: NewNonNull(Boolean), - description: "Included when true.", + PrivateName: "if", + Type: NewNonNull(Boolean), + PrivateDescription: "Included when true.", }, }, OnOperation: false, @@ -55,9 +55,9 @@ var SkipDirective *Directive = NewDirective(&Directive{ "argument is true.", Args: []*Argument{ &Argument{ - name: "if", - Type: NewNonNull(Boolean), - description: "Skipped when true.", + PrivateName: "if", + Type: NewNonNull(Boolean), + PrivateDescription: "Skipped when true.", }, }, OnOperation: false, diff --git a/executor.go b/executor.go index 0e13f010..1d20ede4 100644 --- a/executor.go +++ b/executor.go @@ -170,7 +170,7 @@ func getOperationRootType(schema Schema, operation ast.Definition) (*Object, err return schema.QueryType(), nil case "mutation": mutationType := schema.MutationType() - if mutationType.name == "" { + if mutationType.PrivateName == "" { return nil, errors.New("Schema is not configured for mutations") } return mutationType, nil diff --git a/introspection.go b/introspection.go index e832d949..dd91e5d2 100644 --- a/introspection.go +++ b/introspection.go @@ -433,8 +433,8 @@ mutation operations.`, Description: "Request the type information of a single type.", Args: []*Argument{ &Argument{ - name: "name", - Type: NewNonNull(String), + PrivateName: "name", + Type: NewNonNull(String), }, }, Resolve: func(p ResolveParams) interface{} { diff --git a/schema.go b/schema.go index f9526e5c..94078c78 100644 --- a/schema.go +++ b/schema.go @@ -277,10 +277,10 @@ func assertObjectImplementsInterface(object *Object, iface *Interface) error { // Assert each interface field arg is implemented. for _, ifaceArg := range ifaceField.Args { - argName := ifaceArg.name + argName := ifaceArg.PrivateName var objectArg *Argument for _, arg := range objectField.Args { - if arg.name == argName { + if arg.PrivateName == argName { objectArg = arg break } @@ -314,10 +314,10 @@ func assertObjectImplementsInterface(object *Object, iface *Interface) error { } // Assert argument set invariance. for _, objectArg := range objectField.Args { - argName := objectArg.name + argName := objectArg.PrivateName var ifaceArg *Argument for _, arg := range ifaceField.Args { - if arg.name == argName { + if arg.PrivateName == argName { ifaceArg = arg break } diff --git a/values.go b/values.go index 017b82dc..d2a0f711 100644 --- a/values.go +++ b/values.go @@ -44,7 +44,7 @@ func getArgumentValues(argDefs []*Argument, argASTs []*ast.Argument, variableVar results := map[string]interface{}{} for _, argDef := range argDefs { - name := argDef.name + name := argDef.PrivateName var valueAST ast.Value if argAST, ok := argASTMap[name]; ok { valueAST = argAST.Value From de47e8d7870b6faa559db53310d559bc414cafe7 Mon Sep 17 00:00:00 2001 From: Fugiman Date: Sat, 7 Nov 2015 17:48:11 -0800 Subject: [PATCH 09/41] Fix go vet errors --- examples/http/main.go | 4 ++-- executor.go | 8 -------- language/visitor/visitor.go | 4 +--- 3 files changed, 3 insertions(+), 13 deletions(-) diff --git a/examples/http/main.go b/examples/http/main.go index f1a811b2..5c9a59fa 100644 --- a/examples/http/main.go +++ b/examples/http/main.go @@ -79,7 +79,7 @@ func executeQuery(query string, schema graphql.Schema) *graphql.Result { RequestString: query, }) if len(result.Errors) > 0 { - fmt.Println("wrong result, unexpected errors: %v", result.Errors) + fmt.Printf("wrong result, unexpected errors: %v", result.Errors) } return result } @@ -93,7 +93,7 @@ func main() { }) fmt.Println("Now server is running on port 8080") - fmt.Println("Test with Get : curl -g \"http://localhost:8080/graphql?query={user(id:%221%22){name}}\"") + fmt.Println("Test with Get : curl -g 'http://localhost:8080/graphql?query={user(id:\"1\"){name}}'") http.ListenAndServe(":8080", nil) } diff --git a/executor.go b/executor.go index 1b6eb339..65e7e953 100644 --- a/executor.go +++ b/executor.go @@ -594,10 +594,6 @@ func completeValue(eCtx *ExecutionContext, returnType Type, fieldASTs []*ast.Fie // If field type is Scalar or Enum, serialize to a valid value, returning // null if serialization is not possible. if returnType, ok := returnType.(*Scalar); ok { - err := invariant(returnType.Serialize != nil, "Missing serialize method on type") - if err != nil { - panic(gqlerrors.FormatError(err)) - } serializedResult := returnType.Serialize(result) if isNullish(serializedResult) { return nil @@ -605,10 +601,6 @@ func completeValue(eCtx *ExecutionContext, returnType Type, fieldASTs []*ast.Fie return serializedResult } if returnType, ok := returnType.(*Enum); ok { - err := invariant(returnType.Serialize != nil, "Missing serialize method on type") - if err != nil { - panic(gqlerrors.FormatError(err)) - } serializedResult := returnType.Serialize(result) if isNullish(serializedResult) { return nil diff --git a/language/visitor/visitor.go b/language/visitor/visitor.go index 09297379..8110c9af 100644 --- a/language/visitor/visitor.go +++ b/language/visitor/visitor.go @@ -506,7 +506,6 @@ func getVisitFn(visitorOpts *VisitorOptions, isLeaving bool, kind string) VisitF // { Kind: { enter() {} } } return kindVisitor.Enter } - return nil } if isLeaving { @@ -519,7 +518,6 @@ func getVisitFn(visitorOpts *VisitorOptions, isLeaving bool, kind string) VisitF // { leave: { Kind() {} } } return specificKindVisitor } - return nil } else { // { leave() {} } @@ -531,7 +529,7 @@ func getVisitFn(visitorOpts *VisitorOptions, isLeaving bool, kind string) VisitF // { enter: { Kind() {} } } return specificKindVisitor } - return nil } + return nil } From b32c835f6037e69a5d2372ed5181c51a4dbbba5f Mon Sep 17 00:00:00 2001 From: Fugiman Date: Sat, 7 Nov 2015 17:49:28 -0800 Subject: [PATCH 10/41] Add go vet to travis builds --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 8e979e0a..5fcef0e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,3 +10,4 @@ before_install: script: - $HOME/gopath/bin/goveralls -service=travis-ci + - go vet ./... From 9ce95cf224d46018e4fedac7f73da0250ceeca56 Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Mon, 9 Nov 2015 17:57:36 +0800 Subject: [PATCH 11/41] Working draft version of `validator` and a couple of `validation rules` - Ported a portion of tests to verify validator is working at some level. - Updated `visitor` implementation. - Proved to be tricky because current implementation allows user to edit the tree in-memory - for e.g. `printer` reduces the `ast.Node` into a string - Need thorough clean up but working at the moment. - Rules have to exists under `graphql`, due it being tightly-coupled. - Total number of rules: 22 - Currently planned to write all rules in `rules.go`. - Else, split it up to many files - But tests are filed under `rules/` folder. - TODO: - Complete port of tests for `ArgumentsOfCorrectTypeRule` and `KnownTypeNamesRule` - Implement other validation rules. - Should be relatively straight forward since now we have examples on how to implement it. --- definition.go | 41 ++ graphql.go | 2 +- language/kinds/kinds.go | 4 +- language/printer/printer.go | 148 ++++++- language/printer/printer_old.go | 359 ++++++++++++++++ language/visitor/visitor.go | 440 +++++++++++++++----- language/visitor/visitor_test.go | 184 +++------ rules.go | 177 ++++++++ rules/arguments_of_correct_type_test.go | 112 +++++ rules/harness_test.go | 517 ++++++++++++++++++++++++ rules/known_type_names_test.go | 47 +++ schema.go | 9 + type_info.go | 235 +++++++++++ validator.go | 191 ++++++++- 14 files changed, 2225 insertions(+), 241 deletions(-) create mode 100644 language/printer/printer_old.go create mode 100644 rules.go create mode 100644 rules/arguments_of_correct_type_test.go create mode 100644 rules/harness_test.go create mode 100644 rules/known_type_names_test.go create mode 100644 type_info.go diff --git a/definition.go b/definition.go index 3eacbbd8..7df1d7ca 100644 --- a/definition.go +++ b/definition.go @@ -100,6 +100,19 @@ var _ Composite = (*Object)(nil) var _ Composite = (*Interface)(nil) var _ Composite = (*Union)(nil) +func IsCompositeType(ttype interface{}) bool { + if _, ok := ttype.(*Object); ok { + return true + } + if _, ok := ttype.(*Interface); ok { + return true + } + if _, ok := ttype.(*Union); ok { + return true + } + return false +} + // These types may describe the parent context of a selection set. type Abstract interface { GetObjectType(value interface{}, info ResolveInfo) *Object @@ -110,6 +123,34 @@ type Abstract interface { var _ Abstract = (*Interface)(nil) var _ Abstract = (*Union)(nil) +func IsAbstractType(ttype Type) bool { + if _, ok := ttype.(*Interface); ok { + return true + } + if _, ok := ttype.(*Union); ok { + return true + } + return false +} + +type Nullable interface { +} + +var _ Nullable = (*Scalar)(nil) +var _ Nullable = (*Object)(nil) +var _ Nullable = (*Interface)(nil) +var _ Nullable = (*Union)(nil) +var _ Nullable = (*Enum)(nil) +var _ Nullable = (*InputObject)(nil) +var _ Nullable = (*List)(nil) + +func GetNullable(ttype Type) Nullable { + if ttype, ok := ttype.(*NonNull); ok { + return ttype.OfType + } + return ttype +} + // These named types do not include modifiers like List or NonNull. type Named interface { String() string diff --git a/graphql.go b/graphql.go index c3e1703f..8416551c 100644 --- a/graphql.go +++ b/graphql.go @@ -25,7 +25,7 @@ func Graphql(p Params) *Result { Errors: gqlerrors.FormatErrors(err), } } - validationResult := ValidateDocument(p.Schema, AST) + validationResult := ValidateDocument(&p.Schema, AST, nil) if !validationResult.IsValid { return &Result{ diff --git a/language/kinds/kinds.go b/language/kinds/kinds.go index 1aafca81..d1161763 100644 --- a/language/kinds/kinds.go +++ b/language/kinds/kinds.go @@ -9,8 +9,8 @@ const ( Directive = "Directive" VariableDefinition = "VariableDefinition" Variable = "Variable" - Named = "Named" - List = "List" + Named = "Named" // previously NamedType + List = "List" // previously ListType NonNull = "NonNull" InlineFragment = "InlineFragment" FragmentSpread = "FragmentSpread" diff --git a/language/printer/printer.go b/language/printer/printer.go index c4a35f52..8d41b672 100644 --- a/language/printer/printer.go +++ b/language/printer/printer.go @@ -6,6 +6,7 @@ import ( "github.com/graphql-go/graphql/language/ast" "github.com/graphql-go/graphql/language/visitor" + "reflect" ) func getMapValue(m map[string]interface{}, key string) interface{} { @@ -57,13 +58,20 @@ func toSliceString(slice interface{}) []string { return []string{} } res := []string{} - for _, s := range slice.([]interface{}) { - switch s := s.(type) { - case string: - res = append(res, s) + switch reflect.TypeOf(slice).Kind() { + case reflect.Slice: + s := reflect.ValueOf(slice) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + elemInterface := elem.Interface() + if elem, ok := elemInterface.(string); ok { + res = append(res, elem) + } } + return res + default: + return res } - return res } func join(str []string, sep string) string { @@ -106,6 +114,8 @@ func indent(maybeString interface{}) string { var printDocASTReducer = map[string]visitor.VisitFunc{ "Name": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.Name: + return visitor.ActionUpdate, node.Value case map[string]interface{}: return visitor.ActionUpdate, getMapValue(node, "Value") } @@ -113,6 +123,8 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "Variable": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.Variable: + return visitor.ActionUpdate, fmt.Sprintf("$%v", node.Name) case map[string]interface{}: return visitor.ActionUpdate, "$" + getMapValueString(node, "Name") } @@ -120,6 +132,9 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "Document": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.Document: + definitions := toSliceString(node.Definitions) + return visitor.ActionUpdate, join(definitions, "\n\n") + "\n" case map[string]interface{}: definitions := toSliceString(getMapValue(node, "Definitions")) return visitor.ActionUpdate, join(definitions, "\n\n") + "\n" @@ -128,6 +143,25 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "OperationDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.OperationDefinition: + op := node.Operation + name := fmt.Sprintf("%v", node.Name) + + defs := wrap("(", join(toSliceString(node.VariableDefinitions), ", "), ")") + directives := join(toSliceString(node.Directives), " ") + selectionSet := fmt.Sprintf("%v", node.SelectionSet) + str := "" + if name == "" { + str = selectionSet + } else { + str = join([]string{ + op, + join([]string{name, defs}, ""), + directives, + selectionSet, + }, " ") + } + return visitor.ActionUpdate, str case map[string]interface{}: op := getMapValueString(node, "Operation") name := getMapValueString(node, "Name") @@ -152,6 +186,12 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "VariableDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.VariableDefinition: + variable := fmt.Sprintf("%v", node.Variable) + ttype := fmt.Sprintf("%v", node.Type) + defaultValue := fmt.Sprintf("%v", node.DefaultValue) + + return visitor.ActionUpdate, variable + ": " + ttype + wrap(" = ", defaultValue, "") case map[string]interface{}: variable := getMapValueString(node, "Variable") @@ -165,6 +205,9 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "SelectionSet": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.SelectionSet: + str := block(node.Selections) + return visitor.ActionUpdate, str case map[string]interface{}: selections := getMapValue(node, "Selections") str := block(selections) @@ -175,6 +218,10 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "Field": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.Argument: + name := fmt.Sprintf("%v", node.Name) + value := fmt.Sprintf("%v", node.Value) + return visitor.ActionUpdate, name + ": " + value case map[string]interface{}: alias := getMapValueString(node, "Alias") @@ -197,6 +244,10 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "Argument": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.FragmentSpread: + name := fmt.Sprintf("%v", node.Name) + directives := toSliceString(node.Directives) + return visitor.ActionUpdate, "..." + name + wrap(" ", join(directives, " "), "") case map[string]interface{}: name := getMapValueString(node, "Name") value := getMapValueString(node, "Value") @@ -206,6 +257,11 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "FragmentSpread": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.InlineFragment: + typeCondition := fmt.Sprintf("%v", node.TypeCondition) + directives := toSliceString(node.Directives) + selectionSet := fmt.Sprintf("%v", node.SelectionSet) + return visitor.ActionUpdate, "... on " + typeCondition + " " + wrap("", join(directives, " "), " ") + selectionSet case map[string]interface{}: name := getMapValueString(node, "Name") directives := toSliceString(getMapValue(node, "Directives")) @@ -225,6 +281,12 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "FragmentDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.FragmentDefinition: + name := fmt.Sprintf("%v", node.Name) + typeCondition := fmt.Sprintf("%v", node.TypeCondition) + directives := toSliceString(node.Directives) + selectionSet := fmt.Sprintf("%v", node.SelectionSet) + return visitor.ActionUpdate, "fragment " + name + " on " + typeCondition + " " + wrap("", join(directives, " "), " ") + selectionSet case map[string]interface{}: name := getMapValueString(node, "Name") typeCondition := getMapValueString(node, "TypeCondition") @@ -237,6 +299,8 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ "IntValue": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.IntValue: + return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value) case map[string]interface{}: return visitor.ActionUpdate, getMapValueString(node, "Value") } @@ -244,6 +308,8 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "FloatValue": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.FloatValue: + return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value) case map[string]interface{}: return visitor.ActionUpdate, getMapValueString(node, "Value") } @@ -251,6 +317,8 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "StringValue": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.StringValue: + return visitor.ActionUpdate, `"` + fmt.Sprintf("%v", node.Value) + `"` case map[string]interface{}: return visitor.ActionUpdate, `"` + getMapValueString(node, "Value") + `"` } @@ -258,6 +326,8 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "BooleanValue": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.BooleanValue: + return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value) case map[string]interface{}: return visitor.ActionUpdate, getMapValueString(node, "Value") } @@ -265,6 +335,8 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "EnumValue": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.EnumValue: + return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value) case map[string]interface{}: return visitor.ActionUpdate, getMapValueString(node, "Value") } @@ -272,6 +344,8 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "ListValue": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.ListValue: + return visitor.ActionUpdate, "[" + join(toSliceString(node.Values), ", ") + "]" case map[string]interface{}: return visitor.ActionUpdate, "[" + join(toSliceString(getMapValue(node, "Values")), ", ") + "]" } @@ -279,6 +353,8 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "ObjectValue": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.ObjectValue: + return visitor.ActionUpdate, "{" + join(toSliceString(node.Fields), ", ") + "}" case map[string]interface{}: return visitor.ActionUpdate, "{" + join(toSliceString(getMapValue(node, "Fields")), ", ") + "}" } @@ -286,6 +362,10 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "ObjectField": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.ObjectField: + name := fmt.Sprintf("%v", node.Name) + value := fmt.Sprintf("%v", node.Value) + return visitor.ActionUpdate, name + ": " + value case map[string]interface{}: name := getMapValueString(node, "Name") value := getMapValueString(node, "Value") @@ -296,6 +376,10 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ "Directive": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.Directive: + name := fmt.Sprintf("%v", node.Name) + args := toSliceString(node.Arguments) + return visitor.ActionUpdate, "@" + name + wrap("(", join(args, ", "), ")") case map[string]interface{}: name := getMapValueString(node, "Name") args := toSliceString(getMapValue(node, "Arguments")) @@ -306,6 +390,8 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ "Named": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.Named: + return visitor.ActionUpdate, fmt.Sprintf("%v", node.Name) case map[string]interface{}: return visitor.ActionUpdate, getMapValueString(node, "Name") } @@ -313,6 +399,8 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "List": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.List: + return visitor.ActionUpdate, "[" + fmt.Sprintf("%v", node.Type) + "]" case map[string]interface{}: return visitor.ActionUpdate, "[" + getMapValueString(node, "Type") + "]" } @@ -320,6 +408,8 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "NonNull": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.NonNull: + return visitor.ActionUpdate, fmt.Sprintf("%v", node.Type) + "!" case map[string]interface{}: return visitor.ActionUpdate, getMapValueString(node, "Type") + "!" } @@ -328,6 +418,12 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ "ObjectDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.ObjectDefinition: + name := fmt.Sprintf("%v", node.Name) + interfaces := toSliceString(node.Interfaces) + fields := node.Fields + str := "type " + name + " " + wrap("implements ", join(interfaces, ", "), " ") + block(fields) + return visitor.ActionUpdate, str case map[string]interface{}: name := getMapValueString(node, "Name") interfaces := toSliceString(getMapValue(node, "Interfaces")) @@ -339,6 +435,12 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "FieldDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.FieldDefinition: + name := fmt.Sprintf("%v", node.Name) + ttype := fmt.Sprintf("%v", node.Type) + args := toSliceString(node.Arguments) + str := name + wrap("(", join(args, ", "), ")") + ": " + ttype + return visitor.ActionUpdate, str case map[string]interface{}: name := getMapValueString(node, "Name") ttype := getMapValueString(node, "Type") @@ -350,6 +452,12 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "InputValueDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.InputValueDefinition: + name := fmt.Sprintf("%v", node.Name) + ttype := fmt.Sprintf("%v", node.Type) + defaultValue := fmt.Sprintf("%v", node.DefaultValue) + str := name + ": " + ttype + wrap(" = ", defaultValue, "") + return visitor.ActionUpdate, str case map[string]interface{}: name := getMapValueString(node, "Name") ttype := getMapValueString(node, "Type") @@ -361,6 +469,11 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "InterfaceDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.InterfaceDefinition: + name := fmt.Sprintf("%v", node.Name) + fields := node.Fields + str := "interface " + name + " " + block(fields) + return visitor.ActionUpdate, str case map[string]interface{}: name := getMapValueString(node, "Name") fields := getMapValue(node, "Fields") @@ -371,6 +484,11 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "UnionDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.UnionDefinition: + name := fmt.Sprintf("%v", node.Name) + types := toSliceString(node.Types) + str := "union " + name + " = " + join(types, " | ") + return visitor.ActionUpdate, str case map[string]interface{}: name := getMapValueString(node, "Name") types := toSliceString(getMapValue(node, "Types")) @@ -381,6 +499,10 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "ScalarDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.ScalarDefinition: + name := fmt.Sprintf("%v", node.Name) + str := "scalar " + name + return visitor.ActionUpdate, str case map[string]interface{}: name := getMapValueString(node, "Name") str := "scalar " + name @@ -390,6 +512,11 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "EnumDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.EnumDefinition: + name := fmt.Sprintf("%v", node.Name) + values := node.Values + str := "enum " + name + " " + block(values) + return visitor.ActionUpdate, str case map[string]interface{}: name := getMapValueString(node, "Name") values := getMapValue(node, "Values") @@ -400,6 +527,9 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "EnumValueDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.EnumValueDefinition: + name := fmt.Sprintf("%v", node.Name) + return visitor.ActionUpdate, name case map[string]interface{}: name := getMapValueString(node, "Name") return visitor.ActionUpdate, name @@ -408,6 +538,10 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "InputObjectDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.InputObjectDefinition: + name := fmt.Sprintf("%v", node.Name) + fields := node.Fields + return visitor.ActionUpdate, "input " + name + " " + block(fields) case map[string]interface{}: name := getMapValueString(node, "Name") fields := getMapValue(node, "Fields") @@ -417,6 +551,10 @@ var printDocASTReducer = map[string]visitor.VisitFunc{ }, "TypeExtensionDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { + case *ast.TypeExtensionDefinition: + definition := fmt.Sprintf("%v", node.Definition) + str := "extend " + definition + return visitor.ActionUpdate, str case map[string]interface{}: definition := getMapValueString(node, "Definition") str := "extend " + definition diff --git a/language/printer/printer_old.go b/language/printer/printer_old.go new file mode 100644 index 00000000..71d9157e --- /dev/null +++ b/language/printer/printer_old.go @@ -0,0 +1,359 @@ +package printer + +import ( + "fmt" + + "github.com/graphql-go/graphql/language/ast" + "github.com/graphql-go/graphql/language/visitor" + // "log" +) + +var printDocASTReducer11 = map[string]visitor.VisitFunc{ + "Name": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.Name: + return visitor.ActionUpdate, node.Value + } + return visitor.ActionNoChange, nil + + }, + "Variable": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.Variable: + return visitor.ActionUpdate, fmt.Sprintf("$%v", node.Name) + } + return visitor.ActionNoChange, nil + }, + "Document": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.Document: + definitions := toSliceString(node.Definitions) + return visitor.ActionUpdate, join(definitions, "\n\n") + "\n" + } + return visitor.ActionNoChange, nil + }, + "OperationDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.OperationDefinition: + op := node.Operation + name := fmt.Sprintf("%v", node.Name) + + defs := wrap("(", join(toSliceString(node.VariableDefinitions), ", "), ")") + directives := join(toSliceString(node.Directives), " ") + selectionSet := fmt.Sprintf("%v", node.SelectionSet) + str := "" + if name == "" { + str = selectionSet + } else { + str = join([]string{ + op, + join([]string{name, defs}, ""), + directives, + selectionSet, + }, " ") + } + return visitor.ActionUpdate, str + } + return visitor.ActionNoChange, nil + }, + "VariableDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.VariableDefinition: + variable := fmt.Sprintf("%v", node.Variable) + ttype := fmt.Sprintf("%v", node.Type) + defaultValue := fmt.Sprintf("%v", node.DefaultValue) + + return visitor.ActionUpdate, variable + ": " + ttype + wrap(" = ", defaultValue, "") + + } + return visitor.ActionNoChange, nil + }, + "SelectionSet": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.SelectionSet: + str := block(node.Selections) + return visitor.ActionUpdate, str + + } + return visitor.ActionNoChange, nil + }, + "Field": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.Field: + + alias := fmt.Sprintf("%v", node.Alias) + name := fmt.Sprintf("%v", node.Name) + args := toSliceString(node.Arguments) + directives := toSliceString(node.Directives) + selectionSet := fmt.Sprintf("%v", node.SelectionSet) + + str := join( + []string{ + wrap("", alias, ": ") + name + wrap("(", join(args, ", "), ")"), + join(directives, " "), + selectionSet, + }, + " ", + ) + return visitor.ActionUpdate, str + } + return visitor.ActionNoChange, nil + }, + "Argument": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.Argument: + name := fmt.Sprintf("%v", node.Name) + value := fmt.Sprintf("%v", node.Value) + return visitor.ActionUpdate, name + ": " + value + } + return visitor.ActionNoChange, nil + }, + "FragmentSpread": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.FragmentSpread: + name := fmt.Sprintf("%v", node.Name) + directives := toSliceString(node.Directives) + return visitor.ActionUpdate, "..." + name + wrap(" ", join(directives, " "), "") + } + return visitor.ActionNoChange, nil + }, + "InlineFragment": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.InlineFragment: + typeCondition := fmt.Sprintf("%v", node.TypeCondition) + directives := toSliceString(node.Directives) + selectionSet := fmt.Sprintf("%v", node.SelectionSet) + return visitor.ActionUpdate, "... on " + typeCondition + " " + wrap("", join(directives, " "), " ") + selectionSet + } + return visitor.ActionNoChange, nil + }, + "FragmentDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.FragmentDefinition: + name := fmt.Sprintf("%v", node.Name) + typeCondition := fmt.Sprintf("%v", node.TypeCondition) + directives := toSliceString(node.Directives) + selectionSet := fmt.Sprintf("%v", node.SelectionSet) + return visitor.ActionUpdate, "fragment " + name + " on " + typeCondition + " " + wrap("", join(directives, " "), " ") + selectionSet + } + return visitor.ActionNoChange, nil + }, + + "IntValue": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.IntValue: + return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value) + } + return visitor.ActionNoChange, nil + }, + "FloatValue": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.FloatValue: + return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value) + } + return visitor.ActionNoChange, nil + }, + "StringValue": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.StringValue: + return visitor.ActionUpdate, `"` + fmt.Sprintf("%v", node.Value) + `"` + } + return visitor.ActionNoChange, nil + }, + "BooleanValue": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.BooleanValue: + return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value) + } + return visitor.ActionNoChange, nil + }, + "EnumValue": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.EnumValue: + return visitor.ActionUpdate, fmt.Sprintf("%v", node.Value) + } + return visitor.ActionNoChange, nil + }, + "ListValue": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.ListValue: + return visitor.ActionUpdate, "[" + join(toSliceString(node.Values), ", ") + "]" + } + return visitor.ActionNoChange, nil + }, + "ObjectValue": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.ObjectValue: + return visitor.ActionUpdate, "{" + join(toSliceString(node.Fields), ", ") + "}" + } + return visitor.ActionNoChange, nil + }, + "ObjectField": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.ObjectField: + name := fmt.Sprintf("%v", node.Name) + value := fmt.Sprintf("%v", node.Value) + return visitor.ActionUpdate, name + ": " + value + } + return visitor.ActionNoChange, nil + }, + + "Directive": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.Directive: + name := fmt.Sprintf("%v", node.Name) + args := toSliceString(node.Arguments) + return visitor.ActionUpdate, "@" + name + wrap("(", join(args, ", "), ")") + } + return visitor.ActionNoChange, nil + }, + + "Named": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.Named: + return visitor.ActionUpdate, fmt.Sprintf("%v", node.Name) + } + return visitor.ActionNoChange, nil + }, + "List": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.List: + return visitor.ActionUpdate, "[" + fmt.Sprintf("%v", node.Type) + "]" + } + return visitor.ActionNoChange, nil + }, + "NonNull": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.NonNull: + return visitor.ActionUpdate, fmt.Sprintf("%v", node.Type) + "!" + } + return visitor.ActionNoChange, nil + }, + + "ObjectDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.ObjectDefinition: + name := fmt.Sprintf("%v", node.Name) + interfaces := toSliceString(node.Interfaces) + fields := node.Fields + str := "type " + name + " " + wrap("implements ", join(interfaces, ", "), " ") + block(fields) + return visitor.ActionUpdate, str + } + return visitor.ActionNoChange, nil + }, + "FieldDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.FieldDefinition: + name := fmt.Sprintf("%v", node.Name) + ttype := fmt.Sprintf("%v", node.Type) + args := toSliceString(node.Arguments) + str := name + wrap("(", join(args, ", "), ")") + ": " + ttype + return visitor.ActionUpdate, str + } + return visitor.ActionNoChange, nil + }, + "InputValueDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.InputValueDefinition: + name := fmt.Sprintf("%v", node.Name) + ttype := fmt.Sprintf("%v", node.Type) + defaultValue := fmt.Sprintf("%v", node.DefaultValue) + str := name + ": " + ttype + wrap(" = ", defaultValue, "") + return visitor.ActionUpdate, str + } + return visitor.ActionNoChange, nil + }, + "InterfaceDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.InterfaceDefinition: + name := fmt.Sprintf("%v", node.Name) + fields := node.Fields + str := "interface " + name + " " + block(fields) + return visitor.ActionUpdate, str + } + return visitor.ActionNoChange, nil + }, + "UnionDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.UnionDefinition: + name := fmt.Sprintf("%v", node.Name) + types := toSliceString(node.Types) + str := "union " + name + " = " + join(types, " | ") + return visitor.ActionUpdate, str + } + return visitor.ActionNoChange, nil + }, + "ScalarDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.ScalarDefinition: + name := fmt.Sprintf("%v", node.Name) + str := "scalar " + name + return visitor.ActionUpdate, str + } + return visitor.ActionNoChange, nil + }, + "EnumDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.EnumDefinition: + name := fmt.Sprintf("%v", node.Name) + values := node.Values + str := "enum " + name + " " + block(values) + return visitor.ActionUpdate, str + } + return visitor.ActionNoChange, nil + }, + "EnumValueDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.EnumValueDefinition: + name := fmt.Sprintf("%v", node.Name) + return visitor.ActionUpdate, name + } + return visitor.ActionNoChange, nil + }, + "InputObjectDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.InputObjectDefinition: + name := fmt.Sprintf("%v", node.Name) + fields := node.Fields + return visitor.ActionUpdate, "input " + name + " " + block(fields) + } + return visitor.ActionNoChange, nil + }, + "TypeExtensionDefinition": func(p visitor.VisitFuncParams) (string, interface{}) { + switch node := p.Node.(type) { + case *ast.TypeExtensionDefinition: + definition := fmt.Sprintf("%v", node.Definition) + str := "extend " + definition + return visitor.ActionUpdate, str + } + return visitor.ActionNoChange, nil + }, +} + +func Print11(astNode ast.Node) (printed interface{}) { + // defer func() interface{} { + // if r := recover(); r != nil { + // log.Println("Error: %v", r) + // return printed + // } + // return printed + // }() + printed = visitor.Visit(astNode, &visitor.VisitorOptions{ + LeaveKindMap: printDocASTReducer, + }, nil) + return printed +} + +// +//func PrintMap(astNodeMap map[string]interface{}) (printed interface{}) { +// defer func() interface{} { +// if r := recover(); r != nil { +// return fmt.Sprintf("%v", astNodeMap) +// } +// return printed +// }() +// printed = visitor.Visit(astNodeMap, &visitor.VisitorOptions{ +// LeaveKindMap: printDocASTReducer, +// }, nil) +// return printed +//} diff --git a/language/visitor/visitor.go b/language/visitor/visitor.go index 09297379..21b54952 100644 --- a/language/visitor/visitor.go +++ b/language/visitor/visitor.go @@ -3,6 +3,7 @@ package visitor import ( "encoding/json" "fmt" + "github.com/graphql-go/graphql/language/ast" "reflect" ) @@ -121,7 +122,7 @@ type stack struct { Index int Keys []interface{} Edits []*edit - InArray bool + inSlice bool Prev *stack } type edit struct { @@ -132,10 +133,11 @@ type edit struct { type VisitFuncParams struct { Node interface{} Key interface{} - Parent interface{} + Parent ast.Node Path []interface{} - Ancestors []interface{} + Ancestors []ast.Node } + type VisitFunc func(p VisitFuncParams) (string, interface{}) type NamedVisitFuncs struct { @@ -153,81 +155,126 @@ type VisitorOptions struct { LeaveKindMap map[string]VisitFunc // 4) Parallel visitors for entering and leaving nodes of a specific kind } -func Visit(root interface{}, visitorOpts *VisitorOptions, keyMap KeyMap) interface{} { +func Visit(root ast.Node, visitorOpts *VisitorOptions, keyMap KeyMap) interface{} { visitorKeys := keyMap if visitorKeys == nil { visitorKeys = QueryDocumentKeys } - var newRoot interface{} - // convert any interface{} into map[string]interface{} - b, err := json.Marshal(root) - if err != nil { - panic(fmt.Sprintf("Invalid root AST Node: %v", root)) - } - err = json.Unmarshal(b, &newRoot) - if err != nil || newRoot == nil { - panic(fmt.Sprintf("Invalid root AST Node (2): %v", root)) - } - + var result interface{} + var newRoot = root var sstack *stack var parent interface{} - inArray := isSlice(newRoot) + var parentSlice []interface{} + inSlice := false + prevInSlice := false keys := []interface{}{newRoot} index := -1 edits := []*edit{} path := []interface{}{} ancestors := []interface{}{} + ancestorsSlice := [][]interface{}{} Loop: for { index = index + 1 isLeaving := (len(keys) == index) - var key interface{} - var node interface{} + var key interface{} // string for structs or int for slices + var node interface{} // ast.Node or can be anything + var nodeSlice []interface{} isEdited := (isLeaving && len(edits) != 0) if isLeaving { - if len(ancestors) == 0 { - key = nil + if !inSlice { + if len(ancestors) == 0 { + key = nil + } else { + key, path = pop(path) + } } else { - key, path = pop(path) + if len(ancestorsSlice) == 0 { + key = nil + } else { + key, path = pop(path) + } } node = parent parent, ancestors = pop(ancestors) + nodeSlice = parentSlice + parentSlice, ancestorsSlice = popNodeSlice(ancestorsSlice) + if isEdited { + prevInSlice = inSlice editOffset := 0 for _, edit := range edits { arrayEditKey := 0 - if inArray { + if inSlice { keyInt := edit.Key.(int) edit.Key = keyInt - editOffset arrayEditKey = edit.Key.(int) } - if inArray && isNilNode(edit.Value) { - if n, ok := node.([]interface{}); ok { - node = splice(n, arrayEditKey) - } else { - panic(fmt.Sprintf("Invalid AST Node (1): %v", node)) - } + if inSlice && isNilNode(edit.Value) { + nodeSlice = spliceNode(nodeSlice, arrayEditKey) editOffset = editOffset + 1 } else { - if inArray { - if n, ok := node.([]interface{}); ok { - n[arrayEditKey] = edit.Value - node = n - } else { - panic(fmt.Sprintf("Invalid AST Node (2): %v", node)) - } + if inSlice { + nodeSlice[arrayEditKey] = edit.Value } else { - if n, ok := node.(map[string]interface{}); ok { - key := edit.Key.(string) - n[key] = edit.Value - node = n + key, _ := edit.Key.(string) + + var updatedNode interface{} + if !isSlice(edit.Value) { + if isStructNode(edit.Value) { + updatedNode = updateNodeField(node, key, edit.Value) + } else { + var todoNode map[string]interface{} + b, err := json.Marshal(node) + if err != nil { + panic(fmt.Sprintf("Invalid root AST Node: %v", root)) + } + err = json.Unmarshal(b, &todoNode) + if err != nil { + panic(fmt.Sprintf("Invalid root AST Node (2): %v", root)) + } + todoNode[key] = edit.Value + updatedNode = todoNode + } } else { - panic(fmt.Sprintf("Invalid AST Node (3): %v", node)) + isSliceOfNodes := true + + // check if edit.value slice is ast.nodes + switch reflect.TypeOf(edit.Value).Kind() { + case reflect.Slice: + s := reflect.ValueOf(edit.Value) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + if !isStructNode(elem.Interface()) { + isSliceOfNodes = false + } + } + } + + // is a slice of real nodes + if isSliceOfNodes { + // the node we are writing to is an ast.Node + updatedNode = updateNodeField(node, key, edit.Value) + } else { + var todoNode map[string]interface{} + b, err := json.Marshal(node) + if err != nil { + panic(fmt.Sprintf("Invalid root AST Node: %v", root)) + } + err = json.Unmarshal(b, &todoNode) + if err != nil { + panic(fmt.Sprintf("Invalid root AST Node (2): %v", root)) + } + todoNode[key] = edit.Value + updatedNode = todoNode + } + } + node = updatedNode } } } @@ -235,59 +282,112 @@ Loop: index = sstack.Index keys = sstack.Keys edits = sstack.Edits - inArray = sstack.InArray + inSlice = sstack.inSlice sstack = sstack.Prev } else { // get key - if !isNilNode(parent) { - if inArray { - key = index + if !inSlice { + if !isNilNode(parent) { + key = getFieldValue(keys, index) } else { - key = getField(keys, index) + // initial conditions + key = nil } } else { - // initial conditions - key = nil + key = index } // get node - if !isNilNode(parent) { - node = getField(parent, key) + if !inSlice { + if !isNilNode(parent) { + fieldValue := getFieldValue(parent, key) + if isNode(fieldValue) { + node = fieldValue.(ast.Node) + } + if isSlice(fieldValue) { + nodeSlice = toSliceInterfaces(fieldValue) + } + } else { + // initial conditions + node = newRoot + } } else { - // initial conditions - node = newRoot + if len(parentSlice) != 0 { + fieldValue := getFieldValue(parentSlice, key) + if isNode(fieldValue) { + node = fieldValue.(ast.Node) + } + if isSlice(fieldValue) { + nodeSlice = toSliceInterfaces(fieldValue) + } + } else { + // initial conditions + nodeSlice = []interface{}{} + } } - if isNilNode(node) { + if isNilNode(node) && len(nodeSlice) == 0 { continue } - if !isNilNode(parent) { - path = append(path, key) + + if !inSlice { + if !isNilNode(parent) { + path = append(path, key) + } + } else { + if len(parentSlice) != 0 { + path = append(path, key) + } } } // get result from visitFn for a node if set var result interface{} resultIsUndefined := true - if !isSlice(node) && !isNilNode(node) { - if !isNode(node) { + if !isNilNode(node) { + if !isNode(node) { // is node-ish. panic(fmt.Sprintf("Invalid AST Node (4): %v", node)) } - n, ok := node.(map[string]interface{}) - if !ok { - panic(fmt.Sprintf("Invalid AST Node (5): %v", node)) + + // Try to pass in current node as ast.Node + // Note that since user can potentially return a non-ast.Node from visit functions. + // In that case, we try to unmarshal map[string]interface{} into ast.Node + var nodeIn interface{} + if _, ok := node.(map[string]interface{}); ok { + b, err := json.Marshal(node) + if err != nil { + panic(fmt.Sprintf("Invalid root AST Node: %v", root)) + } + err = json.Unmarshal(b, &nodeIn) + if err != nil { + panic(fmt.Sprintf("Invalid root AST Node (2a): %v", root)) + } + } else { + nodeIn = node } - kind, ok := n["Kind"].(string) - if !ok { - kind = "" + parentConcrete, _ := parent.(ast.Node) + ancestorsConcrete := []ast.Node{} + for _, ancestor := range ancestors { + if ancestorConcrete, ok := ancestor.(ast.Node); ok { + ancestorsConcrete = append(ancestorsConcrete, ancestorConcrete) + } } - visitFn := getVisitFn(visitorOpts, isLeaving, kind) + + kind := "" + if node, ok := node.(map[string]interface{}); ok { + kind, _ = node["Kind"].(string) + } + if node, ok := node.(ast.Node); ok { + kind = node.GetKind() + } + + visitFn := GetVisitFn(visitorOpts, isLeaving, kind) if visitFn != nil { p := VisitFuncParams{ - Node: node, + Node: nodeIn, Key: key, - Parent: parent, + Parent: parentConcrete, Path: path, - Ancestors: ancestors, + Ancestors: ancestorsConcrete, } action := ActionUpdate action, result = visitFn(p) @@ -295,7 +395,7 @@ Loop: break Loop } if action == ActionSkip { - if isLeaving { + if !isLeaving { _, path = pop(path) continue } @@ -320,19 +420,27 @@ Loop: } } + + // collect back edits on the way out if resultIsUndefined && isEdited { - edits = append(edits, &edit{ - Key: key, - Value: node, - }) + if !prevInSlice { + edits = append(edits, &edit{ + Key: key, + Value: node, + }) + } else { + edits = append(edits, &edit{ + Key: key, + Value: nodeSlice, + }) + } } - if !isLeaving { // add to stack prevStack := sstack sstack = &stack{ - InArray: inArray, + inSlice: inSlice, Index: index, Keys: keys, Edits: edits, @@ -340,42 +448,39 @@ Loop: } // replace keys - inArray = isSlice(node) + inSlice = false + if len(nodeSlice) > 0 { + inSlice = true + } keys = []interface{}{} - if !isNilNode(node) { - if inArray { - // get keys - if n, ok := node.([]interface{}); ok { - for _, m := range n { - keys = append(keys, m) - } - } else { - panic(fmt.Sprintf("Invalid AST Node (6): %v", node)) - } - } else { - if n, ok := node.(map[string]interface{}); ok { - kind, ok := n["Kind"].(string) - if !ok { - kind = "" - } + if inSlice { + // get keys + for _, m := range nodeSlice { + keys = append(keys, m) + } + } else { + if !isNilNode(node) { + if node, ok := node.(ast.Node); ok { + kind := node.GetKind() if n, ok := visitorKeys[kind]; ok { for _, m := range n { keys = append(keys, m) } } - } else { - panic(fmt.Sprintf("Invalid AST Node (7): %v", node)) } + } - } + } index = -1 edits = []*edit{} - if !isNilNode(parent) { - ancestors = append(ancestors, parent) - } + + ancestors = append(ancestors, parent) parent = node + ancestorsSlice = append(ancestorsSlice, parentSlice) + parentSlice = nodeSlice + } // loop guard @@ -384,9 +489,9 @@ Loop: } } if len(edits) != 0 { - newRoot = edits[0].Value + result = edits[0].Value } - return newRoot + return result } func pop(a []interface{}) (x interface{}, aa []interface{}) { @@ -396,17 +501,39 @@ func pop(a []interface{}) (x interface{}, aa []interface{}) { x, aa = a[len(a)-1], a[:len(a)-1] return x, aa } -func splice(a []interface{}, i int) []interface{} { - if i >= len(a) { - return a +func popNodeSlice(a [][]interface{}) (x []interface{}, aa [][]interface{}) { + if len(a) == 0 { + return x, aa } + x, aa = a[len(a)-1], a[:len(a)-1] + return x, aa +} +func spliceNode(a interface{}, i int) (result []interface{}) { if i < 0 { - return []interface{}{} + return result + } + typeOf := reflect.TypeOf(a) + if typeOf == nil { + return result + } + switch typeOf.Kind() { + case reflect.Slice: + s := reflect.ValueOf(a) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + elemInterface := elem.Interface() + result = append(result, elemInterface) + } + if i >= s.Len() { + return result + } + return append(result[:i], result[i+1:]...) + default: + return result } - return append(a[:i], a[i+1:]...) } -func getField(obj interface{}, key interface{}) interface{} { +func getFieldValue(obj interface{}, key interface{}) interface{} { val := reflect.ValueOf(obj) if val.Type().Kind() == reflect.Ptr { val = val.Elem() @@ -447,8 +574,82 @@ func getField(obj interface{}, key interface{}) interface{} { return nil } -func isSlice(Value interface{}) bool { - val := reflect.ValueOf(Value) +func updateNodeField(value interface{}, fieldName string, fieldValue interface{}) (retVal interface{}) { + retVal = value + val := reflect.ValueOf(value) + + isPtr := false + if val.IsValid() && val.Type().Kind() == reflect.Ptr { + val = val.Elem() + isPtr = true + } + if !val.IsValid() { + return retVal + } + if val.Type().Kind() == reflect.Struct { + for i := 0; i < val.NumField(); i++ { + valueField := val.Field(i) + typeField := val.Type().Field(i) + + // try matching the field name + if typeField.Name == fieldName { + fieldValueVal := reflect.ValueOf(fieldValue) + if valueField.CanSet() { + + if fieldValueVal.IsValid() { + if valueField.Type().Kind() == fieldValueVal.Type().Kind() { + if fieldValueVal.Type().Kind() == reflect.Slice { + newSliceValue := reflect.MakeSlice(reflect.TypeOf(valueField.Interface()), fieldValueVal.Len(), fieldValueVal.Len()) + for i := 0; i < newSliceValue.Len(); i++ { + dst := newSliceValue.Index(i) + src := fieldValueVal.Index(i) + srcValue := reflect.ValueOf(src.Interface()) + if dst.CanSet() { + dst.Set(srcValue) + } + } + valueField.Set(newSliceValue) + + } else { + valueField.Set(fieldValueVal) + } + } + } else { + valueField.Set(reflect.New(valueField.Type()).Elem()) + } + if isPtr == true { + retVal = val.Addr().Interface() + return retVal + } else { + retVal = val.Interface() + return retVal + } + + } + } + } + } + return retVal +} +func toSliceInterfaces(slice interface{}) (result []interface{}) { + switch reflect.TypeOf(slice).Kind() { + case reflect.Slice: + s := reflect.ValueOf(slice) + for i := 0; i < s.Len(); i++ { + elem := s.Index(i) + elemInterface := elem.Interface() + if elem, ok := elemInterface.(ast.Node); ok { + result = append(result, elem) + } + } + return result + default: + return result + } +} + +func isSlice(value interface{}) bool { + val := reflect.ValueOf(value) if val.IsValid() && val.Type().Kind() == reflect.Slice { return true } @@ -456,19 +657,38 @@ func isSlice(Value interface{}) bool { } func isNode(node interface{}) bool { val := reflect.ValueOf(node) + if val.IsValid() && val.Type().Kind() == reflect.Ptr { + val = val.Elem() + } if !val.IsValid() { return false } - if val.Type().Kind() == reflect.Ptr { - val = val.Elem() - } if val.Type().Kind() == reflect.Map { keyVal := reflect.ValueOf("Kind") valField := val.MapIndex(keyVal) return valField.IsValid() } + if val.Type().Kind() == reflect.Struct { + valField := val.FieldByName("Kind") + return valField.IsValid() + } return false } +func isStructNode(node interface{}) bool { + val := reflect.ValueOf(node) + if val.IsValid() && val.Type().Kind() == reflect.Ptr { + val = val.Elem() + } + if !val.IsValid() { + return false + } + if val.Type().Kind() == reflect.Struct { + valField := val.FieldByName("Kind") + return valField.IsValid() + } + return false +} + func isNilNode(node interface{}) bool { val := reflect.ValueOf(node) if !val.IsValid() { @@ -489,7 +709,7 @@ func isNilNode(node interface{}) bool { return val.Interface() == nil } -func getVisitFn(visitorOpts *VisitorOptions, isLeaving bool, kind string) VisitFunc { +func GetVisitFn(visitorOpts *VisitorOptions, isLeaving bool, kind string) VisitFunc { if visitorOpts == nil { return nil } diff --git a/language/visitor/visitor_test.go b/language/visitor/visitor_test.go index d2323c0f..412f96c0 100644 --- a/language/visitor/visitor_test.go +++ b/language/visitor/visitor_test.go @@ -1,10 +1,8 @@ package visitor_test import ( - "encoding/json" "io/ioutil" "reflect" - "strings" "testing" "github.com/graphql-go/graphql/language/ast" @@ -26,47 +24,6 @@ func parse(t *testing.T, query string) *ast.Document { return astDoc } -// Helper functions to get map value by key -// Allow keys to specify dot paths (e.g `Name.Value`) -func getMapValue(m map[string]interface{}, key string) interface{} { - tokens := strings.Split(key, ".") - valMap := m - for _, token := range tokens { - v, ok := valMap[token] - if !ok { - return nil - } - switch v := v.(type) { - case []interface{}: - return v - case map[string]interface{}: - valMap = v - continue - case string: - return v - } - } - return valMap -} -func getMapValueString(m map[string]interface{}, key string) string { - tokens := strings.Split(key, ".") - valMap := m - for _, token := range tokens { - v, ok := valMap[token] - if !ok { - return "" - } - switch v := v.(type) { - case map[string]interface{}: - valMap = v - continue - case string: - return v - } - } - return "" -} - func TestVisitor_AllowsForEditingOnEnter(t *testing.T) { query := `{ a, b, c { a, b, c } }` @@ -77,8 +34,8 @@ func TestVisitor_AllowsForEditingOnEnter(t *testing.T) { v := &visitor.VisitorOptions{ Enter: func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { - case map[string]interface{}: - if getMapValueString(node, "Kind") == "Field" && getMapValueString(node, "Name.Value") == "b" { + case *ast.Field: + if node.Name != nil && node.Name.Value == "b" { return visitor.ActionUpdate, nil } } @@ -87,7 +44,7 @@ func TestVisitor_AllowsForEditingOnEnter(t *testing.T) { } editedAst := visitor.Visit(astDoc, v, nil) - if !reflect.DeepEqual(ASTToJSON(t, expectedAST), editedAst) { + if !reflect.DeepEqual(expectedAST, editedAst) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expectedAST, editedAst)) } @@ -102,8 +59,8 @@ func TestVisitor_AllowsForEditingOnLeave(t *testing.T) { v := &visitor.VisitorOptions{ Leave: func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { - case map[string]interface{}: - if getMapValueString(node, "Kind") == "Field" && getMapValueString(node, "Name.Value") == "b" { + case *ast.Field: + if node.Name != nil && node.Name.Value == "b" { return visitor.ActionUpdate, nil } } @@ -112,7 +69,7 @@ func TestVisitor_AllowsForEditingOnLeave(t *testing.T) { } editedAst := visitor.Visit(astDoc, v, nil) - if !reflect.DeepEqual(ASTToJSON(t, expectedAST), editedAst) { + if !reflect.DeepEqual(expectedAST, editedAst) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expectedAST, editedAst)) } } @@ -122,11 +79,11 @@ func TestVisitor_VisitsEditedNode(t *testing.T) { query := `{ a { x } }` astDoc := parse(t, query) - addedField := map[string]interface{}{ - "Kind": "Field", - "Name": map[string]interface{}{ - "Kind": "Name", - "Value": "__typename", + addedField := &ast.Field{ + Kind: "Field", + Name: &ast.Name{ + Kind: "Name", + Value: "__typename", }, } @@ -134,13 +91,15 @@ func TestVisitor_VisitsEditedNode(t *testing.T) { v := &visitor.VisitorOptions{ Enter: func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { - case map[string]interface{}: - if getMapValueString(node, "Kind") == "Field" && getMapValueString(node, "Name.Value") == "a" { - s := getMapValue(node, "SelectionSet.Selections").([]interface{}) + case *ast.Field: + if node.Name != nil && node.Name.Value == "a" { + s := node.SelectionSet.Selections s = append(s, addedField) - return visitor.ActionUpdate, map[string]interface{}{ - "Kind": "Field", - "SelectionSet": s, + ss := node.SelectionSet + ss.Selections = s + return visitor.ActionUpdate, &ast.Field{ + Kind: "Field", + SelectionSet: ss, } } if reflect.DeepEqual(node, addedField) { @@ -183,18 +142,28 @@ func TestVisitor_AllowsSkippingASubTree(t *testing.T) { v := &visitor.VisitorOptions{ Enter: func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { - case map[string]interface{}: - visited = append(visited, []interface{}{"enter", getMapValue(node, "Kind"), getMapValue(node, "Value")}) - if getMapValueString(node, "Kind") == "Field" && getMapValueString(node, "Name.Value") == "b" { + case *ast.Name: + visited = append(visited, []interface{}{"enter", node.Kind, node.Value}) + case *ast.Field: + visited = append(visited, []interface{}{"enter", node.Kind, nil}) + if node.Name != nil && node.Name.Value == "b" { return visitor.ActionSkip, nil } + case ast.Node: + visited = append(visited, []interface{}{"enter", node.GetKind(), nil}) + default: + visited = append(visited, []interface{}{"enter", nil, nil}) } return visitor.ActionNoChange, nil }, Leave: func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { - case map[string]interface{}: - visited = append(visited, []interface{}{"leave", getMapValue(node, "Kind"), getMapValue(node, "Value")}) + case *ast.Name: + visited = append(visited, []interface{}{"leave", node.Kind, node.Value}) + case ast.Node: + visited = append(visited, []interface{}{"leave", node.GetKind(), nil}) + default: + visited = append(visited, []interface{}{"leave", nil, nil}) } return visitor.ActionNoChange, nil }, @@ -233,18 +202,26 @@ func TestVisitor_AllowsEarlyExitWhileVisiting(t *testing.T) { v := &visitor.VisitorOptions{ Enter: func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { - case map[string]interface{}: - visited = append(visited, []interface{}{"enter", getMapValue(node, "Kind"), getMapValue(node, "Value")}) - if getMapValue(node, "Kind") == "Name" && getMapValue(node, "Value") == "x" { + case *ast.Name: + visited = append(visited, []interface{}{"enter", node.Kind, node.Value}) + if node.Value == "x" { return visitor.ActionBreak, nil } + case ast.Node: + visited = append(visited, []interface{}{"enter", node.GetKind(), nil}) + default: + visited = append(visited, []interface{}{"enter", nil, nil}) } return visitor.ActionNoChange, nil }, Leave: func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { - case map[string]interface{}: - visited = append(visited, []interface{}{"leave", getMapValue(node, "Kind"), getMapValue(node, "Value")}) + case *ast.Name: + visited = append(visited, []interface{}{"leave", node.Kind, node.Value}) + case ast.Node: + visited = append(visited, []interface{}{"leave", node.GetKind(), nil}) + default: + visited = append(visited, []interface{}{"leave", nil, nil}) } return visitor.ActionNoChange, nil }, @@ -279,8 +256,8 @@ func TestVisitor_AllowsANamedFunctionsVisitorAPI(t *testing.T) { "Name": visitor.NamedVisitFuncs{ Kind: func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { - case map[string]interface{}: - visited = append(visited, []interface{}{"enter", getMapValue(node, "Kind"), getMapValue(node, "Value")}) + case *ast.Name: + visited = append(visited, []interface{}{"enter", node.Kind, node.Value}) } return visitor.ActionNoChange, nil }, @@ -288,15 +265,15 @@ func TestVisitor_AllowsANamedFunctionsVisitorAPI(t *testing.T) { "SelectionSet": visitor.NamedVisitFuncs{ Enter: func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { - case map[string]interface{}: - visited = append(visited, []interface{}{"enter", getMapValue(node, "Kind"), getMapValue(node, "Value")}) + case *ast.SelectionSet: + visited = append(visited, []interface{}{"enter", node.Kind, nil}) } return visitor.ActionNoChange, nil }, Leave: func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { - case map[string]interface{}: - visited = append(visited, []interface{}{"leave", getMapValue(node, "Kind"), getMapValue(node, "Value")}) + case *ast.SelectionSet: + visited = append(visited, []interface{}{"leave", node.Kind, nil}) } return visitor.ActionNoChange, nil }, @@ -540,27 +517,23 @@ func TestVisitor_VisitsKitchenSink(t *testing.T) { v := &visitor.VisitorOptions{ Enter: func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { - case map[string]interface{}: - - parent, ok := p.Parent.(map[string]interface{}) - if !ok { - parent = map[string]interface{}{} + case ast.Node: + if p.Parent != nil { + visited = append(visited, []interface{}{"enter", node.GetKind(), p.Key, p.Parent.GetKind()}) + } else { + visited = append(visited, []interface{}{"enter", node.GetKind(), p.Key, nil}) } - - visited = append(visited, []interface{}{"enter", getMapValue(node, "Kind"), p.Key, getMapValue(parent, "Kind")}) } return visitor.ActionNoChange, nil }, Leave: func(p visitor.VisitFuncParams) (string, interface{}) { switch node := p.Node.(type) { - case map[string]interface{}: - - parent, ok := p.Parent.(map[string]interface{}) - if !ok { - parent = map[string]interface{}{} + case ast.Node: + if p.Parent != nil { + visited = append(visited, []interface{}{"leave", node.GetKind(), p.Key, p.Parent.GetKind()}) + } else { + visited = append(visited, []interface{}{"leave", node.GetKind(), p.Key, nil}) } - - visited = append(visited, []interface{}{"leave", getMapValue(node, "Kind"), p.Key, getMapValue(parent, "Kind")}) } return visitor.ActionNoChange, nil }, @@ -572,34 +545,3 @@ func TestVisitor_VisitsKitchenSink(t *testing.T) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expectedVisited, visited)) } } - -func TestVisitor_ProducesHelpfulErrorMessages(t *testing.T) { - defer func() { - if r := recover(); r != nil { - err := r.(string) - expectedErr := `Invalid AST Node (4): map[random:Data]` - if err != expectedErr { - t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(err, expectedErr)) - } - return - } - t.Fatalf("expected to panic") - }() - astDoc := map[string]interface{}{ - "random": "Data", - } - _ = visitor.Visit(astDoc, nil, nil) -} - -func ASTToJSON(t *testing.T, a ast.Node) interface{} { - b, err := json.Marshal(a) - if err != nil { - t.Fatalf("Failed to marshal Node %v", err) - } - var f interface{} - err = json.Unmarshal(b, &f) - if err != nil { - t.Fatalf("Failed to unmarshal Node %v", err) - } - return f -} diff --git a/rules.go b/rules.go new file mode 100644 index 00000000..d1156cce --- /dev/null +++ b/rules.go @@ -0,0 +1,177 @@ +package graphql + +import ( + "fmt" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/language/ast" + "github.com/graphql-go/graphql/language/kinds" + "github.com/graphql-go/graphql/language/printer" + "github.com/graphql-go/graphql/language/visitor" +) + +/** + * SpecifiedRules set includes all validation rules defined by the GraphQL spec. + */ +var SpecifiedRules = []ValidationRuleFn{ + ArgumentsOfCorrectTypeRule, + KnownTypeNamesRule, +} + +type ValidationRuleInstance struct { + VisitorOpts *visitor.VisitorOptions + VisitSpreadFragments bool +} + +type ValidationRuleFn func(context *ValidationContext) *ValidationRuleInstance + +func ArgumentsOfCorrectTypeRule(context *ValidationContext) *ValidationRuleInstance { + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.Argument: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + var action = visitor.ActionNoChange + var result interface{} + if argAST, ok := p.Node.(*ast.Argument); ok { + value := argAST.Value + argDef := context.GetArgument() + if argDef != nil && !isValidLiteralValue(argDef.Type, value) { + argNameValue := "" + argName := argAST.Name + if argName != nil { + argNameValue = argName.Value + } + // TODO: helper to construct gqlerror with message + []ast.Node + return visitor.ActionNoChange, gqlerrors.NewError( + fmt.Sprintf(`Argument "%v" expected type "%v" but got: %v.`, + argNameValue, argDef.Type, printer.Print(value)), + []ast.Node{value}, + "", + nil, + []int{}, + ) + } + } + return action, result + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + +func KnownTypeNamesRule(context *ValidationContext) *ValidationRuleInstance { + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.Named: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.Named); ok { + typeNameValue := "" + typeName := node.Name + if typeName != nil { + typeNameValue = typeName.Value + } + ttype := context.GetSchema().GetType(typeNameValue) + if ttype == nil { + return visitor.ActionNoChange, gqlerrors.NewError( + fmt.Sprintf(`Unknown type "%v".`, typeNameValue), + []ast.Node{node}, + "", + nil, + []int{}, + ) + } + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + +/** + * Utility for validators which determines if a value literal AST is valid given + * an input type. + * + * Note that this only validates literal values, variables are assumed to + * provide values of the correct type. + */ +func isValidLiteralValue(ttype Input, valueAST ast.Value) bool { + // A value must be provided if the type is non-null. + if ttype, ok := ttype.(*NonNull); ok { + if valueAST == nil { + return false + } + ofType, _ := ttype.OfType.(Input) + return isValidLiteralValue(ofType, valueAST) + } + + if valueAST == nil { + return true + } + + // This function only tests literals, and assumes variables will provide + // values of the correct type. + if valueAST.GetKind() == kinds.Variable { + return true + } + + // Lists accept a non-list value as a list of one. + if ttype, ok := ttype.(*List); ok { + itemType, _ := ttype.OfType.(Input) + if valueAST, ok := valueAST.(*ast.ListValue); ok { + for _, value := range valueAST.Values { + if isValidLiteralValue(itemType, value) == false { + return false + } + } + return true + } + return isValidLiteralValue(itemType, valueAST) + + } + + // Input objects check each defined field and look for undefined fields. + if ttype, ok := ttype.(*InputObject); ok { + valueAST, ok := valueAST.(*ast.ObjectValue) + if !ok { + return false + } + fields := ttype.GetFields() + + // Ensure every provided field is defined. + // Ensure every defined field is valid. + fieldASTs := valueAST.Fields + for _, fieldAST := range fieldASTs { + fieldASTName := "" + if fieldAST.Name != nil { + fieldASTName = fieldAST.Name.Value + } + field, ok := fields[fieldASTName] + if !ok { + return false + } + if fieldAST == nil { + return false + } + if !isValidLiteralValue(field.Type, fieldAST.Value) { + return false + } + } + } + + if ttype, ok := ttype.(*Scalar); ok { + return !isNullish(ttype.ParseLiteral(valueAST)) + } + if ttype, ok := ttype.(*Enum); ok { + return !isNullish(ttype.ParseLiteral(valueAST)) + } + + // Must be input type (not scalar or enum) + // Silently fail, instead of panic() + return false +} diff --git a/rules/arguments_of_correct_type_test.go b/rules/arguments_of_correct_type_test.go new file mode 100644 index 00000000..792a38a3 --- /dev/null +++ b/rules/arguments_of_correct_type_test.go @@ -0,0 +1,112 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodIntValue(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + intArgField(intArg: 2) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodBooleanValue(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + booleanArgField(booleanArg: true) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodStringValue(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + stringArgField(stringArg: "foo") + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodFloatValue(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + floatArgField(floatArg: 1.1) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidValue_IntIntoFloat(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + floatArgField(floatArg: 1) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidValue_IntIntoID(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + idArgField(idArg: 1) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidValue_StringIntoID(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + idArgField(idArg: "someIdString") + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodEnumValue(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + dog { + doesKnowCommand(dogCommand: SIT) + } + } + `) +} + +func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_IntIntoString(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + stringArgField(stringArg: 1) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "stringArg" expected type "String" but got: 1.`, + 4, 39, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_FloatIntoString(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + stringArgField(stringArg: 1.0) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "stringArg" expected type "String" but got: 1.0.`, + 4, 39, + ), + }) +} diff --git a/rules/harness_test.go b/rules/harness_test.go new file mode 100644 index 00000000..80974041 --- /dev/null +++ b/rules/harness_test.go @@ -0,0 +1,517 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/language/location" + "github.com/graphql-go/graphql/language/parser" + "github.com/graphql-go/graphql/language/source" + "github.com/graphql-go/graphql/testutil" + "reflect" +) + +var beingInterface = graphql.NewInterface(graphql.InterfaceConfig{ + Name: "Being", + Fields: graphql.FieldConfigMap{ + "name": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "surname": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + }, + }, + }, + }, +}) +var petInterface = graphql.NewInterface(graphql.InterfaceConfig{ + Name: "Pet", + Fields: graphql.FieldConfigMap{ + "name": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "surname": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + }, + }, + }, + }, +}) +var dogCommandEnum = graphql.NewEnum(graphql.EnumConfig{ + Name: "DogCommand", + Values: graphql.EnumValueConfigMap{ + "SIT": &graphql.EnumValueConfig{ + Value: 0, + }, + "HEEL": &graphql.EnumValueConfig{ + Value: 1, + }, + "DOWN": &graphql.EnumValueConfig{ + Value: 2, + }, + }, +}) +var dogType = graphql.NewObject(graphql.ObjectConfig{ + Name: "Dog", + IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { + return true + }, + Fields: graphql.FieldConfigMap{ + "name": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "surname": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + }, + }, + }, + "nickname": &graphql.FieldConfig{ + Type: graphql.String, + }, + "barkVolume": &graphql.FieldConfig{ + Type: graphql.Int, + }, + "barks": &graphql.FieldConfig{ + Type: graphql.Boolean, + }, + "doesKnowCommand": &graphql.FieldConfig{ + Type: graphql.Boolean, + Args: graphql.FieldConfigArgument{ + "dogCommand": &graphql.ArgumentConfig{ + Type: dogCommandEnum, + }, + }, + }, + "isHousetrained": &graphql.FieldConfig{ + Type: graphql.Boolean, + Args: graphql.FieldConfigArgument{ + "atOtherHomes": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + DefaultValue: true, + }, + }, + }, + "isAtLocation": &graphql.FieldConfig{ + Type: graphql.Boolean, + Args: graphql.FieldConfigArgument{ + "x": &graphql.ArgumentConfig{ + Type: graphql.Int, + }, + "y": &graphql.ArgumentConfig{ + Type: graphql.Int, + }, + }, + }, + }, + Interfaces: []*graphql.Interface{ + beingInterface, + petInterface, + }, +}) +var furColorEnum = graphql.NewEnum(graphql.EnumConfig{ + Name: "FurColor", + Values: graphql.EnumValueConfigMap{ + "BROWN": &graphql.EnumValueConfig{ + Value: 0, + }, + "BLACK": &graphql.EnumValueConfig{ + Value: 1, + }, + "TAN": &graphql.EnumValueConfig{ + Value: 2, + }, + "SPOTTED": &graphql.EnumValueConfig{ + Value: 3, + }, + }, +}) + +var catType = graphql.NewObject(graphql.ObjectConfig{ + Name: "Cat", + IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { + return true + }, + Fields: graphql.FieldConfigMap{ + "name": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "surname": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + }, + }, + }, + "nickname": &graphql.FieldConfig{ + Type: graphql.String, + }, + "meowVolume": &graphql.FieldConfig{ + Type: graphql.Int, + }, + "meows": &graphql.FieldConfig{ + Type: graphql.Boolean, + }, + "furColor": &graphql.FieldConfig{ + Type: furColorEnum, + }, + }, + Interfaces: []*graphql.Interface{ + beingInterface, + petInterface, + }, +}) +var catOrDogUnion = graphql.NewUnion(graphql.UnionConfig{ + Name: "CatOrDog", + Types: []*graphql.Object{ + dogType, + catType, + }, + ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { + // not used for validation + return nil + }, +}) +var intelligentInterface = graphql.NewInterface(graphql.InterfaceConfig{ + Name: "Intelligent", + Fields: graphql.FieldConfigMap{ + "iq": &graphql.FieldConfig{ + Type: graphql.Int, + }, + }, +}) + +var humanType = graphql.NewObject(graphql.ObjectConfig{ + Name: "Human", + IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { + return true + }, + Interfaces: []*graphql.Interface{ + beingInterface, + intelligentInterface, + }, + Fields: graphql.FieldConfigMap{ + "name": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "surname": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + }, + }, + }, + "pets": &graphql.FieldConfig{ + Type: graphql.NewList(petInterface), + }, + "iq": &graphql.FieldConfig{ + Type: graphql.Int, + }, + // `relatives` field added later in init() + }, +}) + +var alienType = graphql.NewObject(graphql.ObjectConfig{ + Name: "Alien", + IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { + return true + }, + Interfaces: []*graphql.Interface{ + beingInterface, + intelligentInterface, + }, + Fields: graphql.FieldConfigMap{ + "name": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "surname": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + }, + }, + }, + "iq": &graphql.FieldConfig{ + Type: graphql.Int, + }, + "numEyes": &graphql.FieldConfig{ + Type: graphql.Int, + }, + }, +}) +var dogOrHumanUnion = graphql.NewUnion(graphql.UnionConfig{ + Name: "DogOrHuman", + Types: []*graphql.Object{ + dogType, + humanType, + }, + ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { + // not used for validation + return nil + }, +}) +var humanOrAlienUnion = graphql.NewUnion(graphql.UnionConfig{ + Name: "HumanOrAlien", + Types: []*graphql.Object{ + alienType, + humanType, + }, + ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { + // not used for validation + return nil + }, +}) + +var complexInputObject = graphql.NewInputObject(graphql.InputObjectConfig{ + Name: "ComplexInput", + Fields: graphql.InputObjectConfigFieldMap{ + "requiredField": &graphql.InputObjectFieldConfig{ + Type: graphql.NewNonNull(graphql.Boolean), + }, + "intField": &graphql.InputObjectFieldConfig{ + Type: graphql.Int, + }, + "stringField": &graphql.InputObjectFieldConfig{ + Type: graphql.String, + }, + "booleanField": &graphql.InputObjectFieldConfig{ + Type: graphql.Boolean, + }, + "stringListField": &graphql.InputObjectFieldConfig{ + Type: graphql.NewList(graphql.String), + }, + }, +}) +var complicatedArgs = graphql.NewObject(graphql.ObjectConfig{ + Name: "ComplicatedArgs", + // TODO List + // TODO Coercion + // TODO NotNulls + Fields: graphql.FieldConfigMap{ + "intArgField": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "intArg": &graphql.ArgumentConfig{ + Type: graphql.Int, + }, + }, + }, + "nonNullIntArgField": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "nonNullIntArg": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.Int), + }, + }, + }, + "stringArgField": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "stringArg": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + }, + }, + "booleanArgField": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "booleanArg": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + }, + }, + }, + "enumArgField": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "enumArg": &graphql.ArgumentConfig{ + Type: furColorEnum, + }, + }, + }, + "floatArgField": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "floatArg": &graphql.ArgumentConfig{ + Type: graphql.Float, + }, + }, + }, + "idArgField": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "idArg": &graphql.ArgumentConfig{ + Type: graphql.ID, + }, + }, + }, + "stringListArgField": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "stringListArg": &graphql.ArgumentConfig{ + Type: graphql.NewList(graphql.String), + }, + }, + }, + "complexArgField": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "complexArg": &graphql.ArgumentConfig{ + Type: complexInputObject, + }, + }, + }, + "multipleReqs": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "req1": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.Int), + }, + "req2": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.Int), + }, + }, + }, + "multipleOpts": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "opt1": &graphql.ArgumentConfig{ + Type: graphql.Int, + DefaultValue: 0, + }, + "opt2": &graphql.ArgumentConfig{ + Type: graphql.Int, + DefaultValue: 0, + }, + }, + }, + "multipleOptAndReq": &graphql.FieldConfig{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "req1": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.Int), + }, + "req2": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.Int), + }, + "opt1": &graphql.ArgumentConfig{ + Type: graphql.Int, + DefaultValue: 0, + }, + "opt2": &graphql.ArgumentConfig{ + Type: graphql.Int, + DefaultValue: 0, + }, + }, + }, + }, +}) +var queryRoot *graphql.Object +var defaultSchema *graphql.Schema + +func init() { + + humanType.AddFieldConfig("relatives", &graphql.FieldConfig{ + Type: graphql.NewList(humanType), + }) + queryRoot = graphql.NewObject(graphql.ObjectConfig{ + Name: "QueryRoot", + Fields: graphql.FieldConfigMap{ + "human": &graphql.FieldConfig{ + Args: graphql.FieldConfigArgument{ + "id": &graphql.ArgumentConfig{ + Type: graphql.ID, + }, + }, + Type: humanType, + }, + "alien": &graphql.FieldConfig{ + Type: alienType, + }, + "dog": &graphql.FieldConfig{ + Type: dogType, + }, + "cat": &graphql.FieldConfig{ + Type: catType, + }, + "pet": &graphql.FieldConfig{ + Type: petInterface, + }, + "catOrDog": &graphql.FieldConfig{ + Type: catOrDogUnion, + }, + "dogOrHuman": &graphql.FieldConfig{ + Type: dogOrHumanUnion, + }, + "humanOrAlien": &graphql.FieldConfig{ + Type: humanOrAlienUnion, + }, + "complicatedArgs": &graphql.FieldConfig{ + Type: complicatedArgs, + }, + }, + }) + schema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: queryRoot, + }) + if err != nil { + panic(err) + } + defaultSchema = &schema + +} +func expectValid(t *testing.T, schema *graphql.Schema, rules []graphql.ValidationRuleFn, queryString string) { + source := source.NewSource(&source.Source{ + Body: queryString, + }) + AST, err := parser.Parse(parser.ParseParams{Source: source}) + if err != nil { + t.Fatal(err) + } + result := graphql.ValidateDocument(schema, AST, rules) + if len(result.Errors) > 0 { + t.Fatalf("Should validate, got %v", result.Errors) + } + if result.IsValid != true { + t.Fatalf("IsValid should be true, got %v", result.IsValid) + } + +} +func expectInvalid(t *testing.T, schema *graphql.Schema, rules []graphql.ValidationRuleFn, queryString string, expectedErrors []gqlerrors.FormattedError) { + source := source.NewSource(&source.Source{ + Body: queryString, + }) + AST, err := parser.Parse(parser.ParseParams{Source: source}) + if err != nil { + t.Fatal(err) + } + result := graphql.ValidateDocument(schema, AST, rules) + if len(result.Errors) != len(expectedErrors) { + t.Fatalf("Should have %v errors, got %v", len(expectedErrors), len(result.Errors)) + } + if result.IsValid != false { + t.Fatalf("IsValid should be false, got %v", result.IsValid) + } + if !reflect.DeepEqual(expectedErrors, result.Errors) { + t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expectedErrors, result.Errors)) + } + +} +func expectPassesRule(t *testing.T, rule graphql.ValidationRuleFn, queryString string) { + expectValid(t, defaultSchema, []graphql.ValidationRuleFn{rule}, queryString) +} +func expectFailsRule(t *testing.T, rule graphql.ValidationRuleFn, queryString string, expectedErrors []gqlerrors.FormattedError) { + expectInvalid(t, defaultSchema, []graphql.ValidationRuleFn{rule}, queryString, expectedErrors) +} + +func ruleError(message string, locs ...int) gqlerrors.FormattedError { + locations := []location.SourceLocation{} + for i := 0; i < len(locs); i = i + 2 { + line := locs[i] + col := 0 + if i+1 < len(locs) { + col = locs[i+1] + } + locations = append(locations, location.SourceLocation{ + Line: line, + Column: col, + }) + } + return gqlerrors.FormattedError{ + Message: message, + Locations: locations, + } +} diff --git a/rules/known_type_names_test.go b/rules/known_type_names_test.go new file mode 100644 index 00000000..8c5a1a64 --- /dev/null +++ b/rules/known_type_names_test.go @@ -0,0 +1,47 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_KnownTypeNames_KnownTypeNamesAreValid(t *testing.T) { + expectPassesRule(t, graphql.KnownTypeNamesRule, ` + query Foo($var: String, $required: [String!]!) { + user(id: 4) { + pets { ... on Pet { name }, ...PetFields } + } + } + fragment PetFields on Pet { + name + } + `) +} +func TestValidate_KnownTypeNames_UnknownTypeNamesAreInValid(t *testing.T) { + expectFailsRule(t, graphql.KnownTypeNamesRule, ` + query Foo($var: JumbledUpLetters) { + user(id: 4) { + name + pets { ... on Badger { name }, ...PetFields } + } + } + fragment PetFields on Peettt { + name + } + `, []gqlerrors.FormattedError{ + ruleError( + `Unknown type "JumbledUpLetters".`, + 2, 23, + ), + ruleError( + `Unknown type "Badger".`, + 5, 25, + ), + ruleError( + `Unknown type "Peettt".`, + 8, 29, + ), + }) +} diff --git a/schema.go b/schema.go index dad5ebd6..44182001 100644 --- a/schema.go +++ b/schema.go @@ -104,6 +104,15 @@ func (gq *Schema) GetDirectives() []*Directive { return gq.directives } +func (gq *Schema) GetDirective(name string) *Directive { + for _, directive := range gq.GetDirectives() { + if directive.Name == name { + return directive + } + } + return nil +} + func (gq *Schema) GetTypeMap() TypeMap { return gq.typeMap } diff --git a/type_info.go b/type_info.go new file mode 100644 index 00000000..9a95a529 --- /dev/null +++ b/type_info.go @@ -0,0 +1,235 @@ +package graphql + +import ( + "github.com/graphql-go/graphql/language/ast" + "github.com/graphql-go/graphql/language/kinds" +) + +// TODO: can move TypeInfo to a utils package if there ever is one +/** + * TypeInfo is a utility class which, given a GraphQL schema, can keep track + * of the current field and type definitions at any point in a GraphQL document + * AST during a recursive descent by calling `enter(node)` and `leave(node)`. + */ +type TypeInfo struct { + schema *Schema + typeStack []Output + parentTypeStack []Composite + inputTypeStack []Input + fieldDefStack []*FieldDefinition + directive *Directive + argument *Argument +} + +func NewTypeInfo(schema *Schema) *TypeInfo { + return &TypeInfo{ + schema: schema, + } +} + +func (ti *TypeInfo) GetType() Output { + if len(ti.typeStack) > 0 { + return ti.typeStack[len(ti.typeStack)-1] + } + return nil +} + +func (ti *TypeInfo) GetParentType() Composite { + if len(ti.parentTypeStack) > 0 { + return ti.parentTypeStack[len(ti.parentTypeStack)-1] + } + return nil +} + +func (ti *TypeInfo) GetInputType() Input { + if len(ti.inputTypeStack) > 0 { + return ti.inputTypeStack[len(ti.inputTypeStack)-1] + } + return nil +} +func (ti *TypeInfo) GetFieldDef() *FieldDefinition { + if len(ti.fieldDefStack) > 0 { + return ti.fieldDefStack[len(ti.fieldDefStack)-1] + } + return nil +} + +func (ti *TypeInfo) GetDirective() *Directive { + return ti.directive +} + +func (ti *TypeInfo) GetArgument() *Argument { + return ti.argument +} + +func (ti *TypeInfo) Enter(node ast.Node) { + + schema := ti.schema + var ttype Type + switch node := node.(type) { + case *ast.SelectionSet: + namedType := GetNamed(ti.GetType()) + var compositeType Composite = nil + if IsCompositeType(namedType) { + compositeType, _ = namedType.(Composite) + } + ti.parentTypeStack = append(ti.parentTypeStack, compositeType) + case *ast.Field: + parentType := ti.GetParentType() + var fieldDef *FieldDefinition + if parentType != nil { + fieldDef = getTypeInfoFieldDef(*schema, parentType.(Type), node) + } + ti.fieldDefStack = append(ti.fieldDefStack, fieldDef) + if fieldDef != nil { + ti.typeStack = append(ti.typeStack, fieldDef.Type) + } else { + ti.typeStack = append(ti.typeStack, nil) + } + case *ast.Directive: + nameVal := "" + if node.Name != nil { + nameVal = node.Name.Value + } + ti.directive = schema.GetDirective(nameVal) + case *ast.OperationDefinition: + if node.Operation == "query" { + ttype = schema.GetQueryType() + } else if node.Operation == "mutation" { + ttype = schema.GetMutationType() + } + ti.typeStack = append(ti.typeStack, ttype) + case *ast.InlineFragment: + ttype, _ = typeFromAST(*schema, node.TypeCondition) + ti.typeStack = append(ti.typeStack, ttype) + case *ast.FragmentDefinition: + ttype, _ = typeFromAST(*schema, node.TypeCondition) + ti.typeStack = append(ti.typeStack, ttype) + case *ast.VariableDefinition: + ttype, _ = typeFromAST(*schema, node.Type) + ti.inputTypeStack = append(ti.inputTypeStack, ttype) + case *ast.Argument: + nameVal := "" + if node.Name != nil { + nameVal = node.Name.Value + } + var argType Input + var argDef *Argument + directive := ti.GetDirective() + fieldDef := ti.GetFieldDef() + if directive != nil { + for _, arg := range directive.Args { + if arg.Name == nameVal { + argDef = arg + } + } + } else if fieldDef != nil { + for _, arg := range fieldDef.Args { + if arg.Name == nameVal { + argDef = arg + } + } + } + if argDef != nil { + argType = argDef.Type + } + ti.argument = argDef + ti.inputTypeStack = append(ti.inputTypeStack, argType) + case *ast.ListValue: + listType := GetNullable(ti.GetInputType()) + if list, ok := listType.(*List); ok { + ti.inputTypeStack = append(ti.inputTypeStack, list.OfType) + } else { + ti.inputTypeStack = append(ti.inputTypeStack, nil) + } + case *ast.ObjectField: + var fieldType Input + objectType := GetNamed(ti.GetInputType()) + + if objectType, ok := objectType.(*InputObject); ok { + nameVal := "" + if node.Name != nil { + nameVal = node.Name.Value + } + if inputField, ok := objectType.GetFields()[nameVal]; ok { + fieldType = inputField.Type + } + } + ti.inputTypeStack = append(ti.inputTypeStack, fieldType) + } +} +func (ti *TypeInfo) Leave(node ast.Node) { + kind := node.GetKind() + switch kind { + case kinds.SelectionSet: + // pop ti.parentTypeStack + _, ti.parentTypeStack = ti.parentTypeStack[len(ti.parentTypeStack)-1], ti.parentTypeStack[:len(ti.parentTypeStack)-1] + case kinds.Field: + // pop ti.fieldDefStack + _, ti.fieldDefStack = ti.fieldDefStack[len(ti.fieldDefStack)-1], ti.fieldDefStack[:len(ti.fieldDefStack)-1] + // pop ti.typeStack + _, ti.typeStack = ti.typeStack[len(ti.typeStack)-1], ti.typeStack[:len(ti.typeStack)-1] + case kinds.Directive: + ti.directive = nil + case kinds.OperationDefinition: + fallthrough + case kinds.InlineFragment: + fallthrough + case kinds.FragmentDefinition: + // pop ti.typeStack + _, ti.typeStack = ti.typeStack[len(ti.typeStack)-1], ti.typeStack[:len(ti.typeStack)-1] + case kinds.VariableDefinition: + // pop ti.inputTypeStack + _, ti.inputTypeStack = ti.inputTypeStack[len(ti.inputTypeStack)-1], ti.inputTypeStack[:len(ti.inputTypeStack)-1] + case kinds.Argument: + ti.argument = nil + // pop ti.inputTypeStack + _, ti.inputTypeStack = ti.inputTypeStack[len(ti.inputTypeStack)-1], ti.inputTypeStack[:len(ti.inputTypeStack)-1] + case kinds.ListValue: + fallthrough + case kinds.ObjectField: + // pop ti.inputTypeStack + _, ti.inputTypeStack = ti.inputTypeStack[len(ti.inputTypeStack)-1], ti.inputTypeStack[:len(ti.inputTypeStack)-1] + } +} + +/** + * Not exactly the same as the executor's definition of getFieldDef, in this + * statically evaluated environment we do not always have an Object type, + * and need to handle Interface and Union types. + */ +func getTypeInfoFieldDef(schema Schema, parentType Type, fieldAST *ast.Field) *FieldDefinition { + name := "" + if fieldAST.Name != nil { + name = fieldAST.Name.Value + } + if name == SchemaMetaFieldDef.Name && + schema.GetQueryType() == parentType { + return SchemaMetaFieldDef + } + if name == TypeMetaFieldDef.Name && + schema.GetQueryType() == parentType { + return TypeMetaFieldDef + } + if name == TypeNameMetaFieldDef.Name { + if _, ok := parentType.(*Object); ok { + return TypeNameMetaFieldDef + } + if _, ok := parentType.(*Interface); ok { + return TypeNameMetaFieldDef + } + if _, ok := parentType.(*Union); ok { + return TypeNameMetaFieldDef + } + } + + if parentType, ok := parentType.(*Object); ok { + field, _ := parentType.GetFields()[name] + return field + } + if parentType, ok := parentType.(*Interface); ok { + field, _ := parentType.GetFields()[name] + return field + } + return nil +} diff --git a/validator.go b/validator.go index 3d1a8e72..2490f7bc 100644 --- a/validator.go +++ b/validator.go @@ -3,6 +3,8 @@ package graphql import ( "github.com/graphql-go/graphql/gqlerrors" "github.com/graphql-go/graphql/language/ast" + "github.com/graphql-go/graphql/language/kinds" + "github.com/graphql-go/graphql/language/visitor" ) type ValidationResult struct { @@ -10,7 +12,192 @@ type ValidationResult struct { Errors []gqlerrors.FormattedError } -func ValidateDocument(schema Schema, ast *ast.Document) (vr ValidationResult) { - vr.IsValid = true +func ValidateDocument(schema *Schema, astDoc *ast.Document, rules []ValidationRuleFn) (vr ValidationResult) { + if len(rules) == 0 { + rules = SpecifiedRules + } + + vr.IsValid = false + if schema == nil { + vr.Errors = append(vr.Errors, gqlerrors.NewFormattedError("Must provide schema")) + return vr + } + if astDoc == nil { + vr.Errors = append(vr.Errors, gqlerrors.NewFormattedError("Must provide document")) + return vr + } + vr.Errors = visitUsingRules(schema, astDoc, rules) + if len(vr.Errors) == 0 { + vr.IsValid = true + } return vr } + +func visitUsingRules(schema *Schema, astDoc *ast.Document, rules []ValidationRuleFn) (errors []gqlerrors.FormattedError) { + typeInfo := NewTypeInfo(schema) + context := NewValidationContext(schema, astDoc, typeInfo) + + var visitInstance func(astNode ast.Node, instance *ValidationRuleInstance) + + visitInstance = func(astNode ast.Node, instance *ValidationRuleInstance) { + visitor.Visit(astNode, &visitor.VisitorOptions{ + Enter: func(p visitor.VisitFuncParams) (string, interface{}) { + var action = visitor.ActionNoChange + var result interface{} + switch node := p.Node.(type) { + case ast.Node: + // Collect type information about the current position in the AST. + typeInfo.Enter(node) + + // Do not visit top level fragment definitions if this instance will + // visit those fragments inline because it + // provided `visitSpreadFragments`. + kind := node.GetKind() + + if kind == kinds.FragmentDefinition && + p.Key != nil && instance.VisitSpreadFragments == true { + return visitor.ActionSkip, nil + } + + // Get the visitor function from the validation instance, and if it + // exists, call it with the visitor arguments. + enterFn := visitor.GetVisitFn(instance.VisitorOpts, false, kind) + if enterFn != nil { + action, result = enterFn(p) + } + + // If the visitor returned an error, log it and do not visit any + // deeper nodes. + if err, ok := result.(error); ok && err != nil { + errors = append(errors, gqlerrors.FormatError(err)) + action = visitor.ActionSkip + } + + // If any validation instances provide the flag `visitSpreadFragments` + // and this node is a fragment spread, visit the fragment definition + // from this point. + if result == nil && instance.VisitSpreadFragments == true && kind == kinds.FragmentSpread { + node, _ := node.(*ast.FragmentSpread) + name := node.Name + nameVal := "" + if name != nil { + nameVal = name.Value + } + fragment := context.GetFragment(nameVal) + if fragment != nil { + visitInstance(fragment, instance) + } + } + + // If the result is "false" (ie action === Action.Skip, we're not visiting any descendent nodes, + // but need to update typeInfo. + if action == visitor.ActionSkip { + typeInfo.Leave(node) + } + + } + + return action, result + }, + Leave: func(p visitor.VisitFuncParams) (string, interface{}) { + var action = visitor.ActionNoChange + var result interface{} + switch node := p.Node.(type) { + case ast.Node: + kind := node.GetKind() + + // Get the visitor function from the validation instance, and if it + // exists, call it with the visitor arguments. + leaveFn := visitor.GetVisitFn(instance.VisitorOpts, true, kind) + if leaveFn != nil { + action, result = leaveFn(p) + } + + // If the visitor returned an error, log it and do not visit any + // deeper nodes. + if err, ok := result.(error); ok && err != nil { + errors = append(errors, gqlerrors.FormatError(err)) + action = visitor.ActionSkip + } + + // Update typeInfo. + typeInfo.Leave(node) + } + return action, result + }, + }, nil) + } + + instances := []*ValidationRuleInstance{} + for _, rule := range rules { + instance := rule(context) + instances = append(instances, instance) + } + for _, instance := range instances { + visitInstance(astDoc, instance) + } + return errors +} + +type ValidationContext struct { + schema *Schema + astDoc *ast.Document + typeInfo *TypeInfo + fragments map[string]*ast.FragmentDefinition +} + +func NewValidationContext(schema *Schema, astDoc *ast.Document, typeInfo *TypeInfo) *ValidationContext { + return &ValidationContext{ + schema: schema, + astDoc: astDoc, + typeInfo: typeInfo, + } +} + +func (ctx *ValidationContext) GetSchema() *Schema { + return ctx.schema +} +func (ctx *ValidationContext) GetDocument() *ast.Document { + return ctx.astDoc +} + +func (ctx *ValidationContext) GetFragment(name string) *ast.FragmentDefinition { + if len(ctx.fragments) == 0 { + if ctx.GetDocument() == nil { + return nil + } + defs := ctx.GetDocument().Definitions + fragments := map[string]*ast.FragmentDefinition{} + for _, def := range defs { + if def, ok := def.(*ast.FragmentDefinition); ok { + name := "" + if def.Name != nil { + name = def.Name.Value + } + fragments[name] = def + } + } + ctx.fragments = fragments + } + f, _ := ctx.fragments[name] + return f +} + +func (ctx *ValidationContext) GetType() Output { + return ctx.typeInfo.GetType() +} +func (ctx *ValidationContext) GetParentType() Composite { + return ctx.typeInfo.GetParentType() +} +func (ctx *ValidationContext) GetInputType() Input { + return ctx.typeInfo.GetInputType() +} +func (ctx *ValidationContext) GetFieldDef() *FieldDefinition { + return ctx.typeInfo.GetFieldDef() +} +func (ctx *ValidationContext) GetDirective() *Directive { + return ctx.typeInfo.GetDirective() +} +func (ctx *ValidationContext) GetArgument() *Argument { + return ctx.typeInfo.GetArgument() +} From ba98d9bcd5f6351d2b8c99f3767e1b87ab90578f Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Mon, 9 Nov 2015 18:03:02 +0800 Subject: [PATCH 12/41] Fix travis error - Add an empty package --- rules/rules.go | 1 + 1 file changed, 1 insertion(+) create mode 100644 rules/rules.go diff --git a/rules/rules.go b/rules/rules.go new file mode 100644 index 00000000..1e8c7fa0 --- /dev/null +++ b/rules/rules.go @@ -0,0 +1 @@ +package rules From b4a10dec637a0140a510f2082fb53566150f9b7b Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Tue, 10 Nov 2015 02:09:55 +0800 Subject: [PATCH 13/41] Completed port of tests for `ArgumentsOfCorrectTypeRule` - All tests passed - Update `ParseLiteral` funcs for built-in `scalars` to return nil for incorrect types. - Will be used by `validator` to raise errors arg values of incorrect types ``` ok github.com/graphql-go/graphql 0.195s ? github.com/graphql-go/graphql/examples/hello-world [no test files] ? github.com/graphql-go/graphql/examples/http [no test files] ? github.com/graphql-go/graphql/gqlerrors [no test files] ? github.com/graphql-go/graphql/language/ast [no test files] ? github.com/graphql-go/graphql/language/kinds [no test files] ok github.com/graphql-go/graphql/language/lexer 0.012s ? github.com/graphql-go/graphql/language/location [no test files] ok github.com/graphql-go/graphql/language/parser 0.031s ok github.com/graphql-go/graphql/language/printer 0.081s ? github.com/graphql-go/graphql/language/source [no test files] ok github.com/graphql-go/graphql/language/visitor 0.014s ok github.com/graphql-go/graphql/rules 0.080s ok github.com/graphql-go/graphql/testutil 0.016s ``` --- language/visitor/visitor.go | 2 - rules.go | 23 +- rules/arguments_of_correct_type_test.go | 625 ++++++++++++++++++++++++ scalars.go | 8 +- 4 files changed, 645 insertions(+), 13 deletions(-) diff --git a/language/visitor/visitor.go b/language/visitor/visitor.go index 21b54952..f0f9d37c 100644 --- a/language/visitor/visitor.go +++ b/language/visitor/visitor.go @@ -726,7 +726,6 @@ func GetVisitFn(visitorOpts *VisitorOptions, isLeaving bool, kind string) VisitF // { Kind: { enter() {} } } return kindVisitor.Enter } - return nil } if isLeaving { @@ -753,5 +752,4 @@ func GetVisitFn(visitorOpts *VisitorOptions, isLeaving bool, kind string) VisitF } return nil } - return nil } diff --git a/rules.go b/rules.go index d1156cce..e940f79e 100644 --- a/rules.go +++ b/rules.go @@ -36,9 +36,8 @@ func ArgumentsOfCorrectTypeRule(context *ValidationContext) *ValidationRuleInsta argDef := context.GetArgument() if argDef != nil && !isValidLiteralValue(argDef.Type, value) { argNameValue := "" - argName := argAST.Name - if argName != nil { - argNameValue = argName.Value + if argAST.Name != nil { + argNameValue = argAST.Name.Value } // TODO: helper to construct gqlerror with message + []ast.Node return visitor.ActionNoChange, gqlerrors.NewError( @@ -146,22 +145,32 @@ func isValidLiteralValue(ttype Input, valueAST ast.Value) bool { // Ensure every provided field is defined. // Ensure every defined field is valid. fieldASTs := valueAST.Fields + fieldASTMap := map[string]*ast.ObjectField{} for _, fieldAST := range fieldASTs { fieldASTName := "" if fieldAST.Name != nil { fieldASTName = fieldAST.Name.Value } + + fieldASTMap[fieldASTName] = fieldAST + + // check if field is defined field, ok := fields[fieldASTName] - if !ok { + if !ok || field == nil { return false } - if fieldAST == nil { - return false + } + for fieldName, field := range fields { + fieldAST, _ := fieldASTMap[fieldName] + var fieldASTValue ast.Value + if fieldAST != nil { + fieldASTValue = fieldAST.Value } - if !isValidLiteralValue(field.Type, fieldAST.Value) { + if !isValidLiteralValue(field.Type, fieldASTValue) { return false } } + return true } if ttype, ok := ttype.(*Scalar); ok { diff --git a/rules/arguments_of_correct_type_test.go b/rules/arguments_of_correct_type_test.go index 792a38a3..14102946 100644 --- a/rules/arguments_of_correct_type_test.go +++ b/rules/arguments_of_correct_type_test.go @@ -110,3 +110,628 @@ func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_FloatIntoString(t * ), }) } +func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_BooleanIntoString(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + stringArgField(stringArg: true) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "stringArg" expected type "String" but got: true.`, + 4, 39, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_UnquotedStringIntoString(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + stringArgField(stringArg: BAR) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "stringArg" expected type "String" but got: BAR.`, + 4, 39, + ), + }) +} + +func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_BigIntIntoInt(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + intArgField(intArg: 829384293849283498239482938) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "intArg" expected type "Int" but got: 829384293849283498239482938.`, + 4, 33, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_UnquotedStringIntoInt(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + intArgField(intArg: FOO) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "intArg" expected type "Int" but got: FOO.`, + 4, 33, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_SimpleFloatIntoInt(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + intArgField(intArg: 3.0) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "intArg" expected type "Int" but got: 3.0.`, + 4, 33, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_FloatIntoInt(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + intArgField(intArg: 3.333) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "intArg" expected type "Int" but got: 3.333.`, + 4, 33, + ), + }) +} + +func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_IntIntoBoolean(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + booleanArgField(booleanArg: 2) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "booleanArg" expected type "Boolean" but got: 2.`, + 4, 41, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_FloatIntoBoolean(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + booleanArgField(booleanArg: 1.0) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "booleanArg" expected type "Boolean" but got: 1.0.`, + 4, 41, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_StringIntoBoolean(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + booleanArgField(booleanArg: "true") + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "booleanArg" expected type "Boolean" but got: "true".`, + 4, 41, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_UnquotedStringIntoBoolean(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + booleanArgField(booleanArg: TRUE) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "booleanArg" expected type "Boolean" but got: TRUE.`, + 4, 41, + ), + }) +} + +func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_FloatIntoID(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + idArgField(idArg: 1.0) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "idArg" expected type "ID" but got: 1.0.`, + 4, 31, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_BooleanIntoID(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + idArgField(idArg: true) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "idArg" expected type "ID" but got: true.`, + 4, 31, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_UnquotedIntoID(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + idArgField(idArg: SOMETHING) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "idArg" expected type "ID" but got: SOMETHING.`, + 4, 31, + ), + }) +} + +func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_IntIntoEnum(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + dog { + doesKnowCommand(dogCommand: 2) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "dogCommand" expected type "DogCommand" but got: 2.`, + 4, 41, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_FloatIntoEnum(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + dog { + doesKnowCommand(dogCommand: 1.0) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "dogCommand" expected type "DogCommand" but got: 1.0.`, + 4, 41, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_StringIntoEnum(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + dog { + doesKnowCommand(dogCommand: "SIT") + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "dogCommand" expected type "DogCommand" but got: "SIT".`, + 4, 41, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_BooleanIntoEnum(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + dog { + doesKnowCommand(dogCommand: true) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "dogCommand" expected type "DogCommand" but got: true.`, + 4, 41, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_UnknownEnumValueIntoEnum(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + dog { + doesKnowCommand(dogCommand: JUGGLE) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "dogCommand" expected type "DogCommand" but got: JUGGLE.`, + 4, 41, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_DifferentCaseEnumValueIntoEnum(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + dog { + doesKnowCommand(dogCommand: sit) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "dogCommand" expected type "DogCommand" but got: sit.`, + 4, 41, + ), + }) +} + +func TestValidate_ArgValuesOfCorrectType_ValidListValue_GoodListValue(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + stringListArgField(stringListArg: ["one", "two"]) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidListValue_EmptyListValue(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + stringListArgField(stringListArg: []) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidListValue_SingleValueIntoList(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + stringListArgField(stringListArg: "one") + } + } + `) +} + +func TestValidate_ArgValuesOfCorrectType_InvalidListValue_IncorrectItemType(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + stringListArgField(stringListArg: ["one", 2]) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "stringListArg" expected type "[String]" but got: ["one", 2].`, + 4, 47, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidListValue_SingleValueOfIncorrentType(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + stringListArgField(stringListArg: 1) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "stringListArg" expected type "[String]" but got: 1.`, + 4, 47, + ), + }) +} + +func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_ArgOnOptionalArg(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + dog { + isHousetrained(atOtherHomes: true) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_NoArgOnOptionalArg(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + dog { + isHousetrained + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_MultipleArgs(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + multipleReqs(req1: 1, req2: 2) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_MultipleArgsReverseOrder(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + multipleReqs(req2: 2, req1: 1) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_NoArgsOnMultipleOptional(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + multipleOpts + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_OneArgOnMultipleOptional(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + multipleOpts(opt1: 1) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_SecondArgOnMultipleOptional(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + multipleOpts(opt2: 1) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_MultipleRequiredsOnMixedList(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + multipleOptAndReq(req1: 3, req2: 4) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_MultipleRequiredsAndOptionalOnMixedList(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + multipleOptAndReq(req1: 3, req2: 4, opt1: 5) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_AllRequiredsAndOptionalOnMixedList(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) + } + } + `) +} + +func TestValidate_ArgValuesOfCorrectType_InvalidNonNullableValue_IncorrectValueType(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + multipleReqs(req2: "two", req1: "one") + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "req2" expected type "Int!" but got: "two".`, + 4, 32, + ), + ruleError( + `Argument "req1" expected type "Int!" but got: "one".`, + 4, 45, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidNonNullableValue_IncorrectValueAndMissingArgument(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + multipleReqs(req1: "one") + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "req1" expected type "Int!" but got: "one".`, + 4, 32, + ), + }) +} + +func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_OptionalArg_DespiteRequiredFieldInType(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + complexArgField + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_PartialObject_OnlyRequired(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + complexArgField(complexArg: { requiredField: true }) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_PartialObject_RequiredFieldCanBeFalsey(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + complexArgField(complexArg: { requiredField: false }) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_PartialObject_IncludingRequired(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + complexArgField(complexArg: { requiredField: false }) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_FullObject(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + complexArgField(complexArg: { + requiredField: true, + intField: 4, + stringField: "foo", + booleanField: false, + stringListField: ["one", "two"] + }) + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_FullObject_WithFieldsInDifferentOrder(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + complexArgField(complexArg: { + stringListField: ["one", "two"], + booleanField: false, + requiredField: true, + stringField: "foo", + intField: 4, + }) + } + } + `) +} + +func TestValidate_ArgValuesOfCorrectType_InvalidInputObjectValue_PartialObject_MissingRequired(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + complexArgField(complexArg: { intField: 4 }) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "complexArg" expected type "ComplexInput" but got: {intField: 4}.`, + 4, 41, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidInputObjectValue_PartialObject_InvalidFieldType(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + complexArgField(complexArg: { + stringListField: ["one", 2], + requiredField: true, + }) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "complexArg" expected type "ComplexInput" but got: {stringListField: ["one", 2], requiredField: true}.`, + 4, 41, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidInputObjectValue_PartialObject_UnknownFieldArg(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + complexArgField(complexArg: { + requiredField: true, + unknownField: "value" + }) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "complexArg" expected type "ComplexInput" but got: {requiredField: true, unknownField: "value"}.`, + 4, 41, + ), + }) +} + +func TestValidate_ArgValuesOfCorrectType_DirectiveArguments_WithDirectivesOfValidType(t *testing.T) { + expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + dog @include(if: true) { + name + } + human @skip(if: false) { + name + } + } + `) +} +func TestValidate_ArgValuesOfCorrectType_DirectiveArguments_WithDirectivesWithIncorrectTypes(t *testing.T) { + expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + dog @include(if: "yes") { + name @skip(if: ENUM) + } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Argument "if" expected type "Boolean!" but got: "yes".`, + 3, 28, + ), + ruleError( + `Argument "if" expected type "Boolean!" but got: ENUM.`, + 4, 28, + ), + }) +} diff --git a/scalars.go b/scalars.go index 78505db6..7d22a456 100644 --- a/scalars.go +++ b/scalars.go @@ -98,7 +98,7 @@ var Float *Scalar = NewScalar(ScalarConfig{ return floatValue } } - return float32(0) + return nil }, }) @@ -115,7 +115,7 @@ var String *Scalar = NewScalar(ScalarConfig{ case *ast.StringValue: return valueAST.Value } - return "" + return nil }, }) @@ -157,7 +157,7 @@ var Boolean *Scalar = NewScalar(ScalarConfig{ case *ast.BooleanValue: return valueAST.Value } - return false + return nil }, }) @@ -172,6 +172,6 @@ var ID *Scalar = NewScalar(ScalarConfig{ case *ast.StringValue: return valueAST.Value } - return "" + return nil }, }) From e82559d6c6020914e2c6a097d0bd2f3bf976d214 Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Tue, 10 Nov 2015 14:19:04 +0800 Subject: [PATCH 14/41] Implemented `DefaultValuesOfCorrectTypeRule` and tested --- rules.go | 46 +++++++++- rules/default_values_of_correct_type_test.go | 92 ++++++++++++++++++++ 2 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 rules/default_values_of_correct_type_test.go diff --git a/rules.go b/rules.go index e940f79e..2267c14a 100644 --- a/rules.go +++ b/rules.go @@ -15,13 +15,13 @@ import ( var SpecifiedRules = []ValidationRuleFn{ ArgumentsOfCorrectTypeRule, KnownTypeNamesRule, + DefaultValuesOfCorrectTypeRule, } type ValidationRuleInstance struct { VisitorOpts *visitor.VisitorOptions VisitSpreadFragments bool } - type ValidationRuleFn func(context *ValidationContext) *ValidationRuleInstance func ArgumentsOfCorrectTypeRule(context *ValidationContext) *ValidationRuleInstance { @@ -59,7 +59,51 @@ func ArgumentsOfCorrectTypeRule(context *ValidationContext) *ValidationRuleInsta VisitorOpts: visitorOpts, } } +func DefaultValuesOfCorrectTypeRule(context *ValidationContext) *ValidationRuleInstance { + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.VariableDefinition: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + var action = visitor.ActionNoChange + var result interface{} + if varDefAST, ok := p.Node.(*ast.VariableDefinition); ok { + name := "" + if varDefAST.Variable != nil && varDefAST.Variable.Name != nil { + name = varDefAST.Variable.Name.Value + } + defaultValue := varDefAST.DefaultValue + ttype := context.GetInputType() + if ttype, ok := ttype.(*NonNull); ok && defaultValue != nil { + return visitor.ActionNoChange, gqlerrors.NewError( + fmt.Sprintf(`Variable "$%v" of type "%v" is required and will not use the default value. Perhaps you meant to use type "%v".`, + name, ttype, ttype.OfType), + []ast.Node{defaultValue}, + "", + nil, + []int{}, + ) + } + if ttype != nil && defaultValue != nil && !isValidLiteralValue(ttype, defaultValue) { + return visitor.ActionNoChange, gqlerrors.NewError( + fmt.Sprintf(`Variable "$%v" of type "%v" has invalid default value: %v.`, + name, ttype, printer.Print(defaultValue)), + []ast.Node{defaultValue}, + "", + nil, + []int{}, + ) + } + } + return action, result + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} func KnownTypeNamesRule(context *ValidationContext) *ValidationRuleInstance { visitorOpts := &visitor.VisitorOptions{ KindFuncMap: map[string]visitor.NamedVisitFuncs{ diff --git a/rules/default_values_of_correct_type_test.go b/rules/default_values_of_correct_type_test.go new file mode 100644 index 00000000..201a6b44 --- /dev/null +++ b/rules/default_values_of_correct_type_test.go @@ -0,0 +1,92 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_VariableDefaultValuesOfCorrectType_VariablesWithNoDefaultValues(t *testing.T) { + expectPassesRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` + query NullableValues($a: Int, $b: String, $c: ComplexInput) { + dog { name } + } + `) +} +func TestValidate_VariableDefaultValuesOfCorrectType_RequiredVariablesWithoutDefaultValues(t *testing.T) { + expectPassesRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` + query RequiredValues($a: Int!, $b: String!) { + dog { name } + } + `) +} +func TestValidate_VariableDefaultValuesOfCorrectType_VariablesWithValidDefaultValues(t *testing.T) { + expectPassesRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` + query WithDefaultValues( + $a: Int = 1, + $b: String = "ok", + $c: ComplexInput = { requiredField: true, intField: 3 } + ) { + dog { name } + } + `) +} + +func TestValidate_VariableDefaultValuesOfCorrectType_NoRequiredVariablesWithDefaultValues(t *testing.T) { + expectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` + query UnreachableDefaultValues($a: Int! = 3, $b: String! = "default") { + dog { name } + } + `, + []gqlerrors.FormattedError{ + ruleError( + `Variable "$a" of type "Int!" is required and will not `+ + `use the default value. Perhaps you meant to use type "Int".`, + 2, 49, + ), + ruleError( + `Variable "$b" of type "String!" is required and will not `+ + `use the default value. Perhaps you meant to use type "String".`, + 2, 66, + ), + }) +} +func TestValidate_VariableDefaultValuesOfCorrectType_VariablesWithInvalidDefaultValues(t *testing.T) { + expectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` + query InvalidDefaultValues( + $a: Int = "one", + $b: String = 4, + $c: ComplexInput = "notverycomplex" + ) { + dog { name } + } + `, + []gqlerrors.FormattedError{ + ruleError(`Variable "$a" of type "Int" has invalid default value: "one".`, 3, 19), + ruleError(`Variable "$b" of type "String" has invalid default value: 4.`, 4, 22), + ruleError(`Variable "$c" of type "ComplexInput" has invalid default value: "notverycomplex".`, 5, 28), + }) +} + +func TestValidate_VariableDefaultValuesOfCorrectType_ComplexVariablesMissingRequiredField(t *testing.T) { + expectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` + query MissingRequiredField($a: ComplexInput = {intField: 3}) { + dog { name } + } + `, + []gqlerrors.FormattedError{ + ruleError(`Variable "$a" of type "ComplexInput" has invalid default value: {intField: 3}.`, 2, 53), + }) +} + +func TestValidate_VariableDefaultValuesOfCorrectType_ListVariablesWithInvalidItem(t *testing.T) { + expectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` + query InvalidItem($a: [String] = ["one", 2]) { + dog { name } + } + `, + []gqlerrors.FormattedError{ + ruleError(`Variable "$a" of type "[String]" has invalid default value: ["one", 2].`, 2, 40), + }) +} From 303b6e12a02f031a4241dc5945b787bb42cd7e2c Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Tue, 10 Nov 2015 20:41:01 +0800 Subject: [PATCH 15/41] Implemented `FieldsOnCorrectTypeRule ` and tested - Fixed failing `abstract_test.go` --- abstract_test.go | 88 ++------------ rules.go | 71 +++++++++++- rules/fields_on_correct_type_test.go | 167 +++++++++++++++++++++++++++ 3 files changed, 246 insertions(+), 80 deletions(-) create mode 100644 rules/fields_on_correct_type_test.go diff --git a/abstract_test.go b/abstract_test.go index 7639ac75..af4b3109 100644 --- a/abstract_test.go +++ b/abstract_test.go @@ -11,17 +11,17 @@ import ( ) type testDog struct { - Name string - Woofs bool + Name string `json:"name"` + Woofs bool `json:"woofs"` } type testCat struct { - Name string - Meows bool + Name string `json:"name"` + Meows bool `json:"meows"` } type testHuman struct { - Name string + Name string `json:"name"` } func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { @@ -168,21 +168,9 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { Fields: graphql.FieldConfigMap{ "name": &graphql.FieldConfig{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { - if dog, ok := p.Source.(*testDog); ok { - return dog.Name - } - return nil - }, }, "woofs": &graphql.FieldConfig{ Type: graphql.Boolean, - Resolve: func(p graphql.GQLFRParams) interface{} { - if dog, ok := p.Source.(*testDog); ok { - return dog.Woofs - } - return nil - }, }, }, }) @@ -195,21 +183,9 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { Fields: graphql.FieldConfigMap{ "name": &graphql.FieldConfig{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { - if cat, ok := p.Source.(*testCat); ok { - return cat.Name - } - return nil - }, }, "meows": &graphql.FieldConfig{ Type: graphql.Boolean, - Resolve: func(p graphql.GQLFRParams) interface{} { - if cat, ok := p.Source.(*testCat); ok { - return cat.Meows - } - return nil - }, }, }, }) @@ -219,15 +195,6 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { Types: []*graphql.Object{ dogType, catType, }, - ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { - if _, ok := value.(*testCat); ok { - return catType - } - if _, ok := value.(*testDog); ok { - return dogType - } - return nil - }, }) schema, err := graphql.NewSchema(graphql.SchemaConfig{ Query: graphql.NewObject(graphql.ObjectConfig{ @@ -251,11 +218,12 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { query := `{ pets { - name ... on Dog { + name woofs } ... on Cat { + name meows } } @@ -281,7 +249,6 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { Schema: schema, RequestString: query, }) - if len(result.Errors) != 0 { t.Fatalf("wrong result, unexpected errors: %v", result.Errors) } @@ -464,66 +431,28 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { Fields: graphql.FieldConfigMap{ "name": &graphql.FieldConfig{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { - if human, ok := p.Source.(*testHuman); ok { - return human.Name - } - return nil - }, }, }, }) dogType := graphql.NewObject(graphql.ObjectConfig{ Name: "Dog", - IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { - _, ok := value.(*testDog) - return ok - }, Fields: graphql.FieldConfigMap{ "name": &graphql.FieldConfig{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { - if dog, ok := p.Source.(*testDog); ok { - return dog.Name - } - return nil - }, }, "woofs": &graphql.FieldConfig{ Type: graphql.Boolean, - Resolve: func(p graphql.GQLFRParams) interface{} { - if dog, ok := p.Source.(*testDog); ok { - return dog.Woofs - } - return nil - }, }, }, }) catType := graphql.NewObject(graphql.ObjectConfig{ Name: "Cat", - IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { - _, ok := value.(*testCat) - return ok - }, Fields: graphql.FieldConfigMap{ "name": &graphql.FieldConfig{ Type: graphql.String, - Resolve: func(p graphql.GQLFRParams) interface{} { - if cat, ok := p.Source.(*testCat); ok { - return cat.Name - } - return nil - }, }, "meows": &graphql.FieldConfig{ Type: graphql.Boolean, - Resolve: func(p graphql.GQLFRParams) interface{} { - if cat, ok := p.Source.(*testCat); ok { - return cat.Meows - } - return nil - }, }, }, }) @@ -568,11 +497,12 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { query := `{ pets { - name ... on Dog { + name woofs } ... on Cat { + name meows } } diff --git a/rules.go b/rules.go index 2267c14a..df6849f7 100644 --- a/rules.go +++ b/rules.go @@ -14,8 +14,9 @@ import ( */ var SpecifiedRules = []ValidationRuleFn{ ArgumentsOfCorrectTypeRule, - KnownTypeNamesRule, DefaultValuesOfCorrectTypeRule, + FieldsOnCorrectTypeRule, + KnownTypeNamesRule, } type ValidationRuleInstance struct { @@ -24,6 +25,13 @@ type ValidationRuleInstance struct { } type ValidationRuleFn func(context *ValidationContext) *ValidationRuleInstance +/** + * ArgumentsOfCorrectTypeRule + * Argument values of correct type + * + * A GraphQL document is only valid if all field argument literal values are + * of the type expected by their position. + */ func ArgumentsOfCorrectTypeRule(context *ValidationContext) *ValidationRuleInstance { visitorOpts := &visitor.VisitorOptions{ KindFuncMap: map[string]visitor.NamedVisitFuncs{ @@ -59,6 +67,14 @@ func ArgumentsOfCorrectTypeRule(context *ValidationContext) *ValidationRuleInsta VisitorOpts: visitorOpts, } } + +/** + * DefaultValuesOfCorrectTypeRule + * Variable default values of correct type + * + * A GraphQL document is only valid if all variable default values are of the + * type expected by their definition. + */ func DefaultValuesOfCorrectTypeRule(context *ValidationContext) *ValidationRuleInstance { visitorOpts := &visitor.VisitorOptions{ KindFuncMap: map[string]visitor.NamedVisitFuncs{ @@ -104,6 +120,59 @@ func DefaultValuesOfCorrectTypeRule(context *ValidationContext) *ValidationRuleI VisitorOpts: visitorOpts, } } + +/** + * FieldsOnCorrectTypeRule + * Fields on correct type + * + * A GraphQL document is only valid if all fields selected are defined by the + * parent type, or are an allowed meta field such as __typenamme + */ +func FieldsOnCorrectTypeRule(context *ValidationContext) *ValidationRuleInstance { + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.Field: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + var action = visitor.ActionNoChange + var result interface{} + if node, ok := p.Node.(*ast.Field); ok { + ttype := context.GetParentType() + + if ttype != nil { + fieldDef := context.GetFieldDef() + if fieldDef == nil { + nodeName := "" + if node.Name != nil { + nodeName = node.Name.Value + } + return visitor.ActionNoChange, gqlerrors.NewError( + fmt.Sprintf(`Cannot query field "%v" on "%v".`, + nodeName, ttype.GetName()), + []ast.Node{node}, + "", + nil, + []int{}, + ) + } + } + } + return action, result + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + +/** + * KnownTypeNamesRule + * Known type names + * + * A GraphQL document is only valid if referenced types (specifically + * variable definitions and fragment conditions) are defined by the type schema. + */ func KnownTypeNamesRule(context *ValidationContext) *ValidationRuleInstance { visitorOpts := &visitor.VisitorOptions{ KindFuncMap: map[string]visitor.NamedVisitFuncs{ diff --git a/rules/fields_on_correct_type_test.go b/rules/fields_on_correct_type_test.go new file mode 100644 index 00000000..1fb1d0af --- /dev/null +++ b/rules/fields_on_correct_type_test.go @@ -0,0 +1,167 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + // "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_FieldsOnCorrectType_ObjectFieldSelection(t *testing.T) { + expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment objectFieldSelection on Dog { + __typename + name + } + `) +} +func TestValidate_FieldsOnCorrectType_AliasedObjectFieldSelection(t *testing.T) { + expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment aliasedObjectFieldSelection on Dog { + tn : __typename + otherName : name + } + `) +} +func TestValidate_FieldsOnCorrectType_InterfaceFieldSelection(t *testing.T) { + expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment interfaceFieldSelection on Pet { + __typename + name + } + `) +} +func TestValidate_FieldsOnCorrectType_AliasedInterfaceFieldSelection(t *testing.T) { + expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment interfaceFieldSelection on Pet { + otherName : name + } + `) +} +func TestValidate_FieldsOnCorrectType_LyingAliasSelection(t *testing.T) { + expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment lyingAliasSelection on Dog { + name : nickname + } + `) +} +func TestValidate_FieldsOnCorrectType_IgnoresFieldsOnUnknownType(t *testing.T) { + expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment unknownSelection on UnknownType { + unknownField + } + `) +} +func TestValidate_FieldsOnCorrectType_FieldNotDefinedOnFragment(t *testing.T) { + expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment fieldNotDefined on Dog { + meowVolume + } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot query field "meowVolume" on "Dog".`, 3, 9), + }) +} +func TestValidate_FieldsOnCorrectType_FieldNotDefinedDeeplyOnlyReportsFirst(t *testing.T) { + expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment deepFieldNotDefined on Dog { + unknown_field { + deeper_unknown_field + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot query field "unknown_field" on "Dog".`, 3, 9), + }) +} +func TestValidate_FieldsOnCorrectType_SubFieldNotDefined(t *testing.T) { + expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment subFieldNotDefined on Human { + pets { + unknown_field + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot query field "unknown_field" on "Pet".`, 4, 11), + }) +} +func TestValidate_FieldsOnCorrectType_FieldNotDefinedOnInlineFragment(t *testing.T) { + expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment fieldNotDefined on Pet { + ... on Dog { + meowVolume + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot query field "meowVolume" on "Dog".`, 4, 11), + }) +} +func TestValidate_FieldsOnCorrectType_AliasedFieldTargetNotDefined(t *testing.T) { + expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment aliasedFieldTargetNotDefined on Dog { + volume : mooVolume + } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot query field "mooVolume" on "Dog".`, 3, 9), + }) +} +func TestValidate_FieldsOnCorrectType_AliasedLyingFieldTargetNotDefined(t *testing.T) { + expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment aliasedLyingFieldTargetNotDefined on Dog { + barkVolume : kawVolume + } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot query field "kawVolume" on "Dog".`, 3, 9), + }) +} +func TestValidate_FieldsOnCorrectType_NotDefinedOnInterface(t *testing.T) { + expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment notDefinedOnInterface on Pet { + tailLength + } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot query field "tailLength" on "Pet".`, 3, 9), + }) +} +func TestValidate_FieldsOnCorrectType_DefinedOnImplementorsButNotOnInterface(t *testing.T) { + expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment definedOnImplementorsButNotInterface on Pet { + nickname + } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot query field "nickname" on "Pet".`, 3, 9), + }) +} +func TestValidate_FieldsOnCorrectType_MetaFieldSelectionOnUnion(t *testing.T) { + expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment directFieldSelectionOnUnion on CatOrDog { + __typename + } + `) +} +func TestValidate_FieldsOnCorrectType_DirectFieldSelectionOnUnion(t *testing.T) { + expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment directFieldSelectionOnUnion on CatOrDog { + directField + } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot query field "directField" on "CatOrDog".`, 3, 9), + }) +} +func TestValidate_FieldsOnCorrectType_DirectImplementorsQueriedOnUnion(t *testing.T) { + expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment definedOnImplementorsQueriedOnUnion on CatOrDog { + name + } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot query field "name" on "CatOrDog".`, 3, 9), + }) +} +func TestValidate_FieldsOnCorrectType_ValidFieldInInlineFragment(t *testing.T) { + expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + fragment objectFieldSelection on Pet { + ... on Dog { + name + } + } + `) +} From 7ce1c941adda08d7049267109e39cf40e34ba06b Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Tue, 10 Nov 2015 23:19:40 +0800 Subject: [PATCH 16/41] Implemented `FragmentsOnCompositeTypesRule` & `KnownArgumentNamesRule` and tested --- definition.go | 10 -- rules.go | 140 +++++++++++++++++++++ rules/fragments_on_composite_types_test.go | 78 ++++++++++++ rules/known_argument_names_test.go | 114 +++++++++++++++++ 4 files changed, 332 insertions(+), 10 deletions(-) create mode 100644 rules/fragments_on_composite_types_test.go create mode 100644 rules/known_argument_names_test.go diff --git a/definition.go b/definition.go index 7df1d7ca..c089d9de 100644 --- a/definition.go +++ b/definition.go @@ -123,16 +123,6 @@ type Abstract interface { var _ Abstract = (*Interface)(nil) var _ Abstract = (*Union)(nil) -func IsAbstractType(ttype Type) bool { - if _, ok := ttype.(*Interface); ok { - return true - } - if _, ok := ttype.(*Union); ok { - return true - } - return false -} - type Nullable interface { } diff --git a/rules.go b/rules.go index df6849f7..94cc8501 100644 --- a/rules.go +++ b/rules.go @@ -16,6 +16,8 @@ var SpecifiedRules = []ValidationRuleFn{ ArgumentsOfCorrectTypeRule, DefaultValuesOfCorrectTypeRule, FieldsOnCorrectTypeRule, + FragmentsOnCompositeTypesRule, + KnownArgumentNamesRule, KnownTypeNamesRule, } @@ -205,6 +207,144 @@ func KnownTypeNamesRule(context *ValidationContext) *ValidationRuleInstance { } } +/** + * FragmentsOnCompositeTypesRule + * Fragments on composite type + * + * Fragments use a type condition to determine if they apply, since fragments + * can only be spread into a composite type (object, interface, or union), the + * type condition must also be a composite type. + */ +func FragmentsOnCompositeTypesRule(context *ValidationContext) *ValidationRuleInstance { + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.InlineFragment: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.InlineFragment); ok { + ttype := context.GetType() + if ttype != nil && !IsCompositeType(ttype) { + return visitor.ActionNoChange, gqlerrors.NewError( + fmt.Sprintf(`Fragment cannot condition on non composite type "%v".`, ttype), + []ast.Node{node.TypeCondition}, + "", + nil, + []int{}, + ) + } + } + return visitor.ActionNoChange, nil + }, + }, + kinds.FragmentDefinition: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.FragmentDefinition); ok { + ttype := context.GetType() + if ttype != nil && !IsCompositeType(ttype) { + nodeName := "" + if node.Name != nil { + nodeName = node.Name.Value + } + return visitor.ActionNoChange, gqlerrors.NewError( + fmt.Sprintf(`Fragment "%v" cannot condition on non composite type "%v".`, nodeName, printer.Print(node.TypeCondition)), + []ast.Node{node.TypeCondition}, + "", + nil, + []int{}, + ) + } + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + +/** + * KnownArgumentNamesRule + * Known argument names + * + * A GraphQL field is only valid if all supplied arguments are defined by + * that field. + */ +func KnownArgumentNamesRule(context *ValidationContext) *ValidationRuleInstance { + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.Argument: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + var action = visitor.ActionNoChange + var result interface{} + if node, ok := p.Node.(*ast.Argument); ok { + argumentOf := p.Ancestors[len(p.Ancestors)-1] + if argumentOf.GetKind() == "Field" { + fieldDef := context.GetFieldDef() + if fieldDef == nil { + return action, result + } + nodeName := "" + if node.Name != nil { + nodeName = node.Name.Value + } + var fieldArgDef *Argument + for _, arg := range fieldDef.Args { + if arg.Name == nodeName { + fieldArgDef = arg + } + } + if fieldArgDef == nil { + parentType := context.GetParentType() + parentTypeName := "" + if parentType != nil { + parentTypeName = parentType.GetName() + } + return visitor.ActionNoChange, gqlerrors.NewError( + fmt.Sprintf(`Unknown argument "%v" on field "%v" of type "%v".`, nodeName, fieldDef.Name, parentTypeName), + []ast.Node{node}, + "", + nil, + []int{}, + ) + } + } else if argumentOf.GetKind() == "Directive" { + directive := context.GetDirective() + if directive == nil { + return action, result + } + nodeName := "" + if node.Name != nil { + nodeName = node.Name.Value + } + var directiveArgDef *Argument + for _, arg := range directive.Args { + if arg.Name == nodeName { + directiveArgDef = arg + } + } + if directiveArgDef == nil { + return visitor.ActionNoChange, gqlerrors.NewError( + fmt.Sprintf(`Unknown argument "%v" on directive "@%v".`, nodeName, directive.Name), + []ast.Node{node}, + "", + nil, + []int{}, + ) + } + } + + } + return action, result + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + /** * Utility for validators which determines if a value literal AST is valid given * an input type. diff --git a/rules/fragments_on_composite_types_test.go b/rules/fragments_on_composite_types_test.go new file mode 100644 index 00000000..97655c1d --- /dev/null +++ b/rules/fragments_on_composite_types_test.go @@ -0,0 +1,78 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_FragmentsOnCompositeTypes_ObjectIsValidFragmentType(t *testing.T) { + expectPassesRule(t, graphql.FragmentsOnCompositeTypesRule, ` + fragment validFragment on Dog { + barks + } + `) +} +func TestValidate_FragmentsOnCompositeTypes_InterfaceIsValidFragmentType(t *testing.T) { + expectPassesRule(t, graphql.FragmentsOnCompositeTypesRule, ` + fragment validFragment on Pet { + name + } + `) +} +func TestValidate_FragmentsOnCompositeTypes_ObjectIsValidInlineFragmentType(t *testing.T) { + expectPassesRule(t, graphql.FragmentsOnCompositeTypesRule, ` + fragment validFragment on Pet { + ... on Dog { + barks + } + } + `) +} +func TestValidate_FragmentsOnCompositeTypes_UnionIsValidFragmentType(t *testing.T) { + expectPassesRule(t, graphql.FragmentsOnCompositeTypesRule, ` + fragment validFragment on CatOrDog { + __typename + } + `) +} + +func TestValidate_FragmentsOnCompositeTypes_ScalarIsInvalidFragmentType(t *testing.T) { + expectFailsRule(t, graphql.FragmentsOnCompositeTypesRule, ` + fragment scalarFragment on Boolean { + bad + } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "scalarFragment" cannot condition on non composite type "Boolean".`, 2, 34), + }) +} +func TestValidate_FragmentsOnCompositeTypes_EnumIsInvalidFragmentType(t *testing.T) { + expectFailsRule(t, graphql.FragmentsOnCompositeTypesRule, ` + fragment scalarFragment on FurColor { + bad + } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "scalarFragment" cannot condition on non composite type "FurColor".`, 2, 34), + }) +} +func TestValidate_FragmentsOnCompositeTypes_InputObjectIsInvalidFragmentType(t *testing.T) { + expectFailsRule(t, graphql.FragmentsOnCompositeTypesRule, ` + fragment inputFragment on ComplexInput { + stringField + } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "inputFragment" cannot condition on non composite type "ComplexInput".`, 2, 33), + }) +} +func TestValidate_FragmentsOnCompositeTypes_ScalarIsInvalidInlineFragmentType(t *testing.T) { + expectFailsRule(t, graphql.FragmentsOnCompositeTypesRule, ` + fragment invalidFragment on Pet { + ... on String { + barks + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment cannot condition on non composite type "String".`, 3, 16), + }) +} diff --git a/rules/known_argument_names_test.go b/rules/known_argument_names_test.go new file mode 100644 index 00000000..743f3466 --- /dev/null +++ b/rules/known_argument_names_test.go @@ -0,0 +1,114 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_KnownArgumentNames_SingleArgIsKnown(t *testing.T) { + expectPassesRule(t, graphql.KnownArgumentNamesRule, ` + fragment argOnRequiredArg on Dog { + doesKnowCommand(dogCommand: SIT) + } + `) +} +func TestValidate_KnownArgumentNames_MultipleArgsAreKnown(t *testing.T) { + expectPassesRule(t, graphql.KnownArgumentNamesRule, ` + fragment multipleArgs on ComplicatedArgs { + multipleReqs(req1: 1, req2: 2) + } + `) +} +func TestValidate_KnownArgumentNames_IgnoresArgsOfUnknownFields(t *testing.T) { + expectPassesRule(t, graphql.KnownArgumentNamesRule, ` + fragment argOnUnknownField on Dog { + unknownField(unknownArg: SIT) + } + `) +} +func TestValidate_KnownArgumentNames_MultipleArgsInReverseOrderAreKnown(t *testing.T) { + expectPassesRule(t, graphql.KnownArgumentNamesRule, ` + fragment multipleArgsReverseOrder on ComplicatedArgs { + multipleReqs(req2: 2, req1: 1) + } + `) +} +func TestValidate_KnownArgumentNames_NoArgsOnOptionalArg(t *testing.T) { + expectPassesRule(t, graphql.KnownArgumentNamesRule, ` + fragment noArgOnOptionalArg on Dog { + isHousetrained + } + `) +} +func TestValidate_KnownArgumentNames_ArgsAreKnownDeeply(t *testing.T) { + expectPassesRule(t, graphql.KnownArgumentNamesRule, ` + { + dog { + doesKnowCommand(dogCommand: SIT) + } + human { + pet { + ... on Dog { + doesKnowCommand(dogCommand: SIT) + } + } + } + } + `) +} +func TestValidate_KnownArgumentNames_DirectiveArgsAreKnown(t *testing.T) { + expectPassesRule(t, graphql.KnownArgumentNamesRule, ` + { + dog @skip(if: true) + } + `) +} +func TestValidate_KnownArgumentNames_UndirectiveArgsAreInvalid(t *testing.T) { + expectFailsRule(t, graphql.KnownArgumentNamesRule, ` + { + dog @skip(unless: true) + } + `, []gqlerrors.FormattedError{ + ruleError(`Unknown argument "unless" on directive "@skip".`, 3, 19), + }) +} +func TestValidate_KnownArgumentNames_InvalidArgName(t *testing.T) { + expectFailsRule(t, graphql.KnownArgumentNamesRule, ` + fragment invalidArgName on Dog { + doesKnowCommand(unknown: true) + } + `, []gqlerrors.FormattedError{ + ruleError(`Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".`, 3, 25), + }) +} +func TestValidate_KnownArgumentNames_UnknownArgsAmongstKnownArgs(t *testing.T) { + expectFailsRule(t, graphql.KnownArgumentNamesRule, ` + fragment oneGoodArgOneInvalidArg on Dog { + doesKnowCommand(whoknows: 1, dogCommand: SIT, unknown: true) + } + `, []gqlerrors.FormattedError{ + ruleError(`Unknown argument "whoknows" on field "doesKnowCommand" of type "Dog".`, 3, 25), + ruleError(`Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".`, 3, 55), + }) +} +func TestValidate_KnownArgumentNames_UnknownArgsDeeply(t *testing.T) { + expectFailsRule(t, graphql.KnownArgumentNamesRule, ` + { + dog { + doesKnowCommand(unknown: true) + } + human { + pet { + ... on Dog { + doesKnowCommand(unknown: true) + } + } + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".`, 4, 27), + ruleError(`Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".`, 9, 31), + }) +} From 86bf407d88c4024b47501de0210843277de8ea6e Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Wed, 11 Nov 2015 02:11:31 +0800 Subject: [PATCH 17/41] Implemented `KnownDirectivesRule ` & `KnownFragmentNamesRule ` and tested --- rules.go | 248 ++++++++++++++++++++-------- rules/known_directives_rule_test.go | 71 ++++++++ rules/known_fragment_names_test.go | 51 ++++++ rules/known_type_names_test.go | 15 +- 4 files changed, 300 insertions(+), 85 deletions(-) create mode 100644 rules/known_directives_rule_test.go create mode 100644 rules/known_fragment_names_test.go diff --git a/rules.go b/rules.go index 94cc8501..85aa9d19 100644 --- a/rules.go +++ b/rules.go @@ -18,6 +18,8 @@ var SpecifiedRules = []ValidationRuleFn{ FieldsOnCorrectTypeRule, FragmentsOnCompositeTypesRule, KnownArgumentNamesRule, + KnownDirectivesRule, + KnownFragmentNamesRule, KnownTypeNamesRule, } @@ -27,6 +29,16 @@ type ValidationRuleInstance struct { } type ValidationRuleFn func(context *ValidationContext) *ValidationRuleInstance +func newValidationRuleError(message string, nodes []ast.Node) (string, error) { + return visitor.ActionNoChange, gqlerrors.NewError( + message, + nodes, + "", + nil, + []int{}, + ) +} + /** * ArgumentsOfCorrectTypeRule * Argument values of correct type @@ -49,14 +61,10 @@ func ArgumentsOfCorrectTypeRule(context *ValidationContext) *ValidationRuleInsta if argAST.Name != nil { argNameValue = argAST.Name.Value } - // TODO: helper to construct gqlerror with message + []ast.Node - return visitor.ActionNoChange, gqlerrors.NewError( + return newValidationRuleError( fmt.Sprintf(`Argument "%v" expected type "%v" but got: %v.`, argNameValue, argDef.Type, printer.Print(value)), []ast.Node{value}, - "", - nil, - []int{}, ) } } @@ -93,23 +101,17 @@ func DefaultValuesOfCorrectTypeRule(context *ValidationContext) *ValidationRuleI ttype := context.GetInputType() if ttype, ok := ttype.(*NonNull); ok && defaultValue != nil { - return visitor.ActionNoChange, gqlerrors.NewError( + return newValidationRuleError( fmt.Sprintf(`Variable "$%v" of type "%v" is required and will not use the default value. Perhaps you meant to use type "%v".`, name, ttype, ttype.OfType), []ast.Node{defaultValue}, - "", - nil, - []int{}, ) } if ttype != nil && defaultValue != nil && !isValidLiteralValue(ttype, defaultValue) { - return visitor.ActionNoChange, gqlerrors.NewError( + return newValidationRuleError( fmt.Sprintf(`Variable "$%v" of type "%v" has invalid default value: %v.`, name, ttype, printer.Print(defaultValue)), []ast.Node{defaultValue}, - "", - nil, - []int{}, ) } } @@ -147,13 +149,10 @@ func FieldsOnCorrectTypeRule(context *ValidationContext) *ValidationRuleInstance if node.Name != nil { nodeName = node.Name.Value } - return visitor.ActionNoChange, gqlerrors.NewError( + return newValidationRuleError( fmt.Sprintf(`Cannot query field "%v" on "%v".`, nodeName, ttype.GetName()), []ast.Node{node}, - "", - nil, - []int{}, ) } } @@ -168,45 +167,6 @@ func FieldsOnCorrectTypeRule(context *ValidationContext) *ValidationRuleInstance } } -/** - * KnownTypeNamesRule - * Known type names - * - * A GraphQL document is only valid if referenced types (specifically - * variable definitions and fragment conditions) are defined by the type schema. - */ -func KnownTypeNamesRule(context *ValidationContext) *ValidationRuleInstance { - visitorOpts := &visitor.VisitorOptions{ - KindFuncMap: map[string]visitor.NamedVisitFuncs{ - kinds.Named: visitor.NamedVisitFuncs{ - Kind: func(p visitor.VisitFuncParams) (string, interface{}) { - if node, ok := p.Node.(*ast.Named); ok { - typeNameValue := "" - typeName := node.Name - if typeName != nil { - typeNameValue = typeName.Value - } - ttype := context.GetSchema().GetType(typeNameValue) - if ttype == nil { - return visitor.ActionNoChange, gqlerrors.NewError( - fmt.Sprintf(`Unknown type "%v".`, typeNameValue), - []ast.Node{node}, - "", - nil, - []int{}, - ) - } - } - return visitor.ActionNoChange, nil - }, - }, - }, - } - return &ValidationRuleInstance{ - VisitorOpts: visitorOpts, - } -} - /** * FragmentsOnCompositeTypesRule * Fragments on composite type @@ -223,12 +183,9 @@ func FragmentsOnCompositeTypesRule(context *ValidationContext) *ValidationRuleIn if node, ok := p.Node.(*ast.InlineFragment); ok { ttype := context.GetType() if ttype != nil && !IsCompositeType(ttype) { - return visitor.ActionNoChange, gqlerrors.NewError( + return newValidationRuleError( fmt.Sprintf(`Fragment cannot condition on non composite type "%v".`, ttype), []ast.Node{node.TypeCondition}, - "", - nil, - []int{}, ) } } @@ -244,12 +201,9 @@ func FragmentsOnCompositeTypesRule(context *ValidationContext) *ValidationRuleIn if node.Name != nil { nodeName = node.Name.Value } - return visitor.ActionNoChange, gqlerrors.NewError( + return newValidationRuleError( fmt.Sprintf(`Fragment "%v" cannot condition on non composite type "%v".`, nodeName, printer.Print(node.TypeCondition)), []ast.Node{node.TypeCondition}, - "", - nil, - []int{}, ) } } @@ -278,7 +232,13 @@ func KnownArgumentNamesRule(context *ValidationContext) *ValidationRuleInstance var action = visitor.ActionNoChange var result interface{} if node, ok := p.Node.(*ast.Argument); ok { - argumentOf := p.Ancestors[len(p.Ancestors)-1] + var argumentOf ast.Node + if len(p.Ancestors) > 0 { + argumentOf = p.Ancestors[len(p.Ancestors)-1] + } + if argumentOf == nil { + return action, result + } if argumentOf.GetKind() == "Field" { fieldDef := context.GetFieldDef() if fieldDef == nil { @@ -300,12 +260,9 @@ func KnownArgumentNamesRule(context *ValidationContext) *ValidationRuleInstance if parentType != nil { parentTypeName = parentType.GetName() } - return visitor.ActionNoChange, gqlerrors.NewError( + return newValidationRuleError( fmt.Sprintf(`Unknown argument "%v" on field "%v" of type "%v".`, nodeName, fieldDef.Name, parentTypeName), []ast.Node{node}, - "", - nil, - []int{}, ) } } else if argumentOf.GetKind() == "Directive" { @@ -324,12 +281,9 @@ func KnownArgumentNamesRule(context *ValidationContext) *ValidationRuleInstance } } if directiveArgDef == nil { - return visitor.ActionNoChange, gqlerrors.NewError( + return newValidationRuleError( fmt.Sprintf(`Unknown argument "%v" on directive "@%v".`, nodeName, directive.Name), []ast.Node{node}, - "", - nil, - []int{}, ) } } @@ -345,6 +299,154 @@ func KnownArgumentNamesRule(context *ValidationContext) *ValidationRuleInstance } } +/** + * Known directives + * + * A GraphQL document is only valid if all `@directives` are known by the + * schema and legally positioned. + */ +func KnownDirectivesRule(context *ValidationContext) *ValidationRuleInstance { + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.Directive: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + var action = visitor.ActionNoChange + var result interface{} + if node, ok := p.Node.(*ast.Directive); ok { + + nodeName := "" + if node.Name != nil { + nodeName = node.Name.Value + } + + var directiveDef *Directive + for _, def := range context.GetSchema().GetDirectives() { + if def.Name == nodeName { + directiveDef = def + } + } + if directiveDef == nil { + return newValidationRuleError( + fmt.Sprintf(`Unknown directive "%v".`, nodeName), + []ast.Node{node}, + ) + } + + var appliedTo ast.Node + if len(p.Ancestors) > 0 { + appliedTo = p.Ancestors[len(p.Ancestors)-1] + } + if appliedTo == nil { + return action, result + } + + if appliedTo.GetKind() == kinds.OperationDefinition && directiveDef.OnOperation == false { + return newValidationRuleError( + fmt.Sprintf(`Directive "%v" may not be used on "%v".`, nodeName, "operation"), + []ast.Node{node}, + ) + } + if appliedTo.GetKind() == kinds.Field && directiveDef.OnField == false { + return newValidationRuleError( + fmt.Sprintf(`Directive "%v" may not be used on "%v".`, nodeName, "field"), + []ast.Node{node}, + ) + } + if (appliedTo.GetKind() == kinds.FragmentSpread || + appliedTo.GetKind() == kinds.InlineFragment || + appliedTo.GetKind() == kinds.FragmentDefinition) && directiveDef.OnFragment == false { + return newValidationRuleError( + fmt.Sprintf(`Directive "%v" may not be used on "%v".`, nodeName, "fragment"), + []ast.Node{node}, + ) + } + + } + return action, result + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + +/** + * KnownFragmentNamesRule + * Known fragment names + * + * A GraphQL document is only valid if all `...Fragment` fragment spreads refer + * to fragments defined in the same document. + */ +func KnownFragmentNamesRule(context *ValidationContext) *ValidationRuleInstance { + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.FragmentSpread: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + var action = visitor.ActionNoChange + var result interface{} + if node, ok := p.Node.(*ast.FragmentSpread); ok { + + fragmentName := "" + if node.Name != nil { + fragmentName = node.Name.Value + } + + fragment := context.GetFragment(fragmentName) + if fragment == nil { + return newValidationRuleError( + fmt.Sprintf(`Unknown fragment "%v".`, fragmentName), + []ast.Node{node.Name}, + ) + } + } + return action, result + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + +/** + * KnownTypeNamesRule + * Known type names + * + * A GraphQL document is only valid if referenced types (specifically + * variable definitions and fragment conditions) are defined by the type schema. + */ +func KnownTypeNamesRule(context *ValidationContext) *ValidationRuleInstance { + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.Named: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.Named); ok { + typeNameValue := "" + typeName := node.Name + if typeName != nil { + typeNameValue = typeName.Value + } + ttype := context.GetSchema().GetType(typeNameValue) + if ttype == nil { + return newValidationRuleError( + fmt.Sprintf(`Unknown type "%v".`, typeNameValue), + []ast.Node{node}, + ) + } + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + /** * Utility for validators which determines if a value literal AST is valid given * an input type. diff --git a/rules/known_directives_rule_test.go b/rules/known_directives_rule_test.go new file mode 100644 index 00000000..43fc32f6 --- /dev/null +++ b/rules/known_directives_rule_test.go @@ -0,0 +1,71 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_KnownDirectives_WithNoDirectives(t *testing.T) { + expectPassesRule(t, graphql.KnownDirectivesRule, ` + query Foo { + name + ...Frag + } + + fragment Frag on Dog { + name + } + `) +} +func TestValidate_KnownDirectives_WithUnknownDirective(t *testing.T) { + expectFailsRule(t, graphql.KnownDirectivesRule, ` + { + dog @unknown(directive: "value") { + name + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Unknown directive "unknown".`, 3, 13), + }) +} +func TestValidate_KnownDirectives_WithManyUnknownDirectives(t *testing.T) { + expectFailsRule(t, graphql.KnownDirectivesRule, ` + { + dog @unknown(directive: "value") { + name + } + human @unknown(directive: "value") { + name + pets @unknown(directive: "value") { + name + } + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Unknown directive "unknown".`, 3, 13), + ruleError(`Unknown directive "unknown".`, 6, 15), + ruleError(`Unknown directive "unknown".`, 8, 16), + }) +} +func TestValidate_KnownDirectives_WithWellPlacedDirectives(t *testing.T) { + expectPassesRule(t, graphql.KnownDirectivesRule, ` + query Foo { + name @include(if: true) + ...Frag @include(if: true) + skippedField @skip(if: true) + ...SkippedFrag @skip(if: true) + } + `) +} +func TestValidate_KnownDirectives_WithMisplacedDirectives(t *testing.T) { + expectFailsRule(t, graphql.KnownDirectivesRule, ` + query Foo @include(if: true) { + name + ...Frag + } + `, []gqlerrors.FormattedError{ + ruleError(`Directive "include" may not be used on "operation".`, 2, 17), + }) +} diff --git a/rules/known_fragment_names_test.go b/rules/known_fragment_names_test.go new file mode 100644 index 00000000..55bef4d9 --- /dev/null +++ b/rules/known_fragment_names_test.go @@ -0,0 +1,51 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_KnownFragmentNames_KnownFragmentNamesAreValid(t *testing.T) { + expectPassesRule(t, graphql.KnownFragmentNamesRule, ` + { + human(id: 4) { + ...HumanFields1 + ... on Human { + ...HumanFields2 + } + } + } + fragment HumanFields1 on Human { + name + ...HumanFields3 + } + fragment HumanFields2 on Human { + name + } + fragment HumanFields3 on Human { + name + } + `) +} +func TestValidate_KnownFragmentNames_UnknownFragmentNamesAreInvalid(t *testing.T) { + expectFailsRule(t, graphql.KnownFragmentNamesRule, ` + { + human(id: 4) { + ...UnknownFragment1 + ... on Human { + ...UnknownFragment2 + } + } + } + fragment HumanFields on Human { + name + ...UnknownFragment3 + } + `, []gqlerrors.FormattedError{ + ruleError(`Unknown fragment "UnknownFragment1".`, 4, 14), + ruleError(`Unknown fragment "UnknownFragment2".`, 6, 16), + ruleError(`Unknown fragment "UnknownFragment3".`, 12, 12), + }) +} diff --git a/rules/known_type_names_test.go b/rules/known_type_names_test.go index 8c5a1a64..8b089e16 100644 --- a/rules/known_type_names_test.go +++ b/rules/known_type_names_test.go @@ -31,17 +31,8 @@ func TestValidate_KnownTypeNames_UnknownTypeNamesAreInValid(t *testing.T) { name } `, []gqlerrors.FormattedError{ - ruleError( - `Unknown type "JumbledUpLetters".`, - 2, 23, - ), - ruleError( - `Unknown type "Badger".`, - 5, 25, - ), - ruleError( - `Unknown type "Peettt".`, - 8, 29, - ), + ruleError(`Unknown type "JumbledUpLetters".`, 2, 23), + ruleError(`Unknown type "Badger".`, 5, 25), + ruleError(`Unknown type "Peettt".`, 8, 29), }) } From 9e62e2daaacda85805daf68d07af0e341c1a2902 Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Thu, 12 Nov 2015 23:25:08 +0800 Subject: [PATCH 18/41] Implemented `LoneAnonymousOperationRule` & `NoFragmentCyclesRule` and tested --- rules.go | 190 ++++++++++++++++++++ rules/lone_anonymous_operation_rule_test.go | 70 ++++++++ rules/no_fragment_cycles_test.go | 114 ++++++++++++ type_info.go | 11 +- validator.go | 8 + 5 files changed, 388 insertions(+), 5 deletions(-) create mode 100644 rules/lone_anonymous_operation_rule_test.go create mode 100644 rules/no_fragment_cycles_test.go diff --git a/rules.go b/rules.go index 85aa9d19..7357b9af 100644 --- a/rules.go +++ b/rules.go @@ -7,6 +7,7 @@ import ( "github.com/graphql-go/graphql/language/kinds" "github.com/graphql-go/graphql/language/printer" "github.com/graphql-go/graphql/language/visitor" + "strings" ) /** @@ -21,6 +22,8 @@ var SpecifiedRules = []ValidationRuleFn{ KnownDirectivesRule, KnownFragmentNamesRule, KnownTypeNamesRule, + LoneAnonymousOperationRule, + NoFragmentCyclesRule, } type ValidationRuleInstance struct { @@ -447,6 +450,171 @@ func KnownTypeNamesRule(context *ValidationContext) *ValidationRuleInstance { } } +/** + * LoneAnonymousOperationRule + * Lone anonymous operation + * + * A GraphQL document is only valid if when it contains an anonymous operation + * (the query short-hand) that it contains only that one operation definition. + */ +func LoneAnonymousOperationRule(context *ValidationContext) *ValidationRuleInstance { + var operationCount = 0 + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.Document: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.Document); ok { + operationCount = 0 + for _, definition := range node.Definitions { + if definition.GetKind() == kinds.OperationDefinition { + operationCount = operationCount + 1 + } + } + } + return visitor.ActionNoChange, nil + }, + }, + kinds.OperationDefinition: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.OperationDefinition); ok { + if node.Name == nil && operationCount > 1 { + return newValidationRuleError( + `This anonymous operation must be the only defined operation.`, + []ast.Node{node}, + ) + } + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + +type nodeSet struct { + set map[ast.Node]bool +} + +func newNodeSet() *nodeSet { + return &nodeSet{ + set: map[ast.Node]bool{}, + } +} +func (set *nodeSet) Has(node ast.Node) bool { + _, ok := set.set[node] + return ok +} +func (set *nodeSet) Add(node ast.Node) bool { + if set.Has(node) { + return false + } + set.set[node] = true + return true +} + +/** + * NoFragmentCyclesRule + */ +func NoFragmentCyclesRule(context *ValidationContext) *ValidationRuleInstance { + // Gather all the fragment spreads ASTs for each fragment definition. + // Importantly this does not include inline fragments. + definitions := context.GetDocument().Definitions + spreadsInFragment := map[string][]*ast.FragmentSpread{} + for _, node := range definitions { + if node.GetKind() == kinds.FragmentDefinition { + if node, ok := node.(*ast.FragmentDefinition); ok && node != nil { + nodeName := "" + if node.Name != nil { + nodeName = node.Name.Value + } + spreadsInFragment[nodeName] = gatherSpreads(node) + } + } + } + // Tracks spreads known to lead to cycles to ensure that cycles are not + // redundantly reported. + knownToLeadToCycle := newNodeSet() + + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.FragmentDefinition: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.FragmentDefinition); ok && node != nil { + errors := []error{} + spreadPath := []*ast.FragmentSpread{} + initialName := "" + if node.Name != nil { + initialName = node.Name.Value + } + var detectCycleRecursive func(fragmentName string) + detectCycleRecursive = func(fragmentName string) { + spreadNodes, _ := spreadsInFragment[fragmentName] + for _, spreadNode := range spreadNodes { + if knownToLeadToCycle.Has(spreadNode) { + continue + } + spreadNodeName := "" + if spreadNode.Name != nil { + spreadNodeName = spreadNode.Name.Value + } + if spreadNodeName == initialName { + cyclePath := []ast.Node{} + for _, path := range spreadPath { + cyclePath = append(cyclePath, path) + } + cyclePath = append(cyclePath, spreadNode) + for _, spread := range cyclePath { + knownToLeadToCycle.Add(spread) + } + via := "" + spreadNames := []string{} + for _, s := range spreadPath { + if s.Name != nil { + spreadNames = append(spreadNames, s.Name.Value) + } + } + if len(spreadNames) > 0 { + via = " via " + strings.Join(spreadNames, ", ") + } + _, err := newValidationRuleError( + fmt.Sprintf(`Cannot spread fragment "%v" within itself%v.`, initialName, via), + cyclePath, + ) + errors = append(errors, err) + continue + } + spreadPathHasCurrentNode := false + for _, spread := range spreadPath { + if spread == spreadNode { + spreadPathHasCurrentNode = true + } + } + if spreadPathHasCurrentNode { + continue + } + spreadPath = append(spreadPath, spreadNode) + detectCycleRecursive(spreadNodeName) + _, spreadPath = spreadPath[len(spreadPath)-1], spreadPath[:len(spreadPath)-1] + } + } + detectCycleRecursive(initialName) + if len(errors) > 0 { + return visitor.ActionNoChange, errors + } + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + /** * Utility for validators which determines if a value literal AST is valid given * an input type. @@ -539,3 +707,25 @@ func isValidLiteralValue(ttype Input, valueAST ast.Value) bool { // Silently fail, instead of panic() return false } + +/** + * Given an operation or fragment AST node, gather all the + * named spreads defined within the scope of the fragment + * or operation + */ +func gatherSpreads(node ast.Node) (spreadNodes []*ast.FragmentSpread) { + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.FragmentSpread: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.FragmentSpread); ok && node != nil { + spreadNodes = append(spreadNodes, node) + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + visitor.Visit(node, visitorOpts, nil) + return spreadNodes +} diff --git a/rules/lone_anonymous_operation_rule_test.go b/rules/lone_anonymous_operation_rule_test.go new file mode 100644 index 00000000..b5233e95 --- /dev/null +++ b/rules/lone_anonymous_operation_rule_test.go @@ -0,0 +1,70 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_AnonymousOperationMustBeAlone_NoOperations(t *testing.T) { + expectPassesRule(t, graphql.LoneAnonymousOperationRule, ` + fragment fragA on Type { + field + } + `) +} +func TestValidate_AnonymousOperationMustBeAlone_OneAnonOperation(t *testing.T) { + expectPassesRule(t, graphql.LoneAnonymousOperationRule, ` + { + field + } + `) +} +func TestValidate_AnonymousOperationMustBeAlone_MultipleNamedOperations(t *testing.T) { + expectPassesRule(t, graphql.LoneAnonymousOperationRule, ` + query Foo { + field + } + + query Bar { + field + } + `) +} +func TestValidate_AnonymousOperationMustBeAlone_AnonOperationWithFragment(t *testing.T) { + expectPassesRule(t, graphql.LoneAnonymousOperationRule, ` + { + ...Foo + } + fragment Foo on Type { + field + } + `) +} + +func TestValidate_AnonymousOperationMustBeAlone_MultipleAnonOperations(t *testing.T) { + expectFailsRule(t, graphql.LoneAnonymousOperationRule, ` + { + fieldA + } + { + fieldB + } + `, []gqlerrors.FormattedError{ + ruleError(`This anonymous operation must be the only defined operation.`, 2, 7), + ruleError(`This anonymous operation must be the only defined operation.`, 5, 7), + }) +} +func TestValidate_AnonymousOperationMustBeAlone_AnonOperationWithAnotherOperation(t *testing.T) { + expectFailsRule(t, graphql.LoneAnonymousOperationRule, ` + { + fieldA + } + mutation Foo { + fieldB + } + `, []gqlerrors.FormattedError{ + ruleError(`This anonymous operation must be the only defined operation.`, 2, 7), + }) +} diff --git a/rules/no_fragment_cycles_test.go b/rules/no_fragment_cycles_test.go new file mode 100644 index 00000000..3fe76c67 --- /dev/null +++ b/rules/no_fragment_cycles_test.go @@ -0,0 +1,114 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_NoCircularFragmentSpreads_SingleReferenceIsValid(t *testing.T) { + expectPassesRule(t, graphql.NoFragmentCyclesRule, ` + fragment fragA on Dog { ...fragB } + fragment fragB on Dog { name } + `) +} +func TestValidate_NoCircularFragmentSpreads_SpreadingTwiceIsNotCircular(t *testing.T) { + expectPassesRule(t, graphql.NoFragmentCyclesRule, ` + fragment fragA on Dog { ...fragB, ...fragB } + fragment fragB on Dog { name } + `) +} +func TestValidate_NoCircularFragmentSpreads_SpreadingTwiceIndirectlyIsNotCircular(t *testing.T) { + expectPassesRule(t, graphql.NoFragmentCyclesRule, ` + fragment fragA on Dog { ...fragB, ...fragC } + fragment fragB on Dog { ...fragC } + fragment fragC on Dog { name } + `) +} +func TestValidate_NoCircularFragmentSpreads_DoubleSpreadWithinAbstractTypes(t *testing.T) { + expectPassesRule(t, graphql.NoFragmentCyclesRule, ` + fragment nameFragment on Pet { + ... on Dog { name } + ... on Cat { name } + } + + fragment spreadsInAnon on Pet { + ... on Dog { ...nameFragment } + ... on Cat { ...nameFragment } + } + `) +} +func TestValidate_NoCircularFragmentSpreads_SpreadingRecursivelyWithinFieldFails(t *testing.T) { + expectFailsRule(t, graphql.NoFragmentCyclesRule, ` + fragment fragA on Human { relatives { ...fragA } }, + `, []gqlerrors.FormattedError{ + ruleError(`Cannot spread fragment "fragA" within itself.`, 2, 45), + }) +} +func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectly(t *testing.T) { + expectFailsRule(t, graphql.NoFragmentCyclesRule, ` + fragment fragA on Dog { ...fragA } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot spread fragment "fragA" within itself.`, 2, 31), + }) +} +func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectlyWithinInlineFragment(t *testing.T) { + expectFailsRule(t, graphql.NoFragmentCyclesRule, ` + fragment fragA on Pet { + ... on Dog { + ...fragA + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot spread fragment "fragA" within itself.`, 4, 11), + }) +} +func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectlyMultiple(t *testing.T) { + expectFailsRule(t, graphql.NoFragmentCyclesRule, ` + fragment fragA on Dog { ...fragB } + fragment fragB on Dog { ...fragA } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot spread fragment "fragA" within itself via fragB.`, 2, 31, 3, 31), + }) +} +func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectlyWithinInlineFragmentMultiple(t *testing.T) { + expectFailsRule(t, graphql.NoFragmentCyclesRule, ` + fragment fragA on Pet { + ... on Dog { + ...fragB + } + } + fragment fragB on Pet { + ... on Dog { + ...fragA + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot spread fragment "fragA" within itself via fragB.`, 4, 11, 9, 11), + }) +} +func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDeeply(t *testing.T) { + expectFailsRule(t, graphql.NoFragmentCyclesRule, ` + fragment fragA on Dog { ...fragB } + fragment fragB on Dog { ...fragC } + fragment fragC on Dog { ...fragO } + fragment fragX on Dog { ...fragY } + fragment fragY on Dog { ...fragZ } + fragment fragZ on Dog { ...fragO } + fragment fragO on Dog { ...fragA, ...fragX } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot spread fragment "fragA" within itself via fragB, fragC, fragO.`, 2, 31, 3, 31, 4, 31, 8, 31), + ruleError(`Cannot spread fragment "fragX" within itself via fragY, fragZ, fragO.`, 5, 31, 6, 31, 7, 31, 8, 41), + }) +} +func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDeeplyTwoPaths(t *testing.T) { + expectFailsRule(t, graphql.NoFragmentCyclesRule, ` + fragment fragA on Dog { ...fragB, ...fragC } + fragment fragB on Dog { ...fragA } + fragment fragC on Dog { ...fragA } + `, []gqlerrors.FormattedError{ + ruleError(`Cannot spread fragment "fragA" within itself via fragB.`, 2, 31, 3, 31), + ruleError(`Cannot spread fragment "fragA" within itself via fragC.`, 2, 41, 4, 31), + }) +} diff --git a/type_info.go b/type_info.go index 9a95a529..458e2bdd 100644 --- a/type_info.go +++ b/type_info.go @@ -79,6 +79,7 @@ func (ti *TypeInfo) Enter(node ast.Node) { var fieldDef *FieldDefinition if parentType != nil { fieldDef = getTypeInfoFieldDef(*schema, parentType.(Type), node) + } else { } ti.fieldDefStack = append(ti.fieldDefStack, fieldDef) if fieldDef != nil { @@ -212,22 +213,22 @@ func getTypeInfoFieldDef(schema Schema, parentType Type, fieldAST *ast.Field) *F return TypeMetaFieldDef } if name == TypeNameMetaFieldDef.Name { - if _, ok := parentType.(*Object); ok { + if _, ok := parentType.(*Object); ok && parentType != nil { return TypeNameMetaFieldDef } - if _, ok := parentType.(*Interface); ok { + if _, ok := parentType.(*Interface); ok && parentType != nil { return TypeNameMetaFieldDef } - if _, ok := parentType.(*Union); ok { + if _, ok := parentType.(*Union); ok && parentType != nil { return TypeNameMetaFieldDef } } - if parentType, ok := parentType.(*Object); ok { + if parentType, ok := parentType.(*Object); ok && parentType != nil { field, _ := parentType.GetFields()[name] return field } - if parentType, ok := parentType.(*Interface); ok { + if parentType, ok := parentType.(*Interface); ok && parentType != nil { field, _ := parentType.GetFields()[name] return field } diff --git a/validator.go b/validator.go index 2490f7bc..cdbf57ac 100644 --- a/validator.go +++ b/validator.go @@ -72,6 +72,10 @@ func visitUsingRules(schema *Schema, astDoc *ast.Document, rules []ValidationRul errors = append(errors, gqlerrors.FormatError(err)) action = visitor.ActionSkip } + if err, ok := result.([]error); ok && err != nil { + errors = append(errors, gqlerrors.FormatErrors(err...)...) + action = visitor.ActionSkip + } // If any validation instances provide the flag `visitSpreadFragments` // and this node is a fragment spread, visit the fragment definition @@ -119,6 +123,10 @@ func visitUsingRules(schema *Schema, astDoc *ast.Document, rules []ValidationRul errors = append(errors, gqlerrors.FormatError(err)) action = visitor.ActionSkip } + if err, ok := result.([]error); ok && err != nil { + errors = append(errors, gqlerrors.FormatErrors(err...)...) + action = visitor.ActionSkip + } // Update typeInfo. typeInfo.Leave(node) From 4c94ee360b827c576b66547ab0a6372db187fd6d Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Fri, 13 Nov 2015 01:02:26 +0800 Subject: [PATCH 19/41] Implemented `NoUndefinedVariablesRule` --- rules.go | 90 +++++++++ rules/no_undefined_variables_test.go | 270 +++++++++++++++++++++++++++ validator.go | 5 +- 3 files changed, 363 insertions(+), 2 deletions(-) create mode 100644 rules/no_undefined_variables_test.go diff --git a/rules.go b/rules.go index 7357b9af..053ad308 100644 --- a/rules.go +++ b/rules.go @@ -24,6 +24,7 @@ var SpecifiedRules = []ValidationRuleFn{ KnownTypeNamesRule, LoneAnonymousOperationRule, NoFragmentCyclesRule, + NoUndefinedVariablesRule, } type ValidationRuleInstance struct { @@ -615,6 +616,95 @@ func NoFragmentCyclesRule(context *ValidationContext) *ValidationRuleInstance { } } +/** + * NoUndefinedVariables + * No undefined variables + * + * A GraphQL operation is only valid if all variables encountered, both directly + * and via fragment spreads, are defined by that operation. + */ +func NoUndefinedVariablesRule(context *ValidationContext) *ValidationRuleInstance { + var operation *ast.OperationDefinition + var visitedFragmentNames = map[string]bool{} + var definedVariableNames = map[string]bool{} + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.OperationDefinition: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.OperationDefinition); ok && node != nil { + operation = node + visitedFragmentNames = map[string]bool{} + definedVariableNames = map[string]bool{} + } + return visitor.ActionNoChange, nil + }, + }, + kinds.VariableDefinition: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.VariableDefinition); ok && node != nil { + variableName := "" + if node.Variable != nil && node.Variable.Name != nil { + variableName = node.Variable.Name.Value + } + definedVariableNames[variableName] = true + } + return visitor.ActionNoChange, nil + }, + }, + kinds.Variable: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if variable, ok := p.Node.(*ast.Variable); ok && variable != nil { + variableName := "" + if variable.Name != nil { + variableName = variable.Name.Value + } + if val, _ := definedVariableNames[variableName]; !val { + withinFragment := false + for _, node := range p.Ancestors { + if node.GetKind() == kinds.FragmentDefinition { + withinFragment = true + break + } + } + if withinFragment == true && operation != nil && operation.Name != nil { + return newValidationRuleError( + fmt.Sprintf(`Variable "$%v" is not defined by operation "%v".`, variableName, operation.Name.Value), + []ast.Node{variable, operation}, + ) + } + return newValidationRuleError( + fmt.Sprintf(`Variable "$%v" is not defined.`, variableName), + []ast.Node{variable}, + ) + } + } + return visitor.ActionNoChange, nil + }, + }, + kinds.FragmentSpread: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.FragmentSpread); ok && node != nil { + // Only visit fragments of a particular name once per operation + fragmentName := "" + if node.Name != nil { + fragmentName = node.Name.Value + } + if val, ok := visitedFragmentNames[fragmentName]; ok && val == true { + return visitor.ActionSkip, nil + } + visitedFragmentNames[fragmentName] = true + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitSpreadFragments: true, + VisitorOpts: visitorOpts, + } +} + /** * Utility for validators which determines if a value literal AST is valid given * an input type. diff --git a/rules/no_undefined_variables_test.go b/rules/no_undefined_variables_test.go new file mode 100644 index 00000000..6b1cd563 --- /dev/null +++ b/rules/no_undefined_variables_test.go @@ -0,0 +1,270 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_NoUndefinedVariables_AllVariablesDefined(t *testing.T) { + expectPassesRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($a: String, $b: String, $c: String) { + field(a: $a, b: $b, c: $c) + } + `) +} +func TestValidate_NoUndefinedVariables_AllVariablesDeeplyDefined(t *testing.T) { + expectPassesRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($a: String, $b: String, $c: String) { + field(a: $a) { + field(b: $b) { + field(c: $c) + } + } + } + `) +} +func TestValidate_NoUndefinedVariables_AllVariablesDeeplyDefinedInInlineFragmentsDefined(t *testing.T) { + expectPassesRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($a: String, $b: String, $c: String) { + ... on Type { + field(a: $a) { + field(b: $b) { + ... on Type { + field(c: $c) + } + } + } + } + } + `) +} +func TestValidate_NoUndefinedVariables_AllVariablesInFragmentsDeeplyDefined(t *testing.T) { + expectPassesRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($a: String, $b: String, $c: String) { + ...FragA + } + fragment FragA on Type { + field(a: $a) { + ...FragB + } + } + fragment FragB on Type { + field(b: $b) { + ...FragC + } + } + fragment FragC on Type { + field(c: $c) + } + `) +} +func TestValidate_NoUndefinedVariables_VariablesWithinSingleFragmentDefinedInMultipleOperations(t *testing.T) { + expectPassesRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($a: String) { + ...FragA + } + query Bar($a: String) { + ...FragA + } + fragment FragA on Type { + field(a: $a) + } + `) +} +func TestValidate_NoUndefinedVariables_VariableWithinFragmentsDefinedInOperations(t *testing.T) { + expectPassesRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($a: String) { + ...FragA + } + query Bar($b: String) { + ...FragB + } + fragment FragA on Type { + field(a: $a) + } + fragment FragB on Type { + field(b: $b) + } + `) +} +func TestValidate_NoUndefinedVariables_VariableWithinRecursiveFragmentDefined(t *testing.T) { + expectPassesRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($a: String) { + ...FragA + } + fragment FragA on Type { + field(a: $a) { + ...FragA + } + } + `) +} +func TestValidate_NoUndefinedVariables_VariableNotDefined(t *testing.T) { + expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($a: String, $b: String, $c: String) { + field(a: $a, b: $b, c: $c, d: $d) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$d" is not defined.`, 3, 39), + }) +} +func TestValidate_NoUndefinedVariables_VariableNotDefinedByUnnamedQuery(t *testing.T) { + expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + { + field(a: $a) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$a" is not defined.`, 3, 18), + }) +} +func TestValidate_NoUndefinedVariables_MultipleVariablesNotDefined(t *testing.T) { + expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($b: String) { + field(a: $a, b: $b, c: $c) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$a" is not defined.`, 3, 18), + ruleError(`Variable "$c" is not defined.`, 3, 32), + }) +} + +func TestValidate_NoUndefinedVariables_VariableInFragmentNotDefinedByUnnamedQuery(t *testing.T) { + expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + { + ...FragA + } + fragment FragA on Type { + field(a: $a) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$a" is not defined.`, 6, 18), + }) +} + +func TestValidate_NoUndefinedVariables_VariableInFragmentNotDefinedByOperation(t *testing.T) { + expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($a: String, $b: String) { + ...FragA + } + fragment FragA on Type { + field(a: $a) { + ...FragB + } + } + fragment FragB on Type { + field(b: $b) { + ...FragC + } + } + fragment FragC on Type { + field(c: $c) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$c" is not defined by operation "Foo".`, 16, 18, 2, 7), + }) +} + +func TestValidate_NoUndefinedVariables_MultipleVariablesInFragmentsNotDefined(t *testing.T) { + expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($b: String) { + ...FragA + } + fragment FragA on Type { + field(a: $a) { + ...FragB + } + } + fragment FragB on Type { + field(b: $b) { + ...FragC + } + } + fragment FragC on Type { + field(c: $c) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$a" is not defined by operation "Foo".`, 6, 18, 2, 7), + ruleError(`Variable "$c" is not defined by operation "Foo".`, 16, 18, 2, 7), + }) +} + +func TestValidate_NoUndefinedVariables_SingleVariableInFragmentNotDefinedByMultipleOperations(t *testing.T) { + expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($a: String) { + ...FragAB + } + query Bar($a: String) { + ...FragAB + } + fragment FragAB on Type { + field(a: $a, b: $b) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$b" is not defined by operation "Foo".`, 9, 25, 2, 7), + ruleError(`Variable "$b" is not defined by operation "Bar".`, 9, 25, 5, 7), + }) +} + +func TestValidate_NoUndefinedVariables_VariablesInFragmentNotDefinedByMultipleOperations(t *testing.T) { + expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($b: String) { + ...FragAB + } + query Bar($a: String) { + ...FragAB + } + fragment FragAB on Type { + field(a: $a, b: $b) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$a" is not defined by operation "Foo".`, 9, 18, 2, 7), + ruleError(`Variable "$b" is not defined by operation "Bar".`, 9, 25, 5, 7), + }) +} +func TestValidate_NoUndefinedVariables_VariableInFragmentUsedByOtherOperation(t *testing.T) { + expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($b: String) { + ...FragA + } + query Bar($a: String) { + ...FragB + } + fragment FragA on Type { + field(a: $a) + } + fragment FragB on Type { + field(b: $b) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$a" is not defined by operation "Foo".`, 9, 18, 2, 7), + ruleError(`Variable "$b" is not defined by operation "Bar".`, 12, 18, 5, 7), + }) +} + +func TestValidate_NoUndefinedVariables_VaMultipleUndefinedVariablesProduceMultipleErrors(t *testing.T) { + expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + query Foo($b: String) { + ...FragAB + } + query Bar($a: String) { + ...FragAB + } + fragment FragAB on Type { + field1(a: $a, b: $b) + ...FragC + field3(a: $a, b: $b) + } + fragment FragC on Type { + field2(c: $c) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$a" is not defined by operation "Foo".`, 9, 19, 2, 7), + ruleError(`Variable "$c" is not defined by operation "Foo".`, 14, 19, 2, 7), + ruleError(`Variable "$a" is not defined by operation "Foo".`, 11, 19, 2, 7), + ruleError(`Variable "$b" is not defined by operation "Bar".`, 9, 26, 5, 7), + ruleError(`Variable "$c" is not defined by operation "Bar".`, 14, 19, 5, 7), + ruleError(`Variable "$b" is not defined by operation "Bar".`, 11, 26, 5, 7), + }) +} diff --git a/validator.go b/validator.go index cdbf57ac..2fcaff15 100644 --- a/validator.go +++ b/validator.go @@ -80,7 +80,8 @@ func visitUsingRules(schema *Schema, astDoc *ast.Document, rules []ValidationRul // If any validation instances provide the flag `visitSpreadFragments` // and this node is a fragment spread, visit the fragment definition // from this point. - if result == nil && instance.VisitSpreadFragments == true && kind == kinds.FragmentSpread { + if action == visitor.ActionNoChange && result == nil && + instance.VisitSpreadFragments == true && kind == kinds.FragmentSpread { node, _ := node.(*ast.FragmentSpread) name := node.Name nameVal := "" @@ -93,7 +94,7 @@ func visitUsingRules(schema *Schema, astDoc *ast.Document, rules []ValidationRul } } - // If the result is "false" (ie action === Action.Skip, we're not visiting any descendent nodes, + // If the result is "false" (ie action === Action.Skip), we're not visiting any descendent nodes, // but need to update typeInfo. if action == visitor.ActionSkip { typeInfo.Leave(node) From d2f6f2c2cb71a178680e15ddd5b82dcaea64ca9e Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Sun, 15 Nov 2015 10:41:06 +0800 Subject: [PATCH 20/41] Implemented `NoUnusedFragmentsRule` and tested --- rules.go | 103 ++++++++++++++++++++++ rules/no_unused_fragments_test.go | 139 ++++++++++++++++++++++++++++++ validator.go | 6 +- 3 files changed, 245 insertions(+), 3 deletions(-) create mode 100644 rules/no_unused_fragments_test.go diff --git a/rules.go b/rules.go index 053ad308..057d0f10 100644 --- a/rules.go +++ b/rules.go @@ -25,6 +25,7 @@ var SpecifiedRules = []ValidationRuleFn{ LoneAnonymousOperationRule, NoFragmentCyclesRule, NoUndefinedVariablesRule, + NoUnusedFragmentsRule, } type ValidationRuleInstance struct { @@ -705,6 +706,108 @@ func NoUndefinedVariablesRule(context *ValidationContext) *ValidationRuleInstanc } } +/** + * NoUnusedFragmentsRule + * No unused fragments + * + * A GraphQL document is only valid if all fragment definitions are spread + * within operations, or spread within other fragments spread within operations. + */ +func NoUnusedFragmentsRule(context *ValidationContext) *ValidationRuleInstance { + + var fragmentDefs = []*ast.FragmentDefinition{} + var spreadsWithinOperation = []map[string]bool{} + var fragAdjacencies = map[string]map[string]bool{} + var spreadNames = map[string]bool{} + + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.OperationDefinition: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.OperationDefinition); ok && node != nil { + spreadNames = map[string]bool{} + spreadsWithinOperation = append(spreadsWithinOperation, spreadNames) + } + return visitor.ActionNoChange, nil + }, + }, + kinds.FragmentDefinition: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if def, ok := p.Node.(*ast.FragmentDefinition); ok && def != nil { + defName := "" + if def.Name != nil { + defName = def.Name.Value + } + + fragmentDefs = append(fragmentDefs, def) + spreadNames = map[string]bool{} + fragAdjacencies[defName] = spreadNames + } + return visitor.ActionNoChange, nil + }, + }, + kinds.FragmentSpread: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if spread, ok := p.Node.(*ast.FragmentSpread); ok && spread != nil { + spreadName := "" + if spread.Name != nil { + spreadName = spread.Name.Value + } + spreadNames[spreadName] = true + } + return visitor.ActionNoChange, nil + }, + }, + kinds.Document: visitor.NamedVisitFuncs{ + Leave: func(p visitor.VisitFuncParams) (string, interface{}) { + + fragmentNameUsed := map[string]interface{}{} + + var reduceSpreadFragments func(spreads map[string]bool) + reduceSpreadFragments = func(spreads map[string]bool) { + for fragName, _ := range spreads { + if isFragNameUsed, _ := fragmentNameUsed[fragName]; isFragNameUsed != true { + fragmentNameUsed[fragName] = true + + if adjacencies, ok := fragAdjacencies[fragName]; ok { + reduceSpreadFragments(adjacencies) + } + } + } + } + for _, spreadWithinOperation := range spreadsWithinOperation { + reduceSpreadFragments(spreadWithinOperation) + } + errors := []error{} + for _, def := range fragmentDefs { + defName := "" + if def.Name != nil { + defName = def.Name.Value + } + + isFragNameUsed, ok := fragmentNameUsed[defName] + if !ok || isFragNameUsed != true { + _, err := newValidationRuleError( + fmt.Sprintf(`Fragment "%v" is never used.`, defName), + []ast.Node{def}, + ) + + errors = append(errors, err) + } + } + if len(errors) > 0 { + return visitor.ActionNoChange, errors + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + /** * Utility for validators which determines if a value literal AST is valid given * an input type. diff --git a/rules/no_unused_fragments_test.go b/rules/no_unused_fragments_test.go new file mode 100644 index 00000000..38369e31 --- /dev/null +++ b/rules/no_unused_fragments_test.go @@ -0,0 +1,139 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_NoUnusedFragments_AllFragmentNamesAreUsed(t *testing.T) { + expectPassesRule(t, graphql.NoUnusedFragmentsRule, ` + { + human(id: 4) { + ...HumanFields1 + ... on Human { + ...HumanFields2 + } + } + } + fragment HumanFields1 on Human { + name + ...HumanFields3 + } + fragment HumanFields2 on Human { + name + } + fragment HumanFields3 on Human { + name + } + `) +} +func TestValidate_NoUnusedFragments_AllFragmentNamesAreUsedByMultipleOperations(t *testing.T) { + expectPassesRule(t, graphql.NoUnusedFragmentsRule, ` + query Foo { + human(id: 4) { + ...HumanFields1 + } + } + query Bar { + human(id: 4) { + ...HumanFields2 + } + } + fragment HumanFields1 on Human { + name + ...HumanFields3 + } + fragment HumanFields2 on Human { + name + } + fragment HumanFields3 on Human { + name + } + `) +} +func TestValidate_NoUnusedFragments_ContainsUnknownFragments(t *testing.T) { + expectFailsRule(t, graphql.NoUnusedFragmentsRule, ` + query Foo { + human(id: 4) { + ...HumanFields1 + } + } + query Bar { + human(id: 4) { + ...HumanFields2 + } + } + fragment HumanFields1 on Human { + name + ...HumanFields3 + } + fragment HumanFields2 on Human { + name + } + fragment HumanFields3 on Human { + name + } + fragment Unused1 on Human { + name + } + fragment Unused2 on Human { + name + } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "Unused1" is never used.`, 22, 7), + ruleError(`Fragment "Unused2" is never used.`, 25, 7), + }) +} + +func TestValidate_NoUnusedFragments_ContainsUnknownFragmentsWithRefCycle(t *testing.T) { + expectFailsRule(t, graphql.NoUnusedFragmentsRule, ` + query Foo { + human(id: 4) { + ...HumanFields1 + } + } + query Bar { + human(id: 4) { + ...HumanFields2 + } + } + fragment HumanFields1 on Human { + name + ...HumanFields3 + } + fragment HumanFields2 on Human { + name + } + fragment HumanFields3 on Human { + name + } + fragment Unused1 on Human { + name + ...Unused2 + } + fragment Unused2 on Human { + name + ...Unused1 + } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "Unused1" is never used.`, 22, 7), + ruleError(`Fragment "Unused2" is never used.`, 26, 7), + }) +} + +func TestValidate_NoUnusedFragments_ContainsUnknownAndUndefFragments(t *testing.T) { + expectFailsRule(t, graphql.NoUnusedFragmentsRule, ` + query Foo { + human(id: 4) { + ...bar + } + } + fragment foo on Human { + name + } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "foo" is never used.`, 7, 7), + }) +} diff --git a/validator.go b/validator.go index 2fcaff15..9b32f7ec 100644 --- a/validator.go +++ b/validator.go @@ -179,11 +179,11 @@ func (ctx *ValidationContext) GetFragment(name string) *ast.FragmentDefinition { fragments := map[string]*ast.FragmentDefinition{} for _, def := range defs { if def, ok := def.(*ast.FragmentDefinition); ok { - name := "" + defName := "" if def.Name != nil { - name = def.Name.Value + defName = def.Name.Value } - fragments[name] = def + fragments[defName] = def } } ctx.fragments = fragments From d0063b31cd331a4f62c618cc65f2afd1bf1d8a96 Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Tue, 17 Nov 2015 18:03:37 +0800 Subject: [PATCH 21/41] Implemented `OverlappingFieldsCanBeMergedRule` and tested --- rules.go | 411 ++++++++++++++++++ rules/harness_test.go | 8 + .../overlapping_fields_can_be_merged_test.go | 409 +++++++++++++++++ values.go | 2 +- 4 files changed, 829 insertions(+), 1 deletion(-) create mode 100644 rules/overlapping_fields_can_be_merged_test.go diff --git a/rules.go b/rules.go index 057d0f10..4d8fc4bf 100644 --- a/rules.go +++ b/rules.go @@ -7,6 +7,7 @@ import ( "github.com/graphql-go/graphql/language/kinds" "github.com/graphql-go/graphql/language/printer" "github.com/graphql-go/graphql/language/visitor" + "sort" "strings" ) @@ -26,6 +27,7 @@ var SpecifiedRules = []ValidationRuleFn{ NoFragmentCyclesRule, NoUndefinedVariablesRule, NoUnusedFragmentsRule, + OverlappingFieldsCanBeMergedRule, } type ValidationRuleInstance struct { @@ -808,6 +810,415 @@ func NoUnusedFragmentsRule(context *ValidationContext) *ValidationRuleInstance { } } +type fieldDefPair struct { + Field *ast.Field + FieldDef *FieldDefinition +} + +func collectFieldASTsAndDefs(context *ValidationContext, parentType Named, selectionSet *ast.SelectionSet, visitedFragmentNames map[string]bool, astAndDefs map[string][]*fieldDefPair) map[string][]*fieldDefPair { + + if astAndDefs == nil { + astAndDefs = map[string][]*fieldDefPair{} + } + if visitedFragmentNames == nil { + visitedFragmentNames = map[string]bool{} + } + if selectionSet == nil { + return astAndDefs + } + for _, selection := range selectionSet.Selections { + switch selection := selection.(type) { + case *ast.Field: + fieldName := "" + if selection.Name != nil { + fieldName = selection.Name.Value + } + var fieldDef *FieldDefinition + if parentType, ok := parentType.(*Object); ok { + fieldDef, _ = parentType.GetFields()[fieldName] + } + if parentType, ok := parentType.(*Interface); ok { + fieldDef, _ = parentType.GetFields()[fieldName] + } + + responseName := fieldName + if selection.Alias != nil { + responseName = selection.Alias.Value + } + _, ok := astAndDefs[responseName] + if !ok { + astAndDefs[responseName] = []*fieldDefPair{} + } + astAndDefs[responseName] = append(astAndDefs[responseName], &fieldDefPair{ + Field: selection, + FieldDef: fieldDef, + }) + case *ast.InlineFragment: + parentType, _ := typeFromAST(*context.GetSchema(), selection.TypeCondition) + astAndDefs = collectFieldASTsAndDefs( + context, + parentType, + selection.SelectionSet, + visitedFragmentNames, + astAndDefs, + ) + case *ast.FragmentSpread: + fragName := "" + if selection.Name != nil { + fragName = selection.Name.Value + } + if _, ok := visitedFragmentNames[fragName]; ok { + continue + } + visitedFragmentNames[fragName] = true + fragment := context.GetFragment(fragName) + if fragment == nil { + continue + } + parentType, _ := typeFromAST(*context.GetSchema(), fragment.TypeCondition) + astAndDefs = collectFieldASTsAndDefs( + context, + parentType, + fragment.SelectionSet, + visitedFragmentNames, + astAndDefs, + ) + } + } + return astAndDefs +} + +/** + * pairSet A way to keep track of pairs of things when the ordering of the pair does + * not matter. We do this by maintaining a sort of double adjacency sets. + */ +type pairSet struct { + data map[ast.Node]*nodeSet +} + +func newPairSet() *pairSet { + return &pairSet{ + data: map[ast.Node]*nodeSet{}, + } +} +func (pair *pairSet) Has(a ast.Node, b ast.Node) bool { + first, ok := pair.data[a] + if !ok || first == nil { + return false + } + res := first.Has(b) + return res +} +func (pair *pairSet) Add(a ast.Node, b ast.Node) bool { + pair.data = pairSetAdd(pair.data, a, b) + pair.data = pairSetAdd(pair.data, b, a) + return true +} + +func pairSetAdd(data map[ast.Node]*nodeSet, a, b ast.Node) map[ast.Node]*nodeSet { + set, ok := data[a] + if !ok || set == nil { + set = newNodeSet() + data[a] = set + } + set.Add(b) + return data +} + +type conflictReason struct { + Name string + Message interface{} // conflictReason || []conflictReason +} +type conflict struct { + Reason conflictReason + Fields []ast.Node +} + +func sameDirectives(directives1 []*ast.Directive, directives2 []*ast.Directive) bool { + if len(directives1) != len(directives1) { + return false + } + for _, directive1 := range directives1 { + directive1Name := "" + if directive1.Name != nil { + directive1Name = directive1.Name.Value + } + + var foundDirective2 *ast.Directive + for _, directive2 := range directives2 { + directive2Name := "" + if directive2.Name != nil { + directive2Name = directive2.Name.Value + } + if directive1Name == directive2Name { + foundDirective2 = directive2 + } + break + } + if foundDirective2 == nil { + return false + } + if sameArguments(directive1.Arguments, foundDirective2.Arguments) == false { + return false + } + } + + return true +} +func sameArguments(args1 []*ast.Argument, args2 []*ast.Argument) bool { + if len(args1) != len(args2) { + return false + } + + for _, arg1 := range args1 { + arg1Name := "" + if arg1.Name != nil { + arg1Name = arg1.Name.Value + } + + var foundArgs2 *ast.Argument + for _, arg2 := range args2 { + arg2Name := "" + if arg2.Name != nil { + arg2Name = arg2.Name.Value + } + if arg1Name == arg2Name { + foundArgs2 = arg2 + } + break + } + if foundArgs2 == nil { + return false + } + if sameValue(arg1.Value, foundArgs2.Value) == false { + return false + } + } + + return true +} +func sameValue(value1 ast.Value, value2 ast.Value) bool { + if value1 == nil && value2 == nil { + return true + } + val1 := printer.Print(value1) + val2 := printer.Print(value2) + + return val1 == val2 +} +func sameType(type1 Type, type2 Type) bool { + t := fmt.Sprintf("%v", type1) + t2 := fmt.Sprintf("%v", type2) + return t == t2 +} + +/** + * OverlappingFieldsCanBeMergedRule + * Overlapping fields can be merged + * + * A selection set is only valid if all fields (including spreading any + * fragments) either correspond to distinct response names or can be merged + * without ambiguity. + */ +func OverlappingFieldsCanBeMergedRule(context *ValidationContext) *ValidationRuleInstance { + + comparedSet := newPairSet() + var findConflicts func(fieldMap map[string][]*fieldDefPair) (conflicts []*conflict) + findConflict := func(responseName string, pair *fieldDefPair, pair2 *fieldDefPair) *conflict { + + ast1 := pair.Field + def1 := pair.FieldDef + + ast2 := pair2.Field + def2 := pair2.FieldDef + + if ast1 == ast2 || comparedSet.Has(ast1, ast2) { + return nil + } + comparedSet.Add(ast1, ast2) + + name1 := "" + if ast1.Name != nil { + name1 = ast1.Name.Value + } + name2 := "" + if ast2.Name != nil { + name2 = ast2.Name.Value + } + if name1 != name2 { + return &conflict{ + Reason: conflictReason{ + Name: responseName, + Message: fmt.Sprintf(`%v and %v are different fields`, name1, name2), + }, + Fields: []ast.Node{ast1, ast2}, + } + } + + var type1 Type + var type2 Type + if def1 != nil { + type1 = def1.Type + } + if def2 != nil { + type2 = def2.Type + } + + if type1 != nil && type2 != nil && !sameType(type1, type2) { + return &conflict{ + Reason: conflictReason{ + Name: responseName, + Message: fmt.Sprintf(`they return differing types %v and %v`, type1, type2), + }, + Fields: []ast.Node{ast1, ast2}, + } + } + if !sameArguments(ast1.Arguments, ast2.Arguments) { + return &conflict{ + Reason: conflictReason{ + Name: responseName, + Message: `they have differing arguments`, + }, + Fields: []ast.Node{ast1, ast2}, + } + } + if !sameDirectives(ast1.Directives, ast2.Directives) { + return &conflict{ + Reason: conflictReason{ + Name: responseName, + Message: `they have differing directives`, + }, + Fields: []ast.Node{ast1, ast2}, + } + } + + selectionSet1 := ast1.SelectionSet + selectionSet2 := ast2.SelectionSet + if selectionSet1 != nil && selectionSet2 != nil { + visitedFragmentNames := map[string]bool{} + subfieldMap := collectFieldASTsAndDefs( + context, + GetNamed(type1), + selectionSet1, + visitedFragmentNames, + nil, + ) + subfieldMap = collectFieldASTsAndDefs( + context, + GetNamed(type2), + selectionSet2, + visitedFragmentNames, + subfieldMap, + ) + conflicts := findConflicts(subfieldMap) + if len(conflicts) > 0 { + + conflictReasons := []conflictReason{} + conflictFields := []ast.Node{ast1, ast2} + for _, c := range conflicts { + conflictReasons = append(conflictReasons, c.Reason) + conflictFields = append(conflictFields, c.Fields...) + } + + return &conflict{ + Reason: conflictReason{ + Name: responseName, + Message: conflictReasons, + }, + Fields: conflictFields, + } + } + } + return nil + } + + findConflicts = func(fieldMap map[string][]*fieldDefPair) (conflicts []*conflict) { + + // ensure field traversal + orderedName := sort.StringSlice{} + for responseName, _ := range fieldMap { + orderedName = append(orderedName, responseName) + } + orderedName.Sort() + + for _, responseName := range orderedName { + fields, _ := fieldMap[responseName] + for _, fieldA := range fields { + for _, fieldB := range fields { + c := findConflict(responseName, fieldA, fieldB) + if c != nil { + conflicts = append(conflicts, c) + } + } + } + } + return conflicts + } + + var reasonMessage func(message interface{}) string + reasonMessage = func(message interface{}) string { + switch reason := message.(type) { + case string: + return reason + case conflictReason: + return reasonMessage(reason.Message) + case []conflictReason: + messages := []string{} + for _, r := range reason { + messages = append(messages, fmt.Sprintf( + `subfields "%v" conflict because %v`, + r.Name, + reasonMessage(r.Message), + )) + } + return strings.Join(messages, " and ") + } + return "" + } + + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.SelectionSet: visitor.NamedVisitFuncs{ + Leave: func(p visitor.VisitFuncParams) (string, interface{}) { + if selectionSet, ok := p.Node.(*ast.SelectionSet); ok && selectionSet != nil { + parentType, _ := context.GetParentType().(Named) + fieldMap := collectFieldASTsAndDefs( + context, + parentType, + selectionSet, + nil, + nil, + ) + conflicts := findConflicts(fieldMap) + if len(conflicts) > 0 { + errors := []error{} + for _, c := range conflicts { + responseName := c.Reason.Name + reason := c.Reason + _, err := newValidationRuleError( + fmt.Sprintf( + `Fields "%v" conflict because %v.`, + responseName, + reasonMessage(reason), + ), + c.Fields, + ) + errors = append(errors, err) + + } + return visitor.ActionNoChange, errors + } + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + /** * Utility for validators which determines if a value literal AST is valid given * an input type. diff --git a/rules/harness_test.go b/rules/harness_test.go index 80974041..9001b27c 100644 --- a/rules/harness_test.go +++ b/rules/harness_test.go @@ -497,6 +497,14 @@ func expectFailsRule(t *testing.T, rule graphql.ValidationRuleFn, queryString st expectInvalid(t, defaultSchema, []graphql.ValidationRuleFn{rule}, queryString, expectedErrors) } +func expectFailsRuleWithSchema(t *testing.T, schema *graphql.Schema, rule graphql.ValidationRuleFn, queryString string, expectedErrors []gqlerrors.FormattedError) { + expectInvalid(t, schema, []graphql.ValidationRuleFn{rule}, queryString, expectedErrors) +} + +func expectPassesRuleWithSchema(t *testing.T, schema *graphql.Schema, rule graphql.ValidationRuleFn, queryString string) { + expectValid(t, schema, []graphql.ValidationRuleFn{rule}, queryString) +} + func ruleError(message string, locs ...int) gqlerrors.FormattedError { locations := []location.SourceLocation{} for i := 0; i < len(locs); i = i + 2 { diff --git a/rules/overlapping_fields_can_be_merged_test.go b/rules/overlapping_fields_can_be_merged_test.go new file mode 100644 index 00000000..2749c22c --- /dev/null +++ b/rules/overlapping_fields_can_be_merged_test.go @@ -0,0 +1,409 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_OverlappingFieldsCanBeMerged_UniqueFields(t *testing.T) { + expectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + fragment uniqueFields on Dog { + name + nickname + } + `) +} +func TestValidate_OverlappingFieldsCanBeMerged_IdenticalFields(t *testing.T) { + expectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + fragment mergeIdenticalFields on Dog { + name + name + } + `) +} +func TestValidate_OverlappingFieldsCanBeMerged_IdenticalFieldsWithIdenticalArgs(t *testing.T) { + expectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + fragment mergeIdenticalFieldsWithIdenticalArgs on Dog { + doesKnowCommand(dogCommand: SIT) + doesKnowCommand(dogCommand: SIT) + } + `) +} +func TestValidate_OverlappingFieldsCanBeMerged_IdenticalFieldsWithIdenticalDirectives(t *testing.T) { + expectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + fragment mergeSameFieldsWithSameDirectives on Dog { + name @include(if: true) + name @include(if: true) + } + `) +} +func TestValidate_OverlappingFieldsCanBeMerged_DifferentArgsWithDifferentAliases(t *testing.T) { + expectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + fragment differentArgsWithDifferentAliases on Dog { + knowsSit: doesKnowCommand(dogCommand: SIT) + knowsDown: doesKnowCommand(dogCommand: DOWN) + } + `) +} +func TestValidate_OverlappingFieldsCanBeMerged_DifferentDirectivesWithDifferentAliases(t *testing.T) { + expectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + fragment differentDirectivesWithDifferentAliases on Dog { + nameIfTrue: name @include(if: true) + nameIfFalse: name @include(if: false) + } + `) +} +func TestValidate_OverlappingFieldsCanBeMerged_SameAliasesWithDifferentFieldTargets(t *testing.T) { + expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + fragment sameAliasesWithDifferentFieldTargets on Dog { + fido: name + fido: nickname + } + `, []gqlerrors.FormattedError{ + ruleError(`Fields "fido" conflict because name and nickname are different fields.`, 3, 9, 4, 9), + }) +} +func TestValidate_OverlappingFieldsCanBeMerged_AliasMakingDirectFieldAccess(t *testing.T) { + expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + fragment aliasMaskingDirectFieldAccess on Dog { + name: nickname + name + } + `, []gqlerrors.FormattedError{ + ruleError(`Fields "name" conflict because nickname and name are different fields.`, 3, 9, 4, 9), + }) +} +func TestValidate_OverlappingFieldsCanBeMerged_ConflictingArgs(t *testing.T) { + expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + fragment conflictingArgs on Dog { + doesKnowCommand(dogCommand: SIT) + doesKnowCommand(dogCommand: HEEL) + } + `, []gqlerrors.FormattedError{ + ruleError(`Fields "doesKnowCommand" conflict because they have differing arguments.`, 3, 9, 4, 9), + }) +} +func TestValidate_OverlappingFieldsCanBeMerged_ConflictingDirectives(t *testing.T) { + expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + fragment conflictingDirectiveArgs on Dog { + name @include(if: true) + name @skip(if: false) + } + `, []gqlerrors.FormattedError{ + ruleError(`Fields "name" conflict because they have differing directives.`, 3, 9, 4, 9), + }) +} +func TestValidate_OverlappingFieldsCanBeMerged_ConflictingDirectiveArgs(t *testing.T) { + expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + fragment conflictingDirectiveArgs on Dog { + name @include(if: true) + name @include(if: false) + } + `, []gqlerrors.FormattedError{ + ruleError(`Fields "name" conflict because they have differing directives.`, 3, 9, 4, 9), + }) +} +func TestValidate_OverlappingFieldsCanBeMerged_ConflictingArgsWithMatchingDirectives(t *testing.T) { + expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + fragment conflictingArgsWithMatchingDirectiveArgs on Dog { + doesKnowCommand(dogCommand: SIT) @include(if: true) + doesKnowCommand(dogCommand: HEEL) @include(if: true) + } + `, []gqlerrors.FormattedError{ + ruleError(`Fields "doesKnowCommand" conflict because they have differing arguments.`, 3, 9, 4, 9), + }) +} +func TestValidate_OverlappingFieldsCanBeMerged_ConflictingDirectivesWithMatchingArgs(t *testing.T) { + expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + fragment conflictingDirectiveArgsWithMatchingArgs on Dog { + doesKnowCommand(dogCommand: SIT) @include(if: true) + doesKnowCommand(dogCommand: SIT) @skip(if: false) + } + `, []gqlerrors.FormattedError{ + ruleError(`Fields "doesKnowCommand" conflict because they have differing directives.`, 3, 9, 4, 9), + }) +} +func TestValidate_OverlappingFieldsCanBeMerged_EncountersConflictInFragments(t *testing.T) { + expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + { + ...A + ...B + } + fragment A on Type { + x: a + } + fragment B on Type { + x: b + } + `, []gqlerrors.FormattedError{ + ruleError(`Fields "x" conflict because a and b are different fields.`, 7, 9, 10, 9), + }) +} +func TestValidate_OverlappingFieldsCanBeMerged_ReportsEachConflictOnce(t *testing.T) { + expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + { + f1 { + ...A + ...B + } + f2 { + ...B + ...A + } + f3 { + ...A + ...B + x: c + } + } + fragment A on Type { + x: a + } + fragment B on Type { + x: b + } + `, []gqlerrors.FormattedError{ + ruleError(`Fields "x" conflict because a and b are different fields.`, 18, 9, 21, 9), + ruleError(`Fields "x" conflict because a and c are different fields.`, 18, 9, 14, 11), + ruleError(`Fields "x" conflict because b and c are different fields.`, 21, 9, 14, 11), + }) +} +func TestValidate_OverlappingFieldsCanBeMerged_DeepConflict(t *testing.T) { + expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + { + field { + x: a + }, + field { + x: b + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Fields "field" conflict because subfields "x" conflict because a and b are different fields.`, + 3, 9, 6, 9, 4, 11, 7, 11), + }) +} +func TestValidate_OverlappingFieldsCanBeMerged_DeepConflictWithMultipleIssues(t *testing.T) { + expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + { + field { + x: a + y: c + }, + field { + x: b + y: d + } + } + `, []gqlerrors.FormattedError{ + ruleError( + `Fields "field" conflict because subfields "x" conflict because a and b are different fields and `+ + `subfields "y" conflict because c and d are different fields.`, + 3, 9, 7, 9, 4, 11, 8, 11, 5, 11, 9, 11), + }) +} +func TestValidate_OverlappingFieldsCanBeMerged_VeryDeepConflict(t *testing.T) { + expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + { + field { + deepField { + x: a + } + }, + field { + deepField { + x: b + } + } + } + `, []gqlerrors.FormattedError{ + ruleError( + `Fields "field" conflict because subfields "deepField" conflict because subfields "x" conflict because `+ + `a and b are different fields.`, + 3, 9, 8, 9, 4, 11, 9, 11, 5, 13, 10, 13), + }) +} +func TestValidate_OverlappingFieldsCanBeMerged_ReportsDeepConflictToNearestCommonAncestor(t *testing.T) { + expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + { + field { + deepField { + x: a + } + deepField { + x: b + } + }, + field { + deepField { + y + } + } + } + `, []gqlerrors.FormattedError{ + ruleError( + `Fields "deepField" conflict because subfields "x" conflict because `+ + `a and b are different fields.`, + 4, 11, 7, 11, 5, 13, 8, 13), + }) +} + +var stringBoxObject = graphql.NewObject(graphql.ObjectConfig{ + Name: "StringBox", + Fields: graphql.FieldConfigMap{ + "scalar": &graphql.FieldConfig{ + Type: graphql.String, + }, + }, +}) +var intBoxObject = graphql.NewObject(graphql.ObjectConfig{ + Name: "IntBox", + Fields: graphql.FieldConfigMap{ + "scalar": &graphql.FieldConfig{ + Type: graphql.Int, + }, + }, +}) +var nonNullStringBox1Object = graphql.NewObject(graphql.ObjectConfig{ + Name: "NonNullStringBox1", + Fields: graphql.FieldConfigMap{ + "scalar": &graphql.FieldConfig{ + Type: graphql.NewNonNull(graphql.String), + }, + }, +}) +var nonNullStringBox2Object = graphql.NewObject(graphql.ObjectConfig{ + Name: "NonNullStringBox2", + Fields: graphql.FieldConfigMap{ + "scalar": &graphql.FieldConfig{ + Type: graphql.NewNonNull(graphql.String), + }, + }, +}) +var boxUnionObject = graphql.NewUnion(graphql.UnionConfig{ + Name: "BoxUnion", + ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { + return stringBoxObject + }, + Types: []*graphql.Object{ + stringBoxObject, + intBoxObject, + nonNullStringBox1Object, + nonNullStringBox2Object, + }, +}) + +var connectionObject = graphql.NewObject(graphql.ObjectConfig{ + Name: "Connection", + Fields: graphql.FieldConfigMap{ + "edges": &graphql.FieldConfig{ + Type: graphql.NewList(graphql.NewObject(graphql.ObjectConfig{ + Name: "Edge", + Fields: graphql.FieldConfigMap{ + "node": &graphql.FieldConfig{ + Type: graphql.NewObject(graphql.ObjectConfig{ + Name: "Node", + Fields: graphql.FieldConfigMap{ + "id": &graphql.FieldConfig{ + Type: graphql.ID, + }, + "name": &graphql.FieldConfig{ + Type: graphql.String, + }, + }, + }), + }, + }, + })), + }, + }, +}) +var schema, _ = graphql.NewSchema(graphql.SchemaConfig{ + Query: graphql.NewObject(graphql.ObjectConfig{ + Name: "QueryRoot", + Fields: graphql.FieldConfigMap{ + "boxUnion": &graphql.FieldConfig{ + Type: boxUnionObject, + }, + "connection": &graphql.FieldConfig{ + Type: connectionObject, + }, + }, + }), +}) + +func TestValidate_OverlappingFieldsCanBeMerged_ReturnTypesMustBeUnambiguous_ConflictingScalarReturnTypes(t *testing.T) { + expectFailsRuleWithSchema(t, &schema, graphql.OverlappingFieldsCanBeMergedRule, ` + { + boxUnion { + ...on IntBox { + scalar + } + ...on StringBox { + scalar + } + } + } + `, []gqlerrors.FormattedError{ + ruleError( + `Fields "scalar" conflict because they return differing types Int and String.`, + 5, 15, 8, 15), + }) +} +func TestValidate_OverlappingFieldsCanBeMerged_ReturnTypesMustBeUnambiguous_SameWrappedScalarReturnTypes(t *testing.T) { + expectPassesRuleWithSchema(t, &schema, graphql.OverlappingFieldsCanBeMergedRule, ` + { + boxUnion { + ...on NonNullStringBox1 { + scalar + } + ...on NonNullStringBox2 { + scalar + } + } + } + `) +} +func TestValidate_OverlappingFieldsCanBeMerged_ReturnTypesMustBeUnambiguous_ComparesDeepTypesIncludingList(t *testing.T) { + expectFailsRuleWithSchema(t, &schema, graphql.OverlappingFieldsCanBeMergedRule, ` + { + connection { + ...edgeID + edges { + node { + id: name + } + } + } + } + + fragment edgeID on Connection { + edges { + node { + id + } + } + } + `, []gqlerrors.FormattedError{ + ruleError( + `Fields "edges" conflict because subfields "node" conflict because subfields "id" conflict because `+ + `id and name are different fields.`, + 14, 11, 5, 13, 15, 13, 6, 15, 16, 15, 7, 17), + }) +} +func TestValidate_OverlappingFieldsCanBeMerged_ReturnTypesMustBeUnambiguous_IgnoresUnknownTypes(t *testing.T) { + expectPassesRuleWithSchema(t, &schema, graphql.OverlappingFieldsCanBeMergedRule, ` + { + boxUnion { + ...on UnknownType { + scalar + } + ...on NonNullStringBox2 { + scalar + } + } + } + `) +} diff --git a/values.go b/values.go index 880a5129..130f235c 100644 --- a/values.go +++ b/values.go @@ -177,7 +177,7 @@ func coerceValue(ttype Input, value interface{}) interface{} { // graphql-js/src/utilities.js` // TODO: figure out where to organize utils - +// TODO: change to *Schema func typeFromAST(schema Schema, inputTypeAST ast.Type) (Type, error) { switch inputTypeAST := inputTypeAST.(type) { case *ast.List: From d0824e03f64e0bd2a6c688a9f52107bfe19bc7e4 Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Tue, 17 Nov 2015 21:31:28 +0800 Subject: [PATCH 22/41] Implemented `NoUnusedVariablesRule` and tested --- rules.go | 88 ++++++++++++++ rules/no_unused_variables_test.go | 188 ++++++++++++++++++++++++++++++ 2 files changed, 276 insertions(+) create mode 100644 rules/no_unused_variables_test.go diff --git a/rules.go b/rules.go index 4d8fc4bf..8db7caec 100644 --- a/rules.go +++ b/rules.go @@ -27,6 +27,7 @@ var SpecifiedRules = []ValidationRuleFn{ NoFragmentCyclesRule, NoUndefinedVariablesRule, NoUnusedFragmentsRule, + NoUnusedVariablesRule, OverlappingFieldsCanBeMergedRule, } @@ -810,6 +811,93 @@ func NoUnusedFragmentsRule(context *ValidationContext) *ValidationRuleInstance { } } +/** + * NoUnusedVariablesRule + * No unused variables + * + * A GraphQL operation is only valid if all variables defined by an operation + * are used, either directly or within a spread fragment. + */ +func NoUnusedVariablesRule(context *ValidationContext) *ValidationRuleInstance { + + var visitedFragmentNames = map[string]bool{} + var variableDefs = []*ast.VariableDefinition{} + var variableNameUsed = map[string]bool{} + + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.OperationDefinition: visitor.NamedVisitFuncs{ + Enter: func(p visitor.VisitFuncParams) (string, interface{}) { + visitedFragmentNames = map[string]bool{} + variableDefs = []*ast.VariableDefinition{} + variableNameUsed = map[string]bool{} + return visitor.ActionNoChange, nil + }, + Leave: func(p visitor.VisitFuncParams) (string, interface{}) { + errors := []error{} + for _, def := range variableDefs { + variableName := "" + if def.Variable != nil && def.Variable.Name != nil { + variableName = def.Variable.Name.Value + } + if isVariableNameUsed, _ := variableNameUsed[variableName]; isVariableNameUsed != true { + _, err := newValidationRuleError( + fmt.Sprintf(`Variable "$%v" is never used.`, variableName), + []ast.Node{def}, + ) + errors = append(errors, err) + } + } + if len(errors) > 0 { + return visitor.ActionNoChange, errors + } + return visitor.ActionNoChange, nil + }, + }, + kinds.VariableDefinition: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if def, ok := p.Node.(*ast.VariableDefinition); ok && def != nil { + variableDefs = append(variableDefs, def) + } + // Do not visit deeper, or else the defined variable name will be visited. + return visitor.ActionSkip, nil + }, + }, + kinds.Variable: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if variable, ok := p.Node.(*ast.Variable); ok && variable != nil { + if variable.Name != nil { + variableNameUsed[variable.Name.Value] = true + } + } + return visitor.ActionNoChange, nil + }, + }, + kinds.FragmentSpread: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if spreadAST, ok := p.Node.(*ast.FragmentSpread); ok && spreadAST != nil { + // Only visit fragments of a particular name once per operation + spreadName := "" + if spreadAST.Name != nil { + spreadName = spreadAST.Name.Value + } + if hasVisitedFragmentNames, _ := visitedFragmentNames[spreadName]; hasVisitedFragmentNames == true { + return visitor.ActionSkip, nil + } + visitedFragmentNames[spreadName] = true + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + // Visit FragmentDefinition after visiting FragmentSpread + VisitSpreadFragments: true, + VisitorOpts: visitorOpts, + } +} + type fieldDefPair struct { Field *ast.Field FieldDef *FieldDefinition diff --git a/rules/no_unused_variables_test.go b/rules/no_unused_variables_test.go new file mode 100644 index 00000000..d15d06ea --- /dev/null +++ b/rules/no_unused_variables_test.go @@ -0,0 +1,188 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_NoUnusedVariables_UsesAllVariables(t *testing.T) { + expectPassesRule(t, graphql.NoUnusedVariablesRule, ` + query Foo($a: String, $b: String, $c: String) { + field(a: $a, b: $b, c: $c) + } + `) +} +func TestValidate_NoUnusedVariables_UsesAllVariablesDeeply(t *testing.T) { + expectPassesRule(t, graphql.NoUnusedVariablesRule, ` + query Foo($a: String, $b: String, $c: String) { + field(a: $a) { + field(b: $b) { + field(c: $c) + } + } + } + `) +} +func TestValidate_NoUnusedVariables_UsesAllVariablesDeeplyInInlineFragments(t *testing.T) { + expectPassesRule(t, graphql.NoUnusedVariablesRule, ` + query Foo($a: String, $b: String, $c: String) { + ... on Type { + field(a: $a) { + field(b: $b) { + ... on Type { + field(c: $c) + } + } + } + } + } + `) +} +func TestValidate_NoUnusedVariables_UsesAllVariablesInFragments(t *testing.T) { + expectPassesRule(t, graphql.NoUnusedVariablesRule, ` + query Foo($a: String, $b: String, $c: String) { + ...FragA + } + fragment FragA on Type { + field(a: $a) { + ...FragB + } + } + fragment FragB on Type { + field(b: $b) { + ...FragC + } + } + fragment FragC on Type { + field(c: $c) + } + `) +} +func TestValidate_NoUnusedVariables_VariableUsedByFragmentInMultipleOperations(t *testing.T) { + expectPassesRule(t, graphql.NoUnusedVariablesRule, ` + query Foo($a: String) { + ...FragA + } + query Bar($b: String) { + ...FragB + } + fragment FragA on Type { + field(a: $a) + } + fragment FragB on Type { + field(b: $b) + } + `) +} +func TestValidate_NoUnusedVariables_VariableUsedByRecursiveFragment(t *testing.T) { + expectPassesRule(t, graphql.NoUnusedVariablesRule, ` + query Foo($a: String) { + ...FragA + } + fragment FragA on Type { + field(a: $a) { + ...FragA + } + } + `) +} +func TestValidate_NoUnusedVariables_VariableNotUsed(t *testing.T) { + expectFailsRule(t, graphql.NoUnusedVariablesRule, ` + query Foo($a: String, $b: String, $c: String) { + field(a: $a, b: $b) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$c" is never used.`, 2, 41), + }) +} +func TestValidate_NoUnusedVariables_MultipleVariablesNotUsed(t *testing.T) { + expectFailsRule(t, graphql.NoUnusedVariablesRule, ` + query Foo($a: String, $b: String, $c: String) { + field(b: $b) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$a" is never used.`, 2, 17), + ruleError(`Variable "$c" is never used.`, 2, 41), + }) +} +func TestValidate_NoUnusedVariables_VariableNotUsedInFragments(t *testing.T) { + expectFailsRule(t, graphql.NoUnusedVariablesRule, ` + query Foo($a: String, $b: String, $c: String) { + ...FragA + } + fragment FragA on Type { + field(a: $a) { + ...FragB + } + } + fragment FragB on Type { + field(b: $b) { + ...FragC + } + } + fragment FragC on Type { + field + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$c" is never used.`, 2, 41), + }) +} +func TestValidate_NoUnusedVariables_MultipleVariablesNotUsed2(t *testing.T) { + expectFailsRule(t, graphql.NoUnusedVariablesRule, ` + query Foo($a: String, $b: String, $c: String) { + ...FragA + } + fragment FragA on Type { + field { + ...FragB + } + } + fragment FragB on Type { + field(b: $b) { + ...FragC + } + } + fragment FragC on Type { + field + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$a" is never used.`, 2, 17), + ruleError(`Variable "$c" is never used.`, 2, 41), + }) +} +func TestValidate_NoUnusedVariables_VariableNotUsedByUnreferencedFragment(t *testing.T) { + expectFailsRule(t, graphql.NoUnusedVariablesRule, ` + query Foo($b: String) { + ...FragA + } + fragment FragA on Type { + field(a: $a) + } + fragment FragB on Type { + field(b: $b) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$b" is never used.`, 2, 17), + }) +} +func TestValidate_NoUnusedVariables_VariableNotUsedByFragmentUsedByOtherOperation(t *testing.T) { + expectFailsRule(t, graphql.NoUnusedVariablesRule, ` + query Foo($b: String) { + ...FragA + } + query Bar($a: String) { + ...FragB + } + fragment FragA on Type { + field(a: $a) + } + fragment FragB on Type { + field(b: $b) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$b" is never used.`, 2, 17), + ruleError(`Variable "$a" is never used.`, 5, 17), + }) +} From 385a163c34fc0646692bca862c6d985e83a70645 Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Tue, 17 Nov 2015 22:37:24 +0800 Subject: [PATCH 23/41] Implemented `PossibleFragmentSpreadsRule` and tested --- rules.go | 108 ++++++++++++++ rules/possible_fragment_spreads_test.go | 179 ++++++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 rules/possible_fragment_spreads_test.go diff --git a/rules.go b/rules.go index 8db7caec..50ae6773 100644 --- a/rules.go +++ b/rules.go @@ -29,6 +29,7 @@ var SpecifiedRules = []ValidationRuleFn{ NoUnusedFragmentsRule, NoUnusedVariablesRule, OverlappingFieldsCanBeMergedRule, + PossibleFragmentSpreadsRule, } type ValidationRuleInstance struct { @@ -1307,6 +1308,113 @@ func OverlappingFieldsCanBeMergedRule(context *ValidationContext) *ValidationRul } } +func getFragmentType(context *ValidationContext, name string) Type { + frag := context.GetFragment(name) + if frag == nil { + return nil + } + ttype, _ := typeFromAST(*context.GetSchema(), frag.TypeCondition) + return ttype +} + +func doTypesOverlap(t1 Type, t2 Type) bool { + if t1 == t2 { + return true + } + if _, ok := t1.(*Object); ok { + if _, ok := t2.(*Object); ok { + return false + } + if t2, ok := t2.(Abstract); ok { + for _, ttype := range t2.GetPossibleTypes() { + if ttype == t1 { + return true + } + } + return false + } + } + if t1, ok := t1.(Abstract); ok { + if _, ok := t2.(*Object); ok { + for _, ttype := range t1.GetPossibleTypes() { + if ttype == t2 { + return true + } + } + return false + } + t1TypeNames := map[string]bool{} + for _, ttype := range t1.GetPossibleTypes() { + t1TypeNames[ttype.Name] = true + } + if t2, ok := t2.(Abstract); ok { + for _, ttype := range t2.GetPossibleTypes() { + if hasT1TypeName, _ := t1TypeNames[ttype.Name]; hasT1TypeName { + return true + } + } + return false + } + } + return false +} + +/** + * PossibleFragmentSpreadsRule + * Possible fragment spread + * + * A fragment spread is only valid if the type condition could ever possibly + * be true: if there is a non-empty intersection of the possible parent types, + * and possible types which pass the type condition. + */ +func PossibleFragmentSpreadsRule(context *ValidationContext) *ValidationRuleInstance { + + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.InlineFragment: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.InlineFragment); ok && node != nil { + fragType := context.GetType() + parentType, _ := context.GetParentType().(Type) + + if fragType != nil && parentType != nil && !doTypesOverlap(fragType, parentType) { + return newValidationRuleError( + fmt.Sprintf(`Fragment cannot be spread here as objects of `+ + `type "%v" can never be of type "%v".`, parentType, fragType), + []ast.Node{node}, + ) + } + } + return visitor.ActionNoChange, nil + }, + }, + kinds.FragmentSpread: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.FragmentSpread); ok && node != nil { + fragName := "" + if node.Name != nil { + fragName = node.Name.Value + } + fragType := getFragmentType(context, fragName) + parentType, _ := context.GetParentType().(Type) + if fragType != nil && parentType != nil && !doTypesOverlap(fragType, parentType) { + return newValidationRuleError( + fmt.Sprintf(`Fragment "%v" cannot be spread here as objects of `+ + `type "%v" can never be of type "%v".`, fragName, parentType, fragType), + []ast.Node{node}, + ) + } + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + /** * Utility for validators which determines if a value literal AST is valid given * an input type. diff --git a/rules/possible_fragment_spreads_test.go b/rules/possible_fragment_spreads_test.go new file mode 100644 index 00000000..582d78ff --- /dev/null +++ b/rules/possible_fragment_spreads_test.go @@ -0,0 +1,179 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_PossibleFragmentSpreads_OfTheSameObject(t *testing.T) { + expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment objectWithinObject on Dog { ...dogFragment } + fragment dogFragment on Dog { barkVolume } + `) +} +func TestValidate_PossibleFragmentSpreads_OfTheSameObjectWithInlineFragment(t *testing.T) { + expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment objectWithinObjectAnon on Dog { ... on Dog { barkVolume } } + `) +} +func TestValidate_PossibleFragmentSpreads_ObjectIntoAnImplementedInterface(t *testing.T) { + expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment objectWithinInterface on Pet { ...dogFragment } + fragment dogFragment on Dog { barkVolume } + `) +} +func TestValidate_PossibleFragmentSpreads_ObjectIntoContainingUnion(t *testing.T) { + expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment objectWithinUnion on CatOrDog { ...dogFragment } + fragment dogFragment on Dog { barkVolume } + `) +} +func TestValidate_PossibleFragmentSpreads_UnionIntoContainedObject(t *testing.T) { + expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment unionWithinObject on Dog { ...catOrDogFragment } + fragment catOrDogFragment on CatOrDog { __typename } + `) +} +func TestValidate_PossibleFragmentSpreads_UnionIntoOverlappingInterface(t *testing.T) { + expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment unionWithinInterface on Pet { ...catOrDogFragment } + fragment catOrDogFragment on CatOrDog { __typename } + `) +} +func TestValidate_PossibleFragmentSpreads_UnionIntoOverlappingUnion(t *testing.T) { + expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment unionWithinUnion on DogOrHuman { ...catOrDogFragment } + fragment catOrDogFragment on CatOrDog { __typename } + `) +} +func TestValidate_PossibleFragmentSpreads_InterfaceIntoImplementedObject(t *testing.T) { + expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment interfaceWithinObject on Dog { ...petFragment } + fragment petFragment on Pet { name } + `) +} +func TestValidate_PossibleFragmentSpreads_InterfaceIntoOverlappingInterface(t *testing.T) { + expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment interfaceWithinInterface on Pet { ...beingFragment } + fragment beingFragment on Being { name } + `) +} +func TestValidate_PossibleFragmentSpreads_InterfaceIntoOverlappingInterfaceInInlineFragment(t *testing.T) { + expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment interfaceWithinInterface on Pet { ... on Being { name } } + `) +} +func TestValidate_PossibleFragmentSpreads_InterfaceIntoOverlappingUnion(t *testing.T) { + expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment interfaceWithinUnion on CatOrDog { ...petFragment } + fragment petFragment on Pet { name } + `) +} +func TestValidate_PossibleFragmentSpreads_DifferentObjectIntoObject(t *testing.T) { + expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment invalidObjectWithinObject on Cat { ...dogFragment } + fragment dogFragment on Dog { barkVolume } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "dogFragment" cannot be spread here as objects of `+ + `type "Cat" can never be of type "Dog".`, 2, 51), + }) +} + +func TestValidate_PossibleFragmentSpreads_DifferentObjectIntoObjectInInlineFragment(t *testing.T) { + expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment invalidObjectWithinObjectAnon on Cat { + ... on Dog { barkVolume } + } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment cannot be spread here as objects of `+ + `type "Cat" can never be of type "Dog".`, 3, 9), + }) +} +func TestValidate_PossibleFragmentSpreads_ObjectIntoNotImplementingInterface(t *testing.T) { + expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment invalidObjectWithinInterface on Pet { ...humanFragment } + fragment humanFragment on Human { pets { name } } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "humanFragment" cannot be spread here as objects of `+ + `type "Pet" can never be of type "Human".`, 2, 54), + }) +} +func TestValidate_PossibleFragmentSpreads_ObjectIntoNotContainingUnion(t *testing.T) { + expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment invalidObjectWithinUnion on CatOrDog { ...humanFragment } + fragment humanFragment on Human { pets { name } } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "humanFragment" cannot be spread here as objects of `+ + `type "CatOrDog" can never be of type "Human".`, 2, 55), + }) +} +func TestValidate_PossibleFragmentSpreads_UnionIntoNotContainedObject(t *testing.T) { + expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment invalidUnionWithinObject on Human { ...catOrDogFragment } + fragment catOrDogFragment on CatOrDog { __typename } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "catOrDogFragment" cannot be spread here as objects of `+ + `type "Human" can never be of type "CatOrDog".`, 2, 52), + }) +} +func TestValidate_PossibleFragmentSpreads_UnionIntoNonOverlappingInterface(t *testing.T) { + expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment invalidUnionWithinInterface on Pet { ...humanOrAlienFragment } + fragment humanOrAlienFragment on HumanOrAlien { __typename } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "humanOrAlienFragment" cannot be spread here as objects of `+ + `type "Pet" can never be of type "HumanOrAlien".`, 2, 53), + }) +} + +func TestValidate_PossibleFragmentSpreads_UnionIntoNonOverlappingUnion(t *testing.T) { + expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment invalidUnionWithinUnion on CatOrDog { ...humanOrAlienFragment } + fragment humanOrAlienFragment on HumanOrAlien { __typename } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "humanOrAlienFragment" cannot be spread here as objects of `+ + `type "CatOrDog" can never be of type "HumanOrAlien".`, 2, 54), + }) +} + +func TestValidate_PossibleFragmentSpreads_InterfaceIntoNonImplementingObject(t *testing.T) { + expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment invalidInterfaceWithinObject on Cat { ...intelligentFragment } + fragment intelligentFragment on Intelligent { iq } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "intelligentFragment" cannot be spread here as objects of `+ + `type "Cat" can never be of type "Intelligent".`, 2, 54), + }) +} +func TestValidate_PossibleFragmentSpreads_InterfaceIntoNonOverlappingInterface(t *testing.T) { + expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment invalidInterfaceWithinInterface on Pet { + ...intelligentFragment + } + fragment intelligentFragment on Intelligent { iq } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "intelligentFragment" cannot be spread here as objects of `+ + `type "Pet" can never be of type "Intelligent".`, 3, 9), + }) +} +func TestValidate_PossibleFragmentSpreads_InterfaceIntoNonOverlappingInterfaceInInlineFragment(t *testing.T) { + expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment invalidInterfaceWithinInterfaceAnon on Pet { + ...on Intelligent { iq } + } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment cannot be spread here as objects of `+ + `type "Pet" can never be of type "Intelligent".`, 3, 9), + }) +} +func TestValidate_PossibleFragmentSpreads_InterfaceIntoNonOverlappingUnion(t *testing.T) { + expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + fragment invalidInterfaceWithinUnion on HumanOrAlien { ...petFragment } + fragment petFragment on Pet { name } + `, []gqlerrors.FormattedError{ + ruleError(`Fragment "petFragment" cannot be spread here as objects of `+ + `type "HumanOrAlien" can never be of type "Pet".`, 2, 62), + }) +} From 923f4dbe9e0c95c07281caf2694cdc84f7c22a5b Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Wed, 18 Nov 2015 01:32:29 +0800 Subject: [PATCH 24/41] Implemented `ProvidedNonNullArgumentsRule` and tested --- rules.go | 108 +++++++++++++ rules/harness_test.go | 13 +- rules/provided_non_null_arguments_test.go | 176 ++++++++++++++++++++++ type_info.go | 1 - 4 files changed, 295 insertions(+), 3 deletions(-) create mode 100644 rules/provided_non_null_arguments_test.go diff --git a/rules.go b/rules.go index 50ae6773..41d2ce2c 100644 --- a/rules.go +++ b/rules.go @@ -30,6 +30,7 @@ var SpecifiedRules = []ValidationRuleFn{ NoUnusedVariablesRule, OverlappingFieldsCanBeMergedRule, PossibleFragmentSpreadsRule, + ProvidedNonNullArgumentsRule, } type ValidationRuleInstance struct { @@ -1415,6 +1416,113 @@ func PossibleFragmentSpreadsRule(context *ValidationContext) *ValidationRuleInst } } +/** + * ProvidedNonNullArgumentsRule + * Provided required arguments + * + * A field or directive is only valid if all required (non-null) field arguments + * have been provided. + */ +func ProvidedNonNullArgumentsRule(context *ValidationContext) *ValidationRuleInstance { + + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.Field: visitor.NamedVisitFuncs{ + Leave: func(p visitor.VisitFuncParams) (string, interface{}) { + // Validate on leave to allow for deeper errors to appear first. + if fieldAST, ok := p.Node.(*ast.Field); ok && fieldAST != nil { + fieldDef := context.GetFieldDef() + if fieldDef == nil { + return visitor.ActionSkip, nil + } + + errors := []error{} + argASTs := fieldAST.Arguments + + argASTMap := map[string]*ast.Argument{} + for _, arg := range argASTs { + name := "" + if arg.Name != nil { + name = arg.Name.Value + } + argASTMap[name] = arg + } + for _, argDef := range fieldDef.Args { + argAST, _ := argASTMap[argDef.Name] + if argAST == nil { + if argDefType, ok := argDef.Type.(*NonNull); ok { + fieldName := "" + if fieldAST.Name != nil { + fieldName = fieldAST.Name.Value + } + _, err := newValidationRuleError( + fmt.Sprintf(`Field "%v" argument "%v" of type "%v" `+ + `is required but not provided.`, fieldName, argDef.Name, argDefType), + []ast.Node{fieldAST}, + ) + errors = append(errors, err) + } + } + } + if len(errors) > 0 { + return visitor.ActionNoChange, errors + } + } + return visitor.ActionNoChange, nil + }, + }, + kinds.Directive: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + // Validate on leave to allow for deeper errors to appear first. + + if directiveAST, ok := p.Node.(*ast.Directive); ok && directiveAST != nil { + directiveDef := context.GetDirective() + if directiveDef == nil { + return visitor.ActionSkip, nil + } + errors := []error{} + argASTs := directiveAST.Arguments + + argASTMap := map[string]*ast.Argument{} + for _, arg := range argASTs { + name := "" + if arg.Name != nil { + name = arg.Name.Value + } + argASTMap[name] = arg + } + + for _, argDef := range directiveDef.Args { + argAST, _ := argASTMap[argDef.Name] + if argAST == nil { + if argDefType, ok := argDef.Type.(*NonNull); ok { + directiveName := "" + if directiveAST.Name != nil { + directiveName = directiveAST.Name.Value + } + _, err := newValidationRuleError( + fmt.Sprintf(`Directive "@%v" argument "%v" of type `+ + `"%v" is required but not provided.`, directiveName, argDef.Name, argDefType), + []ast.Node{directiveAST}, + ) + errors = append(errors, err) + } + } + } + if len(errors) > 0 { + return visitor.ActionNoChange, errors + } + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + /** * Utility for validators which determines if a value literal AST is valid given * an input type. diff --git a/rules/harness_test.go b/rules/harness_test.go index 9001b27c..495ef847 100644 --- a/rules/harness_test.go +++ b/rules/harness_test.go @@ -485,8 +485,17 @@ func expectInvalid(t *testing.T, schema *graphql.Schema, rules []graphql.Validat if result.IsValid != false { t.Fatalf("IsValid should be false, got %v", result.IsValid) } - if !reflect.DeepEqual(expectedErrors, result.Errors) { - t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expectedErrors, result.Errors)) + for _, expectedErr := range expectedErrors { + found := false + for _, err := range result.Errors { + if reflect.DeepEqual(expectedErr, err) { + found = true + break + } + } + if found == false { + t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expectedErrors, result.Errors)) + } } } diff --git a/rules/provided_non_null_arguments_test.go b/rules/provided_non_null_arguments_test.go new file mode 100644 index 00000000..71c5d7fc --- /dev/null +++ b/rules/provided_non_null_arguments_test.go @@ -0,0 +1,176 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_ProvidedNonNullArguments_IgnoresUnknownArguments(t *testing.T) { + expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + dog { + isHousetrained(unknownArgument: true) + } + } + `) +} +func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_ArgOnOptionalArg(t *testing.T) { + expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + dog { + isHousetrained(atOtherHomes: true) + } + } + `) +} +func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_NoArgOnOptionalArg(t *testing.T) { + expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + dog { + isHousetrained + } + } + `) +} +func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_MultipleArgs(t *testing.T) { + expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + complicatedArgs { + multipleReqs(req1: 1, req2: 2) + } + } + `) +} +func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_MultipleArgsReverseOrder(t *testing.T) { + expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + complicatedArgs { + multipleReqs(req2: 2, req1: 1) + } + } + `) +} +func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_NoArgsOnMultipleOptional(t *testing.T) { + expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + complicatedArgs { + multipleOpts + } + } + `) +} +func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_OneArgOnMultipleOptional(t *testing.T) { + expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + complicatedArgs { + multipleOpts(opt1: 1) + } + } + `) +} +func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_SecondArgOnMultipleOptional(t *testing.T) { + expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + complicatedArgs { + multipleOpts(opt2: 1) + } + } + `) +} +func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_MultipleReqsOnMixedList(t *testing.T) { + expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + complicatedArgs { + multipleOptAndReq(req1: 3, req2: 4) + } + } + `) +} +func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_MultipleReqsAndOneOptOnMixedList(t *testing.T) { + expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + complicatedArgs { + multipleOptAndReq(req1: 3, req2: 4, opt1: 5) + } + } + `) +} +func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_AllReqsAndOptsOnMixedList(t *testing.T) { + expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + complicatedArgs { + multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) + } + } + `) +} +func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_MissingOneNonNullableArgument(t *testing.T) { + expectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + complicatedArgs { + multipleReqs(req2: 2) + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Field "multipleReqs" argument "req1" of type "Int!" is required but not provided.`, 4, 13), + }) +} + +func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_MissingMultipleNonNullableArguments(t *testing.T) { + expectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + complicatedArgs { + multipleReqs + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Field "multipleReqs" argument "req1" of type "Int!" is required but not provided.`, 4, 13), + ruleError(`Field "multipleReqs" argument "req2" of type "Int!" is required but not provided.`, 4, 13), + }) +} + +func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_IncorrectValueAndMissingArgument(t *testing.T) { + expectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + complicatedArgs { + multipleReqs(req1: "one") + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Field "multipleReqs" argument "req2" of type "Int!" is required but not provided.`, 4, 13), + }) +} + +func TestValidate_ProvidedNonNullArguments_DirectiveArguments_IgnoresUnknownDirectives(t *testing.T) { + expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + dog @unknown + } + `) +} +func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_WithDirectivesOfValidTypes(t *testing.T) { + expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + dog @include(if: true) { + name + } + human @skip(if: false) { + name + } + } + `) +} +func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_WithDirectiveWithMissingTypes(t *testing.T) { + expectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` + { + dog @include { + name @skip + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Directive "@include" argument "if" of type "Boolean!" is required but not provided.`, 3, 15), + ruleError(`Directive "@skip" argument "if" of type "Boolean!" is required but not provided.`, 4, 18), + }) +} diff --git a/type_info.go b/type_info.go index 458e2bdd..4dd38f27 100644 --- a/type_info.go +++ b/type_info.go @@ -79,7 +79,6 @@ func (ti *TypeInfo) Enter(node ast.Node) { var fieldDef *FieldDefinition if parentType != nil { fieldDef = getTypeInfoFieldDef(*schema, parentType.(Type), node) - } else { } ti.fieldDefStack = append(ti.fieldDefStack, fieldDef) if fieldDef != nil { From c35a864e9b8a46d692043b6429369181d85a03c2 Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Wed, 18 Nov 2015 12:16:34 +0800 Subject: [PATCH 25/41] Implemented `ScalarLeafsRule` and tested --- definition.go | 31 +++++++++----- rules.go | 46 ++++++++++++++++++++ rules/scalar_leafs_test.go | 87 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 10 deletions(-) create mode 100644 rules/scalar_leafs_test.go diff --git a/definition.go b/definition.go index c089d9de..cded150b 100644 --- a/definition.go +++ b/definition.go @@ -42,34 +42,45 @@ var _ Input = (*List)(nil) var _ Input = (*NonNull)(nil) func IsInputType(ttype Type) bool { - Named := GetNamed(ttype) - if _, ok := Named.(*Scalar); ok { + named := GetNamed(ttype) + if _, ok := named.(*Scalar); ok { return true } - if _, ok := Named.(*Enum); ok { + if _, ok := named.(*Enum); ok { return true } - if _, ok := Named.(*InputObject); ok { + if _, ok := named.(*InputObject); ok { return true } return false } func IsOutputType(ttype Type) bool { - Named := GetNamed(ttype) - if _, ok := Named.(*Scalar); ok { + name := GetNamed(ttype) + if _, ok := name.(*Scalar); ok { return true } - if _, ok := Named.(*Object); ok { + if _, ok := name.(*Object); ok { return true } - if _, ok := Named.(*Interface); ok { + if _, ok := name.(*Interface); ok { return true } - if _, ok := Named.(*Union); ok { + if _, ok := name.(*Union); ok { return true } - if _, ok := Named.(*Enum); ok { + if _, ok := name.(*Enum); ok { + return true + } + return false +} + +func IsLeafType(ttype Type) bool { + named := GetNamed(ttype) + if _, ok := named.(*Scalar); ok { + return true + } + if _, ok := named.(*Enum); ok { return true } return false diff --git a/rules.go b/rules.go index 41d2ce2c..eb40c3d4 100644 --- a/rules.go +++ b/rules.go @@ -31,6 +31,7 @@ var SpecifiedRules = []ValidationRuleFn{ OverlappingFieldsCanBeMergedRule, PossibleFragmentSpreadsRule, ProvidedNonNullArgumentsRule, + ScalarLeafsRule, } type ValidationRuleInstance struct { @@ -1523,6 +1524,51 @@ func ProvidedNonNullArgumentsRule(context *ValidationContext) *ValidationRuleIns } } +/** + * ScalarLeafsRule + * Scalar leafs + * + * A GraphQL document is valid only if all leaf fields (fields without + * sub selections) are of scalar or enum types. + */ +func ScalarLeafsRule(context *ValidationContext) *ValidationRuleInstance { + + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.Field: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.Field); ok && node != nil { + nodeName := "" + if node.Name != nil { + nodeName = node.Name.Value + } + ttype := context.GetType() + if ttype != nil { + if IsLeafType(ttype) { + if node.SelectionSet != nil { + return newValidationRuleError( + fmt.Sprintf(`Field "%v" of type "%v" must not have a sub selection.`, nodeName, ttype), + []ast.Node{node.SelectionSet}, + ) + } + } else if node.SelectionSet == nil { + return newValidationRuleError( + fmt.Sprintf(`Field "%v" of type "%v" must have a sub selection.`, nodeName, ttype), + []ast.Node{node}, + ) + } + } + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + /** * Utility for validators which determines if a value literal AST is valid given * an input type. diff --git a/rules/scalar_leafs_test.go b/rules/scalar_leafs_test.go new file mode 100644 index 00000000..a2063f2a --- /dev/null +++ b/rules/scalar_leafs_test.go @@ -0,0 +1,87 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_ScalarLeafs_ValidScalarSelection(t *testing.T) { + expectPassesRule(t, graphql.ScalarLeafsRule, ` + fragment scalarSelection on Dog { + barks + } + `) +} +func TestValidate_ScalarLeafs_ObjectTypeMissingSelection(t *testing.T) { + expectFailsRule(t, graphql.ScalarLeafsRule, ` + query directQueryOnObjectWithoutSubFields { + human + } + `, []gqlerrors.FormattedError{ + ruleError(`Field "human" of type "Human" must have a sub selection.`, 3, 9), + }) +} + +func TestValidate_ScalarLeafs_InterfaceTypeMissingSelection(t *testing.T) { + expectFailsRule(t, graphql.ScalarLeafsRule, ` + { + human { pets } + } + `, []gqlerrors.FormattedError{ + ruleError(`Field "pets" of type "[Pet]" must have a sub selection.`, 3, 17), + }) +} +func TestValidate_ScalarLeafs_ValidScalarSelectionWithArgs(t *testing.T) { + expectPassesRule(t, graphql.ScalarLeafsRule, ` + fragment scalarSelectionWithArgs on Dog { + doesKnowCommand(dogCommand: SIT) + } + `) +} +func TestValidate_ScalarLeafs_ScalarSelectionNotAllowedOnBoolean(t *testing.T) { + expectFailsRule(t, graphql.ScalarLeafsRule, ` + fragment scalarSelectionsNotAllowedOnBoolean on Dog { + barks { sinceWhen } + } + `, []gqlerrors.FormattedError{ + ruleError(`Field "barks" of type "Boolean" must not have a sub selection.`, 3, 15), + }) +} +func TestValidate_ScalarLeafs_ScalarSelectionNotAllowedOnEnum(t *testing.T) { + expectFailsRule(t, graphql.ScalarLeafsRule, ` + fragment scalarSelectionsNotAllowedOnEnum on Cat { + furColor { inHexdec } + } + `, []gqlerrors.FormattedError{ + ruleError(`Field "furColor" of type "FurColor" must not have a sub selection.`, 3, 18), + }) +} +func TestValidate_ScalarLeafs_ScalarSelectionNotAllowedWithArgs(t *testing.T) { + expectFailsRule(t, graphql.ScalarLeafsRule, ` + fragment scalarSelectionsNotAllowedWithArgs on Dog { + doesKnowCommand(dogCommand: SIT) { sinceWhen } + } + `, []gqlerrors.FormattedError{ + ruleError(`Field "doesKnowCommand" of type "Boolean" must not have a sub selection.`, 3, 42), + }) +} +func TestValidate_ScalarLeafs_ScalarSelectionNotAllowedWithDirectives(t *testing.T) { + expectFailsRule(t, graphql.ScalarLeafsRule, ` + fragment scalarSelectionsNotAllowedWithDirectives on Dog { + name @include(if: true) { isAlsoHumanName } + } + `, []gqlerrors.FormattedError{ + ruleError(`Field "name" of type "String" must not have a sub selection.`, 3, 33), + }) +} +func TestValidate_ScalarLeafs_ScalarSelectionNotAllowedWithDirectivesAndArgs(t *testing.T) { + expectFailsRule(t, graphql.ScalarLeafsRule, ` + fragment scalarSelectionsNotAllowedWithDirectivesAndArgs on Dog { + doesKnowCommand(dogCommand: SIT) @include(if: true) { sinceWhen } + } + `, []gqlerrors.FormattedError{ + ruleError(`Field "doesKnowCommand" of type "Boolean" must not have a sub selection.`, 3, 61), + }) +} From 4ad62fcd97f1ae7fd59738f63d11e7666286e25f Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Wed, 18 Nov 2015 12:28:26 +0800 Subject: [PATCH 26/41] Implemented `UniqueArgumentNamesRule` and tested --- rules.go | 49 ++++++++++++ rules/unique_argument_names_test.go | 111 ++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 rules/unique_argument_names_test.go diff --git a/rules.go b/rules.go index eb40c3d4..55e24f4e 100644 --- a/rules.go +++ b/rules.go @@ -32,6 +32,7 @@ var SpecifiedRules = []ValidationRuleFn{ PossibleFragmentSpreadsRule, ProvidedNonNullArgumentsRule, ScalarLeafsRule, + UniqueArgumentNamesRule, } type ValidationRuleInstance struct { @@ -1569,6 +1570,54 @@ func ScalarLeafsRule(context *ValidationContext) *ValidationRuleInstance { } } +/** + * UniqueArgumentNamesRule + * Unique argument names + * + * A GraphQL field or directive is only valid if all supplied arguments are + * uniquely named. + */ +func UniqueArgumentNamesRule(context *ValidationContext) *ValidationRuleInstance { + knownArgNames := map[string]*ast.Name{} + + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.Field: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + knownArgNames = map[string]*ast.Name{} + return visitor.ActionNoChange, nil + }, + }, + kinds.Directive: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + knownArgNames = map[string]*ast.Name{} + return visitor.ActionNoChange, nil + }, + }, + kinds.Argument: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.Argument); ok && node != nil { + argName := "" + if node.Name != nil { + argName = node.Name.Value + } + if nameAST, ok := knownArgNames[argName]; ok { + return newValidationRuleError( + fmt.Sprintf(`There can be only one argument named "%v".`, argName), + []ast.Node{nameAST, node.Name}, + ) + } + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + /** * Utility for validators which determines if a value literal AST is valid given * an input type. diff --git a/rules/unique_argument_names_test.go b/rules/unique_argument_names_test.go new file mode 100644 index 00000000..0000fa36 --- /dev/null +++ b/rules/unique_argument_names_test.go @@ -0,0 +1,111 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_UniqueArgumentNames_NoArgumentsOnField(t *testing.T) { + expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + { + field + } + `) +} +func TestValidate_UniqueArgumentNames_NoArgumentsOnDirective(t *testing.T) { + expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + { + field + } + `) +} +func TestValidate_UniqueArgumentNames_ArgumentOnField(t *testing.T) { + expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + { + field(arg: "value") + } + `) +} +func TestValidate_UniqueArgumentNames_ArgumentOnDirective(t *testing.T) { + expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + { + field @directive(arg: "value") + } + `) +} +func TestValidate_UniqueArgumentNames_SameArgumentOnTwoFields(t *testing.T) { + expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + { + one: field(arg: "value") + two: field(arg: "value") + } + `) +} +func TestValidate_UniqueArgumentNames_SameArgumentOnFieldAndDirective(t *testing.T) { + expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + { + field(arg: "value") @directive(arg: "value") + } + `) +} +func TestValidate_UniqueArgumentNames_SameArgumentOnTwoDirectives(t *testing.T) { + expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + { + field @directive1(arg: "value") @directive2(arg: "value") + } + `) +} +func TestValidate_UniqueArgumentNames_MultipleFieldArguments(t *testing.T) { + expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + { + field(arg1: "value", arg2: "value", arg3: "value") + } + `) +} +func TestValidate_UniqueArgumentNames_MultipleDirectiveArguments(t *testing.T) { + expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + { + field @directive(arg1: "value", arg2: "value", arg3: "value") + } + `) +} +func TestValidate_UniqueArgumentNames_DuplicateFieldArguments(t *testing.T) { + expectFailsRule(t, graphql.UniqueArgumentNamesRule, ` + { + field(arg1: "value", arg1: "value") + } + `, []gqlerrors.FormattedError{ + ruleError(`There can be only one argument named "arg1".`, 3, 15, 3, 30), + }) +} +func TestValidate_UniqueArgumentNames_ManyDuplicateFieldArguments(t *testing.T) { + expectFailsRule(t, graphql.UniqueArgumentNamesRule, ` + { + field(arg1: "value", arg1: "value", arg1: "value") + } + `, []gqlerrors.FormattedError{ + ruleError(`There can be only one argument named "arg1".`, 3, 15, 3, 30), + ruleError(`There can be only one argument named "arg1".`, 3, 15, 3, 45), + }) +} +func TestValidate_UniqueArgumentNames_DuplicateDirectiveArguments(t *testing.T) { + expectFailsRule(t, graphql.UniqueArgumentNamesRule, ` + { + field @directive(arg1: "value", arg1: "value") + } + `, []gqlerrors.FormattedError{ + ruleError(`There can be only one argument named "arg1".`, 3, 26, 3, 41), + }) +} +func TestValidate_UniqueArgumentNames_ManyDuplicateDirectiveArguments(t *testing.T) { + expectFailsRule(t, graphql.UniqueArgumentNamesRule, ` + { + field @directive(arg1: "value", arg1: "value", arg1: "value") + } + `, []gqlerrors.FormattedError{ + ruleError(`There can be only one argument named "arg1".`, 3, 26, 3, 41), + ruleError(`There can be only one argument named "arg1".`, 3, 26, 3, 56), + }) +} From b32b47dc14d8e52ac5c8d3f17a0cbcdce6891a93 Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Wed, 18 Nov 2015 12:37:12 +0800 Subject: [PATCH 27/41] Implemented `UniqueFragmentNamesRule` and tested --- rules.go | 40 +++++++++++- rules/unique_fragment_names_test.go | 95 +++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 rules/unique_fragment_names_test.go diff --git a/rules.go b/rules.go index 55e24f4e..a493db32 100644 --- a/rules.go +++ b/rules.go @@ -33,6 +33,7 @@ var SpecifiedRules = []ValidationRuleFn{ ProvidedNonNullArgumentsRule, ScalarLeafsRule, UniqueArgumentNamesRule, + UniqueFragmentNamesRule, } type ValidationRuleInstance struct { @@ -1596,7 +1597,7 @@ func UniqueArgumentNamesRule(context *ValidationContext) *ValidationRuleInstance }, kinds.Argument: visitor.NamedVisitFuncs{ Kind: func(p visitor.VisitFuncParams) (string, interface{}) { - if node, ok := p.Node.(*ast.Argument); ok && node != nil { + if node, ok := p.Node.(*ast.Argument); ok { argName := "" if node.Name != nil { argName = node.Name.Value @@ -1607,6 +1608,43 @@ func UniqueArgumentNamesRule(context *ValidationContext) *ValidationRuleInstance []ast.Node{nameAST, node.Name}, ) } + knownArgNames[argName] = node.Name + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + +/** + * UniqueFragmentNamesRule + * Unique fragment names + * + * A GraphQL document is only valid if all defined fragments have unique names. + */ +func UniqueFragmentNamesRule(context *ValidationContext) *ValidationRuleInstance { + knownFragmentNames := map[string]*ast.Name{} + + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.FragmentDefinition: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.FragmentDefinition); ok && node != nil { + fragmentName := "" + if node.Name != nil { + fragmentName = node.Name.Value + } + if nameAST, ok := knownFragmentNames[fragmentName]; ok { + return newValidationRuleError( + fmt.Sprintf(`There can only be one fragment named "%v".`, fragmentName), + []ast.Node{nameAST, node.Name}, + ) + } + knownFragmentNames[fragmentName] = node.Name } return visitor.ActionNoChange, nil }, diff --git a/rules/unique_fragment_names_test.go b/rules/unique_fragment_names_test.go new file mode 100644 index 00000000..2e5cbcb9 --- /dev/null +++ b/rules/unique_fragment_names_test.go @@ -0,0 +1,95 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_UniqueFragmentNames_NoFragments(t *testing.T) { + expectPassesRule(t, graphql.UniqueFragmentNamesRule, ` + { + field + } + `) +} +func TestValidate_UniqueFragmentNames_OneFragment(t *testing.T) { + expectPassesRule(t, graphql.UniqueFragmentNamesRule, ` + { + ...fragA + } + + fragment fragA on Type { + field + } + `) +} +func TestValidate_UniqueFragmentNames_ManyFragments(t *testing.T) { + expectPassesRule(t, graphql.UniqueFragmentNamesRule, ` + { + ...fragA + ...fragB + ...fragC + } + fragment fragA on Type { + fieldA + } + fragment fragB on Type { + fieldB + } + fragment fragC on Type { + fieldC + } + `) +} +func TestValidate_UniqueFragmentNames_InlineFragmentsAreAlwaysUnique(t *testing.T) { + expectPassesRule(t, graphql.UniqueFragmentNamesRule, ` + { + ...on Type { + fieldA + } + ...on Type { + fieldB + } + } + `) +} +func TestValidate_UniqueFragmentNames_FragmentAndOperationNamedTheSame(t *testing.T) { + expectPassesRule(t, graphql.UniqueFragmentNamesRule, ` + query Foo { + ...Foo + } + fragment Foo on Type { + field + } + `) +} +func TestValidate_UniqueFragmentNames_FragmentsNamedTheSame(t *testing.T) { + expectFailsRule(t, graphql.UniqueFragmentNamesRule, ` + { + ...fragA + } + fragment fragA on Type { + fieldA + } + fragment fragA on Type { + fieldB + } + `, []gqlerrors.FormattedError{ + ruleError(`There can only be one fragment named "fragA".`, 5, 16, 8, 16), + }) +} + +func TestValidate_UniqueFragmentNames_FragmentsNamedTheSameWithoutBeingReferenced(t *testing.T) { + expectFailsRule(t, graphql.UniqueFragmentNamesRule, ` + fragment fragA on Type { + fieldA + } + fragment fragA on Type { + fieldB + } + `, []gqlerrors.FormattedError{ + ruleError(`There can only be one fragment named "fragA".`, 2, 16, 5, 16), + }) +} From 2e55f1e2825594c5b69a53c163990aa026eee7dc Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Wed, 18 Nov 2015 12:43:45 +0800 Subject: [PATCH 28/41] Implemented `UniqueOperationNamesRule` and tested --- rules.go | 37 ++++++++++++ rules/unique_fragment_names_test.go | 1 - rules/unique_operation_names_test.go | 87 ++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 rules/unique_operation_names_test.go diff --git a/rules.go b/rules.go index a493db32..eec0dd48 100644 --- a/rules.go +++ b/rules.go @@ -34,6 +34,7 @@ var SpecifiedRules = []ValidationRuleFn{ ScalarLeafsRule, UniqueArgumentNamesRule, UniqueFragmentNamesRule, + UniqueOperationNamesRule, } type ValidationRuleInstance struct { @@ -1656,6 +1657,42 @@ func UniqueFragmentNamesRule(context *ValidationContext) *ValidationRuleInstance } } +/** + * UniqueOperationNamesRule + * Unique operation names + * + * A GraphQL document is only valid if all defined operations have unique names. + */ +func UniqueOperationNamesRule(context *ValidationContext) *ValidationRuleInstance { + knownOperationNames := map[string]*ast.Name{} + + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.OperationDefinition: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.OperationDefinition); ok && node != nil { + operationName := "" + if node.Name != nil { + operationName = node.Name.Value + } + if nameAST, ok := knownOperationNames[operationName]; ok { + return newValidationRuleError( + fmt.Sprintf(`There can only be one operation named "%v".`, operationName), + []ast.Node{nameAST, node.Name}, + ) + } + knownOperationNames[operationName] = node.Name + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + /** * Utility for validators which determines if a value literal AST is valid given * an input type. diff --git a/rules/unique_fragment_names_test.go b/rules/unique_fragment_names_test.go index 2e5cbcb9..3f1f79d3 100644 --- a/rules/unique_fragment_names_test.go +++ b/rules/unique_fragment_names_test.go @@ -80,7 +80,6 @@ func TestValidate_UniqueFragmentNames_FragmentsNamedTheSame(t *testing.T) { ruleError(`There can only be one fragment named "fragA".`, 5, 16, 8, 16), }) } - func TestValidate_UniqueFragmentNames_FragmentsNamedTheSameWithoutBeingReferenced(t *testing.T) { expectFailsRule(t, graphql.UniqueFragmentNamesRule, ` fragment fragA on Type { diff --git a/rules/unique_operation_names_test.go b/rules/unique_operation_names_test.go new file mode 100644 index 00000000..f2039955 --- /dev/null +++ b/rules/unique_operation_names_test.go @@ -0,0 +1,87 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_UniqueOperationNames_NoOperations(t *testing.T) { + expectPassesRule(t, graphql.UniqueOperationNamesRule, ` + fragment fragA on Type { + field + } + `) +} +func TestValidate_UniqueOperationNames_OneAnonOperation(t *testing.T) { + expectPassesRule(t, graphql.UniqueOperationNamesRule, ` + { + field + } + `) +} +func TestValidate_UniqueOperationNames_OneNamedOperation(t *testing.T) { + expectPassesRule(t, graphql.UniqueOperationNamesRule, ` + query Foo { + field + } + `) +} +func TestValidate_UniqueOperationNames_MultipleOperations(t *testing.T) { + expectPassesRule(t, graphql.UniqueOperationNamesRule, ` + query Foo { + field + } + + query Bar { + field + } + `) +} +func TestValidate_UniqueOperationNames_MultipleOperationsOfDifferentTypes(t *testing.T) { + expectPassesRule(t, graphql.UniqueOperationNamesRule, ` + query Foo { + field + } + + mutation Bar { + field + } + `) +} +func TestValidate_UniqueOperationNames_FragmentAndOperationNamedTheSame(t *testing.T) { + expectPassesRule(t, graphql.UniqueOperationNamesRule, ` + query Foo { + field + } + + mutation Bar { + field + } + `) +} +func TestValidate_UniqueOperationNames_MultipleOperationsOfSameName(t *testing.T) { + expectFailsRule(t, graphql.UniqueOperationNamesRule, ` + query Foo { + fieldA + } + query Foo { + fieldB + } + `, []gqlerrors.FormattedError{ + ruleError(`There can only be one operation named "Foo".`, 2, 13, 5, 13), + }) +} +func TestValidate_UniqueOperationNames_MultipleOperationsOfSameNameOfDifferentTypes(t *testing.T) { + expectFailsRule(t, graphql.UniqueOperationNamesRule, ` + query Foo { + fieldA + } + mutation Foo { + fieldB + } + `, []gqlerrors.FormattedError{ + ruleError(`There can only be one operation named "Foo".`, 2, 13, 5, 16), + }) +} From 39e9c6a752d2f7c9058ff76fcba31a450194af1b Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Wed, 18 Nov 2015 15:40:54 +0800 Subject: [PATCH 29/41] Implemented `VariablesAreInputTypesRule` & `VariablesInAllowedPositionRule` and tested --- rules.go | 152 ++++++++++++ rules/variables_are_input_types_test.go | 27 +++ rules/variables_in_allowed_position_test.go | 252 ++++++++++++++++++++ 3 files changed, 431 insertions(+) create mode 100644 rules/variables_are_input_types_test.go create mode 100644 rules/variables_in_allowed_position_test.go diff --git a/rules.go b/rules.go index eec0dd48..9e3d1cef 100644 --- a/rules.go +++ b/rules.go @@ -35,6 +35,8 @@ var SpecifiedRules = []ValidationRuleFn{ UniqueArgumentNamesRule, UniqueFragmentNamesRule, UniqueOperationNamesRule, + VariablesAreInputTypesRule, + VariablesInAllowedPositionRule, } type ValidationRuleInstance struct { @@ -1693,6 +1695,156 @@ func UniqueOperationNamesRule(context *ValidationContext) *ValidationRuleInstanc } } +/** + * VariablesAreInputTypesRule + * Variables are input types + * + * A GraphQL operation is only valid if all the variables it defines are of + * input types (scalar, enum, or input object). + */ +func VariablesAreInputTypesRule(context *ValidationContext) *ValidationRuleInstance { + + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.VariableDefinition: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if node, ok := p.Node.(*ast.VariableDefinition); ok && node != nil { + ttype, _ := typeFromAST(*context.GetSchema(), node.Type) + + // If the variable type is not an input type, return an error. + if ttype != nil && !IsInputType(ttype) { + variableName := "" + if node.Variable != nil && node.Variable.Name != nil { + variableName = node.Variable.Name.Value + } + return newValidationRuleError( + fmt.Sprintf(`Variable "$%v" cannot be non-input type "%v".`, + variableName, printer.Print(node.Type)), + []ast.Node{node.Type}, + ) + } + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitorOpts: visitorOpts, + } +} + +// If a variable definition has a default value, it's effectively non-null. +func effectiveType(varType Type, varDef *ast.VariableDefinition) Type { + if varDef.DefaultValue == nil { + return varType + } + if _, ok := varType.(*NonNull); ok { + return varType + } + return NewNonNull(varType) +} + +// A var type is allowed if it is the same or more strict than the expected +// type. It can be more strict if the variable type is non-null when the +// expected type is nullable. If both are list types, the variable item type can +// be more strict than the expected item type. +func varTypeAllowedForType(varType Type, expectedType Type) bool { + if expectedType, ok := expectedType.(*NonNull); ok { + if varType, ok := varType.(*NonNull); ok { + return varTypeAllowedForType(varType.OfType, expectedType.OfType) + } + return false + } + if varType, ok := varType.(*NonNull); ok { + return varTypeAllowedForType(varType.OfType, expectedType) + } + if varType, ok := varType.(*List); ok { + if expectedType, ok := expectedType.(*List); ok { + return varTypeAllowedForType(varType.OfType, expectedType.OfType) + } + } + return varType == expectedType +} + +/** + * VariablesInAllowedPositionRule + * Variables passed to field arguments conform to type + */ +func VariablesInAllowedPositionRule(context *ValidationContext) *ValidationRuleInstance { + + varDefMap := map[string]*ast.VariableDefinition{} + visitedFragmentNames := map[string]bool{} + + visitorOpts := &visitor.VisitorOptions{ + KindFuncMap: map[string]visitor.NamedVisitFuncs{ + kinds.OperationDefinition: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + varDefMap = map[string]*ast.VariableDefinition{} + visitedFragmentNames = map[string]bool{} + return visitor.ActionNoChange, nil + }, + }, + kinds.VariableDefinition: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if varDefAST, ok := p.Node.(*ast.VariableDefinition); ok { + defName := "" + if varDefAST.Variable != nil && varDefAST.Variable.Name != nil { + defName = varDefAST.Variable.Name.Value + } + varDefMap[defName] = varDefAST + } + return visitor.ActionNoChange, nil + }, + }, + kinds.FragmentSpread: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + // Only visit fragments of a particular name once per operation + if spreadAST, ok := p.Node.(*ast.FragmentSpread); ok { + spreadName := "" + if spreadAST.Name != nil { + spreadName = spreadAST.Name.Value + } + if hasVisited, _ := visitedFragmentNames[spreadName]; hasVisited { + return visitor.ActionSkip, nil + } + visitedFragmentNames[spreadName] = true + } + return visitor.ActionNoChange, nil + }, + }, + kinds.Variable: visitor.NamedVisitFuncs{ + Kind: func(p visitor.VisitFuncParams) (string, interface{}) { + if variableAST, ok := p.Node.(*ast.Variable); ok && variableAST != nil { + varName := "" + if variableAST.Name != nil { + varName = variableAST.Name.Value + } + varDef, _ := varDefMap[varName] + var varType Type + if varDef != nil { + varType, _ = typeFromAST(*context.GetSchema(), varDef.Type) + } + inputType := context.GetInputType() + if varType != nil && inputType != nil && !varTypeAllowedForType(effectiveType(varType, varDef), inputType) { + return newValidationRuleError( + fmt.Sprintf(`Variable "$%v" of type "%v" used in position `+ + `expecting type "%v".`, varName, varType, inputType), + []ast.Node{variableAST}, + ) + } + } + return visitor.ActionNoChange, nil + }, + }, + }, + } + return &ValidationRuleInstance{ + VisitSpreadFragments: true, + VisitorOpts: visitorOpts, + } +} + /** * Utility for validators which determines if a value literal AST is valid given * an input type. diff --git a/rules/variables_are_input_types_test.go b/rules/variables_are_input_types_test.go new file mode 100644 index 00000000..77dd608c --- /dev/null +++ b/rules/variables_are_input_types_test.go @@ -0,0 +1,27 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_VariablesAreInputTypes_(t *testing.T) { + expectPassesRule(t, graphql.VariablesAreInputTypesRule, ` + query Foo($a: String, $b: [Boolean!]!, $c: ComplexInput) { + field(a: $a, b: $b, c: $c) + } + `) +} +func TestValidate_VariablesAreInputTypes_1(t *testing.T) { + expectFailsRule(t, graphql.VariablesAreInputTypesRule, ` + query Foo($a: Dog, $b: [[CatOrDog!]]!, $c: Pet) { + field(a: $a, b: $b, c: $c) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$a" cannot be non-input type "Dog".`, 2, 21), + ruleError(`Variable "$b" cannot be non-input type "[[CatOrDog!]]!".`, 2, 30), + ruleError(`Variable "$c" cannot be non-input type "Pet".`, 2, 50), + }) +} diff --git a/rules/variables_in_allowed_position_test.go b/rules/variables_in_allowed_position_test.go new file mode 100644 index 00000000..4b04c832 --- /dev/null +++ b/rules/variables_in_allowed_position_test.go @@ -0,0 +1,252 @@ +package rules_test + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" +) + +func TestValidate_VariablesInAllowedPosition_BooleanToBoolean(t *testing.T) { + expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($booleanArg: Boolean) + { + complicatedArgs { + booleanArgField(booleanArg: $booleanArg) + } + } + `) +} +func TestValidate_VariablesInAllowedPosition_BooleanToBooleanWithinFragment(t *testing.T) { + expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + fragment booleanArgFrag on ComplicatedArgs { + booleanArgField(booleanArg: $booleanArg) + } + query Query($booleanArg: Boolean) + { + complicatedArgs { + ...booleanArgFrag + } + } + `) + expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($booleanArg: Boolean) + { + complicatedArgs { + ...booleanArgFrag + } + } + fragment booleanArgFrag on ComplicatedArgs { + booleanArgField(booleanArg: $booleanArg) + } + `) +} +func TestValidate_VariablesInAllowedPosition_NonNullableBooleanToBoolean(t *testing.T) { + expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($nonNullBooleanArg: Boolean!) + { + complicatedArgs { + booleanArgField(booleanArg: $nonNullBooleanArg) + } + } + `) +} +func TestValidate_VariablesInAllowedPosition_NonNullableBooleanToBooleanWithinFragment(t *testing.T) { + expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + fragment booleanArgFrag on ComplicatedArgs { + booleanArgField(booleanArg: $nonNullBooleanArg) + } + + query Query($nonNullBooleanArg: Boolean!) + { + complicatedArgs { + ...booleanArgFrag + } + } + `) +} +func TestValidate_VariablesInAllowedPosition_IntToNonNullableIntWithDefault(t *testing.T) { + expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($intArg: Int = 1) + { + complicatedArgs { + nonNullIntArgField(nonNullIntArg: $intArg) + } + } + `) +} +func TestValidate_VariablesInAllowedPosition_ListOfStringToListOfString(t *testing.T) { + expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($stringListVar: [String]) + { + complicatedArgs { + stringListArgField(stringListArg: $stringListVar) + } + } + `) +} +func TestValidate_VariablesInAllowedPosition_ListOfNonNullableStringToListOfString(t *testing.T) { + expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($stringListVar: [String!]) + { + complicatedArgs { + stringListArgField(stringListArg: $stringListVar) + } + } + `) +} +func TestValidate_VariablesInAllowedPosition_StringToListOfStringInItemPosition(t *testing.T) { + expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($stringVar: String) + { + complicatedArgs { + stringListArgField(stringListArg: [$stringVar]) + } + } + `) +} +func TestValidate_VariablesInAllowedPosition_NonNullableStringToListOfStringInItemPosition(t *testing.T) { + expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($stringVar: String!) + { + complicatedArgs { + stringListArgField(stringListArg: [$stringVar]) + } + } + `) +} +func TestValidate_VariablesInAllowedPosition_ComplexInputToComplexInput(t *testing.T) { + expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($complexVar: ComplexInput) + { + complicatedArgs { + complexArgField(complexArg: $ComplexInput) + } + } + `) +} +func TestValidate_VariablesInAllowedPosition_ComplexInputToComplexInputInFieldPosition(t *testing.T) { + expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($boolVar: Boolean = false) + { + complicatedArgs { + complexArgField(complexArg: {requiredArg: $boolVar}) + } + } + `) +} +func TestValidate_VariablesInAllowedPosition_NonNullableBooleanToNonNullableBooleanInDirective(t *testing.T) { + expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($boolVar: Boolean!) + { + dog @include(if: $boolVar) + } + `) +} +func TestValidate_VariablesInAllowedPosition_NonNullableBooleanToNonNullableBooleanInDirectiveInDirectiveWithDefault(t *testing.T) { + expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($boolVar: Boolean = false) + { + dog @include(if: $boolVar) + } + `) +} +func TestValidate_VariablesInAllowedPosition_IntToNonNullableInt(t *testing.T) { + expectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($intArg: Int) + { + complicatedArgs { + nonNullIntArgField(nonNullIntArg: $intArg) + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$intArg" of type "Int" used in position `+ + `expecting type "Int!".`, 5, 45), + }) +} +func TestValidate_VariablesInAllowedPosition_IntToNonNullableIntWithinFragment(t *testing.T) { + expectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` + fragment nonNullIntArgFieldFrag on ComplicatedArgs { + nonNullIntArgField(nonNullIntArg: $intArg) + } + + query Query($intArg: Int) + { + complicatedArgs { + ...nonNullIntArgFieldFrag + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$intArg" of type "Int" used in position `+ + `expecting type "Int!".`, 3, 43), + }) +} +func TestValidate_VariablesInAllowedPosition_IntToNonNullableIntWithinNestedFragment(t *testing.T) { + expectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` + fragment outerFrag on ComplicatedArgs { + ...nonNullIntArgFieldFrag + } + + fragment nonNullIntArgFieldFrag on ComplicatedArgs { + nonNullIntArgField(nonNullIntArg: $intArg) + } + + query Query($intArg: Int) + { + complicatedArgs { + ...outerFrag + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$intArg" of type "Int" used in position `+ + `expecting type "Int!".`, 7, 43), + }) +} +func TestValidate_VariablesInAllowedPosition_StringOverBoolean(t *testing.T) { + expectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($stringVar: String) + { + complicatedArgs { + booleanArgField(booleanArg: $stringVar) + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$stringVar" of type "String" used in position `+ + `expecting type "Boolean".`, 5, 39), + }) +} +func TestValidate_VariablesInAllowedPosition_StringToListOfString(t *testing.T) { + expectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($stringVar: String) + { + complicatedArgs { + stringListArgField(stringListArg: $stringVar) + } + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$stringVar" of type "String" used in position `+ + `expecting type "[String]".`, 5, 45), + }) +} +func TestValidate_VariablesInAllowedPosition_BooleanToNonNullableBooleanInDirective(t *testing.T) { + expectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($boolVar: Boolean) + { + dog @include(if: $boolVar) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$boolVar" of type "Boolean" used in position `+ + `expecting type "Boolean!".`, 4, 26), + }) +} +func TestValidate_VariablesInAllowedPosition_StringToNonNullableBooleanInDirective(t *testing.T) { + expectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` + query Query($stringVar: String) + { + dog @include(if: $stringVar) + } + `, []gqlerrors.FormattedError{ + ruleError(`Variable "$stringVar" of type "String" used in position `+ + `expecting type "Boolean!".`, 4, 26), + }) +} From f57876e000b539daf5d03c7fef8190f6b0164b12 Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Wed, 18 Nov 2015 21:39:00 +0800 Subject: [PATCH 30/41] Moved tests in `rules` folder out to root - Go's default coverage tool won't cover tests in a different folder. - Need better organization for tests in root folder --- rules/harness_test.go | 534 ------------------ rules/rules.go | 1 - ...=> rules_arguments_of_correct_type_test.go | 179 +++--- ...les_default_values_of_correct_type_test.go | 33 +- ...go => rules_fields_on_correct_type_test.go | 62 +- ...rules_fragments_on_composite_types_test.go | 29 +- ...t.go => rules_known_argument_names_test.go | 39 +- ....go => rules_known_directives_rule_test.go | 25 +- ...t.go => rules_known_fragment_names_test.go | 17 +- ..._test.go => rules_known_type_names_test.go | 15 +- ...ules_lone_anonymous_operation_rule_test.go | 23 +- ...est.go => rules_no_fragment_cycles_test.go | 45 +- ...go => rules_no_undefined_variables_test.go | 79 +-- ...st.go => rules_no_unused_fragments_test.go | 25 +- ...st.go => rules_no_unused_variables_test.go | 47 +- ...s_overlapping_fields_can_be_merged_test.go | 85 +-- ...=> rules_possible_fragment_spreads_test.go | 71 +-- ... rules_provided_non_null_arguments_test.go | 51 +- ...eafs_test.go => rules_scalar_leafs_test.go | 37 +- ....go => rules_unique_argument_names_test.go | 43 +- ....go => rules_unique_fragment_names_test.go | 23 +- ...go => rules_unique_operation_names_test.go | 25 +- ...=> rules_variables_are_input_types_test.go | 13 +- ...ules_variables_in_allowed_position_test.go | 61 +- testutil/rules_test_harness.go | 529 +++++++++++++++++ 25 files changed, 1053 insertions(+), 1038 deletions(-) delete mode 100644 rules/harness_test.go delete mode 100644 rules/rules.go rename rules/arguments_of_correct_type_test.go => rules_arguments_of_correct_type_test.go (78%) rename rules/default_values_of_correct_type_test.go => rules_default_values_of_correct_type_test.go (64%) rename rules/fields_on_correct_type_test.go => rules_fields_on_correct_type_test.go (64%) rename rules/fragments_on_composite_types_test.go => rules_fragments_on_composite_types_test.go (58%) rename rules/known_argument_names_test.go => rules_known_argument_names_test.go (62%) rename rules/known_directives_rule_test.go => rules_known_directives_rule_test.go (62%) rename rules/known_fragment_names_test.go => rules_known_fragment_names_test.go (62%) rename rules/known_type_names_test.go => rules_known_type_names_test.go (62%) rename rules/lone_anonymous_operation_rule_test.go => rules_lone_anonymous_operation_rule_test.go (57%) rename rules/no_fragment_cycles_test.go => rules_no_fragment_cycles_test.go (63%) rename rules/no_undefined_variables_test.go => rules_no_undefined_variables_test.go (65%) rename rules/no_unused_fragments_test.go => rules_no_unused_fragments_test.go (76%) rename rules/no_unused_variables_test.go => rules_no_unused_variables_test.go (72%) rename rules/overlapping_fields_can_be_merged_test.go => rules_overlapping_fields_can_be_merged_test.go (74%) rename rules/possible_fragment_spreads_test.go => rules_possible_fragment_spreads_test.go (70%) rename rules/provided_non_null_arguments_test.go => rules_provided_non_null_arguments_test.go (65%) rename rules/scalar_leafs_test.go => rules_scalar_leafs_test.go (59%) rename rules/unique_argument_names_test.go => rules_unique_argument_names_test.go (59%) rename rules/unique_fragment_names_test.go => rules_unique_fragment_names_test.go (67%) rename rules/unique_operation_names_test.go => rules_unique_operation_names_test.go (63%) rename rules/variables_are_input_types_test.go => rules_variables_are_input_types_test.go (51%) rename rules/variables_in_allowed_position_test.go => rules_variables_in_allowed_position_test.go (73%) create mode 100644 testutil/rules_test_harness.go diff --git a/rules/harness_test.go b/rules/harness_test.go deleted file mode 100644 index f8db06b2..00000000 --- a/rules/harness_test.go +++ /dev/null @@ -1,534 +0,0 @@ -package rules_test - -import ( - "testing" - - "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/language/location" - "github.com/graphql-go/graphql/language/parser" - "github.com/graphql-go/graphql/language/source" - "github.com/graphql-go/graphql/testutil" - "reflect" -) - -var beingInterface = graphql.NewInterface(graphql.InterfaceConfig{ - Name: "Being", - Fields: graphql.Fields{ - "name": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "surname": &graphql.ArgumentConfig{ - Type: graphql.Boolean, - }, - }, - }, - }, -}) -var petInterface = graphql.NewInterface(graphql.InterfaceConfig{ - Name: "Pet", - Fields: graphql.Fields{ - "name": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "surname": &graphql.ArgumentConfig{ - Type: graphql.Boolean, - }, - }, - }, - }, -}) -var dogCommandEnum = graphql.NewEnum(graphql.EnumConfig{ - Name: "DogCommand", - Values: graphql.EnumValueConfigMap{ - "SIT": &graphql.EnumValueConfig{ - Value: 0, - }, - "HEEL": &graphql.EnumValueConfig{ - Value: 1, - }, - "DOWN": &graphql.EnumValueConfig{ - Value: 2, - }, - }, -}) -var dogType = graphql.NewObject(graphql.ObjectConfig{ - Name: "Dog", - IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { - return true - }, - Fields: graphql.Fields{ - "name": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "surname": &graphql.ArgumentConfig{ - Type: graphql.Boolean, - }, - }, - }, - "nickname": &graphql.Field{ - Type: graphql.String, - }, - "barkVolume": &graphql.Field{ - Type: graphql.Int, - }, - "barks": &graphql.Field{ - Type: graphql.Boolean, - }, - "doesKnowCommand": &graphql.Field{ - Type: graphql.Boolean, - Args: graphql.FieldConfigArgument{ - "dogCommand": &graphql.ArgumentConfig{ - Type: dogCommandEnum, - }, - }, - }, - "isHousetrained": &graphql.Field{ - Type: graphql.Boolean, - Args: graphql.FieldConfigArgument{ - "atOtherHomes": &graphql.ArgumentConfig{ - Type: graphql.Boolean, - DefaultValue: true, - }, - }, - }, - "isAtLocation": &graphql.Field{ - Type: graphql.Boolean, - Args: graphql.FieldConfigArgument{ - "x": &graphql.ArgumentConfig{ - Type: graphql.Int, - }, - "y": &graphql.ArgumentConfig{ - Type: graphql.Int, - }, - }, - }, - }, - Interfaces: []*graphql.Interface{ - beingInterface, - petInterface, - }, -}) -var furColorEnum = graphql.NewEnum(graphql.EnumConfig{ - Name: "FurColor", - Values: graphql.EnumValueConfigMap{ - "BROWN": &graphql.EnumValueConfig{ - Value: 0, - }, - "BLACK": &graphql.EnumValueConfig{ - Value: 1, - }, - "TAN": &graphql.EnumValueConfig{ - Value: 2, - }, - "SPOTTED": &graphql.EnumValueConfig{ - Value: 3, - }, - }, -}) - -var catType = graphql.NewObject(graphql.ObjectConfig{ - Name: "Cat", - IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { - return true - }, - Fields: graphql.Fields{ - "name": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "surname": &graphql.ArgumentConfig{ - Type: graphql.Boolean, - }, - }, - }, - "nickname": &graphql.Field{ - Type: graphql.String, - }, - "meowVolume": &graphql.Field{ - Type: graphql.Int, - }, - "meows": &graphql.Field{ - Type: graphql.Boolean, - }, - "furColor": &graphql.Field{ - Type: furColorEnum, - }, - }, - Interfaces: []*graphql.Interface{ - beingInterface, - petInterface, - }, -}) -var catOrDogUnion = graphql.NewUnion(graphql.UnionConfig{ - Name: "CatOrDog", - Types: []*graphql.Object{ - dogType, - catType, - }, - ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { - // not used for validation - return nil - }, -}) -var intelligentInterface = graphql.NewInterface(graphql.InterfaceConfig{ - Name: "Intelligent", - Fields: graphql.Fields{ - "iq": &graphql.Field{ - Type: graphql.Int, - }, - }, -}) - -var humanType = graphql.NewObject(graphql.ObjectConfig{ - Name: "Human", - IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { - return true - }, - Interfaces: []*graphql.Interface{ - beingInterface, - intelligentInterface, - }, - Fields: graphql.Fields{ - "name": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "surname": &graphql.ArgumentConfig{ - Type: graphql.Boolean, - }, - }, - }, - "pets": &graphql.Field{ - Type: graphql.NewList(petInterface), - }, - "iq": &graphql.Field{ - Type: graphql.Int, - }, - // `relatives` field added later in init() - }, -}) - -var alienType = graphql.NewObject(graphql.ObjectConfig{ - Name: "Alien", - IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { - return true - }, - Interfaces: []*graphql.Interface{ - beingInterface, - intelligentInterface, - }, - Fields: graphql.Fields{ - "name": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "surname": &graphql.ArgumentConfig{ - Type: graphql.Boolean, - }, - }, - }, - "iq": &graphql.Field{ - Type: graphql.Int, - }, - "numEyes": &graphql.Field{ - Type: graphql.Int, - }, - }, -}) -var dogOrHumanUnion = graphql.NewUnion(graphql.UnionConfig{ - Name: "DogOrHuman", - Types: []*graphql.Object{ - dogType, - humanType, - }, - ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { - // not used for validation - return nil - }, -}) -var humanOrAlienUnion = graphql.NewUnion(graphql.UnionConfig{ - Name: "HumanOrAlien", - Types: []*graphql.Object{ - alienType, - humanType, - }, - ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { - // not used for validation - return nil - }, -}) - -var complexInputObject = graphql.NewInputObject(graphql.InputObjectConfig{ - Name: "ComplexInput", - Fields: graphql.InputObjectConfigFieldMap{ - "requiredField": &graphql.InputObjectFieldConfig{ - Type: graphql.NewNonNull(graphql.Boolean), - }, - "intField": &graphql.InputObjectFieldConfig{ - Type: graphql.Int, - }, - "stringField": &graphql.InputObjectFieldConfig{ - Type: graphql.String, - }, - "booleanField": &graphql.InputObjectFieldConfig{ - Type: graphql.Boolean, - }, - "stringListField": &graphql.InputObjectFieldConfig{ - Type: graphql.NewList(graphql.String), - }, - }, -}) -var complicatedArgs = graphql.NewObject(graphql.ObjectConfig{ - Name: "ComplicatedArgs", - // TODO List - // TODO Coercion - // TODO NotNulls - Fields: graphql.Fields{ - "intArgField": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "intArg": &graphql.ArgumentConfig{ - Type: graphql.Int, - }, - }, - }, - "nonNullIntArgField": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "nonNullIntArg": &graphql.ArgumentConfig{ - Type: graphql.NewNonNull(graphql.Int), - }, - }, - }, - "stringArgField": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "stringArg": &graphql.ArgumentConfig{ - Type: graphql.String, - }, - }, - }, - "booleanArgField": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "booleanArg": &graphql.ArgumentConfig{ - Type: graphql.Boolean, - }, - }, - }, - "enumArgField": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "enumArg": &graphql.ArgumentConfig{ - Type: furColorEnum, - }, - }, - }, - "floatArgField": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "floatArg": &graphql.ArgumentConfig{ - Type: graphql.Float, - }, - }, - }, - "idArgField": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "idArg": &graphql.ArgumentConfig{ - Type: graphql.ID, - }, - }, - }, - "stringListArgField": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "stringListArg": &graphql.ArgumentConfig{ - Type: graphql.NewList(graphql.String), - }, - }, - }, - "complexArgField": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "complexArg": &graphql.ArgumentConfig{ - Type: complexInputObject, - }, - }, - }, - "multipleReqs": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "req1": &graphql.ArgumentConfig{ - Type: graphql.NewNonNull(graphql.Int), - }, - "req2": &graphql.ArgumentConfig{ - Type: graphql.NewNonNull(graphql.Int), - }, - }, - }, - "multipleOpts": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "opt1": &graphql.ArgumentConfig{ - Type: graphql.Int, - DefaultValue: 0, - }, - "opt2": &graphql.ArgumentConfig{ - Type: graphql.Int, - DefaultValue: 0, - }, - }, - }, - "multipleOptAndReq": &graphql.Field{ - Type: graphql.String, - Args: graphql.FieldConfigArgument{ - "req1": &graphql.ArgumentConfig{ - Type: graphql.NewNonNull(graphql.Int), - }, - "req2": &graphql.ArgumentConfig{ - Type: graphql.NewNonNull(graphql.Int), - }, - "opt1": &graphql.ArgumentConfig{ - Type: graphql.Int, - DefaultValue: 0, - }, - "opt2": &graphql.ArgumentConfig{ - Type: graphql.Int, - DefaultValue: 0, - }, - }, - }, - }, -}) -var queryRoot *graphql.Object -var defaultSchema *graphql.Schema - -func init() { - - humanType.AddFieldConfig("relatives", &graphql.Field{ - Type: graphql.NewList(humanType), - }) - queryRoot = graphql.NewObject(graphql.ObjectConfig{ - Name: "QueryRoot", - Fields: graphql.Fields{ - "human": &graphql.Field{ - Args: graphql.FieldConfigArgument{ - "id": &graphql.ArgumentConfig{ - Type: graphql.ID, - }, - }, - Type: humanType, - }, - "alien": &graphql.Field{ - Type: alienType, - }, - "dog": &graphql.Field{ - Type: dogType, - }, - "cat": &graphql.Field{ - Type: catType, - }, - "pet": &graphql.Field{ - Type: petInterface, - }, - "catOrDog": &graphql.Field{ - Type: catOrDogUnion, - }, - "dogOrHuman": &graphql.Field{ - Type: dogOrHumanUnion, - }, - "humanOrAlien": &graphql.Field{ - Type: humanOrAlienUnion, - }, - "complicatedArgs": &graphql.Field{ - Type: complicatedArgs, - }, - }, - }) - schema, err := graphql.NewSchema(graphql.SchemaConfig{ - Query: queryRoot, - }) - if err != nil { - panic(err) - } - defaultSchema = &schema - -} -func expectValid(t *testing.T, schema *graphql.Schema, rules []graphql.ValidationRuleFn, queryString string) { - source := source.NewSource(&source.Source{ - Body: queryString, - }) - AST, err := parser.Parse(parser.ParseParams{Source: source}) - if err != nil { - t.Fatal(err) - } - result := graphql.ValidateDocument(schema, AST, rules) - if len(result.Errors) > 0 { - t.Fatalf("Should validate, got %v", result.Errors) - } - if result.IsValid != true { - t.Fatalf("IsValid should be true, got %v", result.IsValid) - } - -} -func expectInvalid(t *testing.T, schema *graphql.Schema, rules []graphql.ValidationRuleFn, queryString string, expectedErrors []gqlerrors.FormattedError) { - source := source.NewSource(&source.Source{ - Body: queryString, - }) - AST, err := parser.Parse(parser.ParseParams{Source: source}) - if err != nil { - t.Fatal(err) - } - result := graphql.ValidateDocument(schema, AST, rules) - if len(result.Errors) != len(expectedErrors) { - t.Fatalf("Should have %v errors, got %v", len(expectedErrors), len(result.Errors)) - } - if result.IsValid != false { - t.Fatalf("IsValid should be false, got %v", result.IsValid) - } - for _, expectedErr := range expectedErrors { - found := false - for _, err := range result.Errors { - if reflect.DeepEqual(expectedErr, err) { - found = true - break - } - } - if found == false { - t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expectedErrors, result.Errors)) - } - } - -} -func expectPassesRule(t *testing.T, rule graphql.ValidationRuleFn, queryString string) { - expectValid(t, defaultSchema, []graphql.ValidationRuleFn{rule}, queryString) -} -func expectFailsRule(t *testing.T, rule graphql.ValidationRuleFn, queryString string, expectedErrors []gqlerrors.FormattedError) { - expectInvalid(t, defaultSchema, []graphql.ValidationRuleFn{rule}, queryString, expectedErrors) -} - -func expectFailsRuleWithSchema(t *testing.T, schema *graphql.Schema, rule graphql.ValidationRuleFn, queryString string, expectedErrors []gqlerrors.FormattedError) { - expectInvalid(t, schema, []graphql.ValidationRuleFn{rule}, queryString, expectedErrors) -} - -func expectPassesRuleWithSchema(t *testing.T, schema *graphql.Schema, rule graphql.ValidationRuleFn, queryString string) { - expectValid(t, schema, []graphql.ValidationRuleFn{rule}, queryString) -} - -func ruleError(message string, locs ...int) gqlerrors.FormattedError { - locations := []location.SourceLocation{} - for i := 0; i < len(locs); i = i + 2 { - line := locs[i] - col := 0 - if i+1 < len(locs) { - col = locs[i+1] - } - locations = append(locations, location.SourceLocation{ - Line: line, - Column: col, - }) - } - return gqlerrors.FormattedError{ - Message: message, - Locations: locations, - } -} diff --git a/rules/rules.go b/rules/rules.go deleted file mode 100644 index 1e8c7fa0..00000000 --- a/rules/rules.go +++ /dev/null @@ -1 +0,0 @@ -package rules diff --git a/rules/arguments_of_correct_type_test.go b/rules_arguments_of_correct_type_test.go similarity index 78% rename from rules/arguments_of_correct_type_test.go rename to rules_arguments_of_correct_type_test.go index 14102946..c48e45aa 100644 --- a/rules/arguments_of_correct_type_test.go +++ b/rules_arguments_of_correct_type_test.go @@ -1,14 +1,15 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodIntValue(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { intArgField(intArg: 2) @@ -17,7 +18,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodIntValue(t *testing.T) { `) } func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodBooleanValue(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { booleanArgField(booleanArg: true) @@ -26,7 +27,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodBooleanValue(t *testing. `) } func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodStringValue(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { stringArgField(stringArg: "foo") @@ -35,7 +36,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodStringValue(t *testing.T `) } func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodFloatValue(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { floatArgField(floatArg: 1.1) @@ -44,7 +45,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodFloatValue(t *testing.T) `) } func TestValidate_ArgValuesOfCorrectType_ValidValue_IntIntoFloat(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { floatArgField(floatArg: 1) @@ -53,7 +54,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidValue_IntIntoFloat(t *testing.T) { `) } func TestValidate_ArgValuesOfCorrectType_ValidValue_IntIntoID(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { idArgField(idArg: 1) @@ -62,7 +63,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidValue_IntIntoID(t *testing.T) { `) } func TestValidate_ArgValuesOfCorrectType_ValidValue_StringIntoID(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { idArgField(idArg: "someIdString") @@ -71,7 +72,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidValue_StringIntoID(t *testing.T) { `) } func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodEnumValue(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { dog { doesKnowCommand(dogCommand: SIT) @@ -81,7 +82,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidValue_GoodEnumValue(t *testing.T) } func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_IntIntoString(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { stringArgField(stringArg: 1) @@ -89,14 +90,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_IntIntoString(t *te } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "stringArg" expected type "String" but got: 1.`, 4, 39, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_FloatIntoString(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { stringArgField(stringArg: 1.0) @@ -104,14 +105,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_FloatIntoString(t * } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "stringArg" expected type "String" but got: 1.0.`, 4, 39, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_BooleanIntoString(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { stringArgField(stringArg: true) @@ -119,14 +120,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_BooleanIntoString(t } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "stringArg" expected type "String" but got: true.`, 4, 39, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_UnquotedStringIntoString(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { stringArgField(stringArg: BAR) @@ -134,7 +135,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_UnquotedStringIntoS } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "stringArg" expected type "String" but got: BAR.`, 4, 39, ), @@ -142,7 +143,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_UnquotedStringIntoS } func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_BigIntIntoInt(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { intArgField(intArg: 829384293849283498239482938) @@ -150,14 +151,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_BigIntIntoInt(t *testi } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "intArg" expected type "Int" but got: 829384293849283498239482938.`, 4, 33, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_UnquotedStringIntoInt(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { intArgField(intArg: FOO) @@ -165,14 +166,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_UnquotedStringIntoInt( } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "intArg" expected type "Int" but got: FOO.`, 4, 33, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_SimpleFloatIntoInt(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { intArgField(intArg: 3.0) @@ -180,14 +181,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_SimpleFloatIntoInt(t * } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "intArg" expected type "Int" but got: 3.0.`, 4, 33, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_FloatIntoInt(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { intArgField(intArg: 3.333) @@ -195,7 +196,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_FloatIntoInt(t *testin } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "intArg" expected type "Int" but got: 3.333.`, 4, 33, ), @@ -203,7 +204,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_FloatIntoInt(t *testin } func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_IntIntoBoolean(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { booleanArgField(booleanArg: 2) @@ -211,14 +212,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_IntIntoBoolean(t * } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "booleanArg" expected type "Boolean" but got: 2.`, 4, 41, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_FloatIntoBoolean(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { booleanArgField(booleanArg: 1.0) @@ -226,14 +227,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_FloatIntoBoolean(t } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "booleanArg" expected type "Boolean" but got: 1.0.`, 4, 41, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_StringIntoBoolean(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { booleanArgField(booleanArg: "true") @@ -241,14 +242,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_StringIntoBoolean( } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "booleanArg" expected type "Boolean" but got: "true".`, 4, 41, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_UnquotedStringIntoBoolean(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { booleanArgField(booleanArg: TRUE) @@ -256,7 +257,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_UnquotedStringInto } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "booleanArg" expected type "Boolean" but got: TRUE.`, 4, 41, ), @@ -264,7 +265,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_UnquotedStringInto } func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_FloatIntoID(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { idArgField(idArg: 1.0) @@ -272,14 +273,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_FloatIntoID(t *testing. } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "idArg" expected type "ID" but got: 1.0.`, 4, 31, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_BooleanIntoID(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { idArgField(idArg: true) @@ -287,14 +288,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_BooleanIntoID(t *testin } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "idArg" expected type "ID" but got: true.`, 4, 31, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_UnquotedIntoID(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { idArgField(idArg: SOMETHING) @@ -302,7 +303,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_UnquotedIntoID(t *testi } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "idArg" expected type "ID" but got: SOMETHING.`, 4, 31, ), @@ -310,7 +311,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_UnquotedIntoID(t *testi } func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_IntIntoEnum(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { dog { doesKnowCommand(dogCommand: 2) @@ -318,14 +319,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_IntIntoEnum(t *testing } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "dogCommand" expected type "DogCommand" but got: 2.`, 4, 41, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_FloatIntoEnum(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { dog { doesKnowCommand(dogCommand: 1.0) @@ -333,14 +334,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_FloatIntoEnum(t *testi } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "dogCommand" expected type "DogCommand" but got: 1.0.`, 4, 41, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_StringIntoEnum(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { dog { doesKnowCommand(dogCommand: "SIT") @@ -348,14 +349,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_StringIntoEnum(t *test } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "dogCommand" expected type "DogCommand" but got: "SIT".`, 4, 41, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_BooleanIntoEnum(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { dog { doesKnowCommand(dogCommand: true) @@ -363,14 +364,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_BooleanIntoEnum(t *tes } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "dogCommand" expected type "DogCommand" but got: true.`, 4, 41, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_UnknownEnumValueIntoEnum(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { dog { doesKnowCommand(dogCommand: JUGGLE) @@ -378,14 +379,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_UnknownEnumValueIntoEn } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "dogCommand" expected type "DogCommand" but got: JUGGLE.`, 4, 41, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_DifferentCaseEnumValueIntoEnum(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { dog { doesKnowCommand(dogCommand: sit) @@ -393,7 +394,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_DifferentCaseEnumValue } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "dogCommand" expected type "DogCommand" but got: sit.`, 4, 41, ), @@ -401,7 +402,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidEnumValue_DifferentCaseEnumValue } func TestValidate_ArgValuesOfCorrectType_ValidListValue_GoodListValue(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { stringListArgField(stringListArg: ["one", "two"]) @@ -410,7 +411,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidListValue_GoodListValue(t *testing `) } func TestValidate_ArgValuesOfCorrectType_ValidListValue_EmptyListValue(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { stringListArgField(stringListArg: []) @@ -419,7 +420,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidListValue_EmptyListValue(t *testin `) } func TestValidate_ArgValuesOfCorrectType_ValidListValue_SingleValueIntoList(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { stringListArgField(stringListArg: "one") @@ -429,7 +430,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidListValue_SingleValueIntoList(t *t } func TestValidate_ArgValuesOfCorrectType_InvalidListValue_IncorrectItemType(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { stringListArgField(stringListArg: ["one", 2]) @@ -437,14 +438,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidListValue_IncorrectItemType(t *t } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "stringListArg" expected type "[String]" but got: ["one", 2].`, 4, 47, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidListValue_SingleValueOfIncorrentType(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { stringListArgField(stringListArg: 1) @@ -452,7 +453,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidListValue_SingleValueOfIncorrent } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "stringListArg" expected type "[String]" but got: 1.`, 4, 47, ), @@ -460,7 +461,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidListValue_SingleValueOfIncorrent } func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_ArgOnOptionalArg(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { dog { isHousetrained(atOtherHomes: true) @@ -469,7 +470,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_ArgOnOptionalArg( `) } func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_NoArgOnOptionalArg(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { dog { isHousetrained @@ -478,7 +479,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_NoArgOnOptionalAr `) } func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_MultipleArgs(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { multipleReqs(req1: 1, req2: 2) @@ -487,7 +488,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_MultipleArgs(t *t `) } func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_MultipleArgsReverseOrder(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { multipleReqs(req2: 2, req1: 1) @@ -496,7 +497,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_MultipleArgsRever `) } func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_NoArgsOnMultipleOptional(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { multipleOpts @@ -505,7 +506,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_NoArgsOnMultipleO `) } func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_OneArgOnMultipleOptional(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { multipleOpts(opt1: 1) @@ -514,7 +515,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_OneArgOnMultipleO `) } func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_SecondArgOnMultipleOptional(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { multipleOpts(opt2: 1) @@ -523,7 +524,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_SecondArgOnMultip `) } func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_MultipleRequiredsOnMixedList(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4) @@ -532,7 +533,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_MultipleRequireds `) } func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_MultipleRequiredsAndOptionalOnMixedList(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5) @@ -541,7 +542,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_MultipleRequireds `) } func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_AllRequiredsAndOptionalOnMixedList(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) @@ -551,7 +552,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidNonNullableValue_AllRequiredsAndOp } func TestValidate_ArgValuesOfCorrectType_InvalidNonNullableValue_IncorrectValueType(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { multipleReqs(req2: "two", req1: "one") @@ -559,18 +560,18 @@ func TestValidate_ArgValuesOfCorrectType_InvalidNonNullableValue_IncorrectValueT } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "req2" expected type "Int!" but got: "two".`, 4, 32, ), - ruleError( + testutil.RuleError( `Argument "req1" expected type "Int!" but got: "one".`, 4, 45, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidNonNullableValue_IncorrectValueAndMissingArgument(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { multipleReqs(req1: "one") @@ -578,7 +579,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidNonNullableValue_IncorrectValueA } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "req1" expected type "Int!" but got: "one".`, 4, 32, ), @@ -586,7 +587,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidNonNullableValue_IncorrectValueA } func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_OptionalArg_DespiteRequiredFieldInType(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { complexArgField @@ -595,7 +596,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_OptionalArg_Despi `) } func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_PartialObject_OnlyRequired(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { complexArgField(complexArg: { requiredField: true }) @@ -604,7 +605,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_PartialObject_Onl `) } func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_PartialObject_RequiredFieldCanBeFalsey(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { complexArgField(complexArg: { requiredField: false }) @@ -613,7 +614,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_PartialObject_Req `) } func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_PartialObject_IncludingRequired(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { complexArgField(complexArg: { requiredField: false }) @@ -622,7 +623,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_PartialObject_Inc `) } func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_FullObject(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { complexArgField(complexArg: { @@ -637,7 +638,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_FullObject(t *tes `) } func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_FullObject_WithFieldsInDifferentOrder(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { complexArgField(complexArg: { @@ -653,7 +654,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_FullObject_WithFi } func TestValidate_ArgValuesOfCorrectType_InvalidInputObjectValue_PartialObject_MissingRequired(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { complexArgField(complexArg: { intField: 4 }) @@ -661,14 +662,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidInputObjectValue_PartialObject_M } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "complexArg" expected type "ComplexInput" but got: {intField: 4}.`, 4, 41, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidInputObjectValue_PartialObject_InvalidFieldType(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { complexArgField(complexArg: { @@ -679,14 +680,14 @@ func TestValidate_ArgValuesOfCorrectType_InvalidInputObjectValue_PartialObject_I } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "complexArg" expected type "ComplexInput" but got: {stringListField: ["one", 2], requiredField: true}.`, 4, 41, ), }) } func TestValidate_ArgValuesOfCorrectType_InvalidInputObjectValue_PartialObject_UnknownFieldArg(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { complexArgField(complexArg: { @@ -697,7 +698,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidInputObjectValue_PartialObject_U } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "complexArg" expected type "ComplexInput" but got: {requiredField: true, unknownField: "value"}.`, 4, 41, ), @@ -705,7 +706,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidInputObjectValue_PartialObject_U } func TestValidate_ArgValuesOfCorrectType_DirectiveArguments_WithDirectivesOfValidType(t *testing.T) { - expectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { dog @include(if: true) { name @@ -717,7 +718,7 @@ func TestValidate_ArgValuesOfCorrectType_DirectiveArguments_WithDirectivesOfVali `) } func TestValidate_ArgValuesOfCorrectType_DirectiveArguments_WithDirectivesWithIncorrectTypes(t *testing.T) { - expectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { dog @include(if: "yes") { name @skip(if: ENUM) @@ -725,11 +726,11 @@ func TestValidate_ArgValuesOfCorrectType_DirectiveArguments_WithDirectivesWithIn } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Argument "if" expected type "Boolean!" but got: "yes".`, 3, 28, ), - ruleError( + testutil.RuleError( `Argument "if" expected type "Boolean!" but got: ENUM.`, 4, 28, ), diff --git a/rules/default_values_of_correct_type_test.go b/rules_default_values_of_correct_type_test.go similarity index 64% rename from rules/default_values_of_correct_type_test.go rename to rules_default_values_of_correct_type_test.go index 201a6b44..d4085407 100644 --- a/rules/default_values_of_correct_type_test.go +++ b/rules_default_values_of_correct_type_test.go @@ -1,28 +1,29 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_VariableDefaultValuesOfCorrectType_VariablesWithNoDefaultValues(t *testing.T) { - expectPassesRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` query NullableValues($a: Int, $b: String, $c: ComplexInput) { dog { name } } `) } func TestValidate_VariableDefaultValuesOfCorrectType_RequiredVariablesWithoutDefaultValues(t *testing.T) { - expectPassesRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` query RequiredValues($a: Int!, $b: String!) { dog { name } } `) } func TestValidate_VariableDefaultValuesOfCorrectType_VariablesWithValidDefaultValues(t *testing.T) { - expectPassesRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` query WithDefaultValues( $a: Int = 1, $b: String = "ok", @@ -34,18 +35,18 @@ func TestValidate_VariableDefaultValuesOfCorrectType_VariablesWithValidDefaultVa } func TestValidate_VariableDefaultValuesOfCorrectType_NoRequiredVariablesWithDefaultValues(t *testing.T) { - expectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` query UnreachableDefaultValues($a: Int! = 3, $b: String! = "default") { dog { name } } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Variable "$a" of type "Int!" is required and will not `+ `use the default value. Perhaps you meant to use type "Int".`, 2, 49, ), - ruleError( + testutil.RuleError( `Variable "$b" of type "String!" is required and will not `+ `use the default value. Perhaps you meant to use type "String".`, 2, 66, @@ -53,7 +54,7 @@ func TestValidate_VariableDefaultValuesOfCorrectType_NoRequiredVariablesWithDefa }) } func TestValidate_VariableDefaultValuesOfCorrectType_VariablesWithInvalidDefaultValues(t *testing.T) { - expectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` query InvalidDefaultValues( $a: Int = "one", $b: String = 4, @@ -63,30 +64,30 @@ func TestValidate_VariableDefaultValuesOfCorrectType_VariablesWithInvalidDefault } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$a" of type "Int" has invalid default value: "one".`, 3, 19), - ruleError(`Variable "$b" of type "String" has invalid default value: 4.`, 4, 22), - ruleError(`Variable "$c" of type "ComplexInput" has invalid default value: "notverycomplex".`, 5, 28), + testutil.RuleError(`Variable "$a" of type "Int" has invalid default value: "one".`, 3, 19), + testutil.RuleError(`Variable "$b" of type "String" has invalid default value: 4.`, 4, 22), + testutil.RuleError(`Variable "$c" of type "ComplexInput" has invalid default value: "notverycomplex".`, 5, 28), }) } func TestValidate_VariableDefaultValuesOfCorrectType_ComplexVariablesMissingRequiredField(t *testing.T) { - expectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` query MissingRequiredField($a: ComplexInput = {intField: 3}) { dog { name } } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$a" of type "ComplexInput" has invalid default value: {intField: 3}.`, 2, 53), + testutil.RuleError(`Variable "$a" of type "ComplexInput" has invalid default value: {intField: 3}.`, 2, 53), }) } func TestValidate_VariableDefaultValuesOfCorrectType_ListVariablesWithInvalidItem(t *testing.T) { - expectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` query InvalidItem($a: [String] = ["one", 2]) { dog { name } } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$a" of type "[String]" has invalid default value: ["one", 2].`, 2, 40), + testutil.RuleError(`Variable "$a" of type "[String]" has invalid default value: ["one", 2].`, 2, 40), }) } diff --git a/rules/fields_on_correct_type_test.go b/rules_fields_on_correct_type_test.go similarity index 64% rename from rules/fields_on_correct_type_test.go rename to rules_fields_on_correct_type_test.go index 1fb1d0af..c060289f 100644 --- a/rules/fields_on_correct_type_test.go +++ b/rules_fields_on_correct_type_test.go @@ -1,15 +1,15 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - // "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_FieldsOnCorrectType_ObjectFieldSelection(t *testing.T) { - expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment objectFieldSelection on Dog { __typename name @@ -17,7 +17,7 @@ func TestValidate_FieldsOnCorrectType_ObjectFieldSelection(t *testing.T) { `) } func TestValidate_FieldsOnCorrectType_AliasedObjectFieldSelection(t *testing.T) { - expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment aliasedObjectFieldSelection on Dog { tn : __typename otherName : name @@ -25,7 +25,7 @@ func TestValidate_FieldsOnCorrectType_AliasedObjectFieldSelection(t *testing.T) `) } func TestValidate_FieldsOnCorrectType_InterfaceFieldSelection(t *testing.T) { - expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment interfaceFieldSelection on Pet { __typename name @@ -33,131 +33,131 @@ func TestValidate_FieldsOnCorrectType_InterfaceFieldSelection(t *testing.T) { `) } func TestValidate_FieldsOnCorrectType_AliasedInterfaceFieldSelection(t *testing.T) { - expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment interfaceFieldSelection on Pet { otherName : name } `) } func TestValidate_FieldsOnCorrectType_LyingAliasSelection(t *testing.T) { - expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment lyingAliasSelection on Dog { name : nickname } `) } func TestValidate_FieldsOnCorrectType_IgnoresFieldsOnUnknownType(t *testing.T) { - expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment unknownSelection on UnknownType { unknownField } `) } func TestValidate_FieldsOnCorrectType_FieldNotDefinedOnFragment(t *testing.T) { - expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment fieldNotDefined on Dog { meowVolume } `, []gqlerrors.FormattedError{ - ruleError(`Cannot query field "meowVolume" on "Dog".`, 3, 9), + testutil.RuleError(`Cannot query field "meowVolume" on "Dog".`, 3, 9), }) } func TestValidate_FieldsOnCorrectType_FieldNotDefinedDeeplyOnlyReportsFirst(t *testing.T) { - expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment deepFieldNotDefined on Dog { unknown_field { deeper_unknown_field } } `, []gqlerrors.FormattedError{ - ruleError(`Cannot query field "unknown_field" on "Dog".`, 3, 9), + testutil.RuleError(`Cannot query field "unknown_field" on "Dog".`, 3, 9), }) } func TestValidate_FieldsOnCorrectType_SubFieldNotDefined(t *testing.T) { - expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment subFieldNotDefined on Human { pets { unknown_field } } `, []gqlerrors.FormattedError{ - ruleError(`Cannot query field "unknown_field" on "Pet".`, 4, 11), + testutil.RuleError(`Cannot query field "unknown_field" on "Pet".`, 4, 11), }) } func TestValidate_FieldsOnCorrectType_FieldNotDefinedOnInlineFragment(t *testing.T) { - expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment fieldNotDefined on Pet { ... on Dog { meowVolume } } `, []gqlerrors.FormattedError{ - ruleError(`Cannot query field "meowVolume" on "Dog".`, 4, 11), + testutil.RuleError(`Cannot query field "meowVolume" on "Dog".`, 4, 11), }) } func TestValidate_FieldsOnCorrectType_AliasedFieldTargetNotDefined(t *testing.T) { - expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment aliasedFieldTargetNotDefined on Dog { volume : mooVolume } `, []gqlerrors.FormattedError{ - ruleError(`Cannot query field "mooVolume" on "Dog".`, 3, 9), + testutil.RuleError(`Cannot query field "mooVolume" on "Dog".`, 3, 9), }) } func TestValidate_FieldsOnCorrectType_AliasedLyingFieldTargetNotDefined(t *testing.T) { - expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment aliasedLyingFieldTargetNotDefined on Dog { barkVolume : kawVolume } `, []gqlerrors.FormattedError{ - ruleError(`Cannot query field "kawVolume" on "Dog".`, 3, 9), + testutil.RuleError(`Cannot query field "kawVolume" on "Dog".`, 3, 9), }) } func TestValidate_FieldsOnCorrectType_NotDefinedOnInterface(t *testing.T) { - expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment notDefinedOnInterface on Pet { tailLength } `, []gqlerrors.FormattedError{ - ruleError(`Cannot query field "tailLength" on "Pet".`, 3, 9), + testutil.RuleError(`Cannot query field "tailLength" on "Pet".`, 3, 9), }) } func TestValidate_FieldsOnCorrectType_DefinedOnImplementorsButNotOnInterface(t *testing.T) { - expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment definedOnImplementorsButNotInterface on Pet { nickname } `, []gqlerrors.FormattedError{ - ruleError(`Cannot query field "nickname" on "Pet".`, 3, 9), + testutil.RuleError(`Cannot query field "nickname" on "Pet".`, 3, 9), }) } func TestValidate_FieldsOnCorrectType_MetaFieldSelectionOnUnion(t *testing.T) { - expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment directFieldSelectionOnUnion on CatOrDog { __typename } `) } func TestValidate_FieldsOnCorrectType_DirectFieldSelectionOnUnion(t *testing.T) { - expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment directFieldSelectionOnUnion on CatOrDog { directField } `, []gqlerrors.FormattedError{ - ruleError(`Cannot query field "directField" on "CatOrDog".`, 3, 9), + testutil.RuleError(`Cannot query field "directField" on "CatOrDog".`, 3, 9), }) } func TestValidate_FieldsOnCorrectType_DirectImplementorsQueriedOnUnion(t *testing.T) { - expectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectFailsRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment definedOnImplementorsQueriedOnUnion on CatOrDog { name } `, []gqlerrors.FormattedError{ - ruleError(`Cannot query field "name" on "CatOrDog".`, 3, 9), + testutil.RuleError(`Cannot query field "name" on "CatOrDog".`, 3, 9), }) } func TestValidate_FieldsOnCorrectType_ValidFieldInInlineFragment(t *testing.T) { - expectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` + testutil.ExpectPassesRule(t, graphql.FieldsOnCorrectTypeRule, ` fragment objectFieldSelection on Pet { ... on Dog { name diff --git a/rules/fragments_on_composite_types_test.go b/rules_fragments_on_composite_types_test.go similarity index 58% rename from rules/fragments_on_composite_types_test.go rename to rules_fragments_on_composite_types_test.go index 97655c1d..3b001286 100644 --- a/rules/fragments_on_composite_types_test.go +++ b/rules_fragments_on_composite_types_test.go @@ -1,28 +1,29 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_FragmentsOnCompositeTypes_ObjectIsValidFragmentType(t *testing.T) { - expectPassesRule(t, graphql.FragmentsOnCompositeTypesRule, ` + testutil.ExpectPassesRule(t, graphql.FragmentsOnCompositeTypesRule, ` fragment validFragment on Dog { barks } `) } func TestValidate_FragmentsOnCompositeTypes_InterfaceIsValidFragmentType(t *testing.T) { - expectPassesRule(t, graphql.FragmentsOnCompositeTypesRule, ` + testutil.ExpectPassesRule(t, graphql.FragmentsOnCompositeTypesRule, ` fragment validFragment on Pet { name } `) } func TestValidate_FragmentsOnCompositeTypes_ObjectIsValidInlineFragmentType(t *testing.T) { - expectPassesRule(t, graphql.FragmentsOnCompositeTypesRule, ` + testutil.ExpectPassesRule(t, graphql.FragmentsOnCompositeTypesRule, ` fragment validFragment on Pet { ... on Dog { barks @@ -31,7 +32,7 @@ func TestValidate_FragmentsOnCompositeTypes_ObjectIsValidInlineFragmentType(t *t `) } func TestValidate_FragmentsOnCompositeTypes_UnionIsValidFragmentType(t *testing.T) { - expectPassesRule(t, graphql.FragmentsOnCompositeTypesRule, ` + testutil.ExpectPassesRule(t, graphql.FragmentsOnCompositeTypesRule, ` fragment validFragment on CatOrDog { __typename } @@ -39,40 +40,40 @@ func TestValidate_FragmentsOnCompositeTypes_UnionIsValidFragmentType(t *testing. } func TestValidate_FragmentsOnCompositeTypes_ScalarIsInvalidFragmentType(t *testing.T) { - expectFailsRule(t, graphql.FragmentsOnCompositeTypesRule, ` + testutil.ExpectFailsRule(t, graphql.FragmentsOnCompositeTypesRule, ` fragment scalarFragment on Boolean { bad } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "scalarFragment" cannot condition on non composite type "Boolean".`, 2, 34), + testutil.RuleError(`Fragment "scalarFragment" cannot condition on non composite type "Boolean".`, 2, 34), }) } func TestValidate_FragmentsOnCompositeTypes_EnumIsInvalidFragmentType(t *testing.T) { - expectFailsRule(t, graphql.FragmentsOnCompositeTypesRule, ` + testutil.ExpectFailsRule(t, graphql.FragmentsOnCompositeTypesRule, ` fragment scalarFragment on FurColor { bad } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "scalarFragment" cannot condition on non composite type "FurColor".`, 2, 34), + testutil.RuleError(`Fragment "scalarFragment" cannot condition on non composite type "FurColor".`, 2, 34), }) } func TestValidate_FragmentsOnCompositeTypes_InputObjectIsInvalidFragmentType(t *testing.T) { - expectFailsRule(t, graphql.FragmentsOnCompositeTypesRule, ` + testutil.ExpectFailsRule(t, graphql.FragmentsOnCompositeTypesRule, ` fragment inputFragment on ComplexInput { stringField } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "inputFragment" cannot condition on non composite type "ComplexInput".`, 2, 33), + testutil.RuleError(`Fragment "inputFragment" cannot condition on non composite type "ComplexInput".`, 2, 33), }) } func TestValidate_FragmentsOnCompositeTypes_ScalarIsInvalidInlineFragmentType(t *testing.T) { - expectFailsRule(t, graphql.FragmentsOnCompositeTypesRule, ` + testutil.ExpectFailsRule(t, graphql.FragmentsOnCompositeTypesRule, ` fragment invalidFragment on Pet { ... on String { barks } } `, []gqlerrors.FormattedError{ - ruleError(`Fragment cannot condition on non composite type "String".`, 3, 16), + testutil.RuleError(`Fragment cannot condition on non composite type "String".`, 3, 16), }) } diff --git a/rules/known_argument_names_test.go b/rules_known_argument_names_test.go similarity index 62% rename from rules/known_argument_names_test.go rename to rules_known_argument_names_test.go index 743f3466..3d8c65a5 100644 --- a/rules/known_argument_names_test.go +++ b/rules_known_argument_names_test.go @@ -1,49 +1,50 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_KnownArgumentNames_SingleArgIsKnown(t *testing.T) { - expectPassesRule(t, graphql.KnownArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.KnownArgumentNamesRule, ` fragment argOnRequiredArg on Dog { doesKnowCommand(dogCommand: SIT) } `) } func TestValidate_KnownArgumentNames_MultipleArgsAreKnown(t *testing.T) { - expectPassesRule(t, graphql.KnownArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.KnownArgumentNamesRule, ` fragment multipleArgs on ComplicatedArgs { multipleReqs(req1: 1, req2: 2) } `) } func TestValidate_KnownArgumentNames_IgnoresArgsOfUnknownFields(t *testing.T) { - expectPassesRule(t, graphql.KnownArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.KnownArgumentNamesRule, ` fragment argOnUnknownField on Dog { unknownField(unknownArg: SIT) } `) } func TestValidate_KnownArgumentNames_MultipleArgsInReverseOrderAreKnown(t *testing.T) { - expectPassesRule(t, graphql.KnownArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.KnownArgumentNamesRule, ` fragment multipleArgsReverseOrder on ComplicatedArgs { multipleReqs(req2: 2, req1: 1) } `) } func TestValidate_KnownArgumentNames_NoArgsOnOptionalArg(t *testing.T) { - expectPassesRule(t, graphql.KnownArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.KnownArgumentNamesRule, ` fragment noArgOnOptionalArg on Dog { isHousetrained } `) } func TestValidate_KnownArgumentNames_ArgsAreKnownDeeply(t *testing.T) { - expectPassesRule(t, graphql.KnownArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.KnownArgumentNamesRule, ` { dog { doesKnowCommand(dogCommand: SIT) @@ -59,42 +60,42 @@ func TestValidate_KnownArgumentNames_ArgsAreKnownDeeply(t *testing.T) { `) } func TestValidate_KnownArgumentNames_DirectiveArgsAreKnown(t *testing.T) { - expectPassesRule(t, graphql.KnownArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.KnownArgumentNamesRule, ` { dog @skip(if: true) } `) } func TestValidate_KnownArgumentNames_UndirectiveArgsAreInvalid(t *testing.T) { - expectFailsRule(t, graphql.KnownArgumentNamesRule, ` + testutil.ExpectFailsRule(t, graphql.KnownArgumentNamesRule, ` { dog @skip(unless: true) } `, []gqlerrors.FormattedError{ - ruleError(`Unknown argument "unless" on directive "@skip".`, 3, 19), + testutil.RuleError(`Unknown argument "unless" on directive "@skip".`, 3, 19), }) } func TestValidate_KnownArgumentNames_InvalidArgName(t *testing.T) { - expectFailsRule(t, graphql.KnownArgumentNamesRule, ` + testutil.ExpectFailsRule(t, graphql.KnownArgumentNamesRule, ` fragment invalidArgName on Dog { doesKnowCommand(unknown: true) } `, []gqlerrors.FormattedError{ - ruleError(`Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".`, 3, 25), + testutil.RuleError(`Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".`, 3, 25), }) } func TestValidate_KnownArgumentNames_UnknownArgsAmongstKnownArgs(t *testing.T) { - expectFailsRule(t, graphql.KnownArgumentNamesRule, ` + testutil.ExpectFailsRule(t, graphql.KnownArgumentNamesRule, ` fragment oneGoodArgOneInvalidArg on Dog { doesKnowCommand(whoknows: 1, dogCommand: SIT, unknown: true) } `, []gqlerrors.FormattedError{ - ruleError(`Unknown argument "whoknows" on field "doesKnowCommand" of type "Dog".`, 3, 25), - ruleError(`Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".`, 3, 55), + testutil.RuleError(`Unknown argument "whoknows" on field "doesKnowCommand" of type "Dog".`, 3, 25), + testutil.RuleError(`Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".`, 3, 55), }) } func TestValidate_KnownArgumentNames_UnknownArgsDeeply(t *testing.T) { - expectFailsRule(t, graphql.KnownArgumentNamesRule, ` + testutil.ExpectFailsRule(t, graphql.KnownArgumentNamesRule, ` { dog { doesKnowCommand(unknown: true) @@ -108,7 +109,7 @@ func TestValidate_KnownArgumentNames_UnknownArgsDeeply(t *testing.T) { } } `, []gqlerrors.FormattedError{ - ruleError(`Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".`, 4, 27), - ruleError(`Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".`, 9, 31), + testutil.RuleError(`Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".`, 4, 27), + testutil.RuleError(`Unknown argument "unknown" on field "doesKnowCommand" of type "Dog".`, 9, 31), }) } diff --git a/rules/known_directives_rule_test.go b/rules_known_directives_rule_test.go similarity index 62% rename from rules/known_directives_rule_test.go rename to rules_known_directives_rule_test.go index 43fc32f6..f8f86d2d 100644 --- a/rules/known_directives_rule_test.go +++ b/rules_known_directives_rule_test.go @@ -1,14 +1,15 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_KnownDirectives_WithNoDirectives(t *testing.T) { - expectPassesRule(t, graphql.KnownDirectivesRule, ` + testutil.ExpectPassesRule(t, graphql.KnownDirectivesRule, ` query Foo { name ...Frag @@ -20,18 +21,18 @@ func TestValidate_KnownDirectives_WithNoDirectives(t *testing.T) { `) } func TestValidate_KnownDirectives_WithUnknownDirective(t *testing.T) { - expectFailsRule(t, graphql.KnownDirectivesRule, ` + testutil.ExpectFailsRule(t, graphql.KnownDirectivesRule, ` { dog @unknown(directive: "value") { name } } `, []gqlerrors.FormattedError{ - ruleError(`Unknown directive "unknown".`, 3, 13), + testutil.RuleError(`Unknown directive "unknown".`, 3, 13), }) } func TestValidate_KnownDirectives_WithManyUnknownDirectives(t *testing.T) { - expectFailsRule(t, graphql.KnownDirectivesRule, ` + testutil.ExpectFailsRule(t, graphql.KnownDirectivesRule, ` { dog @unknown(directive: "value") { name @@ -44,13 +45,13 @@ func TestValidate_KnownDirectives_WithManyUnknownDirectives(t *testing.T) { } } `, []gqlerrors.FormattedError{ - ruleError(`Unknown directive "unknown".`, 3, 13), - ruleError(`Unknown directive "unknown".`, 6, 15), - ruleError(`Unknown directive "unknown".`, 8, 16), + testutil.RuleError(`Unknown directive "unknown".`, 3, 13), + testutil.RuleError(`Unknown directive "unknown".`, 6, 15), + testutil.RuleError(`Unknown directive "unknown".`, 8, 16), }) } func TestValidate_KnownDirectives_WithWellPlacedDirectives(t *testing.T) { - expectPassesRule(t, graphql.KnownDirectivesRule, ` + testutil.ExpectPassesRule(t, graphql.KnownDirectivesRule, ` query Foo { name @include(if: true) ...Frag @include(if: true) @@ -60,12 +61,12 @@ func TestValidate_KnownDirectives_WithWellPlacedDirectives(t *testing.T) { `) } func TestValidate_KnownDirectives_WithMisplacedDirectives(t *testing.T) { - expectFailsRule(t, graphql.KnownDirectivesRule, ` + testutil.ExpectFailsRule(t, graphql.KnownDirectivesRule, ` query Foo @include(if: true) { name ...Frag } `, []gqlerrors.FormattedError{ - ruleError(`Directive "include" may not be used on "operation".`, 2, 17), + testutil.RuleError(`Directive "include" may not be used on "operation".`, 2, 17), }) } diff --git a/rules/known_fragment_names_test.go b/rules_known_fragment_names_test.go similarity index 62% rename from rules/known_fragment_names_test.go rename to rules_known_fragment_names_test.go index 55bef4d9..66abe07c 100644 --- a/rules/known_fragment_names_test.go +++ b/rules_known_fragment_names_test.go @@ -1,14 +1,15 @@ -package rules_test +package graphql_test import ( "testing" - "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_KnownFragmentNames_KnownFragmentNamesAreValid(t *testing.T) { - expectPassesRule(t, graphql.KnownFragmentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.KnownFragmentNamesRule, ` { human(id: 4) { ...HumanFields1 @@ -30,7 +31,7 @@ func TestValidate_KnownFragmentNames_KnownFragmentNamesAreValid(t *testing.T) { `) } func TestValidate_KnownFragmentNames_UnknownFragmentNamesAreInvalid(t *testing.T) { - expectFailsRule(t, graphql.KnownFragmentNamesRule, ` + testutil.ExpectFailsRule(t, graphql.KnownFragmentNamesRule, ` { human(id: 4) { ...UnknownFragment1 @@ -44,8 +45,8 @@ func TestValidate_KnownFragmentNames_UnknownFragmentNamesAreInvalid(t *testing.T ...UnknownFragment3 } `, []gqlerrors.FormattedError{ - ruleError(`Unknown fragment "UnknownFragment1".`, 4, 14), - ruleError(`Unknown fragment "UnknownFragment2".`, 6, 16), - ruleError(`Unknown fragment "UnknownFragment3".`, 12, 12), + testutil.RuleError(`Unknown fragment "UnknownFragment1".`, 4, 14), + testutil.RuleError(`Unknown fragment "UnknownFragment2".`, 6, 16), + testutil.RuleError(`Unknown fragment "UnknownFragment3".`, 12, 12), }) } diff --git a/rules/known_type_names_test.go b/rules_known_type_names_test.go similarity index 62% rename from rules/known_type_names_test.go rename to rules_known_type_names_test.go index 8b089e16..59e68468 100644 --- a/rules/known_type_names_test.go +++ b/rules_known_type_names_test.go @@ -1,14 +1,15 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_KnownTypeNames_KnownTypeNamesAreValid(t *testing.T) { - expectPassesRule(t, graphql.KnownTypeNamesRule, ` + testutil.ExpectPassesRule(t, graphql.KnownTypeNamesRule, ` query Foo($var: String, $required: [String!]!) { user(id: 4) { pets { ... on Pet { name }, ...PetFields } @@ -20,7 +21,7 @@ func TestValidate_KnownTypeNames_KnownTypeNamesAreValid(t *testing.T) { `) } func TestValidate_KnownTypeNames_UnknownTypeNamesAreInValid(t *testing.T) { - expectFailsRule(t, graphql.KnownTypeNamesRule, ` + testutil.ExpectFailsRule(t, graphql.KnownTypeNamesRule, ` query Foo($var: JumbledUpLetters) { user(id: 4) { name @@ -31,8 +32,8 @@ func TestValidate_KnownTypeNames_UnknownTypeNamesAreInValid(t *testing.T) { name } `, []gqlerrors.FormattedError{ - ruleError(`Unknown type "JumbledUpLetters".`, 2, 23), - ruleError(`Unknown type "Badger".`, 5, 25), - ruleError(`Unknown type "Peettt".`, 8, 29), + testutil.RuleError(`Unknown type "JumbledUpLetters".`, 2, 23), + testutil.RuleError(`Unknown type "Badger".`, 5, 25), + testutil.RuleError(`Unknown type "Peettt".`, 8, 29), }) } diff --git a/rules/lone_anonymous_operation_rule_test.go b/rules_lone_anonymous_operation_rule_test.go similarity index 57% rename from rules/lone_anonymous_operation_rule_test.go rename to rules_lone_anonymous_operation_rule_test.go index b5233e95..8351a49c 100644 --- a/rules/lone_anonymous_operation_rule_test.go +++ b/rules_lone_anonymous_operation_rule_test.go @@ -1,28 +1,29 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_AnonymousOperationMustBeAlone_NoOperations(t *testing.T) { - expectPassesRule(t, graphql.LoneAnonymousOperationRule, ` + testutil.ExpectPassesRule(t, graphql.LoneAnonymousOperationRule, ` fragment fragA on Type { field } `) } func TestValidate_AnonymousOperationMustBeAlone_OneAnonOperation(t *testing.T) { - expectPassesRule(t, graphql.LoneAnonymousOperationRule, ` + testutil.ExpectPassesRule(t, graphql.LoneAnonymousOperationRule, ` { field } `) } func TestValidate_AnonymousOperationMustBeAlone_MultipleNamedOperations(t *testing.T) { - expectPassesRule(t, graphql.LoneAnonymousOperationRule, ` + testutil.ExpectPassesRule(t, graphql.LoneAnonymousOperationRule, ` query Foo { field } @@ -33,7 +34,7 @@ func TestValidate_AnonymousOperationMustBeAlone_MultipleNamedOperations(t *testi `) } func TestValidate_AnonymousOperationMustBeAlone_AnonOperationWithFragment(t *testing.T) { - expectPassesRule(t, graphql.LoneAnonymousOperationRule, ` + testutil.ExpectPassesRule(t, graphql.LoneAnonymousOperationRule, ` { ...Foo } @@ -44,7 +45,7 @@ func TestValidate_AnonymousOperationMustBeAlone_AnonOperationWithFragment(t *tes } func TestValidate_AnonymousOperationMustBeAlone_MultipleAnonOperations(t *testing.T) { - expectFailsRule(t, graphql.LoneAnonymousOperationRule, ` + testutil.ExpectFailsRule(t, graphql.LoneAnonymousOperationRule, ` { fieldA } @@ -52,12 +53,12 @@ func TestValidate_AnonymousOperationMustBeAlone_MultipleAnonOperations(t *testin fieldB } `, []gqlerrors.FormattedError{ - ruleError(`This anonymous operation must be the only defined operation.`, 2, 7), - ruleError(`This anonymous operation must be the only defined operation.`, 5, 7), + testutil.RuleError(`This anonymous operation must be the only defined operation.`, 2, 7), + testutil.RuleError(`This anonymous operation must be the only defined operation.`, 5, 7), }) } func TestValidate_AnonymousOperationMustBeAlone_AnonOperationWithAnotherOperation(t *testing.T) { - expectFailsRule(t, graphql.LoneAnonymousOperationRule, ` + testutil.ExpectFailsRule(t, graphql.LoneAnonymousOperationRule, ` { fieldA } @@ -65,6 +66,6 @@ func TestValidate_AnonymousOperationMustBeAlone_AnonOperationWithAnotherOperatio fieldB } `, []gqlerrors.FormattedError{ - ruleError(`This anonymous operation must be the only defined operation.`, 2, 7), + testutil.RuleError(`This anonymous operation must be the only defined operation.`, 2, 7), }) } diff --git a/rules/no_fragment_cycles_test.go b/rules_no_fragment_cycles_test.go similarity index 63% rename from rules/no_fragment_cycles_test.go rename to rules_no_fragment_cycles_test.go index 3fe76c67..526bb7c5 100644 --- a/rules/no_fragment_cycles_test.go +++ b/rules_no_fragment_cycles_test.go @@ -1,33 +1,34 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_NoCircularFragmentSpreads_SingleReferenceIsValid(t *testing.T) { - expectPassesRule(t, graphql.NoFragmentCyclesRule, ` + testutil.ExpectPassesRule(t, graphql.NoFragmentCyclesRule, ` fragment fragA on Dog { ...fragB } fragment fragB on Dog { name } `) } func TestValidate_NoCircularFragmentSpreads_SpreadingTwiceIsNotCircular(t *testing.T) { - expectPassesRule(t, graphql.NoFragmentCyclesRule, ` + testutil.ExpectPassesRule(t, graphql.NoFragmentCyclesRule, ` fragment fragA on Dog { ...fragB, ...fragB } fragment fragB on Dog { name } `) } func TestValidate_NoCircularFragmentSpreads_SpreadingTwiceIndirectlyIsNotCircular(t *testing.T) { - expectPassesRule(t, graphql.NoFragmentCyclesRule, ` + testutil.ExpectPassesRule(t, graphql.NoFragmentCyclesRule, ` fragment fragA on Dog { ...fragB, ...fragC } fragment fragB on Dog { ...fragC } fragment fragC on Dog { name } `) } func TestValidate_NoCircularFragmentSpreads_DoubleSpreadWithinAbstractTypes(t *testing.T) { - expectPassesRule(t, graphql.NoFragmentCyclesRule, ` + testutil.ExpectPassesRule(t, graphql.NoFragmentCyclesRule, ` fragment nameFragment on Pet { ... on Dog { name } ... on Cat { name } @@ -40,40 +41,40 @@ func TestValidate_NoCircularFragmentSpreads_DoubleSpreadWithinAbstractTypes(t *t `) } func TestValidate_NoCircularFragmentSpreads_SpreadingRecursivelyWithinFieldFails(t *testing.T) { - expectFailsRule(t, graphql.NoFragmentCyclesRule, ` + testutil.ExpectFailsRule(t, graphql.NoFragmentCyclesRule, ` fragment fragA on Human { relatives { ...fragA } }, `, []gqlerrors.FormattedError{ - ruleError(`Cannot spread fragment "fragA" within itself.`, 2, 45), + testutil.RuleError(`Cannot spread fragment "fragA" within itself.`, 2, 45), }) } func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectly(t *testing.T) { - expectFailsRule(t, graphql.NoFragmentCyclesRule, ` + testutil.ExpectFailsRule(t, graphql.NoFragmentCyclesRule, ` fragment fragA on Dog { ...fragA } `, []gqlerrors.FormattedError{ - ruleError(`Cannot spread fragment "fragA" within itself.`, 2, 31), + testutil.RuleError(`Cannot spread fragment "fragA" within itself.`, 2, 31), }) } func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectlyWithinInlineFragment(t *testing.T) { - expectFailsRule(t, graphql.NoFragmentCyclesRule, ` + testutil.ExpectFailsRule(t, graphql.NoFragmentCyclesRule, ` fragment fragA on Pet { ... on Dog { ...fragA } } `, []gqlerrors.FormattedError{ - ruleError(`Cannot spread fragment "fragA" within itself.`, 4, 11), + testutil.RuleError(`Cannot spread fragment "fragA" within itself.`, 4, 11), }) } func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectlyMultiple(t *testing.T) { - expectFailsRule(t, graphql.NoFragmentCyclesRule, ` + testutil.ExpectFailsRule(t, graphql.NoFragmentCyclesRule, ` fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragA } `, []gqlerrors.FormattedError{ - ruleError(`Cannot spread fragment "fragA" within itself via fragB.`, 2, 31, 3, 31), + testutil.RuleError(`Cannot spread fragment "fragA" within itself via fragB.`, 2, 31, 3, 31), }) } func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectlyWithinInlineFragmentMultiple(t *testing.T) { - expectFailsRule(t, graphql.NoFragmentCyclesRule, ` + testutil.ExpectFailsRule(t, graphql.NoFragmentCyclesRule, ` fragment fragA on Pet { ... on Dog { ...fragB @@ -85,11 +86,11 @@ func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectlyWithinInlin } } `, []gqlerrors.FormattedError{ - ruleError(`Cannot spread fragment "fragA" within itself via fragB.`, 4, 11, 9, 11), + testutil.RuleError(`Cannot spread fragment "fragA" within itself via fragB.`, 4, 11, 9, 11), }) } func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDeeply(t *testing.T) { - expectFailsRule(t, graphql.NoFragmentCyclesRule, ` + testutil.ExpectFailsRule(t, graphql.NoFragmentCyclesRule, ` fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragC } fragment fragC on Dog { ...fragO } @@ -98,17 +99,17 @@ func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDeeply(t *testing.T fragment fragZ on Dog { ...fragO } fragment fragO on Dog { ...fragA, ...fragX } `, []gqlerrors.FormattedError{ - ruleError(`Cannot spread fragment "fragA" within itself via fragB, fragC, fragO.`, 2, 31, 3, 31, 4, 31, 8, 31), - ruleError(`Cannot spread fragment "fragX" within itself via fragY, fragZ, fragO.`, 5, 31, 6, 31, 7, 31, 8, 41), + testutil.RuleError(`Cannot spread fragment "fragA" within itself via fragB, fragC, fragO.`, 2, 31, 3, 31, 4, 31, 8, 31), + testutil.RuleError(`Cannot spread fragment "fragX" within itself via fragY, fragZ, fragO.`, 5, 31, 6, 31, 7, 31, 8, 41), }) } func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDeeplyTwoPaths(t *testing.T) { - expectFailsRule(t, graphql.NoFragmentCyclesRule, ` + testutil.ExpectFailsRule(t, graphql.NoFragmentCyclesRule, ` fragment fragA on Dog { ...fragB, ...fragC } fragment fragB on Dog { ...fragA } fragment fragC on Dog { ...fragA } `, []gqlerrors.FormattedError{ - ruleError(`Cannot spread fragment "fragA" within itself via fragB.`, 2, 31, 3, 31), - ruleError(`Cannot spread fragment "fragA" within itself via fragC.`, 2, 41, 4, 31), + testutil.RuleError(`Cannot spread fragment "fragA" within itself via fragB.`, 2, 31, 3, 31), + testutil.RuleError(`Cannot spread fragment "fragA" within itself via fragC.`, 2, 41, 4, 31), }) } diff --git a/rules/no_undefined_variables_test.go b/rules_no_undefined_variables_test.go similarity index 65% rename from rules/no_undefined_variables_test.go rename to rules_no_undefined_variables_test.go index 6b1cd563..b2039a28 100644 --- a/rules/no_undefined_variables_test.go +++ b/rules_no_undefined_variables_test.go @@ -1,21 +1,22 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_NoUndefinedVariables_AllVariablesDefined(t *testing.T) { - expectPassesRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectPassesRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c) } `) } func TestValidate_NoUndefinedVariables_AllVariablesDeeplyDefined(t *testing.T) { - expectPassesRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectPassesRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($a: String, $b: String, $c: String) { field(a: $a) { field(b: $b) { @@ -26,7 +27,7 @@ func TestValidate_NoUndefinedVariables_AllVariablesDeeplyDefined(t *testing.T) { `) } func TestValidate_NoUndefinedVariables_AllVariablesDeeplyDefinedInInlineFragmentsDefined(t *testing.T) { - expectPassesRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectPassesRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($a: String, $b: String, $c: String) { ... on Type { field(a: $a) { @@ -41,7 +42,7 @@ func TestValidate_NoUndefinedVariables_AllVariablesDeeplyDefinedInInlineFragment `) } func TestValidate_NoUndefinedVariables_AllVariablesInFragmentsDeeplyDefined(t *testing.T) { - expectPassesRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectPassesRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($a: String, $b: String, $c: String) { ...FragA } @@ -61,7 +62,7 @@ func TestValidate_NoUndefinedVariables_AllVariablesInFragmentsDeeplyDefined(t *t `) } func TestValidate_NoUndefinedVariables_VariablesWithinSingleFragmentDefinedInMultipleOperations(t *testing.T) { - expectPassesRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectPassesRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($a: String) { ...FragA } @@ -74,7 +75,7 @@ func TestValidate_NoUndefinedVariables_VariablesWithinSingleFragmentDefinedInMul `) } func TestValidate_NoUndefinedVariables_VariableWithinFragmentsDefinedInOperations(t *testing.T) { - expectPassesRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectPassesRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($a: String) { ...FragA } @@ -90,7 +91,7 @@ func TestValidate_NoUndefinedVariables_VariableWithinFragmentsDefinedInOperation `) } func TestValidate_NoUndefinedVariables_VariableWithinRecursiveFragmentDefined(t *testing.T) { - expectPassesRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectPassesRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($a: String) { ...FragA } @@ -102,36 +103,36 @@ func TestValidate_NoUndefinedVariables_VariableWithinRecursiveFragmentDefined(t `) } func TestValidate_NoUndefinedVariables_VariableNotDefined(t *testing.T) { - expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c, d: $d) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$d" is not defined.`, 3, 39), + testutil.RuleError(`Variable "$d" is not defined.`, 3, 39), }) } func TestValidate_NoUndefinedVariables_VariableNotDefinedByUnnamedQuery(t *testing.T) { - expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` { field(a: $a) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$a" is not defined.`, 3, 18), + testutil.RuleError(`Variable "$a" is not defined.`, 3, 18), }) } func TestValidate_NoUndefinedVariables_MultipleVariablesNotDefined(t *testing.T) { - expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($b: String) { field(a: $a, b: $b, c: $c) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$a" is not defined.`, 3, 18), - ruleError(`Variable "$c" is not defined.`, 3, 32), + testutil.RuleError(`Variable "$a" is not defined.`, 3, 18), + testutil.RuleError(`Variable "$c" is not defined.`, 3, 32), }) } func TestValidate_NoUndefinedVariables_VariableInFragmentNotDefinedByUnnamedQuery(t *testing.T) { - expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` { ...FragA } @@ -139,12 +140,12 @@ func TestValidate_NoUndefinedVariables_VariableInFragmentNotDefinedByUnnamedQuer field(a: $a) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$a" is not defined.`, 6, 18), + testutil.RuleError(`Variable "$a" is not defined.`, 6, 18), }) } func TestValidate_NoUndefinedVariables_VariableInFragmentNotDefinedByOperation(t *testing.T) { - expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($a: String, $b: String) { ...FragA } @@ -162,12 +163,12 @@ func TestValidate_NoUndefinedVariables_VariableInFragmentNotDefinedByOperation(t field(c: $c) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$c" is not defined by operation "Foo".`, 16, 18, 2, 7), + testutil.RuleError(`Variable "$c" is not defined by operation "Foo".`, 16, 18, 2, 7), }) } func TestValidate_NoUndefinedVariables_MultipleVariablesInFragmentsNotDefined(t *testing.T) { - expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($b: String) { ...FragA } @@ -185,13 +186,13 @@ func TestValidate_NoUndefinedVariables_MultipleVariablesInFragmentsNotDefined(t field(c: $c) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$a" is not defined by operation "Foo".`, 6, 18, 2, 7), - ruleError(`Variable "$c" is not defined by operation "Foo".`, 16, 18, 2, 7), + testutil.RuleError(`Variable "$a" is not defined by operation "Foo".`, 6, 18, 2, 7), + testutil.RuleError(`Variable "$c" is not defined by operation "Foo".`, 16, 18, 2, 7), }) } func TestValidate_NoUndefinedVariables_SingleVariableInFragmentNotDefinedByMultipleOperations(t *testing.T) { - expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($a: String) { ...FragAB } @@ -202,13 +203,13 @@ func TestValidate_NoUndefinedVariables_SingleVariableInFragmentNotDefinedByMulti field(a: $a, b: $b) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$b" is not defined by operation "Foo".`, 9, 25, 2, 7), - ruleError(`Variable "$b" is not defined by operation "Bar".`, 9, 25, 5, 7), + testutil.RuleError(`Variable "$b" is not defined by operation "Foo".`, 9, 25, 2, 7), + testutil.RuleError(`Variable "$b" is not defined by operation "Bar".`, 9, 25, 5, 7), }) } func TestValidate_NoUndefinedVariables_VariablesInFragmentNotDefinedByMultipleOperations(t *testing.T) { - expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($b: String) { ...FragAB } @@ -219,12 +220,12 @@ func TestValidate_NoUndefinedVariables_VariablesInFragmentNotDefinedByMultipleOp field(a: $a, b: $b) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$a" is not defined by operation "Foo".`, 9, 18, 2, 7), - ruleError(`Variable "$b" is not defined by operation "Bar".`, 9, 25, 5, 7), + testutil.RuleError(`Variable "$a" is not defined by operation "Foo".`, 9, 18, 2, 7), + testutil.RuleError(`Variable "$b" is not defined by operation "Bar".`, 9, 25, 5, 7), }) } func TestValidate_NoUndefinedVariables_VariableInFragmentUsedByOtherOperation(t *testing.T) { - expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($b: String) { ...FragA } @@ -238,13 +239,13 @@ func TestValidate_NoUndefinedVariables_VariableInFragmentUsedByOtherOperation(t field(b: $b) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$a" is not defined by operation "Foo".`, 9, 18, 2, 7), - ruleError(`Variable "$b" is not defined by operation "Bar".`, 12, 18, 5, 7), + testutil.RuleError(`Variable "$a" is not defined by operation "Foo".`, 9, 18, 2, 7), + testutil.RuleError(`Variable "$b" is not defined by operation "Bar".`, 12, 18, 5, 7), }) } func TestValidate_NoUndefinedVariables_VaMultipleUndefinedVariablesProduceMultipleErrors(t *testing.T) { - expectFailsRule(t, graphql.NoUndefinedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($b: String) { ...FragAB } @@ -260,11 +261,11 @@ func TestValidate_NoUndefinedVariables_VaMultipleUndefinedVariablesProduceMultip field2(c: $c) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$a" is not defined by operation "Foo".`, 9, 19, 2, 7), - ruleError(`Variable "$c" is not defined by operation "Foo".`, 14, 19, 2, 7), - ruleError(`Variable "$a" is not defined by operation "Foo".`, 11, 19, 2, 7), - ruleError(`Variable "$b" is not defined by operation "Bar".`, 9, 26, 5, 7), - ruleError(`Variable "$c" is not defined by operation "Bar".`, 14, 19, 5, 7), - ruleError(`Variable "$b" is not defined by operation "Bar".`, 11, 26, 5, 7), + testutil.RuleError(`Variable "$a" is not defined by operation "Foo".`, 9, 19, 2, 7), + testutil.RuleError(`Variable "$c" is not defined by operation "Foo".`, 14, 19, 2, 7), + testutil.RuleError(`Variable "$a" is not defined by operation "Foo".`, 11, 19, 2, 7), + testutil.RuleError(`Variable "$b" is not defined by operation "Bar".`, 9, 26, 5, 7), + testutil.RuleError(`Variable "$c" is not defined by operation "Bar".`, 14, 19, 5, 7), + testutil.RuleError(`Variable "$b" is not defined by operation "Bar".`, 11, 26, 5, 7), }) } diff --git a/rules/no_unused_fragments_test.go b/rules_no_unused_fragments_test.go similarity index 76% rename from rules/no_unused_fragments_test.go rename to rules_no_unused_fragments_test.go index 38369e31..a1788a10 100644 --- a/rules/no_unused_fragments_test.go +++ b/rules_no_unused_fragments_test.go @@ -1,14 +1,15 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_NoUnusedFragments_AllFragmentNamesAreUsed(t *testing.T) { - expectPassesRule(t, graphql.NoUnusedFragmentsRule, ` + testutil.ExpectPassesRule(t, graphql.NoUnusedFragmentsRule, ` { human(id: 4) { ...HumanFields1 @@ -30,7 +31,7 @@ func TestValidate_NoUnusedFragments_AllFragmentNamesAreUsed(t *testing.T) { `) } func TestValidate_NoUnusedFragments_AllFragmentNamesAreUsedByMultipleOperations(t *testing.T) { - expectPassesRule(t, graphql.NoUnusedFragmentsRule, ` + testutil.ExpectPassesRule(t, graphql.NoUnusedFragmentsRule, ` query Foo { human(id: 4) { ...HumanFields1 @@ -54,7 +55,7 @@ func TestValidate_NoUnusedFragments_AllFragmentNamesAreUsedByMultipleOperations( `) } func TestValidate_NoUnusedFragments_ContainsUnknownFragments(t *testing.T) { - expectFailsRule(t, graphql.NoUnusedFragmentsRule, ` + testutil.ExpectFailsRule(t, graphql.NoUnusedFragmentsRule, ` query Foo { human(id: 4) { ...HumanFields1 @@ -82,13 +83,13 @@ func TestValidate_NoUnusedFragments_ContainsUnknownFragments(t *testing.T) { name } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "Unused1" is never used.`, 22, 7), - ruleError(`Fragment "Unused2" is never used.`, 25, 7), + testutil.RuleError(`Fragment "Unused1" is never used.`, 22, 7), + testutil.RuleError(`Fragment "Unused2" is never used.`, 25, 7), }) } func TestValidate_NoUnusedFragments_ContainsUnknownFragmentsWithRefCycle(t *testing.T) { - expectFailsRule(t, graphql.NoUnusedFragmentsRule, ` + testutil.ExpectFailsRule(t, graphql.NoUnusedFragmentsRule, ` query Foo { human(id: 4) { ...HumanFields1 @@ -118,13 +119,13 @@ func TestValidate_NoUnusedFragments_ContainsUnknownFragmentsWithRefCycle(t *test ...Unused1 } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "Unused1" is never used.`, 22, 7), - ruleError(`Fragment "Unused2" is never used.`, 26, 7), + testutil.RuleError(`Fragment "Unused1" is never used.`, 22, 7), + testutil.RuleError(`Fragment "Unused2" is never used.`, 26, 7), }) } func TestValidate_NoUnusedFragments_ContainsUnknownAndUndefFragments(t *testing.T) { - expectFailsRule(t, graphql.NoUnusedFragmentsRule, ` + testutil.ExpectFailsRule(t, graphql.NoUnusedFragmentsRule, ` query Foo { human(id: 4) { ...bar @@ -134,6 +135,6 @@ func TestValidate_NoUnusedFragments_ContainsUnknownAndUndefFragments(t *testing. name } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "foo" is never used.`, 7, 7), + testutil.RuleError(`Fragment "foo" is never used.`, 7, 7), }) } diff --git a/rules/no_unused_variables_test.go b/rules_no_unused_variables_test.go similarity index 72% rename from rules/no_unused_variables_test.go rename to rules_no_unused_variables_test.go index d15d06ea..747ae62f 100644 --- a/rules/no_unused_variables_test.go +++ b/rules_no_unused_variables_test.go @@ -1,21 +1,22 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_NoUnusedVariables_UsesAllVariables(t *testing.T) { - expectPassesRule(t, graphql.NoUnusedVariablesRule, ` + testutil.ExpectPassesRule(t, graphql.NoUnusedVariablesRule, ` query Foo($a: String, $b: String, $c: String) { field(a: $a, b: $b, c: $c) } `) } func TestValidate_NoUnusedVariables_UsesAllVariablesDeeply(t *testing.T) { - expectPassesRule(t, graphql.NoUnusedVariablesRule, ` + testutil.ExpectPassesRule(t, graphql.NoUnusedVariablesRule, ` query Foo($a: String, $b: String, $c: String) { field(a: $a) { field(b: $b) { @@ -26,7 +27,7 @@ func TestValidate_NoUnusedVariables_UsesAllVariablesDeeply(t *testing.T) { `) } func TestValidate_NoUnusedVariables_UsesAllVariablesDeeplyInInlineFragments(t *testing.T) { - expectPassesRule(t, graphql.NoUnusedVariablesRule, ` + testutil.ExpectPassesRule(t, graphql.NoUnusedVariablesRule, ` query Foo($a: String, $b: String, $c: String) { ... on Type { field(a: $a) { @@ -41,7 +42,7 @@ func TestValidate_NoUnusedVariables_UsesAllVariablesDeeplyInInlineFragments(t *t `) } func TestValidate_NoUnusedVariables_UsesAllVariablesInFragments(t *testing.T) { - expectPassesRule(t, graphql.NoUnusedVariablesRule, ` + testutil.ExpectPassesRule(t, graphql.NoUnusedVariablesRule, ` query Foo($a: String, $b: String, $c: String) { ...FragA } @@ -61,7 +62,7 @@ func TestValidate_NoUnusedVariables_UsesAllVariablesInFragments(t *testing.T) { `) } func TestValidate_NoUnusedVariables_VariableUsedByFragmentInMultipleOperations(t *testing.T) { - expectPassesRule(t, graphql.NoUnusedVariablesRule, ` + testutil.ExpectPassesRule(t, graphql.NoUnusedVariablesRule, ` query Foo($a: String) { ...FragA } @@ -77,7 +78,7 @@ func TestValidate_NoUnusedVariables_VariableUsedByFragmentInMultipleOperations(t `) } func TestValidate_NoUnusedVariables_VariableUsedByRecursiveFragment(t *testing.T) { - expectPassesRule(t, graphql.NoUnusedVariablesRule, ` + testutil.ExpectPassesRule(t, graphql.NoUnusedVariablesRule, ` query Foo($a: String) { ...FragA } @@ -89,26 +90,26 @@ func TestValidate_NoUnusedVariables_VariableUsedByRecursiveFragment(t *testing.T `) } func TestValidate_NoUnusedVariables_VariableNotUsed(t *testing.T) { - expectFailsRule(t, graphql.NoUnusedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUnusedVariablesRule, ` query Foo($a: String, $b: String, $c: String) { field(a: $a, b: $b) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$c" is never used.`, 2, 41), + testutil.RuleError(`Variable "$c" is never used.`, 2, 41), }) } func TestValidate_NoUnusedVariables_MultipleVariablesNotUsed(t *testing.T) { - expectFailsRule(t, graphql.NoUnusedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUnusedVariablesRule, ` query Foo($a: String, $b: String, $c: String) { field(b: $b) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$a" is never used.`, 2, 17), - ruleError(`Variable "$c" is never used.`, 2, 41), + testutil.RuleError(`Variable "$a" is never used.`, 2, 17), + testutil.RuleError(`Variable "$c" is never used.`, 2, 41), }) } func TestValidate_NoUnusedVariables_VariableNotUsedInFragments(t *testing.T) { - expectFailsRule(t, graphql.NoUnusedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUnusedVariablesRule, ` query Foo($a: String, $b: String, $c: String) { ...FragA } @@ -126,11 +127,11 @@ func TestValidate_NoUnusedVariables_VariableNotUsedInFragments(t *testing.T) { field } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$c" is never used.`, 2, 41), + testutil.RuleError(`Variable "$c" is never used.`, 2, 41), }) } func TestValidate_NoUnusedVariables_MultipleVariablesNotUsed2(t *testing.T) { - expectFailsRule(t, graphql.NoUnusedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUnusedVariablesRule, ` query Foo($a: String, $b: String, $c: String) { ...FragA } @@ -148,12 +149,12 @@ func TestValidate_NoUnusedVariables_MultipleVariablesNotUsed2(t *testing.T) { field } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$a" is never used.`, 2, 17), - ruleError(`Variable "$c" is never used.`, 2, 41), + testutil.RuleError(`Variable "$a" is never used.`, 2, 17), + testutil.RuleError(`Variable "$c" is never used.`, 2, 41), }) } func TestValidate_NoUnusedVariables_VariableNotUsedByUnreferencedFragment(t *testing.T) { - expectFailsRule(t, graphql.NoUnusedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUnusedVariablesRule, ` query Foo($b: String) { ...FragA } @@ -164,11 +165,11 @@ func TestValidate_NoUnusedVariables_VariableNotUsedByUnreferencedFragment(t *tes field(b: $b) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$b" is never used.`, 2, 17), + testutil.RuleError(`Variable "$b" is never used.`, 2, 17), }) } func TestValidate_NoUnusedVariables_VariableNotUsedByFragmentUsedByOtherOperation(t *testing.T) { - expectFailsRule(t, graphql.NoUnusedVariablesRule, ` + testutil.ExpectFailsRule(t, graphql.NoUnusedVariablesRule, ` query Foo($b: String) { ...FragA } @@ -182,7 +183,7 @@ func TestValidate_NoUnusedVariables_VariableNotUsedByFragmentUsedByOtherOperatio field(b: $b) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$b" is never used.`, 2, 17), - ruleError(`Variable "$a" is never used.`, 5, 17), + testutil.RuleError(`Variable "$b" is never used.`, 2, 17), + testutil.RuleError(`Variable "$a" is never used.`, 5, 17), }) } diff --git a/rules/overlapping_fields_can_be_merged_test.go b/rules_overlapping_fields_can_be_merged_test.go similarity index 74% rename from rules/overlapping_fields_can_be_merged_test.go rename to rules_overlapping_fields_can_be_merged_test.go index 2b37fe97..32693403 100644 --- a/rules/overlapping_fields_can_be_merged_test.go +++ b/rules_overlapping_fields_can_be_merged_test.go @@ -1,14 +1,15 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_OverlappingFieldsCanBeMerged_UniqueFields(t *testing.T) { - expectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` fragment uniqueFields on Dog { name nickname @@ -16,7 +17,7 @@ func TestValidate_OverlappingFieldsCanBeMerged_UniqueFields(t *testing.T) { `) } func TestValidate_OverlappingFieldsCanBeMerged_IdenticalFields(t *testing.T) { - expectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` fragment mergeIdenticalFields on Dog { name name @@ -24,7 +25,7 @@ func TestValidate_OverlappingFieldsCanBeMerged_IdenticalFields(t *testing.T) { `) } func TestValidate_OverlappingFieldsCanBeMerged_IdenticalFieldsWithIdenticalArgs(t *testing.T) { - expectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` fragment mergeIdenticalFieldsWithIdenticalArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand(dogCommand: SIT) @@ -32,7 +33,7 @@ func TestValidate_OverlappingFieldsCanBeMerged_IdenticalFieldsWithIdenticalArgs( `) } func TestValidate_OverlappingFieldsCanBeMerged_IdenticalFieldsWithIdenticalDirectives(t *testing.T) { - expectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` fragment mergeSameFieldsWithSameDirectives on Dog { name @include(if: true) name @include(if: true) @@ -40,7 +41,7 @@ func TestValidate_OverlappingFieldsCanBeMerged_IdenticalFieldsWithIdenticalDirec `) } func TestValidate_OverlappingFieldsCanBeMerged_DifferentArgsWithDifferentAliases(t *testing.T) { - expectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` fragment differentArgsWithDifferentAliases on Dog { knowsSit: doesKnowCommand(dogCommand: SIT) knowsDown: doesKnowCommand(dogCommand: DOWN) @@ -48,7 +49,7 @@ func TestValidate_OverlappingFieldsCanBeMerged_DifferentArgsWithDifferentAliases `) } func TestValidate_OverlappingFieldsCanBeMerged_DifferentDirectivesWithDifferentAliases(t *testing.T) { - expectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectPassesRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` fragment differentDirectivesWithDifferentAliases on Dog { nameIfTrue: name @include(if: true) nameIfFalse: name @include(if: false) @@ -56,77 +57,77 @@ func TestValidate_OverlappingFieldsCanBeMerged_DifferentDirectivesWithDifferentA `) } func TestValidate_OverlappingFieldsCanBeMerged_SameAliasesWithDifferentFieldTargets(t *testing.T) { - expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` fragment sameAliasesWithDifferentFieldTargets on Dog { fido: name fido: nickname } `, []gqlerrors.FormattedError{ - ruleError(`Fields "fido" conflict because name and nickname are different fields.`, 3, 9, 4, 9), + testutil.RuleError(`Fields "fido" conflict because name and nickname are different fields.`, 3, 9, 4, 9), }) } func TestValidate_OverlappingFieldsCanBeMerged_AliasMakingDirectFieldAccess(t *testing.T) { - expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` fragment aliasMaskingDirectFieldAccess on Dog { name: nickname name } `, []gqlerrors.FormattedError{ - ruleError(`Fields "name" conflict because nickname and name are different fields.`, 3, 9, 4, 9), + testutil.RuleError(`Fields "name" conflict because nickname and name are different fields.`, 3, 9, 4, 9), }) } func TestValidate_OverlappingFieldsCanBeMerged_ConflictingArgs(t *testing.T) { - expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` fragment conflictingArgs on Dog { doesKnowCommand(dogCommand: SIT) doesKnowCommand(dogCommand: HEEL) } `, []gqlerrors.FormattedError{ - ruleError(`Fields "doesKnowCommand" conflict because they have differing arguments.`, 3, 9, 4, 9), + testutil.RuleError(`Fields "doesKnowCommand" conflict because they have differing arguments.`, 3, 9, 4, 9), }) } func TestValidate_OverlappingFieldsCanBeMerged_ConflictingDirectives(t *testing.T) { - expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` fragment conflictingDirectiveArgs on Dog { name @include(if: true) name @skip(if: false) } `, []gqlerrors.FormattedError{ - ruleError(`Fields "name" conflict because they have differing directives.`, 3, 9, 4, 9), + testutil.RuleError(`Fields "name" conflict because they have differing directives.`, 3, 9, 4, 9), }) } func TestValidate_OverlappingFieldsCanBeMerged_ConflictingDirectiveArgs(t *testing.T) { - expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` fragment conflictingDirectiveArgs on Dog { name @include(if: true) name @include(if: false) } `, []gqlerrors.FormattedError{ - ruleError(`Fields "name" conflict because they have differing directives.`, 3, 9, 4, 9), + testutil.RuleError(`Fields "name" conflict because they have differing directives.`, 3, 9, 4, 9), }) } func TestValidate_OverlappingFieldsCanBeMerged_ConflictingArgsWithMatchingDirectives(t *testing.T) { - expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` fragment conflictingArgsWithMatchingDirectiveArgs on Dog { doesKnowCommand(dogCommand: SIT) @include(if: true) doesKnowCommand(dogCommand: HEEL) @include(if: true) } `, []gqlerrors.FormattedError{ - ruleError(`Fields "doesKnowCommand" conflict because they have differing arguments.`, 3, 9, 4, 9), + testutil.RuleError(`Fields "doesKnowCommand" conflict because they have differing arguments.`, 3, 9, 4, 9), }) } func TestValidate_OverlappingFieldsCanBeMerged_ConflictingDirectivesWithMatchingArgs(t *testing.T) { - expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` fragment conflictingDirectiveArgsWithMatchingArgs on Dog { doesKnowCommand(dogCommand: SIT) @include(if: true) doesKnowCommand(dogCommand: SIT) @skip(if: false) } `, []gqlerrors.FormattedError{ - ruleError(`Fields "doesKnowCommand" conflict because they have differing directives.`, 3, 9, 4, 9), + testutil.RuleError(`Fields "doesKnowCommand" conflict because they have differing directives.`, 3, 9, 4, 9), }) } func TestValidate_OverlappingFieldsCanBeMerged_EncountersConflictInFragments(t *testing.T) { - expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` { ...A ...B @@ -138,11 +139,11 @@ func TestValidate_OverlappingFieldsCanBeMerged_EncountersConflictInFragments(t * x: b } `, []gqlerrors.FormattedError{ - ruleError(`Fields "x" conflict because a and b are different fields.`, 7, 9, 10, 9), + testutil.RuleError(`Fields "x" conflict because a and b are different fields.`, 7, 9, 10, 9), }) } func TestValidate_OverlappingFieldsCanBeMerged_ReportsEachConflictOnce(t *testing.T) { - expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` { f1 { ...A @@ -165,13 +166,13 @@ func TestValidate_OverlappingFieldsCanBeMerged_ReportsEachConflictOnce(t *testin x: b } `, []gqlerrors.FormattedError{ - ruleError(`Fields "x" conflict because a and b are different fields.`, 18, 9, 21, 9), - ruleError(`Fields "x" conflict because a and c are different fields.`, 18, 9, 14, 11), - ruleError(`Fields "x" conflict because b and c are different fields.`, 21, 9, 14, 11), + testutil.RuleError(`Fields "x" conflict because a and b are different fields.`, 18, 9, 21, 9), + testutil.RuleError(`Fields "x" conflict because a and c are different fields.`, 18, 9, 14, 11), + testutil.RuleError(`Fields "x" conflict because b and c are different fields.`, 21, 9, 14, 11), }) } func TestValidate_OverlappingFieldsCanBeMerged_DeepConflict(t *testing.T) { - expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` { field { x: a @@ -181,12 +182,12 @@ func TestValidate_OverlappingFieldsCanBeMerged_DeepConflict(t *testing.T) { } } `, []gqlerrors.FormattedError{ - ruleError(`Fields "field" conflict because subfields "x" conflict because a and b are different fields.`, + testutil.RuleError(`Fields "field" conflict because subfields "x" conflict because a and b are different fields.`, 3, 9, 6, 9, 4, 11, 7, 11), }) } func TestValidate_OverlappingFieldsCanBeMerged_DeepConflictWithMultipleIssues(t *testing.T) { - expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` { field { x: a @@ -198,14 +199,14 @@ func TestValidate_OverlappingFieldsCanBeMerged_DeepConflictWithMultipleIssues(t } } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Fields "field" conflict because subfields "x" conflict because a and b are different fields and `+ `subfields "y" conflict because c and d are different fields.`, 3, 9, 7, 9, 4, 11, 8, 11, 5, 11, 9, 11), }) } func TestValidate_OverlappingFieldsCanBeMerged_VeryDeepConflict(t *testing.T) { - expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` { field { deepField { @@ -219,14 +220,14 @@ func TestValidate_OverlappingFieldsCanBeMerged_VeryDeepConflict(t *testing.T) { } } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Fields "field" conflict because subfields "deepField" conflict because subfields "x" conflict because `+ `a and b are different fields.`, 3, 9, 8, 9, 4, 11, 9, 11, 5, 13, 10, 13), }) } func TestValidate_OverlappingFieldsCanBeMerged_ReportsDeepConflictToNearestCommonAncestor(t *testing.T) { - expectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRule(t, graphql.OverlappingFieldsCanBeMergedRule, ` { field { deepField { @@ -243,7 +244,7 @@ func TestValidate_OverlappingFieldsCanBeMerged_ReportsDeepConflictToNearestCommo } } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Fields "deepField" conflict because subfields "x" conflict because `+ `a and b are different fields.`, 4, 11, 7, 11, 5, 13, 8, 13), @@ -335,7 +336,7 @@ var schema, _ = graphql.NewSchema(graphql.SchemaConfig{ }) func TestValidate_OverlappingFieldsCanBeMerged_ReturnTypesMustBeUnambiguous_ConflictingScalarReturnTypes(t *testing.T) { - expectFailsRuleWithSchema(t, &schema, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRuleWithSchema(t, &schema, graphql.OverlappingFieldsCanBeMergedRule, ` { boxUnion { ...on IntBox { @@ -347,13 +348,13 @@ func TestValidate_OverlappingFieldsCanBeMerged_ReturnTypesMustBeUnambiguous_Conf } } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Fields "scalar" conflict because they return differing types Int and String.`, 5, 15, 8, 15), }) } func TestValidate_OverlappingFieldsCanBeMerged_ReturnTypesMustBeUnambiguous_SameWrappedScalarReturnTypes(t *testing.T) { - expectPassesRuleWithSchema(t, &schema, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectPassesRuleWithSchema(t, &schema, graphql.OverlappingFieldsCanBeMergedRule, ` { boxUnion { ...on NonNullStringBox1 { @@ -367,7 +368,7 @@ func TestValidate_OverlappingFieldsCanBeMerged_ReturnTypesMustBeUnambiguous_Same `) } func TestValidate_OverlappingFieldsCanBeMerged_ReturnTypesMustBeUnambiguous_ComparesDeepTypesIncludingList(t *testing.T) { - expectFailsRuleWithSchema(t, &schema, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectFailsRuleWithSchema(t, &schema, graphql.OverlappingFieldsCanBeMergedRule, ` { connection { ...edgeID @@ -387,14 +388,14 @@ func TestValidate_OverlappingFieldsCanBeMerged_ReturnTypesMustBeUnambiguous_Comp } } `, []gqlerrors.FormattedError{ - ruleError( + testutil.RuleError( `Fields "edges" conflict because subfields "node" conflict because subfields "id" conflict because `+ `id and name are different fields.`, 14, 11, 5, 13, 15, 13, 6, 15, 16, 15, 7, 17), }) } func TestValidate_OverlappingFieldsCanBeMerged_ReturnTypesMustBeUnambiguous_IgnoresUnknownTypes(t *testing.T) { - expectPassesRuleWithSchema(t, &schema, graphql.OverlappingFieldsCanBeMergedRule, ` + testutil.ExpectPassesRuleWithSchema(t, &schema, graphql.OverlappingFieldsCanBeMergedRule, ` { boxUnion { ...on UnknownType { diff --git a/rules/possible_fragment_spreads_test.go b/rules_possible_fragment_spreads_test.go similarity index 70% rename from rules/possible_fragment_spreads_test.go rename to rules_possible_fragment_spreads_test.go index 582d78ff..9e739fa8 100644 --- a/rules/possible_fragment_spreads_test.go +++ b/rules_possible_fragment_spreads_test.go @@ -1,179 +1,180 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_PossibleFragmentSpreads_OfTheSameObject(t *testing.T) { - expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment objectWithinObject on Dog { ...dogFragment } fragment dogFragment on Dog { barkVolume } `) } func TestValidate_PossibleFragmentSpreads_OfTheSameObjectWithInlineFragment(t *testing.T) { - expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment objectWithinObjectAnon on Dog { ... on Dog { barkVolume } } `) } func TestValidate_PossibleFragmentSpreads_ObjectIntoAnImplementedInterface(t *testing.T) { - expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment objectWithinInterface on Pet { ...dogFragment } fragment dogFragment on Dog { barkVolume } `) } func TestValidate_PossibleFragmentSpreads_ObjectIntoContainingUnion(t *testing.T) { - expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment objectWithinUnion on CatOrDog { ...dogFragment } fragment dogFragment on Dog { barkVolume } `) } func TestValidate_PossibleFragmentSpreads_UnionIntoContainedObject(t *testing.T) { - expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment unionWithinObject on Dog { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } `) } func TestValidate_PossibleFragmentSpreads_UnionIntoOverlappingInterface(t *testing.T) { - expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment unionWithinInterface on Pet { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } `) } func TestValidate_PossibleFragmentSpreads_UnionIntoOverlappingUnion(t *testing.T) { - expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment unionWithinUnion on DogOrHuman { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } `) } func TestValidate_PossibleFragmentSpreads_InterfaceIntoImplementedObject(t *testing.T) { - expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment interfaceWithinObject on Dog { ...petFragment } fragment petFragment on Pet { name } `) } func TestValidate_PossibleFragmentSpreads_InterfaceIntoOverlappingInterface(t *testing.T) { - expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment interfaceWithinInterface on Pet { ...beingFragment } fragment beingFragment on Being { name } `) } func TestValidate_PossibleFragmentSpreads_InterfaceIntoOverlappingInterfaceInInlineFragment(t *testing.T) { - expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment interfaceWithinInterface on Pet { ... on Being { name } } `) } func TestValidate_PossibleFragmentSpreads_InterfaceIntoOverlappingUnion(t *testing.T) { - expectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment interfaceWithinUnion on CatOrDog { ...petFragment } fragment petFragment on Pet { name } `) } func TestValidate_PossibleFragmentSpreads_DifferentObjectIntoObject(t *testing.T) { - expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidObjectWithinObject on Cat { ...dogFragment } fragment dogFragment on Dog { barkVolume } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "dogFragment" cannot be spread here as objects of `+ + testutil.RuleError(`Fragment "dogFragment" cannot be spread here as objects of `+ `type "Cat" can never be of type "Dog".`, 2, 51), }) } func TestValidate_PossibleFragmentSpreads_DifferentObjectIntoObjectInInlineFragment(t *testing.T) { - expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidObjectWithinObjectAnon on Cat { ... on Dog { barkVolume } } `, []gqlerrors.FormattedError{ - ruleError(`Fragment cannot be spread here as objects of `+ + testutil.RuleError(`Fragment cannot be spread here as objects of `+ `type "Cat" can never be of type "Dog".`, 3, 9), }) } func TestValidate_PossibleFragmentSpreads_ObjectIntoNotImplementingInterface(t *testing.T) { - expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidObjectWithinInterface on Pet { ...humanFragment } fragment humanFragment on Human { pets { name } } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "humanFragment" cannot be spread here as objects of `+ + testutil.RuleError(`Fragment "humanFragment" cannot be spread here as objects of `+ `type "Pet" can never be of type "Human".`, 2, 54), }) } func TestValidate_PossibleFragmentSpreads_ObjectIntoNotContainingUnion(t *testing.T) { - expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidObjectWithinUnion on CatOrDog { ...humanFragment } fragment humanFragment on Human { pets { name } } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "humanFragment" cannot be spread here as objects of `+ + testutil.RuleError(`Fragment "humanFragment" cannot be spread here as objects of `+ `type "CatOrDog" can never be of type "Human".`, 2, 55), }) } func TestValidate_PossibleFragmentSpreads_UnionIntoNotContainedObject(t *testing.T) { - expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidUnionWithinObject on Human { ...catOrDogFragment } fragment catOrDogFragment on CatOrDog { __typename } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "catOrDogFragment" cannot be spread here as objects of `+ + testutil.RuleError(`Fragment "catOrDogFragment" cannot be spread here as objects of `+ `type "Human" can never be of type "CatOrDog".`, 2, 52), }) } func TestValidate_PossibleFragmentSpreads_UnionIntoNonOverlappingInterface(t *testing.T) { - expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidUnionWithinInterface on Pet { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "humanOrAlienFragment" cannot be spread here as objects of `+ + testutil.RuleError(`Fragment "humanOrAlienFragment" cannot be spread here as objects of `+ `type "Pet" can never be of type "HumanOrAlien".`, 2, 53), }) } func TestValidate_PossibleFragmentSpreads_UnionIntoNonOverlappingUnion(t *testing.T) { - expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidUnionWithinUnion on CatOrDog { ...humanOrAlienFragment } fragment humanOrAlienFragment on HumanOrAlien { __typename } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "humanOrAlienFragment" cannot be spread here as objects of `+ + testutil.RuleError(`Fragment "humanOrAlienFragment" cannot be spread here as objects of `+ `type "CatOrDog" can never be of type "HumanOrAlien".`, 2, 54), }) } func TestValidate_PossibleFragmentSpreads_InterfaceIntoNonImplementingObject(t *testing.T) { - expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidInterfaceWithinObject on Cat { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "intelligentFragment" cannot be spread here as objects of `+ + testutil.RuleError(`Fragment "intelligentFragment" cannot be spread here as objects of `+ `type "Cat" can never be of type "Intelligent".`, 2, 54), }) } func TestValidate_PossibleFragmentSpreads_InterfaceIntoNonOverlappingInterface(t *testing.T) { - expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidInterfaceWithinInterface on Pet { ...intelligentFragment } fragment intelligentFragment on Intelligent { iq } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "intelligentFragment" cannot be spread here as objects of `+ + testutil.RuleError(`Fragment "intelligentFragment" cannot be spread here as objects of `+ `type "Pet" can never be of type "Intelligent".`, 3, 9), }) } func TestValidate_PossibleFragmentSpreads_InterfaceIntoNonOverlappingInterfaceInInlineFragment(t *testing.T) { - expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidInterfaceWithinInterfaceAnon on Pet { ...on Intelligent { iq } } `, []gqlerrors.FormattedError{ - ruleError(`Fragment cannot be spread here as objects of `+ + testutil.RuleError(`Fragment cannot be spread here as objects of `+ `type "Pet" can never be of type "Intelligent".`, 3, 9), }) } func TestValidate_PossibleFragmentSpreads_InterfaceIntoNonOverlappingUnion(t *testing.T) { - expectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` + testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidInterfaceWithinUnion on HumanOrAlien { ...petFragment } fragment petFragment on Pet { name } `, []gqlerrors.FormattedError{ - ruleError(`Fragment "petFragment" cannot be spread here as objects of `+ + testutil.RuleError(`Fragment "petFragment" cannot be spread here as objects of `+ `type "HumanOrAlien" can never be of type "Pet".`, 2, 62), }) } diff --git a/rules/provided_non_null_arguments_test.go b/rules_provided_non_null_arguments_test.go similarity index 65% rename from rules/provided_non_null_arguments_test.go rename to rules_provided_non_null_arguments_test.go index 71c5d7fc..6db35b0b 100644 --- a/rules/provided_non_null_arguments_test.go +++ b/rules_provided_non_null_arguments_test.go @@ -1,14 +1,15 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_ProvidedNonNullArguments_IgnoresUnknownArguments(t *testing.T) { - expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { dog { isHousetrained(unknownArgument: true) @@ -17,7 +18,7 @@ func TestValidate_ProvidedNonNullArguments_IgnoresUnknownArguments(t *testing.T) `) } func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_ArgOnOptionalArg(t *testing.T) { - expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { dog { isHousetrained(atOtherHomes: true) @@ -26,7 +27,7 @@ func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_ArgOnOptionalAr `) } func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_NoArgOnOptionalArg(t *testing.T) { - expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { dog { isHousetrained @@ -35,7 +36,7 @@ func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_NoArgOnOptional `) } func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_MultipleArgs(t *testing.T) { - expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { complicatedArgs { multipleReqs(req1: 1, req2: 2) @@ -44,7 +45,7 @@ func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_MultipleArgs(t `) } func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_MultipleArgsReverseOrder(t *testing.T) { - expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { complicatedArgs { multipleReqs(req2: 2, req1: 1) @@ -53,7 +54,7 @@ func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_MultipleArgsRev `) } func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_NoArgsOnMultipleOptional(t *testing.T) { - expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { complicatedArgs { multipleOpts @@ -62,7 +63,7 @@ func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_NoArgsOnMultipl `) } func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_OneArgOnMultipleOptional(t *testing.T) { - expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { complicatedArgs { multipleOpts(opt1: 1) @@ -71,7 +72,7 @@ func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_OneArgOnMultipl `) } func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_SecondArgOnMultipleOptional(t *testing.T) { - expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { complicatedArgs { multipleOpts(opt2: 1) @@ -80,7 +81,7 @@ func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_SecondArgOnMult `) } func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_MultipleReqsOnMixedList(t *testing.T) { - expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4) @@ -89,7 +90,7 @@ func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_MultipleReqsOnM `) } func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_MultipleReqsAndOneOptOnMixedList(t *testing.T) { - expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5) @@ -98,7 +99,7 @@ func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_MultipleReqsAnd `) } func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_AllReqsAndOptsOnMixedList(t *testing.T) { - expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { complicatedArgs { multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6) @@ -107,51 +108,51 @@ func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_AllReqsAndOptsO `) } func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_MissingOneNonNullableArgument(t *testing.T) { - expectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` { complicatedArgs { multipleReqs(req2: 2) } } `, []gqlerrors.FormattedError{ - ruleError(`Field "multipleReqs" argument "req1" of type "Int!" is required but not provided.`, 4, 13), + testutil.RuleError(`Field "multipleReqs" argument "req1" of type "Int!" is required but not provided.`, 4, 13), }) } func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_MissingMultipleNonNullableArguments(t *testing.T) { - expectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` { complicatedArgs { multipleReqs } } `, []gqlerrors.FormattedError{ - ruleError(`Field "multipleReqs" argument "req1" of type "Int!" is required but not provided.`, 4, 13), - ruleError(`Field "multipleReqs" argument "req2" of type "Int!" is required but not provided.`, 4, 13), + testutil.RuleError(`Field "multipleReqs" argument "req1" of type "Int!" is required but not provided.`, 4, 13), + testutil.RuleError(`Field "multipleReqs" argument "req2" of type "Int!" is required but not provided.`, 4, 13), }) } func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_IncorrectValueAndMissingArgument(t *testing.T) { - expectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` { complicatedArgs { multipleReqs(req1: "one") } } `, []gqlerrors.FormattedError{ - ruleError(`Field "multipleReqs" argument "req2" of type "Int!" is required but not provided.`, 4, 13), + testutil.RuleError(`Field "multipleReqs" argument "req2" of type "Int!" is required but not provided.`, 4, 13), }) } func TestValidate_ProvidedNonNullArguments_DirectiveArguments_IgnoresUnknownDirectives(t *testing.T) { - expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { dog @unknown } `) } func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_WithDirectivesOfValidTypes(t *testing.T) { - expectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { dog @include(if: true) { name @@ -163,14 +164,14 @@ func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_WithDirective `) } func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_WithDirectiveWithMissingTypes(t *testing.T) { - expectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` + testutil.ExpectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` { dog @include { name @skip } } `, []gqlerrors.FormattedError{ - ruleError(`Directive "@include" argument "if" of type "Boolean!" is required but not provided.`, 3, 15), - ruleError(`Directive "@skip" argument "if" of type "Boolean!" is required but not provided.`, 4, 18), + testutil.RuleError(`Directive "@include" argument "if" of type "Boolean!" is required but not provided.`, 3, 15), + testutil.RuleError(`Directive "@skip" argument "if" of type "Boolean!" is required but not provided.`, 4, 18), }) } diff --git a/rules/scalar_leafs_test.go b/rules_scalar_leafs_test.go similarity index 59% rename from rules/scalar_leafs_test.go rename to rules_scalar_leafs_test.go index a2063f2a..9dcd45c4 100644 --- a/rules/scalar_leafs_test.go +++ b/rules_scalar_leafs_test.go @@ -1,87 +1,88 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_ScalarLeafs_ValidScalarSelection(t *testing.T) { - expectPassesRule(t, graphql.ScalarLeafsRule, ` + testutil.ExpectPassesRule(t, graphql.ScalarLeafsRule, ` fragment scalarSelection on Dog { barks } `) } func TestValidate_ScalarLeafs_ObjectTypeMissingSelection(t *testing.T) { - expectFailsRule(t, graphql.ScalarLeafsRule, ` + testutil.ExpectFailsRule(t, graphql.ScalarLeafsRule, ` query directQueryOnObjectWithoutSubFields { human } `, []gqlerrors.FormattedError{ - ruleError(`Field "human" of type "Human" must have a sub selection.`, 3, 9), + testutil.RuleError(`Field "human" of type "Human" must have a sub selection.`, 3, 9), }) } func TestValidate_ScalarLeafs_InterfaceTypeMissingSelection(t *testing.T) { - expectFailsRule(t, graphql.ScalarLeafsRule, ` + testutil.ExpectFailsRule(t, graphql.ScalarLeafsRule, ` { human { pets } } `, []gqlerrors.FormattedError{ - ruleError(`Field "pets" of type "[Pet]" must have a sub selection.`, 3, 17), + testutil.RuleError(`Field "pets" of type "[Pet]" must have a sub selection.`, 3, 17), }) } func TestValidate_ScalarLeafs_ValidScalarSelectionWithArgs(t *testing.T) { - expectPassesRule(t, graphql.ScalarLeafsRule, ` + testutil.ExpectPassesRule(t, graphql.ScalarLeafsRule, ` fragment scalarSelectionWithArgs on Dog { doesKnowCommand(dogCommand: SIT) } `) } func TestValidate_ScalarLeafs_ScalarSelectionNotAllowedOnBoolean(t *testing.T) { - expectFailsRule(t, graphql.ScalarLeafsRule, ` + testutil.ExpectFailsRule(t, graphql.ScalarLeafsRule, ` fragment scalarSelectionsNotAllowedOnBoolean on Dog { barks { sinceWhen } } `, []gqlerrors.FormattedError{ - ruleError(`Field "barks" of type "Boolean" must not have a sub selection.`, 3, 15), + testutil.RuleError(`Field "barks" of type "Boolean" must not have a sub selection.`, 3, 15), }) } func TestValidate_ScalarLeafs_ScalarSelectionNotAllowedOnEnum(t *testing.T) { - expectFailsRule(t, graphql.ScalarLeafsRule, ` + testutil.ExpectFailsRule(t, graphql.ScalarLeafsRule, ` fragment scalarSelectionsNotAllowedOnEnum on Cat { furColor { inHexdec } } `, []gqlerrors.FormattedError{ - ruleError(`Field "furColor" of type "FurColor" must not have a sub selection.`, 3, 18), + testutil.RuleError(`Field "furColor" of type "FurColor" must not have a sub selection.`, 3, 18), }) } func TestValidate_ScalarLeafs_ScalarSelectionNotAllowedWithArgs(t *testing.T) { - expectFailsRule(t, graphql.ScalarLeafsRule, ` + testutil.ExpectFailsRule(t, graphql.ScalarLeafsRule, ` fragment scalarSelectionsNotAllowedWithArgs on Dog { doesKnowCommand(dogCommand: SIT) { sinceWhen } } `, []gqlerrors.FormattedError{ - ruleError(`Field "doesKnowCommand" of type "Boolean" must not have a sub selection.`, 3, 42), + testutil.RuleError(`Field "doesKnowCommand" of type "Boolean" must not have a sub selection.`, 3, 42), }) } func TestValidate_ScalarLeafs_ScalarSelectionNotAllowedWithDirectives(t *testing.T) { - expectFailsRule(t, graphql.ScalarLeafsRule, ` + testutil.ExpectFailsRule(t, graphql.ScalarLeafsRule, ` fragment scalarSelectionsNotAllowedWithDirectives on Dog { name @include(if: true) { isAlsoHumanName } } `, []gqlerrors.FormattedError{ - ruleError(`Field "name" of type "String" must not have a sub selection.`, 3, 33), + testutil.RuleError(`Field "name" of type "String" must not have a sub selection.`, 3, 33), }) } func TestValidate_ScalarLeafs_ScalarSelectionNotAllowedWithDirectivesAndArgs(t *testing.T) { - expectFailsRule(t, graphql.ScalarLeafsRule, ` + testutil.ExpectFailsRule(t, graphql.ScalarLeafsRule, ` fragment scalarSelectionsNotAllowedWithDirectivesAndArgs on Dog { doesKnowCommand(dogCommand: SIT) @include(if: true) { sinceWhen } } `, []gqlerrors.FormattedError{ - ruleError(`Field "doesKnowCommand" of type "Boolean" must not have a sub selection.`, 3, 61), + testutil.RuleError(`Field "doesKnowCommand" of type "Boolean" must not have a sub selection.`, 3, 61), }) } diff --git a/rules/unique_argument_names_test.go b/rules_unique_argument_names_test.go similarity index 59% rename from rules/unique_argument_names_test.go rename to rules_unique_argument_names_test.go index 0000fa36..d22de69c 100644 --- a/rules/unique_argument_names_test.go +++ b/rules_unique_argument_names_test.go @@ -1,42 +1,43 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_UniqueArgumentNames_NoArgumentsOnField(t *testing.T) { - expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueArgumentNamesRule, ` { field } `) } func TestValidate_UniqueArgumentNames_NoArgumentsOnDirective(t *testing.T) { - expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueArgumentNamesRule, ` { field } `) } func TestValidate_UniqueArgumentNames_ArgumentOnField(t *testing.T) { - expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueArgumentNamesRule, ` { field(arg: "value") } `) } func TestValidate_UniqueArgumentNames_ArgumentOnDirective(t *testing.T) { - expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueArgumentNamesRule, ` { field @directive(arg: "value") } `) } func TestValidate_UniqueArgumentNames_SameArgumentOnTwoFields(t *testing.T) { - expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueArgumentNamesRule, ` { one: field(arg: "value") two: field(arg: "value") @@ -44,68 +45,68 @@ func TestValidate_UniqueArgumentNames_SameArgumentOnTwoFields(t *testing.T) { `) } func TestValidate_UniqueArgumentNames_SameArgumentOnFieldAndDirective(t *testing.T) { - expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueArgumentNamesRule, ` { field(arg: "value") @directive(arg: "value") } `) } func TestValidate_UniqueArgumentNames_SameArgumentOnTwoDirectives(t *testing.T) { - expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueArgumentNamesRule, ` { field @directive1(arg: "value") @directive2(arg: "value") } `) } func TestValidate_UniqueArgumentNames_MultipleFieldArguments(t *testing.T) { - expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueArgumentNamesRule, ` { field(arg1: "value", arg2: "value", arg3: "value") } `) } func TestValidate_UniqueArgumentNames_MultipleDirectiveArguments(t *testing.T) { - expectPassesRule(t, graphql.UniqueArgumentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueArgumentNamesRule, ` { field @directive(arg1: "value", arg2: "value", arg3: "value") } `) } func TestValidate_UniqueArgumentNames_DuplicateFieldArguments(t *testing.T) { - expectFailsRule(t, graphql.UniqueArgumentNamesRule, ` + testutil.ExpectFailsRule(t, graphql.UniqueArgumentNamesRule, ` { field(arg1: "value", arg1: "value") } `, []gqlerrors.FormattedError{ - ruleError(`There can be only one argument named "arg1".`, 3, 15, 3, 30), + testutil.RuleError(`There can be only one argument named "arg1".`, 3, 15, 3, 30), }) } func TestValidate_UniqueArgumentNames_ManyDuplicateFieldArguments(t *testing.T) { - expectFailsRule(t, graphql.UniqueArgumentNamesRule, ` + testutil.ExpectFailsRule(t, graphql.UniqueArgumentNamesRule, ` { field(arg1: "value", arg1: "value", arg1: "value") } `, []gqlerrors.FormattedError{ - ruleError(`There can be only one argument named "arg1".`, 3, 15, 3, 30), - ruleError(`There can be only one argument named "arg1".`, 3, 15, 3, 45), + testutil.RuleError(`There can be only one argument named "arg1".`, 3, 15, 3, 30), + testutil.RuleError(`There can be only one argument named "arg1".`, 3, 15, 3, 45), }) } func TestValidate_UniqueArgumentNames_DuplicateDirectiveArguments(t *testing.T) { - expectFailsRule(t, graphql.UniqueArgumentNamesRule, ` + testutil.ExpectFailsRule(t, graphql.UniqueArgumentNamesRule, ` { field @directive(arg1: "value", arg1: "value") } `, []gqlerrors.FormattedError{ - ruleError(`There can be only one argument named "arg1".`, 3, 26, 3, 41), + testutil.RuleError(`There can be only one argument named "arg1".`, 3, 26, 3, 41), }) } func TestValidate_UniqueArgumentNames_ManyDuplicateDirectiveArguments(t *testing.T) { - expectFailsRule(t, graphql.UniqueArgumentNamesRule, ` + testutil.ExpectFailsRule(t, graphql.UniqueArgumentNamesRule, ` { field @directive(arg1: "value", arg1: "value", arg1: "value") } `, []gqlerrors.FormattedError{ - ruleError(`There can be only one argument named "arg1".`, 3, 26, 3, 41), - ruleError(`There can be only one argument named "arg1".`, 3, 26, 3, 56), + testutil.RuleError(`There can be only one argument named "arg1".`, 3, 26, 3, 41), + testutil.RuleError(`There can be only one argument named "arg1".`, 3, 26, 3, 56), }) } diff --git a/rules/unique_fragment_names_test.go b/rules_unique_fragment_names_test.go similarity index 67% rename from rules/unique_fragment_names_test.go rename to rules_unique_fragment_names_test.go index 3f1f79d3..f6511b7f 100644 --- a/rules/unique_fragment_names_test.go +++ b/rules_unique_fragment_names_test.go @@ -1,21 +1,22 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_UniqueFragmentNames_NoFragments(t *testing.T) { - expectPassesRule(t, graphql.UniqueFragmentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueFragmentNamesRule, ` { field } `) } func TestValidate_UniqueFragmentNames_OneFragment(t *testing.T) { - expectPassesRule(t, graphql.UniqueFragmentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueFragmentNamesRule, ` { ...fragA } @@ -26,7 +27,7 @@ func TestValidate_UniqueFragmentNames_OneFragment(t *testing.T) { `) } func TestValidate_UniqueFragmentNames_ManyFragments(t *testing.T) { - expectPassesRule(t, graphql.UniqueFragmentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueFragmentNamesRule, ` { ...fragA ...fragB @@ -44,7 +45,7 @@ func TestValidate_UniqueFragmentNames_ManyFragments(t *testing.T) { `) } func TestValidate_UniqueFragmentNames_InlineFragmentsAreAlwaysUnique(t *testing.T) { - expectPassesRule(t, graphql.UniqueFragmentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueFragmentNamesRule, ` { ...on Type { fieldA @@ -56,7 +57,7 @@ func TestValidate_UniqueFragmentNames_InlineFragmentsAreAlwaysUnique(t *testing. `) } func TestValidate_UniqueFragmentNames_FragmentAndOperationNamedTheSame(t *testing.T) { - expectPassesRule(t, graphql.UniqueFragmentNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueFragmentNamesRule, ` query Foo { ...Foo } @@ -66,7 +67,7 @@ func TestValidate_UniqueFragmentNames_FragmentAndOperationNamedTheSame(t *testin `) } func TestValidate_UniqueFragmentNames_FragmentsNamedTheSame(t *testing.T) { - expectFailsRule(t, graphql.UniqueFragmentNamesRule, ` + testutil.ExpectFailsRule(t, graphql.UniqueFragmentNamesRule, ` { ...fragA } @@ -77,11 +78,11 @@ func TestValidate_UniqueFragmentNames_FragmentsNamedTheSame(t *testing.T) { fieldB } `, []gqlerrors.FormattedError{ - ruleError(`There can only be one fragment named "fragA".`, 5, 16, 8, 16), + testutil.RuleError(`There can only be one fragment named "fragA".`, 5, 16, 8, 16), }) } func TestValidate_UniqueFragmentNames_FragmentsNamedTheSameWithoutBeingReferenced(t *testing.T) { - expectFailsRule(t, graphql.UniqueFragmentNamesRule, ` + testutil.ExpectFailsRule(t, graphql.UniqueFragmentNamesRule, ` fragment fragA on Type { fieldA } @@ -89,6 +90,6 @@ func TestValidate_UniqueFragmentNames_FragmentsNamedTheSameWithoutBeingReference fieldB } `, []gqlerrors.FormattedError{ - ruleError(`There can only be one fragment named "fragA".`, 2, 16, 5, 16), + testutil.RuleError(`There can only be one fragment named "fragA".`, 2, 16, 5, 16), }) } diff --git a/rules/unique_operation_names_test.go b/rules_unique_operation_names_test.go similarity index 63% rename from rules/unique_operation_names_test.go rename to rules_unique_operation_names_test.go index f2039955..bbc52e27 100644 --- a/rules/unique_operation_names_test.go +++ b/rules_unique_operation_names_test.go @@ -1,35 +1,36 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_UniqueOperationNames_NoOperations(t *testing.T) { - expectPassesRule(t, graphql.UniqueOperationNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueOperationNamesRule, ` fragment fragA on Type { field } `) } func TestValidate_UniqueOperationNames_OneAnonOperation(t *testing.T) { - expectPassesRule(t, graphql.UniqueOperationNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueOperationNamesRule, ` { field } `) } func TestValidate_UniqueOperationNames_OneNamedOperation(t *testing.T) { - expectPassesRule(t, graphql.UniqueOperationNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueOperationNamesRule, ` query Foo { field } `) } func TestValidate_UniqueOperationNames_MultipleOperations(t *testing.T) { - expectPassesRule(t, graphql.UniqueOperationNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueOperationNamesRule, ` query Foo { field } @@ -40,7 +41,7 @@ func TestValidate_UniqueOperationNames_MultipleOperations(t *testing.T) { `) } func TestValidate_UniqueOperationNames_MultipleOperationsOfDifferentTypes(t *testing.T) { - expectPassesRule(t, graphql.UniqueOperationNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueOperationNamesRule, ` query Foo { field } @@ -51,7 +52,7 @@ func TestValidate_UniqueOperationNames_MultipleOperationsOfDifferentTypes(t *tes `) } func TestValidate_UniqueOperationNames_FragmentAndOperationNamedTheSame(t *testing.T) { - expectPassesRule(t, graphql.UniqueOperationNamesRule, ` + testutil.ExpectPassesRule(t, graphql.UniqueOperationNamesRule, ` query Foo { field } @@ -62,7 +63,7 @@ func TestValidate_UniqueOperationNames_FragmentAndOperationNamedTheSame(t *testi `) } func TestValidate_UniqueOperationNames_MultipleOperationsOfSameName(t *testing.T) { - expectFailsRule(t, graphql.UniqueOperationNamesRule, ` + testutil.ExpectFailsRule(t, graphql.UniqueOperationNamesRule, ` query Foo { fieldA } @@ -70,11 +71,11 @@ func TestValidate_UniqueOperationNames_MultipleOperationsOfSameName(t *testing.T fieldB } `, []gqlerrors.FormattedError{ - ruleError(`There can only be one operation named "Foo".`, 2, 13, 5, 13), + testutil.RuleError(`There can only be one operation named "Foo".`, 2, 13, 5, 13), }) } func TestValidate_UniqueOperationNames_MultipleOperationsOfSameNameOfDifferentTypes(t *testing.T) { - expectFailsRule(t, graphql.UniqueOperationNamesRule, ` + testutil.ExpectFailsRule(t, graphql.UniqueOperationNamesRule, ` query Foo { fieldA } @@ -82,6 +83,6 @@ func TestValidate_UniqueOperationNames_MultipleOperationsOfSameNameOfDifferentTy fieldB } `, []gqlerrors.FormattedError{ - ruleError(`There can only be one operation named "Foo".`, 2, 13, 5, 16), + testutil.RuleError(`There can only be one operation named "Foo".`, 2, 13, 5, 16), }) } diff --git a/rules/variables_are_input_types_test.go b/rules_variables_are_input_types_test.go similarity index 51% rename from rules/variables_are_input_types_test.go rename to rules_variables_are_input_types_test.go index 77dd608c..fb1d1675 100644 --- a/rules/variables_are_input_types_test.go +++ b/rules_variables_are_input_types_test.go @@ -1,27 +1,28 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_VariablesAreInputTypes_(t *testing.T) { - expectPassesRule(t, graphql.VariablesAreInputTypesRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesAreInputTypesRule, ` query Foo($a: String, $b: [Boolean!]!, $c: ComplexInput) { field(a: $a, b: $b, c: $c) } `) } func TestValidate_VariablesAreInputTypes_1(t *testing.T) { - expectFailsRule(t, graphql.VariablesAreInputTypesRule, ` + testutil.ExpectFailsRule(t, graphql.VariablesAreInputTypesRule, ` query Foo($a: Dog, $b: [[CatOrDog!]]!, $c: Pet) { field(a: $a, b: $b, c: $c) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$a" cannot be non-input type "Dog".`, 2, 21), - ruleError(`Variable "$b" cannot be non-input type "[[CatOrDog!]]!".`, 2, 30), - ruleError(`Variable "$c" cannot be non-input type "Pet".`, 2, 50), + testutil.RuleError(`Variable "$a" cannot be non-input type "Dog".`, 2, 21), + testutil.RuleError(`Variable "$b" cannot be non-input type "[[CatOrDog!]]!".`, 2, 30), + testutil.RuleError(`Variable "$c" cannot be non-input type "Pet".`, 2, 50), }) } diff --git a/rules/variables_in_allowed_position_test.go b/rules_variables_in_allowed_position_test.go similarity index 73% rename from rules/variables_in_allowed_position_test.go rename to rules_variables_in_allowed_position_test.go index 4b04c832..660ab5d2 100644 --- a/rules/variables_in_allowed_position_test.go +++ b/rules_variables_in_allowed_position_test.go @@ -1,14 +1,15 @@ -package rules_test +package graphql_test import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_VariablesInAllowedPosition_BooleanToBoolean(t *testing.T) { - expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($booleanArg: Boolean) { complicatedArgs { @@ -18,7 +19,7 @@ func TestValidate_VariablesInAllowedPosition_BooleanToBoolean(t *testing.T) { `) } func TestValidate_VariablesInAllowedPosition_BooleanToBooleanWithinFragment(t *testing.T) { - expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $booleanArg) } @@ -29,7 +30,7 @@ func TestValidate_VariablesInAllowedPosition_BooleanToBooleanWithinFragment(t *t } } `) - expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($booleanArg: Boolean) { complicatedArgs { @@ -42,7 +43,7 @@ func TestValidate_VariablesInAllowedPosition_BooleanToBooleanWithinFragment(t *t `) } func TestValidate_VariablesInAllowedPosition_NonNullableBooleanToBoolean(t *testing.T) { - expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($nonNullBooleanArg: Boolean!) { complicatedArgs { @@ -52,7 +53,7 @@ func TestValidate_VariablesInAllowedPosition_NonNullableBooleanToBoolean(t *test `) } func TestValidate_VariablesInAllowedPosition_NonNullableBooleanToBooleanWithinFragment(t *testing.T) { - expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` fragment booleanArgFrag on ComplicatedArgs { booleanArgField(booleanArg: $nonNullBooleanArg) } @@ -66,7 +67,7 @@ func TestValidate_VariablesInAllowedPosition_NonNullableBooleanToBooleanWithinFr `) } func TestValidate_VariablesInAllowedPosition_IntToNonNullableIntWithDefault(t *testing.T) { - expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($intArg: Int = 1) { complicatedArgs { @@ -76,7 +77,7 @@ func TestValidate_VariablesInAllowedPosition_IntToNonNullableIntWithDefault(t *t `) } func TestValidate_VariablesInAllowedPosition_ListOfStringToListOfString(t *testing.T) { - expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($stringListVar: [String]) { complicatedArgs { @@ -86,7 +87,7 @@ func TestValidate_VariablesInAllowedPosition_ListOfStringToListOfString(t *testi `) } func TestValidate_VariablesInAllowedPosition_ListOfNonNullableStringToListOfString(t *testing.T) { - expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($stringListVar: [String!]) { complicatedArgs { @@ -96,7 +97,7 @@ func TestValidate_VariablesInAllowedPosition_ListOfNonNullableStringToListOfStri `) } func TestValidate_VariablesInAllowedPosition_StringToListOfStringInItemPosition(t *testing.T) { - expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($stringVar: String) { complicatedArgs { @@ -106,7 +107,7 @@ func TestValidate_VariablesInAllowedPosition_StringToListOfStringInItemPosition( `) } func TestValidate_VariablesInAllowedPosition_NonNullableStringToListOfStringInItemPosition(t *testing.T) { - expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($stringVar: String!) { complicatedArgs { @@ -116,7 +117,7 @@ func TestValidate_VariablesInAllowedPosition_NonNullableStringToListOfStringInIt `) } func TestValidate_VariablesInAllowedPosition_ComplexInputToComplexInput(t *testing.T) { - expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($complexVar: ComplexInput) { complicatedArgs { @@ -126,7 +127,7 @@ func TestValidate_VariablesInAllowedPosition_ComplexInputToComplexInput(t *testi `) } func TestValidate_VariablesInAllowedPosition_ComplexInputToComplexInputInFieldPosition(t *testing.T) { - expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($boolVar: Boolean = false) { complicatedArgs { @@ -136,7 +137,7 @@ func TestValidate_VariablesInAllowedPosition_ComplexInputToComplexInputInFieldPo `) } func TestValidate_VariablesInAllowedPosition_NonNullableBooleanToNonNullableBooleanInDirective(t *testing.T) { - expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($boolVar: Boolean!) { dog @include(if: $boolVar) @@ -144,7 +145,7 @@ func TestValidate_VariablesInAllowedPosition_NonNullableBooleanToNonNullableBool `) } func TestValidate_VariablesInAllowedPosition_NonNullableBooleanToNonNullableBooleanInDirectiveInDirectiveWithDefault(t *testing.T) { - expectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectPassesRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($boolVar: Boolean = false) { dog @include(if: $boolVar) @@ -152,7 +153,7 @@ func TestValidate_VariablesInAllowedPosition_NonNullableBooleanToNonNullableBool `) } func TestValidate_VariablesInAllowedPosition_IntToNonNullableInt(t *testing.T) { - expectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($intArg: Int) { complicatedArgs { @@ -160,12 +161,12 @@ func TestValidate_VariablesInAllowedPosition_IntToNonNullableInt(t *testing.T) { } } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$intArg" of type "Int" used in position `+ + testutil.RuleError(`Variable "$intArg" of type "Int" used in position `+ `expecting type "Int!".`, 5, 45), }) } func TestValidate_VariablesInAllowedPosition_IntToNonNullableIntWithinFragment(t *testing.T) { - expectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` fragment nonNullIntArgFieldFrag on ComplicatedArgs { nonNullIntArgField(nonNullIntArg: $intArg) } @@ -177,12 +178,12 @@ func TestValidate_VariablesInAllowedPosition_IntToNonNullableIntWithinFragment(t } } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$intArg" of type "Int" used in position `+ + testutil.RuleError(`Variable "$intArg" of type "Int" used in position `+ `expecting type "Int!".`, 3, 43), }) } func TestValidate_VariablesInAllowedPosition_IntToNonNullableIntWithinNestedFragment(t *testing.T) { - expectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` fragment outerFrag on ComplicatedArgs { ...nonNullIntArgFieldFrag } @@ -198,12 +199,12 @@ func TestValidate_VariablesInAllowedPosition_IntToNonNullableIntWithinNestedFrag } } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$intArg" of type "Int" used in position `+ + testutil.RuleError(`Variable "$intArg" of type "Int" used in position `+ `expecting type "Int!".`, 7, 43), }) } func TestValidate_VariablesInAllowedPosition_StringOverBoolean(t *testing.T) { - expectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($stringVar: String) { complicatedArgs { @@ -211,12 +212,12 @@ func TestValidate_VariablesInAllowedPosition_StringOverBoolean(t *testing.T) { } } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$stringVar" of type "String" used in position `+ + testutil.RuleError(`Variable "$stringVar" of type "String" used in position `+ `expecting type "Boolean".`, 5, 39), }) } func TestValidate_VariablesInAllowedPosition_StringToListOfString(t *testing.T) { - expectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($stringVar: String) { complicatedArgs { @@ -224,29 +225,29 @@ func TestValidate_VariablesInAllowedPosition_StringToListOfString(t *testing.T) } } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$stringVar" of type "String" used in position `+ + testutil.RuleError(`Variable "$stringVar" of type "String" used in position `+ `expecting type "[String]".`, 5, 45), }) } func TestValidate_VariablesInAllowedPosition_BooleanToNonNullableBooleanInDirective(t *testing.T) { - expectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($boolVar: Boolean) { dog @include(if: $boolVar) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$boolVar" of type "Boolean" used in position `+ + testutil.RuleError(`Variable "$boolVar" of type "Boolean" used in position `+ `expecting type "Boolean!".`, 4, 26), }) } func TestValidate_VariablesInAllowedPosition_StringToNonNullableBooleanInDirective(t *testing.T) { - expectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` + testutil.ExpectFailsRule(t, graphql.VariablesInAllowedPositionRule, ` query Query($stringVar: String) { dog @include(if: $stringVar) } `, []gqlerrors.FormattedError{ - ruleError(`Variable "$stringVar" of type "String" used in position `+ + testutil.RuleError(`Variable "$stringVar" of type "String" used in position `+ `expecting type "Boolean!".`, 4, 26), }) } diff --git a/testutil/rules_test_harness.go b/testutil/rules_test_harness.go new file mode 100644 index 00000000..3acb9094 --- /dev/null +++ b/testutil/rules_test_harness.go @@ -0,0 +1,529 @@ +package testutil + +import ( + "testing" + + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/language/location" + "github.com/graphql-go/graphql/language/parser" + "github.com/graphql-go/graphql/language/source" + "reflect" +) + +var defaultRulesTestSchema *graphql.Schema + +func init() { + + var beingInterface = graphql.NewInterface(graphql.InterfaceConfig{ + Name: "Being", + Fields: graphql.Fields{ + "name": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "surname": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + }, + }, + }, + }, + }) + var petInterface = graphql.NewInterface(graphql.InterfaceConfig{ + Name: "Pet", + Fields: graphql.Fields{ + "name": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "surname": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + }, + }, + }, + }, + }) + var dogCommandEnum = graphql.NewEnum(graphql.EnumConfig{ + Name: "DogCommand", + Values: graphql.EnumValueConfigMap{ + "SIT": &graphql.EnumValueConfig{ + Value: 0, + }, + "HEEL": &graphql.EnumValueConfig{ + Value: 1, + }, + "DOWN": &graphql.EnumValueConfig{ + Value: 2, + }, + }, + }) + var dogType = graphql.NewObject(graphql.ObjectConfig{ + Name: "Dog", + IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { + return true + }, + Fields: graphql.Fields{ + "name": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "surname": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + }, + }, + }, + "nickname": &graphql.Field{ + Type: graphql.String, + }, + "barkVolume": &graphql.Field{ + Type: graphql.Int, + }, + "barks": &graphql.Field{ + Type: graphql.Boolean, + }, + "doesKnowCommand": &graphql.Field{ + Type: graphql.Boolean, + Args: graphql.FieldConfigArgument{ + "dogCommand": &graphql.ArgumentConfig{ + Type: dogCommandEnum, + }, + }, + }, + "isHousetrained": &graphql.Field{ + Type: graphql.Boolean, + Args: graphql.FieldConfigArgument{ + "atOtherHomes": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + DefaultValue: true, + }, + }, + }, + "isAtLocation": &graphql.Field{ + Type: graphql.Boolean, + Args: graphql.FieldConfigArgument{ + "x": &graphql.ArgumentConfig{ + Type: graphql.Int, + }, + "y": &graphql.ArgumentConfig{ + Type: graphql.Int, + }, + }, + }, + }, + Interfaces: []*graphql.Interface{ + beingInterface, + petInterface, + }, + }) + var furColorEnum = graphql.NewEnum(graphql.EnumConfig{ + Name: "FurColor", + Values: graphql.EnumValueConfigMap{ + "BROWN": &graphql.EnumValueConfig{ + Value: 0, + }, + "BLACK": &graphql.EnumValueConfig{ + Value: 1, + }, + "TAN": &graphql.EnumValueConfig{ + Value: 2, + }, + "SPOTTED": &graphql.EnumValueConfig{ + Value: 3, + }, + }, + }) + + var catType = graphql.NewObject(graphql.ObjectConfig{ + Name: "Cat", + IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { + return true + }, + Fields: graphql.Fields{ + "name": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "surname": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + }, + }, + }, + "nickname": &graphql.Field{ + Type: graphql.String, + }, + "meowVolume": &graphql.Field{ + Type: graphql.Int, + }, + "meows": &graphql.Field{ + Type: graphql.Boolean, + }, + "furColor": &graphql.Field{ + Type: furColorEnum, + }, + }, + Interfaces: []*graphql.Interface{ + beingInterface, + petInterface, + }, + }) + var catOrDogUnion = graphql.NewUnion(graphql.UnionConfig{ + Name: "CatOrDog", + Types: []*graphql.Object{ + dogType, + catType, + }, + ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { + // not used for validation + return nil + }, + }) + var intelligentInterface = graphql.NewInterface(graphql.InterfaceConfig{ + Name: "Intelligent", + Fields: graphql.Fields{ + "iq": &graphql.Field{ + Type: graphql.Int, + }, + }, + }) + + var humanType = graphql.NewObject(graphql.ObjectConfig{ + Name: "Human", + IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { + return true + }, + Interfaces: []*graphql.Interface{ + beingInterface, + intelligentInterface, + }, + Fields: graphql.Fields{ + "name": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "surname": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + }, + }, + }, + "pets": &graphql.Field{ + Type: graphql.NewList(petInterface), + }, + "iq": &graphql.Field{ + Type: graphql.Int, + }, + }, + }) + + humanType.AddFieldConfig("relatives", &graphql.Field{ + Type: graphql.NewList(humanType), + }) + + var alienType = graphql.NewObject(graphql.ObjectConfig{ + Name: "Alien", + IsTypeOf: func(value interface{}, info graphql.ResolveInfo) bool { + return true + }, + Interfaces: []*graphql.Interface{ + beingInterface, + intelligentInterface, + }, + Fields: graphql.Fields{ + "name": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "surname": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + }, + }, + }, + "iq": &graphql.Field{ + Type: graphql.Int, + }, + "numEyes": &graphql.Field{ + Type: graphql.Int, + }, + }, + }) + var dogOrHumanUnion = graphql.NewUnion(graphql.UnionConfig{ + Name: "DogOrHuman", + Types: []*graphql.Object{ + dogType, + humanType, + }, + ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { + // not used for validation + return nil + }, + }) + var humanOrAlienUnion = graphql.NewUnion(graphql.UnionConfig{ + Name: "HumanOrAlien", + Types: []*graphql.Object{ + alienType, + humanType, + }, + ResolveType: func(value interface{}, info graphql.ResolveInfo) *graphql.Object { + // not used for validation + return nil + }, + }) + + var complexInputObject = graphql.NewInputObject(graphql.InputObjectConfig{ + Name: "ComplexInput", + Fields: graphql.InputObjectConfigFieldMap{ + "requiredField": &graphql.InputObjectFieldConfig{ + Type: graphql.NewNonNull(graphql.Boolean), + }, + "intField": &graphql.InputObjectFieldConfig{ + Type: graphql.Int, + }, + "stringField": &graphql.InputObjectFieldConfig{ + Type: graphql.String, + }, + "booleanField": &graphql.InputObjectFieldConfig{ + Type: graphql.Boolean, + }, + "stringListField": &graphql.InputObjectFieldConfig{ + Type: graphql.NewList(graphql.String), + }, + }, + }) + var complicatedArgs = graphql.NewObject(graphql.ObjectConfig{ + Name: "ComplicatedArgs", + // TODO List + // TODO Coercion + // TODO NotNulls + Fields: graphql.Fields{ + "intArgField": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "intArg": &graphql.ArgumentConfig{ + Type: graphql.Int, + }, + }, + }, + "nonNullIntArgField": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "nonNullIntArg": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.Int), + }, + }, + }, + "stringArgField": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "stringArg": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + }, + }, + "booleanArgField": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "booleanArg": &graphql.ArgumentConfig{ + Type: graphql.Boolean, + }, + }, + }, + "enumArgField": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "enumArg": &graphql.ArgumentConfig{ + Type: furColorEnum, + }, + }, + }, + "floatArgField": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "floatArg": &graphql.ArgumentConfig{ + Type: graphql.Float, + }, + }, + }, + "idArgField": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "idArg": &graphql.ArgumentConfig{ + Type: graphql.ID, + }, + }, + }, + "stringListArgField": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "stringListArg": &graphql.ArgumentConfig{ + Type: graphql.NewList(graphql.String), + }, + }, + }, + "complexArgField": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "complexArg": &graphql.ArgumentConfig{ + Type: complexInputObject, + }, + }, + }, + "multipleReqs": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "req1": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.Int), + }, + "req2": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.Int), + }, + }, + }, + "multipleOpts": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "opt1": &graphql.ArgumentConfig{ + Type: graphql.Int, + DefaultValue: 0, + }, + "opt2": &graphql.ArgumentConfig{ + Type: graphql.Int, + DefaultValue: 0, + }, + }, + }, + "multipleOptAndReq": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "req1": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.Int), + }, + "req2": &graphql.ArgumentConfig{ + Type: graphql.NewNonNull(graphql.Int), + }, + "opt1": &graphql.ArgumentConfig{ + Type: graphql.Int, + DefaultValue: 0, + }, + "opt2": &graphql.ArgumentConfig{ + Type: graphql.Int, + DefaultValue: 0, + }, + }, + }, + }, + }) + queryRoot := graphql.NewObject(graphql.ObjectConfig{ + Name: "QueryRoot", + Fields: graphql.Fields{ + "human": &graphql.Field{ + Args: graphql.FieldConfigArgument{ + "id": &graphql.ArgumentConfig{ + Type: graphql.ID, + }, + }, + Type: humanType, + }, + "alien": &graphql.Field{ + Type: alienType, + }, + "dog": &graphql.Field{ + Type: dogType, + }, + "cat": &graphql.Field{ + Type: catType, + }, + "pet": &graphql.Field{ + Type: petInterface, + }, + "catOrDog": &graphql.Field{ + Type: catOrDogUnion, + }, + "dogOrHuman": &graphql.Field{ + Type: dogOrHumanUnion, + }, + "humanOrAlien": &graphql.Field{ + Type: humanOrAlienUnion, + }, + "complicatedArgs": &graphql.Field{ + Type: complicatedArgs, + }, + }, + }) + schema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: queryRoot, + }) + if err != nil { + panic(err) + } + defaultRulesTestSchema = &schema + +} +func expectValidRule(t *testing.T, schema *graphql.Schema, rules []graphql.ValidationRuleFn, queryString string) { + source := source.NewSource(&source.Source{ + Body: queryString, + }) + AST, err := parser.Parse(parser.ParseParams{Source: source}) + if err != nil { + t.Fatal(err) + } + result := graphql.ValidateDocument(schema, AST, rules) + if len(result.Errors) > 0 { + t.Fatalf("Should validate, got %v", result.Errors) + } + if result.IsValid != true { + t.Fatalf("IsValid should be true, got %v", result.IsValid) + } + +} +func expectInvalidRule(t *testing.T, schema *graphql.Schema, rules []graphql.ValidationRuleFn, queryString string, expectedErrors []gqlerrors.FormattedError) { + source := source.NewSource(&source.Source{ + Body: queryString, + }) + AST, err := parser.Parse(parser.ParseParams{Source: source}) + if err != nil { + t.Fatal(err) + } + result := graphql.ValidateDocument(schema, AST, rules) + if len(result.Errors) != len(expectedErrors) { + t.Fatalf("Should have %v errors, got %v", len(expectedErrors), len(result.Errors)) + } + if result.IsValid != false { + t.Fatalf("IsValid should be false, got %v", result.IsValid) + } + for _, expectedErr := range expectedErrors { + found := false + for _, err := range result.Errors { + if reflect.DeepEqual(expectedErr, err) { + found = true + break + } + } + if found == false { + t.Fatalf("Unexpected result, Diff: %v", Diff(expectedErrors, result.Errors)) + } + } + +} +func ExpectPassesRule(t *testing.T, rule graphql.ValidationRuleFn, queryString string) { + expectValidRule(t, defaultRulesTestSchema, []graphql.ValidationRuleFn{rule}, queryString) +} +func ExpectFailsRule(t *testing.T, rule graphql.ValidationRuleFn, queryString string, expectedErrors []gqlerrors.FormattedError) { + expectInvalidRule(t, defaultRulesTestSchema, []graphql.ValidationRuleFn{rule}, queryString, expectedErrors) +} +func ExpectFailsRuleWithSchema(t *testing.T, schema *graphql.Schema, rule graphql.ValidationRuleFn, queryString string, expectedErrors []gqlerrors.FormattedError) { + expectInvalidRule(t, schema, []graphql.ValidationRuleFn{rule}, queryString, expectedErrors) +} +func ExpectPassesRuleWithSchema(t *testing.T, schema *graphql.Schema, rule graphql.ValidationRuleFn, queryString string) { + expectValidRule(t, schema, []graphql.ValidationRuleFn{rule}, queryString) +} +func RuleError(message string, locs ...int) gqlerrors.FormattedError { + locations := []location.SourceLocation{} + for i := 0; i < len(locs); i = i + 2 { + line := locs[i] + col := 0 + if i+1 < len(locs) { + col = locs[i+1] + } + locations = append(locations, location.SourceLocation{ + Line: line, + Column: col, + }) + } + return gqlerrors.FormattedError{ + Message: message, + Locations: locations, + } +} From 7b9d6e373a2a45be620161a4e7f0397bf59bd158 Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Wed, 18 Nov 2015 21:41:56 +0800 Subject: [PATCH 31/41] Minor `gofmt` --- rules_default_values_of_correct_type_test.go | 4 ++-- rules_fields_on_correct_type_test.go | 4 ++-- rules_fragments_on_composite_types_test.go | 4 ++-- rules_known_argument_names_test.go | 4 ++-- rules_known_directives_rule_test.go | 4 ++-- rules_known_fragment_names_test.go | 6 +++--- rules_known_type_names_test.go | 4 ++-- rules_lone_anonymous_operation_rule_test.go | 4 ++-- rules_no_fragment_cycles_test.go | 4 ++-- rules_no_undefined_variables_test.go | 4 ++-- rules_no_unused_fragments_test.go | 4 ++-- rules_no_unused_variables_test.go | 4 ++-- rules_overlapping_fields_can_be_merged_test.go | 4 ++-- rules_possible_fragment_spreads_test.go | 4 ++-- rules_provided_non_null_arguments_test.go | 4 ++-- rules_scalar_leafs_test.go | 4 ++-- rules_unique_argument_names_test.go | 4 ++-- rules_unique_fragment_names_test.go | 4 ++-- rules_unique_operation_names_test.go | 4 ++-- rules_variables_in_allowed_position_test.go | 4 ++-- 20 files changed, 41 insertions(+), 41 deletions(-) diff --git a/rules_default_values_of_correct_type_test.go b/rules_default_values_of_correct_type_test.go index d4085407..f5e84dc8 100644 --- a/rules_default_values_of_correct_type_test.go +++ b/rules_default_values_of_correct_type_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_VariableDefaultValuesOfCorrectType_VariablesWithNoDefaultValues(t *testing.T) { diff --git a/rules_fields_on_correct_type_test.go b/rules_fields_on_correct_type_test.go index c060289f..af1f571e 100644 --- a/rules_fields_on_correct_type_test.go +++ b/rules_fields_on_correct_type_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_FieldsOnCorrectType_ObjectFieldSelection(t *testing.T) { diff --git a/rules_fragments_on_composite_types_test.go b/rules_fragments_on_composite_types_test.go index 3b001286..34e900c2 100644 --- a/rules_fragments_on_composite_types_test.go +++ b/rules_fragments_on_composite_types_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_FragmentsOnCompositeTypes_ObjectIsValidFragmentType(t *testing.T) { diff --git a/rules_known_argument_names_test.go b/rules_known_argument_names_test.go index 3d8c65a5..7536161d 100644 --- a/rules_known_argument_names_test.go +++ b/rules_known_argument_names_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_KnownArgumentNames_SingleArgIsKnown(t *testing.T) { diff --git a/rules_known_directives_rule_test.go b/rules_known_directives_rule_test.go index f8f86d2d..2e4f2acf 100644 --- a/rules_known_directives_rule_test.go +++ b/rules_known_directives_rule_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_KnownDirectives_WithNoDirectives(t *testing.T) { diff --git a/rules_known_fragment_names_test.go b/rules_known_fragment_names_test.go index 66abe07c..b3d5d52e 100644 --- a/rules_known_fragment_names_test.go +++ b/rules_known_fragment_names_test.go @@ -3,9 +3,9 @@ package graphql_test import ( "testing" - "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_KnownFragmentNames_KnownFragmentNamesAreValid(t *testing.T) { diff --git a/rules_known_type_names_test.go b/rules_known_type_names_test.go index 59e68468..00c70263 100644 --- a/rules_known_type_names_test.go +++ b/rules_known_type_names_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_KnownTypeNames_KnownTypeNamesAreValid(t *testing.T) { diff --git a/rules_lone_anonymous_operation_rule_test.go b/rules_lone_anonymous_operation_rule_test.go index 8351a49c..2f515130 100644 --- a/rules_lone_anonymous_operation_rule_test.go +++ b/rules_lone_anonymous_operation_rule_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_AnonymousOperationMustBeAlone_NoOperations(t *testing.T) { diff --git a/rules_no_fragment_cycles_test.go b/rules_no_fragment_cycles_test.go index 526bb7c5..32b0a0a1 100644 --- a/rules_no_fragment_cycles_test.go +++ b/rules_no_fragment_cycles_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_NoCircularFragmentSpreads_SingleReferenceIsValid(t *testing.T) { diff --git a/rules_no_undefined_variables_test.go b/rules_no_undefined_variables_test.go index b2039a28..db466f75 100644 --- a/rules_no_undefined_variables_test.go +++ b/rules_no_undefined_variables_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_NoUndefinedVariables_AllVariablesDefined(t *testing.T) { diff --git a/rules_no_unused_fragments_test.go b/rules_no_unused_fragments_test.go index a1788a10..5bd09051 100644 --- a/rules_no_unused_fragments_test.go +++ b/rules_no_unused_fragments_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_NoUnusedFragments_AllFragmentNamesAreUsed(t *testing.T) { diff --git a/rules_no_unused_variables_test.go b/rules_no_unused_variables_test.go index 747ae62f..d3bcdae4 100644 --- a/rules_no_unused_variables_test.go +++ b/rules_no_unused_variables_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_NoUnusedVariables_UsesAllVariables(t *testing.T) { diff --git a/rules_overlapping_fields_can_be_merged_test.go b/rules_overlapping_fields_can_be_merged_test.go index 32693403..755c8bbe 100644 --- a/rules_overlapping_fields_can_be_merged_test.go +++ b/rules_overlapping_fields_can_be_merged_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_OverlappingFieldsCanBeMerged_UniqueFields(t *testing.T) { diff --git a/rules_possible_fragment_spreads_test.go b/rules_possible_fragment_spreads_test.go index 9e739fa8..088548c3 100644 --- a/rules_possible_fragment_spreads_test.go +++ b/rules_possible_fragment_spreads_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_PossibleFragmentSpreads_OfTheSameObject(t *testing.T) { diff --git a/rules_provided_non_null_arguments_test.go b/rules_provided_non_null_arguments_test.go index 6db35b0b..bb639045 100644 --- a/rules_provided_non_null_arguments_test.go +++ b/rules_provided_non_null_arguments_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_ProvidedNonNullArguments_IgnoresUnknownArguments(t *testing.T) { diff --git a/rules_scalar_leafs_test.go b/rules_scalar_leafs_test.go index 9dcd45c4..8c3f296c 100644 --- a/rules_scalar_leafs_test.go +++ b/rules_scalar_leafs_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_ScalarLeafs_ValidScalarSelection(t *testing.T) { diff --git a/rules_unique_argument_names_test.go b/rules_unique_argument_names_test.go index d22de69c..2c111b80 100644 --- a/rules_unique_argument_names_test.go +++ b/rules_unique_argument_names_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_UniqueArgumentNames_NoArgumentsOnField(t *testing.T) { diff --git a/rules_unique_fragment_names_test.go b/rules_unique_fragment_names_test.go index f6511b7f..5cacd5e9 100644 --- a/rules_unique_fragment_names_test.go +++ b/rules_unique_fragment_names_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_UniqueFragmentNames_NoFragments(t *testing.T) { diff --git a/rules_unique_operation_names_test.go b/rules_unique_operation_names_test.go index bbc52e27..44e59b60 100644 --- a/rules_unique_operation_names_test.go +++ b/rules_unique_operation_names_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_UniqueOperationNames_NoOperations(t *testing.T) { diff --git a/rules_variables_in_allowed_position_test.go b/rules_variables_in_allowed_position_test.go index 660ab5d2..83ee2aa7 100644 --- a/rules_variables_in_allowed_position_test.go +++ b/rules_variables_in_allowed_position_test.go @@ -4,8 +4,8 @@ import ( "testing" "github.com/graphql-go/graphql" - "github.com/graphql-go/graphql/gqlerrors" - "github.com/graphql-go/graphql/testutil" + "github.com/graphql-go/graphql/gqlerrors" + "github.com/graphql-go/graphql/testutil" ) func TestValidate_VariablesInAllowedPosition_BooleanToBoolean(t *testing.T) { From 49b0daba8e4532fe7e0393e00a89870f09ea6c20 Mon Sep 17 00:00:00 2001 From: Hafiz Ismail Date: Wed, 18 Nov 2015 22:01:40 +0800 Subject: [PATCH 32/41] Added missing rule tests - Re-checked the number of tests against `graphql-js` to ensure that all tests have been ported --- rules_arguments_of_correct_type_test.go | 67 +++++++++++++++++++- rules_default_values_of_correct_type_test.go | 3 - rules_fragments_on_composite_types_test.go | 1 - rules_known_directives_rule_test.go | 12 ++++ rules_lone_anonymous_operation_rule_test.go | 1 - rules_no_fragment_cycles_test.go | 15 ++++- rules_no_undefined_variables_test.go | 6 -- rules_no_unused_fragments_test.go | 2 - rules_possible_fragment_spreads_test.go | 6 +- rules_provided_non_null_arguments_test.go | 8 +-- rules_scalar_leafs_test.go | 2 +- 11 files changed, 98 insertions(+), 25 deletions(-) diff --git a/rules_arguments_of_correct_type_test.go b/rules_arguments_of_correct_type_test.go index c48e45aa..a89edbf3 100644 --- a/rules_arguments_of_correct_type_test.go +++ b/rules_arguments_of_correct_type_test.go @@ -142,6 +142,21 @@ func TestValidate_ArgValuesOfCorrectType_InvalidStringValues_UnquotedStringIntoS }) } +func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_StringIntoInt(t *testing.T) { + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + intArgField(intArg: "3") + } + } + `, + []gqlerrors.FormattedError{ + testutil.RuleError( + `Argument "intArg" expected type "Int" but got: "3".`, + 4, 33, + ), + }) +} func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_BigIntIntoInt(t *testing.T) { testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { @@ -203,6 +218,52 @@ func TestValidate_ArgValuesOfCorrectType_InvalidIntValues_FloatIntoInt(t *testin }) } +func TestValidate_ArgValuesOfCorrectType_InvalidFloatValues_StringIntoFloat(t *testing.T) { + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + floatArgField(floatArg: "3.333") + } + } + `, + []gqlerrors.FormattedError{ + testutil.RuleError( + `Argument "floatArg" expected type "Float" but got: "3.333".`, + 4, 37, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidFloatValues_BooleanIntoFloat(t *testing.T) { + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + floatArgField(floatArg: true) + } + } + `, + []gqlerrors.FormattedError{ + testutil.RuleError( + `Argument "floatArg" expected type "Float" but got: true.`, + 4, 37, + ), + }) +} +func TestValidate_ArgValuesOfCorrectType_InvalidFloatValues_UnquotedIntoFloat(t *testing.T) { + testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` + { + complicatedArgs { + floatArgField(floatArg: FOO) + } + } + `, + []gqlerrors.FormattedError{ + testutil.RuleError( + `Argument "floatArg" expected type "Float" but got: FOO.`, + 4, 37, + ), + }) +} + func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_IntIntoBoolean(t *testing.T) { testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { @@ -264,7 +325,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidBooleanValues_UnquotedStringInto }) } -func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_FloatIntoID(t *testing.T) { +func TestValidate_ArgValuesOfCorrectType_InvalidIDValue_FloatIntoID(t *testing.T) { testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { @@ -279,7 +340,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_FloatIntoID(t *testing. ), }) } -func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_BooleanIntoID(t *testing.T) { +func TestValidate_ArgValuesOfCorrectType_InvalidIDValue_BooleanIntoID(t *testing.T) { testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { @@ -294,7 +355,7 @@ func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_BooleanIntoID(t *testin ), }) } -func TestValidate_ArgValuesOfCorrectType_InvalidIDValues_UnquotedIntoID(t *testing.T) { +func TestValidate_ArgValuesOfCorrectType_InvalidIDValue_UnquotedIntoID(t *testing.T) { testutil.ExpectFailsRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { diff --git a/rules_default_values_of_correct_type_test.go b/rules_default_values_of_correct_type_test.go index f5e84dc8..8ef76210 100644 --- a/rules_default_values_of_correct_type_test.go +++ b/rules_default_values_of_correct_type_test.go @@ -33,7 +33,6 @@ func TestValidate_VariableDefaultValuesOfCorrectType_VariablesWithValidDefaultVa } `) } - func TestValidate_VariableDefaultValuesOfCorrectType_NoRequiredVariablesWithDefaultValues(t *testing.T) { testutil.ExpectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` query UnreachableDefaultValues($a: Int! = 3, $b: String! = "default") { @@ -69,7 +68,6 @@ func TestValidate_VariableDefaultValuesOfCorrectType_VariablesWithInvalidDefault testutil.RuleError(`Variable "$c" of type "ComplexInput" has invalid default value: "notverycomplex".`, 5, 28), }) } - func TestValidate_VariableDefaultValuesOfCorrectType_ComplexVariablesMissingRequiredField(t *testing.T) { testutil.ExpectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` query MissingRequiredField($a: ComplexInput = {intField: 3}) { @@ -80,7 +78,6 @@ func TestValidate_VariableDefaultValuesOfCorrectType_ComplexVariablesMissingRequ testutil.RuleError(`Variable "$a" of type "ComplexInput" has invalid default value: {intField: 3}.`, 2, 53), }) } - func TestValidate_VariableDefaultValuesOfCorrectType_ListVariablesWithInvalidItem(t *testing.T) { testutil.ExpectFailsRule(t, graphql.DefaultValuesOfCorrectTypeRule, ` query InvalidItem($a: [String] = ["one", 2]) { diff --git a/rules_fragments_on_composite_types_test.go b/rules_fragments_on_composite_types_test.go index 34e900c2..31fbf08b 100644 --- a/rules_fragments_on_composite_types_test.go +++ b/rules_fragments_on_composite_types_test.go @@ -38,7 +38,6 @@ func TestValidate_FragmentsOnCompositeTypes_UnionIsValidFragmentType(t *testing. } `) } - func TestValidate_FragmentsOnCompositeTypes_ScalarIsInvalidFragmentType(t *testing.T) { testutil.ExpectFailsRule(t, graphql.FragmentsOnCompositeTypesRule, ` fragment scalarFragment on Boolean { diff --git a/rules_known_directives_rule_test.go b/rules_known_directives_rule_test.go index 2e4f2acf..0ece1888 100644 --- a/rules_known_directives_rule_test.go +++ b/rules_known_directives_rule_test.go @@ -20,6 +20,18 @@ func TestValidate_KnownDirectives_WithNoDirectives(t *testing.T) { } `) } +func TestValidate_KnownDirectives_WithKnownDirective(t *testing.T) { + testutil.ExpectPassesRule(t, graphql.KnownDirectivesRule, ` + { + dog @include(if: true) { + name + } + human @skip(if: false) { + name + } + } + `) +} func TestValidate_KnownDirectives_WithUnknownDirective(t *testing.T) { testutil.ExpectFailsRule(t, graphql.KnownDirectivesRule, ` { diff --git a/rules_lone_anonymous_operation_rule_test.go b/rules_lone_anonymous_operation_rule_test.go index 2f515130..cefaff64 100644 --- a/rules_lone_anonymous_operation_rule_test.go +++ b/rules_lone_anonymous_operation_rule_test.go @@ -43,7 +43,6 @@ func TestValidate_AnonymousOperationMustBeAlone_AnonOperationWithFragment(t *tes } `) } - func TestValidate_AnonymousOperationMustBeAlone_MultipleAnonOperations(t *testing.T) { testutil.ExpectFailsRule(t, graphql.LoneAnonymousOperationRule, ` { diff --git a/rules_no_fragment_cycles_test.go b/rules_no_fragment_cycles_test.go index 32b0a0a1..0eabdb77 100644 --- a/rules_no_fragment_cycles_test.go +++ b/rules_no_fragment_cycles_test.go @@ -47,6 +47,7 @@ func TestValidate_NoCircularFragmentSpreads_SpreadingRecursivelyWithinFieldFails testutil.RuleError(`Cannot spread fragment "fragA" within itself.`, 2, 45), }) } + func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectly(t *testing.T) { testutil.ExpectFailsRule(t, graphql.NoFragmentCyclesRule, ` fragment fragA on Dog { ...fragA } @@ -65,7 +66,8 @@ func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectlyWithinInlin testutil.RuleError(`Cannot spread fragment "fragA" within itself.`, 4, 11), }) } -func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectlyMultiple(t *testing.T) { + +func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfIndirectly(t *testing.T) { testutil.ExpectFailsRule(t, graphql.NoFragmentCyclesRule, ` fragment fragA on Dog { ...fragB } fragment fragB on Dog { ...fragA } @@ -73,7 +75,15 @@ func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectlyMultiple(t testutil.RuleError(`Cannot spread fragment "fragA" within itself via fragB.`, 2, 31, 3, 31), }) } -func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectlyWithinInlineFragmentMultiple(t *testing.T) { +func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfIndirectlyReportsOppositeOrder(t *testing.T) { + testutil.ExpectFailsRule(t, graphql.NoFragmentCyclesRule, ` + fragment fragB on Dog { ...fragA } + fragment fragA on Dog { ...fragB } + `, []gqlerrors.FormattedError{ + testutil.RuleError(`Cannot spread fragment "fragB" within itself via fragA.`, 2, 31, 3, 31), + }) +} +func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfIndirectlyWithinInlineFragment(t *testing.T) { testutil.ExpectFailsRule(t, graphql.NoFragmentCyclesRule, ` fragment fragA on Pet { ... on Dog { @@ -89,6 +99,7 @@ func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDirectlyWithinInlin testutil.RuleError(`Cannot spread fragment "fragA" within itself via fragB.`, 4, 11, 9, 11), }) } + func TestValidate_NoCircularFragmentSpreads_NoSpreadingItselfDeeply(t *testing.T) { testutil.ExpectFailsRule(t, graphql.NoFragmentCyclesRule, ` fragment fragA on Dog { ...fragB } diff --git a/rules_no_undefined_variables_test.go b/rules_no_undefined_variables_test.go index db466f75..64449842 100644 --- a/rules_no_undefined_variables_test.go +++ b/rules_no_undefined_variables_test.go @@ -130,7 +130,6 @@ func TestValidate_NoUndefinedVariables_MultipleVariablesNotDefined(t *testing.T) testutil.RuleError(`Variable "$c" is not defined.`, 3, 32), }) } - func TestValidate_NoUndefinedVariables_VariableInFragmentNotDefinedByUnnamedQuery(t *testing.T) { testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` { @@ -143,7 +142,6 @@ func TestValidate_NoUndefinedVariables_VariableInFragmentNotDefinedByUnnamedQuer testutil.RuleError(`Variable "$a" is not defined.`, 6, 18), }) } - func TestValidate_NoUndefinedVariables_VariableInFragmentNotDefinedByOperation(t *testing.T) { testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($a: String, $b: String) { @@ -166,7 +164,6 @@ func TestValidate_NoUndefinedVariables_VariableInFragmentNotDefinedByOperation(t testutil.RuleError(`Variable "$c" is not defined by operation "Foo".`, 16, 18, 2, 7), }) } - func TestValidate_NoUndefinedVariables_MultipleVariablesInFragmentsNotDefined(t *testing.T) { testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($b: String) { @@ -190,7 +187,6 @@ func TestValidate_NoUndefinedVariables_MultipleVariablesInFragmentsNotDefined(t testutil.RuleError(`Variable "$c" is not defined by operation "Foo".`, 16, 18, 2, 7), }) } - func TestValidate_NoUndefinedVariables_SingleVariableInFragmentNotDefinedByMultipleOperations(t *testing.T) { testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($a: String) { @@ -207,7 +203,6 @@ func TestValidate_NoUndefinedVariables_SingleVariableInFragmentNotDefinedByMulti testutil.RuleError(`Variable "$b" is not defined by operation "Bar".`, 9, 25, 5, 7), }) } - func TestValidate_NoUndefinedVariables_VariablesInFragmentNotDefinedByMultipleOperations(t *testing.T) { testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($b: String) { @@ -243,7 +238,6 @@ func TestValidate_NoUndefinedVariables_VariableInFragmentUsedByOtherOperation(t testutil.RuleError(`Variable "$b" is not defined by operation "Bar".`, 12, 18, 5, 7), }) } - func TestValidate_NoUndefinedVariables_VaMultipleUndefinedVariablesProduceMultipleErrors(t *testing.T) { testutil.ExpectFailsRule(t, graphql.NoUndefinedVariablesRule, ` query Foo($b: String) { diff --git a/rules_no_unused_fragments_test.go b/rules_no_unused_fragments_test.go index 5bd09051..47f70ad3 100644 --- a/rules_no_unused_fragments_test.go +++ b/rules_no_unused_fragments_test.go @@ -87,7 +87,6 @@ func TestValidate_NoUnusedFragments_ContainsUnknownFragments(t *testing.T) { testutil.RuleError(`Fragment "Unused2" is never used.`, 25, 7), }) } - func TestValidate_NoUnusedFragments_ContainsUnknownFragmentsWithRefCycle(t *testing.T) { testutil.ExpectFailsRule(t, graphql.NoUnusedFragmentsRule, ` query Foo { @@ -123,7 +122,6 @@ func TestValidate_NoUnusedFragments_ContainsUnknownFragmentsWithRefCycle(t *test testutil.RuleError(`Fragment "Unused2" is never used.`, 26, 7), }) } - func TestValidate_NoUnusedFragments_ContainsUnknownAndUndefFragments(t *testing.T) { testutil.ExpectFailsRule(t, graphql.NoUnusedFragmentsRule, ` query Foo { diff --git a/rules_possible_fragment_spreads_test.go b/rules_possible_fragment_spreads_test.go index 088548c3..9c0dff54 100644 --- a/rules_possible_fragment_spreads_test.go +++ b/rules_possible_fragment_spreads_test.go @@ -31,6 +31,7 @@ func TestValidate_PossibleFragmentSpreads_ObjectIntoContainingUnion(t *testing.T fragment dogFragment on Dog { barkVolume } `) } + func TestValidate_PossibleFragmentSpreads_UnionIntoContainedObject(t *testing.T) { testutil.ExpectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment unionWithinObject on Dog { ...catOrDogFragment } @@ -49,6 +50,7 @@ func TestValidate_PossibleFragmentSpreads_UnionIntoOverlappingUnion(t *testing.T fragment catOrDogFragment on CatOrDog { __typename } `) } + func TestValidate_PossibleFragmentSpreads_InterfaceIntoImplementedObject(t *testing.T) { testutil.ExpectPassesRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment interfaceWithinObject on Dog { ...petFragment } @@ -81,7 +83,6 @@ func TestValidate_PossibleFragmentSpreads_DifferentObjectIntoObject(t *testing.T `type "Cat" can never be of type "Dog".`, 2, 51), }) } - func TestValidate_PossibleFragmentSpreads_DifferentObjectIntoObjectInInlineFragment(t *testing.T) { testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidObjectWithinObjectAnon on Cat { @@ -92,6 +93,7 @@ func TestValidate_PossibleFragmentSpreads_DifferentObjectIntoObjectInInlineFragm `type "Cat" can never be of type "Dog".`, 3, 9), }) } + func TestValidate_PossibleFragmentSpreads_ObjectIntoNotImplementingInterface(t *testing.T) { testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidObjectWithinInterface on Pet { ...humanFragment } @@ -110,6 +112,7 @@ func TestValidate_PossibleFragmentSpreads_ObjectIntoNotContainingUnion(t *testin `type "CatOrDog" can never be of type "Human".`, 2, 55), }) } + func TestValidate_PossibleFragmentSpreads_UnionIntoNotContainedObject(t *testing.T) { testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidUnionWithinObject on Human { ...catOrDogFragment } @@ -128,7 +131,6 @@ func TestValidate_PossibleFragmentSpreads_UnionIntoNonOverlappingInterface(t *te `type "Pet" can never be of type "HumanOrAlien".`, 2, 53), }) } - func TestValidate_PossibleFragmentSpreads_UnionIntoNonOverlappingUnion(t *testing.T) { testutil.ExpectFailsRule(t, graphql.PossibleFragmentSpreadsRule, ` fragment invalidUnionWithinUnion on CatOrDog { ...humanOrAlienFragment } diff --git a/rules_provided_non_null_arguments_test.go b/rules_provided_non_null_arguments_test.go index bb639045..fed6c008 100644 --- a/rules_provided_non_null_arguments_test.go +++ b/rules_provided_non_null_arguments_test.go @@ -17,6 +17,7 @@ func TestValidate_ProvidedNonNullArguments_IgnoresUnknownArguments(t *testing.T) } `) } + func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_ArgOnOptionalArg(t *testing.T) { testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { @@ -107,6 +108,7 @@ func TestValidate_ProvidedNonNullArguments_ValidNonNullableValue_AllReqsAndOptsO } `) } + func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_MissingOneNonNullableArgument(t *testing.T) { testutil.ExpectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` { @@ -118,7 +120,6 @@ func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_MissingOneNon testutil.RuleError(`Field "multipleReqs" argument "req1" of type "Int!" is required but not provided.`, 4, 13), }) } - func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_MissingMultipleNonNullableArguments(t *testing.T) { testutil.ExpectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` { @@ -131,7 +132,6 @@ func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_MissingMultip testutil.RuleError(`Field "multipleReqs" argument "req2" of type "Int!" is required but not provided.`, 4, 13), }) } - func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_IncorrectValueAndMissingArgument(t *testing.T) { testutil.ExpectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` { @@ -151,7 +151,7 @@ func TestValidate_ProvidedNonNullArguments_DirectiveArguments_IgnoresUnknownDire } `) } -func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_WithDirectivesOfValidTypes(t *testing.T) { +func TestValidate_ProvidedNonNullArguments_DirectiveArguments_WithDirectivesOfValidTypes(t *testing.T) { testutil.ExpectPassesRule(t, graphql.ProvidedNonNullArgumentsRule, ` { dog @include(if: true) { @@ -163,7 +163,7 @@ func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_WithDirective } `) } -func TestValidate_ProvidedNonNullArguments_InvalidNonNullableValue_WithDirectiveWithMissingTypes(t *testing.T) { +func TestValidate_ProvidedNonNullArguments_DirectiveArguments_WithDirectiveWithMissingTypes(t *testing.T) { testutil.ExpectFailsRule(t, graphql.ProvidedNonNullArgumentsRule, ` { dog @include { diff --git a/rules_scalar_leafs_test.go b/rules_scalar_leafs_test.go index 8c3f296c..09729952 100644 --- a/rules_scalar_leafs_test.go +++ b/rules_scalar_leafs_test.go @@ -24,7 +24,6 @@ func TestValidate_ScalarLeafs_ObjectTypeMissingSelection(t *testing.T) { testutil.RuleError(`Field "human" of type "Human" must have a sub selection.`, 3, 9), }) } - func TestValidate_ScalarLeafs_InterfaceTypeMissingSelection(t *testing.T) { testutil.ExpectFailsRule(t, graphql.ScalarLeafsRule, ` { @@ -41,6 +40,7 @@ func TestValidate_ScalarLeafs_ValidScalarSelectionWithArgs(t *testing.T) { } `) } + func TestValidate_ScalarLeafs_ScalarSelectionNotAllowedOnBoolean(t *testing.T) { testutil.ExpectFailsRule(t, graphql.ScalarLeafsRule, ` fragment scalarSelectionsNotAllowedOnBoolean on Dog { From 21ee236cd562fffe30d033daa2dca63b79bfa2f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Ram=C3=B3n?= Date: Mon, 23 Nov 2015 19:18:37 -0500 Subject: [PATCH 33/41] updates queries to match `graphql-js` ones - #78 --- rules_arguments_of_correct_type_test.go | 2 +- rules_unique_operation_names_test.go | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rules_arguments_of_correct_type_test.go b/rules_arguments_of_correct_type_test.go index a89edbf3..27a2443b 100644 --- a/rules_arguments_of_correct_type_test.go +++ b/rules_arguments_of_correct_type_test.go @@ -678,7 +678,7 @@ func TestValidate_ArgValuesOfCorrectType_ValidInputObjectValue_PartialObject_Inc testutil.ExpectPassesRule(t, graphql.ArgumentsOfCorrectTypeRule, ` { complicatedArgs { - complexArgField(complexArg: { requiredField: false }) + complexArgField(complexArg: { requiredField: false, intField: 4 }) } } `) diff --git a/rules_unique_operation_names_test.go b/rules_unique_operation_names_test.go index 44e59b60..7004819e 100644 --- a/rules_unique_operation_names_test.go +++ b/rules_unique_operation_names_test.go @@ -54,10 +54,9 @@ func TestValidate_UniqueOperationNames_MultipleOperationsOfDifferentTypes(t *tes func TestValidate_UniqueOperationNames_FragmentAndOperationNamedTheSame(t *testing.T) { testutil.ExpectPassesRule(t, graphql.UniqueOperationNamesRule, ` query Foo { - field + ...Foo } - - mutation Bar { + fragment Foo on Type { field } `) From 149040dd6ad218d470821a36838ad5d58c6c8987 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Ram=C3=B3n?= Date: Wed, 25 Nov 2015 18:22:23 -0500 Subject: [PATCH 34/41] updates on FieldResolveFn to allow return optional error - #44 --- definition.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/definition.go b/definition.go index 657a5edc..1d226fcc 100644 --- a/definition.go +++ b/definition.go @@ -540,7 +540,7 @@ type ResolveParams struct { } // TODO: relook at FieldResolveFn params -type FieldResolveFn func(p ResolveParams) interface{} +type FieldResolveFn func(p ResolveParams) (interface{}, error) type ResolveInfo struct { FieldName string From 67d621ac70a90e8f4e0be7d0c0f1c1b5c869cd5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Ram=C3=B3n?= Date: Wed, 25 Nov 2015 18:23:57 -0500 Subject: [PATCH 35/41] updates to match new FieldResolveFn returning params - #44 --- abstract_test.go | 70 +++++++++---------- enum_type_test.go | 24 +++---- examples/hello-world/main.go | 4 +- examples/http/main.go | 6 +- executor.go | 18 ++--- executor_schema_test.go | 14 ++-- executor_test.go | 44 ++++++------ graphql_test.go | 4 +- introspection.go | 126 +++++++++++++++++------------------ introspection_test.go | 4 +- lists_test.go | 4 +- mutations_test.go | 16 ++--- testutil/testutil.go | 72 ++++++++++---------- variables_test.go | 8 +-- 14 files changed, 207 insertions(+), 207 deletions(-) diff --git a/abstract_test.go b/abstract_test.go index a0640cf8..37f2eb3d 100644 --- a/abstract_test.go +++ b/abstract_test.go @@ -48,20 +48,20 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if dog, ok := p.Source.(*testDog); ok { - return dog.Name + return dog.Name, nil } - return nil + return nil, nil }, }, "woofs": &graphql.Field{ Type: graphql.Boolean, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if dog, ok := p.Source.(*testDog); ok { - return dog.Woofs + return dog.Woofs, nil } - return nil + return nil, nil }, }, }, @@ -79,20 +79,20 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if cat, ok := p.Source.(*testCat); ok { - return cat.Name + return cat.Name, nil } - return nil + return nil, nil }, }, "meows": &graphql.Field{ Type: graphql.Boolean, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if cat, ok := p.Source.(*testCat); ok { - return cat.Meows + return cat.Meows, nil } - return nil + return nil, nil }, }, }, @@ -103,11 +103,11 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForInterface(t *testing.T) { Fields: graphql.Fields{ "pets": &graphql.Field{ Type: graphql.NewList(petType), - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { return []interface{}{ &testDog{"Odie", true}, &testCat{"Garfield", false}, - } + }, nil }, }, }, @@ -202,11 +202,11 @@ func TestIsTypeOfUsedToResolveRuntimeTypeForUnion(t *testing.T) { Fields: graphql.Fields{ "pets": &graphql.Field{ Type: graphql.NewList(petType), - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { return []interface{}{ &testDog{"Odie", true}, &testCat{"Garfield", false}, - } + }, nil }, }, }, @@ -288,11 +288,11 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(*testHuman); ok { - return human.Name + return human.Name, nil } - return nil + return nil, nil }, }, }, @@ -309,20 +309,20 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if dog, ok := p.Source.(*testDog); ok { - return dog.Name + return dog.Name, nil } - return nil + return nil, nil }, }, "woofs": &graphql.Field{ Type: graphql.Boolean, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if dog, ok := p.Source.(*testDog); ok { - return dog.Woofs + return dog.Woofs, nil } - return nil + return nil, nil }, }, }, @@ -339,20 +339,20 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { Fields: graphql.Fields{ "name": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if cat, ok := p.Source.(*testCat); ok { - return cat.Name + return cat.Name, nil } - return nil + return nil, nil }, }, "meows": &graphql.Field{ Type: graphql.Boolean, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if cat, ok := p.Source.(*testCat); ok { - return cat.Meows + return cat.Meows, nil } - return nil + return nil, nil }, }, }, @@ -363,12 +363,12 @@ func TestResolveTypeOnInterfaceYieldsUsefulError(t *testing.T) { Fields: graphql.Fields{ "pets": &graphql.Field{ Type: graphql.NewList(petType), - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { return []interface{}{ &testDog{"Odie", true}, &testCat{"Garfield", false}, &testHuman{"Jon"}, - } + }, nil }, }, }, @@ -480,12 +480,12 @@ func TestResolveTypeOnUnionYieldsUsefulError(t *testing.T) { Fields: graphql.Fields{ "pets": &graphql.Field{ Type: graphql.NewList(petType), - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { return []interface{}{ &testDog{"Odie", true}, &testCat{"Garfield", false}, &testHuman{"Jon"}, - } + }, nil }, }, }, diff --git a/enum_type_test.go b/enum_type_test.go index 1db322ce..f4bcce99 100644 --- a/enum_type_test.go +++ b/enum_type_test.go @@ -39,17 +39,17 @@ var enumTypeTestQueryType = graphql.NewObject(graphql.ObjectConfig{ Type: graphql.String, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if fromInt, ok := p.Args["fromInt"]; ok { - return fromInt + return fromInt, nil } if fromString, ok := p.Args["fromString"]; ok { - return fromString + return fromString, nil } if fromEnum, ok := p.Args["fromEnum"]; ok { - return fromEnum + return fromEnum, nil } - return nil + return nil, nil }, }, "colorInt": &graphql.Field{ @@ -62,14 +62,14 @@ var enumTypeTestQueryType = graphql.NewObject(graphql.ObjectConfig{ Type: graphql.Int, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if fromInt, ok := p.Args["fromInt"]; ok { - return fromInt + return fromInt, nil } if fromEnum, ok := p.Args["fromEnum"]; ok { - return fromEnum + return fromEnum, nil } - return nil + return nil, nil }, }, }, @@ -84,11 +84,11 @@ var enumTypeTestMutationType = graphql.NewObject(graphql.ObjectConfig{ Type: enumTypeTestColorType, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if color, ok := p.Args["color"]; ok { - return color + return color, nil } - return nil + return nil, nil }, }, }, diff --git a/examples/hello-world/main.go b/examples/hello-world/main.go index dda06cd3..d014e942 100644 --- a/examples/hello-world/main.go +++ b/examples/hello-world/main.go @@ -13,8 +13,8 @@ func main() { fields := graphql.Fields{ "hello": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { - return "world" + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "world", nil }, }, } diff --git a/examples/http/main.go b/examples/http/main.go index 3af79bd7..26d10768 100644 --- a/examples/http/main.go +++ b/examples/http/main.go @@ -56,12 +56,12 @@ var queryType = graphql.NewObject( Type: graphql.String, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { idQuery, isOK := p.Args["id"].(string) if isOK { - return data[idQuery] + return data[idQuery], nil } - return nil + return nil, nil }, }, }, diff --git a/executor.go b/executor.go index 8f3ab359..49629a4f 100644 --- a/executor.go +++ b/executor.go @@ -498,7 +498,7 @@ func resolveField(eCtx *ExecutionContext, parentType *Object, source interface{} // it is wrapped as a Error with locations. Log this error and return // null if allowed, otherwise throw the error so the parent field can handle // it. - result = resolveFn(ResolveParams{ + result, _ = resolveFn(ResolveParams{ Source: source, Args: args, Info: info, @@ -666,14 +666,14 @@ func completeValue(eCtx *ExecutionContext, returnType Type, fieldASTs []*ast.Fie } -func defaultResolveFn(p ResolveParams) interface{} { +func defaultResolveFn(p ResolveParams) (interface{}, error) { // try to resolve p.Source as a struct first sourceVal := reflect.ValueOf(p.Source) if sourceVal.IsValid() && sourceVal.Type().Kind() == reflect.Ptr { sourceVal = sourceVal.Elem() } if !sourceVal.IsValid() { - return nil + return nil, nil } if sourceVal.Type().Kind() == reflect.Struct { // find field based on struct's json tag @@ -685,7 +685,7 @@ func defaultResolveFn(p ResolveParams) interface{} { typeField := sourceVal.Type().Field(i) // try matching the field name first if typeField.Name == p.Info.FieldName { - return valueField.Interface() + return valueField.Interface(), nil } tag := typeField.Tag jsonTag := tag.Get("json") @@ -696,9 +696,9 @@ func defaultResolveFn(p ResolveParams) interface{} { if jsonOptions[0] != p.Info.FieldName { continue } - return valueField.Interface() + return valueField.Interface(), nil } - return nil + return nil, nil } // try p.Source as a map[string]interface @@ -709,14 +709,14 @@ func defaultResolveFn(p ResolveParams) interface{} { // try type casting the func to the most basic func signature // for more complex signatures, user have to define ResolveFn if propertyFn, ok := property.(func() interface{}); ok { - return propertyFn() + return propertyFn(), nil } } - return property + return property, nil } // last resort, return nil - return nil + return nil, nil } /** diff --git a/executor_schema_test.go b/executor_schema_test.go index a127310a..b39c4c3a 100644 --- a/executor_schema_test.go +++ b/executor_schema_test.go @@ -106,13 +106,13 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { Type: graphql.Int, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if author, ok := p.Source.(*testAuthor); ok { width := fmt.Sprintf("%v", p.Args["width"]) height := fmt.Sprintf("%v", p.Args["height"]) - return author.Pic(width, height) + return author.Pic(width, height), nil } - return nil + return nil, nil }, }, "recentArticle": &graphql.Field{}, @@ -156,14 +156,14 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { Type: graphql.ID, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { id := p.Args["id"] - return article(id) + return article(id), nil }, }, "feed": &graphql.Field{ Type: graphql.NewList(blogArticle), - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { return []*testArticle{ article(1), article(2), @@ -175,7 +175,7 @@ func TestExecutesUsingAComplexSchema(t *testing.T) { article(8), article(9), article(10), - } + }, nil }, }, }, diff --git a/executor_test.go b/executor_test.go index 8707b9e9..031f5836 100644 --- a/executor_test.go +++ b/executor_test.go @@ -103,18 +103,18 @@ func TestExecutesArbitraryCode(t *testing.T) { } // Schema Definitions - picResolverFn := func(p graphql.ResolveParams) interface{} { + picResolverFn := func(p graphql.ResolveParams) (interface{}, error) { // get and type assert ResolveFn for this field picResolver, ok := p.Source.(map[string]interface{})["pic"].(func(size int) string) if !ok { - return nil + return nil, nil } // get and type assert argument sizeArg, ok := p.Args["size"].(int) if !ok { - return nil + return nil, nil } - return picResolver(sizeArg) + return picResolver(sizeArg), nil } dataType := graphql.NewObject(graphql.ObjectConfig{ Name: "DataType", @@ -244,28 +244,28 @@ func TestMergesParallelFragments(t *testing.T) { Fields: graphql.Fields{ "a": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { - return "Apple" + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "Apple", nil }, }, "b": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { - return "Banana" + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "Banana", nil }, }, "c": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { - return "Cherry" + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "Cherry", nil }, }, }, }) deepTypeFieldConfig := &graphql.Field{ Type: typeObjectType, - Resolve: func(p graphql.ResolveParams) interface{} { - return p.Source + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return p.Source, nil }, } typeObjectType.AddFieldConfig("deep", deepTypeFieldConfig) @@ -312,9 +312,9 @@ func TestThreadsContextCorrectly(t *testing.T) { Fields: graphql.Fields{ "a": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { resolvedContext = p.Source.(map[string]interface{}) - return resolvedContext + return resolvedContext, nil }, }, }, @@ -368,9 +368,9 @@ func TestCorrectlyThreadsArguments(t *testing.T) { }, }, Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { resolvedArgs = p.Args - return resolvedArgs + return resolvedArgs, nil }, }, }, @@ -944,9 +944,9 @@ func TestDoesNotIncludeArgumentsThatWereNotSet(t *testing.T) { Type: graphql.Int, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { args, _ := json.Marshal(p.Args) - return string(args) + return string(args), nil }, }, }, @@ -1019,8 +1019,8 @@ func TestFailsWhenAnIsTypeOfCheckIsNotMet(t *testing.T) { Fields: graphql.Fields{ "value": &graphql.Field{ Type: graphql.String, - Resolve: func(p graphql.ResolveParams) interface{} { - return p.Source.(testSpecialType).Value + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return p.Source.(testSpecialType).Value, nil }, }, }, @@ -1031,8 +1031,8 @@ func TestFailsWhenAnIsTypeOfCheckIsNotMet(t *testing.T) { Fields: graphql.Fields{ "specials": &graphql.Field{ Type: graphql.NewList(specialType), - Resolve: func(p graphql.ResolveParams) interface{} { - return p.Source.(map[string]interface{})["specials"] + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return p.Source.(map[string]interface{})["specials"], nil }, }, }, diff --git a/graphql_test.go b/graphql_test.go index fc0473d5..07c3e508 100644 --- a/graphql_test.go +++ b/graphql_test.go @@ -94,8 +94,8 @@ func testGraphql(test T, p graphql.Params, t *testing.T) { func TestBasicGraphQLExample(t *testing.T) { // taken from `graphql-js` README - helloFieldResolved := func(p graphql.ResolveParams) interface{} { - return "world" + helloFieldResolved := func(p graphql.ResolveParams) (interface{}, error) { + return "world", nil } schema, err := graphql.NewSchema(graphql.SchemaConfig{ diff --git a/introspection.go b/introspection.go index dd91e5d2..944cdf77 100644 --- a/introspection.go +++ b/introspection.go @@ -86,24 +86,24 @@ func init() { Fields: Fields{ "kind": &Field{ Type: NewNonNull(__TypeKind), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { switch p.Source.(type) { case *Scalar: - return TypeKindScalar + return TypeKindScalar, nil case *Object: - return TypeKindObject + return TypeKindObject, nil case *Interface: - return TypeKindInterface + return TypeKindInterface, nil case *Union: - return TypeKindUnion + return TypeKindUnion, nil case *Enum: - return TypeKindEnum + return TypeKindEnum, nil case *InputObject: - return TypeKindInputObject + return TypeKindInputObject, nil case *List: - return TypeKindList + return TypeKindList, nil case *NonNull: - return TypeKindNonNull + return TypeKindNonNull, nil } panic(fmt.Sprintf("Unknown kind of type: %v", p.Source)) }, @@ -137,22 +137,22 @@ func init() { }, "defaultValue": &Field{ Type: String, - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if inputVal, ok := p.Source.(*Argument); ok { if inputVal.DefaultValue == nil { - return nil + return nil, nil } astVal := astFromValue(inputVal.DefaultValue, inputVal) - return printer.Print(astVal) + return printer.Print(astVal), nil } if inputVal, ok := p.Source.(*InputObjectField); ok { if inputVal.DefaultValue == nil { - return nil + return nil, nil } astVal := astFromValue(inputVal.DefaultValue, inputVal) - return printer.Print(astVal) + return printer.Print(astVal), nil } - return nil + return nil, nil }, }, }, @@ -169,11 +169,11 @@ func init() { }, "args": &Field{ Type: NewNonNull(NewList(NewNonNull(__InputValue))), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if field, ok := p.Source.(*FieldDefinition); ok { - return field.Args + return field.Args, nil } - return []interface{}{} + return []interface{}{}, nil }, }, "type": &Field{ @@ -181,11 +181,11 @@ func init() { }, "isDeprecated": &Field{ Type: NewNonNull(Boolean), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if field, ok := p.Source.(*FieldDefinition); ok { - return (field.DeprecationReason != "") + return (field.DeprecationReason != ""), nil } - return false + return false, nil }, }, "deprecationReason": &Field{ @@ -232,38 +232,38 @@ mutation operations.`, Type: NewNonNull(NewList( NewNonNull(__Type), )), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if schema, ok := p.Source.(Schema); ok { results := []Type{} for _, ttype := range schema.TypeMap() { results = append(results, ttype) } - return results + return results, nil } - return []Type{} + return []Type{}, nil }, }, "queryType": &Field{ Description: "The type that query operations will be rooted at.", Type: NewNonNull(__Type), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if schema, ok := p.Source.(Schema); ok { - return schema.QueryType() + return schema.QueryType(), nil } - return nil + return nil, nil }, }, "mutationType": &Field{ Description: `If this server supports mutation, the type that ` + `mutation operations will be rooted at.`, Type: __Type, - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if schema, ok := p.Source.(Schema); ok { if schema.MutationType() != nil { - return schema.MutationType() + return schema.MutationType(), nil } } - return nil + return nil, nil }, }, "directives": &Field{ @@ -271,11 +271,11 @@ mutation operations.`, Type: NewNonNull(NewList( NewNonNull(__Directive), )), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if schema, ok := p.Source.(Schema); ok { - return schema.Directives() + return schema.Directives(), nil } - return nil + return nil, nil }, }, }, @@ -292,11 +292,11 @@ mutation operations.`, }, "isDeprecated": &Field{ Type: NewNonNull(Boolean), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { if field, ok := p.Source.(*EnumValueDefinition); ok { - return (field.DeprecationReason != "") + return (field.DeprecationReason != ""), nil } - return false + return false, nil }, }, "deprecationReason": &Field{ @@ -315,12 +315,12 @@ mutation operations.`, DefaultValue: false, }, }, - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { includeDeprecated, _ := p.Args["includeDeprecated"].(bool) switch ttype := p.Source.(type) { case *Object: if ttype == nil { - return nil + return nil, nil } fields := []*FieldDefinition{} for _, field := range ttype.Fields() { @@ -329,10 +329,10 @@ mutation operations.`, } fields = append(fields, field) } - return fields + return fields, nil case *Interface: if ttype == nil { - return nil + return nil, nil } fields := []*FieldDefinition{} for _, field := range ttype.Fields() { @@ -341,31 +341,31 @@ mutation operations.`, } fields = append(fields, field) } - return fields + return fields, nil } - return nil + return nil, nil }, }) __Type.AddFieldConfig("interfaces", &Field{ Type: NewList(NewNonNull(__Type)), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { switch ttype := p.Source.(type) { case *Object: - return ttype.Interfaces() + return ttype.Interfaces(), nil } - return nil + return nil, nil }, }) __Type.AddFieldConfig("possibleTypes", &Field{ Type: NewList(NewNonNull(__Type)), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { switch ttype := p.Source.(type) { case *Interface: - return ttype.PossibleTypes() + return ttype.PossibleTypes(), nil case *Union: - return ttype.PossibleTypes() + return ttype.PossibleTypes(), nil } - return nil + return nil, nil }, }) __Type.AddFieldConfig("enumValues", &Field{ @@ -376,12 +376,12 @@ mutation operations.`, DefaultValue: false, }, }, - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { includeDeprecated, _ := p.Args["includeDeprecated"].(bool) switch ttype := p.Source.(type) { case *Enum: if includeDeprecated { - return ttype.Values() + return ttype.Values(), nil } values := []*EnumValueDefinition{} for _, value := range ttype.Values() { @@ -390,23 +390,23 @@ mutation operations.`, } values = append(values, value) } - return values + return values, nil } - return nil + return nil, nil }, }) __Type.AddFieldConfig("inputFields", &Field{ Type: NewList(NewNonNull(__InputValue)), - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { switch ttype := p.Source.(type) { case *InputObject: fields := []*InputObjectField{} for _, field := range ttype.Fields() { fields = append(fields, field) } - return fields + return fields, nil } - return nil + return nil, nil }, }) __Type.AddFieldConfig("ofType", &Field{ @@ -423,8 +423,8 @@ mutation operations.`, Type: NewNonNull(__Schema), Description: "Access the current type schema of this server.", Args: []*Argument{}, - Resolve: func(p ResolveParams) interface{} { - return p.Info.Schema + Resolve: func(p ResolveParams) (interface{}, error) { + return p.Info.Schema, nil }, } TypeMetaFieldDef = &FieldDefinition{ @@ -437,12 +437,12 @@ mutation operations.`, Type: NewNonNull(String), }, }, - Resolve: func(p ResolveParams) interface{} { + Resolve: func(p ResolveParams) (interface{}, error) { name, ok := p.Args["name"].(string) if !ok { - return nil + return nil, nil } - return p.Info.Schema.Type(name) + return p.Info.Schema.Type(name), nil }, } @@ -451,8 +451,8 @@ mutation operations.`, Type: NewNonNull(String), Description: "The name of the current Object type at runtime.", Args: []*Argument{}, - Resolve: func(p ResolveParams) interface{} { - return p.Info.ParentType.Name() + Resolve: func(p ResolveParams) (interface{}, error) { + return p.Info.ParentType.Name(), nil }, } diff --git a/introspection_test.go b/introspection_test.go index 1d314e93..b0e785e6 100644 --- a/introspection_test.go +++ b/introspection_test.go @@ -768,8 +768,8 @@ func TestIntrospection_ExecutesAnInputObject(t *testing.T) { Type: testInputObject, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { - return p.Args["complex"] + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return p.Args["complex"], nil }, }, }, diff --git a/lists_test.go b/lists_test.go index 5dad96c3..4bc47cd7 100644 --- a/lists_test.go +++ b/lists_test.go @@ -25,8 +25,8 @@ func checkList(t *testing.T, testType graphql.Type, testData interface{}, expect }) dataType.AddFieldConfig("nest", &graphql.Field{ Type: dataType, - Resolve: func(p graphql.ResolveParams) interface{} { - return data + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return data, nil }, }) diff --git a/mutations_test.go b/mutations_test.go index eb076dcb..0a52d136 100644 --- a/mutations_test.go +++ b/mutations_test.go @@ -66,11 +66,11 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Type: graphql.Int, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { newNumber := 0 obj, _ := p.Source.(*testRoot) newNumber, _ = p.Args["newNumber"].(int) - return obj.ImmediatelyChangeTheNumber(newNumber) + return obj.ImmediatelyChangeTheNumber(newNumber), nil }, }, "promiseToChangeTheNumber": &graphql.Field{ @@ -80,11 +80,11 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Type: graphql.Int, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { newNumber := 0 obj, _ := p.Source.(*testRoot) newNumber, _ = p.Args["newNumber"].(int) - return obj.PromiseToChangeTheNumber(newNumber) + return obj.PromiseToChangeTheNumber(newNumber), nil }, }, "failToChangeTheNumber": &graphql.Field{ @@ -94,11 +94,11 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Type: graphql.Int, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { newNumber := 0 obj, _ := p.Source.(*testRoot) newNumber, _ = p.Args["newNumber"].(int) - return obj.FailToChangeTheNumber(newNumber) + return obj.FailToChangeTheNumber(newNumber), nil }, }, "promiseAndFailToChangeTheNumber": &graphql.Field{ @@ -108,11 +108,11 @@ var mutationsTestSchema, _ = graphql.NewSchema(graphql.SchemaConfig{ Type: graphql.Int, }, }, - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { newNumber := 0 obj, _ := p.Source.(*testRoot) newNumber, _ = p.Args["newNumber"].(int) - return obj.PromiseAndFailToChangeTheNumber(newNumber) + return obj.PromiseAndFailToChangeTheNumber(newNumber), nil }, }, }, diff --git a/testutil/testutil.go b/testutil/testutil.go index 11c0fc06..972ee240 100644 --- a/testutil/testutil.go +++ b/testutil/testutil.go @@ -156,51 +156,51 @@ func init() { "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the human.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { - return human.Id + return human.Id, nil } - return nil + return nil, nil }, }, "name": &graphql.Field{ Type: graphql.String, Description: "The name of the human.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { - return human.Name + return human.Name, nil } - return nil + return nil, nil }, }, "friends": &graphql.Field{ Type: graphql.NewList(characterInterface), Description: "The friends of the human, or an empty list if they have none.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { - return human.Friends + return human.Friends, nil } - return []interface{}{} + return []interface{}{}, nil }, }, "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { - return human.AppearsIn + return human.AppearsIn, nil } - return nil + return nil, nil }, }, "homePlanet": &graphql.Field{ Type: graphql.String, Description: "The home planet of the human, or null if unknown.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if human, ok := p.Source.(StarWarsChar); ok { - return human.HomePlanet + return human.HomePlanet, nil } - return nil + return nil, nil }, }, }, @@ -215,27 +215,27 @@ func init() { "id": &graphql.Field{ Type: graphql.NewNonNull(graphql.String), Description: "The id of the droid.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { - return droid.Id + return droid.Id, nil } - return nil + return nil, nil }, }, "name": &graphql.Field{ Type: graphql.String, Description: "The name of the droid.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { - return droid.Name + return droid.Name, nil } - return nil + return nil, nil }, }, "friends": &graphql.Field{ Type: graphql.NewList(characterInterface), Description: "The friends of the droid, or an empty list if they have none.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { friends := []map[string]interface{}{} for _, friend := range droid.Friends { @@ -244,29 +244,29 @@ func init() { "id": friend.Id, }) } - return droid.Friends + return droid.Friends, nil } - return []interface{}{} + return []interface{}{}, nil }, }, "appearsIn": &graphql.Field{ Type: graphql.NewList(episodeEnum), Description: "Which movies they appear in.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { - return droid.AppearsIn + return droid.AppearsIn, nil } - return nil + return nil, nil }, }, "primaryFunction": &graphql.Field{ Type: graphql.String, Description: "The primary function of the droid.", - Resolve: func(p graphql.ResolveParams) interface{} { + Resolve: func(p graphql.ResolveParams) (interface{}, error) { if droid, ok := p.Source.(StarWarsChar); ok { - return droid.PrimaryFunction + return droid.PrimaryFunction, nil } - return nil + return nil, nil }, }, }, @@ -287,8 +287,8 @@ func init() { Type: episodeEnum, }, }, - Resolve: func(p graphql.ResolveParams) (r interface{}) { - return GetHero(p.Args["episode"]) + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return GetHero(p.Args["episode"]), nil }, }, "human": &graphql.Field{ @@ -299,8 +299,8 @@ func init() { Type: graphql.NewNonNull(graphql.String), }, }, - Resolve: func(p graphql.ResolveParams) (r interface{}) { - return GetHuman(p.Args["id"].(int)) + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return GetHuman(p.Args["id"].(int)), nil }, }, "droid": &graphql.Field{ @@ -311,8 +311,8 @@ func init() { Type: graphql.NewNonNull(graphql.String), }, }, - Resolve: func(p graphql.ResolveParams) (r interface{}) { - return GetDroid(p.Args["id"].(int)) + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return GetDroid(p.Args["id"].(int)), nil }, }, }, diff --git a/variables_test.go b/variables_test.go index cc9126b0..b8e118f2 100644 --- a/variables_test.go +++ b/variables_test.go @@ -53,16 +53,16 @@ var testInputObject *graphql.InputObject = graphql.NewInputObject(graphql.InputO }, }) -func inputResolved(p graphql.ResolveParams) interface{} { +func inputResolved(p graphql.ResolveParams) (interface{}, error) { input, ok := p.Args["input"] if !ok { - return nil + return nil, nil } b, err := json.Marshal(input) if err != nil { - return nil + return nil, nil } - return string(b) + return string(b), nil } var testType *graphql.Object = graphql.NewObject(graphql.ObjectConfig{ From c7e177b6fea52d77f8fe8ffccb489fa5bf91542f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Ram=C3=B3n?= Date: Thu, 26 Nov 2015 02:17:00 -0500 Subject: [PATCH 36/41] handles potential error from FieldResolveFn - #44 --- executor.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/executor.go b/executor.go index 49629a4f..1b34a7ae 100644 --- a/executor.go +++ b/executor.go @@ -498,12 +498,18 @@ func resolveField(eCtx *ExecutionContext, parentType *Object, source interface{} // it is wrapped as a Error with locations. Log this error and return // null if allowed, otherwise throw the error so the parent field can handle // it. - result, _ = resolveFn(ResolveParams{ + var resultError error + + result, resultError = resolveFn(ResolveParams{ Source: source, Args: args, Info: info, }) + if resultError != nil { + panic(gqlerrors.FormatError(resultError)) + } + completed := completeValueCatchingError(eCtx, returnType, fieldASTs, info, result) return completed, resultState } From 4b2b57d7b82aef2ccf95877f160aa1a0c56436c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Ram=C3=B3n?= Date: Thu, 26 Nov 2015 02:38:08 -0500 Subject: [PATCH 37/41] matches new graphql.FieldResolveFn return signature - #44 --- introspection.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/introspection.go b/introspection.go index 944cdf77..0323a23e 100644 --- a/introspection.go +++ b/introspection.go @@ -105,7 +105,7 @@ func init() { case *NonNull: return TypeKindNonNull, nil } - panic(fmt.Sprintf("Unknown kind of type: %v", p.Source)) + return nil, fmt.Errorf("Unknown kind of type: %v", p.Source) }, }, "name": &Field{ From a7990c2dbb48778ae74f9beb252350dbaf855138 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Ram=C3=B3n?= Date: Thu, 26 Nov 2015 02:38:51 -0500 Subject: [PATCH 38/41] adds couple of tests for graphql.FieldResolveFn - #44 adds query and mutation test to check correct returning error from graphql.FieldResolveFn --- definition_test.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/definition_test.go b/definition_test.go index 97a361fa..2f06c15c 100644 --- a/definition_test.go +++ b/definition_test.go @@ -1,6 +1,7 @@ package graphql_test import ( + "errors" "fmt" "reflect" "testing" @@ -66,6 +67,10 @@ var blogArticle = graphql.NewObject(graphql.ObjectConfig{ }, }, }) + +var ErrArticleQuery = errors.New("ErrArticleQuery") +var ErrArticleMutation = errors.New("ErrArticleMutation") + var blogQuery = graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ @@ -76,6 +81,9 @@ var blogQuery = graphql.NewObject(graphql.ObjectConfig{ Type: graphql.String, }, }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return nil, ErrArticleQuery + }, }, "feed": &graphql.Field{ Type: graphql.NewList(blogArticle), @@ -88,6 +96,14 @@ var blogMutation = graphql.NewObject(graphql.ObjectConfig{ Fields: graphql.Fields{ "writeArticle": &graphql.Field{ Type: blogArticle, + Args: graphql.FieldConfigArgument{ + "title": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return nil, ErrArticleMutation + }, }, }, }) @@ -533,3 +549,45 @@ func TestTypeSystem_DefinitionExample_DoesNotMutatePassedFieldDefinitions(t *tes } } + +func TestQuery_FieldResolveFn_AddsErrorsToGraphQLResult(t *testing.T) { + blogSchema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: blogQuery, + Mutation: blogMutation, + }) + if err != nil { + t.Fatalf("unexpected error, got: %v", err) + } + query := "{ article(id:\"1\") { id } }" + result := graphql.Do(graphql.Params{ + Schema: blogSchema, + RequestString: query, + }) + if len(result.Errors) == 0 { + t.Fatal("wrong result, expected errors, got no errors") + } + if result.Errors[0].Error() != ErrArticleQuery.Error() { + t.Fatalf("wrong result, unexpected error, got: %v, expected: %v", result.Errors[0], ErrArticleQuery) + } +} + +func TestMutation_FieldResolveFn_AddsErrorsToGraphQLResult(t *testing.T) { + blogSchema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: blogQuery, + Mutation: blogMutation, + }) + if err != nil { + t.Fatalf("unexpected error, got: %v", err) + } + query := "mutation _ { newArticle: writeArticle(title:\"article title\") { id } }" + result := graphql.Do(graphql.Params{ + Schema: blogSchema, + RequestString: query, + }) + if len(result.Errors) == 0 { + t.Fatal("wrong result, expected errors, got no errors") + } + if result.Errors[0].Error() != ErrArticleMutation.Error() { + t.Fatalf("wrong result, unexpected error, got: %v, expected: %v", result.Errors[0], ErrArticleMutation) + } +} From 5cb69f46fca46c2cde17ad407dee2702f6c29cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Ram=C3=B3n?= Date: Thu, 26 Nov 2015 23:10:21 -0500 Subject: [PATCH 39/41] moves tests to executor test file - #44 executor does handle potential errors for executing graphql.FieldResolveFn --- definition_test.go | 52 ------------- executor_test.go | 185 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 185 insertions(+), 52 deletions(-) diff --git a/definition_test.go b/definition_test.go index 2f06c15c..fb266a33 100644 --- a/definition_test.go +++ b/definition_test.go @@ -1,7 +1,6 @@ package graphql_test import ( - "errors" "fmt" "reflect" "testing" @@ -68,9 +67,6 @@ var blogArticle = graphql.NewObject(graphql.ObjectConfig{ }, }) -var ErrArticleQuery = errors.New("ErrArticleQuery") -var ErrArticleMutation = errors.New("ErrArticleMutation") - var blogQuery = graphql.NewObject(graphql.ObjectConfig{ Name: "Query", Fields: graphql.Fields{ @@ -81,9 +77,6 @@ var blogQuery = graphql.NewObject(graphql.ObjectConfig{ Type: graphql.String, }, }, - Resolve: func(p graphql.ResolveParams) (interface{}, error) { - return nil, ErrArticleQuery - }, }, "feed": &graphql.Field{ Type: graphql.NewList(blogArticle), @@ -101,9 +94,6 @@ var blogMutation = graphql.NewObject(graphql.ObjectConfig{ Type: graphql.String, }, }, - Resolve: func(p graphql.ResolveParams) (interface{}, error) { - return nil, ErrArticleMutation - }, }, }, }) @@ -549,45 +539,3 @@ func TestTypeSystem_DefinitionExample_DoesNotMutatePassedFieldDefinitions(t *tes } } - -func TestQuery_FieldResolveFn_AddsErrorsToGraphQLResult(t *testing.T) { - blogSchema, err := graphql.NewSchema(graphql.SchemaConfig{ - Query: blogQuery, - Mutation: blogMutation, - }) - if err != nil { - t.Fatalf("unexpected error, got: %v", err) - } - query := "{ article(id:\"1\") { id } }" - result := graphql.Do(graphql.Params{ - Schema: blogSchema, - RequestString: query, - }) - if len(result.Errors) == 0 { - t.Fatal("wrong result, expected errors, got no errors") - } - if result.Errors[0].Error() != ErrArticleQuery.Error() { - t.Fatalf("wrong result, unexpected error, got: %v, expected: %v", result.Errors[0], ErrArticleQuery) - } -} - -func TestMutation_FieldResolveFn_AddsErrorsToGraphQLResult(t *testing.T) { - blogSchema, err := graphql.NewSchema(graphql.SchemaConfig{ - Query: blogQuery, - Mutation: blogMutation, - }) - if err != nil { - t.Fatalf("unexpected error, got: %v", err) - } - query := "mutation _ { newArticle: writeArticle(title:\"article title\") { id } }" - result := graphql.Do(graphql.Params{ - Schema: blogSchema, - RequestString: query, - }) - if len(result.Errors) == 0 { - t.Fatal("wrong result, expected errors, got no errors") - } - if result.Errors[0].Error() != ErrArticleMutation.Error() { - t.Fatalf("wrong result, unexpected error, got: %v, expected: %v", result.Errors[0], ErrArticleMutation) - } -} diff --git a/executor_test.go b/executor_test.go index 031f5836..05bd0a94 100644 --- a/executor_test.go +++ b/executor_test.go @@ -2,6 +2,7 @@ package graphql_test import ( "encoding/json" + "errors" "fmt" "reflect" "testing" @@ -1107,3 +1108,187 @@ func TestFailsToExecuteQueryContainingATypeDefinition(t *testing.T) { t.Fatalf("Unexpected result, Diff: %v", testutil.Diff(expected, result)) } } + +func TestQuery_ExecutionAddsErrorsFromFieldResolveFn(t *testing.T) { + qError := errors.New("queryError") + q := graphql.NewObject(graphql.ObjectConfig{ + Name: "Query", + Fields: graphql.Fields{ + "a": &graphql.Field{ + Type: graphql.String, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return nil, qError + }, + }, + "b": &graphql.Field{ + Type: graphql.String, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "ok", nil + }, + }, + }, + }) + blogSchema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: q, + }) + if err != nil { + t.Fatalf("unexpected error, got: %v", err) + } + query := "{ a }" + result := graphql.Do(graphql.Params{ + Schema: blogSchema, + RequestString: query, + }) + if len(result.Errors) == 0 { + t.Fatal("wrong result, expected errors, got no errors") + } + if result.Errors[0].Error() != qError.Error() { + t.Fatalf("wrong result, unexpected error, got: %v, expected: %v", result.Errors[0], qError) + } +} + +func TestQuery_ExecutionDoesNotAddErrorsFromFieldResolveFn(t *testing.T) { + qError := errors.New("queryError") + q := graphql.NewObject(graphql.ObjectConfig{ + Name: "Query", + Fields: graphql.Fields{ + "a": &graphql.Field{ + Type: graphql.String, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return nil, qError + }, + }, + "b": &graphql.Field{ + Type: graphql.String, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "ok", nil + }, + }, + }, + }) + blogSchema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: q, + }) + if err != nil { + t.Fatalf("unexpected error, got: %v", err) + } + query := "{ b }" + result := graphql.Do(graphql.Params{ + Schema: blogSchema, + RequestString: query, + }) + if len(result.Errors) != 0 { + t.Fatal("wrong result, unexpected errors: %+v", result.Errors) + } +} + +func TestMutation_ExecutionAddsErrorsFromFieldResolveFn(t *testing.T) { + mError := errors.New("mutationError") + q := graphql.NewObject(graphql.ObjectConfig{ + Name: "Query", + Fields: graphql.Fields{ + "a": &graphql.Field{ + Type: graphql.String, + }, + }, + }) + m := graphql.NewObject(graphql.ObjectConfig{ + Name: "Mutation", + Fields: graphql.Fields{ + "foo": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "f": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return nil, mError + }, + }, + "bar": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "b": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "ok", nil + }, + }, + }, + }) + schema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: q, + Mutation: m, + }) + if err != nil { + t.Fatalf("unexpected error, got: %v", err) + } + query := "mutation _ { newFoo: foo(f:\"title\") }" + result := graphql.Do(graphql.Params{ + Schema: schema, + RequestString: query, + }) + if len(result.Errors) == 0 { + t.Fatal("wrong result, expected errors, got no errors") + } + if result.Errors[0].Error() != mError.Error() { + t.Fatalf("wrong result, unexpected error, got: %v, expected: %v", result.Errors[0], mError) + } +} + +func TestMutation_ExecutionDoesNotAddErrorsFromFieldResolveFn(t *testing.T) { + mError := errors.New("mutationError") + q := graphql.NewObject(graphql.ObjectConfig{ + Name: "Query", + Fields: graphql.Fields{ + "a": &graphql.Field{ + Type: graphql.String, + }, + }, + }) + m := graphql.NewObject(graphql.ObjectConfig{ + Name: "Mutation", + Fields: graphql.Fields{ + "foo": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "f": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return nil, mError + }, + }, + "bar": &graphql.Field{ + Type: graphql.String, + Args: graphql.FieldConfigArgument{ + "b": &graphql.ArgumentConfig{ + Type: graphql.String, + }, + }, + Resolve: func(p graphql.ResolveParams) (interface{}, error) { + return "ok", nil + }, + }, + }, + }) + schema, err := graphql.NewSchema(graphql.SchemaConfig{ + Query: q, + Mutation: m, + }) + if err != nil { + t.Fatalf("unexpected error, got: %v", err) + } + query := "mutation _ { newBar: bar(b:\"title\") }" + result := graphql.Do(graphql.Params{ + Schema: schema, + RequestString: query, + }) + if len(result.Errors) != 0 { + t.Fatal("wrong result, expected errors, got no errors") + } +} From 87c64f40c7d965034a112720397626db5fc029f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Ram=C3=B3n?= Date: Thu, 26 Nov 2015 23:11:54 -0500 Subject: [PATCH 40/41] updates to better error name --- executor.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/executor.go b/executor.go index 1b34a7ae..9be274c1 100644 --- a/executor.go +++ b/executor.go @@ -498,16 +498,16 @@ func resolveField(eCtx *ExecutionContext, parentType *Object, source interface{} // it is wrapped as a Error with locations. Log this error and return // null if allowed, otherwise throw the error so the parent field can handle // it. - var resultError error + var resolveFnError error - result, resultError = resolveFn(ResolveParams{ + result, resolveFnError = resolveFn(ResolveParams{ Source: source, Args: args, Info: info, }) - if resultError != nil { - panic(gqlerrors.FormatError(resultError)) + if resolveFnError != nil { + panic(gqlerrors.FormatError(resolveFnError)) } completed := completeValueCatchingError(eCtx, returnType, fieldASTs, info, result) From 1c902e8955e9f55ba9e0e9d6c3cd2c91b516f5bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Ram=C3=B3n?= Date: Thu, 26 Nov 2015 23:20:12 -0500 Subject: [PATCH 41/41] fixes for go vet --- executor_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/executor_test.go b/executor_test.go index 05bd0a94..e643f31e 100644 --- a/executor_test.go +++ b/executor_test.go @@ -1178,7 +1178,7 @@ func TestQuery_ExecutionDoesNotAddErrorsFromFieldResolveFn(t *testing.T) { RequestString: query, }) if len(result.Errors) != 0 { - t.Fatal("wrong result, unexpected errors: %+v", result.Errors) + t.Fatalf("wrong result, unexpected errors: %+v", result.Errors) } } @@ -1289,6 +1289,6 @@ func TestMutation_ExecutionDoesNotAddErrorsFromFieldResolveFn(t *testing.T) { RequestString: query, }) if len(result.Errors) != 0 { - t.Fatal("wrong result, expected errors, got no errors") + t.Fatalf("wrong result, unexpected errors: %+v", result.Errors) } }