-- | A library to create @Expecation@s for @Task@s.
module Expect.Task
  ( check,
    andCheck,
    succeeds,
    fails,
    Failure,
  )
where

import qualified Debug
import qualified Expect
import NriPrelude
import qualified Task
import qualified Test.Internal as Internal

-- | Error generated when a test expectation is not met.
type Failure = Internal.Failure

-- | Check a task returns an expected value, than pass that value on.
--
-- > task "Greetings are friendly" <| do
-- >     getGreeting
-- >         |> andCheck (Expect.equal "Hi!")
andCheck :: (a -> Expect.Expectation) -> Task Failure a -> Task Failure a
andCheck :: (a -> Expectation) -> Task Failure a -> Task Failure a
andCheck a -> Expectation
expectation Task Failure a
task = do
  a
x <- Task Failure a
task
  TestResult
res <-
    a -> Expectation
expectation a
x
      Expectation
-> (Expectation -> Task Never TestResult) -> Task Never TestResult
forall a b. a -> (a -> b) -> b
|> Expectation -> Task Never TestResult
Internal.unExpectation
      Task Never TestResult
-> (Task Never TestResult -> Task Failure TestResult)
-> Task Failure TestResult
forall a b. a -> (a -> b) -> b
|> (Never -> Failure)
-> Task Never TestResult -> Task Failure TestResult
forall x y a. (x -> y) -> Task x a -> Task y a
Task.mapError Never -> Failure
forall a. Never -> a
never
  case TestResult
res of
    TestResult
Internal.Succeeded -> Task Failure a
task
    Internal.Failed Failure
failure -> Failure -> Task Failure a
forall x a. x -> Task x a
Task.fail Failure
failure

-- | Check an expectation in the middle of a @do@ block.
--
-- > task "Laundry gets done" <| do
-- >     weightInKgs <- clothesInWasher
-- >     check (weightInKgs |> Expect.atMost 8)
-- >     soapInWasher
-- >     startMachine
check :: Expect.Expectation -> Task Failure ()
check :: Expectation -> Task Failure ()
check Expectation
expectation =
  () -> Task Failure ()
forall a x. a -> Task x a
Task.succeed ()
    Task Failure ()
-> (Task Failure () -> Task Failure ()) -> Task Failure ()
forall a b. a -> (a -> b) -> b
|> (() -> Expectation) -> Task Failure () -> Task Failure ()
forall a. (a -> Expectation) -> Task Failure a -> Task Failure a
andCheck (\() -> Expectation
expectation)

-- | Check a task succeeds.
--
-- > task "solve rubicskube" <| do
-- >     solveRubicsKube
-- >         |> succeeds
succeeds :: Show err => Task err a -> Task Failure a
succeeds :: Task err a -> Task Failure a
succeeds Task err a
task =
  (err -> Failure) -> Task err a -> Task Failure a
forall x y a. (x -> y) -> Task x a -> Task y a
Task.mapError
    ( \err
message ->
        Text -> Failure
Internal.FailedAssertion (err -> Text
forall a. Show a => a -> Text
Debug.toString err
message)
    )
    Task err a
task

-- | Check a task fails.
--
-- > task "chemistry experiment" <| do
-- >     mixRedAndGreenLiquids
-- >         |> fails
fails :: Text -> Task Failure a
fails :: Text -> Task Failure a
fails Text
msg =
  Text
msg
    Text -> (Text -> Failure) -> Failure
forall a b. a -> (a -> b) -> b
|> Text -> Failure
Internal.FailedAssertion
    Failure -> (Failure -> Task Failure a) -> Task Failure a
forall a b. a -> (a -> b) -> b
|> Failure -> Task Failure a
forall x a. x -> Task x a
Task.fail