packages feed

kempe-0.2.0.6: test/Type.hs

module Type ( typeTests
            , assignTypes
            , yeetIO
            ) where

import           Control.DeepSeq   (deepseq)
import           Control.Exception (Exception, throwIO)
import           Kempe.AST
import           Kempe.File
import           Kempe.Module
import           Kempe.TyAssign
import           Prettyprinter     (pretty)
import           Test.Tasty
import           Test.Tasty.HUnit

typeTests :: TestTree
typeTests =
    testGroup "Type assignment"
        [ tyInfer "test/data/ty.kmp"
        , tyInfer "prelude/fn.kmp"
        , tyInfer "lib/maybe.kmp"
        , tyInfer "lib/either.kmp"
        , tyInfer "test/data/mutual.kmp"
        , tyInfer "examples/factorial.kmp"
        , tyInfer "lib/bool.kmp"
        , tyInfer "examples/hamming.kmp"
        , tyInfer "lib/gaussian.kmp"
        , tyInfer "test/data/transitive.kmp"
        , tyInfer "lib/tuple.kmp"
        , badType "test/err/merge.kmp" "Type a_5 -- Int a_4 is not as general as type a_3 -- a_3 a_3"
        , badType "test/err/kind.kmp" "Ill-kinded type: '(Maybe_1 Maybe_1)'. Note that type variables have kind \11089 in Kempe."
        , badType "test/err/patternMatch.kmp" "Inexhaustive pattern match."
        , detectsWarn "test/err/stupid.kmp" "4:1 'rand_1' is defined more than once."
        , detectsWarn "test/err/questionable.kmp" "3:19 'Some_3' is defined more than once."
        , testAssignment "test/data/ty.kmp"
        , testAssignment "lib/either.kmp"
        , testAssignment "prelude/fn.kmp"
        , testAssignment "test/data/mutual.kmp"
        ]

yeetIO :: Exception e => Either e a -> IO a
yeetIO = either throwIO pure

assignTypes :: FilePath -> IO (Declarations () (StackType ()) (StackType ()), Int)
assignTypes fp = do
    (maxU, m) <- parseProcess fp
    yeetIO $ runTypeM maxU (assignModule m)

testAssignment :: FilePath -> TestTree
testAssignment fp = testCase ("Annotates " ++ fp ++ " with types") $ do
    (m, i) <- assignTypes fp
    assertBool "Does not throw an exception" (m `deepseq` i `seq` True)

tyInfer :: FilePath -> TestTree
tyInfer fp = testCase ("Checks types (" ++ fp ++ ")") $ do
    res <- tcFile fp
    case res of
        Left err -> assertFailure (show $ pretty err)
        Right{}  -> assertBool "Doesn't fail type-checking" True

detectsWarn :: FilePath -> String -> TestTree
detectsWarn fp msg = testCase ("Warns (" ++ fp ++ ")") $ do
    res <- warnFile fp
    case res of
        Just err -> show (pretty err) @?= msg
        Nothing  -> assertFailure "Failed to warn!"

badType :: FilePath -> String -> TestTree
badType fp msg = testCase ("Detects error (" ++ fp ++ ")") $ do
    res <- tcFile fp
    case res of
        Left err -> show (pretty err) @?= msg
        Right{}  -> assertFailure "No error detected!"