eoc/tests/Main.hs

116 lines
4.5 KiB
Haskell

module Main where
import qualified Bril as B
import qualified Bril.CFG as BCFG
import Data.Aeson (eitherDecode, decode, encode, toJSON, parseJSON, Result(..))
import Data.Aeson.Types (parse)
import Data.Text
import Data.Maybe
import Data.Either
import Data.Function ((&))
import Control.Exception (try)
import Test.HUnit
import qualified Test.QuickCheck as QC
import qualified System.Exit as Exit
testTypes :: Test
testTypes = TestCase $ do
assertEqual "int type" (decode "\"int\"" :: Maybe B.Type) (Just B.Int)
assertEqual "bool type" (decode "\"bool\"" :: Maybe B.Type) (Just B.Bool)
testLiterals :: Test
testLiterals = TestCase $ do
assertEqual "true literal"
(parseLiteral B.Bool True) (Success $ B.BoolValue True)
assertEqual "false literal"
(parseLiteral B.Bool False) (Success $ B.BoolValue False)
assertEqual "int literal"
(parseLiteral B.Int (1434 :: Int)) (Success $ B.IntValue 1434)
assertEqual "wrong int literal"
(parseLiteral B.Int (100000000000000000000 :: Integer))
(Error "Integer exceeds int64: 1.0e20")
assertEqual "wrong int literal"
(parseLiteral B.Int (123.5 :: Double)) (Error "Invalid integer literal: 123.5")
where
parseLiteral type_ x = (parse (B.parseValue type_) (toJSON x))
testInstrs :: Test
testInstrs = TestCase $ do
assertEqual "add instr"
(eitherDecode "{\"op\": \"add\", \"type\": \"int\", \"dest\": \"x\", \"args\": [\"a\", \"b\"]}")
(Right $ B.ValueInstr B.Add B.Int "x" ["a", "b"] [] [])
assertEqual "sub instr"
(decode "{\"op\": \"sub\", \"type\": \"int\", \"dest\": \"x\", \"args\": [\"a\", \"b\"]}")
(Just $ B.ValueInstr B.Sub B.Int "x" ["a", "b"] [] [])
assertEqual "wrong instr"
(eitherDecode "{\"op\": \"wrnog\", \"type\": \"int\", \"dest\": \"x\", \"args\": [\"a\", \"b\"]}")
(Left "Error in $: Invalid op: wrnog" :: Either String B.Instruction)
assertEqual "wrong arity"
(eitherDecode "{\"op\": \"add\", \"type\": \"int\", \"dest\": \"x\", \"args\": [\"b\"]}")
(Left "Error in $: wrong arity for add: got 1, 0" :: Either String B.Instruction)
assertEqual "wrong label arity"
(eitherDecode "{\"op\": \"add\", \"type\": \"int\", \"dest\": \"x\", \"args\": [\"a\", \"b\"], \"labels\": [\"a\"]}")
(Left "Error in $: wrong arity for add: got 2, 1" :: Either String B.Instruction)
assertEqual "parse effect call"
(eitherDecode "{\"op\": \"call\", \"args\": [\"a\", \"b\"], \"funcs\": [\"a\"]}")
(Right $ B.EffectInstr B.Call ["a", "b"] ["a"] [])
assertEqual "parse value call"
(eitherDecode "{\"op\": \"call\", \"type\": \"bool\", \"dest\": \"z\", \"args\": [\"a\", \"b\"], \"funcs\": [\"a\"]}")
(Right $ B.ValueInstr B.Call B.Bool "z" ["a", "b"] ["a"] [])
assertEqual "parse invalid call"
(eitherDecode "{\"op\": \"call\", \"type\": \"bool\", \"dest\": \"z\", \"args\": [\"a\", \"b\"], \"funcs\": []}")
(Left "Error in $: call op must have exactly one entry in \"funcs\"" :: Either String B.Instruction)
assertEqual "parse jmp"
(eitherDecode "{\"op\": \"jmp\", \"labels\": [\"a\"]}")
(Right $ B.EffectInstr B.Jmp [] [] ["a"])
assertEqual "parse br"
(eitherDecode "{\"op\": \"br\", \"labels\": [\"a\", \"b\"], \"args\": [\"z\"]}")
(Right $ B.EffectInstr B.Br ["z"] [] ["a", "b"])
assertEqual "parse id"
(eitherDecode "{\"op\": \"id\", \"dest\": \"a\", \"type\": \"bool\", \"args\": [\"b\"]}")
(Right $ B.ValueInstr B.Id B.Bool "a" ["b"] [] [])
assertEqual "parse label"
(eitherDecode "{\"label\": \"test\"}")
(Right $ B.Label "test")
testProgramFromFiles :: Test
testProgramFromFiles = TestCase $ do
res <- try $ (B.parseBrilFromPath "bril-sources/add.json") :: IO (Either IOError (Either String B.Program))
case res of
(Right parseResult) -> assertBool "parse add.json" $ isRight parseResult
_ -> assertFailure "cannot open file"
prop_InvariantBrilSerialization :: B.Program -> Bool
prop_InvariantBrilSerialization program =
(decode (encode program)) == (Just program)
tests :: Test
tests = TestList [
TestLabel "bril parser: type" testTypes,
TestLabel "bril parser: literal" testLiterals,
TestLabel "bril parser: instruction" testInstrs,
TestLabel "bril parser: parse files" testProgramFromFiles
]
main :: IO ()
main = do
result <- runTestTT tests
-- QC.quickCheck prop_InvariantBrilSerialization
if failures result > 0 then Exit.exitFailure else Exit.exitSuccess