aboutsummaryrefslogtreecommitdiff
path: root/tests/Language
diff options
context:
space:
mode:
Diffstat (limited to 'tests/Language')
-rw-r--r--tests/Language/GraphQL/AST/EncoderSpec.hs107
-rw-r--r--tests/Language/GraphQL/AST/LexerSpec.hs11
-rw-r--r--tests/Language/GraphQL/AST/ParserSpec.hs108
3 files changed, 210 insertions, 16 deletions
diff --git a/tests/Language/GraphQL/AST/EncoderSpec.hs b/tests/Language/GraphQL/AST/EncoderSpec.hs
index 0067c83..71ee948 100644
--- a/tests/Language/GraphQL/AST/EncoderSpec.hs
+++ b/tests/Language/GraphQL/AST/EncoderSpec.hs
@@ -6,37 +6,124 @@ module Language.GraphQL.AST.EncoderSpec
import Language.GraphQL.AST
import Language.GraphQL.AST.Encoder
-import Test.Hspec (Spec, context, describe, it, shouldBe)
+import Test.Hspec (Spec, context, describe, it, shouldBe, shouldStartWith, shouldEndWith, shouldNotContain)
+import Test.QuickCheck (choose, oneof, forAll)
import Text.RawString.QQ (r)
+import Data.Text.Lazy (cons, toStrict, unpack)
spec :: Spec
spec = do
describe "value" $ do
+ context "null value" $ do
+ let testNull formatter = value formatter Null `shouldBe` "null"
+ it "minified" $ testNull minified
+ it "pretty" $ testNull pretty
+
context "minified" $ do
it "escapes \\" $
value minified (String "\\") `shouldBe` "\"\\\\\""
- it "escapes quotes" $
+ it "escapes double quotes" $
value minified (String "\"") `shouldBe` "\"\\\"\""
+ it "escapes \\f" $
+ value minified (String "\f") `shouldBe` "\"\\f\""
+ it "escapes \\n" $
+ value minified (String "\n") `shouldBe` "\"\\n\""
+ it "escapes \\r" $
+ value minified (String "\r") `shouldBe` "\"\\r\""
+ it "escapes \\t" $
+ value minified (String "\t") `shouldBe` "\"\\t\""
it "escapes backspace" $
value minified (String "a\bc") `shouldBe` "\"a\\bc\""
- it "escapes Unicode" $
- value minified (String "\0") `shouldBe` "\"\\u0000\""
+ context "escapes Unicode for chars less than 0010" $ do
+ it "Null" $ value minified (String "\x0000") `shouldBe` "\"\\u0000\""
+ it "bell" $ value minified (String "\x0007") `shouldBe` "\"\\u0007\""
+ context "escapes Unicode for char less than 0020" $ do
+ it "DLE" $ value minified (String "\x0010") `shouldBe` "\"\\u0010\""
+ it "EM" $ value minified (String "\x0019") `shouldBe` "\"\\u0019\""
+ context "encodes without escape" $ do
+ it "space" $ value minified (String "\x0020") `shouldBe` "\" \""
+ it "~" $ value minified (String "\x007E") `shouldBe` "\"~\""
context "pretty" $ do
it "uses strings for short string values" $
value pretty (String "Short text") `shouldBe` "\"Short text\""
- it "uses block strings for text with new lines" $
+ it "uses block strings for text with new lines, with newline symbol" $
value pretty (String "Line 1\nLine 2")
- `shouldBe` "\"\"\"\n Line 1\n Line 2\n\"\"\""
- it "escapes \\ in short strings" $
- value pretty (String "\\") `shouldBe` "\"\\\\\""
+ `shouldBe` [r|"""
+ Line 1
+ Line 2
+"""|]
+ it "uses block strings for text with new lines, with CR symbol" $
+ value pretty (String "Line 1\rLine 2")
+ `shouldBe` [r|"""
+ Line 1
+ Line 2
+"""|]
+ it "uses block strings for text with new lines, with CR symbol followed by newline" $
+ value pretty (String "Line 1\r\nLine 2")
+ `shouldBe` [r|"""
+ Line 1
+ Line 2
+"""|]
+ it "encodes as one line string if has escaped symbols" $ do
+ let
+ genNotAllowedSymbol = oneof
+ [ choose ('\x0000', '\x0008')
+ , choose ('\x000B', '\x000C')
+ , choose ('\x000E', '\x001F')
+ , pure '\x007F'
+ ]
+
+ forAll genNotAllowedSymbol $ \x -> do
+ let
+ rawValue = "Short \n" <> cons x "text"
+ encoded = value pretty (String $ toStrict rawValue)
+ shouldStartWith (unpack encoded) "\""
+ shouldEndWith (unpack encoded) "\""
+ shouldNotContain (unpack encoded) "\"\"\""
+
+ it "Hello world" $ value pretty (String "Hello,\n World!\n\nYours,\n GraphQL.")
+ `shouldBe` [r|"""
+ Hello,
+ World!
+
+ Yours,
+ GraphQL.
+"""|]
+
+ it "has only newlines" $ value pretty (String "\n") `shouldBe` [r|"""
+
+
+"""|]
+ it "has newlines and one symbol at the begining" $
+ value pretty (String "a\n\n") `shouldBe` [r|"""
+ a
+
+
+"""|]
+ it "has newlines and one symbol at the end" $
+ value pretty (String "\n\na") `shouldBe` [r|"""
+
+
+ a
+"""|]
+ it "has newlines and one symbol in the middle" $
+ value pretty (String "\na\n") `shouldBe` [r|"""
+
+ a
+
+"""|]
+ it "skip trailing whitespaces" $ value pretty (String " Short\ntext ")
+ `shouldBe` [r|"""
+ Short
+ text
+"""|]
describe "definition" $
it "indents block strings in arguments" $
let arguments = [Argument "message" (String "line1\nline2")]
field = Field Nothing "field" arguments [] []
- set = OperationSelectionSet $ pure $ SelectionField field
- operation = DefinitionOperation set
+ operation = DefinitionOperation $ SelectionSet $ pure field
in definition pretty operation `shouldBe` [r|{
field(message: """
line1
diff --git a/tests/Language/GraphQL/AST/LexerSpec.hs b/tests/Language/GraphQL/AST/LexerSpec.hs
index a0acb9f..0b4cb31 100644
--- a/tests/Language/GraphQL/AST/LexerSpec.hs
+++ b/tests/Language/GraphQL/AST/LexerSpec.hs
@@ -8,7 +8,7 @@ import Data.Text (Text)
import Data.Void (Void)
import Language.GraphQL.AST.Lexer
import Test.Hspec (Spec, context, describe, it)
-import Test.Hspec.Megaparsec (shouldParse, shouldSucceedOn)
+import Test.Hspec.Megaparsec (shouldParse, shouldFailOn, shouldSucceedOn)
import Text.Megaparsec (ParseErrorBundle, parse)
import Text.RawString.QQ (r)
@@ -77,7 +77,7 @@ spec = describe "Lexer" $ do
parse spread "" "..." `shouldParse` "..."
parse colon "" ":" `shouldParse` ":"
parse equals "" "=" `shouldParse` "="
- parse at "" "@" `shouldParse` '@'
+ parse at "" "@" `shouldParse` "@"
runBetween brackets `shouldSucceedOn` "[]"
runBetween braces `shouldSucceedOn` "{}"
parse pipe "" "|" `shouldParse` "|"
@@ -87,6 +87,13 @@ spec = describe "Lexer" $ do
parse blockString "" [r|""""""|] `shouldParse` ""
it "lexes ampersand" $
parse amp "" "&" `shouldParse` "&"
+ it "lexes schema extensions" $
+ parseExtend "schema" `shouldSucceedOn` "extend schema"
+ it "fails if the given token doesn't match" $
+ parseExtend "schema" `shouldFailOn` "extend shema"
+
+parseExtend :: Text -> (Text -> Either (ParseErrorBundle Text Void) ())
+parseExtend extension = parse (extend extension "" $ pure $ pure ()) ""
runBetween :: (Parser () -> Parser ()) -> Text -> Either (ParseErrorBundle Text Void) ()
runBetween parser = parse (parser $ pure ()) ""
diff --git a/tests/Language/GraphQL/AST/ParserSpec.hs b/tests/Language/GraphQL/AST/ParserSpec.hs
index 420d3cf..4fae5b1 100644
--- a/tests/Language/GraphQL/AST/ParserSpec.hs
+++ b/tests/Language/GraphQL/AST/ParserSpec.hs
@@ -4,9 +4,11 @@ module Language.GraphQL.AST.ParserSpec
( spec
) where
+import Data.List.NonEmpty (NonEmpty(..))
+import Language.GraphQL.AST.Document
import Language.GraphQL.AST.Parser
import Test.Hspec (Spec, describe, it)
-import Test.Hspec.Megaparsec (shouldSucceedOn)
+import Test.Hspec.Megaparsec (shouldParse, shouldSucceedOn)
import Text.Megaparsec (parse)
import Text.RawString.QQ (r)
@@ -28,17 +30,115 @@ spec = describe "Parser" $ do
it "accepts two required arguments" $
parse document "" `shouldSucceedOn` [r|
mutation auth($username: String!, $password: String!){
- test
+ test
}|]
it "accepts two string arguments" $
parse document "" `shouldSucceedOn` [r|
mutation auth{
- test(username: "username", password: "password")
+ test(username: "username", password: "password")
}|]
it "accepts two block string arguments" $
parse document "" `shouldSucceedOn` [r|
mutation auth{
- test(username: """username""", password: """password""")
+ test(username: """username""", password: """password""")
}|]
+
+ it "parses minimal schema definition" $
+ parse document "" `shouldSucceedOn` [r|schema { query: Query }|]
+
+ it "parses minimal scalar definition" $
+ parse document "" `shouldSucceedOn` [r|scalar Time|]
+
+ it "parses ImplementsInterfaces" $
+ parse document "" `shouldSucceedOn` [r|
+ type Person implements NamedEntity & ValuedEntity {
+ name: String
+ }
+ |]
+
+ it "parses a type without ImplementsInterfaces" $
+ parse document "" `shouldSucceedOn` [r|
+ type Person {
+ name: String
+ }
+ |]
+
+ it "parses ArgumentsDefinition in an ObjectDefinition" $
+ parse document "" `shouldSucceedOn` [r|
+ type Person {
+ name(first: String, last: String): String
+ }
+ |]
+
+ it "parses minimal union type definition" $
+ parse document "" `shouldSucceedOn` [r|
+ union SearchResult = Photo | Person
+ |]
+
+ it "parses minimal interface type definition" $
+ parse document "" `shouldSucceedOn` [r|
+ interface NamedEntity {
+ name: String
+ }
+ |]
+
+ it "parses minimal enum type definition" $
+ parse document "" `shouldSucceedOn` [r|
+ enum Direction {
+ NORTH
+ EAST
+ SOUTH
+ WEST
+ }
+ |]
+
+ it "parses minimal enum type definition" $
+ parse document "" `shouldSucceedOn` [r|
+ enum Direction {
+ NORTH
+ EAST
+ SOUTH
+ WEST
+ }
+ |]
+
+ it "parses minimal input object type definition" $
+ parse document "" `shouldSucceedOn` [r|
+ input Point2D {
+ x: Float
+ y: Float
+ }
+ |]
+
+ it "parses minimal input enum definition with an optional pipe" $
+ parse document "" `shouldSucceedOn` [r|
+ directive @example on
+ | FIELD
+ | FRAGMENT_SPREAD
+ |]
+
+ it "parses schema extension with a new directive" $
+ parse document "" `shouldSucceedOn`[r|
+ extend schema @newDirective
+ |]
+
+ it "parses schema extension with an operation type definition" $
+ parse document "" `shouldSucceedOn` [r|extend schema { query: Query }|]
+
+ it "parses schema extension with an operation type and directive" $
+ let newDirective = Directive "newDirective" []
+ testSchemaExtension = TypeSystemExtension
+ $ SchemaExtension
+ $ SchemaOperationExtension [newDirective]
+ $ OperationTypeDefinition Query "Query" :| []
+ query = [r|extend schema @newDirective { query: Query }|]
+ in parse document "" query `shouldParse` (testSchemaExtension :| [])
+
+ it "parses an object extension" $
+ parse document "" `shouldSucceedOn` [r|
+ extend type Story {
+ isHiddenLocally: Boolean
+ }
+ |] \ No newline at end of file