packages feed

nano-ui-0.1.0.0: lib/NanoUI/Testing/Runner.hs

-- | Shared runner for the @exitcode-stdio@ integration suites: runs named
-- specs against fresh contexts, selecting them by command-line name.
module NanoUI.Testing.Runner
  ( runTests
  ) where

import Control.Monad (forM_, when)
import Data.IORef (IORef, modifyIORef', newIORef, readIORef)
import NanoUI.Testing (Context)
import System.Environment (getArgs)
import System.IO (hFlush, stdout)

-- | Run the given specs. Each entry is a test name, a context maker, and the
-- test body (which receives the context and a shared failure counter). Names
-- passed as program arguments select which tests run; with no arguments
-- everything runs. A test counts as failed when it incremented the counter.
runTests :: [(String, IO Context, Context -> IORef Int -> IO ())] -> IO ()
runTests specs = do
  args <- getArgs
  let
    wantAll = null args
    want name = wantAll || name `elem` args
    names = [name | (name, _, _) <- specs]
    unknown = filter (`notElem` names) args
  when (not (null unknown)) $
    fail ("Unknown test names: " ++ unwords unknown)
  failed <- newIORef (0 :: Int)
  failedTests <- newIORef (0 :: Int)
  forM_ specs $ \(name, mkCtx, run) ->
    when (want name) $ do
      putStrLn ("RUN: " ++ name)
      hFlush stdout
      before <- readIORef failed
      ctx <- mkCtx
      run ctx failed
      after <- readIORef failed
      when (after > before) $ do
        modifyIORef' failedTests (+ 1)
        putStrLn ("FAIL: " ++ name)
  n <- readIORef failedTests
  if n == 0
    then putStrLn "All tests passed."
    else do
      putStrLn $ show n ++ " test(s) failed."
      fail "tests failed"