packages feed

hedgehog 0.2.2 → 0.3

raw patch · 10 files changed

+322/−35 lines, 10 filesdep ~mmorphPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: mmorph

API changes (from Hackage documentation)

+ Hedgehog: distribute :: (Distributive g, Transformer f g m) => g (f m) a -> f (g m) a
+ Hedgehog: withExceptT :: (Monad m, Show x, HasCallStack) => Test (ExceptT x m) a -> Test m a
+ Hedgehog.Gen: instance Hedgehog.Internal.Distributive.Distributive Hedgehog.Gen.Gen
+ Hedgehog.Internal.Distributive: (Monad m, Monad (f m), Monad (g m), Monad (f (g m)), MonadTrans f,
+ Hedgehog.Internal.Distributive: (g :: (* -> *) -> * -> *)
+ Hedgehog.Internal.Distributive: (m :: * -> *) :: Constraint;
+ Hedgehog.Internal.Distributive: MFunctor f);
+ Hedgehog.Internal.Distributive: class Distributive g where type Transformer (f :: (* -> *) -> * -> *) (g :: (* -> *) -> * -> *) (m :: * -> *) :: Constraint type Transformer f g m = (Monad m, Monad (f m), Monad (g m), Monad (f (g m)), MonadTrans f, MFunctor f) where {
+ Hedgehog.Internal.Distributive: distribute :: (Distributive g, Transformer f g m) => g (f m) a -> f (g m) a
+ Hedgehog.Internal.Distributive: instance GHC.Base.Monoid w => Hedgehog.Internal.Distributive.Distributive (Control.Monad.Trans.Writer.Lazy.WriterT w)
+ Hedgehog.Internal.Distributive: instance Hedgehog.Internal.Distributive.Distributive (Control.Monad.Trans.Except.ExceptT x)
+ Hedgehog.Internal.Distributive: instance Hedgehog.Internal.Distributive.Distributive (Control.Monad.Trans.Reader.ReaderT r)
+ Hedgehog.Internal.Distributive: instance Hedgehog.Internal.Distributive.Distributive Control.Monad.Trans.Maybe.MaybeT
+ Hedgehog.Internal.Distributive: type Transformer f g m =
+ Hedgehog.Internal.Distributive: type family Transformer (f :: (* -> *) -> * -> *)
+ Hedgehog.Internal.Distributive: }
+ Hedgehog.Internal.Property: instance Hedgehog.Internal.Distributive.Distributive Hedgehog.Internal.Property.Test
+ Hedgehog.Internal.Property: withExceptT :: (Monad m, Show x, HasCallStack) => Test (ExceptT x m) a -> Test m a
+ Hedgehog.Internal.Tree: fromNode :: Applicative m => Node m a -> Tree m a
+ Hedgehog.Internal.Tree: instance Hedgehog.Internal.Distributive.Distributive Hedgehog.Internal.Tree.Tree
+ Hedgehog.Range: exponential :: Integral a => a -> a -> Range a
+ Hedgehog.Range: exponentialBounded :: (Bounded a, Integral a) => Range a
+ Hedgehog.Range: exponentialFloat :: (Floating a, Ord a) => a -> a -> Range a
+ Hedgehog.Range: exponentialFloatFrom :: (Floating a, Ord a) => a -> a -> a -> Range a
+ Hedgehog.Range: exponentialFrom :: Integral a => a -> a -> a -> Range a
+ Hedgehog.Range: scaleExponential :: Integral a => Size -> a -> a -> a
+ Hedgehog.Range: scaleExponentialFloat :: Floating a => Size -> a -> a -> a
- Hedgehog: tripping :: HasCallStack => Applicative f => Monad m => Show (f a) => Eq (f a) => a -> (a -> b) -> (b -> f a) -> Test m ()
+ Hedgehog: tripping :: HasCallStack => Applicative f => Monad m => Show b => Show (f a) => Eq (f a) => a -> (a -> b) -> (b -> f a) -> Test m ()
- Hedgehog.Internal.Tripping: tripping :: HasCallStack => Applicative f => Monad m => Show (f a) => Eq (f a) => a -> (a -> b) -> (b -> f a) -> Test m ()
+ Hedgehog.Internal.Tripping: tripping :: HasCallStack => Applicative f => Monad m => Show b => Show (f a) => Eq (f a) => a -> (a -> b) -> (b -> f a) -> Test m ()

