Skip to content

Commit

Permalink
validation: ProvidedNonNullArguments
Browse files Browse the repository at this point in the history
  • Loading branch information
neelance committed Mar 22, 2017
1 parent c741ea8 commit 4584498
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 22 deletions.
2 changes: 1 addition & 1 deletion internal/tests/testdata/export.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ require('./src/validation/__tests__/LoneAnonymousOperation-test');
// require('./src/validation/__tests__/NoUnusedVariables-test');
// require('./src/validation/__tests__/OverlappingFieldsCanBeMerged-test');
// require('./src/validation/__tests__/PossibleFragmentSpreads-test');
// require('./src/validation/__tests__/ProvidedNonNullArguments-test');
require('./src/validation/__tests__/ProvidedNonNullArguments-test');
// require('./src/validation/__tests__/ScalarLeafs-test');
require('./src/validation/__tests__/UniqueArgumentNames-test');
// require('./src/validation/__tests__/UniqueDirectivesPerLocation-test');
Expand Down
160 changes: 160 additions & 0 deletions internal/tests/testdata/tests.json
Original file line number Diff line number Diff line change
Expand Up @@ -1621,6 +1621,166 @@
}
]
},
{
"name": "Validate: Provided required arguments/ignores unknown arguments",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n dog {\n isHousetrained(unknownArgument: true)\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Provided required arguments/Valid non-nullable value/Arg on optional arg",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n dog {\n isHousetrained(atOtherHomes: true)\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Provided required arguments/Valid non-nullable value/No Arg on optional arg",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n dog {\n isHousetrained\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Provided required arguments/Valid non-nullable value/Multiple args",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n complicatedArgs {\n multipleReqs(req1: 1, req2: 2)\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Provided required arguments/Valid non-nullable value/Multiple args reverse order",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n complicatedArgs {\n multipleReqs(req2: 2, req1: 1)\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Provided required arguments/Valid non-nullable value/No args on multiple optional",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n complicatedArgs {\n multipleOpts\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Provided required arguments/Valid non-nullable value/One arg on multiple optional",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n complicatedArgs {\n multipleOpts(opt1: 1)\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Provided required arguments/Valid non-nullable value/Second arg on multiple optional",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n complicatedArgs {\n multipleOpts(opt2: 1)\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Provided required arguments/Valid non-nullable value/Multiple reqs on mixedList",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n complicatedArgs {\n multipleOptAndReq(req1: 3, req2: 4)\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Provided required arguments/Valid non-nullable value/Multiple reqs and one opt on mixedList",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n complicatedArgs {\n multipleOptAndReq(req1: 3, req2: 4, opt1: 5)\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Provided required arguments/Valid non-nullable value/All reqs and opts on mixedList",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n complicatedArgs {\n multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6)\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Provided required arguments/Invalid non-nullable value/Missing one non-nullable argument",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n complicatedArgs {\n multipleReqs(req2: 2)\n }\n }\n ",
"errors": [
{
"message": "Field \"multipleReqs\" argument \"req1\" of type \"Int!\" is required but not provided.",
"locations": [
{
"line": 4,
"column": 13
}
]
}
]
},
{
"name": "Validate: Provided required arguments/Invalid non-nullable value/Missing multiple non-nullable arguments",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n complicatedArgs {\n multipleReqs\n }\n }\n ",
"errors": [
{
"message": "Field \"multipleReqs\" argument \"req1\" of type \"Int!\" is required but not provided.",
"locations": [
{
"line": 4,
"column": 13
}
]
},
{
"message": "Field \"multipleReqs\" argument \"req2\" of type \"Int!\" is required but not provided.",
"locations": [
{
"line": 4,
"column": 13
}
]
}
]
},
{
"name": "Validate: Provided required arguments/Invalid non-nullable value/Incorrect value and missing argument",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n complicatedArgs {\n multipleReqs(req1: \"one\")\n }\n }\n ",
"errors": [
{
"message": "Field \"multipleReqs\" argument \"req2\" of type \"Int!\" is required but not provided.",
"locations": [
{
"line": 4,
"column": 13
}
]
}
]
},
{
"name": "Validate: Provided required arguments/Directive arguments/ignores unknown directives",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n dog @unknown\n }\n ",
"errors": []
},
{
"name": "Validate: Provided required arguments/Directive arguments/with directives of valid types",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n dog @include(if: true) {\n name\n }\n human @skip(if: false) {\n name\n }\n }\n ",
"errors": []
},
{
"name": "Validate: Provided required arguments/Directive arguments/with directive with missing types",
"rule": "ProvidedNonNullArguments",
"query": "\n {\n dog @include {\n name @skip\n }\n }\n ",
"errors": [
{
"message": "Directive \"@include\" argument \"if\" of type \"Boolean!\" is required but not provided.",
"locations": [
{
"line": 3,
"column": 15
}
]
},
{
"message": "Directive \"@skip\" argument \"if\" of type \"Boolean!\" is required but not provided.",
"locations": [
{
"line": 4,
"column": 18
}
]
}
]
},
{
"name": "Validate: Unique argument names/no arguments on field",
"rule": "UniqueArgumentNames",
Expand Down
50 changes: 29 additions & 21 deletions internal/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,17 +110,10 @@ func (c *context) validateSelection(sel query.Selection, t common.Type) {

c.validateArgumentNames(sel.Arguments)
if f != nil {
for _, selArg := range sel.Arguments {
arg := f.Args.Get(selArg.Name.Name)
if arg == nil {
c.addErr(selArg.Name.Loc, "KnownArgumentNames", "Unknown argument %q on field %q of type %q.", selArg.Name.Name, sel.Name, t)
continue
}
value := selArg.Value
if ok, reason := validateValue(value.Value, arg.Type); !ok {
c.addErr(value.Loc, "ArgumentsOfCorrectType", "Argument %q has invalid value %s.\n%s", arg.Name.Name, stringify(value.Value), reason)
}
}
c.validateArguments(sel.Arguments, f.Args, sel.Loc,
func() string { return fmt.Sprintf("field %q of type %q", sel.Name, t) },
func() string { return fmt.Sprintf("Field %q", sel.Name) },
)
}

var ft common.Type
Expand Down Expand Up @@ -206,16 +199,10 @@ func (c *context) validateDirectives(loc string, directives map[string]*common.D
c.addErr(d.Name.Loc, "KnownDirectives", "Directive %q may not be used on %s.", name, loc)
}

for _, arg := range d.Args {
iv := dd.Args.Get(arg.Name.Name)
if iv == nil {
c.addErr(arg.Name.Loc, "KnownArgumentNames", "Unknown argument %q on directive %q.", arg.Name.Name, "@"+name)
continue
}
if ok, reason := validateValue(arg.Value.Value, iv.Type); !ok {
c.addErr(arg.Value.Loc, "ArgumentsOfCorrectType", "Argument %q has invalid value %s.\n%s", arg.Name.Name, stringify(arg.Value.Value), reason)
}
}
c.validateArguments(d.Args, dd.Args, d.Name.Loc,
func() string { return fmt.Sprintf("directive %q", "@"+d.Name.Name) },
func() string { return fmt.Sprintf("Directive %q", "@"+d.Name.Name) },
)
}
return
}
Expand All @@ -235,6 +222,27 @@ func (c *context) validateArgumentNames(args common.ArgumentList) {
}
}

func (c *context) validateArguments(args common.ArgumentList, argDecls common.InputValueList, loc errors.Location, owner1, owner2 func() string) {
for _, selArg := range args {
arg := argDecls.Get(selArg.Name.Name)
if arg == nil {
c.addErr(selArg.Name.Loc, "KnownArgumentNames", "Unknown argument %q on %s.", selArg.Name.Name, owner1())
continue
}
value := selArg.Value
if ok, reason := validateValue(value.Value, arg.Type); !ok {
c.addErr(value.Loc, "ArgumentsOfCorrectType", "Argument %q has invalid value %s.\n%s", arg.Name.Name, stringify(value.Value), reason)
}
}
for _, decl := range argDecls {
if _, ok := decl.Type.(*common.NonNull); ok {
if _, ok := args.Get(decl.Name.Name); !ok {
c.addErr(loc, "ProvidedNonNullArguments", "%s argument %q of type %q is required but not provided.", owner2(), decl.Name.Name, decl.Type)
}
}
}
}

func validateValue(v interface{}, t common.Type) (bool, string) {
if nn, ok := t.(*common.NonNull); ok {
if v == nil {
Expand Down

0 comments on commit 4584498

Please sign in to comment.