mockcat-1.3.0.0: test/Test/MockCat/ShouldBeCalledMockMSpec.hs
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE TypeApplications #-}
{-# OPTIONS_GHC -Wno-type-defaults #-}
{-# OPTIONS_GHC -fno-hpc #-}
module Test.MockCat.ShouldBeCalledMockMSpec (spec) where
import Control.Exception (ErrorCall(..), try)
import Control.Monad (replicateM_, void)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Reader (runReaderT)
import Test.Hspec
import Test.MockCat
import Prelude hiding (any)
spec :: Spec
spec = describe "shouldBeCalled API (mockM)" $ do
describe "Simple verification" do
it "records arguments and results" do
f <- mockM $ "a" ~> True
result <- f "a"
result `shouldBe` True
f `shouldBeCalled` "a"
it "fails when called with unexpected argument" do
f <- mockM $ "a" ~> True
void $ f "a"
f `shouldBeCalled` "b" `shouldThrow` anyErrorCall
it "anything expectation succeeds" do
f <- mockM $ any @String ~> True
void $ f "x"
f `shouldBeCalled` anything
it "anything expectation fails when never called" do
f <- mockM $ any @String ~> True
f `shouldBeCalled` anything `shouldThrow` anyErrorCall
it "never expectation" do
f <- mockM $ any @String ~> True
f `shouldBeCalled` (never `withArgs` "z")
void $ f "a"
f `shouldBeCalled` (never `withArgs` "a") `shouldThrow` anyErrorCall
describe "Count verification" do
it "times succeeds" do
f <- mockM $ "a" ~> True
replicateM_ 3 (void $ f "a")
f `shouldBeCalled` (times 3 `withArgs` "a")
it "times fails" do
f <- mockM $ "a" ~> True
replicateM_ 2 (void $ f "a")
f `shouldBeCalled` (times 3 `withArgs` "a") `shouldThrow` anyErrorCall
it "atLeast / atMost" do
f <- mockM $ "a" ~> True
replicateM_ 3 (void $ f "a")
f `shouldBeCalled` (atLeast 2 `withArgs` "a")
f `shouldBeCalled` (atMost 3 `withArgs` "a")
f `shouldBeCalled` (atMost 2 `withArgs` "a") `shouldThrow` anyErrorCall
it "greaterThan / lessThan" do
f <- mockM $ "a" ~> True
replicateM_ 3 (void $ f "a")
f `shouldBeCalled` (greaterThan 2 `withArgs` "a")
f `shouldBeCalled` (lessThan 4 `withArgs` "a")
f `shouldBeCalled` (lessThan 3 `withArgs` "a") `shouldThrow` anyErrorCall
describe "Multiple arguments" do
it "works with Param combinators" do
f <- mockM $ any @String ~> any @String ~> True
void $ f "x" "y"
f `shouldBeCalled` (any @String ~> any @String)
it "supports explicit Param values" do
f <- mockM $ param "x" ~> param "y" ~> True
void $ f "x" "y"
f `shouldBeCalled` ("x" ~> "y")
f `shouldBeCalled` ("y" ~> "x") `shouldThrow` anyErrorCall
it "accepts cases blocks" do
f <- mockM $ cases
[ "hello" ~> True
, "world" ~> False
]
void $ f "hello"
result <- f "world"
result `shouldBe` False
f `shouldBeCalled` ("hello" :: String)
f `shouldBeCalled` ("world" :: String)
describe "Order verification" do
it "validates inOrderWith" do
f <- mockM $ any @String ~> ()
void $ f "first"
void $ f "second"
f `shouldBeCalled` inOrderWith ["first", "second"]
f `shouldBeCalled` inOrderWith ["second", "first"] `shouldThrow` anyErrorCall
it "validates inPartialOrderWith" do
f <- mockM $ any @String ~> ()
void $ f "alpha"
void $ f "beta"
void $ f "gamma"
f `shouldBeCalled` inPartialOrderWith ["alpha", "gamma"]
f `shouldBeCalled` inPartialOrderWith ["gamma", "alpha"] `shouldThrow` anyErrorCall
describe "named mocks and errors" do
it "reports names in error messages" do
f <- mockM (label "named" :: Label) $ "a" ~> True
result <- f "a"
result `shouldBe` True
e <- try (f `shouldBeCalled` "b") :: IO (Either ErrorCall ())
case e of
Left (ErrorCall msg) -> msg `shouldContain` "named"
Right _ -> expectationFailure "expected an error"
describe "integration with transformer stacks" do
it "works inside ReaderT IO" do
runReaderT @() @IO
(do
f <- mockM $ any @String ~> True
void $ f "lifted"
void $ f "lifted"
liftIO $ f `shouldBeCalled` (times 2 `withArgs` "lifted"))
()