module Main (main) where import Control.Monad.State (evalState) import Control.Monad.State.Class (MonadState, get, put) import Control.Monad.Trans.State (evalStateT) import Hedgehog (withTests) import qualified Hedgehog.Gen as Gen import qualified Hedgehog.Range as Range import Test.Lawful.Hedgehog (forAll, forAllShow, testLaws, testLawsWith) import Test.Lawful.Types (Laws, assert, discard) import Test.Tasty (TestTree, defaultMain, testGroup) import Test.Tasty.ExpectedFailure (expectFailBecause) main :: IO () main = defaultMain tests monadStateLaws :: (MonadState s m, Eq s) => m s -> Laws m monadStateLaws gen = [ ( "get returns what was put", do a0 <- get a <- gen if a == a0 then discard else do put a a' <- get assert $ a' == a ) ] newtype NoShow = NoShow Int deriving (Eq) tests :: TestTree tests = testGroup "lawful-classes-hedgehog" [ testGroup "StateT Int" [ testLaws "monadStateLaws" (`evalStateT` (0 :: Int)) (monadStateLaws $ forAll $ Gen.integral Range.linearBounded) ], testGroup "StateT NoShow" [ testLaws "monadStateLaws" (`evalStateT` NoShow 0) (monadStateLaws (forAllShow (\(NoShow _) -> "NoShow") (NoShow <$> Gen.integral Range.linearBounded))) ], testGroup "StateT ()" [ expectFailBecause "() has only one possible value" $ testLaws "monadStateLaws" (`evalStateT` ()) (monadStateLaws $ forAll $ pure ()) ], testGroup "State Int" [ testLawsWith (withTests 1) "monadStateLaws" (pure . flip evalState (0 :: Int)) (monadStateLaws $ pure 1) ] ]