hedgehog 1.5 → 1.7
raw patch · 5 files changed
Files
- CHANGELOG.md +46/−18
- README.md +3/−3
- hedgehog.cabal +18/−12
- src/Hedgehog/Internal/Gen.hs +37/−34
- src/Hedgehog/Internal/State.hs +29/−18
CHANGELOG.md view
@@ -1,23 +1,37 @@+## Version 1.7 (2025-09-22)++* Fix eta-reduction issues for GHC 9.0; add CI and cabal support for GHC 9.0.2 ([#557][557], [@tomjaguarpaw][tomjaguarpaw])+* Allow lifted-async 0.11 ([#556][556], [@felixonmars][felixonmars])+* Remove `fromJust` call by using a separate existential wrapper ([#554][554], [@HuwCampbell][HuwCampbell])++## Version 1.6 (2025-09-08)++* Fix GitHub CI URL ([#545][545], [@tmcgilchrist][tmcgilchrist])+* Bump upper bounds for containers and random ([#544][544], [@moodmosaic][moodmosaic])+* Support GHC 9.12 ([#540][540], [@erikd][erikd])+* Add callstacks to generators that can error ([#538][538], [@ChickenProp][ChickenProp])+* Drop support for GHC 8.0.2 ([#538][538], [@ChickenProp][ChickenProp])+ ## Version 1.5 (2024-07-25) -* Bump containers and filepath dependencies ([#533](533), [@erikd][erikd])-* Hedgehog.Internal.Report: Add `configPrintShrinkPath` ([#531](531), [@sol][sol])-* Allow GHC 9.10 ([#530](530), [@erikd][erikd])-* hedgehog-{example,quickcheck,test-laws}: Raise QuickCheck bound ([#529](529), [@JackKelly-Bellroy][JackKelly-Bellroy])-* Allow to omit icons at the start of important output lines ([#524](524), [@sol][sol])-* Allow to omit source location from report ([#523](523), [@sol][sol])-* Fix "insufficient coverage" message ([#521](521), [@sol][sol])-* Support empty property names ([#520](520), [@sol][sol])-* Allow to disable the `recheckAt`-message ([#519](519), [@sol][sol])-* Remove redundant `Show` constraints: `evalMaybe`, `evalMaybeM` ([#516](516), [@endgame][endgame])-* Relax upper bound on `ansi-terminal` ([#515](515), [@moodmosaic][moodmosaic])-* Report.hs refactoring ([#514](514), [@sol][sol])-* Relax time dependency to < 1.15 ([#513](513), [@tomjaguarpaw][tomjaguarpaw])-* Bump barbies upper bound ([#510](510), [@jchia][jchia])-* Support primitive 0.9 ([#509](509), [@Vekhir][Vekhir])-* Show less context on failure ([#505](505), [@sol][sol])-* Allow GHC 9.8 ([#504](504), [@tomjaguarpaw][tomjaguarpaw])-* Wrap `evalMaybeM` and `evalEitherM` in `withFrozenCallStack` ([#499](499), [@ocharles][ocharles])+* Bump containers and filepath dependencies ([#533][533], [@erikd][erikd])+* Hedgehog.Internal.Report: Add `configPrintShrinkPath` ([#531][531], [@sol][sol])+* Allow GHC 9.10 ([#530][530], [@erikd][erikd])+* hedgehog-{example,quickcheck,test-laws}: Raise QuickCheck bound ([#529][529], [@JackKelly-Bellroy][JackKelly-Bellroy])+* Allow to omit icons at the start of important output lines ([#524][524], [@sol][sol])+* Allow to omit source location from report ([#523][523], [@sol][sol])+* Fix "insufficient coverage" message ([#521][521], [@sol][sol])+* Support empty property names ([#520][520], [@sol][sol])+* Allow to disable the `recheckAt`-message ([#519][519], [@sol][sol])+* Remove redundant `Show` constraints: `evalMaybe`, `evalMaybeM` ([#516][516], [@endgame][endgame])+* Relax upper bound on `ansi-terminal` ([#515][515], [@moodmosaic][moodmosaic])+* Report.hs refactoring ([#514][514], [@sol][sol])+* Relax time dependency to < 1.15 ([#513][513], [@tomjaguarpaw][tomjaguarpaw])+* Bump barbies upper bound ([#510][510], [@jchia][jchia])+* Support primitive 0.9 ([#509][509], [@Vekhir][Vekhir])+* Show less context on failure ([#505][505], [@sol][sol])+* Allow GHC 9.8 ([#504][504], [@tomjaguarpaw][tomjaguarpaw])+* Wrap `evalMaybeM` and `evalEitherM` in `withFrozenCallStack` ([#499][499], [@ocharles][ocharles]) ## Version 1.4 (2023-08-07) @@ -315,7 +329,21 @@ https://github.com/jchia [Vekhir]: https://github.com/Vekhir+[tmcgilchrist]:+ https://github.com/tmcgilchrist +[557]:+ https://github.com/hedgehogqa/haskell-hedgehog/pull/557+[556]:+ https://github.com/hedgehogqa/haskell-hedgehog/pull/556+[554]:+ https://github.com/hedgehogqa/haskell-hedgehog/pull/554+[544]:+ https://github.com/hedgehogqa/haskell-hedgehog/pull/544+[540]:+ https://github.com/hedgehogqa/haskell-hedgehog/pull/540+[538]:+ https://github.com/hedgehogqa/haskell-hedgehog/pull/538 [533]: https://github.com/hedgehogqa/haskell-hedgehog/pull/533 [531]:
README.md view
@@ -17,7 +17,7 @@ <div align="left"> -[Hedgehog](http://hedgehog.qa/) automatically generates a comprehensive array of test cases, exercising your software in ways human testers would never imagine.+[Hedgehog](https://hackage.haskell.org/package/hedgehog) automatically generates a comprehensive array of test cases, exercising your software in ways human testers would never imagine. Generate hundreds of test cases automatically, exposing even the most insidious of corner cases. Failures are automatically simplified, giving developers coherent, intelligible error messages. @@ -112,8 +112,8 @@ [hackage]: http://hackage.haskell.org/package/hedgehog [hackage-shield]: https://img.shields.io/hackage/v/hedgehog.svg?style=flat - [github-shield]: https://github.com/hedgehogqa/haskell-hedgehog/actions/workflows/ci.yaml/badge.svg- [github-ci]: https://github.com/hedgehogqa/haskell-hedgehog/actions/workflows/ci.yaml+ [github-shield]: https://github.com/hedgehogqa/haskell-hedgehog/actions/workflows/haskell-ci.yml/badge.svg+ [github-ci]: https://github.com/hedgehogqa/haskell-hedgehog/actions/workflows/haskell-ci.yml [haddock-hedgehog]: http://hackage.haskell.org/package/hedgehog/docs/Hedgehog.html [haddock-hedgehog-gen]: http://hackage.haskell.org/package/hedgehog/docs/Hedgehog-Gen.html
hedgehog.cabal view
@@ -1,4 +1,4 @@-version: 1.5+version: 1.7 name: hedgehog@@ -7,13 +7,13 @@ maintainer: Jacob Stanley <jacob@stanley.io> homepage:- https://hedgehog.qa+ http://github.com/hedgehogqa/haskell-hedgehog bug-reports: https://github.com/hedgehogqa/haskell-hedgehog/issues synopsis: Release with confidence. description:- <http://hedgehog.qa/ Hedgehog> automatically generates a comprehensive array+ <http://github.com/hedgehogqa/haskell-hedgehog/ Hedgehog> automatically generates a comprehensive array of test cases, exercising your software in ways human testers would never imagine. .@@ -33,20 +33,26 @@ build-type: Simple tested-with:- GHC == 8.0.2- , GHC == 8.2.2+ GHC == 8.2.2 , GHC == 8.4.4 , GHC == 8.6.5 , GHC == 8.8.3 , GHC == 8.10.1- , GHC == 9.2.1+ , GHC == 9.0.2+ , GHC == 9.2.7+ , GHC == 9.4.8+ , GHC == 9.6.6+ , GHC == 9.8.4+ , GHC == 9.10.1+ , GHC == 9.12.1+ extra-source-files: README.md CHANGELOG.md source-repository head type: git- location: git://github.com/hedgehogqa/haskell-hedgehog.git+ location: https://github.com/hedgehogqa/haskell-hedgehog library build-depends:@@ -57,22 +63,22 @@ , barbies >= 1.0 && < 2.2 , bytestring >= 0.10 && < 0.13 , concurrent-output >= 1.7 && < 1.11- , containers >= 0.4 && < 0.8+ , containers >= 0.4 && < 0.9 , deepseq >= 1.1.0.0 && < 1.6 , directory >= 1.2 && < 1.4 , erf >= 2.0 && < 2.1 , exceptions >= 0.7 && < 0.11- , lifted-async >= 0.7 && < 0.11+ , lifted-async >= 0.7 && < 0.12 , mmorph >= 1.0 && < 1.3 , monad-control >= 1.0 && < 1.1 , mtl >= 2.1 && < 2.4 , pretty-show >= 1.6 && < 1.11 , primitive >= 0.6 && < 0.10- , random >= 1.1 && < 1.3+ , random >= 1.1 && < 1.4 , resourcet >= 1.1 && < 1.4 , safe-exceptions >= 0.1 && < 0.2 , stm >= 2.4 && < 2.6- , template-haskell >= 2.10 && < 2.23+ , template-haskell >= 2.10 && < 2.24 , text >= 1.1 && < 2.2 , time >= 1.4 && < 1.15 , transformers >= 0.5 && < 0.7@@ -144,7 +150,7 @@ build-depends: hedgehog , base >= 3 && < 5- , containers >= 0.4 && < 0.8+ , containers >= 0.4 && < 0.9 , mmorph >= 1.0 && < 1.3 , mtl >= 2.1 && < 2.4 , pretty-show >= 1.6 && < 1.11
src/Hedgehog/Internal/Gen.hs view
@@ -231,6 +231,7 @@ import Hedgehog.Internal.Seed (Seed) import qualified Hedgehog.Internal.Seed as Seed import qualified Hedgehog.Internal.Shrink as Shrink+import Hedgehog.Internal.Source (HasCallStack, withFrozenCallStack) import Hedgehog.Internal.Tree (Tree, TreeT(..), NodeT(..)) import qualified Hedgehog.Internal.Tree as Tree import Hedgehog.Range (Size, Range)@@ -749,18 +750,19 @@ -- | Adjust the size parameter by transforming it with the given function. ---scale :: MonadGen m => (Size -> Size) -> m a -> m a+scale :: (HasCallStack, MonadGen m) => (Size -> Size) -> m a -> m a scale f =- withGenT $ \gen ->- GenT $ \size0 seed ->- let- size =- f size0- in- if size < 0 then- error "Hedgehog.Gen.scale: negative size"- else- runGenT size seed gen+ withFrozenCallStack $+ withGenT $ \gen ->+ GenT $ \size0 seed ->+ let+ size =+ f size0+ in+ if size < 0 then+ error "Hedgehog.Gen.scale: negative size"+ else+ runGenT size seed gen -- | Make a generator smaller by scaling its size parameter. --@@ -1191,8 +1193,8 @@ -- -- /The input list must be non-empty./ ---element :: (Foldable f, MonadGen m) => f a -> m a-element fa = case toList fa of+element :: (HasCallStack, Foldable f, MonadGen m) => f a -> m a+element fa = withFrozenCallStack $ case toList fa of [] -> error "Hedgehog.Gen.element: used with empty Foldable" xs -> do@@ -1205,8 +1207,8 @@ -- -- /The input list must be non-empty./ ---element_ :: MonadGen m => [a] -> m a-element_ = \case+element_ :: (HasCallStack, MonadGen m) => [a] -> m a+element_ l = withFrozenCallStack $ case l of [] -> error "Hedgehog.Gen.element: used with empty list" xs -> do@@ -1219,8 +1221,8 @@ -- -- /The input list must be non-empty./ ---choice :: MonadGen m => [m a] -> m a-choice = \case+choice :: (HasCallStack, MonadGen m) => [m a] -> m a+choice l = withFrozenCallStack $ case l of [] -> error "Hedgehog.Gen.choice: used with empty list" xs -> do@@ -1234,8 +1236,8 @@ -- -- /The input list must be non-empty./ ---frequency :: MonadGen m => [(Int, m a)] -> m a-frequency = \case+frequency :: (HasCallStack, MonadGen m) => [(Int, m a)] -> m a+frequency l = withFrozenCallStack $ case l of [] -> error "Hedgehog.Gen.frequency: used with empty list" xs0 -> do@@ -1815,22 +1817,23 @@ -- i <- Gen.int -- i /== 0 -- @-sample :: MonadIO m => Gen a -> m a+sample :: (HasCallStack, MonadIO m) => Gen a -> m a sample gen =- liftIO $- let- loop n =- if n <= 0 then- error "Hedgehog.Gen.sample: too many discards, could not generate a sample"- else do- seed <- Seed.random- case evalGen 30 seed gen of- Nothing ->- loop (n - 1)- Just x ->- pure $ Tree.treeValue x- in- loop (100 :: Int)+ withFrozenCallStack $+ liftIO $+ let+ loop n =+ if n <= 0 then+ error "Hedgehog.Gen.sample: too many discards, could not generate a sample"+ else do+ seed <- Seed.random+ case evalGen 30 seed gen of+ Nothing ->+ loop (n - 1)+ Just x ->+ pure $ Tree.treeValue x+ in+ loop (100 :: Int) -- | Run a generator with a random seed and print the outcome, and the first -- level of shrinks.
src/Hedgehog/Internal/State.hs view
@@ -35,7 +35,6 @@ -- * Commands , Command(..) , Callback(..)- , commandGenOK -- * Actions , Action(..)@@ -402,12 +401,27 @@ [Callback input output state] } --- | Checks that input for a command can be executed in the given state.++-- | An actionable command is a command that can generate an action given+-- the current symbolic state, that is, its @commandGen@ returns @Just@. ---commandGenOK :: Command gen m state -> state Symbolic -> Bool-commandGenOK (Command inputGen _ _) state =- Maybe.isJust (inputGen state)+-- This is an internal type required to hold on to the existential+-- types when building actions.+--+data Actionable gen m (state :: (Type -> Type) -> Type) =+ forall input output.+ (TraversableB input, Show (input Symbolic), Show output, Typeable output) =>+ Actionable {+ _actionableGen ::+ gen (input Symbolic) + , _actionableExecute ::+ input Concrete -> m output++ , _actionableCallbacks ::+ [Callback input output state]+ }+ -- | An instantiation of a 'Command' which can be executed, and its effect -- evaluated. --@@ -545,21 +559,19 @@ Gen.justT $ do Context state0 _ <- get - Command mgenInput exec callbacks <-- Gen.element_ $ filter (\c -> commandGenOK c state0) commands+ Actionable genInput exec callbacks <-+ Gen.element_+ [ Actionable gen exec callbacks+ | Command inputGen exec callbacks <- commands+ , Just gen <- [inputGen state0]+ ] -- If we shrink the input, we still want to use the same output. Otherwise -- any actions using this output as part of their input will be dropped. But -- the existing output is still in the context, so `contextNewVar` will -- create a new one. To avoid that, we generate the output before the input. output <- contextNewVar-- input <-- case mgenInput state0 of- Nothing ->- error "genCommand: internal error, tried to use generator with invalid state."- Just gen ->- hoist lift $ Gen.toGenT gen+ input <- hoist lift $ Gen.toGenT genInput if not $ callbackRequire callbacks state0 input then pure Nothing@@ -650,7 +662,7 @@ -> [Command gen m state] -> gen (Sequential m state) sequential range initial commands =- fmap (Sequential . fst) $+ Sequential . fst <$> genActions range commands (mkContext initial) -- | A sequential prefix of actions to execute, with two branches to execute in parallel.@@ -808,9 +820,8 @@ withFrozenCallStack $ let ok =- any successful .- fmap (checkActions initial) $- interleave branch1 branch2+ any (successful . checkActions initial) $+ interleave branch1 branch2 in if ok then pure ()