protected override ISyntaxVisitorAction Enter(
            DocumentNode node,
            IDocumentValidatorContext context)
        {
            context.Names.Clear();

            for (int i = 0; i < node.Definitions.Count; i++)
            {
                IDefinitionNode definition = node.Definitions[i];
                if (definition.Kind == NodeKind.FragmentDefinition)
                {
                    string fragmentName = ((FragmentDefinitionNode)definition).Name.Value;
                    if (!context.Names.Add(fragmentName))
                    {
                        context.Errors.Add(
                            ErrorBuilder.New()
                            .SetMessage(
                                "There are multiple fragments with the name " +
                                $"`{fragmentName}`.")
                            .AddLocation(definition)
                            .SetExtension("fragment", fragmentName)
                            .SpecifiedBy("sec-Fragment-Name-Uniqueness")
                            .Build());
                    }
                }
            }

            context.Names.Clear();

            return(Continue);
        }
Esempio n. 2
0
        protected override ISyntaxVisitorAction Enter(
            VariableDefinitionNode node,
            IDocumentValidatorContext context)
        {
            base.Enter(node, context);

            var variableName = node.Variable.Name.Value;

            context.Unused.Add(variableName);
            context.Declared.Add(variableName);

            if (context.Schema.TryGetType(
                    node.Type.NamedType().Name.Value, out INamedType type) &&
                !type.IsInputType())
            {
                context.Errors.Add(context.VariableNotInputType(node, variableName));
            }

            if (!context.Names.Add(variableName))
            {
                context.Errors.Add(context.VariableNameNotUnique(node, variableName));
            }

            return(Skip);
        }
Esempio n. 3
0
        protected override ISyntaxVisitorAction Enter(
            ArgumentNode node,
            IDocumentValidatorContext context)
        {
            if (context.Directives.TryPeek(out DirectiveType directive))
            {
                if (directive.Arguments.TryGetField(node.Name.Value, out Argument? argument))
                {
                    context.InputFields.Push(argument);
                    context.Types.Push(argument.Type);
                    return(Continue);
                }
                context.UnexpectedErrorsDetected = true;
                return(Skip);
            }

            if (context.OutputFields.TryPeek(out IOutputField field))
            {
                if (field.Arguments.TryGetField(node.Name.Value, out IInputField? argument))
                {
                    context.InputFields.Push(argument);
                    context.Types.Push(argument.Type);
                    return(Continue);
                }
                context.UnexpectedErrorsDetected = true;
                return(Skip);
            }

            context.UnexpectedErrorsDetected = true;
            return(Skip);
        }
