Skip to content

Commit

Permalink
Merge pull request #3552 from jbellenger/jbellenger-validate-dir-loc
Browse files Browse the repository at this point in the history
require non-empty directive locations
  • Loading branch information
bbakerman committed Apr 2, 2024
2 parents 6eb188b + 479440d commit c49da41
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 74 deletions.
2 changes: 2 additions & 0 deletions src/main/java/graphql/schema/GraphQLDirective.java
Expand Up @@ -15,6 +15,7 @@
import java.util.function.Consumer;
import java.util.function.UnaryOperator;

import static graphql.Assert.assertNotEmpty;
import static graphql.Assert.assertNotNull;
import static graphql.Assert.assertValidName;
import static graphql.introspection.Introspection.DirectiveLocation;
Expand Down Expand Up @@ -52,6 +53,7 @@ private GraphQLDirective(String name,
DirectiveDefinition definition) {
assertValidName(name);
assertNotNull(arguments, () -> "arguments can't be null");
assertNotEmpty(locations, () -> "locations can't be empty");
this.name = name;
this.description = description;
this.repeatable = repeatable;
Expand Down
15 changes: 11 additions & 4 deletions src/test/groovy/graphql/TestUtil.groovy
Expand Up @@ -2,6 +2,7 @@ package graphql

import graphql.execution.MergedField
import graphql.execution.MergedSelectionSet
import graphql.introspection.Introspection.DirectiveLocation
import graphql.language.Document
import graphql.language.Field
import graphql.language.NullValue
Expand All @@ -12,8 +13,8 @@ import graphql.language.Type
import graphql.parser.Parser
import graphql.schema.Coercing
import graphql.schema.DataFetcher
import graphql.schema.GraphQLAppliedDirectiveArgument
import graphql.schema.GraphQLAppliedDirective
import graphql.schema.GraphQLAppliedDirectiveArgument
import graphql.schema.GraphQLArgument
import graphql.schema.GraphQLDirective
import graphql.schema.GraphQLInputType
Expand Down Expand Up @@ -194,13 +195,19 @@ class TestUtil {
.name(definition.getName())
.description(definition.getDescription() == null ? null : definition.getDescription().getContent())
.coercing(mockCoercing())
.replaceDirectives(definition.getDirectives().stream().map({ mockDirective(it.getName()) }).collect(Collectors.toList()))
.replaceDirectives(
definition.getDirectives()
.stream()
.map({ mkDirective(it.getName(), DirectiveLocation.SCALAR) })
.collect(Collectors.toList()))
.definition(definition)
.build()
}

static GraphQLDirective mockDirective(String name) {
newDirective().name(name).description(name).build()
static GraphQLDirective mkDirective(String name, DirectiveLocation location, GraphQLArgument arg = null) {
def b = newDirective().name(name).description(name).validLocation(location)
if (arg != null) b.argument(arg)
b.build()
}

static TypeRuntimeWiring mockTypeRuntimeWiring(String typeName, boolean withResolver) {
Expand Down
23 changes: 12 additions & 11 deletions src/test/groovy/graphql/schema/GraphQLArgumentTest.groovy
@@ -1,6 +1,7 @@
package graphql.schema

import graphql.collect.ImmutableKit
import static graphql.introspection.Introspection.DirectiveLocation.ARGUMENT_DEFINITION
import graphql.language.FloatValue
import graphql.schema.validation.InvalidSchemaException
import spock.lang.Specification
Expand All @@ -9,10 +10,10 @@ import static graphql.Scalars.GraphQLFloat
import static graphql.Scalars.GraphQLInt
import static graphql.Scalars.GraphQLString
import static graphql.schema.GraphQLArgument.newArgument
import static graphql.schema.GraphQLDirective.newDirective
import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition
import static graphql.schema.GraphQLObjectType.newObject
import static graphql.schema.GraphQLSchema.newSchema
import static graphql.TestUtil.mkDirective

class GraphQLArgumentTest extends Specification {

Expand All @@ -22,15 +23,15 @@ class GraphQLArgumentTest extends Specification {
.description("A1_description")
.type(GraphQLInt)
.deprecate("custom reason")
.withDirective(newDirective().name("directive1"))
.withDirective(mkDirective("directive1", ARGUMENT_DEFINITION))
.build()
when:
def transformedArgument = startingArgument.transform({
it
.name("A2")
.description("A2_description")
.type(GraphQLString)
.withDirective(newDirective().name("directive3"))
.withDirective(mkDirective("directive3", ARGUMENT_DEFINITION))
.value("VALUE") // Retain deprecated for test coverage
.deprecate(null)
.defaultValue("DEFAULT") // Retain deprecated for test coverage
Expand Down Expand Up @@ -79,9 +80,9 @@ class GraphQLArgumentTest extends Specification {
def argument

given:
def builder = GraphQLArgument.newArgument().name("A1")
def builder = newArgument().name("A1")
.type(GraphQLInt)
.withDirective(newDirective().name("directive1"))
.withDirective(mkDirective("directive1", ARGUMENT_DEFINITION))

when:
argument = builder.build()
Expand All @@ -96,8 +97,8 @@ class GraphQLArgumentTest extends Specification {
when:
argument = builder
.clearDirectives()
.withDirective(newDirective().name("directive2"))
.withDirective(newDirective().name("directive3"))
.withDirective(mkDirective("directive2", ARGUMENT_DEFINITION))
.withDirective(mkDirective("directive3", ARGUMENT_DEFINITION))
.build()

then:
Expand All @@ -109,9 +110,9 @@ class GraphQLArgumentTest extends Specification {
when:
argument = builder
.replaceDirectives([
newDirective().name("directive1").build(),
newDirective().name("directive2").build(),
newDirective().name("directive3").build()]) // overwrite
mkDirective("directive1", ARGUMENT_DEFINITION),
mkDirective("directive2", ARGUMENT_DEFINITION),
mkDirective("directive3", ARGUMENT_DEFINITION)]) // overwrite
.build()

then:
Expand Down Expand Up @@ -198,7 +199,7 @@ class GraphQLArgumentTest extends Specification {
def "Applied schema directives arguments are validated for programmatic schemas"() {
given:
def arg = newArgument().name("arg").type(GraphQLInt).valueProgrammatic(ImmutableKit.emptyMap()).build() // Retain for test coverage
def directive = GraphQLDirective.newDirective().name("cached").argument(arg).build()
def directive = mkDirective("cached", ARGUMENT_DEFINITION, arg)
def field = newFieldDefinition()
.name("hello")
.type(GraphQLString)
Expand Down
31 changes: 31 additions & 0 deletions src/test/groovy/graphql/schema/GraphQLDirectiveTest.groovy
@@ -1,6 +1,8 @@
package graphql.schema

import graphql.AssertException
import graphql.TestUtil
import graphql.introspection.Introspection
import graphql.language.Node
import spock.lang.Specification

Expand Down Expand Up @@ -168,9 +170,38 @@ class GraphQLDirectiveTest extends Specification {

then:
assertDirectiveContainer(scalarType)
}

def "throws an error on missing required properties"() {
given:
def validDirective = GraphQLDirective.newDirective()
.name("dir")
.validLocation(Introspection.DirectiveLocation.SCALAR)
.build()

when:
validDirective.transform { it.name(null) }

then:
def e = thrown(AssertException)
e.message.contains("Name must be non-null, non-empty")

when:
validDirective.transform { it.replaceArguments(null) }

then:
def e2 = thrown(AssertException)
e2.message.contains("arguments must not be null")

when:
validDirective.transform { it.clearValidLocations() }

then:
def e3 = thrown(AssertException)
e3.message.contains("locations can't be empty")
}


static boolean assertDirectiveContainer(GraphQLDirectiveContainer container) {
assert container.hasDirective("d1") // Retain for test coverage
assert container.hasAppliedDirective("d1")
Expand Down
@@ -1,25 +1,25 @@
package graphql.schema

import static graphql.introspection.Introspection.DirectiveLocation
import spock.lang.Specification

import static graphql.schema.GraphQLDirective.newDirective
import static graphql.schema.GraphQLEnumValueDefinition.newEnumValueDefinition
import static graphql.TestUtil.mkDirective

class GraphQLEnumValueDefinitionTest extends Specification {
def "object can be transformed"() {
given:
def startEnumValue = newEnumValueDefinition().name("EV1")
.description("EV1_description")
.value("A")
.withDirective(newDirective().name("directive1"))
.withDirective(mkDirective("directive1", DirectiveLocation.ENUM_VALUE))
.build()
when:
def transformedEnumValue = startEnumValue.transform({
it
.name("EV2")
.value("X")
.withDirective(newDirective().name("directive2"))

.withDirective(mkDirective("directive2", DirectiveLocation.ENUM_VALUE))
})

then:
Expand Down
12 changes: 5 additions & 7 deletions src/test/groovy/graphql/schema/GraphQLFieldDefinitionTest.groovy
Expand Up @@ -2,6 +2,7 @@ package graphql.schema

import graphql.AssertException
import graphql.TestUtil
import graphql.introspection.Introspection
import graphql.schema.idl.SchemaPrinter
import spock.lang.Specification

Expand All @@ -10,9 +11,9 @@ import static graphql.Scalars.GraphQLFloat
import static graphql.Scalars.GraphQLInt
import static graphql.Scalars.GraphQLString
import static graphql.TestUtil.mockArguments
import static graphql.TestUtil.mkDirective
import static graphql.schema.DefaultGraphqlTypeComparatorRegistry.newComparators
import static graphql.schema.GraphQLArgument.newArgument
import static graphql.schema.GraphQLDirective.newDirective
import static graphql.schema.GraphQLFieldDefinition.newFieldDefinition
import static graphql.schema.idl.SchemaPrinter.Options.defaultOptions

Expand All @@ -35,8 +36,8 @@ class GraphQLFieldDefinitionTest extends Specification {
.deprecate("F1_deprecated")
.argument(newArgument().name("argStr").type(GraphQLString))
.argument(newArgument().name("argInt").type(GraphQLInt))
.withDirective(newDirective().name("directive1"))
.withDirective(newDirective().name("directive2"))
.withDirective(mkDirective("directive1", Introspection.DirectiveLocation.FIELD_DEFINITION))
.withDirective(mkDirective("directive2", Introspection.DirectiveLocation.FIELD_DEFINITION))
.build()

when:
Expand All @@ -47,13 +48,10 @@ class GraphQLFieldDefinitionTest extends Specification {
.argument(newArgument().name("argStr").type(GraphQLString))
.argument(newArgument().name("argInt").type(GraphQLBoolean))
.argument(newArgument().name("argIntAdded").type(GraphQLInt))
.withDirective(newDirective().name("directive3"))

.withDirective(mkDirective("directive3", Introspection.DirectiveLocation.FIELD_DEFINITION))
})


then:

startingField.name == "F1"
startingField.type == GraphQLFloat
startingField.description == "F1_description"
Expand Down
@@ -1,12 +1,13 @@
package graphql.schema

import graphql.introspection.Introspection
import graphql.language.FloatValue
import spock.lang.Specification

import static graphql.Scalars.GraphQLFloat
import static graphql.Scalars.GraphQLInt
import static graphql.schema.GraphQLDirective.newDirective
import static graphql.schema.GraphQLInputObjectField.newInputObjectField
import static graphql.TestUtil.mkDirective

class GraphQLInputObjectFieldTest extends Specification {

Expand All @@ -16,8 +17,8 @@ class GraphQLInputObjectFieldTest extends Specification {
.name("F1")
.type(GraphQLFloat)
.description("F1_description")
.withDirective(newDirective().name("directive1"))
.withDirective(newDirective().name("directive2"))
.withDirective(mkDirective("directive1", Introspection.DirectiveLocation.INPUT_FIELD_DEFINITION))
.withDirective(mkDirective("directive2", Introspection.DirectiveLocation.INPUT_FIELD_DEFINITION))
.deprecate("No longer useful")
.build()

Expand All @@ -26,13 +27,10 @@ class GraphQLInputObjectFieldTest extends Specification {
builder.name("F2")
.type(GraphQLInt)
.deprecate(null)
.withDirective(newDirective().name("directive3"))

.withDirective(mkDirective("directive3", Introspection.DirectiveLocation.INPUT_FIELD_DEFINITION))
})


then:

startingField.name == "F1"
startingField.type == GraphQLFloat
startingField.description == "F1_description"
Expand Down
10 changes: 5 additions & 5 deletions src/test/groovy/graphql/schema/GraphQLScalarTypeTest.groovy
@@ -1,8 +1,9 @@
package graphql.schema

import graphql.introspection.Introspection
import spock.lang.Specification

import static graphql.schema.GraphQLDirective.newDirective
import static graphql.TestUtil.mkDirective

class GraphQLScalarTypeTest extends Specification {
Coercing<String, String> coercing = new Coercing<String, String>() {
Expand All @@ -28,14 +29,14 @@ class GraphQLScalarTypeTest extends Specification {
.name("S1")
.description("S1_description")
.coercing(coercing)
.withDirective(newDirective().name("directive1"))
.withDirective(newDirective().name("directive2"))
.withDirective(mkDirective("directive1", Introspection.DirectiveLocation.SCALAR))
.withDirective(mkDirective("directive2", Introspection.DirectiveLocation.SCALAR))
.build()
when:
def transformedScalar = startingScalar.transform({ builder ->
builder.name("S2")
.description("S2_description")
.withDirective(newDirective().name("directive3"))
.withDirective(mkDirective("directive3", Introspection.DirectiveLocation.SCALAR))
})

then:
Expand All @@ -55,6 +56,5 @@ class GraphQLScalarTypeTest extends Specification {
transformedScalar.getDirective("directive1") != null
transformedScalar.getDirective("directive2") != null
transformedScalar.getDirective("directive3") != null

}
}

0 comments on commit c49da41

Please sign in to comment.