func TestSchemaParser_UnionWithTwoTypes(t *testing.T) { body := `union Hello = Wo | Rld` astDoc := parse(t, body) expected := ast.NewDocument(&ast.Document{ Loc: testLoc(0, 22), Definitions: []ast.Node{ ast.NewUnionDefinition(&ast.UnionDefinition{ Loc: testLoc(0, 22), Name: ast.NewName(&ast.Name{ Value: "Hello", Loc: testLoc(6, 11), }), Types: []*ast.Named{ ast.NewNamed(&ast.Named{ Loc: testLoc(14, 16), Name: ast.NewName(&ast.Name{ Value: "Wo", Loc: testLoc(14, 16), }), }), ast.NewNamed(&ast.Named{ Loc: testLoc(19, 22), Name: ast.NewName(&ast.Name{ Value: "Rld", Loc: testLoc(19, 22), }), }), }, }), }, }) if !reflect.DeepEqual(astDoc, expected) { t.Fatalf("unexpected document, expected: %v, got: %v", expected, astDoc) } }
func TestSchemaParser_DoubleValueEnum(t *testing.T) { body := `enum Hello { WO, RLD }` astDoc := parse(t, body) expected := ast.NewDocument(&ast.Document{ Loc: testLoc(0, 22), Definitions: []ast.Node{ ast.NewEnumDefinition(&ast.EnumDefinition{ Loc: testLoc(0, 22), Name: ast.NewName(&ast.Name{ Value: "Hello", Loc: testLoc(5, 10), }), Values: []*ast.EnumValueDefinition{ ast.NewEnumValueDefinition(&ast.EnumValueDefinition{ Name: ast.NewName(&ast.Name{ Value: "WO", Loc: testLoc(13, 15), }), Loc: testLoc(13, 15), }), ast.NewEnumValueDefinition(&ast.EnumValueDefinition{ Name: ast.NewName(&ast.Name{ Value: "RLD", Loc: testLoc(17, 20), }), Loc: testLoc(17, 20), }), }, }), }, }) if !reflect.DeepEqual(astDoc, expected) { t.Fatalf("unexpected document, expected: %v, got: %v", expected, astDoc) } }
func TestSchemaParser_SimpleTypeInheritingInterface(t *testing.T) { body := `type Hello implements World { }` astDoc := parse(t, body) expected := ast.NewDocument(&ast.Document{ Loc: testLoc(0, 31), Definitions: []ast.Node{ ast.NewObjectDefinition(&ast.ObjectDefinition{ Loc: testLoc(0, 31), Name: ast.NewName(&ast.Name{ Value: "Hello", Loc: testLoc(5, 10), }), Interfaces: []*ast.Named{ ast.NewNamed(&ast.Named{ Name: ast.NewName(&ast.Name{ Value: "World", Loc: testLoc(22, 27), }), Loc: testLoc(22, 27), }), }, Fields: []*ast.FieldDefinition{}, }), }, }) if !reflect.DeepEqual(astDoc, expected) { t.Fatalf("unexpected document, expected: %v, got: %v", expected, astDoc) } }
func TestSchemaParser_SimpleFieldWithListArg(t *testing.T) { body := ` type Hello { world(things: [String]): String }` astDoc := parse(t, body) expected := ast.NewDocument(&ast.Document{ Loc: testLoc(1, 49), Definitions: []ast.Node{ ast.NewObjectDefinition(&ast.ObjectDefinition{ Loc: testLoc(1, 49), Name: ast.NewName(&ast.Name{ Value: "Hello", Loc: testLoc(6, 11), }), Interfaces: []*ast.Named{}, Fields: []*ast.FieldDefinition{ ast.NewFieldDefinition(&ast.FieldDefinition{ Loc: testLoc(16, 47), Name: ast.NewName(&ast.Name{ Value: "world", Loc: testLoc(16, 21), }), Arguments: []*ast.InputValueDefinition{ ast.NewInputValueDefinition(&ast.InputValueDefinition{ Loc: testLoc(22, 38), Name: ast.NewName(&ast.Name{ Value: "things", Loc: testLoc(22, 28), }), Type: ast.NewList(&ast.List{ Loc: testLoc(30, 38), Type: ast.NewNamed(&ast.Named{ Loc: testLoc(31, 37), Name: ast.NewName(&ast.Name{ Value: "String", Loc: testLoc(31, 37), }), }), }), DefaultValue: nil, }), }, Type: ast.NewNamed(&ast.Named{ Loc: testLoc(41, 47), Name: ast.NewName(&ast.Name{ Value: "String", Loc: testLoc(41, 47), }), }), }), }, }), }, }) if !reflect.DeepEqual(astDoc, expected) { t.Fatalf("unexpected document, expected: %v, got: %v", expected, astDoc) } }
func TestSchemaParser_SimpleFieldWithArgWithDefaultValue(t *testing.T) { body := ` type Hello { world(flag: Boolean = true): String }` astDoc := parse(t, body) expected := ast.NewDocument(&ast.Document{ Loc: testLoc(1, 53), Definitions: []ast.Node{ ast.NewObjectDefinition(&ast.ObjectDefinition{ Loc: testLoc(1, 53), Name: ast.NewName(&ast.Name{ Value: "Hello", Loc: testLoc(6, 11), }), Interfaces: []*ast.Named{}, Fields: []*ast.FieldDefinition{ ast.NewFieldDefinition(&ast.FieldDefinition{ Loc: testLoc(16, 51), Name: ast.NewName(&ast.Name{ Value: "world", Loc: testLoc(16, 21), }), Arguments: []*ast.InputValueDefinition{ ast.NewInputValueDefinition(&ast.InputValueDefinition{ Loc: testLoc(22, 42), Name: ast.NewName(&ast.Name{ Value: "flag", Loc: testLoc(22, 26), }), Type: ast.NewNamed(&ast.Named{ Loc: testLoc(28, 35), Name: ast.NewName(&ast.Name{ Value: "Boolean", Loc: testLoc(28, 35), }), }), DefaultValue: ast.NewBooleanValue(&ast.BooleanValue{ Value: true, Loc: testLoc(38, 42), }), }), }, Type: ast.NewNamed(&ast.Named{ Loc: testLoc(45, 51), Name: ast.NewName(&ast.Name{ Value: "String", Loc: testLoc(45, 51), }), }), }), }, }), }, }) if !reflect.DeepEqual(astDoc, expected) { t.Fatalf("unexpected document, expected: %v, got: %v", expected, astDoc) } }
func TestAcceptsOptionToNotIncludeSource(t *testing.T) { opts := ParseOptions{ NoSource: true, } params := ParseParams{ Source: "{ field }", Options: opts, } document, err := Parse(params) if err != nil { t.Fatalf("unexpected error: %v", err) } oDef := ast.OperationDefinition{ Kind: "OperationDefinition", Loc: &ast.Location{ Start: 0, End: 9, }, Operation: "query", Directives: []*ast.Directive{}, SelectionSet: &ast.SelectionSet{ Kind: "SelectionSet", Loc: &ast.Location{ Start: 0, End: 9, }, Selections: []ast.Selection{ &ast.Field{ Kind: "Field", Loc: &ast.Location{ Start: 2, End: 7, }, Name: &ast.Name{ Kind: "Name", Loc: &ast.Location{ Start: 2, End: 7, }, Value: "field", }, Arguments: []*ast.Argument{}, Directives: []*ast.Directive{}, }, }, }, } expectedDocument := ast.NewDocument(&ast.Document{ Loc: &ast.Location{ Start: 0, End: 9, }, Definitions: []ast.Node{&oDef}, }) if !reflect.DeepEqual(document, expectedDocument) { t.Fatalf("unexpected document, expected: %v, got: %v", expectedDocument, document) } }
func TestSchemaParser_SimpleNonNullType(t *testing.T) { body := ` type Hello { world: String! }` astDoc := parse(t, body) expected := ast.NewDocument(&ast.Document{ Loc: testLoc(1, 32), Definitions: []ast.Node{ ast.NewObjectDefinition(&ast.ObjectDefinition{ Loc: testLoc(1, 32), Name: ast.NewName(&ast.Name{ Value: "Hello", Loc: testLoc(6, 11), }), Interfaces: []*ast.Named{}, Fields: []*ast.FieldDefinition{ ast.NewFieldDefinition(&ast.FieldDefinition{ Loc: testLoc(16, 30), Name: ast.NewName(&ast.Name{ Value: "world", Loc: testLoc(16, 21), }), Arguments: []*ast.InputValueDefinition{}, Type: ast.NewNonNull(&ast.NonNull{ Kind: "NonNullType", Loc: testLoc(23, 30), Type: ast.NewNamed(&ast.Named{ Loc: testLoc(23, 29), Name: ast.NewName(&ast.Name{ Value: "String", Loc: testLoc(23, 29), }), }), }), }), }, }), }, }) if !reflect.DeepEqual(astDoc, expected) { t.Fatalf("unexpected document, expected: %v, got: %v", expected, astDoc) } }
func TestSchemaParser_SimpleExtension(t *testing.T) { body := ` extend type Hello { world: String }` astDoc := parse(t, body) expected := ast.NewDocument(&ast.Document{ Loc: testLoc(1, 38), Definitions: []ast.Node{ ast.NewTypeExtensionDefinition(&ast.TypeExtensionDefinition{ Loc: testLoc(1, 38), Definition: ast.NewObjectDefinition(&ast.ObjectDefinition{ Loc: testLoc(8, 38), Name: ast.NewName(&ast.Name{ Value: "Hello", Loc: testLoc(13, 18), }), Interfaces: []*ast.Named{}, Fields: []*ast.FieldDefinition{ ast.NewFieldDefinition(&ast.FieldDefinition{ Loc: testLoc(23, 36), Name: ast.NewName(&ast.Name{ Value: "world", Loc: testLoc(23, 28), }), Arguments: []*ast.InputValueDefinition{}, Type: ast.NewNamed(&ast.Named{ Loc: testLoc(30, 36), Name: ast.NewName(&ast.Name{ Value: "String", Loc: testLoc(30, 36), }), }), }), }, }), }), }, }) if !reflect.DeepEqual(astDoc, expected) { t.Fatalf("unexpected document, expected: %v, got: %v", expected, astDoc) } }
func TestSchemaParser_Scalar(t *testing.T) { body := `scalar Hello` astDoc := parse(t, body) expected := ast.NewDocument(&ast.Document{ Loc: testLoc(0, 12), Definitions: []ast.Node{ ast.NewScalarDefinition(&ast.ScalarDefinition{ Loc: testLoc(0, 12), Name: ast.NewName(&ast.Name{ Value: "Hello", Loc: testLoc(7, 12), }), }), }, }) if !reflect.DeepEqual(astDoc, expected) { t.Fatalf("unexpected document, expected: %v, got: %v", expected, astDoc) } }
func TestSchemaParser_SimpleInputObject(t *testing.T) { body := ` input Hello { world: String }` astDoc := parse(t, body) expected := ast.NewDocument(&ast.Document{ Loc: testLoc(1, 32), Definitions: []ast.Node{ ast.NewInputObjectDefinition(&ast.InputObjectDefinition{ Loc: testLoc(1, 32), Name: ast.NewName(&ast.Name{ Value: "Hello", Loc: testLoc(7, 12), }), Fields: []*ast.InputValueDefinition{ ast.NewInputValueDefinition(&ast.InputValueDefinition{ Loc: testLoc(17, 30), Name: ast.NewName(&ast.Name{ Value: "world", Loc: testLoc(17, 22), }), Type: ast.NewNamed(&ast.Named{ Loc: testLoc(24, 30), Name: ast.NewName(&ast.Name{ Value: "String", Loc: testLoc(24, 30), }), }), DefaultValue: nil, }), }, }), }, }) if !reflect.DeepEqual(astDoc, expected) { t.Fatalf("unexpected document, expected: %v, got: %v", expected, astDoc) } }
func TestSchemaParser_SimpleInterface(t *testing.T) { body := ` interface Hello { world: String }` astDoc := parse(t, body) expected := ast.NewDocument(&ast.Document{ Loc: testLoc(1, 36), Definitions: []ast.Node{ ast.NewInterfaceDefinition(&ast.InterfaceDefinition{ Loc: testLoc(1, 36), Name: ast.NewName(&ast.Name{ Value: "Hello", Loc: testLoc(11, 16), }), Fields: []*ast.FieldDefinition{ ast.NewFieldDefinition(&ast.FieldDefinition{ Loc: testLoc(21, 34), Name: ast.NewName(&ast.Name{ Value: "world", Loc: testLoc(21, 26), }), Arguments: []*ast.InputValueDefinition{}, Type: ast.NewNamed(&ast.Named{ Loc: testLoc(28, 34), Name: ast.NewName(&ast.Name{ Value: "String", Loc: testLoc(28, 34), }), }), }), }, }), }, }) if !reflect.DeepEqual(astDoc, expected) { t.Fatalf("unexpected document, expected: %v, got: %v", expected, astDoc) } }
func parseDocument(parser *Parser) (*ast.Document, error) { start := parser.Token.Start var nodes []ast.Node for { if skp, err := skip(parser, lexer.TokenKind[lexer.EOF]); err != nil { return nil, err } else if skp { break } if peek(parser, lexer.TokenKind[lexer.BRACE_L]) { node, err := parseOperationDefinition(parser) if err != nil { return nil, err } nodes = append(nodes, node) } else if peek(parser, lexer.TokenKind[lexer.NAME]) { switch parser.Token.Value { case "query": fallthrough case "mutation": fallthrough case "subscription": // Note: subscription is an experimental non-spec addition. node, err := parseOperationDefinition(parser) if err != nil { return nil, err } nodes = append(nodes, node) case "fragment": node, err := parseFragmentDefinition(parser) if err != nil { return nil, err } nodes = append(nodes, node) case "type": node, err := parseObjectTypeDefinition(parser) if err != nil { return nil, err } nodes = append(nodes, node) case "interface": node, err := parseInterfaceTypeDefinition(parser) if err != nil { return nil, err } nodes = append(nodes, node) case "union": node, err := parseUnionTypeDefinition(parser) if err != nil { return nil, err } nodes = append(nodes, node) case "scalar": node, err := parseScalarTypeDefinition(parser) if err != nil { return nil, err } nodes = append(nodes, node) case "enum": node, err := parseEnumTypeDefinition(parser) if err != nil { return nil, err } nodes = append(nodes, node) case "input": node, err := parseInputObjectTypeDefinition(parser) if err != nil { return nil, err } nodes = append(nodes, node) case "extend": node, err := parseTypeExtensionDefinition(parser) if err != nil { return nil, err } nodes = append(nodes, node) default: if err := unexpected(parser, lexer.Token{}); err != nil { return nil, err } } } else { if err := unexpected(parser, lexer.Token{}); err != nil { return nil, err } } } return ast.NewDocument(&ast.Document{ Loc: loc(parser, start), Definitions: nodes, }), nil }
func TestParseCreatesAst(t *testing.T) { body := `{ node(id: 4) { id, name } } ` source := source.NewSource(&source.Source{Body: body}) document, err := Parse( ParseParams{ Source: source, Options: ParseOptions{ NoSource: true, }, }, ) if err != nil { t.Fatalf("unexpected error: %v", err) } oDef := ast.OperationDefinition{ Kind: "OperationDefinition", Loc: &ast.Location{ Start: 0, End: 40, }, Operation: "query", Directives: []*ast.Directive{}, SelectionSet: &ast.SelectionSet{ Kind: "SelectionSet", Loc: &ast.Location{ Start: 0, End: 40, }, Selections: []ast.Selection{ &ast.Field{ Kind: "Field", Loc: &ast.Location{ Start: 4, End: 38, }, Name: &ast.Name{ Kind: "Name", Loc: &ast.Location{ Start: 4, End: 8, }, Value: "node", }, Arguments: []*ast.Argument{ { Kind: "Argument", Name: &ast.Name{ Kind: "Name", Loc: &ast.Location{ Start: 9, End: 11, }, Value: "id", }, Value: &ast.IntValue{ Kind: "IntValue", Loc: &ast.Location{ Start: 13, End: 14, }, Value: "4", }, Loc: &ast.Location{ Start: 9, End: 14, }, }, }, Directives: []*ast.Directive{}, SelectionSet: &ast.SelectionSet{ Kind: "SelectionSet", Loc: &ast.Location{ Start: 16, End: 38, }, Selections: []ast.Selection{ &ast.Field{ Kind: "Field", Loc: &ast.Location{ Start: 22, End: 24, }, Name: &ast.Name{ Kind: "Name", Loc: &ast.Location{ Start: 22, End: 24, }, Value: "id", }, Arguments: []*ast.Argument{}, Directives: []*ast.Directive{}, SelectionSet: nil, }, &ast.Field{ Kind: "Field", Loc: &ast.Location{ Start: 30, End: 34, }, Name: &ast.Name{ Kind: "Name", Loc: &ast.Location{ Start: 30, End: 34, }, Value: "name", }, Arguments: []*ast.Argument{}, Directives: []*ast.Directive{}, SelectionSet: nil, }, }, }, }, }, }, } expectedDocument := ast.NewDocument(&ast.Document{ Loc: &ast.Location{ Start: 0, End: 41, }, Definitions: []ast.Node{&oDef}, }) if !reflect.DeepEqual(document, expectedDocument) { t.Fatalf("unexpected document, expected: %v, got: %v", expectedDocument, document.Definitions) } }
func TestParsesMultiByteCharacters_UnicodeText(t *testing.T) { doc := ` # This comment has a фы世界 multi-byte character. { field(arg: "Has a фы世界 multi-byte character.") } ` astDoc := parse(t, doc) expectedASTDoc := ast.NewDocument(&ast.Document{ Loc: ast.NewLocation(&ast.Location{ Start: 67, End: 121, }), Definitions: []ast.Node{ ast.NewOperationDefinition(&ast.OperationDefinition{ Loc: ast.NewLocation(&ast.Location{ Start: 67, End: 119, }), Operation: "query", SelectionSet: ast.NewSelectionSet(&ast.SelectionSet{ Loc: ast.NewLocation(&ast.Location{ Start: 67, End: 119, }), Selections: []ast.Selection{ ast.NewField(&ast.Field{ Loc: ast.NewLocation(&ast.Location{ Start: 67, End: 117, }), Name: ast.NewName(&ast.Name{ Loc: ast.NewLocation(&ast.Location{ Start: 69, End: 74, }), Value: "field", }), Arguments: []*ast.Argument{ ast.NewArgument(&ast.Argument{ Loc: ast.NewLocation(&ast.Location{ Start: 75, End: 116, }), Name: ast.NewName(&ast.Name{ Loc: ast.NewLocation(&ast.Location{ Start: 75, End: 78, }), Value: "arg", }), Value: ast.NewStringValue(&ast.StringValue{ Loc: ast.NewLocation(&ast.Location{ Start: 80, End: 116, }), Value: "Has a фы世界 multi-byte character.", }), }), }, }), }, }), }), }, }) astDocQuery := printer.Print(astDoc) expectedASTDocQuery := printer.Print(expectedASTDoc) if !reflect.DeepEqual(astDocQuery, expectedASTDocQuery) { t.Fatalf("unexpected document, expected: %v, got: %v", astDocQuery, expectedASTDocQuery) } }
func TestSchemaParser_SimpleFieldWithTwoArg(t *testing.T) { body := ` type Hello { world(argOne: Boolean, argTwo: Int): String }` astDoc := parse(t, body) expected := ast.NewDocument(&ast.Document{ Loc: testLoc(1, 61), Definitions: []ast.Node{ ast.NewObjectDefinition(&ast.ObjectDefinition{ Loc: testLoc(1, 61), Name: ast.NewName(&ast.Name{ Value: "Hello", Loc: testLoc(6, 11), }), Interfaces: []*ast.Named{}, Fields: []*ast.FieldDefinition{ ast.NewFieldDefinition(&ast.FieldDefinition{ Loc: testLoc(16, 59), Name: ast.NewName(&ast.Name{ Value: "world", Loc: testLoc(16, 21), }), Arguments: []*ast.InputValueDefinition{ ast.NewInputValueDefinition(&ast.InputValueDefinition{ Loc: testLoc(22, 37), Name: ast.NewName(&ast.Name{ Value: "argOne", Loc: testLoc(22, 28), }), Type: ast.NewNamed(&ast.Named{ Loc: testLoc(30, 37), Name: ast.NewName(&ast.Name{ Value: "Boolean", Loc: testLoc(30, 37), }), }), DefaultValue: nil, }), ast.NewInputValueDefinition(&ast.InputValueDefinition{ Loc: testLoc(39, 50), Name: ast.NewName(&ast.Name{ Value: "argTwo", Loc: testLoc(39, 45), }), Type: ast.NewNamed(&ast.Named{ Loc: testLoc(47, 50), Name: ast.NewName(&ast.Name{ Value: "Int", Loc: testLoc(47, 50), }), }), DefaultValue: nil, }), }, Type: ast.NewNamed(&ast.Named{ Loc: testLoc(53, 59), Name: ast.NewName(&ast.Name{ Value: "String", Loc: testLoc(53, 59), }), }), }), }, }), }, }) if !reflect.DeepEqual(astDoc, expected) { t.Fatalf("unexpected document, expected: %v, got: %v", expected, astDoc) } }