Repository: graph-gophers/graphql-go (go)

Issue:
Multiline strings in mutation error
Hello,
I have an issue whereby sending a multiline string in a mutation will return a difficult to understand error message.
I have reproduced this issue on the starwars example in this repo.

**Graphql mutation(not using block strings) that will reproduce the error:**
```
mutation {
  createReview(episode:NEWHOPE, review: {stars: 0, commentary: "1
    2"}) {
    
  }
}
```
**Expected:** Error message indicating that a multiline/un-terminated string was found in the query.
**Actual:** 
```
{
  "errors": [
    {
      "message": "syntax error: unexpected \"2\", expecting Ident",
      "locations": [
        {
          "line": 32,
          "column": 5
        }
      ]
    }
  ]
}
```
Log output: `<input>:31:64: literal not terminated `

Pull request description:
Issue #299: unclear error message in case of multiline string argument
Fix #299 

Package text/scanner, which is used to parse queries, already detects multiline strings as an error. But it only puts log message to console, as it was pointed in the issue description. Scanner can also call a function each time it encounters error 

So the idea of the fix is:
- provide Scanner a function to catch errors
- generate high-level errors in that function
- couple of tests

Patch:
diff --git a/internal/common/lexer.go b/internal/common/lexer.go
index 5807f7a..af385ec 100644
--- a/internal/common/lexer.go
+++ b/internal/common/lexer.go
@@ -30,7 +30,11 @@ func NewLexer(s string, useStringDescriptions bool) *Lexer {
 	}
 	sc.Init(strings.NewReader(s))
 
-	return &Lexer{sc: sc, useStringDescriptions: useStringDescriptions}
+
+	l := Lexer{sc: sc, useStringDescriptions: useStringDescriptions}
+	l.sc.Error = l.CatchScannerError
+
+	return &l
 }
 
 func (l *Lexer) CatchSyntaxError(f func()) (errRes *errors.QueryError) {
@@ -219,3 +223,7 @@ func (l *Lexer) consumeComment() {
 		l.comment.WriteRune(next)
 	}
 }
+
+func (l *Lexer) CatchScannerError(s *scanner.Scanner, msg string) {
+	l.SyntaxError(msg)
+}


Test patch:
diff --git a/internal/common/lexer_test.go b/internal/common/lexer_test.go
index 40e967e..e775a9f 100644
--- a/internal/common/lexer_test.go
+++ b/internal/common/lexer_test.go
@@ -93,3 +93,42 @@ func TestConsume(t *testing.T) {
 		})
 	}
 }
+
+var multilineStringTests = []consumeTestCase {
+	{
+		description: "Oneline strings are okay",
+		definition: `"Hello World"`,
+		expected: "",
+		failureExpected: false,
+		useStringDescriptions: true,		
+	},
+	{
+		description: "Multiline strings are not allowed",
+		definition: `"Hello
+				 World"`,
+		expected: `graphql: syntax error: literal not terminated (line 1, column 1)`,
+		failureExpected: true,
+		useStringDescriptions: true,		
+	},
+}
+
+func TestMultilineString(t *testing.T) {
+	for _, test := range multilineStringTests {
+		t.Run(test.description, func(t *testing.T) {
+			lex := common.NewLexer(test.definition, test.useStringDescriptions)
+
+			err := lex.CatchSyntaxError(func() { lex.ConsumeWhitespace() })
+			if test.failureExpected && err == nil {
+				t.Fatalf("Test '%s' should fail", test.description)
+			} else if test.failureExpected && err != nil {
+				if test.expected != err.Error() {
+					t.Fatalf("Test '%s' failed with wrong error: '%s'. Error should be: '%s'", test.description, err.Error(), test.expected)
+				}
+			}
+
+			if !test.failureExpected && err != nil {
+				t.Fatalf("Test '%s' failed with error: '%s'", test.description, err.Error())
+			}
+		})
+	}	
+}