property-matchers 0.2.0.0 → 0.3.0.0
raw patch · 3 files changed
+94/−16 lines, 3 filesdep +semialigndep +thesePVP ok
version bump matches the API change (PVP)
Dependencies added: semialign, these
API changes (from Hackage documentation)
- PropertyMatchers: propful :: (HasCallStack, Eq (f ()), Functor f, Foldable f) => f (Prop a) -> Prop (f a)
+ PropertyMatchers: alignExact :: (HasCallStack, Traversable f, Semialign f) => f (Prop a) -> Prop (f a)
+ PropertyMatchers: alignLax :: (Traversable f, Semialign f) => Prop a -> f (Prop (Maybe a)) -> Prop (f a)
+ PropertyMatchers: elem :: (HasCallStack, Traversable f) => Prop a -> Prop (f a)
+ PropertyMatchers: fails :: Exception e => Prop e -> Prop (IO a)
+ PropertyMatchers: gt :: (HasCallStack, Ord a) => a -> Prop a
+ PropertyMatchers: gte :: (HasCallStack, Ord a) => a -> Prop a
+ PropertyMatchers: infixr 7 :=>
+ PropertyMatchers: lt :: (HasCallStack, Ord a) => a -> Prop a
+ PropertyMatchers: lte :: (HasCallStack, Ord a) => a -> Prop a
Files
- CHANGELOG.md +11/−2
- property-matchers.cabal +3/−1
- src/PropertyMatchers.hs +80/−13
CHANGELOG.md view
@@ -1,7 +1,16 @@ # Revision history for property-matchers -## 0.2.0.0+## 0.3+* Add `fails` function, for asserting that an exception is thrown+* Replace `propful` with `alignExact`+* Add `alignLax` generalizing `alignExact`+* Add `elem`+* Add fixity for `:=>` to be compatible with `?`+* Add comparisons other than `equals` ++## 0.2+ * Add `bool` function * Add hspec + smallcheck test suite * Add `branch` for non-backtracking disjunction of properties@@ -12,7 +21,7 @@ * Reorder `PropertyMatchers` module for intelligibility -## 0.1.0.0+## 0.1 * Rename to property-matchers * Rename kth to atIndex
property-matchers.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.4 name: property-matchers-version: 0.2.0.0+version: 0.3.0.0 synopsis: A library for tests, based on transforming and writing properties description: This package provides ways to write properties for testing such that they compose nicely and are easy to debug.@@ -25,7 +25,9 @@ ,recover-rtti >= 0.3 && < 0.6 ,pretty-simple >= 1.1 && < 4.2 ,prettyprinter >= 1.6 && < 2.0+ ,semialign >= 1 && < 2 ,text >= 1.0 && < 2.2+ ,these >= 1 && < 2 if !impl(ghc >= 8.0) build-depends: semigroups >= 0.8.4 && < 1
src/PropertyMatchers.hs view
@@ -38,30 +38,38 @@ , match , atIndex , list- , propful+ , alignExact+ , alignLax+ , elem , compose , allTrue , allOf1 , pair , fun+ , fails , traced , tracedShow , traceFailShow , traceFail , forced , equals+ , lt+ , lte+ , gt+ , gte , bool , pattern (:=>) , (?) ) where -import Prelude hiding (and, fail, or)+import Prelude hiding (and, elem, fail, or) import Control.Concurrent (myThreadId) import Control.Exception-import Control.Monad hiding (fail)+import qualified Data.Align as Align import Data.Foldable (toList) import Data.Functor.Const+import Data.These import Data.Typeable import Debug.Trace import GHC.Stack@@ -255,20 +263,53 @@ where psl = length ps --- | Given a functor-full of properties, and a functor-full of values, ensure--- that the structures of the two functors match and apply all of the properties--- to all of the values.+-- | Given a functor-full of properties, and a functor-full of values, align+-- the two together and apply all of the properties to the values pointwise.+-- If there is any misalignment between the two, fail. -- Generalized version of `list`.-propful ::- (HasCallStack, Eq (f ()), Functor f, Foldable f) =>+alignExact+ :: (HasCallStack, Traversable f, Align.Semialign f) => f (Prop a) -> Prop (f a)-propful props values- | void props == void values =- list (toList props) (toList values)- | otherwise =- fail ("shape equal to that of" <> PP.pretty (anythingToTextPretty props)) values+alignExact props values =+ sequence_ $ Align.alignWith+ (\case+ This _extraProp -> fail ("no extra elements relative to " <> PP.pretty (anythingToTextPretty props)) values+ That _extraValue -> fail ("no missing elements relative to " <> PP.pretty (anythingToTextPretty props)) values+ These prop value -> prop value+ )+ props values +-- | Given a functor-full of properties and a functor-full of values+-- (and a property for excess values) align the properties and values and apply+-- them to each other pointwise. If there is any misalignment between the two:+-- * if there's an excess value, apply the excess property to it+-- * if there's a missing value, pass the corresponding property `Nothing`+-- Examples:+-- alignLax (Map.fromList ["k" :=> P.lt 3, "g" :=> P.match P.gt 4]) (Map.fromList )+alignLax+ :: (Traversable f, Align.Semialign f) =>+ Prop a ->+ f (Prop (Maybe a)) ->+ Prop (f a)+alignLax excess props values = sequence_ $ Align.alignWith+ (\case+ This prop -> prop Nothing+ That extraValue -> excess extraValue+ These prop value -> prop (Just value)+ )+ props values++-- | Given a property and a traversable functor-full of values,+-- succeed if the property succeeds on at least one of the values.+elem+ :: (HasCallStack, Traversable f) =>+ Prop a ->+ Prop (f a)+elem prop values+ | null values = fail "nonempty value" values+ | otherwise = foldr1 or $ prop <$> values+ -- | Given a representable functor-full of properties, and a functor-full of values, -- yield a representable functor-full of booleans. Similar to `propful`. compose ::@@ -305,6 +346,11 @@ fun :: (a -> b) -> PT b a fun f p = p . f +fails :: Exception e => Prop e -> Prop (IO a)+fails p actual = trySync actual >>= \case+ Left e -> p e+ Right r -> fail "a failed computation" r+ -- | Prints the input of a property, if the property fails, using `Show`. -- Requires that the property's output type can be checked for failure. traceFailShow :: Show a => PT a a@@ -339,6 +385,26 @@ | expected == actual = succeed actual | otherwise = fail (PP.pretty (anythingToTextPretty expected)) actual +lt :: (HasCallStack, Ord a) => a -> Prop a+lt expected actual+ | actual < expected = succeed actual+ | otherwise = fail ("less than " <> PP.pretty (anythingToTextPretty expected)) actual++gt :: (HasCallStack, Ord a) => a -> Prop a+gt expected actual+ | actual > expected = succeed actual+ | otherwise = fail ("greater than " <> PP.pretty (anythingToTextPretty expected)) actual++gte :: (HasCallStack, Ord a) => a -> Prop a+gte expected actual+ | actual >= expected = succeed actual+ | otherwise = fail ("greater than/equal to " <> PP.pretty (anythingToTextPretty expected)) actual++lte :: (HasCallStack, Ord a) => a -> Prop a+lte expected actual+ | actual <= expected = succeed actual+ | otherwise = fail ("less than/equal to " <> PP.pretty (anythingToTextPretty expected)) actual+ bool :: HasCallStack => Bool -> Assertion bool b | b = succeed b@@ -349,6 +415,7 @@ -- `(x :: Either Int Int) & branch [match _Left :=> equals 1, match _Right :=> equals 2]` pattern (:=>) :: a -> b -> (a, b) pattern a :=> b = (a, b)+infixr 7 :=> -- | Higher precedence '$', to work well with '&'. -- The intended use is something like `x & match _Right ? equals 2`.