disco-0.1.0.0: test/Tests.hs
module Main where
import Control.Monad (filterM)
import qualified Data.ByteString as BS
import Data.Function (on)
import Data.List (groupBy, sort)
import System.Directory (doesFileExist,
getDirectoryContents)
import System.FilePath (isPathSeparator, (</>))
import System.IO (hGetContents)
import System.Process (StdStream (CreatePipe),
createProcess, shell, std_out,
system)
import Text.Printf
import Test.Tasty
import Test.Tasty.Golden.Advanced
main :: IO ()
main = do
testDirs <- getDirectoryContents "test"
>>= filterM (doesFileExist . (\d -> ("test" </> d </> "input")))
let testDirs'
= groupBy ((==) `on` extractGroup)
. sort
. filter (\f -> f /= "." && f /= "..")
$ testDirs
let testTree = testGroup "disco" $ map mkGroup testDirs'
defaultMain testTree
where
mkGroup ds = testGroup (extractGroup (head ds)) $ map mkGolden ds
-- (head ds) is safe since mkGroup is called on testDirs', which
-- is the output of groupBy, so each element of testDirs' will
-- be a non-empty list.
extractGroup :: FilePath -> String
extractGroup = takeWhile (/='-')
extractName :: FilePath -> String
extractName = takeWhile (not . isPathSeparator) . drop 1 . dropWhile (/='-')
mkGolden :: FilePath -> TestTree
mkGolden relDir =
goldenVsFileWithDiff
(extractName relDir)
(dir </> "expected")
(dir </> "output")
(system ("disco -f " ++ (dir </> "input") ++ " > " ++ (dir </> "output")) >> return ())
where
dir = "test" </> relDir
-- | A variant of goldenVsFile that prints the result of @diff@ if
-- the files are different, so we don't have to manually call @diff@
-- every time there is a test failure.
goldenVsFileWithDiff
:: TestName -- ^ test name
-> FilePath -- ^ path to the «golden» file (the file that contains correct output)
-> FilePath -- ^ path to the output file
-> IO () -- ^ action that creates the output file
-> TestTree -- ^ the test verifies that the output file contents is the same as the golden file contents
goldenVsFileWithDiff name ref new act =
goldenTest
name
(BS.readFile ref)
(act >> BS.readFile new)
cmp
upd
where
cmp = cmpWithDiff ref new
upd = BS.writeFile ref
cmpWithDiff :: Eq a => FilePath -> FilePath -> a -> a -> IO (Maybe String)
cmpWithDiff f1 f2 x y = do
if x == y
then return Nothing
else do
(_, Just hout, _, _)
<- createProcess (shell $ printf "diff %s %s" f1 f2) { std_out = CreatePipe }
diffStr <- hGetContents hout
return $ Just $ unlines
[ printf "Files '%s' and '%s' differ:" f1 f2
, diffStr
]