123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614 |
- /*
- * Public Domain Software
- *
- * I (Matthias Ladkau) am the author of the source code in this file.
- * I have placed the source code in this file in the public domain.
- *
- * For further information see: http://creativecommons.org/publicdomain/zero/1.0/
- */
- package parser
- import (
- "encoding/json"
- "fmt"
- "os"
- "strings"
- "testing"
- )
- func TestSimpleExpressionPrinting(t *testing.T) {
- input := `query {
- likeStory(storyID: 12345) {
- story {
- likeCount
- }
- }
- }`
- expectedOutput := `
- Document
- ExecutableDefinition
- OperationDefinition
- OperationType: query
- SelectionSet
- Field
- Name: likeStory
- Arguments
- Argument
- Name: storyID
- Value: 12345
- SelectionSet
- Field
- Name: story
- SelectionSet
- Field
- Name: likeCount
- `[1:]
- if err := testPrettyPrinting(input, expectedOutput,
- input); err != nil {
- t.Error(err)
- return
- }
- /*
- From the spec 2.9.4 Strings
- Since block strings represent freeform text often used in indented positions,
- the string value semantics of a block string excludes uniform indentation and
- blank initial and trailing lines via BlockStringValue().
- For example, the following operation containing a block string:
- mutation {
- sendEmail(message: """
- Hello,
- World!
- Yours,
- GraphQL.
- """)
- }
- Is identical to the standard quoted string:
- mutation {
- sendEmail(message: "Hello,\n World!\n\nYours,\n GraphQL.")
- }
- */
- input = `{
- foo(bar: """
- Hello,
- World!
- Yours,
- GraphQL.
- """) # Block string value
- }
- `
- expectedOutput = `
- Document
- ExecutableDefinition
- OperationDefinition
- SelectionSet
- Field
- Name: foo
- Arguments
- Argument
- Name: bar
- Value: Hello,
- World!
- Yours,
- GraphQL.
- `[1:]
- astres, err := ParseWithRuntime("mytest", input, &TestRuntimeProvider{})
- if err != nil || fmt.Sprint(astres) != expectedOutput {
- t.Error(fmt.Sprintf("Unexpected parser output:\n%v expected was:\n%v Error: %v", astres, expectedOutput, err))
- return
- }
- ppOutput := `{
- foo(bar: """Hello,
- World!
- Yours,
- GraphQL.""")
- }`
- ppres, err := PrettyPrint(astres)
- if err != nil || ppres != ppOutput {
- fmt.Fprintf(os.Stderr, "#\n%v#", ppres)
- t.Error(fmt.Sprintf("Unexpected result:\n%v\nError: %v", ppres, err))
- return
- }
- val := astres.Children[0].Children[0].Children[0].Children[0].Children[1].Children[0].Children[1].Token.Val
- if val != "Hello,\n World!\n\nYours,\n GraphQL." {
- t.Error("Unexpected result:", val)
- }
- input = `{
- foo(bar: $Hello) # Variable value
- foo(bar: 1) # Int value
- foo(bar: 1.1) # Float value
- foo(bar: "Hello") # String value
- foo(bar: false) # Boolean value
- foo(bar: null) # Null value
- foo(bar: MOBILE_WEB) # Enum value
- foo(bar: [1,2,[A,"B"]]) # List value
- foo(bar: {foo:"bar"
- foo2 : [12],
- foo3 : { X:Y }
- }) # Object value
- }
- `
- expectedOutput = `
- Document
- ExecutableDefinition
- OperationDefinition
- SelectionSet
- Field
- Name: foo
- Arguments
- Argument
- Name: bar
- Variable: Hello
- Field
- Name: foo
- Arguments
- Argument
- Name: bar
- Value: 1
- Field
- Name: foo
- Arguments
- Argument
- Name: bar
- Value: 1.1
- Field
- Name: foo
- Arguments
- Argument
- Name: bar
- Value: Hello
- Field
- Name: foo
- Arguments
- Argument
- Name: bar
- Value: false
- Field
- Name: foo
- Arguments
- Argument
- Name: bar
- Value: null
- Field
- Name: foo
- Arguments
- Argument
- Name: bar
- EnumValue: MOBILE_WEB
- Field
- Name: foo
- Arguments
- Argument
- Name: bar
- ListValue
- Value: 1
- Value: 2
- ListValue
- EnumValue: A
- Value: B
- Field
- Name: foo
- Arguments
- Argument
- Name: bar
- ObjectValue
- ObjectField: foo
- Value: bar
- ObjectField: foo2
- ListValue
- Value: 12
- ObjectField: foo3
- ObjectValue
- ObjectField: X
- EnumValue: Y
- `[1:]
- expectedPPResult := `{
- foo(bar: $Hello)
- foo(bar: 1)
- foo(bar: 1.1)
- foo(bar: "Hello")
- foo(bar: false)
- foo(bar: null)
- foo(bar: MOBILE_WEB)
- foo(bar: [1, 2, [A, "B"]])
- foo(bar: {foo : "bar", foo2 : [12], foo3 : {X : Y}})
- }`
- if err := testPrettyPrinting(input, expectedOutput,
- expectedPPResult); err != nil {
- t.Error(err)
- return
- }
- input = `{
- my : field
- }`
- expectedOutput = `
- Document
- ExecutableDefinition
- OperationDefinition
- SelectionSet
- Field
- Alias: my
- Name: field
- `[1:]
- if err := testPrettyPrinting(input, expectedOutput,
- input); err != nil {
- t.Error(err)
- return
- }
- input = `query getBozoProfile ($devicePicSize: Int, $foo: bar=123) {
- user(id: 4) {
- id
- name
- profilePic(size: $devicePicSize)
- }
- }`
- expectedOutput = `
- Document
- ExecutableDefinition
- OperationDefinition
- OperationType: query
- Name: getBozoProfile
- VariableDefinitions
- VariableDefinition
- Variable: devicePicSize
- Type: Int
- VariableDefinition
- Variable: foo
- Type: bar
- DefaultValue: 123
- SelectionSet
- Field
- Name: user
- Arguments
- Argument
- Name: id
- Value: 4
- SelectionSet
- Field
- Name: id
- Field
- Name: name
- Field
- Name: profilePic
- Arguments
- Argument
- Name: size
- Variable: devicePicSize
- `[1:]
- if err := testPrettyPrinting(input, expectedOutput,
- input); err != nil {
- t.Error(err)
- return
- }
- input = `
- query withNestedFragments {
- user(id: 4) {
- friends(first: 10) {
- ...friendFields
- }
- mutualFriends(first: 10) {
- ...friendFields
- }
- }
- }
- fragment friendFields on User {
- id
- name
- ...standardProfilePic
- }
- fragment standardProfilePic on User {
- profilePic(size: 50)
- }`[1:]
- expectedOutput = `
- Document
- ExecutableDefinition
- OperationDefinition
- OperationType: query
- Name: withNestedFragments
- SelectionSet
- Field
- Name: user
- Arguments
- Argument
- Name: id
- Value: 4
- SelectionSet
- Field
- Name: friends
- Arguments
- Argument
- Name: first
- Value: 10
- SelectionSet
- FragmentSpread: friendFields
- Field
- Name: mutualFriends
- Arguments
- Argument
- Name: first
- Value: 10
- SelectionSet
- FragmentSpread: friendFields
- ExecutableDefinition
- FragmentDefinition
- FragmentName: friendFields
- TypeCondition: User
- SelectionSet
- Field
- Name: id
- Field
- Name: name
- FragmentSpread: standardProfilePic
- ExecutableDefinition
- FragmentDefinition
- FragmentName: standardProfilePic
- TypeCondition: User
- SelectionSet
- Field
- Name: profilePic
- Arguments
- Argument
- Name: size
- Value: 50
- `[1:]
- if err := testPrettyPrinting(input, expectedOutput,
- input); err != nil {
- t.Error(err)
- return
- }
- input = `
- query inlineFragmentTyping {
- profiles(handles: ["zuck", "cocacola"]) {
- handle
- ... on User {
- friends {
- count
- }
- }
- ... on Page {
- likers {
- count
- }
- }
- }
- }`[1:]
- expectedOutput = `
- Document
- ExecutableDefinition
- OperationDefinition
- OperationType: query
- Name: inlineFragmentTyping
- SelectionSet
- Field
- Name: profiles
- Arguments
- Argument
- Name: handles
- ListValue
- Value: zuck
- Value: cocacola
- SelectionSet
- Field
- Name: handle
- InlineFragment
- TypeCondition: User
- SelectionSet
- Field
- Name: friends
- SelectionSet
- Field
- Name: count
- InlineFragment
- TypeCondition: Page
- SelectionSet
- Field
- Name: likers
- SelectionSet
- Field
- Name: count
- `[1:]
- if err := testPrettyPrinting(input, expectedOutput,
- input); err != nil {
- t.Error(err)
- return
- }
- input = `
- {
- my : field(size: 4) @include(if: true) @id() @foo(x: 1, y: "z")
- }`[1:]
- expectedOutput = `
- Document
- ExecutableDefinition
- OperationDefinition
- SelectionSet
- Field
- Alias: my
- Name: field
- Arguments
- Argument
- Name: size
- Value: 4
- Directives
- Directive
- Name: include
- Arguments
- Argument
- Name: if
- Value: true
- Directive
- Name: id
- Arguments
- Directive
- Name: foo
- Arguments
- Argument
- Name: x
- Value: 1
- Argument
- Name: y
- Value: z
- `[1:]
- if err := testPrettyPrinting(input, expectedOutput,
- input); err != nil {
- t.Error(err)
- return
- }
- }
- func TestErrorCases(t *testing.T) {
- astres, _ := ParseWithRuntime("mytest", `{ a }`, &TestRuntimeProvider{})
- astres.Children[0].Name = "foo"
- _, err := PrettyPrint(astres)
- if err == nil || err.Error() != "Could not find template for foo (tempkey: foo_1)" {
- t.Error("Unexpected result:", err)
- return
- }
- astres, err = ParseWithRuntime("mytest", `{ a(b:"""a"a""" x:""){ d} }`, &TestRuntimeProvider{})
- if err != nil {
- t.Error(err)
- return
- }
- pp, _ := PrettyPrint(astres)
- astres, err = ParseWithRuntime("mytest", pp, &TestRuntimeProvider{})
- if err != nil {
- t.Error(err)
- return
- }
- if astres.String() != `
- Document
- ExecutableDefinition
- OperationDefinition
- SelectionSet
- Field
- Name: a
- Arguments
- Argument
- Name: b
- Value: a"a
- Argument
- Name: x
- Value:
- SelectionSet
- Field
- Name: d
- `[1:] {
- t.Error("Unexpected result:", astres)
- return
- }
- plainAST := astres.Plain()
- plainAST["children"].([]map[string]interface{})[0]["name"] = "Value"
- _, err = ASTFromPlain(plainAST)
- if err == nil || err.Error() != "Found plain ast value node without a value: Value" {
- t.Error("Unexpected result:", err)
- return
- }
- delete(plainAST["children"].([]map[string]interface{})[0], "name")
- _, err = ASTFromPlain(plainAST)
- if err == nil || !strings.HasPrefix(err.Error(), "Found plain ast node without a name") {
- t.Error("Unexpected result:", err)
- return
- }
- }
- func testPPOut(input string) (string, error) {
- var ppres string
- astres, err := ParseWithRuntime("mytest", input, &TestRuntimeProvider{})
- if err == nil {
- ppres, err = PrettyPrint(astres)
- }
- return ppres, err
- }
- func testPrettyPrinting(input, astOutput, ppOutput string) error {
- astres, err := ParseWithRuntime("mytest", input, &TestRuntimeProvider{})
- if err != nil || fmt.Sprint(astres) != astOutput {
- return fmt.Errorf("Unexpected parser output:\n%v expected was:\n%v Error: %v", astres, astOutput, err)
- }
- ppres, err := PrettyPrint(astres)
- if err != nil || ppres != ppOutput {
- fmt.Fprintf(os.Stderr, "#\n%v#", ppres)
- return fmt.Errorf("Unexpected result:\n%v\nError: %v", ppres, err)
- }
- // Make sure the pretty printed result is valid and gets the same parse tree
- astres2, err := ParseWithRuntime("mytest", ppres, &TestRuntimeProvider{})
- if err != nil || fmt.Sprint(astres2) != astOutput {
- return fmt.Errorf("Unexpected parser output from pretty print string:\n%v expected was:\n%v Error: %v", astres2, astOutput, err)
- }
- mAST, _ := json.Marshal(astres2.Plain())
- var plainAST interface{}
- json.Unmarshal(mAST, &plainAST)
- ast, err := ASTFromPlain(plainAST.(map[string]interface{}))
- if err != nil {
- return fmt.Errorf("Could not build AST from plain AST: %v", err)
- }
- ppres2, err := PrettyPrint(ast)
- if err != nil {
- return fmt.Errorf("Could not pretty print plain AST: %v", err)
- }
- if ppres != ppres2 {
- return fmt.Errorf("Unexpected pretty print - normal:\n%v\nFrom plain:\n%v", ppres, ppres2)
- }
- return nil
- }
|