packages feed

lhc-0.10: tests/UnitTests.hs

module UnitTests
    ( unitTests
    ) where

import Test.Framework (testGroup)
import Test.Framework.Providers.HUnit

import Test.HUnit
import System.FilePath
import System.Directory
import System.Process
import Control.Monad
import Control.Monad.Error
import qualified Data.ByteString.Char8 as B
import Control.Concurrent
import Control.Exception
import System.Exit
import System.IO

unitTests = [ testGroup "io" basicTests
            , testGroup "language" languageTests
            , testGroup "shootout" shootoutTests
            , testGroup "nofib" nofibTests
            , testGroup "bugs" bugsTests
            ]


basicTests
    = [ lhcTest dir name | name <- tests ]
    where dir = ["tests","1_io","basic"]
          tests = [ "Args"
                  , "HelloWorld"
                  , "enum"
                  , "fastest_fib"
                  , "IORef"
                  , "Echo" ]

languageTests
    = [ lhcTest dir name | name <- tests ]
    where dir = ["tests","2_language"]
          tests = [ "Bounds"
                  , "CPP"
                  , "EnumEnum"
                  , "IntEnum"
                  , "IrrefutableLambda"
                  , "KindInference"
                  , "Kleisli"
                  , "PureInteger"
                  , "Laziness"
                  , "Defaulting"
                  , "NoMonomorphism" ]

shootoutTests
    = [ lhcTest dir name | name <- tests ]
    where dir = ["tests", "3_shootout"]
          tests = [ "BinaryTrees"
                  , "Mandelbrot"
                  , "SumFile"]

nofibTests
    = [ lhcTest dir name | name <- tests ] ++
      [ lhcTest (dir ++ ["spectral","calendar"]) "Calendar" ] ++
      [ lhcTest (dir ++ ["spectral","primes"]) "Primes" ]
    where dir = ["tests", "9_nofib"]
          tests = [ "digits-of-e1" ]


bugsTests
    = [ lhcTest dir name | name <- tests ]
    where dir = ["tests", "bugs"]
          tests = ["ImportZeal"
                  ,"Parsing1"
                  ,"RayT"
                  ,"Qualify1"
                  ,"Recursive2"
                  ,"UnpackedPoly"
                  ,"Exceptions1"]







------------------------------------------------------------------------------
-- Framework code

lhcTest path name
    = testCase name $
      do let testFile = joinPath path </> name <.> "hs"
         exist <- doesFileExist testFile
         unless exist $ fail "Cannot find test file."
         removeFile (dropExtension testFile) `mplus` return ()
         args <- B.readFile (replaceExtension testFile "args") `mplus` return B.empty
         input <- B.readFile (replaceExtension testFile "stdin") `mplus` return B.empty
         expectedOutput <- B.readFile (replaceExtension testFile "expected.stdout") `mplus` return B.empty
         mustfail <- doesFileExist (replaceExtension testFile "mustfail")
         handleFailures mustfail $ do
           execProcess "lhc" ["--make", "-O2", "-c", "-fforce-recomp", testFile] B.empty
           execProcess "lhc" ["benchmark", replaceExtension testFile "hcr"] B.empty
           (_,output,_) <- execProcess (dropExtension testFile) (words $ B.unpack args) input
           let failed = output /= expectedOutput
           when failed $
             fail $ unlines [ "Program result doesn't match expected output."
                            , "Program output:"
                            , take 100 (show (B.unpack output))
                            , "Expected output:"
                            , take 100 (show (B.unpack expectedOutput)) ]

handleFailures False cmd = cmd
handleFailures True cmd
    = do e <- try cmd :: IO (Either SomeException ())
         case e of
           Right () -> fail $ "Program succeded unexpectantly."
           Left e   -> return ()
         

execProcess :: FilePath -> [String] -> B.ByteString -> IO (ExitCode, B.ByteString, B.ByteString)
execProcess cmd args input = do
  (inh, outh, errh, pid) <- runInteractiveProcess cmd args Nothing Nothing
  handle (\e -> do terminateProcess pid
                   throw (e::SomeException)) $ do
  outVar <- newEmptyMVar
  forkIO $ B.hGetContents outh >>= putMVar outVar
  errVar <- newEmptyMVar
  forkIO $ B.hGetContents errh >>= putMVar errVar

  when (not (B.null input)) $ do B.hPutStr inh input >> hFlush inh
  hClose inh

  out <- takeMVar outVar
  err <- takeMVar errVar
  ret <- waitForProcess pid
  return (ret, out, err)