packages feed

effectful-zoo-0.0.3.0: components/hedgehog/Effectful/Zoo/Hedgehog/Effect/Hedgehog.hs

{- HLINT ignore "Eta reduce" -}

{-# OPTIONS_GHC -Wno-orphans #-}

module Effectful.Zoo.Hedgehog.Effect.Hedgehog
  ( Hedgehog,
    HedgehogEnv(..),
    runHedgehogProperty,
    runHedgehogUnit,
  ) where

import Control.Concurrent.STM qualified as IO
import Control.Monad
import Control.Monad.Catch (MonadThrow(..))
import Effectful
import Effectful.Concurrent
import Effectful.Concurrent.STM
import Effectful.Dispatch.Static
import Effectful.Zoo.Core
import Effectful.Zoo.Error.Static
import Effectful.Zoo.Hedgehog.Api.MonadAssertion
import Effectful.Zoo.Hedgehog.Data.TestResult
import HaskellWorks.Prelude
import Hedgehog (MonadTest(..))
import Hedgehog qualified as H
import Hedgehog.Internal.Property qualified as H

-- | An effect for interacting with the filesystem.
data Hedgehog :: Effect

type instance DispatchOf Hedgehog = Static WithSideEffects
newtype instance StaticRep Hedgehog = Hedgehog HedgehogEnv

data HedgehogEnv
  = PropertyEnv (TMVar (H.PropertyT IO ()))
  | UnitTestEnv (TMVar (H.TestT IO ()))

instance {-# OVERLAPS #-}
    ( r <: Concurrent
    , r <: Error H.Failure
    , r <: Hedgehog
    ) => MonadTest (Eff r) where
  liftTest f = do
    Hedgehog env <- getStaticRep
    mvA <- newEmptyTMVarIO
    case env of
      PropertyEnv mvAction ->
        atomically $ putTMVar mvAction (tryExceptAssertion (liftTest f) >>= liftIO . IO.atomically . IO.putTMVar mvA)
      UnitTestEnv mvAction ->
        atomically $ putTMVar mvAction (tryExceptAssertion (liftTest f) >>= liftIO . IO.atomically . IO.putTMVar mvA)
    testResult <- atomically $ takeTMVar mvA
    getTestResult testResult

instance
    ( r <: Error H.Failure
    ) => MonadAssertion (Eff r) where
  throwAssertion f = throw f
  catchAssertion g h = g & trapIn h

getTestResult :: ()
  => r <: Error H.Failure
  => TestResult a
  -> Eff r a
getTestResult = \case
  TestResult a -> pure a
  TestFailure f -> throw f
  TestError e -> throwM e

runHedgehogProperty :: ()
  => r <: IOE
  => TMVar (H.PropertyT IO ())
  -> Eff (Hedgehog : r) a
  -> Eff r a
runHedgehogProperty tvAction =
  evalStaticRep (Hedgehog (PropertyEnv tvAction))

runHedgehogUnit :: ()
  => r <: IOE
  => TMVar (H.TestT IO ())
  -> Eff (Hedgehog : r) a
  -> Eff r a
runHedgehogUnit tvAction =
  evalStaticRep (Hedgehog (UnitTestEnv tvAction))