packages feed

mockcat 0.5.4.0 → 0.5.5.0

raw patch · 6 files changed

+73/−22 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Test.MockCat.MockT: expectApplyTimes :: forall (m :: Type -> Type). MonadIO m => MockT m () -> Int -> MockT m ()
+ Test.MockCat.MockT: expectNever :: forall (m :: Type -> Type). MonadIO m => MockT m () -> MockT m ()

Files

CHANGELOG.md view
@@ -6,6 +6,18 @@ and this project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/). +## 0.5.5.0+### Added+- Aliases `expectApplyTimes` and `expectNever` (preferred names) for pre-run expectation declarations.++### Documentation+- README (EN/JA) now recommends `expectApplyTimes` / `expectNever` over legacy `applyTimesIs` / `neverApply`.+- Clarified that `expectApplyTimes n` is the canonical form; `expectNever` is sugar for `expectApplyTimes 0`.++### Notes+- Legacy names remain exported for backward compatibility (no deprecation pragma yet). They may receive a soft deprecation notice in a future minor release after community feedback.++ ## 0.5.4.0 ### Added - Parallel execution support (verified counting under concurrency, stress tests).
README-ja.md view
@@ -211,14 +211,14 @@     writeFile outputPath content ``` -これは次のように`applyTimesIs`関数を使うことで実現できます。+これは次のように`expectApplyTimes`関数(旧: `applyTimesIs`)を使うことで実現できます。 ```haskell import Test.MockCat as M ... it "Read, and output files (contain ng word)" do   result <- runMockT do     _readFile ("input.txt" |> pack "contains ngWord")-    _writeFile ("output.txt" |> M.any |> ()) `applyTimesIs` 0+    _writeFile ("output.txt" |> M.any |> ()) `expectApplyTimes` 0     operationProgram "input.txt" "output.txt"    result `shouldBe` ()@@ -442,7 +442,7 @@ spec :: Spec spec = do   it "named stub" do-    f <- createNamedStubFun "named stub" $ "x" |> "y" |> True+    f <- createNamedStubFn "named stub" $ "x" |> "y" |> True     f "x" "z" `shouldBe` True ``` 期待した引数に適用されなかった場合に出力されるエラーメッセージには、この名前が含まれるようになります。
README.md view
@@ -27,6 +27,22 @@ * Template Haskell helpers: `makeMock` to cut boilerplate for typeclasses * No hidden global state: tests stay isolated +### Tested Versions+mockcat is continuously tested in CI across these configurations (see `.github/workflows/Test.yml`):++| GHC | Cabal | OS |+|-----|-------|----|+| 9.2.8 | 3.10.3.0 / 3.12.1.0 | Ubuntu, macOS, Windows |+| 9.4.8 | 3.10.3.0 / 3.12.1.0 | Ubuntu, macOS, Windows |+| 9.6.3 | 3.10.3.0 / 3.12.1.0 | Ubuntu, macOS, Windows |+| 9.8.2 | 3.10.3.0 / 3.12.1.0 | Ubuntu, macOS, Windows |+| 9.10.1 | 3.10.3.0 / 3.12.1.0 | Ubuntu, macOS, Windows |++Notes:+* The `tested-with` stanza in the cabal file reflects the same GHC list.+* Other patch releases within the same minor series typically work; open an issue if you hit a snag.+* Older GHCs (< 9.2) are not targeted due to dependency bounds and modern TH/unliftio requirements.+ Designed to be something you can pick up to stub one or two spots and then forget again – more a handy extension of regular Haskell testing than a new framework.  ### Quick Start@@ -71,7 +87,7 @@  Non‑invocation (two styles): ```haskell-  _putKV ("x" |> "y" |> ()) `applyTimesIs` 0+  _putKV ("x" |> "y" |> ()) `expectApplyTimes` 0  -- (legacy name: applyTimesIs)   neverApply $ _putKV ("x" |> "y" |> ()) ``` @@ -79,7 +95,7 @@ * Pipeline DSL: `a |> b |> returnValue` describes one expected application. * Matchers: `any`, `expect p label`, `expect_ p`, `$(expectByExpr [| predicate |])`. * Argument‑dependent returns: `onCase` or `cases [...]` (including differing values for same arg on later occurrences).-* Counting: `applyTimesIs`, `neverApply`, plus `shouldApplyTimes*` predicates on mocks.+* Counting: `expectApplyTimes` (legacy: `applyTimesIs`), `expectNever` (legacy: `neverApply`), plus `shouldApplyTimes*` predicates on mocks. * Ordering: `shouldApplyInOrder`, `shouldApplyInPartialOrder`. * Concurrency: Call recorded only when result evaluated; counting atomic. * Partial mocks: `makePartialMock` for generating only some methods.@@ -298,14 +314,14 @@   unless (pack "ngWord" `isInfixOf` content) $     writeFile outputPath content ```-This can be accomplished by using the `applyTimesIs` function as follows.+This can be accomplished by using the `expectApplyTimes` function (legacy name: `applyTimesIs`) as follows. ```haskell import Test.MockCat as M ... it "Read, and output files (contain ng word)" do   result <- runMockT do     _readFile ("input.txt" |> pack "contains ngWord")-    _writeFile ("output.txt" |> M.any |> ()) `applyTimesIs` 0+    _writeFile ("output.txt" |> M.any |> ()) `expectApplyTimes` 0     operationProgram "input.txt" "output.txt"    result `shouldBe` ()@@ -513,7 +529,7 @@ spec :: Spec spec = do   it "named stub" do-    f <- createNamedStubFun "named stub" $ "x" |> "y" |> True+  f <- createNamedStubFn "named stub" $ "x" |> "y" |> True     f "x" "z" `shouldBe` True ``` The error message printed when a stub function is not applied to an expected argument will include this name.
mockcat.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           mockcat-version:        0.5.4.0+version:        0.5.5.0 synopsis:       Mock library for test in Haskell. description:    mockcat is a small mocking / stubbing DSL for Haskell tests.                 .@@ -30,6 +30,12 @@ license:        MIT license-file:   LICENSE build-type:     Simple+tested-with:+    GHC == 9.2.8+  , GHC == 9.4.8+  , GHC == 9.6.3+  , GHC == 9.8.2+  , GHC == 9.10.1 extra-source-files:     README.md     README-ja.md
src/Test/MockCat/Mock.hs view
@@ -7,7 +7,7 @@ {-# HLINT ignore "Use null" #-} {-# OPTIONS_GHC -Wno-name-shadowing #-} -{- | This module provides bellow functions.+{- | This module provides the following functions.    - Create mocks that can be stubbed and verified. @@ -527,13 +527,13 @@ doVerify :: (Eq a, Show a) => Maybe MockName -> AppliedParamsList a -> VerifyMatchType a -> Maybe VerifyFailed doVerify name list (MatchAny a) = do   guard $ notElem a list-  pure $ verifyFailedMesssage name list a+  pure $ verifyFailedMessage name list a doVerify name list (MatchAll a) = do   guard $ Prelude.any (a /=) list-  pure $ verifyFailedMesssage name list a+  pure $ verifyFailedMessage name list a -verifyFailedMesssage :: Show a => Maybe MockName -> AppliedParamsList a -> a -> VerifyFailed-verifyFailedMesssage name appliedParams expected =+verifyFailedMessage :: Show a => Maybe MockName -> AppliedParamsList a -> a -> VerifyFailed+verifyFailedMessage name appliedParams expected =   VerifyFailed $     intercalate       "\n"
src/Test/MockCat/MockT.hs view
@@ -5,7 +5,15 @@ {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# OPTIONS_GHC -Wno-name-shadowing #-}-module Test.MockCat.MockT (MockT(..), Definition(..), runMockT, applyTimesIs, neverApply, MonadMockDefs(..)) where+module Test.MockCat.MockT (+  MockT(..), Definition(..),+  runMockT,+  applyTimesIs,+  expectApplyTimes,+  neverApply,+  expectNever,+  MonadMockDefs(..)+  ) where import Control.Monad.IO.Class (MonadIO(..)) import Control.Monad.Trans.Class (MonadTrans(..)) import Control.Monad.Reader (ReaderT(..), runReaderT)@@ -28,7 +36,7 @@     appear in the verification log.   * Order-sensitive checks reflect evaluation order, not necessarily wall-clock     start order between threads.-  * Perform verification (e.g. 'shouldApplyTimes', 'applyTimesIs') after all+  * Perform verification (e.g. 'shouldApplyTimes', 'expectApplyTimes') after all     parallel work has completed; running it mid-flight may observe fewer calls     simply because some results are still lazy.   * Each 'runMockT' call uses a fresh IORef store; mocks are not shared across@@ -94,17 +102,18 @@   for_ defs (\(Definition _ m v) -> liftIO $ v m)   pure a -{- | Specify how many times a stub function (or group of stub definitions) must-     be applied (to /any/ arguments). The function patches the verification-     predicate for the provided stub definitions so that, after 'runMockT'-     completes, the total number of evaluated applications is checked.+{- | (Preferred: 'expectApplyTimes'; legacy: 'applyTimesIs')+  Specify how many times a stub function (or group of stub definitions) must+  be applied (to /any/ arguments). The function patches the verification+  predicate for the provided stub definitions so that, after 'runMockT'+  completes, the total number of evaluated applications is checked.    Concurrency & laziness notes:     * Counting is thread-safe: each evaluated application contributes exactly 1.     * An application is only counted once its return value is evaluated; ensure       your test forces (e.g. via @shouldBe@ or sequencing) all stub results       before relying on the count.-    * Invoke 'applyTimesIs' inside the 'runMockT' block during setup; do not+    * Invoke 'expectApplyTimes' (or legacy 'applyTimesIs') inside the 'runMockT' block during setup; do not       call it after the block ends.    @@@ -132,7 +141,7 @@     it "test runMockT" do       result <- runMockT do         _readFile ("input.txt" |> pack "content")-        _writeFile ("output.text" |> pack "content" |> ()) `applyTimesIs` 0+        _writeFile ("output.text" |> pack "content" |> ()) `expectApplyTimes` 0         operationProgram "input.txt" "output.text"        result `shouldBe` ()@@ -149,6 +158,10 @@   liftIO $ atomicModifyIORef' ref (\xs -> (xs ++ patched, ()))   pure () +-- | Preferred clearer alias for 'applyTimesIs'. Use this in new code.+expectApplyTimes :: MonadIO m => MockT m () -> Int -> MockT m ()+expectApplyTimes = applyTimesIs+ neverApply :: MonadIO m => MockT m () -> MockT m () neverApply (MockT inner) = MockT $ ReaderT $ \ref -> do   tmp <- liftIO $ newIORef []@@ -157,6 +170,10 @@   let patched = map (\(Definition s m _) -> Definition s m (`shouldApplyTimesToAnything` 0)) defs   liftIO $ atomicModifyIORef' ref (\xs -> (xs ++ patched, ()))   pure ()++-- | Alias for 'neverApply' providing naming symmetry with 'expectApplyTimes'.+expectNever :: MonadIO m => MockT m () -> MockT m ()+expectNever = neverApply  instance MonadIO m => MonadMockDefs (MockT m) where   addDefinition d = MockT $ ReaderT $ \ref -> liftIO $ atomicModifyIORef' ref (\xs -> (xs ++ [d], ()))