module Main where
import Language.Boogie.Parser
import Language.Boogie.PrettyPrinter
import Language.Boogie.TypeChecker
import Language.Boogie.Interpreter
import Data.Map (Map, (!))
import qualified Data.Map as M
import System.FilePath
import Text.ParserCombinators.Parsec (parse, parseFromFile)
import Test.HUnit
main = runTestTT allTests
allTests = TestList [parserTests, typeCheckerTests, interpreterTests]
parserTests = TestLabel "Parser" $ TestList [
testCase parserSuccess "AttributeParsing"
]
typeCheckerTests = TestLabel "TypeChecker" $ TestList [
testCase (typeCheckerFailure 8) "BadLabels",
testCase (typeCheckerFailure 4) "Orderings",
testCase (typeCheckerFailure 2) "WhereResolution",
testCase (typeCheckerFailure 35) "Arrays",
testCase (typeCheckerFailure 15) "Frame",
testCase (typeCheckerFailure 3) "FunBody",
testCase (typeCheckerFailure 3) "IfThenElse",
testCase (typeCheckerFailure 4) "Lambda",
testCase (typeCheckerFailure 12) "UpdateExprTyping",
testCase (typeCheckerFailure 1) "TypeVarClash"
]
interpreterTests = TestLabel "Interpreter" $ TestList [
testCase interpreterSuccess "NoGuards",
testCase interpreterSuccess "EmptyDomains"
]
-- | Directory with test programs
testDir = "tests"
-- | Entry point for test programs
entryPoint = "Test"
testCase kind name = TestLabel name (TestCase $ kind (testDir </> name <.> "bpl"))
-- | Test that parser fails on file
parserFailure file = do
parseResult <- parseFromFile program file
case parseResult of
Left parseErr -> return ()
Right p -> assertFailure ("Undetected syntax error")
-- | Test that parser succeeds on file, and re-parsing pretty printer code produces the same AST
parserSuccess file = do
parseResult <- parseFromFile program file
case parseResult of
Left parseErr -> assertFailure (show parseErr)
Right p -> case parse program ('*' : file) (show p) of
Left parseErr' -> assertFailure (show parseErr')
Right p' -> if p == p'
then return ()
else assertFailure "Re-parsing resulted in a different AST"
-- | Test that type checker reports n errors on file
typeCheckerFailure n file = do
parseResult <- parseFromFile program file
case parseResult of
Left parseErr -> assertFailure (show parseErr)
Right p -> case checkProgram p of
Left typeErrs -> let m = length typeErrs in assertBool ("Expected " ++ show n ++ " type errors and got " ++ show m) (m == n)
Right context -> assertFailure ("Expected " ++ show n ++ " type errors and got 0")
-- | Test that type checker succeeds on file
typeCheckerSuccess file = do
parseResult <- parseFromFile program file
case parseResult of
Left parseErr -> assertFailure (show parseErr)
Right p -> case checkProgram p of
Left typeErrs -> assertFailure (show (typeErrorsDoc typeErrs))
Right context -> return ()
-- | Test that interpreter succeeds (no run-time failures or crashes) on procedure entryPoint in file
interpreterSuccess file = do
parseResult <- parseFromFile program file
case parseResult of
Left parseErr -> assertFailure (show parseErr)
Right p -> case checkProgram p of
Left typeErrs -> assertFailure (show (typeErrorsDoc typeErrs))
Right context -> case executeProgram p context entryPoint of
Left err -> assertFailure (show err)
Right env -> return ()