parser provides useful errors:
  - name: unclosed paren
    input: '{'
    error:
      message: "Expected Name, found <EOF>"
      locations: [{line: 1, column: 2}]

  - name: missing on in fragment
    input: |
      { ...MissingOn }
      fragment MissingOn Type
    error:
      message: 'Expected "on", found Name "Type"'
      locations: [{ line: 2, column: 20 }]

  - name: missing name after alias
    input: '{ field: {} }'
    error:
      message: "Expected Name, found {"
      locations: [{ line: 1, column: 10 }]

  - name: not an operation
    input: 'notanoperation Foo { field }'
    error:
      message: 'Unexpected Name "notanoperation"'
      locations: [{ line: 1, column: 1 }]

  - name: a wild splat appears
    input: '...'
    error:
      message: 'Unexpected ...'
      locations: [{ line: 1, column: 1}]

variables:
  - name: are allowed in args
    input: '{ field(complex: { a: { b: [ $var ] } }) }'

  - name: are not allowed in default args
    input: 'query Foo($x: Complex = { a: { b: [ $var ] } }) { field }'
    error:
      message: 'Unexpected $'
      locations: [{ line: 1, column: 37 }]

  - name: can have directives
    input: 'query ($withDirective: String @first @second, $withoutDirective: String) { f }'
    ast: |
      <QueryDocument>
        Operations: [OperationDefinition]
        - <OperationDefinition>
            Operation: Operation("query")
            VariableDefinitions: [VariableDefinition]
            - <VariableDefinition>
                Variable: "withDirective"
                Type: String
                Directives: [Directive]
                - <Directive>
                    Name: "first"
                - <Directive>
                    Name: "second"
            - <VariableDefinition>
                Variable: "withoutDirective"
                Type: String
            SelectionSet: [Selection]
            - <Field>
                Alias: "f"
                Name: "f"

fragments:
  - name: can not be named 'on'
    input: 'fragment on on on { on }'
    error:
      message: 'Unexpected Name "on"'
      locations: [{ line: 1, column: 10 }]

  - name: can not spread fragments called 'on'
    input: '{ ...on }'
    error:
      message: 'Expected Name, found }'
      locations: [{ line: 1, column: 9 }]

encoding:
  - name: multibyte characters are supported
    input: |
      # This comment has a ਊ multi-byte character.
      { field(arg: "Has a ਊ multi-byte character.") }
    ast: |
      <QueryDocument>
        Operations: [OperationDefinition]
        - <OperationDefinition>
            Operation: Operation("query")
            SelectionSet: [Selection]
            - <Field>
                Alias: "field"
                Name: "field"
                Arguments: [Argument]
                - <Argument>
                    Name: "arg"
                    Value: "Has a ਊ multi-byte character."

keywords are allowed anywhere a name is:
  - name: on
    input: |
      query on {
        ... a
        ... on on { field }
      }
      fragment a on Type {
        on(on: $on)
          @on(on: on)
      }

  - name: subscription
    input: |
      query subscription {
        ... subscription
        ... on subscription { field }
      }
      fragment subscription on Type {
        subscription(subscription: $subscription)
          @subscription(subscription: subscription)
      }

  - name: true
    input: |
      query true {
        ... true
        ... on true { field }
      }
      fragment true on Type {
        true(true: $true)
          @true(true: true)
      }

operations:
  - name: anonymous mutation
    input: 'mutation { mutationField }'

  - name: named mutation
    input: 'mutation Foo { mutationField }'

  - name: anonymous subscription
    input: 'subscription { subscriptionField }'

  - name: named subscription
    input: 'subscription Foo { subscriptionField }'


ast:
  - name: simple query
    input: |
      {
        node(id: 4) {
          id,
          name
        }
      }
    ast: |
      <QueryDocument>
        Operations: [OperationDefinition]
        - <OperationDefinition>
            Operation: Operation("query")
            SelectionSet: [Selection]
            - <Field>
                Alias: "node"
                Name: "node"
                Arguments: [Argument]
                - <Argument>
                    Name: "id"
                    Value: 4
                SelectionSet: [Selection]
                - <Field>
                    Alias: "id"
                    Name: "id"
                - <Field>
                    Alias: "name"
                    Name: "name"

  - name: nameless query with no variables
    input: |
      query {
        node {
          id
        }
      }
    ast: |
      <QueryDocument>
        Operations: [OperationDefinition]
        - <OperationDefinition>
            Operation: Operation("query")
            SelectionSet: [Selection]
            - <Field>
                Alias: "node"
                Name: "node"
                SelectionSet: [Selection]
                - <Field>
                    Alias: "id"
                    Name: "id"

  - name: fragment defined variables
    input: 'fragment a($v: Boolean = false) on t { f(v: $v) }'
    ast: |
      <QueryDocument>
        Fragments: [FragmentDefinition]
        - <FragmentDefinition>
            Name: "a"
            VariableDefinition: [VariableDefinition]
            - <VariableDefinition>
                Variable: "v"
                Type: Boolean
                DefaultValue: false
            TypeCondition: "t"
            SelectionSet: [Selection]
            - <Field>
                Alias: "f"
                Name: "f"
                Arguments: [Argument]
                - <Argument>
                    Name: "v"
                    Value: $v


