-- | Use "runhaskell Setup.hs test" or "cabal test" to run these tests. -- Particular files may be selected by supplying their names as arguments. module Main where import Language.Haskell.Exts.Annotated import System.IO import Control.Monad import Data.List import Data.Char import System.Directory import System.Environment (getArgs) import System.Exit (exitFailure) import System.FilePath main :: IO () main = go =<< getArgs -- | Run the selected tests - or all of them if the supplied list is empty go :: [FilePath] -> IO () go testsToRun = do hSetBuffering stdout NoBuffering files <- if null testsToRun then getDirectoryContents examplesDir else return testsToRun putStrLn "Testing parser:" src <- liftM (map (head . words) . lines) . readFile $ "Test" "failing.txt" results <- sequence [check (x `elem` src) (examplesDir x) | x <- files, not $ "." `isPrefixOf` x] putStrLn "\nAll parsing tests completed!\n" putStrLn "Testing exact printer:" pSrc <- liftM (map (head . words) . lines) . readFile $ "Test" "printFail.txt" pResults <- sequence [roundTrip (x `elem` pSrc) (examplesDir x) | x <- files, x `notElem` src, not $ "." `isPrefixOf` x] putStrLn "\nAll printing tests completed!\n" unless (all id $ results ++ pResults) exitFailure -- | Where all the tests are to be found examplesDir :: FilePath examplesDir = "Test" "examples" -- | Runs the test, and returns True unless there is an unexpected result check :: Bool -> FilePath -> IO Bool check expected file = do res <- parseFile file case res of ParseOk x | expected -> putStrLn ("\n") >> return False | otherwise -> putChar '.' >> return True err | expected -> putChar '!' >> return True | otherwise -> putStrLn ("\nFailure when parsing " ++ show file ++ "\n" ++ show err) >> return False roundTrip :: Bool -> FilePath -> IO Bool roundTrip expected file = do fc <- readFile file pr <- parseFileWithComments (defaultParseMode { parseFilename = file }) file case pr of ParseOk (ast,cs) -> do let res = exactPrint ast cs xs = dropWhile (uncurry (==)) $ zip (map (reverse . dropWhile isSpace . reverse) $ lines fc) (map (reverse . dropWhile isSpace . reverse) $ lines res) case xs of [] | expected -> putStrLn ("\n") >> return False | otherwise -> putChar '.' >> return True (lfc, lres):_ | expected -> putChar '!' >> return True | otherwise -> do putStrLn $ "Result of print does not match input when printing " ++ show file putStrLn $ "First unmatching lines are (line length):" putStrLn $ " Input (" ++ show (length lfc) ++ "): " ++ lfc putStrLn $ " Result (" ++ show (length lres) ++ "): " ++ lres return False err -> putStrLn ("\nFailure when parsing " ++ show file ++ "\n" ++ show err) >> return False