content: {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE RankNTypes #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# LANGUAGE TypeApplications #-}
  {-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
  {-# HLINT ignore "Eta reduce" #-}
  module Empty
  ( tests
  , gen0
  , test
  ) where
  
  import qualified Control.Carrier.Empty.Church as C.Church
  import qualified Control.Carrier.Empty.Maybe as C.Maybe
  import qualified Control.Monad.Trans.Maybe as T.Maybe
  import           Control.Effect.Empty
  import           Data.Maybe (maybeToList)
  import           Gen
  import qualified Monad
  import qualified MonadFix
  
  tests :: TestTree
  tests = testGroup "Empty"
    [ testGroup "EmptyC (Church)" $
      [ testMonad
      , testMonadFix
      , testEmpty
      ] >>= ($ runL (fmap maybeToList . C.Church.runEmpty (pure Nothing) (pure . Just)))
    , testGroup "EmptyC (Maybe)" $
      [ testMonad
      , testMonadFix
      , testEmpty
      ] >>= ($ runL (fmap maybeToList . C.Maybe.runEmpty))
    , testGroup "MaybeT" $ testEmpty (runL (fmap maybeToList . T.Maybe.runMaybeT))
    , testGroup "Maybe"  $ testEmpty (runL (pure . maybeToList))
    ] where
    testMonad    run = Monad.test    (m gen0 (\ _ _ -> [])) a b c initial run
    testMonadFix run = MonadFix.test (m gen0 (\ _ _ -> [])) a b   initial run
    testEmpty    run = Empty.test    (m gen0 (\ _ _ -> [])) a b   initial run
    initial = identity <*> unit
  
  
  gen0 :: Has Empty sig m => GenTerm a -> [GenTerm (m a)]
  gen0 _ = [ label "empty" empty ]
  
  
  test
    :: forall a b m f sig
    .  (Has Empty sig m, Arg a, Eq b, Show a, Show b, Vary a, Functor f)
    => GenM m
    -> GenTerm a
    -> GenTerm b
    -> GenTerm (f ())
    -> Run f [] m
    -> [TestTree]
  test m _ b i (Run runEmpty) =
    [ testProperty "empty annihilates >>=" . forall_ (i :. fn @a (m b) :. Nil) $
      \ i k -> runEmpty ((empty >>= k) <$ i) === runEmpty (empty <$ i)
    ]
  