values:
  - name: null
    input: '{ f(id: null) }'
    ast: |
      <QueryDocument>
        Operations: [OperationDefinition]
        - <OperationDefinition>
            Operation: Operation("query")
            SelectionSet: [Selection]
            - <Field>
                Alias: "f"
                Name: "f"
                Arguments: [Argument]
                - <Argument>
                    Name: "id"
                    Value: null

  - name: strings
    input: '{ f(long: """long""", short: "short") } '
    ast: |
      <QueryDocument>
        Operations: [OperationDefinition]
        - <OperationDefinition>
            Operation: Operation("query")
            SelectionSet: [Selection]
            - <Field>
                Alias: "f"
                Name: "f"
                Arguments: [Argument]
                - <Argument>
                    Name: "long"
                    Value: "long"
                - <Argument>
                    Name: "short"
                    Value: "short"

  - name: list
    input: '{ f(id: [1,2]) }'
    ast: |
      <QueryDocument>
        Operations: [OperationDefinition]
        - <OperationDefinition>
            Operation: Operation("query")
            SelectionSet: [Selection]
            - <Field>
                Alias: "f"
                Name: "f"
                Arguments: [Argument]
                - <Argument>
                    Name: "id"
                    Value: [1,2]

types:
  - name: common types
    input: 'query ($string: String, $int: Int, $arr: [Arr], $notnull: [Arr!]!) { f }'
    ast: |
      <QueryDocument>
        Operations: [OperationDefinition]
        - <OperationDefinition>
            Operation: Operation("query")
            VariableDefinitions: [VariableDefinition]
            - <VariableDefinition>
                Variable: "string"
                Type: String
            - <VariableDefinition>
                Variable: "int"
                Type: Int
            - <VariableDefinition>
                Variable: "arr"
                Type: [Arr]
            - <VariableDefinition>
                Variable: "notnull"
                Type: [Arr!]!
            SelectionSet: [Selection]
            - <Field>
                Alias: "f"
                Name: "f"

