packages feed

hint-0.2.4: unit-tests/run-unit-tests.hs

module Main ( main ) where

import Control.Exception

import Control.Monad       ( liftM, when )
import Control.Monad.Trans ( MonadIO(liftIO) )
import Control.Monad.Error ( catchError )

import System.IO
import System.Directory
import System.Exit


import Test.HUnit ( (@?=), (@?) )
import qualified Test.HUnit as HUnit

import qualified Language.Haskell.Interpreter.GHC as H

test_reload_modified :: H.InterpreterSession -> HUnit.Test
test_reload_modified s = testCase "reload_modified" [mod_file] $ do
                            writeFile mod_file mod_v1
                            f_v1 <- H.withSession s get_f
                            --
                            writeFile mod_file mod_v2
                            f_v2 <- H.withSession s get_f
                            --
                            (f_v1 5, f_v2 5) @?= (5, 6)
    --
    where mod_name = "TEST_ReloadModified"
          mod_file = mod_name ++ ".hs"
          --
          mod_v1   = unlines ["module " ++ mod_name,
                              "where",
                              "f :: Int -> Int",
                              "f = id"]
          mod_v2   = unlines ["module " ++ mod_name,
                              "where",
                              "f :: Int -> Int",
                              "f = (1 +)"]
          --
          get_f    =  do H.loadModules [mod_file]
                         H.setTopLevelModules [mod_name]
                         H.interpret "f" (H.as :: Int -> Int)

test_lang_exts :: H.InterpreterSession -> HUnit.Test
test_lang_exts s = testCase "lang_exts" [mod_file] $ do
                      writeFile mod_file "data T where T :: T"
                      H.withSession s $ do
                        loadFails @@? "first time, it shouldn't load"
                        --
                        H.setUseLanguageExtensions True
                        loadSucceeds @@? "now, it should load"
                        --
                        H.setUseLanguageExtensions False
                        loadFails @@? "it shouldn't load, again"
    --
    where mod_name     = "TEST_LangExts"
          mod_file     = mod_name ++ ".hs"
          --
          loadFails    = not `liftM` loadSucceeds
          loadSucceeds = do H.loadModules [mod_name]
                            return True
                         `catchError` (\_ -> return False)

test_work_in_main :: H.InterpreterSession -> HUnit.Test
test_work_in_main s = testCase "work_in_main" [mod_file] $ do
                        writeFile mod_file "f = id"
                        H.withSession s $ do
                          H.loadModules [mod_file]
                          H.setTopLevelModules ["Main"]
                          H.setImports ["Prelude"]
                          --
                          H.typeOf "f $ 1+1" @@?= "(Num a) => a"
                          H.eval "f $ filter odd [1,2]" @@?= "[1]"
                          H.interpret "f $ 1 == 2" H.infer @@?= False
    --
    where mod_file     = "TEST_WorkInMain.hs"

test_priv_syms_in_scope :: H.InterpreterSession -> HUnit.Test
test_priv_syms_in_scope s = testCase "private_syms_in_scope" [mod_file] $ do
                               writeFile mod_file mod_text
                               H.withSession s $ do
                                 H.loadModules [mod_file]
                                 H.setTopLevelModules ["T"]
                                 H.typeChecks "g" @@? "g is hidden"
    where mod_text = unlines ["module T(f) where", "f = g", "g = id"]
          mod_file = "TEST_PrivateSymbolsInScope.hs"


common_tests :: H.InterpreterSession -> [HUnit.Test]
common_tests s = [test_reload_modified s,
                  test_lang_exts s,
                  test_work_in_main s]


non_sb_tests :: H.InterpreterSession -> HUnit.Test
non_sb_tests s = HUnit.TestList $ common_tests s ++ [test_priv_syms_in_scope s]

sb_tests :: H.InterpreterSession -> HUnit.Test
sb_tests s = HUnit.TestList $ common_tests s

main :: IO ()
main = do s <- H.newSession
          --
          -- run the tests...
          c <- HUnit.runTestTT $ non_sb_tests s
          -- then run again, but with sandboxing on...
          setSandbox s
          c' <- HUnit.runTestTT $ sb_tests s
          --
          let failures  = HUnit.errors c  + HUnit.failures c +
                          HUnit.errors c' + HUnit.failures c'
              exit_code
                  | failures > 0 = ExitFailure failures
                  | otherwise    = ExitSuccess
          exitWith exit_code
       `catchDyn` (printInterpreterError >=> \_ -> exitWith (ExitFailure $ -1))

printInterpreterError :: H.InterpreterError -> IO ()
printInterpreterError = hPutStrLn stderr . show

setSandbox :: H.InterpreterSession -> IO ()
setSandbox s = H.withSession s $ H.setInstalledModsAreInScopeQualified False

(>=>) :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
f >=> g = \a -> f a >>= g

(@@?) :: (HUnit.AssertionPredicable p, MonadIO m) => m p -> String -> m ()
p @@? msg = do b <- p; liftIO (b @? msg)

(@@?=) :: (Eq a, Show a, MonadIO m) => m a -> a -> m ()
m_a @@?= b = do a <- m_a; liftIO (a @?= b)

testCase :: String -> [FilePath] -> HUnit.Assertion -> HUnit.Test
testCase title tmps test = HUnit.TestLabel title $
                               HUnit.TestCase (test' `finally` clean_up)
    where test' = test `catchDyn` (printInterpreterError >=> throwDyn)
          clean_up = mapM_ removeIfExists tmps
          removeIfExists f = do exists <- doesFileExist f
                                when exists $
                                     removeFile f