packages feed

HUnit-Plus-2.0.0: test/Tests/Test/HUnitPlus/ReporterUtils.hs

{-# LANGUAGE OverloadedStrings #-}

module Tests.Test.HUnitPlus.ReporterUtils where

import Control.Monad
import Data.List
import Distribution.TestSuite(Result(Pass, Fail))
import Test.HUnitPlus.Reporting

import qualified Data.HashMap.Strict as HashMap
import qualified Data.Text as Strict

data ReportEvent =
    End Double
  | StartSuite
  | EndSuite Double
  | StartCase
  | EndCase Double
  | Skip
  | Progress Strict.Text
  | Failure Strict.Text
  | Error Strict.Text
  | Exception Strict.Text
  | SystemErr Strict.Text
  | SystemOut Strict.Text
    deriving (Show)

instance Eq ReportEvent where
  End e1 == End e2 = e1 == e2
  StartSuite == StartSuite = True
  EndSuite e1 == EndSuite e2 = e1 == e2
  StartCase == StartCase = True
  EndCase e1 == EndCase e2 = e1 == e2
  Skip == Skip = True
  Progress s1 == Progress s2 = s1 == s2
  Failure s1 == Failure s2 = s1 == s2
  Error s1 == Error s2 = s1 == s2
  Exception s1 == Error s2 = Strict.isInfixOf s1 s2
  Error s1 == Exception s2 = Strict.isInfixOf s2 s1
  Exception s1 == Exception s2 = s1 == s2
  SystemErr s1 == SystemErr s2 = s1 == s2
  SystemOut s1 == SystemOut s2 = s1 == s2
  _ == _ = False

type ReporterOp us = (State, us) -> IO (State, us)

loggingReporter :: Reporter [ReportEvent]
loggingReporter = defaultReporter {
    reporterStart = return [],
    reporterEnd = (\time _ events -> return (events ++ [End time])),
    reporterStartSuite = (\_ events -> return (events ++ [StartSuite])),
    reporterEndSuite = (\time _ events -> return (events ++ [EndSuite time])),
    reporterStartCase = (\_ events -> return (events ++ [StartCase])),
    reporterEndCase = (\time _ events -> return (events ++ [EndCase time])),
    reporterSkipCase = (\_ events -> return (events ++ [Skip])),
    reporterCaseProgress = (\msg _ events -> return (events ++ [Progress msg])),
    reporterFailure = (\msg _ events -> return (events ++ [Failure msg])),
    reporterError = (\msg _ events -> return (events ++ [Error msg])),
    reporterSystemErr = (\msg _ events -> return (events ++ [SystemErr msg])),
    reporterSystemOut = (\msg _ events -> return (events ++ [SystemOut msg]))
  }

initState :: State
initState = State { stName = "", stPath = [], stCounts = zeroCounts,
                    stOptions = HashMap.empty, stOptionDescs = [] }

setName :: Strict.Text -> ReporterOp us
setName name (s @ State { stName = _ }, repstate) =
  return (s { stName = name }, repstate)

setOpt :: Strict.Text -> Strict.Text -> ReporterOp us
setOpt key value (s @ State { stOptions = opts }, repstate) =
  return (s { stOptions = HashMap.insert key value opts }, repstate)

pushPath :: Strict.Text -> ReporterOp us
pushPath name (s @ State { stPath = path }, repstate) =
  return (s { stPath = Label name : path }, repstate)

popPath :: ReporterOp us
popPath (s @ State { stPath = _ : path }, repstate) =
  return (s { stPath = path }, repstate)

addOption :: Strict.Text -> Strict.Text -> ReporterOp us
addOption key value (s @ State { stOptions = opts }, repstate) =
  return (s { stOptions = HashMap.insert key value opts }, repstate)

countAsserts :: Word -> ReporterOp us
countAsserts count (s @ State { stCounts = c @ Counts { cAsserts = n } },
                    repstate) =
  return (s { stCounts = c { cAsserts = n + count,
                             cCaseAsserts = count } }, repstate)

countTried :: Word -> ReporterOp us
countTried count (s @ State { stCounts = c @ Counts { cCases = cases,
                                                      cTried = tried } },
                  repstate) =
  return (s { stCounts = c { cCases = cases + count,
                             cTried = tried + count } },
          repstate)

countSkipped :: Word -> ReporterOp us
countSkipped count (s @ State { stCounts = c @ Counts { cSkipped = skipped,
                                                        cCases = cases } },
                  repstate) =
  return (s { stCounts = c { cSkipped = skipped + count,
                             cCases = cases + count } },
          repstate)

countErrors :: Word -> ReporterOp us
countErrors count (s @ State { stCounts = c @ Counts { cErrors = errors } },
                   repstate) =
  return (s { stCounts = c { cErrors = errors + count } }, repstate)

countFailed :: Word -> ReporterOp us
countFailed count (s @ State { stCounts = c @ Counts { cFailures = failed } },
                   repstate) =
  return (s { stCounts = c { cFailures = failed + count } }, repstate)

reportProgress :: Reporter us -> Strict.Text -> ReporterOp us
reportProgress reporter msg (state, repstate) =
  do
    repstate' <- (reporterCaseProgress reporter) msg state repstate
    return (state, repstate')

reportSystemErr :: Reporter us -> Strict.Text -> ReporterOp us
reportSystemErr reporter msg (state, repstate) =
  do
    repstate' <- (reporterSystemErr reporter) msg state repstate
    return (state, repstate')

reportSystemOut :: Reporter us -> Strict.Text -> ReporterOp us
reportSystemOut reporter msg (state, repstate) =
  do
    repstate' <- (reporterSystemOut reporter) msg state repstate
    return (state, repstate')

reportFailure :: Reporter us -> Strict.Text -> ReporterOp us
reportFailure reporter msg (state, repstate) =
  do
    repstate' <- (reporterFailure reporter) msg state repstate
    return (state, repstate')

reportError :: Reporter us -> Strict.Text -> ReporterOp us
reportError reporter msg (state, repstate) =
  do
    repstate' <- (reporterError reporter) msg state repstate
    return (state, repstate')

reportSkip :: Reporter us -> ReporterOp us
reportSkip reporter (state, repstate) =
  do
    repstate' <- (reporterSkipCase reporter) state repstate
    return (state, repstate')

reportStartCase :: Reporter us -> ReporterOp us
reportStartCase reporter (state, repstate) =
  do
    repstate' <- (reporterStartCase reporter) state repstate
    return (state, repstate')

reportEndCase :: Reporter us -> Double -> ReporterOp us
reportEndCase reporter time (state, repstate) =
  do
    repstate' <- (reporterEndCase reporter) time state repstate
    return (state, repstate')

reportStartSuite :: Reporter us -> ReporterOp us
reportStartSuite reporter (state, repstate) =
  do
    repstate' <- (reporterStartSuite reporter) state repstate
    return (state, repstate')

reportEndSuite :: Reporter us -> Double -> ReporterOp us
reportEndSuite reporter time (state, repstate) =
  do
    repstate' <- (reporterEndSuite reporter) time state repstate
    return (state, repstate')

reportEnd :: Reporter us -> Double -> ReporterOp us
reportEnd reporter time (state @ State { stCounts = counts }, repstate) =
  do
    repstate' <- (reporterEnd reporter) time counts repstate
    return (state, repstate')

runReporterTest :: Eq us => Reporter us -> [ReporterOp us] -> us ->
                   (us -> String) -> IO Result
runReporterTest reporter tests expected format =
  do
    initrepstate <- reporterStart reporter
    (_, actual) <- foldM (\state op -> op state) (initState, initrepstate) tests
    if actual == expected
      then return Pass
      else return (Fail ("Expected " ++ format expected ++
                        "\nbut got " ++ format actual))