-- TODO verbosity options -- FIXME atm this parser is VERY brittle, please email me if there are any -- issues -J module Main where import System.IO import System.Posix.IO import Data.List import Data.Either import Text.Parsec.String (Parser) import Prelude hiding (fail) import Control.Applicative ((<*>),(<$>)) import Data.String.Indent (indent) import Text.Parsec.Prim (parse, try, (<|>), many) import Text.Parsec.Combinator (optionMaybe, count, many1, choice) import Text.Parsec.Char (alphaNum, char, string, noneOf) import Text.Parsec.Extra ( natural, eol, whitespace ) import qualified Filesystem.Path.CurrentOS as FS import Prelude hiding (FilePath) data Success = Success { successMsg :: String } deriving Show data Failure = Failure { line :: Int, failureMsg :: String } deriving Show data Test = Test { test :: String, result :: Either Failure Success } deriving Show data File = File { filepath :: FS.FilePath, tests :: [Test] } deriving Show fromResult :: FS.FilePath -> Test -> String fromResult fp (Test t (Left (Failure l msg))) = FS.encodeString fp ++ '|':show l ++ " error | " ++ t ++ '\n':indent 1 msg fromResult _ (Test t (Right (Success msg))) = t ++ "\n " ++ msg fromFile :: File -> String fromFile f = let (failures, successes) = partition failed (tests f) in (++) (intercalate "\n" $ map toString failures) ('\n': fromSuccesses successes) where failed :: Test -> Bool failed (Test _ (Left (Failure _ _))) = True failed (Test _ (Right (Success _))) = False toString :: Test -> String toString = fromResult (filepath f) fromSuccesses :: [Test] -> String fromSuccesses [] = [] fromSuccesses list = FS.encodeString (filepath f) ++ " successes: \n" ++ indent 2 (concatMap toString list) pathLine :: Parser FS.FilePath pathLine = do count 2 whitespace non_ext <- many1 $ noneOf ".\SP\n\r" ext <- string ".hs" eol return . FS.decodeString $ non_ext ++ ext messages :: Parser [String] messages = do count 6 whitespace content <- many $ noneOf "\n\r" many1 eol rest <- optionMaybe (try messages) return $ maybe [content] (content:) rest testP :: Parser Test testP = do count 4 whitespace l <- natural char ':' whitespace string "prop_" prop_name <- many1 (alphaNum <|> char '_') char ':' many1 whitespace ; f <- status prop_name l ; eol f . unlines <$> messages where status :: String -> Int -> Parser (String -> Test) status prop_name l = do lit <- choice $ map string ["OK", "FAIL"] return $ Test prop_name . if lit == "OK" then Right . Success else Left . Failure l parser :: Parser [File] parser = do string "modules" eol many1 (File <$> pathLine <*> many1 (try testP)) parseResults :: String -> String parseResults runner_output = case parse parser "tasty consoleRunner output" runner_output of Left errors -> show errors Right files -> (intercalate "\n" . map fromFile $ files) ++ "\n" main :: IO () main = fdToHandle stdInput >>= hGetContents >>= putStr . parseResults