-- | This is a TAP13 (Test Anything Protocol version 13) compatible -- test output formatter for tasty. You can read more about tap -- . module Test.Tasty.Runners.TAP ( tapRunner , tapRunner' ) where ------------------------------------------------------------------------------- import Control.Concurrent.STM import Control.Monad import qualified Data.IntMap.Strict as IM import Data.List import Data.Maybe import Data.Monoid import System.IO import Test.Tasty.Ingredients import Test.Tasty.Options import Test.Tasty.Runners ------------------------------------------------------------------------------- tapRunner :: Ingredient tapRunner = tapRunner' stdout ------------------------------------------------------------------------------- tapRunner' :: Handle -> Ingredient tapRunner' h = TestReporter reporterOpts go where reporterOpts = [] go opts tree = (Just (tapCallback h opts tree)) ------------------------------------------------------------------------------- tapCallback :: Handle -> OptionSet -> TestTree -> StatusMap -> IO (Time -> IO Bool) tapCallback h opts tree smap = do let names = IM.fromList (zip [0..] (testsNames opts tree)) hPutStrLn h tapHeader hPutStrLn h (tapPlan smap) results <- forM (IM.toList smap) $ \(idx, stat) -> do let n = fromMaybe mempty (IM.lookup idx names) reportStatus h n idx stat return (const (return (and results))) ------------------------------------------------------------------------------- tapHeader :: String tapHeader = "TAP version 13" ------------------------------------------------------------------------------- tapPlan :: StatusMap -> String tapPlan sm | IM.null sm = "Bail out! There were no tests to run." | otherwise = "1.." <> show (IM.size sm) ------------------------------------------------------------------------------- reportStatus :: Handle -> String -> Int -> TVar Status -> IO Bool reportStatus h name zeroIdx statRef = do res <- atomically (waitFinished ) hPutStrLn h (renderResult res) return (resultSuccessful res) where testNum = zeroIdx + 1 waitFinished = do stat <- readTVar statRef case stat of Done res -> return res _ -> retry renderResult res | resultSuccessful res = "ok " <> show testNum <> " - " <> name <> desc | otherwise = "not ok " <> show testNum <> " - " <> name <> desc --TODO: how do we get the test name? where desc = case resultDescription res of "" -> "" nonEmpty -> "\n" <> formatDesc nonEmpty ------------------------------------------------------------------------------- formatDesc :: String -> String formatDesc = intercalate "\n" . map ("# " <> ) . lines