language-thrift-0.9.0.2: test/Language/Thrift/ParserSpec.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TupleSections #-}
module Language.Thrift.ParserSpec (spec) where
#if __GLASGOW_HASKELL__ < 709
import Control.Applicative
#endif
import Control.Monad
import Data.Text (pack)
import Test.Hspec
import Text.Megaparsec (SourcePos, eof, skipMany, spaceChar)
import TestUtils
import qualified Language.Thrift.AST as T
import qualified Language.Thrift.Parser as P
spec :: Spec
spec = describe "Parser" $ do
it "can parse empty documents" $
parseSuccessCases P.program $ map (, T.Program [] [])
[ ""
, "// line comment at EOF"
, "# line comment at EOF\n"
, "/** docstring at EOF */"
, "/** docstring with space\nand newline at EOF\n\t\t*/ "
, "/* comment\n\tat eof\n\t */"
]
it "can parse docstrings" $ forM_
[ ( return "/** foo */", "foo " )
, ( return "/** foo\n */", "foo" )
, ( readFile "test/data/docstring-1.txt"
, "Hello. This is the first\n" ++
"paragraph.\n\n" ++
" This is some text indented 4 spaces,\n" ++
" spread across multiple lines.\n\n" ++
"Back."
)
, ( readFile "test/data/docstring-2.txt"
, "The docstring itself is indented 4 spaces.\n\n" ++
"And has a missing * in between."
)
] $ \(i, o) -> do
input <- i
assertParses (skipMany spaceChar *> P.docstring) (pack o) input
it "can parse basic constants" $ parseSuccessCases P.constantValue
[ ("42", T.ConstInt 42 ())
, ("0x2a", T.ConstInt 42 ())
, ("1.2", T.ConstFloat 1.2 ())
, ("foo", T.ConstIdentifier "foo" ())
, ("\"foo\"", T.ConstLiteral "foo" ())
]
testParseFailure
testParseFailure :: Spec
testParseFailure = do
it "cannot parse invalid documents" $
parseFailureCases P.program
[ "namespace foo"
, "const i32 100 = \"foo\""
, "include \"foo"
, "enum { }"
, "struct { }"
, "service A extends B"
, "service A extends {}"
]
it "cannot parse invalid type references" $
parseFailureCases (P.typeReference <* eof)
[ "list<i32"
, "set<string, string>"
, "map<i64>"
, "something_else<foo>"
]
it "cannot parse reserved keywords in names" $
parseFailureCases P.program
[ "enum struct {}"
, "strut Foo { 1: required string service }"
]
parseFailureCases :: Show a => Parser a -> [String] -> Expectation
parseFailureCases p = mapM_ (p `shouldNotParse`)
parseSuccessCases
:: (Show (a ()), Eq (a ()), Functor a)
=> Parser (a SourcePos) -> [(String, a ())] -> Expectation
parseSuccessCases parser = mapM_ $ \(input, value) ->
assertParses (void `fmap` parser) value input