effectful-zoo-0.0.4.0: components/hedgehog/Effectful/Zoo/Hedgehog/Effect/Run.hs
{- HLINT ignore "Eta reduce" -}
{-# OPTIONS_GHC -Wno-orphans #-}
module Effectful.Zoo.Hedgehog.Effect.Run
( Hedgehog,
property,
unit,
forAll,
) where
import Control.Concurrent qualified as IO
import Control.Concurrent.STM qualified as IO
import Control.Exception qualified as IO
import Control.Exception.Lifted qualified as CEL
import Control.Monad
import Effectful
import Effectful.Concurrent
import Effectful.Concurrent.STM
import Effectful.Concurrent.STM qualified as CC
import Effectful.Environment
import Effectful.FileSystem
import Effectful.Zoo.Core
import Effectful.Zoo.Error.Static
import Effectful.Zoo.Hedgehog.Api.Failure
import Effectful.Zoo.Hedgehog.Api.Journal
import Effectful.Zoo.Hedgehog.Api.MonadAssertion
import Effectful.Zoo.Hedgehog.Effect.Hedgehog
import Effectful.Zoo.Hedgehog.Effect.HedgehogGen
import Effectful.Zoo.Log.Data.LogMessage
import Effectful.Zoo.Log.Static
import Effectful.Zoo.Resource
import HaskellWorks.Control.Monad
import HaskellWorks.Prelude
import HaskellWorks.ToText
import Hedgehog (Gen)
import Hedgehog qualified as H
import Hedgehog.Internal.Property qualified as H
property :: ()
=> Eff
[ Log Text
, HedgehogGen
, Hedgehog
, Error H.Failure
, Resource
, FileSystem
, Environment
, Concurrent
, IOE
] ()
-> H.PropertyT IO ()
property f = do
tvResult <- liftIO IO.newEmptyTMVarIO
tvAction <- liftIO IO.newEmptyTMVarIO
CEL.bracket
do liftIO $ IO.forkFinally
do f
& runLog @Text (ConcUnlift Persistent Unlimited) logTextToHedgehog
& runHedgehogGenProperty tvAction
& runHedgehogProperty tvAction
& runError @H.Failure
& runResource
& runFileSystem
& runEnvironment
& runConcurrent
& runEff
(liftIO . IO.atomically . IO.putTMVar tvResult)
do liftIO . IO.killThread
do \_ -> do
whileNothingM do
mActionOrResult <- liftIO $ IO.atomically do
mAction <- CC.tryTakeTMVar tvAction
case mAction of
Nothing -> do
mResult <- CC.tryTakeTMVar tvResult
case mResult of
Just a -> pure $ Just $ Right a
Nothing -> retry
Just action -> pure $ Just $ Left action
case mActionOrResult of
Nothing -> pure Nothing
Just (Left action) -> action >> pure Nothing
Just (Right (Left e)) -> liftIO $ IO.throwIO e
Just (Right (Right (Left (_, e)))) -> throwAssertion e
Just (Right (Right (Right a))) -> pure $ Just a
logTextToHedgehog :: ()
=> r <: Concurrent
=> r <: Hedgehog
=> r <: Error Failure
=> CallStack
-> LogMessage Text
-> Eff r ()
logTextToHedgehog callStack msg = do
let LogMessage severity text = msg
jotTextWithCallStack callStack $ toText severity <> " " <> text
unit :: ()
=> Eff
[ Log Text
, Hedgehog
, Error H.Failure
, Resource
, FileSystem
, Environment
, Concurrent
, IOE
] ()
-> H.TestT IO ()
unit f = do
tvResult <- liftIO IO.newEmptyTMVarIO
tvAction <- liftIO IO.newEmptyTMVarIO
CEL.bracket
do liftIO $ IO.forkFinally
do f & runLog @Text (ConcUnlift Persistent Unlimited) logTextToHedgehog
& runHedgehogUnit tvAction
& runError @H.Failure
& runResource
& runFileSystem
& runEnvironment
& runConcurrent
& runEff
(liftIO . IO.atomically . IO.putTMVar tvResult)
do liftIO . IO.killThread
do \_ -> do
whileNothingM do
mActionOrResult <- liftIO $ IO.atomically do
mAction <- CC.tryTakeTMVar tvAction
case mAction of
Nothing -> do
mResult <- CC.tryTakeTMVar tvResult
case mResult of
Just a -> pure $ Just $ Right a
Nothing -> retry
Just action -> pure $ Just $ Left action
case mActionOrResult of
Nothing -> pure Nothing
Just (Left action) -> action >> pure Nothing
Just (Right (Left e)) -> liftIO $ IO.throwIO e
Just (Right (Right (Left (_, e)))) -> throwAssertion e
Just (Right (Right (Right a))) -> pure $ Just a
forAll :: ()
=> r <: Concurrent
=> r <: HedgehogGen
=> Show a
=> Gen a
-> Eff r a
forAll gen = do
HedgehogGenEnv mvAction <- askHedgehogGenEnv
mvA <- newEmptyTMVarIO
atomically $ putTMVar mvAction (H.forAll gen >>= liftIO . IO.atomically . IO.putTMVar mvA)
atomically $ takeTMVar mvA