large queries:
  - name: kitchen sink
    input: |
      # Copyright (c) 2015-present, Facebook, Inc.
      #
      # This source code is licensed under the MIT license found in the
      # LICENSE file in the root directory of this source tree.

      query queryName($foo: ComplexType, $site: Site = MOBILE) {
        whoever123is: node(id: [123, 456]) {
          id ,
          ... on User @defer {
            field2 {
              id ,
              alias: field1(first:10, after:$foo,) @include(if: $foo) {
                id,
                ...frag
              }
            }
          }
          ... @skip(unless: $foo) {
            id
          }
          ... {
            id
          }
        }
      }

      mutation likeStory {
        like(story: 123) @defer {
          story {
            id
          }
        }
      }

      subscription StoryLikeSubscription($input: StoryLikeSubscribeInput) {
        storyLikeSubscribe(input: $input) {
          story {
            likers {
              count
            }
            likeSentence {
              text
            }
          }
        }
      }

      fragment frag on Friend {
        foo(size: $size, bar: $b, obj: {key: "value", block: """
            block string uses \"""
        """})
      }

      {
        unnamed(truthy: true, falsey: false, nullish: null),
        query
      }
    ast: |
      <QueryDocument>
        Operations: [OperationDefinition]
        - <OperationDefinition>
            Operation: Operation("query")
            Name: "queryName"
            VariableDefinitions: [VariableDefinition]
            - <VariableDefinition>
                Variable: "foo"
                Type: ComplexType
            - <VariableDefinition>
                Variable: "site"
                Type: Site
                DefaultValue: MOBILE
            SelectionSet: [Selection]
            - <Field>
                Alias: "whoever123is"
                Name: "node"
                Arguments: [Argument]
                - <Argument>
                    Name: "id"
                    Value: [123,456]
                SelectionSet: [Selection]
                - <Field>
                    Alias: "id"
                    Name: "id"
                - <InlineFragment>
                    TypeCondition: "User"
                    Directives: [Directive]
                    - <Directive>
                        Name: "defer"
                    SelectionSet: [Selection]
                    - <Field>
                        Alias: "field2"
                        Name: "field2"
                        SelectionSet: [Selection]
                        - <Field>
                            Alias: "id"
                            Name: "id"
                        - <Field>
                            Alias: "alias"
                            Name: "field1"
                            Arguments: [Argument]
                            - <Argument>
                                Name: "first"
                                Value: 10
                            - <Argument>
                                Name: "after"
                                Value: $foo
                            Directives: [Directive]
                            - <Directive>
                                Name: "include"
                                Arguments: [Argument]
                                - <Argument>
                                    Name: "if"
                                    Value: $foo
                            SelectionSet: [Selection]
                            - <Field>
                                Alias: "id"
                                Name: "id"
                            - <FragmentSpread>
                                Name: "frag"
                - <InlineFragment>
                    Directives: [Directive]
                    - <Directive>
                        Name: "skip"
                        Arguments: [Argument]
                        - <Argument>
                            Name: "unless"
                            Value: $foo
                    SelectionSet: [Selection]
                    - <Field>
                        Alias: "id"
                        Name: "id"
                - <InlineFragment>
                    SelectionSet: [Selection]
                    - <Field>
                        Alias: "id"
                        Name: "id"
        - <OperationDefinition>
            Operation: Operation("mutation")
            Name: "likeStory"
            SelectionSet: [Selection]
            - <Field>
                Alias: "like"
                Name: "like"
                Arguments: [Argument]
                - <Argument>
                    Name: "story"
                    Value: 123
                Directives: [Directive]
                - <Directive>
                    Name: "defer"
                SelectionSet: [Selection]
                - <Field>
                    Alias: "story"
                    Name: "story"
                    SelectionSet: [Selection]
                    - <Field>
                        Alias: "id"
                        Name: "id"
        - <OperationDefinition>
            Operation: Operation("subscription")
            Name: "StoryLikeSubscription"
            VariableDefinitions: [VariableDefinition]
            - <VariableDefinition>
                Variable: "input"
                Type: StoryLikeSubscribeInput
            SelectionSet: [Selection]
            - <Field>
                Alias: "storyLikeSubscribe"
                Name: "storyLikeSubscribe"
                Arguments: [Argument]
                - <Argument>
                    Name: "input"
                    Value: $input
                SelectionSet: [Selection]
                - <Field>
                    Alias: "story"
                    Name: "story"
                    SelectionSet: [Selection]
                    - <Field>
                        Alias: "likers"
                        Name: "likers"
                        SelectionSet: [Selection]
                        - <Field>
                            Alias: "count"
                            Name: "count"
                    - <Field>
                        Alias: "likeSentence"
                        Name: "likeSentence"
                        SelectionSet: [Selection]
                        - <Field>
                            Alias: "text"
                            Name: "text"
        - <OperationDefinition>
            Operation: Operation("query")
            SelectionSet: [Selection]
            - <Field>
                Alias: "unnamed"
                Name: "unnamed"
                Arguments: [Argument]
                - <Argument>
                    Name: "truthy"
                    Value: true
                - <Argument>
                    Name: "falsey"
                    Value: false
                - <Argument>
                    Name: "nullish"
                    Value: null
            - <Field>
                Alias: "query"
                Name: "query"
        Fragments: [FragmentDefinition]
        - <FragmentDefinition>
            Name: "frag"
            TypeCondition: "Friend"
            SelectionSet: [Selection]
            - <Field>
                Alias: "foo"
                Name: "foo"
                Arguments: [Argument]
                - <Argument>
                    Name: "size"
                    Value: $size
                - <Argument>
                    Name: "bar"
                    Value: $b
                - <Argument>
                    Name: "obj"
                    Value: {key:"value",block:"block string uses \"\"\""}

fuzzer:
- name: 01
  input: '{__typename{...}}'
  error:
    message: 'Expected {, found }'
    locations: [{ line: 1, column: 16 }]

- name: 02
  input: '{...{__typename{...{}}}}'
  error:
    message: 'expected at least one definition, found }'
    locations: [{ line: 1, column: 21 }]