Esempio n. 4
0
 protected override ISyntaxVisitorAction Enter(
     VariableDefinitionNode node,
     IDocumentValidatorContext context)
 {
     context.Variables[node.Variable.Name.Value] = node;
     return(Continue);
 }
        public void TwoOperationsThatShareVariableName()
        {
            // arrange
            IDocumentValidatorContext context = ValidationUtils.CreateContext();
            DocumentNode query = Utf8GraphQLParser.Parse(@"
                query A($atOtherHomes: Boolean) {
                  ...HouseTrainedFragment
                }

                query B($atOtherHomes: Boolean) {
                  ...HouseTrainedFragment
                }

                fragment HouseTrainedFragment on Query {
                  dog {
                    isHousetrained(atOtherHomes: $atOtherHomes)
                  }
                }
            ");

            context.Prepare(query);

            // act
            Rule.Validate(context, query);

            // assert
            Assert.Empty(context.Errors);
        }
 protected override ISyntaxVisitorAction Enter(
     OperationDefinitionNode node,
     IDocumentValidatorContext context)
 {
     context.List.Push(new List <Expression>());
     return(base.Enter(node, context));
 }
Esempio n. 7
0
        public void UniqueFragments()
        {
            // arrange
            IDocumentValidatorContext context = ValidationUtils.CreateContext();
            DocumentNode query = Utf8GraphQLParser.Parse(@"
                {
                    dog {
                        ...fragmentOne
                        ...fragmentTwo
                    }
                }

                fragment fragmentOne on Dog {
                    name
                }

                fragment fragmentTwo on Dog {
                    owner {
                        name
                    }
                }
            ");

            context.Prepare(query);

            // act
            Rule.Validate(context, query);

            // assert
            Assert.Empty(context.Errors);
        }
        public void UndefinedFragment()
        {
            // arrange
            IDocumentValidatorContext context = ValidationUtils.CreateContext();
            DocumentNode query = Utf8GraphQLParser.Parse(@"
                {
                    dog {
                        ...undefinedFragment
                    }
                }
            ");

            context.Prepare(query);

            // act
            Rule.Validate(context, query);

            // assert
            Assert.Collection(context.Errors,
                              t => Assert.Equal(
                                  "The specified fragment `undefinedFragment` " +
                                  "does not exist.",
                                  t.Message));
            context.Errors.MatchSnapshot();
        }
        public void DefinedFragment()
        {
            // arrange
            IDocumentValidatorContext context = ValidationUtils.CreateContext();
            DocumentNode query = Utf8GraphQLParser.Parse(@"
                {
                    dog {
                        ...definedFragment
                    }
                }

                fragment definedFragment on Dog
                {
                    barkVolume
                }
            ");

            context.Prepare(query);

            // act
            Rule.Validate(context, query);

            // assert
            Assert.Empty(context.Errors);
        }
Esempio n. 10
0
 protected override ISyntaxVisitorAction Enter(
     OperationDefinitionNode node,
     IDocumentValidatorContext context)
 {
     context.Count = 0;
     return(base.Enter(node, context));
 }
Esempio n. 11
0
        protected override ISyntaxVisitorAction Enter(
            FieldNode node,
            IDocumentValidatorContext context)
        {
            if (IntrospectionFields.TypeName.Equals(node.Name.Value))
            {
                context.Count += _options.ComplexityCalculation.Invoke(
                    TypeNameField,
                    node,
                    null,
                    context.OutputFields.Count + 1,
                    context.Path.Count + 1,
                    GetVariable,
                    _options);
                return(Skip);
            }
            else if (context.Types.TryPeek(out IType type) &&
                     type.NamedType() is IComplexOutputType ot &&
                     ot.Fields.TryGetField(node.Name.Value, out IOutputField of))
            {
                context.Count += _options.ComplexityCalculation.Invoke(
                    of,
                    node,
                    of.Directives["cost"].FirstOrDefault()?.ToObject <CostDirective>(),
                    context.OutputFields.Count + 1,
                    context.Path.Count + 1,
                    GetVariable,
                    _options);

                context.OutputFields.Push(of);
                context.Types.Push(of.Type);
                return(Continue);
            }
Esempio n. 12
0
        public static void ExpectValid(
            ISchema schema,
            Action <IValidationBuilder> configure,
            string sourceText)
        {
            // arrange
            var serviceCollection = new ServiceCollection();

            IValidationBuilder builder = serviceCollection
                                         .AddValidation()
                                         .ConfigureValidation(c => c.Modifiers.Add(o => o.Rules.Clear()));

            configure(builder);

            IServiceProvider services = serviceCollection.BuildServiceProvider();
            var rule = services.GetRequiredService <IValidationConfiguration>()
                       .GetRules("Default").First();

            IDocumentValidatorContext context = ValidationUtils.CreateContext(schema);
            DocumentNode query = Utf8GraphQLParser.Parse(sourceText);

            context.Prepare(query);

            // act
            rule.Validate(context, query);

            // assert
            Assert.False(context.UnexpectedErrorsDetected);
            Assert.Empty(context.Errors);
        }
        public void QueryWithTypeSystemDefinitions()
        {
            // arrange
            IDocumentValidatorContext context = ValidationUtils.CreateContext();
            DocumentNode query = Utf8GraphQLParser.Parse(@"
                query getDogName {
                    dog {
                        name
                        color
                    }
                }

                extend type Dog {
                    color: String
                }
            ");

            // act
            Rule.Validate(context, query);

            // assert
            Assert.Collection(context.Errors,
                              t => Assert.Equal(
                                  "A document containing TypeSystemDefinition " +
                                  "is invalid for execution.", t.Message));
            context.Errors.First().MatchSnapshot();
        }
Esempio n. 14
0
        protected override ISyntaxVisitorAction Enter(
            FieldNode node,
            IDocumentValidatorContext context)
        {
            context.Names.Clear();

            if (IntrospectionFields.TypeName.Equals(node.Name.Value))
            {
                ValidateArguments(
                    context, node, node.Arguments,
                    TypeNameField.Arguments, field: TypeNameField);

                return(Skip);
            }
            else if (context.Types.TryPeek(out IType type) &&
                     type.NamedType() is IComplexOutputType ot &&
                     ot.Fields.TryGetField(node.Name.Value, out IOutputField of))
            {
                ValidateArguments(
                    context, node, node.Arguments,
                    of.Arguments, field: of);

                context.OutputFields.Push(of);
                context.Types.Push(of.Type);
                return(Continue);
            }
Esempio n. 15
0
 protected override ISyntaxVisitorAction Enter(
     FragmentDefinitionNode node,
     IDocumentValidatorContext context)
 {
     ValidateDirectiveAreUniquePerLocation(node, context);
     return(Continue);
 }
Esempio n. 16
0
 protected override ISyntaxVisitorAction Enter(
     FieldNode node,
     IDocumentValidatorContext context)
 {
     context.Names.Add((node.Alias ?? node.Name).Value);
     return(Skip);
 }
 protected override ISyntaxVisitorAction Enter(
     DocumentNode node,
     IDocumentValidatorContext context)
 {
     context.List.Push(new List <OperationComplexityAnalyzer>());
     return(base.Enter(node, context));
 }
        public void QueriesWithValidVariableTypes()
        {
            // arrange
            IDocumentValidatorContext context = ValidationUtils.CreateContext();
            DocumentNode query = Utf8GraphQLParser.Parse(@"
                query takesBoolean($atOtherHomes: Boolean) {
                    dog {
                        isHouseTrained(atOtherHomes: $atOtherHomes)
                    }
                }

                query takesComplexInput($complexInput: ComplexInput) {
                    findDog(complex: $complexInput) {
                        name
                    }
                }

                query TakesListOfBooleanBang($booleans: [Boolean!]) {
                    booleanList(booleanListArg: $booleans)
                }
            ");

            context.Prepare(query);

            // act
            Rule.Validate(context, query);

            // assert
            Assert.Empty(context.Errors);
        }
Esempio n. 19
0
        public void Validate(IDocumentValidatorContext context, DocumentNode document)
        {
            if (context is null)
            {
                throw new ArgumentNullException(nameof(context));
            }

            if (document is null)
            {
                throw new ArgumentNullException(nameof(document));
            }

            IDefinitionNode?typeSystemNode = null;

            for (int i = 0; i < document.Definitions.Count; i++)
            {
                IDefinitionNode node = document.Definitions[i];
                if (node.Kind != NodeKind.OperationDefinition &&
                    node.Kind != NodeKind.FragmentDefinition)
                {
                    typeSystemNode = node;
                    break;
                }
            }

            if (typeSystemNode is { })
        public void QueryWithSideBySideFragSpreads()
        {
            // arrange
            IDocumentValidatorContext context = ValidationUtils.CreateContext();
            DocumentNode query = Utf8GraphQLParser.Parse(@"
                {
                    dog {
                        ...dogFragment
                        ...dogFragment
                        ...dogFragment
                        ...dogFragment
                        ...dogFragment
                        ...dogFragment
                        ...dogFragment
                    }
                }

                fragment dogFragment on Dog {
                    name
                }
            ");

            context.Prepare(query);

            // act
            Rule.Validate(context, query);

            // assert
            Assert.Empty(context.Errors);
        }
Esempio n. 21
0
        public void DuplicateFragments()
        {
            // arrange
            IDocumentValidatorContext context = ValidationUtils.CreateContext();
            DocumentNode query = Utf8GraphQLParser.Parse(@"
                {
                    dog {
                        ...fragmentOne
                    }
                }

                fragment fragmentOne on Dog {
                    name
                }

                fragment fragmentOne on Dog {
                    owner {
                        name
                    }
                }
            ");

            context.Prepare(query);

            // act
            Rule.Validate(context, query);

            // assert
            Assert.Collection(context.Errors,
                              t => Assert.Equal(
                                  "There are multiple fragments with the name `fragmentOne`.",
                                  t.Message));
            context.Errors.First().MatchSnapshot();
        }
Esempio n. 22
0
        public void UnusedFragment()
        {
            // arrange
            IDocumentValidatorContext context = ValidationUtils.CreateContext();
            DocumentNode query = Utf8GraphQLParser.Parse(@"
                fragment nameFragment on Dog { # unused
                    name
                }

                {
                    dog {
                        name
                    }
                }
            ");

            context.Prepare(query);

            // act
            Rule.Validate(context, query);

            // assert
            Assert.Collection(context.Errors,
                              t => Assert.Equal(
                                  "The specified fragment `nameFragment` " +
                                  "is not used within the current document.", t.Message));
            context.Errors.MatchSnapshot();
        }
        public void OperationWithTwoVariablesThatHaveTheSameName()
        {
            // arrange
            IDocumentValidatorContext context = ValidationUtils.CreateContext();
            DocumentNode query = Utf8GraphQLParser.Parse(@"
                query houseTrainedQuery($atOtherHomes: Boolean, $atOtherHomes: Boolean) {
                    dog {
                        isHousetrained(atOtherHomes: $atOtherHomes)
                    }
                }
            ");

            context.Prepare(query);

            // act
            Rule.Validate(context, query);

            // assert
            Assert.Single(context.Errors);
            Assert.Collection(context.Errors,
                              t => Assert.Equal(
                                  "A document containing operations that " +
                                  "define more than one variable with the same " +
                                  "name is invalid for execution.", t.Message));
        }
Esempio n. 24
0
        public void UsedNestedFragment()
        {
            // arrange
            IDocumentValidatorContext context = ValidationUtils.CreateContext();
            DocumentNode query = Utf8GraphQLParser.Parse(@"
                fragment nameFragment on Dog {
                    name
                    ... nestedNameFragment
                }

                fragment nestedNameFragment on Dog {
                    name
                }

                {
                    dog {
                        name
                        ... nameFragment
                    }
                }
            ");

            context.Prepare(query);

            // act
            Rule.Validate(context, query);

            // assert
            Assert.Empty(context.Errors);
        }
Esempio n. 25
0
        protected override ISyntaxVisitorAction Enter(
            VariableNode node,
            IDocumentValidatorContext context)
        {
            context.Used.Add(node.Name.Value);

            ISyntaxNode parent = context.Path.Peek();

            IValueNode?defaultValue = parent.Kind switch
            {
                SyntaxKind.Argument => context.InputFields.Peek().DefaultValue,
                SyntaxKind.ObjectField => context.InputFields.Peek().DefaultValue,
                _ => null
            };

            if (context.Variables.TryGetValue(
                    node.Name.Value,
                    out VariableDefinitionNode? variableDefinition) &&
                !IsVariableUsageAllowed(variableDefinition, context.Types.Peek(), defaultValue))
            {
                context.Errors.Add(ErrorHelper.VariableIsNotCompatible(
                                       context, node, variableDefinition));
            }

            return(Skip);
        }
Esempio n. 26
0
        public void FragOnUnion()
        {
            // arrange
            IDocumentValidatorContext context = ValidationUtils.CreateContext();
            DocumentNode query = Utf8GraphQLParser.Parse(@"
                {
                    dog {
                       ... fragOnUnion
                    }
                }

                fragment fragOnUnion on CatOrDog {
                    ... on Dog {
                        name
                    }
                }
            ");

            context.Prepare(query);

            // act
            Rule.Validate(context, query);

            // assert
            Assert.Empty(context.Errors);
        }
Esempio n. 27
0
 protected override ISyntaxVisitorAction Leave(
     DirectiveNode node,
     IDocumentValidatorContext context)
 {
     context.Directives.Pop();
     return(Continue);
 }
Esempio n. 28
0
        public void FragOnScalar()
        {
            // arrange
            IDocumentValidatorContext context = ValidationUtils.CreateContext();
            DocumentNode query = Utf8GraphQLParser.Parse(@"
                {
                    dog {
                       ... fragOnScalar
                    }
                }

                fragment fragOnScalar on Int {
                    something
                }
            ");

            context.Prepare(query);

            // act
            Rule.Validate(context, query);

            // assert
            Assert.Collection(context.Errors,
                              t => Assert.Equal(t.Message,
                                                "Fragments can only be declared on unions, interfaces, " +
                                                "and objects."));
            context.Errors.MatchSnapshot();
        }
Esempio n. 29
0
 protected override ISyntaxVisitorAction Leave(
     VariableDefinitionNode node,
     IDocumentValidatorContext context)
 {
     context.Types.Pop();
     return(base.Enter(node, context));
 }
        private void ValidateFragmentSpreadIsPossible(
            ISyntaxNode node,
            IDocumentValidatorContext context)
        {
            if (context.Types.Count > 1 &&
                context.Types.TryPeek(out IType type) &&
                type.IsComplexType())
            {
                INamedType typeCondition = type.NamedType();
                INamedType parentType    = context.Types[context.Types.Count - 2].NamedType();

                if (!IsCompatibleType(parentType, typeCondition))
                {
                    context.Errors.Add(
                        ErrorBuilder.New()
                        .SetMessage(
                            "The parent type does not match the type condition on the fragment.")
                        .AddLocation(node)
                        .SetPath(context.CreateErrorPath())
                        .SetExtension("typeCondition", typeCondition.Visualize())
                        .SetFragmentName(node)
                        .SpecifiedBy("sec-Fragment-spread-is-possible")
                        .Build());
                }
            }
        }