{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where
import System.FilePath
import Data.List hiding (find)
import System.Exit
import System.Directory
import Test.HUnit
import System.FilePath.Find
import Debug.Trace
import Control.Monad
import System.Environment
import qualified Data.Set as S
import Test.Common
import System.IO.Temp
import System.IO (hClose, hPutStr)
data Verbosity = Debug | Status | None deriving (Eq, Show, Ord, Enum)
verb :: Verbosity
verb = Debug
cppFile, parseFailFile, processed :: String
cppFile = "cpp.txt"
parseFailFile = "pfail.txt"
processed = "processed.txt"
writeCPP :: FilePath -> IO ()
writeCPP fp = appendFile cppFile (('\n' : fp))
writeParseFail :: FilePath -> String -> IO ()
writeParseFail fp s = appendFile parseFailFile (('\n' : (fp ++ " " ++ s)))
writeProcessed :: FilePath -> IO ()
writeProcessed fp = appendFile processed (('\n' : fp))
main :: IO ()
main = do
as <- getArgs
case as of
[] -> putStrLn "Must enter directory to process"
["failures"] -> do
fs <- lines <$> readFile "origfailures.txt"
() <$ runTests (TestList (map mkParserTest fs))
["clean"] -> do
putStrLn "Cleaning..."
writeFile "processed.txt" ""
writeFile "pfail.txt" ""
writeFile "cpp.txt" ""
removeDirectoryRecursive "tests/roundtrip"
createDirectory "tests/roundtrip"
putStrLn "Done."
ds -> () <$ (runTests =<< (TestList <$> mapM tests ds))
runTests :: Test -> IO Counts
runTests t = do
let n = testCaseCount t
putStrLn $ "Running " ++ show n ++ " tests."
putStrLn $ "Verbosity: " ++ show verb
runTestTT t
tests :: FilePath -> IO Test
tests dir = do
done <- S.fromList . lines <$> readFile processed
roundTripHackage done dir
-- Selection:
-- Given base directory finds all haskell source files
findSrcFiles :: FilePath -> IO [FilePath]
findSrcFiles = find filterDirectory filterFilename
filterDirectory :: FindClause Bool
filterDirectory =
p <$> fileName
where
p x
| "." `isPrefixOf` x = False
| otherwise = True
filterFilename :: FindClause Bool
filterFilename = do
ext <- extension
fname <- fileName
return (ext == ".hs" && p fname)
where
p x
| "refactored" `isInfixOf` x = False
| "Setup.hs" `isInfixOf` x = False
| "HLint.hs" `isInfixOf` x = False -- HLint config files
| otherwise = True
-- Hackage dir
roundTripHackage :: S.Set String -> FilePath -> IO Test
roundTripHackage done hackageDir = do
packageDirs <- drop 2 <$> getDirectoryContents hackageDir
when (verb <= Debug) (traceShowM packageDirs)
TestList <$> mapM (roundTripPackage done) (zip [0..] (map (hackageDir </>) packageDirs))
roundTripPackage :: S.Set String -> (Int, FilePath) -> IO Test
roundTripPackage done (n, dir) = do
putStrLn (show n)
when (verb <= Status) (traceM dir)
hsFiles <- filter (flip S.notMember done) <$> findSrcFiles dir
return (TestLabel (dropFileName dir) (TestList $ map mkParserTest hsFiles))
mkParserTest :: FilePath -> Test
mkParserTest fp =
TestCase (do r <- either (\(ParseFailure _ s) -> exitFailure) return
=<< roundTripTest fp
writeProcessed fp
unless (status r == Success) (writeFailure fp (debugTxt r))
assertBool fp (status r == Success))
writeFailure :: FilePath -> String -> IO ()
writeFailure fp db = do
let outdir = "tests" </> "roundtrip"
outname = takeFileName fp <.> "out"
(fname, handle) <- openTempFile outdir outname
(hPutStr handle db >> hClose handle)