packages feed

nri-prelude-0.3.1.0: src/Test.hs

-- | A module containing functions for creating and managing tests.
module Test
  ( -- * Organizing Tests
    Internal.Test,
    Internal.test,
    Internal.describe,
    Internal.skip,
    Internal.only,
    Internal.todo,

    -- * Fuzz Testing
    Internal.fuzz,
    Internal.fuzz2,
    Internal.fuzz3,

    -- * Task Testing
    Internal.task,

    -- * Running test
    run,
  )
where

import qualified Control.Concurrent.Async as Async
import qualified GHC.Stack as Stack
import NriPrelude
import qualified Platform
import qualified Platform.DevLog
import qualified System.Directory
import qualified System.Environment
import qualified System.IO
import qualified Task
import qualified Test.Internal as Internal
import qualified Test.Reporter.ExitCode
import qualified Test.Reporter.Junit
import qualified Test.Reporter.Logfile
import qualified Test.Reporter.Stdout
import qualified Prelude

-- | Turn a test suite into a program that can be executed in Haskell. Use like
-- this:
--
-- > module Main (main) where
-- >
-- > import qualified Test
-- >
-- > main :: IO ()
-- > main = Test.run (Test.todo "write your tests here!")
run :: Stack.HasCallStack => Internal.Test -> Prelude.IO ()
run suite = do
  log <- Platform.silentHandler
  (results, logExplorerAvailable) <-
    Async.concurrently
      (Task.perform log (Internal.run suite))
      isLogExplorerAvailable
  Async.mapConcurrently_
    identity
    [ reportStdout results,
      Stack.withFrozenCallStack reportLogfile results,
      reportJunit results
    ]
  if logExplorerAvailable
    then Prelude.putStrLn "\nRun log-explorer in your shell to inspect logs collected during this test run."
    else Prelude.putStrLn "\nInstall the log-explorer tool to inspect logs collected during test runs. Find it at github.com/NoRedInk/haskell-libraries."
  Test.Reporter.ExitCode.report results

reportStdout :: Internal.SuiteResult -> Prelude.IO ()
reportStdout results =
  Test.Reporter.Stdout.report System.IO.stdout results

reportLogfile :: Stack.HasCallStack => Internal.SuiteResult -> Prelude.IO ()
reportLogfile results =
  Stack.withFrozenCallStack
    Test.Reporter.Logfile.report
    Platform.DevLog.writeSpanToDevLog
    results

reportJunit :: Internal.SuiteResult -> Prelude.IO ()
reportJunit results =
  do
    args <- System.Environment.getArgs
    case getPath args of
      Nothing -> Prelude.pure ()
      Just path -> Test.Reporter.Junit.report path results

getPath :: [Prelude.String] -> Maybe Prelude.String
getPath args =
  case args of
    [] -> Nothing
    "--xml" : path : _ -> Just path
    _ : rest -> getPath rest

isLogExplorerAvailable :: Prelude.IO Bool
isLogExplorerAvailable = do
  System.Directory.findExecutable "log-explorer"
    |> map (/= Nothing)