packages feed

DocTest-0.0.0: Test/DocTest.hs

-- Copyright (c) 2009 Simon Hengel <simon.hengel@web.de>
module Test.DocTest where

import Control.Exception
import Test.HUnit
import System.Plugins
import System.IO
import System.FilePath
import System.Directory
import Test.DocTest.Util


loadTest :: FilePath -> FilePath -> IO Test
loadTest file dir = do
	mv <- load file [dir] [] "docTest"
	case mv of
		LoadFailure msg -> fail ("error while loading " ++ file ++ ": " ++ (concat msg))
		LoadSuccess _ v -> return v


compileModule filename dir = do
	status <- makeAll filename ["-i" ++ dir]
	case status of
		 MakeFailure errors -> fail (concat errors)
		 MakeSuccess _ file -> return file


-- Example:
--
-- > makeTest (DocTest "Fib.hs - line 6: " "Fib" "fib 10" "55")
-- "docTest = TestCase (assertEqual \"Fib.hs - line 6: \" (show (fib 10)) \"55\")"

makeTest (DocTest source _ expression result) = (
		"docTest = TestCase (assertEqual \"" ++
		source ++ "\" " ++
		"(show (" ++ expression ++ "))" ++ " \"" ++
		(escape result) ++ "\")"
	)

escape :: String -> String
escape str = replace "\"" "\\\"" $ replace "\\" "\\\\" str


data DocTest = DocTest {
	  source		:: String
	, _module		:: String
	, expression	:: String
	, result		:: String
	}
	deriving (Show)


writeModule test moduleName handle = do
	hPutStrLn handle ("module " ++ moduleName ++ " where")
	hPutStrLn handle "import Test.HUnit"
	hPutStrLn handle ("import " ++ (_module test))
	hPutStrLn handle (makeTest test)


doTest :: FilePath -> DocTest -> IO Test
doTest directory test = do
	let moduleBaseName = replace "." "_" (_module test)
	(filename, handle) <- openTempFile directory (moduleBaseName ++ ".hs")

	putStrLn filename
	let testModuleName = takeBaseName filename

	--withFile filename WriteMode (writeModule test testModuleName)
	writeModule test testModuleName handle
	hClose handle


	canonicalModulePath <- canonicalizePath $ source test
	putStrLn canonicalModulePath

	let baseDir = packageBaseDir canonicalModulePath (_module test)
	putStrLn baseDir

	obj_file <- compileModule filename baseDir
	loadTest obj_file directory

packageBaseDir :: FilePath -> String -> FilePath
packageBaseDir moduleSrcFile moduleName = stripPostfix (dropExtension moduleSrcFile) (replace "." [pathSeparator] moduleName)