language-rust-0.1.0.0: test/unit-tests/LexerTest.hs
{-# LANGUAGE OverloadedStrings, UnicodeSyntax #-}
module LexerTest (lexerSuite) where
import Test.Framework (testGroup, Test)
import Test.Framework.Providers.HUnit
import Test.HUnit hiding (Test)
import Language.Rust.Parser.Lexer
import Language.Rust.Parser.ParseMonad
import Language.Rust.Syntax
import Language.Rust.Data.Ident
import Language.Rust.Data.Position
import Language.Rust.Data.InputStream
lexerSuite :: Test
lexerSuite = testGroup "lexer suite" [ commonCode, literals ]
-- | This contains some random real-life code fragments. The purpose here is
-- primarily black-box testing.
commonCode :: Test
commonCode = testGroup "lexing common code fragments"
[ testCode "let span = $p.span;"
[ IdentTok (mkIdent "let")
, Space Whitespace " "
, IdentTok (mkIdent "span")
, Space Whitespace " "
, Equal
, Space Whitespace " "
, Dollar
, IdentTok (mkIdent "p")
, Dot
, IdentTok (mkIdent "span")
, Semicolon
]
, testCode "$(p.span),+"
[ Dollar
, OpenDelim Paren
, IdentTok (mkIdent "p")
, Dot
, IdentTok (mkIdent "span")
, CloseDelim Paren
, Comma
, Plus
]
, testCode "pub s: pp::Printer<'a>,"
[ IdentTok (mkIdent "pub")
, Space Whitespace " "
, IdentTok (mkIdent "s")
, Colon
, Space Whitespace " "
, IdentTok (mkIdent "pp")
, ModSep
, IdentTok (mkIdent "Printer")
, Less
, LifetimeTok (mkIdent "a")
, Greater
, Comma
]
, testCode "impl<'a,T> Tr for &'a T {}"
[ IdentTok (mkIdent "impl")
, Less
, LifetimeTok (mkIdent "a")
, Comma
, IdentTok (mkIdent "T")
, Greater
, Space Whitespace " "
, IdentTok (mkIdent "Tr")
, Space Whitespace " "
, IdentTok (mkIdent "for")
, Space Whitespace " "
, Ampersand
, LifetimeTok (mkIdent "a")
, Space Whitespace " "
, IdentTok (mkIdent "T")
, Space Whitespace " "
, OpenDelim Brace
, CloseDelim Brace
]
, testCode "x /* some comment */ y"
[ IdentTok (mkIdent "x")
, Space Whitespace " "
, Space Comment " some comment "
, Space Whitespace " "
, IdentTok (mkIdent "y")
]
, testCode "x /* some /* nested */ comment */ y"
[ IdentTok (mkIdent "x")
, Space Whitespace " "
, Space Comment " some /* nested */ comment "
, Space Whitespace " "
, IdentTok (mkIdent "y")
]
, testCode "fn ܐ_ܐ() { println!(\"Hello, čušpajž日本語\"); }"
[ IdentTok (mkIdent "fn")
, Space Whitespace " "
, IdentTok (mkIdent "ܐ_ܐ")
, OpenDelim Paren
, CloseDelim Paren
, Space Whitespace " "
, OpenDelim Brace
, Space Whitespace " "
, IdentTok (mkIdent "println")
, Exclamation
, OpenDelim Paren
, LiteralTok (StrTok "Hello, čušpajž日本語") Nothing
, CloseDelim Paren
, Semicolon
, Space Whitespace " "
, CloseDelim Brace
]
, testCode "123.f32"
[ LiteralTok (IntegerTok "123") Nothing
, Dot
, IdentTok (mkIdent "f32")
]
, testCode "0e+10"
[ LiteralTok (FloatTok "0e+10") Nothing
]
, testCode "123.+1"
[ LiteralTok (FloatTok "123.") Nothing
, Plus
, LiteralTok (IntegerTok "1") Nothing
]
]
-- | test group for literals. Note that literals can have any suffix (even if
-- almost all of those suffixes end up being invalid).
literals :: Test
literals = testGroup "literals (numbers, characters, strings, etc.)"
-- byte's
[ testCode "b'a'" [ LiteralTok (ByteTok "a") Nothing ]
, testCode "b'\\n'" [ LiteralTok (ByteTok "\\n") Nothing ]
, testCode "b'a'suffix" [ LiteralTok (ByteTok "a") (Just "suffix") ]
-- char's
, testCode "'a'" [ LiteralTok (CharTok "a") Nothing ]
, testCode "'\\n'" [ LiteralTok (CharTok "\\n") Nothing ]
, testCode "'a'suffix" [ LiteralTok (CharTok "a") (Just "suffix") ]
-- integers
, testCode "123" [ LiteralTok (IntegerTok "123") Nothing ]
, testCode "123i32" [ LiteralTok (IntegerTok "123") (Just "i32") ]
, testCode "0b1100_1101" [ LiteralTok (IntegerTok "0b1100_1101") Nothing ]
, testCode "0b1100_1101isize" [ LiteralTok (IntegerTok "0b1100_1101") (Just "isize") ]
, testCode "0o3170" [ LiteralTok (IntegerTok "0o3170") Nothing ]
, testCode "0o3170i64" [ LiteralTok (IntegerTok "0o3170") (Just "i64") ]
, testCode "0xAFAC" [ LiteralTok (IntegerTok "0xAFAC") Nothing ]
, testCode "0xAFACu32" [ LiteralTok (IntegerTok "0xAFAC") (Just "u32") ]
-- float's
, testCode "123." [ LiteralTok (FloatTok "123.") Nothing ]
, testCode "123.1" [ LiteralTok (FloatTok "123.1") Nothing ]
, testCode "123.1f32" [ LiteralTok (FloatTok "123.1") (Just "f32") ]
, testCode "123e-9f32" [ LiteralTok (FloatTok "123e-9") (Just "f32") ]
, testCode "9e+10" [ LiteralTok (FloatTok "9e+10") Nothing ]
-- string's
, testCode "\"hello \\n world!\"" [ LiteralTok (StrTok "hello \\n world!") Nothing ]
, testCode "\"hello \\n world!\"suffix" [ LiteralTok (StrTok "hello \\n world!") (Just "suffix") ]
-- raw string's
, testCode "r\"hello \n world!\"" [ LiteralTok (StrRawTok "hello \n world!" 0) Nothing ]
, testCode "r\"hello \n world!\"suffix" [ LiteralTok (StrRawTok "hello \n world!" 0) (Just "suffix") ]
, testCode "r##\"hello \"#\n world!\"##suffix" [ LiteralTok (StrRawTok "hello \"#\n world!" 2) (Just "suffix") ]
-- bytestring's
, testCode "b\"hello \\n world!\"" [ LiteralTok (ByteStrTok "hello \\n world!") Nothing ]
, testCode "b\"hello \\n world!\"suffix" [ LiteralTok (ByteStrTok "hello \\n world!") (Just "suffix") ]
-- raw bytestring's
, testCode "br\"hello \n world!\"" [ LiteralTok (ByteStrRawTok "hello \n world!" 0) Nothing ]
, testCode "br\"hello \n world!\"suffix" [ LiteralTok (ByteStrRawTok "hello \n world!" 0) (Just "suffix") ]
, testCode "br##\"hello \"#\n world!\"##suffix" [ LiteralTok (ByteStrRawTok "hello \"#\n world!" 2) (Just "suffix") ]
-- multiline strings
, testCode "\"hello \\\n world!\"" [ LiteralTok (StrTok "hello \\\n world!") Nothing ]
, testCode "b\"hello \\\n world!\"" [ LiteralTok (ByteStrTok "hello \\\n world!") Nothing ]
]
-- | Create a test for a code fragment that should tokenize.
testCode :: String -> [Token] -> Test
testCode inp toks = testCase inp $ Right toks @=? lexTokensNoSpans (inputStreamFromString inp)
-- | Turn an InputStream into either an error or a list of tokens.
lexTokensNoSpans :: InputStream -> Either ParseFail [Token]
lexTokensNoSpans inp = map unspan <$> execParser (lexTokens lexToken) inp initPos