Skip to content

Commit

Permalink
Feature/improve values validation to reflect reference implementation (
Browse files Browse the repository at this point in the history
…wundergraph#447)

* allow integer to be used in place of ID type

* reduce responsibility of valid arguments rule
use testify require instead of panic
update test to use proper rules
move some tests in more proper sections

* add position to values

* make variable errors messages compatible with reference tests
add location to incompatible types error msg
add initial values error messages draft

* remove skips

* partially refactor values validation - fail in exact places when we have more info about fail reason

* handle unexpected null error

* add more precise enum values error msgs

* fix null as a list value
fix single item as a list value

* skip not existing args in valid arguments validation
add a check that default arg value has a non null type

* fix arguments validation when variable is placed inside a fragment but defined on operation

* add basic known arguments rule

* added known arguments names validation rule

* store more precise position for types
fix variables are input types rule

* bring back is satisfies bool flag for flow control

* add an error for missing required input object field

* use Walker.FieldDefinition everywhere
deprecate Walker.FieldDefinitionWithExists
add fallback for old planner to fix old planning tests

* fix logical err in valueSatisfiesTypeDefinitionNode

* fix string for a list test

* add locations helper
split scalar err messages into separate funcs

* add big int value err msg

* add BytesIsValidInt32

* add separate scalar types validation with precise error messages

* add consts for existing rules names and use them for rules maping

* add proper error for unknown input object field
add text position to ast object field

* add proper error for duplicated fields input object
use custom schema for each of test cases for UniqueInputFieldNamesRule test

* add variables default values validation
add values is not an input object type error

* partially fix reporting unknown type for operation

* cleanup error messages

* chore: fix build

* Add failed test cases with boolean args

* add variable error helpers
reorder helper methods
extend validation tests with error messages

* check for default values of nested variable usages

* chore: fix test

* add mapping to reference known arguments rule test

* use ast.InvalidRef everywhere in parser

* use bytes equal and lexer vars for built-in scalar names

* discard changes to legacy planner

* add more error text expectations

* do not resolve definition unredlying type for variables errors

* fix: empty list should be a valid input

Co-authored-by: Alasdair Tran <[email protected]>
  • Loading branch information
Sergiy Petrunin and alasdairtran authored Nov 17, 2022
1 parent 97325bf commit d75b2c0
Show file tree
Hide file tree
Showing 25 changed files with 1,416 additions and 488 deletions.
5 changes: 5 additions & 0 deletions internal/pkg/unsafebytes/unsafebytes.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ func BytesIsValidInt64(byteSlice []byte) bool {
return err == nil
}

func BytesIsValidInt32(byteSlice []byte) bool {
_, err := strconv.ParseInt(*(*string)(unsafe.Pointer(&byteSlice)), 10, 32)
return err == nil
}

func BytesIsValidBool(byteSlice []byte) bool {
_, err := strconv.ParseBool(*(*string)(unsafe.Pointer(&byteSlice)))
return err == nil
Expand Down
17 changes: 14 additions & 3 deletions internal/pkg/unsafebytes/unsafebytes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,20 @@ func TestBytesIsValidFloat32(t *testing.T) {

func TestBytesIsValidInt64(t *testing.T) {
t.Run("valid int", testValidation(BytesIsValidInt64, []byte("123"), true))
t.Run("invalid int", testValidation(BytesIsValidInt64, []byte("1.23"), false))
t.Run("invalid int", testValidation(BytesIsValidInt64, []byte("true"), false))
t.Run("invalid int", testValidation(BytesIsValidInt64, []byte("\"123\""), false))
t.Run("valid big int", testValidation(BytesIsValidInt64, []byte("8293842938492834982"), true))
t.Run("invalid very big int", testValidation(BytesIsValidInt64, []byte("8293842938492834982394"), false))
t.Run("invalid float", testValidation(BytesIsValidInt64, []byte("1.23"), false))
t.Run("invalid bool", testValidation(BytesIsValidInt64, []byte("true"), false))
t.Run("invalid quoted int", testValidation(BytesIsValidInt64, []byte("\"123\""), false))
}

func TestBytesIsValidInt32(t *testing.T) {
t.Run("valid int", testValidation(BytesIsValidInt32, []byte("123"), true))
t.Run("invalid valid big int", testValidation(BytesIsValidInt32, []byte("8293842938492834982"), false))
t.Run("invalid very big int", testValidation(BytesIsValidInt32, []byte("829384293849283498239482938"), false))
t.Run("invalid float", testValidation(BytesIsValidInt32, []byte("1.23"), false))
t.Run("invalid bool", testValidation(BytesIsValidInt32, []byte("true"), false))
t.Run("invalid quoted int", testValidation(BytesIsValidInt32, []byte("\"123\""), false))
}

func TestBytesIsValidBool(t *testing.T) {
Expand Down
7 changes: 4 additions & 3 deletions pkg/ast/ast_argument.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@ type ArgumentList struct {
}

type Argument struct {
Name ByteSliceReference // e.g. foo
Colon position.Position // :
Value Value // e.g. 100 or "Bar"
Name ByteSliceReference // e.g. foo
Colon position.Position // :
Value Value // e.g. 100 or "Bar"
Position position.Position
}

func (d *Document) CopyArgument(ref int) int {
Expand Down
7 changes: 4 additions & 3 deletions pkg/ast/ast_object_field.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import (
// example:
// lon: 12.43
type ObjectField struct {
Name ByteSliceReference // e.g. lon
Colon position.Position // :
Value Value // e.g. 12.43
Name ByteSliceReference // e.g. lon
Colon position.Position // :
Value Value // e.g. 12.43
Position position.Position
}

func (d *Document) CopyObjectField(ref int) int {
Expand Down
21 changes: 12 additions & 9 deletions pkg/ast/ast_type.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ const (
type Type struct {
TypeKind TypeKind // one of Named,List,NonNull
Name ByteSliceReference // e.g. String (only on NamedType)
Open position.Position // [ (only on ListType)
Close position.Position // ] (only on ListType)
Bang position.Position // ! (only on NonNullType)
Position position.Position
Open position.Position // [ (only on ListType)
Close position.Position // ] (only on ListType)
Bang position.Position // ! (only on NonNullType)
OfType int
}

Expand Down Expand Up @@ -76,17 +77,18 @@ func (d *Document) AddType(t Type) (ref int) {
return len(d.Types) - 1
}

func (d *Document) AddNamedTypeByNameRef(nameRef ByteSliceReference) (ref int) {
func (d *Document) AddNamedTypeWithPosition(nameRef ByteSliceReference, position position.Position) (ref int) {
return d.AddType(Type{
TypeKind: TypeKindNamed,
Name: nameRef,
OfType: -1,
Position: position,
})
}

func (d *Document) AddNamedType(name []byte) (ref int) {
nameRef := d.Input.AppendInputBytes(name)
return d.AddNamedTypeByNameRef(nameRef)
return d.AddNamedTypeWithPosition(nameRef, position.Position{})
}

func (d *Document) AddListType(ofType int) (ref int) {
Expand All @@ -99,18 +101,20 @@ func (d *Document) AddListTypeWithPosition(ofType int, open position.Position, c
Open: open,
Close: close,
OfType: ofType,
Position: open,
})
}

func (d *Document) AddNonNullType(ofType int) (ref int) {
return d.AddNonNullTypeWithPosition(ofType, position.Position{})
return d.AddNonNullTypeWithBangPosition(ofType, position.Position{})
}

func (d *Document) AddNonNullTypeWithPosition(ofType int, bang position.Position) (ref int) {
func (d *Document) AddNonNullTypeWithBangPosition(ofType int, bang position.Position) (ref int) {
return d.AddType(Type{
TypeKind: TypeKindNonNull,
Bang: bang,
OfType: ofType,
Position: d.Types[ofType].Position,
})
}

Expand Down Expand Up @@ -216,8 +220,7 @@ func (d *Document) TypesAreCompatibleDeep(left int, right int) bool {

func (d *Document) ResolveTypeNameBytes(ref int) ByteSlice {
resolvedTypeRef := d.ResolveUnderlyingType(ref)
graphqlType := d.Types[resolvedTypeRef]
return d.Input.ByteSlice(graphqlType.Name)
return d.TypeNameBytes(resolvedTypeRef)
}

func (d *Document) ResolveTypeNameString(ref int) string {
Expand Down
5 changes: 5 additions & 0 deletions pkg/ast/ast_val_int_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ func (d *Document) IntValueAsInt32(ref int) (out int32) {
return
}

func (d *Document) IntValueValidInt32(ref int) bool {
in := d.Input.ByteSlice(d.IntValues[ref].Raw)
return unsafebytes.BytesIsValidInt32(in)
}

func (d *Document) IntValue(ref int) IntValue {
return d.IntValues[ref]
}
Expand Down
6 changes: 4 additions & 2 deletions pkg/ast/ast_value.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/wundergraph/graphql-go-tools/internal/pkg/quotes"
"github.com/wundergraph/graphql-go-tools/internal/pkg/unsafebytes"
"github.com/wundergraph/graphql-go-tools/pkg/lexer/literal"
"github.com/wundergraph/graphql-go-tools/pkg/lexer/position"
)

type ValueKind int
Expand All @@ -28,8 +29,9 @@ const (
)

type Value struct {
Kind ValueKind // e.g. 100 or "Bar"
Ref int
Kind ValueKind // e.g. 100 or "Bar"
Ref int
Position position.Position
}

func (d *Document) CopyValue(ref int) int {
Expand Down
Loading

0 comments on commit d75b2c0

Please sign in to comment.