Files

CHANGELOG.md view
@@ -1,20 +1,29 @@+## Version 0.3 (2017-06-11)++- Exponential range combinators (#43, @chris-martin)+- Roundtrip example, check out the [blog post](http://teh.id.au/posts/2017/06/07/round-trip-property/) (#85, @thumphries)+- `tripping` now displays intermediate value (#85, @jystic)+- `distribute` function for pulling a transformer out to the top level (#83, @jystic)+- `withExceptT` function for executing tests with an inner `ExceptT` (e.g. `Test (ExceptT x m) a`) (#83, @jystic)+ ## Version 0.2.2 (2017-05-16) -- Fixed scope of `unicode` character generators.-- Widen version bounds for some dependencies.-- Expose test modules to fix build on nix / hydra.+- Fixed scope of `unicode` character generators (#76, @moodmosaic)+- Widen version bounds for some dependencies (#80, @amarpotghan)+- Expose test modules to fix build on nix / hydra (#78, @amarpotghan)+- Fixes for GHC 8.2 RC2 (#77, @erikd)  ## Version 0.2.1 (2017-05-09) -- Added `ascii`, `latin1`, `unicode` character generators.+- Added `ascii`, `latin1`, `unicode` character generators (#73, @jystic)  ## Version 0.2 (2017-05-06) -- Added a quiet test runner which can be activated by setting `HEDGEHOG_VERBOSITY=0`-- Concurrent test runner does not display tests until they are executing.-- Test runner now outputs a summary of how many successful / failed tests were run.-- `checkSequential` and `checkParallel` now allow for tests to be run without Template Haskell.-- Auto-discovery of properties is now available via `discover` instead of being baked in.-- `annotate` allows source code to be annotated inline with extra information.-- `forAllWith` can be used to generate values without a `Show` instance.-- Removed uses of `Typeable` to allow for generating types which cannot implement it.+- Added a quiet test runner which can be activated by setting `HEDGEHOG_VERBOSITY=0` (@jystic)+- Concurrent test runner does not display tests until they are executing (@jystic)+- Test runner now outputs a summary of how many successful / failed tests were run (@jystic)+- `checkSequential` and `checkParallel` now allow for tests to be run without Template Haskell (@jystic)+- Auto-discovery of properties is now available via `discover` instead of being baked in (@jystic)+- `annotate` allows source code to be annotated inline with extra information (@jystic)+- `forAllWith` can be used to generate values without a `Show` instance (@jystic)+- Removed uses of `Typeable` to allow for generating types which cannot implement it (@jystic)
README.md view
@@ -74,7 +74,7 @@ ```   [hackage]: http://hackage.haskell.org/package/hedgehog- [hackage-shield]: http://img.shields.io/hackage/v/hedgehog.svg?style=flat+ [hackage-shield]: https://img.shields.io/badge/hackage-v0.3-blue.svg   [travis]: https://travis-ci.org/hedgehogqa/haskell-hedgehog  [travis-shield]: https://travis-ci.org/hedgehogqa/haskell-hedgehog.svg?branch=master
hedgehog.cabal view
@@ -1,7 +1,7 @@ name:   hedgehog version:-  0.2.2+  0.3 license:   BSD3 author:@@ -54,7 +54,7 @@     , containers                      >= 0.4        && < 0.6     , directory                       >= 1.2        && < 1.4     , exceptions                      >= 0.7        && < 0.9-    , mmorph                          >= 1.0        && < 1.1+    , mmorph                          >= 1.0        && < 1.2     , mtl                             >= 2.1        && < 2.3     , pretty-show                     >= 1.6        && < 1.7     , primitive                       >= 0.6        && < 0.7@@ -90,6 +90,7 @@      Hedgehog.Internal.Config     Hedgehog.Internal.Discovery+    Hedgehog.Internal.Distributive     Hedgehog.Internal.Property     Hedgehog.Internal.Queue     Hedgehog.Internal.Region
src/Hedgehog.hs view
@@ -84,23 +84,29 @@    , liftEither   , liftExceptT+  , withExceptT   , withResourceT    , tripping++  -- * Transformers+  , distribute   ) where  import           Hedgehog.Gen (Gen)+import           Hedgehog.Internal.Distributive (distribute)+import           Hedgehog.Internal.Property (annotate, annotateShow) import           Hedgehog.Internal.Property (assert, (===)) import           Hedgehog.Internal.Property (discard, failure, success) import           Hedgehog.Internal.Property (DiscardLimit, withDiscards)-import           Hedgehog.Internal.Property (forAll, forAllWith)-import           Hedgehog.Internal.Property (annotate, annotateShow) import           Hedgehog.Internal.Property (footnote, footnoteShow)-import           Hedgehog.Internal.Property (liftEither, liftExceptT, withResourceT)+import           Hedgehog.Internal.Property (forAll, forAllWith)+import           Hedgehog.Internal.Property (liftEither, liftExceptT) import           Hedgehog.Internal.Property (Property, PropertyName, Group(..), GroupName) import           Hedgehog.Internal.Property (ShrinkLimit, withShrinks) import           Hedgehog.Internal.Property (Test, property) import           Hedgehog.Internal.Property (TestLimit, withTests)+import           Hedgehog.Internal.Property (withExceptT, withResourceT) import           Hedgehog.Internal.Runner (check, recheck, checkSequential, checkParallel) import           Hedgehog.Internal.Seed (Seed(..)) import           Hedgehog.Internal.TH (discover)
src/Hedgehog/Gen.hs view
@@ -145,7 +145,7 @@   ) where  import           Control.Applicative (Alternative(..))-import           Control.Monad (MonadPlus(..), mfilter, filterM, replicateM, ap)+import           Control.Monad (MonadPlus(..), mfilter, filterM, replicateM, ap, join) import           Control.Monad.Base (MonadBase(..)) import           Control.Monad.Catch (MonadThrow(..), MonadCatch(..)) import           Control.Monad.Error.Class (MonadError(..))@@ -178,6 +178,7 @@ import qualified Data.Text.Encoding as Text import           Data.Word (Word8, Word16, Word32, Word64) +import           Hedgehog.Internal.Distributive (Distributive(..)) import           Hedgehog.Internal.Seed (Seed) import qualified Hedgehog.Internal.Seed as Seed import qualified Hedgehog.Internal.Shrink as Shrink@@ -233,7 +234,7 @@       Nothing ->         mzero       Just (Node x xs) ->-        pure (x, liftTree . Tree . pure $ Node x xs)+        pure (x, liftTree . Tree.fromNode $ Node x xs)  -- | Lift a predefined shrink tree in to a generator, ignoring the seed and the --   size.@@ -246,14 +247,8 @@ --   at the nodes. 'Nothing' means discarded, 'Just' means we have a value. -- runDiscardEffect :: Monad m => Tree (MaybeT m) a -> Tree m (Maybe a)-runDiscardEffect s =-  Tree $ do-    mx <- runMaybeT $ runTree s-    case mx of-      Nothing ->-        pure $ Node Nothing []-      Just (Node x xs) ->-        pure $ Node (Just x) (fmap runDiscardEffect xs)+runDiscardEffect =+  runMaybeT . distribute  ------------------------------------------------------------------------ -- Gen instances@@ -330,6 +325,21 @@ instance MMonad Gen where   embed =     embedGen++distributeGen :: Transformer t Gen m => Gen (t m) a -> t (Gen m) a+distributeGen x =+  join . lift . Gen $ \size seed ->+    pure . hoist liftTree . distribute . hoist distribute $ runGen size seed x++instance Distributive Gen where+  type Transformer t Gen m = (+      Monad (t (Gen m))+    , Transformer t MaybeT m+    , Transformer t Tree (MaybeT m)+    )++  distribute =+    distributeGen  instance PrimMonad m => PrimMonad (Gen m) where   type PrimState (Gen m) =
+ src/Hedgehog/Internal/Distributive.hs view
@@ -0,0 +1,51 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeOperators #-}+module Hedgehog.Internal.Distributive (+    Distributive(..)+  ) where++import           Control.Monad (join)+import           Control.Monad.Morph (MFunctor(..))+import           Control.Monad.Trans.Class (MonadTrans(..))+import           Control.Monad.Trans.Except (ExceptT(..), runExceptT)+import           Control.Monad.Trans.Maybe (MaybeT(..))+import           Control.Monad.Trans.Reader (ReaderT(..))+import           Control.Monad.Trans.Writer (WriterT(..))++import           GHC.Exts (Constraint)+++class Distributive g where+  type Transformer+    (f :: (* -> *) -> * -> *)+    (g :: (* -> *) -> * -> *)+    (m :: * -> *) :: Constraint++  type Transformer f g m = (+        Monad m+      , Monad (f m)+      , Monad (g m)+      , Monad (f (g m))+      , MonadTrans f+      , MFunctor f+      )++  distribute :: Transformer f g m => g (f m) a -> f (g m) a++instance Distributive MaybeT where+  distribute x =+    lift . MaybeT . pure =<< hoist lift (runMaybeT x)++instance Distributive (ExceptT x) where+  distribute x =+    lift . ExceptT . pure =<< hoist lift (runExceptT x)++instance Monoid w => Distributive (WriterT w) where+  distribute x =+    lift . WriterT . pure =<< hoist lift (runWriterT x)++instance Distributive (ReaderT r) where+  distribute x =+    join . lift . ReaderT $ \r ->+      pure . hoist lift $ runReaderT x r
src/Hedgehog/Internal/Property.hs view
@@ -48,6 +48,7 @@    , liftEither   , liftExceptT+  , withExceptT   , withResourceT    -- * Internal@@ -81,6 +82,7 @@  import           Hedgehog.Gen (Gen) import qualified Hedgehog.Gen as Gen+import           Hedgehog.Internal.Distributive import           Hedgehog.Internal.Show import           Hedgehog.Internal.Source @@ -219,6 +221,24 @@   hoist f =     Test . hoist (hoist (hoist f)) . unTest +distributeTest :: Transformer t Test m => Test (t m) a -> t (Test m) a+distributeTest =+  hoist Test .+  distribute .+  hoist distribute .+  hoist (hoist distribute) .+  unTest++instance Distributive Test where+  type Transformer t Test m = (+      Transformer t Gen m+    , Transformer t (WriterT [Log]) (Gen m)+    , Transformer t (ExceptT Failure) (WriterT [Log] (Gen m))+    )++  distribute =+    distributeTest+ instance PrimMonad m => PrimMonad (Test m) where   type PrimState (Test m) =     PrimState m@@ -448,6 +468,13 @@ liftExceptT :: (Monad m, Show x, HasCallStack) => ExceptT x m a -> Test m a liftExceptT m =   withFrozenCallStack liftEither =<< lift (runExceptT m)++-- | Fails the test if the 'ExceptT' is 'Left', otherwise returns the value in+--   the 'Right'.+--+withExceptT :: (Monad m, Show x, HasCallStack) => Test (ExceptT x m) a -> Test m a+withExceptT m =+  withFrozenCallStack liftEither =<< runExceptT (distribute m)  -- | Run a computation which requires resource acquisition / release. --
src/Hedgehog/Internal/Tree.hs view
@@ -9,6 +9,8 @@     Tree(..)   , Node(..) +  , fromNode+   , unfold   , unfoldForest @@ -19,7 +21,7 @@   ) where  import           Control.Applicative (Alternative(..))-import           Control.Monad (MonadPlus(..), ap)+import           Control.Monad (MonadPlus(..), ap, join) import           Control.Monad.Base (MonadBase(..)) import           Control.Monad.Catch (MonadThrow(..), MonadCatch(..), Exception) import           Control.Monad.Error.Class (MonadError(..))@@ -37,6 +39,8 @@ import           Data.Functor.Classes (showsUnaryWith, showsBinaryWith) #endif +import           Hedgehog.Internal.Distributive+ ------------------------------------------------------------------------  -- | An effectful tree, each node in the tree can have an effect before it is@@ -55,6 +59,12 @@     , nodeChildren :: [Tree m a]     } +-- | Create a 'Tree' from a 'Node'+--+fromNode :: Applicative m => Node m a -> Tree m a+fromNode =+  Tree . pure+ -- | Create a tree from a value and an unfolding function. -- unfold :: Monad m => (a -> [a]) -> a -> Tree m a@@ -166,6 +176,19 @@ instance MMonad Tree where   embed f m =     embedTree f m++distributeNode :: Transformer t Tree m => Node (t m) a -> t (Tree m) a+distributeNode (Node x xs) =+  join . lift . fromNode . Node (pure x) $+    fmap (pure . distributeTree) xs++distributeTree :: Transformer t Tree m => Tree (t m) a -> t (Tree m) a+distributeTree x =+  distributeNode =<< hoist lift (runTree x)++instance Distributive Tree where+  distribute =+    distributeTree  instance PrimMonad m => PrimMonad (Tree m) where   type PrimState (Tree m) =
src/Hedgehog/Internal/Tripping.hs view
@@ -7,25 +7,29 @@ import           Hedgehog.Internal.Source  --- | Test that a pair of render / parse functions are compatible.+-- | Test that a pair of encode / decode functions are compatible. -- tripping ::      HasCallStack   => Applicative f   => Monad m+  => Show b   => Show (f a)   => Eq (f a)   => a   -> (a -> b)   -> (b -> f a)   -> Test m ()-tripping x render parse =+tripping x encode decode =   let     mx =       pure x +    i =+      encode x+     my =-      (parse . render) x+      decode i   in     if mx == my then       success@@ -36,12 +40,17 @@             failWith Nothing $ unlines [                 "━━━ Original ━━━"               , showPretty mx+              , "━━━ Intermediate ━━━"+              , showPretty i               , "━━━ Roundtrip ━━━"               , showPretty my               ]          Just diff ->           withFrozenCallStack $-              failWith-                (Just $ Diff "Failed (" "- Original" "/" "+ Roundtrip" ")" diff)-                ""+            failWith+              (Just $ Diff "━━━ " "- Original" "/" "+ Roundtrip" " ━━━" diff) $+              unlines [+                  "━━━ Intermediate ━━━"+                , showPretty i+                ]
src/Hedgehog/Range.hs view
@@ -23,11 +23,20 @@   , linearFracFrom   , linearBounded +  -- * Exponential+  , exponential+  , exponentialFrom+  , exponentialBounded+  , exponentialFloat+  , exponentialFloatFrom+   -- * Internal   -- $internal   , clamp   , scaleLinear   , scaleLinearFrac+  , scaleExponential+  , scaleExponentialFloat   ) where  import           Data.Bifunctor (bimap)@@ -299,6 +308,148 @@       (n - z) * (fromIntegral sz / 99)   in     z + diff++-- | Construct a range which scales the second bound exponentially relative to+--   the size parameter.+--+--   >>> bounds 0 $ exponential 1 512+--   (1,1)+--+--   >>> bounds 11 $ exponential 1 512+--   (1,2)+--+--   >>> bounds 22 $ exponential 1 512+--   (1,4)+--+--   >>> bounds 77 $ exponential 1 512+--   (1,128)+--+--   >>> bounds 88 $ exponential 1 512+--   (1,256)+--+--   >>> bounds 99 $ exponential 1 512+--   (1,512)+--+exponential :: Integral a => a -> a -> Range a+exponential x y =+  exponentialFrom x x y++-- | Construct a range which scales the bounds exponentially relative to the+-- size parameter.+--+--   >>> bounds 0 $ exponentialFrom 0 (-128) 512+--   (0,0)+--+--   >>> bounds 25 $ exponentialFrom 0 (-128) 512+--   (-2,4)+--+--   >>> bounds 50 $ exponentialFrom 0 (-128) 512+--   (-11,22)+--+--   >>> bounds 75 $ exponentialFrom 0 (-128) 512+--   (-39,112)+--+--   >>> bounds 99 $ exponentialFrom x (-128) 512+--   (-128,512)+--+exponentialFrom :: Integral a => a -> a -> a -> Range a+exponentialFrom z x y =+  Range z $ \sz ->+    let+      sized_x =+        clamp x y $ scaleExponential sz z x++      sized_y =+        clamp x y $ scaleExponential sz z y+    in+      (sized_x, sized_y)++-- | Construct a range which is scaled exponentially relative to the size+--   parameter and uses the full range of a data type.+--+--   >>> bounds 0 (exponentialBounded :: Range Int8)+--   (0,0)+--+--   >>> bounds 50 (exponentialBounded :: Range Int8)+--   (-11,11)+--+--   >>> bounds 99 (exponentialBounded :: Range Int8)+--   (-128,127)+--+exponentialBounded :: (Bounded a, Integral a) => Range a+exponentialBounded =+  exponentialFrom 0 minBound maxBound++-- | Construct a range which scales the second bound exponentially relative to+--   the size parameter.+--+--   This works the same as 'exponential', but for floating-point values.+--+--   >>> bounds 0 $ exponentialFloat 0 10+--   (0.0,0.0)+--+--   >>> bounds 50 $ exponentialFloat 0 10+--   (0.0,2.357035250656098)+--+--   >>> bounds 99 $ exponentialFloat 0 10+--   (0.0,10.0)+--+exponentialFloat :: (Floating a, Ord a) => a -> a -> Range a+exponentialFloat x y =+  exponentialFloatFrom x x y++-- | Construct a range which scales the bounds exponentially relative to the+--   size parameter.+--+--   This works the same as 'exponentialFrom', but for floating-point values.+--+--   >>> bounds 0 $ exponentialFloatFrom 0 (-10) 20+--   (0.0,0.0)+--+--   >>> bounds 50 $ exponentialFloatFrom 0 (-10) 20+--   (-2.357035250656098,3.6535836249197002)+--+--   >>> bounds 99 $ exponentialFloatFrom x (-10) 20+--   (-10.0,20.0)+--+exponentialFloatFrom :: (Floating a, Ord a) => a -> a -> a -> Range a+exponentialFloatFrom z x y =+  Range z $ \sz ->+    let+      sized_x =+        clamp x y $ scaleExponentialFloat sz z x++      sized_y =+        clamp x y $ scaleExponentialFloat sz z y+    in+      (sized_x, sized_y)++-- | Scale an integral exponentially with the size parameter.+--+scaleExponential :: Integral a => Size -> a -> a -> a+scaleExponential sz z0 n0 =+  let+    z =+      fromIntegral z0++    n =+      fromIntegral n0+  in+    round (scaleExponentialFloat sz z n :: Double)++-- | Scale a floating-point number exponentially with the size parameter.+--+scaleExponentialFloat :: Floating a => Size -> a -> a -> a+scaleExponentialFloat sz0 z n =+  let+    sz =+      clamp 0 99 sz0++    diff =+      (((abs (n - z) + 1) ** (realToFrac sz / 99)) - 1) * signum (n - z)+  in+    z + diff+  ------------------------------------------------------------------------ -- Internal