getComments(ParserRuleContext ctx) {
return getCommentOnChannel(refChannel);
}
}
- return ImmutableKit.emptyList();
+ return NO_COMMENTS;
}
diff --git a/src/main/java/graphql/parser/ParserOptions.java b/src/main/java/graphql/parser/ParserOptions.java
index e7d4cbdc5..234605bca 100644
--- a/src/main/java/graphql/parser/ParserOptions.java
+++ b/src/main/java/graphql/parser/ParserOptions.java
@@ -21,11 +21,12 @@ public class ParserOptions {
* If you want to allow more, then {@link #setDefaultParserOptions(ParserOptions)} allows you to change this
* JVM wide.
*/
- public static int MAX_QUERY_TOKENS = 15000;
+ public static final int MAX_QUERY_TOKENS = 15000;
private static ParserOptions defaultJvmParserOptions = newParserOptions()
.captureIgnoredChars(false)
.captureSourceLocation(true)
+ .captureLineComments(true)
.maxTokens(MAX_QUERY_TOKENS) // to prevent a billion laughs style attacks, we set a default for graphql-java
.build();
@@ -66,12 +67,14 @@ public static void setDefaultParserOptions(ParserOptions options) {
private final boolean captureIgnoredChars;
private final boolean captureSourceLocation;
+ private final boolean captureLineComments;
private final int maxTokens;
private final ParsingListener parsingListener;
private ParserOptions(Builder builder) {
this.captureIgnoredChars = builder.captureIgnoredChars;
this.captureSourceLocation = builder.captureSourceLocation;
+ this.captureLineComments = builder.captureLineComments;
this.maxTokens = builder.maxTokens;
this.parsingListener = builder.parsingListener;
}
@@ -80,7 +83,7 @@ private ParserOptions(Builder builder) {
* Significant memory savings can be made if we do NOT capture ignored characters,
* especially in SDL parsing. So we have set this to false by default.
*
- * @return true if ignored chars are captured in AST nodes
+ * @return true if ignored chars should be captured as AST nodes
*/
public boolean isCaptureIgnoredChars() {
return captureIgnoredChars;
@@ -91,7 +94,7 @@ public boolean isCaptureIgnoredChars() {
* Memory savings can be made if we do NOT set {@link graphql.language.SourceLocation}s
* on AST nodes, especially in SDL parsing.
*
- * @return true if {@link graphql.language.SourceLocation}s are captured in AST nodes
+ * @return true if {@link graphql.language.SourceLocation}s should be captured as AST nodes
*
* @see graphql.language.SourceLocation
*/
@@ -99,6 +102,20 @@ public boolean isCaptureSourceLocation() {
return captureSourceLocation;
}
+ /**
+ * Single-line {@link graphql.language.Comment}s do not have any semantic meaning in
+ * GraphQL source documents, as such you may wish to ignore them.
+ *
+ * This option does not ignore documentation {@link graphql.language.Description}s.
+ *
+ * @return true if {@link graphql.language.Comment}s should be captured as AST nodes
+ *
+ * @see graphql.language.SourceLocation
+ */
+ public boolean isCaptureLineComments() {
+ return captureLineComments;
+ }
+
/**
* A graphql hacking vector is to send nonsensical queries that burn lots of parsing CPU time and burn
* memory representing a document that won't ever execute. To prevent this you can set a maximum number of parse
@@ -128,6 +145,7 @@ public static class Builder {
private boolean captureIgnoredChars = false;
private boolean captureSourceLocation = true;
+ private boolean captureLineComments = true;
private int maxTokens = MAX_QUERY_TOKENS;
private ParsingListener parsingListener = ParsingListener.NOOP;
@@ -137,6 +155,7 @@ public static class Builder {
Builder(ParserOptions parserOptions) {
this.captureIgnoredChars = parserOptions.captureIgnoredChars;
this.captureSourceLocation = parserOptions.captureSourceLocation;
+ this.captureLineComments = parserOptions.captureLineComments;
this.maxTokens = parserOptions.maxTokens;
this.parsingListener = parserOptions.parsingListener;
}
@@ -151,6 +170,11 @@ public Builder captureSourceLocation(boolean captureSourceLocation) {
return this;
}
+ public Builder captureLineComments(boolean captureLineComments) {
+ this.captureLineComments = captureLineComments;
+ return this;
+ }
+
public Builder maxTokens(int maxTokens) {
this.maxTokens = maxTokens;
return this;
diff --git a/src/main/java/graphql/parser/UnicodeUtil.java b/src/main/java/graphql/parser/UnicodeUtil.java
index 53d1cefe0..cdf55ace4 100644
--- a/src/main/java/graphql/parser/UnicodeUtil.java
+++ b/src/main/java/graphql/parser/UnicodeUtil.java
@@ -13,11 +13,11 @@
*/
@Internal
public class UnicodeUtil {
- public static int MAX_UNICODE_CODE_POINT = 0x10FFFF;
- public static int LEADING_SURROGATE_LOWER_BOUND = 0xD800;
- public static int LEADING_SURROGATE_UPPER_BOUND = 0xDBFF;
- public static int TRAILING_SURROGATE_LOWER_BOUND = 0xDC00;
- public static int TRAILING_SURROGATE_UPPER_BOUND = 0xDFFF;
+ public static final int MAX_UNICODE_CODE_POINT = 0x10FFFF;
+ public static final int LEADING_SURROGATE_LOWER_BOUND = 0xD800;
+ public static final int LEADING_SURROGATE_UPPER_BOUND = 0xDBFF;
+ public static final int TRAILING_SURROGATE_LOWER_BOUND = 0xDC00;
+ public static final int TRAILING_SURROGATE_UPPER_BOUND = 0xDFFF;
public static int parseAndWriteUnicode(StringWriter writer, String string, int i, SourceLocation sourceLocation) {
// Unicode code points can either be:
@@ -31,7 +31,7 @@ public static int parseAndWriteUnicode(StringWriter writer, String string, int i
int continueIndex = isBracedEscape(string, i) ? endIndexExclusive : endIndexExclusive - 1;
String hexStr = string.substring(startIndex, endIndexExclusive);
- Integer codePoint = Integer.parseInt(hexStr, 16);
+ int codePoint = Integer.parseInt(hexStr, 16);
if (isTrailingSurrogateValue(codePoint)) {
throw new InvalidSyntaxException(sourceLocation, "Invalid unicode - trailing surrogate must be preceded with a leading surrogate -", null, string.substring(i - 1, continueIndex + 1), null);
@@ -45,7 +45,7 @@ public static int parseAndWriteUnicode(StringWriter writer, String string, int i
int trailingStartIndex = isBracedEscape(string, i) ? i + 2 : i + 1;
int trailingEndIndexExclusive = getEndIndexExclusive(string, i, sourceLocation);
String trailingHexStr = string.substring(trailingStartIndex, trailingEndIndexExclusive);
- Integer trailingCodePoint = Integer.parseInt(trailingHexStr, 16);
+ int trailingCodePoint = Integer.parseInt(trailingHexStr, 16);
continueIndex = isBracedEscape(string, i) ? trailingEndIndexExclusive : trailingEndIndexExclusive - 1;
if (isTrailingSurrogateValue(trailingCodePoint)) {
diff --git a/src/main/java/graphql/schema/DelegatingDataFetchingEnvironment.java b/src/main/java/graphql/schema/DelegatingDataFetchingEnvironment.java
index 3758d7318..e4f955242 100644
--- a/src/main/java/graphql/schema/DelegatingDataFetchingEnvironment.java
+++ b/src/main/java/graphql/schema/DelegatingDataFetchingEnvironment.java
@@ -39,26 +39,33 @@ public DelegatingDataFetchingEnvironment(DataFetchingEnvironment delegateEnviron
this.delegateEnvironment = delegateEnvironment;
}
+ @Override
public T getSource() {
return delegateEnvironment.getSource();
}
+ @Override
public Map getArguments() {
return delegateEnvironment.getArguments();
}
+ @Override
public boolean containsArgument(String name) {
return delegateEnvironment.containsArgument(name);
}
+ @Override
public T getArgument(String name) {
return delegateEnvironment.getArgument(name);
}
+ @Override
public T getArgumentOrDefault(String name, T defaultValue) {
return delegateEnvironment.getArgumentOrDefault(name, defaultValue);
}
+ @Deprecated
+ @Override
public T getContext() {
return delegateEnvironment.getContext();
}
@@ -68,63 +75,78 @@ public GraphQLContext getGraphQlContext() {
return delegateEnvironment.getGraphQlContext();
}
+ @Override
public T getLocalContext() {
return delegateEnvironment.getLocalContext();
}
+ @Override
public T getRoot() {
return delegateEnvironment.getRoot();
}
+ @Override
public GraphQLFieldDefinition getFieldDefinition() {
return delegateEnvironment.getFieldDefinition();
}
@Deprecated
+ @Override
public List getFields() {
return delegateEnvironment.getFields();
}
+ @Override
public MergedField getMergedField() {
return delegateEnvironment.getMergedField();
}
+ @Override
public Field getField() {
return delegateEnvironment.getField();
}
+ @Override
public GraphQLOutputType getFieldType() {
return delegateEnvironment.getFieldType();
}
+ @Override
public ExecutionStepInfo getExecutionStepInfo() {
return delegateEnvironment.getExecutionStepInfo();
}
+ @Override
public GraphQLType getParentType() {
return delegateEnvironment.getParentType();
}
+ @Override
public GraphQLSchema getGraphQLSchema() {
return delegateEnvironment.getGraphQLSchema();
}
+ @Override
public Map getFragmentsByName() {
return delegateEnvironment.getFragmentsByName();
}
+ @Override
public ExecutionId getExecutionId() {
return delegateEnvironment.getExecutionId();
}
+ @Override
public DataFetchingFieldSelectionSet getSelectionSet() {
return delegateEnvironment.getSelectionSet();
}
+ @Override
public QueryDirectives getQueryDirectives() {
return delegateEnvironment.getQueryDirectives();
}
+ @Override
public DataLoader getDataLoader(String dataLoaderName) {
return delegateEnvironment.getDataLoader(dataLoaderName);
}
@@ -139,18 +161,22 @@ public Locale getLocale() {
return delegateEnvironment.getLocale();
}
+ @Override
public CacheControl getCacheControl() {
return delegateEnvironment.getCacheControl();
}
+ @Override
public OperationDefinition getOperationDefinition() {
return delegateEnvironment.getOperationDefinition();
}
+ @Override
public Document getDocument() {
return delegateEnvironment.getDocument();
}
+ @Override
public Map getVariables() {
return delegateEnvironment.getVariables();
}
diff --git a/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java b/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java
index d5faa84b8..0380ac5cd 100644
--- a/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java
+++ b/src/main/java/graphql/schema/GraphQLTypeResolvingVisitor.java
@@ -60,8 +60,8 @@ public TraversalControl visitBackRef(TraverserContext cont
return CONTINUE;
}
- private class TypeRefResolvingVisitor extends GraphQLTypeVisitorStub {
- protected final GraphQLType resolvedType;
+ private static final class TypeRefResolvingVisitor extends GraphQLTypeVisitorStub {
+ private final GraphQLType resolvedType;
TypeRefResolvingVisitor(GraphQLType resolvedType) {
this.resolvedType = resolvedType;
diff --git a/src/main/java/graphql/schema/idl/DirectiveInfo.java b/src/main/java/graphql/schema/idl/DirectiveInfo.java
index 992074425..4b6159ee2 100644
--- a/src/main/java/graphql/schema/idl/DirectiveInfo.java
+++ b/src/main/java/graphql/schema/idl/DirectiveInfo.java
@@ -1,11 +1,11 @@
package graphql.schema.idl;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import graphql.Directives;
import graphql.PublicApi;
import graphql.schema.GraphQLDirective;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
@@ -18,27 +18,20 @@ public class DirectiveInfo {
/**
* A set of directives which provided by graphql specification
*/
- public static final Set GRAPHQL_SPECIFICATION_DIRECTIVES = new LinkedHashSet<>();
+ public static final Set GRAPHQL_SPECIFICATION_DIRECTIVES = ImmutableSet.of(
+ Directives.IncludeDirective,
+ Directives.SkipDirective,
+ Directives.DeprecatedDirective,
+ Directives.SpecifiedByDirective);
/**
* A map from directive name to directive which provided by specification
*/
- public static final Map GRAPHQL_SPECIFICATION_DIRECTIVE_MAP = new LinkedHashMap<>();
-
- static {
- GRAPHQL_SPECIFICATION_DIRECTIVES.add(Directives.IncludeDirective);
- GRAPHQL_SPECIFICATION_DIRECTIVES.add(Directives.SkipDirective);
- GRAPHQL_SPECIFICATION_DIRECTIVES.add(Directives.DeprecatedDirective);
- GRAPHQL_SPECIFICATION_DIRECTIVES.add(Directives.SpecifiedByDirective);
- }
-
- static {
- GRAPHQL_SPECIFICATION_DIRECTIVE_MAP.put(Directives.IncludeDirective.getName(), Directives.IncludeDirective);
- GRAPHQL_SPECIFICATION_DIRECTIVE_MAP.put(Directives.SkipDirective.getName(), Directives.SkipDirective);
- GRAPHQL_SPECIFICATION_DIRECTIVE_MAP.put(Directives.DeprecatedDirective.getName(), Directives.DeprecatedDirective);
- GRAPHQL_SPECIFICATION_DIRECTIVE_MAP.put(Directives.SpecifiedByDirective.getName(), Directives.SpecifiedByDirective);
- }
-
+ public static final Map GRAPHQL_SPECIFICATION_DIRECTIVE_MAP = ImmutableMap.of(
+ Directives.IncludeDirective.getName(), Directives.IncludeDirective,
+ Directives.SkipDirective.getName(), Directives.SkipDirective,
+ Directives.DeprecatedDirective.getName(), Directives.DeprecatedDirective,
+ Directives.SpecifiedByDirective.getName(), Directives.SpecifiedByDirective);
/**
* Returns true if a directive with provided directiveName has been defined in graphql specification
diff --git a/src/main/java/graphql/schema/idl/ScalarInfo.java b/src/main/java/graphql/schema/idl/ScalarInfo.java
index 13e5a89f1..910b78f4b 100644
--- a/src/main/java/graphql/schema/idl/ScalarInfo.java
+++ b/src/main/java/graphql/schema/idl/ScalarInfo.java
@@ -1,12 +1,12 @@
package graphql.schema.idl;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import graphql.PublicApi;
import graphql.Scalars;
import graphql.language.ScalarTypeDefinition;
import graphql.schema.GraphQLScalarType;
-import java.util.ArrayList;
-import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -19,30 +19,22 @@ public class ScalarInfo {
/**
* A list of the built-in scalar types as defined by the graphql specification
*/
- public static final List GRAPHQL_SPECIFICATION_SCALARS = new ArrayList<>();
+ public static final List GRAPHQL_SPECIFICATION_SCALARS = ImmutableList.of(
+ Scalars.GraphQLInt,
+ Scalars.GraphQLFloat,
+ Scalars.GraphQLString,
+ Scalars.GraphQLBoolean,
+ Scalars.GraphQLID);
/**
* A map of scalar type definitions provided by graphql-java
*/
- public static final Map GRAPHQL_SPECIFICATION_SCALARS_DEFINITIONS = new LinkedHashMap<>();
-
- static {
- GRAPHQL_SPECIFICATION_SCALARS.add(Scalars.GraphQLInt);
- GRAPHQL_SPECIFICATION_SCALARS.add(Scalars.GraphQLFloat);
- GRAPHQL_SPECIFICATION_SCALARS.add(Scalars.GraphQLString);
- GRAPHQL_SPECIFICATION_SCALARS.add(Scalars.GraphQLBoolean);
- GRAPHQL_SPECIFICATION_SCALARS.add(Scalars.GraphQLID);
- }
-
- static {
- // graphql standard scalars
- GRAPHQL_SPECIFICATION_SCALARS_DEFINITIONS.put("Int", ScalarTypeDefinition.newScalarTypeDefinition().name("Int").build());
- GRAPHQL_SPECIFICATION_SCALARS_DEFINITIONS.put("Float", ScalarTypeDefinition.newScalarTypeDefinition().name("Float").build());
- GRAPHQL_SPECIFICATION_SCALARS_DEFINITIONS.put("String", ScalarTypeDefinition.newScalarTypeDefinition().name("String").build());
- GRAPHQL_SPECIFICATION_SCALARS_DEFINITIONS.put("Boolean", ScalarTypeDefinition.newScalarTypeDefinition().name("Boolean").build());
- GRAPHQL_SPECIFICATION_SCALARS_DEFINITIONS.put("ID", ScalarTypeDefinition.newScalarTypeDefinition().name("ID").build());
-
- }
+ public static final Map GRAPHQL_SPECIFICATION_SCALARS_DEFINITIONS = ImmutableMap.of(
+ "Int", ScalarTypeDefinition.newScalarTypeDefinition().name("Int").build(),
+ "Float", ScalarTypeDefinition.newScalarTypeDefinition().name("Float").build(),
+ "String", ScalarTypeDefinition.newScalarTypeDefinition().name("String").build(),
+ "Boolean", ScalarTypeDefinition.newScalarTypeDefinition().name("Boolean").build(),
+ "ID", ScalarTypeDefinition.newScalarTypeDefinition().name("ID").build());
/**
* Returns true if the scalar type is a scalar that is specified by the graphql specification
diff --git a/src/main/java/graphql/schema/idl/TypeInfo.java b/src/main/java/graphql/schema/idl/TypeInfo.java
index fcc34b3fb..fe12d4988 100644
--- a/src/main/java/graphql/schema/idl/TypeInfo.java
+++ b/src/main/java/graphql/schema/idl/TypeInfo.java
@@ -8,8 +8,9 @@
import graphql.language.TypeName;
import graphql.schema.GraphQLType;
+import java.util.ArrayDeque;
+import java.util.Deque;
import java.util.Objects;
-import java.util.Stack;
import static graphql.Assert.assertNotNull;
import static graphql.schema.GraphQLList.list;
@@ -27,7 +28,7 @@ public static TypeInfo typeInfo(Type type) {
private final Type rawType;
private final TypeName typeName;
- private final Stack> decoration = new Stack<>();
+ private final Deque> decoration = new ArrayDeque<>();
private TypeInfo(Type type) {
this.rawType = assertNotNull(type, () -> "type must not be null");
@@ -79,8 +80,7 @@ public TypeInfo renameAs(String newName) {
Type out = TypeName.newTypeName(newName).build();
- Stack> wrappingStack = new Stack<>();
- wrappingStack.addAll(this.decoration);
+ Deque> wrappingStack = new ArrayDeque<>(this.decoration);
while (!wrappingStack.isEmpty()) {
Class> clazz = wrappingStack.pop();
if (clazz.equals(NonNullType.class)) {
@@ -106,8 +106,7 @@ public TypeInfo renameAs(String newName) {
public T decorate(GraphQLType objectType) {
GraphQLType out = objectType;
- Stack> wrappingStack = new Stack<>();
- wrappingStack.addAll(this.decoration);
+ Deque> wrappingStack = new ArrayDeque<>(this.decoration);
while (!wrappingStack.isEmpty()) {
Class> clazz = wrappingStack.pop();
if (clazz.equals(NonNullType.class)) {
diff --git a/src/main/java/graphql/schema/idl/TypeRuntimeWiring.java b/src/main/java/graphql/schema/idl/TypeRuntimeWiring.java
index e0c4079ca..60bfe6f60 100644
--- a/src/main/java/graphql/schema/idl/TypeRuntimeWiring.java
+++ b/src/main/java/graphql/schema/idl/TypeRuntimeWiring.java
@@ -152,7 +152,7 @@ public Builder typeResolver(TypeResolver typeResolver) {
}
public Builder enumValues(EnumValuesProvider enumValuesProvider) {
- assertNotNull(enumValuesProvider, () -> "you must provide a type resolver");
+ assertNotNull(enumValuesProvider, () -> "you must provide an enum values provider");
this.enumValuesProvider = enumValuesProvider;
return this;
}
diff --git a/src/main/java/graphql/schema/idl/errors/NonSDLDefinitionError.java b/src/main/java/graphql/schema/idl/errors/NonSDLDefinitionError.java
index 1f770b701..fb41b7b7d 100644
--- a/src/main/java/graphql/schema/idl/errors/NonSDLDefinitionError.java
+++ b/src/main/java/graphql/schema/idl/errors/NonSDLDefinitionError.java
@@ -9,7 +9,7 @@
public class NonSDLDefinitionError extends BaseError {
public NonSDLDefinitionError(Definition definition) {
- super(definition, format("The schema definition text contains a non schema definition language (SDL) element '%s'",
- definition.getClass().getSimpleName(), lineCol(definition), lineCol(definition)));
+ super(definition, format("%s The schema definition text contains a non schema definition language (SDL) element '%s'",
+ lineCol(definition), definition.getClass().getSimpleName()));
}
}
diff --git a/src/main/java/graphql/util/Anonymizer.java b/src/main/java/graphql/util/Anonymizer.java
index 6720e3bca..846c842f4 100644
--- a/src/main/java/graphql/util/Anonymizer.java
+++ b/src/main/java/graphql/util/Anonymizer.java
@@ -702,7 +702,7 @@ private static List getMatchingArgumentDefinitions(
Set fieldDefinitions) {
List result = new ArrayList<>();
for (GraphQLFieldDefinition fieldDefinition : fieldDefinitions) {
- Optional.ofNullable(fieldDefinition.getArgument(name)).map(result::add);
+ Optional.ofNullable(fieldDefinition.getArgument(name)).ifPresent(result::add);
}
return result;
}
@@ -738,7 +738,7 @@ public void visitField(QueryVisitorFieldEnvironment env) {
for (Argument argument : directive.getArguments()) {
GraphQLArgument argumentDefinition = directiveDefinition.getArgument(argument.getName());
- String newArgumentName = assertNotNull(newNames.get(argumentDefinition), () -> format("%s no new name found for directive argument %s %s", directiveName, argument.getName()));
+ String newArgumentName = assertNotNull(newNames.get(argumentDefinition), () -> format("No new name found for directive %s argument %s", directiveName, argument.getName()));
astNodeToNewName.put(argument, newArgumentName);
visitDirectiveArgumentValues(directive, argument.getValue());
}
diff --git a/src/main/java/graphql/validation/rules/UniqueArgumentNamesRule.java b/src/main/java/graphql/validation/rules/UniqueArgumentNamesRule.java
index 5865ee2b1..b43f19e93 100644
--- a/src/main/java/graphql/validation/rules/UniqueArgumentNamesRule.java
+++ b/src/main/java/graphql/validation/rules/UniqueArgumentNamesRule.java
@@ -1,5 +1,6 @@
package graphql.validation.rules;
+import com.google.common.collect.Sets;
import graphql.Internal;
import graphql.language.Argument;
import graphql.language.Directive;
@@ -10,7 +11,6 @@
import graphql.validation.ValidationErrorCollector;
import graphql.validation.ValidationErrorType;
-import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -31,7 +31,7 @@ public void checkField(Field field) {
return;
}
- Set arguments = new HashSet<>();
+ Set arguments = Sets.newHashSetWithExpectedSize(field.getArguments().size());
for (Argument argument : field.getArguments()) {
if (arguments.contains(argument.getName())) {
@@ -48,7 +48,7 @@ public void checkDirective(Directive directive, List ancestors) {
return;
}
- Set arguments = new HashSet<>(directive.getArguments().size());
+ Set arguments = Sets.newHashSetWithExpectedSize(directive.getArguments().size());
for (Argument argument : directive.getArguments()) {
if (arguments.contains(argument.getName())) {
diff --git a/src/test/groovy/graphql/Issue743.groovy b/src/test/groovy/graphql/Issue743.groovy
index 183d63c80..b6466c65d 100644
--- a/src/test/groovy/graphql/Issue743.groovy
+++ b/src/test/groovy/graphql/Issue743.groovy
@@ -28,6 +28,6 @@ class Issue743 extends Specification {
executionResult.data == null
executionResult.errors.size() == 1
executionResult.errors[0].errorType == ErrorType.ValidationError
- executionResult.errors[0].message == "Variable 'isTrue' has coerced Null value for NonNull type 'Boolean!'"
+ executionResult.errors[0].message == "Variable 'isTrue' has an invalid value: Variable 'isTrue' has coerced Null value for NonNull type 'Boolean!'"
}
}
diff --git a/src/test/groovy/graphql/NullVariableCoercionTest.groovy b/src/test/groovy/graphql/NullVariableCoercionTest.groovy
index 253b9a58c..ffd42ac36 100644
--- a/src/test/groovy/graphql/NullVariableCoercionTest.groovy
+++ b/src/test/groovy/graphql/NullVariableCoercionTest.groovy
@@ -1,6 +1,6 @@
package graphql
-
+import graphql.language.SourceLocation
import graphql.schema.DataFetcher
import graphql.schema.GraphQLObjectType
import graphql.schema.idl.RuntimeWiring
@@ -68,8 +68,8 @@ class NullVariableCoercionTest extends Specification {
varResult.data == null
varResult.errors.size() == 1
varResult.errors[0].errorType == ErrorType.ValidationError
- varResult.errors[0].message == "Field 'baz' has coerced Null value for NonNull type 'String!'"
-// varResult.errors[0].locations == [new SourceLocation(1, 11)]
+ varResult.errors[0].message == "Variable 'input' has an invalid value: Field 'baz' has coerced Null value for NonNull type 'String!'"
+ varResult.errors[0].locations == [new SourceLocation(1, 11)]
}
def "can handle defaulting on complex input objects"() {
diff --git a/src/test/groovy/graphql/analysis/MaxQueryComplexityInstrumentationTest.groovy b/src/test/groovy/graphql/analysis/MaxQueryComplexityInstrumentationTest.groovy
index 704a1c9c6..3670b4fe1 100644
--- a/src/test/groovy/graphql/analysis/MaxQueryComplexityInstrumentationTest.groovy
+++ b/src/test/groovy/graphql/analysis/MaxQueryComplexityInstrumentationTest.groovy
@@ -3,12 +3,14 @@ package graphql.analysis
import graphql.ExecutionInput
import graphql.TestUtil
import graphql.execution.AbortExecutionException
-import graphql.execution.instrumentation.InstrumentationContext
+import graphql.execution.ExecutionContext
+import graphql.execution.ExecutionContextBuilder
+import graphql.execution.ExecutionId
+import graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters
import graphql.execution.instrumentation.parameters.InstrumentationValidationParameters
import graphql.language.Document
import graphql.parser.Parser
-import graphql.validation.ValidationError
-import graphql.validation.ValidationErrorType
+import graphql.schema.GraphQLSchema
import spock.lang.Specification
import java.util.function.Function
@@ -20,61 +22,6 @@ class MaxQueryComplexityInstrumentationTest extends Specification {
parser.parseDocument(query)
}
- def "doesn't do anything if validation errors occur"() {
- given:
- def schema = TestUtil.schema("""
- type Query{
- bar: String
- }
- """)
- def query = createQuery("""
- { bar { thisIsWrong } }
- """)
- def queryTraversal = Mock(QueryTraverser)
- MaxQueryComplexityInstrumentation maxQueryComplexityInstrumentation = new MaxQueryComplexityInstrumentation(6) {
-
- @Override
- QueryTraverser newQueryTraverser(InstrumentationValidationParameters parameters) {
- return queryTraversal
- }
- }
- ExecutionInput executionInput = Mock(ExecutionInput)
- InstrumentationValidationParameters validationParameters = new InstrumentationValidationParameters(executionInput, query, schema, null)
- InstrumentationContext instrumentationContext = maxQueryComplexityInstrumentation.beginValidation(validationParameters)
- when:
- instrumentationContext.onCompleted([new ValidationError(ValidationErrorType.SubSelectionNotAllowed)], null)
- then:
- 0 * queryTraversal._(_)
-
- }
-
- def "doesn't do anything if exception was thrown"() {
- given:
- def schema = TestUtil.schema("""
- type Query{
- bar: String
- }
- """)
- def query = createQuery("""
- { bar { thisIsWrong } }
- """)
- def queryTraversal = Mock(QueryTraverser)
- MaxQueryComplexityInstrumentation maxQueryComplexityInstrumentation = new MaxQueryComplexityInstrumentation(6) {
-
- @Override
- QueryTraverser newQueryTraverser(InstrumentationValidationParameters parameters) {
- return queryTraversal
- }
- }
- ExecutionInput executionInput = Mock(ExecutionInput)
- InstrumentationValidationParameters validationParameters = new InstrumentationValidationParameters(executionInput, query, schema, null)
- InstrumentationContext instrumentationContext = maxQueryComplexityInstrumentation.beginValidation(validationParameters)
- when:
- instrumentationContext.onCompleted(null, new RuntimeException())
- then:
- 0 * queryTraversal._(_)
-
- }
def "default complexity calculator"() {
given:
@@ -93,16 +40,16 @@ class MaxQueryComplexityInstrumentationTest extends Specification {
""")
MaxQueryComplexityInstrumentation queryComplexityInstrumentation = new MaxQueryComplexityInstrumentation(10)
ExecutionInput executionInput = Mock(ExecutionInput)
- InstrumentationValidationParameters validationParameters = new InstrumentationValidationParameters(executionInput, query, schema, null)
- InstrumentationContext instrumentationContext = queryComplexityInstrumentation.beginValidation(validationParameters)
+ InstrumentationExecuteOperationParameters executeOperationParameters = createExecuteOperationParameters(queryComplexityInstrumentation, executionInput, query, schema)
when:
- instrumentationContext.onCompleted(null, null)
+ queryComplexityInstrumentation.beginExecuteOperation(executeOperationParameters)
then:
def e = thrown(AbortExecutionException)
e.message == "maximum query complexity exceeded 11 > 10"
}
+
def "complexity calculator works with __typename field with score 0"() {
given:
def schema = TestUtil.schema("""
@@ -115,10 +62,9 @@ class MaxQueryComplexityInstrumentationTest extends Specification {
""")
MaxQueryComplexityInstrumentation queryComplexityInstrumentation = new MaxQueryComplexityInstrumentation(1)
ExecutionInput executionInput = Mock(ExecutionInput)
- InstrumentationValidationParameters validationParameters = new InstrumentationValidationParameters(executionInput, query, schema, null)
- InstrumentationContext instrumentationContext = queryComplexityInstrumentation.beginValidation(validationParameters)
+ InstrumentationExecuteOperationParameters executeOperationParameters = createExecuteOperationParameters(queryComplexityInstrumentation, executionInput, query, schema)
when:
- instrumentationContext.onCompleted(null, null)
+ queryComplexityInstrumentation.beginExecuteOperation(executeOperationParameters)
then:
def e = thrown(AbortExecutionException)
e.message == "maximum query complexity exceeded 2 > 1"
@@ -143,10 +89,9 @@ class MaxQueryComplexityInstrumentationTest extends Specification {
def calculator = Mock(FieldComplexityCalculator)
MaxQueryComplexityInstrumentation queryComplexityInstrumentation = new MaxQueryComplexityInstrumentation(5, calculator)
ExecutionInput executionInput = Mock(ExecutionInput)
- InstrumentationValidationParameters validationParameters = new InstrumentationValidationParameters(executionInput, query, schema, null)
- InstrumentationContext instrumentationContext = queryComplexityInstrumentation.beginValidation(validationParameters)
+ InstrumentationExecuteOperationParameters executeOperationParameters = createExecuteOperationParameters(queryComplexityInstrumentation, executionInput, query, schema)
when:
- instrumentationContext.onCompleted(null, null)
+ queryComplexityInstrumentation.beginExecuteOperation(executeOperationParameters)
then:
1 * calculator.calculate({ FieldComplexityEnvironment env -> env.field.name == "scalar" }, 0) >> 10
@@ -171,22 +116,23 @@ class MaxQueryComplexityInstrumentationTest extends Specification {
def query = createQuery("""
{f2: foo {scalar foo{scalar}} f1: foo { foo {foo {foo {foo{foo{scalar}}}}}} }
""")
- Boolean test = false
+ Boolean customFunctionCalled = false
Function maxQueryComplexityExceededFunction = new Function() {
@Override
Boolean apply(final QueryComplexityInfo queryComplexityInfo) {
- test = true
+ assert queryComplexityInfo.instrumentationExecuteOperationParameters != null
+ assert queryComplexityInfo.instrumentationValidationParameters != null
+ customFunctionCalled = true
return false
}
}
MaxQueryComplexityInstrumentation queryComplexityInstrumentation = new MaxQueryComplexityInstrumentation(10, maxQueryComplexityExceededFunction)
ExecutionInput executionInput = Mock(ExecutionInput)
- InstrumentationValidationParameters validationParameters = new InstrumentationValidationParameters(executionInput, query, schema, null)
- InstrumentationContext instrumentationContext = queryComplexityInstrumentation.beginValidation(validationParameters)
+ InstrumentationExecuteOperationParameters executeOperationParameters = createExecuteOperationParameters(queryComplexityInstrumentation, executionInput, query, schema)
when:
- instrumentationContext.onCompleted(null, null)
+ queryComplexityInstrumentation.beginExecuteOperation(executeOperationParameters)
then:
- test == true
+ customFunctionCalled
notThrown(Exception)
}
@@ -205,14 +151,29 @@ class MaxQueryComplexityInstrumentationTest extends Specification {
MaxQueryComplexityInstrumentation queryComplexityInstrumentation = new MaxQueryComplexityInstrumentation(0)
ExecutionInput executionInput = Mock(ExecutionInput)
- InstrumentationValidationParameters validationParameters = new InstrumentationValidationParameters(executionInput, query, schema, null)
- InstrumentationContext instrumentationContext = queryComplexityInstrumentation.beginValidation(validationParameters)
+ InstrumentationExecuteOperationParameters executeOperationParameters = createExecuteOperationParameters(queryComplexityInstrumentation, executionInput, query, schema)
when:
- instrumentationContext.onCompleted(null, null)
+ queryComplexityInstrumentation.beginExecuteOperation(executeOperationParameters)
then:
def e = thrown(AbortExecutionException)
e.message == "maximum query complexity exceeded 1 > 0"
}
+
+ private InstrumentationExecuteOperationParameters createExecuteOperationParameters(MaxQueryComplexityInstrumentation queryComplexityInstrumentation, ExecutionInput executionInput, Document query, GraphQLSchema schema) {
+ // we need to run N steps to create instrumentation state
+ def instrumentationState = queryComplexityInstrumentation.createState(null)
+ def validationParameters = new InstrumentationValidationParameters(executionInput, query, schema, instrumentationState)
+ queryComplexityInstrumentation.beginValidation(validationParameters)
+ def executionContext = executionCtx(executionInput, query, schema)
+ def executeOperationParameters = new InstrumentationExecuteOperationParameters(executionContext).withNewState(instrumentationState)
+ executeOperationParameters
+ }
+
+ private ExecutionContext executionCtx(ExecutionInput executionInput, Document query, GraphQLSchema schema) {
+ ExecutionContextBuilder.newExecutionContextBuilder()
+ .executionInput(executionInput).document(query).graphQLSchema(schema).executionId(ExecutionId.generate())
+ .build()
+ }
}
diff --git a/src/test/groovy/graphql/analysis/MaxQueryDepthInstrumentationTest.groovy b/src/test/groovy/graphql/analysis/MaxQueryDepthInstrumentationTest.groovy
index 5a386786e..11ac79bc7 100644
--- a/src/test/groovy/graphql/analysis/MaxQueryDepthInstrumentationTest.groovy
+++ b/src/test/groovy/graphql/analysis/MaxQueryDepthInstrumentationTest.groovy
@@ -1,14 +1,16 @@
package graphql.analysis
import graphql.ExecutionInput
+import graphql.GraphQL
import graphql.TestUtil
import graphql.execution.AbortExecutionException
-import graphql.execution.instrumentation.InstrumentationContext
-import graphql.execution.instrumentation.parameters.InstrumentationValidationParameters
+import graphql.execution.ExecutionContext
+import graphql.execution.ExecutionContextBuilder
+import graphql.execution.ExecutionId
+import graphql.execution.instrumentation.parameters.InstrumentationExecuteOperationParameters
import graphql.language.Document
import graphql.parser.Parser
-import graphql.validation.ValidationError
-import graphql.validation.ValidationErrorType
+import graphql.schema.GraphQLSchema
import spock.lang.Specification
import java.util.function.Function
@@ -21,63 +23,7 @@ class MaxQueryDepthInstrumentationTest extends Specification {
}
- def "doesn't do anything if validation errors occur"() {
- given:
- def schema = TestUtil.schema("""
- type Query{
- bar: String
- }
- """)
- def query = createQuery("""
- { bar { thisIsWrong } }
- """)
- def queryTraversal = Mock(QueryTraverser)
- MaxQueryDepthInstrumentation maximumQueryDepthInstrumentation = new MaxQueryDepthInstrumentation(6) {
-
- @Override
- QueryTraverser newQueryTraverser(InstrumentationValidationParameters parameters) {
- return queryTraversal
- }
- }
- ExecutionInput executionInput = Mock(ExecutionInput)
- InstrumentationValidationParameters validationParameters = new InstrumentationValidationParameters(executionInput, query, schema, null)
- InstrumentationContext instrumentationContext = maximumQueryDepthInstrumentation.beginValidation(validationParameters)
- when:
- instrumentationContext.onCompleted([new ValidationError(ValidationErrorType.SubSelectionNotAllowed)], null)
- then:
- 0 * queryTraversal._(_)
-
- }
-
- def "doesn't do anything if exception was thrown"() {
- given:
- def schema = TestUtil.schema("""
- type Query{
- bar: String
- }
- """)
- def query = createQuery("""
- { bar { thisIsWrong } }
- """)
- def queryTraversal = Mock(QueryTraverser)
- MaxQueryDepthInstrumentation maximumQueryDepthInstrumentation = new MaxQueryDepthInstrumentation(6) {
-
- @Override
- QueryTraverser newQueryTraverser(InstrumentationValidationParameters parameters) {
- return queryTraversal
- }
- }
- ExecutionInput executionInput = Mock(ExecutionInput)
- InstrumentationValidationParameters validationParameters = new InstrumentationValidationParameters(executionInput, query, schema, null)
- InstrumentationContext instrumentationContext = maximumQueryDepthInstrumentation.beginValidation(validationParameters)
- when:
- instrumentationContext.onCompleted(null, new RuntimeException())
- then:
- 0 * queryTraversal._(_)
-
- }
-
- def "throws exception"() {
+ def "throws exception if too deep"() {
given:
def schema = TestUtil.schema("""
type Query{
@@ -94,16 +40,16 @@ class MaxQueryDepthInstrumentationTest extends Specification {
""")
MaxQueryDepthInstrumentation maximumQueryDepthInstrumentation = new MaxQueryDepthInstrumentation(6)
ExecutionInput executionInput = Mock(ExecutionInput)
- InstrumentationValidationParameters validationParameters = new InstrumentationValidationParameters(executionInput, query, schema, null)
- InstrumentationContext instrumentationContext = maximumQueryDepthInstrumentation.beginValidation(validationParameters)
+ def executionContext = executionCtx(executionInput, query, schema)
+ def executeOperationParameters = new InstrumentationExecuteOperationParameters(executionContext)
when:
- instrumentationContext.onCompleted(null, null)
+ maximumQueryDepthInstrumentation.beginExecuteOperation(executeOperationParameters)
then:
def e = thrown(AbortExecutionException)
e.message.contains("maximum query depth exceeded 7 > 6")
}
- def "doesn't throw exception"() {
+ def "doesn't throw exception if not deep enough"() {
given:
def schema = TestUtil.schema("""
type Query{
@@ -120,10 +66,10 @@ class MaxQueryDepthInstrumentationTest extends Specification {
""")
MaxQueryDepthInstrumentation maximumQueryDepthInstrumentation = new MaxQueryDepthInstrumentation(7)
ExecutionInput executionInput = Mock(ExecutionInput)
- InstrumentationValidationParameters validationParameters = new InstrumentationValidationParameters(executionInput, query, schema, null)
- InstrumentationContext instrumentationContext = maximumQueryDepthInstrumentation.beginValidation(validationParameters)
+ def executionContext = executionCtx(executionInput, query, schema)
+ def executeOperationParameters = new InstrumentationExecuteOperationParameters(executionContext)
when:
- instrumentationContext.onCompleted(null, null)
+ maximumQueryDepthInstrumentation.beginExecuteOperation(executeOperationParameters)
then:
notThrown(Exception)
}
@@ -143,22 +89,52 @@ class MaxQueryDepthInstrumentationTest extends Specification {
def query = createQuery("""
{f1: foo {foo {foo {scalar}}} f2: foo { foo {foo {foo {foo{foo{scalar}}}}}} }
""")
- Boolean test = false
+ Boolean calledFunction = false
Function maxQueryDepthExceededFunction = new Function() {
@Override
Boolean apply(final QueryDepthInfo queryDepthInfo) {
- test = true
+ calledFunction = true
return false
}
}
MaxQueryDepthInstrumentation maximumQueryDepthInstrumentation = new MaxQueryDepthInstrumentation(6, maxQueryDepthExceededFunction)
ExecutionInput executionInput = Mock(ExecutionInput)
- InstrumentationValidationParameters validationParameters = new InstrumentationValidationParameters(executionInput, query, schema, null)
- InstrumentationContext instrumentationContext = maximumQueryDepthInstrumentation.beginValidation(validationParameters)
+ def executionContext = executionCtx(executionInput, query, schema)
+ def executeOperationParameters = new InstrumentationExecuteOperationParameters(executionContext)
when:
- instrumentationContext.onCompleted(null, null)
+ maximumQueryDepthInstrumentation.beginExecuteOperation(executeOperationParameters)
then:
- test == true
+ calledFunction
notThrown(Exception)
}
+
+ def "coercing null variables that are marked as non nullable wont blow up early"() {
+
+ given:
+ def schema = TestUtil.schema("""
+ type Query {
+ field(arg : String!) : String
+ }
+ """)
+
+ MaxQueryDepthInstrumentation maximumQueryDepthInstrumentation = new MaxQueryDepthInstrumentation(6)
+ def graphQL = GraphQL.newGraphQL(schema).instrumentation(maximumQueryDepthInstrumentation).build()
+
+ when:
+ def query = '''
+ query x($var : String!) {
+ field(arg : $var)
+ }
+ '''
+ def executionInput = ExecutionInput.newExecutionInput(query).variables(["var": null]).build()
+ def er = graphQL.execute(executionInput)
+
+ then:
+ !er.errors.isEmpty()
+ }
+
+ private ExecutionContext executionCtx(ExecutionInput executionInput, Document query, GraphQLSchema schema) {
+ ExecutionContextBuilder.newExecutionContextBuilder()
+ .executionInput(executionInput).document(query).graphQLSchema(schema).executionId(ExecutionId.generate()).build()
+ }
}
diff --git a/src/test/groovy/graphql/execution/ValuesResolverTest.groovy b/src/test/groovy/graphql/execution/ValuesResolverTest.groovy
index 83a357725..783fb1cdc 100644
--- a/src/test/groovy/graphql/execution/ValuesResolverTest.groovy
+++ b/src/test/groovy/graphql/execution/ValuesResolverTest.groovy
@@ -495,7 +495,25 @@ class ValuesResolverTest extends Specification {
then:
def error = thrown(NonNullableValueCoercedAsNullException)
- error.message == "Variable 'foo' has coerced Null value for NonNull type 'String!'"
+ error.message == "Variable 'foo' has an invalid value: Variable 'foo' has coerced Null value for NonNull type 'String!'"
+ }
+
+ def "coerceVariableValues: if variableType is a list of Non-Nullable type, and element value is null, throw a query error"() {
+ given:
+ def schema = TestUtil.schemaWithInputType(list(nonNull(GraphQLString)))
+
+ def defaultValueForFoo = new ArrayValue([new StringValue("defaultValueForFoo")])
+ def type = new ListType(new NonNullType(new TypeName("String")))
+ VariableDefinition fooVarDef = new VariableDefinition("foo", type, defaultValueForFoo)
+
+ def variableValuesMap = ["foo": [null]]
+
+ when:
+ resolver.coerceVariableValues(schema, [fooVarDef], variableValuesMap)
+
+ then:
+ def error = thrown(NonNullableValueCoercedAsNullException)
+ error.message == "Variable 'foo' has an invalid value: Coerced Null value for NonNull type 'String!'"
}
// Note: use NullValue defined in Field when it exists,
diff --git a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy
index 1bfedf779..82c38ce42 100644
--- a/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy
+++ b/src/test/groovy/graphql/introspection/IntrospectionResultToSchemaTest.groovy
@@ -104,13 +104,11 @@ class IntrospectionResultToSchemaTest extends Specification {
then:
result == """type QueryType implements Query {
- hero(
- \"\"\"
+ hero(\"\"\"
comment about episode
on two lines
\"\"\"
- episode: Episode
- foo: String = \"bar\"): Character @deprecated(reason: "killed off character")
+ episode: Episode, foo: String = \"bar\"): Character @deprecated(reason: "killed off character")
}"""
}
@@ -212,9 +210,13 @@ class IntrospectionResultToSchemaTest extends Specification {
then:
result == """"A character in the Star Wars Trilogy"
interface Character {
+ "The id of the character."
id: String!
+ "The name of the character."
name: String
+ "The friends of the character, or an empty list if they have none."
friends: [Character]
+ "Which movies they appear in."
appearsIn: [Episode]
}"""
@@ -260,8 +262,11 @@ interface Character {
then:
result == """"One of the films in the Star Wars Trilogy"
enum Episode {
+ "Released in 1977."
NEWHOPE
+ "Released in 1980."
EMPIRE
+ "Released in 1983."
JEDI @deprecated(reason: "killed by clones")
}"""
@@ -404,47 +409,61 @@ input CharacterInput {
}
type QueryType {
- hero(
- "If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode."
+ hero("If omitted, returns the hero of the whole saga. If provided, returns the hero of that particular episode."
episode: Episode): Character
- human(
- "id of the human"
+ human("id of the human"
id: String!): Human
- droid(
- "id of the droid"
+ droid("id of the droid"
id: String!): Droid
}
"A character in the Star Wars Trilogy"
interface Character {
+ "The id of the character."
id: String!
+ "The name of the character."
name: String
+ "The friends of the character, or an empty list if they have none."
friends: [Character]
+ "Which movies they appear in."
appearsIn: [Episode]
}
"One of the films in the Star Wars Trilogy"
enum Episode {
+ "Released in 1977."
NEWHOPE
+ "Released in 1980."
EMPIRE
+ "Released in 1983."
JEDI
}
"A humanoid creature in the Star Wars universe."
type Human implements Character {
+ "The id of the human."
id: String!
+ "The name of the human."
name: String
+ "The friends of the human, or an empty list if they have none."
friends: [Character]
+ "Which movies they appear in."
appearsIn: [Episode]
+ "The home planet of the human, or null if unknown."
homePlanet: String
}
"A mechanical creature in the Star Wars universe."
type Droid implements Character {
+ "The id of the droid."
id: String!
+ "The name of the droid."
name: String
+ "The friends of the droid, or an empty list if they have none."
friends: [Character]
+ "Which movies they appear in."
appearsIn: [Episode]
+ "The primary function of the droid."
primaryFunction: String
}
"""
@@ -492,14 +511,17 @@ type Episode {
" Simpson seasons"
enum Season {
+ " the beginning"
Season1
Season2
Season3
Season4
+ " Another one"
Season5
Season6
Season7
Season8
+ " Not really the last one :-)"
Season9
}
@@ -966,4 +988,4 @@ scalar EmployeeRef
scalar EmployeeRef
'''
}
-}
\ No newline at end of file
+}
diff --git a/src/test/groovy/graphql/language/AstPrinterTest.groovy b/src/test/groovy/graphql/language/AstPrinterTest.groovy
index bb7024e8b..54e5eb2d9 100644
--- a/src/test/groovy/graphql/language/AstPrinterTest.groovy
+++ b/src/test/groovy/graphql/language/AstPrinterTest.groovy
@@ -472,6 +472,26 @@ type Query {
}
+ def "print field descriptions"() {
+ def query = '''type Query {
+ "description"
+ field(
+ "description"
+ a: String): String
+}
+'''
+ def document = parse(query)
+ String output = printAst(document)
+ expect:
+ output == '''type Query {
+ "description"
+ field(
+ "description"
+ a: String): String
+}
+'''
+ }
+
def "print empty description"() {
def query = '''
""
diff --git a/src/test/groovy/graphql/parser/ParserTest.groovy b/src/test/groovy/graphql/parser/ParserTest.groovy
index d2423c7fe..99b132ef2 100644
--- a/src/test/groovy/graphql/parser/ParserTest.groovy
+++ b/src/test/groovy/graphql/parser/ParserTest.groovy
@@ -42,6 +42,7 @@ import graphql.language.VariableDefinition
import graphql.language.VariableReference
import org.antlr.v4.runtime.CommonTokenStream
import org.antlr.v4.runtime.ParserRuleContext
+import spock.lang.Issue
import spock.lang.Specification
import spock.lang.Unroll
@@ -373,6 +374,28 @@ class ParserTest extends Specification {
helloField.comments.collect { c -> c.content } == [" this is some comment, which should be captured"]
}
+ @Issue("https://github.com/graphql-java/graphql-java/issues/2767")
+ def "parser does not transform comments to AST nodes when ParserOptions.captureLineComments(false)"() {
+ given:
+ def input = """
+ { # this is some comment, which should be captured
+ hello(arg: "hello, world" ) # test
+ }
+ """
+ def parserOptionsWithoutCaptureLineComments = ParserOptions.newParserOptions()
+ .captureLineComments(false)
+ .build()
+
+ when:
+ def document = new Parser().parseDocument(input, parserOptionsWithoutCaptureLineComments)
+ Field helloField = (document.definitions[0] as OperationDefinition).selectionSet.selections[0] as Field
+
+ then:
+ isEqual(helloField, new Field("hello", [new Argument("arg", new StringValue("hello, world"))]))
+ assert helloField.comments.isEmpty() // No single-line comments on lone fields
+ assert document.comments.isEmpty() // No single-line comments in entire document
+ }
+
@Unroll
def "parse floatValue #floatString"() {
given:
@@ -1118,7 +1141,7 @@ triple3 : """edge cases \\""" "" " \\"" \\" edge cases"""
then:
doc != null
count == 9
- tokens == ["query" , "{", "f" , "(", "arg", ":", "1", ")", "}"]
+ tokens == ["query", "{", "f", "(", "arg", ":", "1", ")", "}"]
when: "integration test to prove it be supplied via EI"
@@ -1138,7 +1161,7 @@ triple3 : """edge cases \\""" "" " \\"" \\" edge cases"""
then:
er.errors.size() == 0
count == 9
- tokens == ["query" , "{", "f" , "(", "arg", ":", "1", ")", "}"]
+ tokens == ["query", "{", "f", "(", "arg", ":", "1", ")", "}"]
}
}
diff --git a/src/test/java/graphql/normalized/ValueToVariableValueCompilerTest.groovy b/src/test/java/graphql/normalized/ValueToVariableValueCompilerTest.groovy
new file mode 100644
index 000000000..58143c5b2
--- /dev/null
+++ b/src/test/java/graphql/normalized/ValueToVariableValueCompilerTest.groovy
@@ -0,0 +1,118 @@
+package graphql.normalized
+
+import graphql.language.ArrayValue
+import graphql.language.BooleanValue
+import graphql.language.EnumValue
+import graphql.language.FloatValue
+import graphql.language.IntValue
+import graphql.language.NullValue
+import graphql.language.ObjectField
+import graphql.language.ObjectValue
+import graphql.language.StringValue
+import graphql.schema.idl.TypeUtil
+import spock.lang.Specification
+
+class ValueToVariableValueCompilerTest extends Specification {
+
+ def "cam handle different ast Value objects"() {
+
+ expect:
+ def actual = ValueToVariableValueCompiler.normalisedValueToVariableValue(value)
+ actual == expected
+
+ where:
+ value | expected
+ NullValue.of() | null
+ IntValue.of(666) | 666
+ StringValue.of("str") | "str"
+ BooleanValue.of(true) | true
+ FloatValue.of(999d) | 999d
+ EnumValue.of("enumValue") | "enumValue"
+ ObjectValue.newObjectValue()
+ .objectField(ObjectField.newObjectField().name("a").value(IntValue.of(64)).build())
+ .objectField(ObjectField.newObjectField().name("b").value(StringValue.of("65")).build())
+ .build() | [a: 64, b: "65"]
+ ArrayValue.newArrayValue()
+ .value(IntValue.of(9))
+ .value(StringValue.of("10"))
+ .value(EnumValue.of("enum"))
+ .build() | [9, "10", "enum"]
+
+ }
+
+ def "can handle NormalizedInputValue values that are literals"() {
+ expect:
+ def niv = new NormalizedInputValue("TypeName", value)
+ def actual = ValueToVariableValueCompiler.normalisedValueToVariableValue(niv)
+ actual == expected
+
+ where:
+ value | expected
+ NullValue.of() | null
+ IntValue.of(666) | 666
+ StringValue.of("str") | "str"
+ BooleanValue.of(true) | true
+ FloatValue.of(999d) | 999d
+ EnumValue.of("enumValue") | "enumValue"
+ ObjectValue.newObjectValue()
+ .objectField(ObjectField.newObjectField().name("a").value(IntValue.of(64)).build())
+ .objectField(ObjectField.newObjectField().name("b").value(StringValue.of("65")).build())
+ .build() | [a: 64, b: "65"]
+ ArrayValue.newArrayValue()
+ .value(IntValue.of(9))
+ .value(StringValue.of("10"))
+ .value(EnumValue.of("enum"))
+ .build() | [9, "10", "enum"]
+
+
+ }
+
+ def "can handle NormalizedInputValue values that are not literals"() {
+ expect:
+ def niv = new NormalizedInputValue("TypeName", value)
+ def actual = ValueToVariableValueCompiler.normalisedValueToVariableValue(niv)
+ actual == expected
+
+ where:
+ value | expected
+ null | null
+ [IntValue.of(666), IntValue.of(664)] | [666, 664]
+ [a: IntValue.of(666), b: IntValue.of(664)] | [a: 666, b: 664]
+
+ // at present we dont handle straight up java objects like 123 because
+ // the ValueResolver never produces them during
+ // ValueResolver.getNormalizedVariableValues say - this is debatable behavior
+ // but for now this is what we do
+ }
+
+
+ def "can print variables as expected"() {
+ expect:
+ def niv = new NormalizedInputValue(typeName, value)
+ def actual = ValueToVariableValueCompiler.normalizedInputValueToVariable(niv, varCount)
+ actual.value == expectedValue
+ actual.variableReference.name == expectedVarName
+ actual.definition.name == expectedVarName
+ TypeUtil.simplePrint(actual.definition.type) == typeName
+
+ where:
+ value | varCount | typeName | expectedValue | expectedVarName
+ NullValue.newNullValue().build() | 1 | "ID" | null | "v1"
+ IntValue.of(666) | 2 | "Int!" | 666 | "v2"
+ StringValue.of("str") | 3 | "String" | "str" | "v3"
+ BooleanValue.of(true) | 4 | "Boolean!" | true | "v4"
+ FloatValue.of(999d) | 5 | "Float" | 999d | "v5"
+ EnumValue.of("enumValue") | 6 | "Foo!" | "enumValue" | "v6"
+ ObjectValue.newObjectValue()
+ .objectField(ObjectField.newObjectField().name("a").value(IntValue.of(64)).build())
+ .objectField(ObjectField.newObjectField().name("b").value(StringValue.of("65")).build())
+ .build() | 7 | "ObjectType" | [a: 64, b: "65"] | "v7"
+ ArrayValue.newArrayValue()
+ .value(IntValue.of(9))
+ .value(StringValue.of("10"))
+ .value(EnumValue.of("enum"))
+ .build() | 8 | "ArrayType" | [9, "10", "enum"] | "v8"
+
+
+ }
+}