content: module KnownRowSpec where
  
  import Polysemy
  import Polysemy.Error
  import Polysemy.State
  import Polysemy.Internal
  import Polysemy.Internal.Union
  
  import Test.Hspec
  
  -- | A variant of 'runState' that uses 'stateToIO' if @r@ contains @Embed IO@.
  -- (Can also be extended to check for @Final IO@)
  runState' :: forall s r a. KnownRow r => s -> Sem (State s ': r) a -> Sem r (s, a)
  runState' s sem = case tryMembership @(Embed IO) of
    Just proof -> subsumeUsing proof (stateToIO s (raiseUnder sem))
    _          -> runState s sem
  
  
  test :: (Member (Error ()) r, KnownRow r)
       => Sem r String
  test = fmap fst $ runState' "" $ do
    put "local state"
    _ <- (put "global state" >> throw ()) `catch` \() -> return ()
    return ()
  
  spec :: Spec
  spec = parallel $ describe "tryMembership" $ do
    it "should return a valid proof when the targeted \
       \ effect is part of the row" $ do
      res <- runM . runError @() $ test
      res `shouldBe` Right "global state"
    it "should not return a valid proof when the targeted \
       \ effect is not part of the row" $ do
      let res = run . runError @() $ test
      res `shouldBe` Right "local state"
  