HMock-0.1.0.1: A flexible mock framework for testing effectful code.
Safe HaskellNone
LanguageHaskell2010

Test.HMock.Internal.Predicates

Synopsis

Documentation

>>> :set -XTemplateHaskell
>>> :set -XTypeApplications
>>> :set -Wno-type-defaults

data Predicate a Source #

A predicate, which tests values and either accepts or rejects them. This is similar to a -> Bool, but also has a Show instance to describe what it is checking.

Predicates are used to define which arguments a general matcher should accept.

Constructors

Predicate 

Fields

Instances

Instances details
Show (Predicate a) Source # 
Instance details

Defined in Test.HMock.Internal.Predicates

anything :: Predicate a Source #

A Predicate that accepts anything at all.

>>> accept anything "foo"
True
>>> accept anything undefined
True

eq :: (Show a, Eq a) => a -> Predicate a Source #

A Predicate that accepts only the given value.

>>> accept (eq "foo") "foo"
True
>>> accept (eq "foo") "bar"
False

neq :: (Show a, Eq a) => a -> Predicate a Source #

A Predicate that accepts anything but the given value.

>>> accept (neq "foo") "foo"
False
>>> accept (neq "foo") "bar"
True

gt :: (Show a, Ord a) => a -> Predicate a Source #

A Predicate that accepts anything greater than the given value.

>>> accept (gt 5) 4
False
>>> accept (gt 5) 5
False
>>> accept (gt 5) 6
True

geq :: (Show a, Ord a) => a -> Predicate a Source #

A Predicate that accepts anything greater than or equal to the given value.

>>> accept (geq 5) 4
False
>>> accept (geq 5) 5
True
>>> accept (geq 5) 6
True

lt :: (Show a, Ord a) => a -> Predicate a Source #

A Predicate that accepts anything less than the given value.

>>> accept (lt 5) 4
True
>>> accept (lt 5) 5
False
>>> accept (lt 5) 6
False

leq :: (Show a, Ord a) => a -> Predicate a Source #

A Predicate that accepts anything less than or equal to the given value.

>>> accept (leq 5) 4
True
>>> accept (leq 5) 5
True
>>> accept (leq 5) 6
False

true :: Predicate Bool Source #

A Predicate that matches True values.

>>> accept true True
True
>>> accept true False
False

false :: Predicate Bool Source #

A Predicate that matches False values.

>>> accept false True
False
>>> accept false False
True

just :: Predicate a -> Predicate (Maybe a) Source #

A Predicate that accepts Maybe values of Just x, where x matches the given child Predicate.

>>> accept (just (eq "value")) Nothing
False
>>> accept (just (eq "value")) (Just "value")
True
>>> accept (just (eq "value")) (Just "wrong value")
False

left :: Predicate a -> Predicate (Either a b) Source #

A Predicate that accepts an Either value of Left x, where x matches the given child Predicate.

>>> accept (left (eq "value")) (Left "value")
True
>>> accept (left (eq "value")) (Right "value")
False
>>> accept (left (eq "value")) (Left "wrong value")
False

right :: Predicate b -> Predicate (Either a b) Source #

A Predicate that accepts an Either value of Right x, where x matches the given child Predicate.

>>> accept (right (eq "value")) (Right "value")
True
>>> accept (right (eq "value")) (Right "wrong value")
False
>>> accept (right (eq "value")) (Left "value")
False

zipP :: Predicate a -> Predicate b -> Predicate (a, b) Source #

A Predicate that accepts pairs whose elements satisfy the corresponding child Predicates.

>>> accept (zipP (eq "foo") (eq "bar")) ("foo", "bar")
True
>>> accept (zipP (eq "foo") (eq "bar")) ("bar", "foo")
False

zip3P :: Predicate a -> Predicate b -> Predicate c -> Predicate (a, b, c) Source #

A Predicate that accepts 3-tuples whose elements satisfy the corresponding child Predicates.

>>> accept (zip3P (eq "foo") (eq "bar") (eq "qux")) ("foo", "bar", "qux")
True
>>> accept (zip3P (eq "foo") (eq "bar") (eq "qux")) ("qux", "bar", "foo")
False

zip4P :: Predicate a -> Predicate b -> Predicate c -> Predicate d -> Predicate (a, b, c, d) Source #

A Predicate that accepts 3-tuples whose elements satisfy the corresponding child Predicates.

>>> accept (zip4P (eq 1) (eq 2) (eq 3) (eq 4)) (1, 2, 3, 4)
True
>>> accept (zip4P (eq 1) (eq 2) (eq 3) (eq 4)) (4, 3, 2, 1)
False

zip5P :: Predicate a -> Predicate b -> Predicate c -> Predicate d -> Predicate e -> Predicate (a, b, c, d, e) Source #

A Predicate that accepts 3-tuples whose elements satisfy the corresponding child Predicates.

>>> accept (zip5P (eq 1) (eq 2) (eq 3) (eq 4) (eq 5)) (1, 2, 3, 4, 5)
True
>>> accept (zip5P (eq 1) (eq 2) (eq 3) (eq 4) (eq 5)) (5, 4, 3, 2, 1)
False

andP :: Predicate a -> Predicate a -> Predicate a Source #

A Predicate that accepts anything accepted by both of its children.

>>> accept (lt "foo" `andP` gt "bar") "eta"
True
>>> accept (lt "foo" `andP` gt "bar") "quz"
False
>>> accept (lt "foo" `andP` gt "bar") "alpha"
False

orP :: Predicate a -> Predicate a -> Predicate a Source #

A Predicate that accepts anything accepted by either of its children.

>>> accept (lt "bar" `orP` gt "foo") "eta"
False
>>> accept (lt "bar" `orP` gt "foo") "quz"
True
>>> accept (lt "bar" `orP` gt "foo") "alpha"
True

notP :: Predicate a -> Predicate a Source #

A Predicate that inverts another Predicate, accepting whatever its child rejects, and rejecting whatever its child accepts.

>>> accept (notP (eq "negative")) "positive"
True
>>> accept (notP (eq "negative")) "negative"
False

startsWith :: (Show t, IsSequence t, Eq (Element t)) => t -> Predicate t Source #

A Predicate that accepts sequences that start with the given prefix.

>>> accept (startsWith "fun") "fungible"
True
>>> accept (startsWith "gib") "fungible"
False

endsWith :: (Show t, IsSequence t, Eq (Element t)) => t -> Predicate t Source #

A Predicate that accepts sequences that end with the given suffix.

>>> accept (endsWith "ow") "crossbow"
True
>>> accept (endsWith "ow") "trebuchet"
False

hasSubstr :: (Show t, IsSequence t, Eq (Element t)) => t -> Predicate t Source #

A Predicate that accepts sequences that contain the given (consecutive) substring.

>>> accept (hasSubstr "i") "team"
False
>>> accept (hasSubstr "i") "partnership"
True

hasSubsequence :: (Show t, IsSequence t, Eq (Element t)) => t -> Predicate t Source #

A Predicate that accepts sequences that contain the given (not necessarily consecutive) subsequence.

>>> accept (hasSubsequence [1..5]) [1, 2, 3, 4, 5]
True
>>> accept (hasSubsequence [1..5]) [0, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0]
True
>>> accept (hasSubsequence [1..5]) [2, 3, 5, 7, 11]
False

caseInsensitive :: (MonoFunctor t, MonoFunctor a, Element t ~ Char, Element a ~ Char) => (t -> Predicate a) -> t -> Predicate a Source #

Transforms a Predicate on Strings or string-like types to match without regard to case.

>>> accept (caseInsensitive startsWith "foo") "FOOTBALL!"
True
>>> accept (caseInsensitive endsWith "ball") "soccer"
False
>>> accept (caseInsensitive eq "time") "TIME"
True
>>> accept (caseInsensitive gt "NOTHING") "everything"
False

matchesRegex :: (RegexLike Regex a, Eq a) => String -> Predicate a Source #

A Predicate that accepts Strings or string-like values matching a regular expression. The expression must match the entire argument.

You should not use caseInsensitive matchesRegex, because regular expression syntax itself is still case-sensitive even when the text you are matching is not. Instead, use matchesCaseInsensitiveRegex.

>>> accept (matchesRegex "x{2,5}y?") "xxxy"
True
>>> accept (matchesRegex "x{2,5}y?") "xyy"
False
>>> accept (matchesRegex "x{2,5}y?") "wxxxyz"
False

matchesCaseInsensitiveRegex :: (RegexLike Regex a, Eq a) => String -> Predicate a Source #

A Predicate that accepts Strings or string-like values matching a regular expression in a case-insensitive way. The expression must match the entire argument.

You should use this instead of caseInsensitive matchesRegex, because regular expression syntax itself is still case-sensitive even when the text you are matching is not.

>>> accept (matchesCaseInsensitiveRegex "x{2,5}y?") "XXXY"
True
>>> accept (matchesCaseInsensitiveRegex "x{2,5}y?") "XYY"
False
>>> accept (matchesCaseInsensitiveRegex "x{2,5}y?") "WXXXYZ"
False

containsRegex :: (RegexLike Regex a, Eq a) => String -> Predicate a Source #

A Predicate that accepts Strings or string-like values containing a match for a regular expression. The expression need not match the entire argument.

You should not use caseInsensitive containsRegex, because regular expression syntax itself is still case-sensitive even when the text you are matching is not. Instead, use containsCaseInsensitiveRegex.

>>> accept (containsRegex "x{2,5}y?") "xxxy"
True
>>> accept (containsRegex "x{2,5}y?") "xyy"
False
>>> accept (containsRegex "x{2,5}y?") "wxxxyz"
True

containsCaseInsensitiveRegex :: (RegexLike Regex a, Eq a) => String -> Predicate a Source #

A Predicate that accepts Strings or string-like values containing a match for a regular expression in a case-insensitive way. The expression need match the entire argument.

You should use this instead of caseInsensitive containsRegex, because regular expression syntax itself is still case-sensitive even when the text you are matching is not.

>>> accept (containsCaseInsensitiveRegex "x{2,5}y?") "XXXY"
True
>>> accept (containsCaseInsensitiveRegex "x{2,5}y?") "XYY"
False
>>> accept (containsCaseInsensitiveRegex "x{2,5}y?") "WXXXYZ"
True

isEmpty :: MonoFoldable t => Predicate t Source #

A Predicate that accepts empty data structures.

>>> accept isEmpty []
True
>>> accept isEmpty [1, 2, 3]
False
>>> accept isEmpty ""
True
>>> accept isEmpty "gas tank"
False

nonEmpty :: MonoFoldable t => Predicate t Source #

A Predicate that accepts non-empty data structures.

>>> accept nonEmpty []
False
>>> accept nonEmpty [1, 2, 3]
True
>>> accept nonEmpty ""
False
>>> accept nonEmpty "gas tank"
True

sizeIs :: MonoFoldable t => Predicate Int -> Predicate t Source #

A Predicate that accepts data structures whose number of elements match the child Predicate.

>>> accept (sizeIs (lt 3)) ['a' .. 'f']
False
>>> accept (sizeIs (lt 3)) ['a' .. 'b']
True

elemsAre :: MonoFoldable t => [Predicate (Element t)] -> Predicate t Source #

A Predicate that accepts data structures whose contents each match the corresponding Predicate in the given list, in the same order.

>>> accept (elemsAre [lt 3, lt 4, lt 5]) [2, 3, 4]
True
>>> accept (elemsAre [lt 3, lt 4, lt 5]) [2, 3, 4, 5]
False
>>> accept (elemsAre [lt 3, lt 4, lt 5]) [2, 10, 4]
False

unorderedElemsAre :: MonoFoldable t => [Predicate (Element t)] -> Predicate t Source #

A Predicate that accepts data structures whose contents each match the corresponding Predicate in the given list, in any order.

>>> accept (unorderedElemsAre [eq 1, eq 2, eq 3]) [1, 2, 3]
True
>>> accept (unorderedElemsAre [eq 1, eq 2, eq 3]) [2, 3, 1]
True
>>> accept (unorderedElemsAre [eq 1, eq 2, eq 3]) [1, 2, 3, 4]
False
>>> accept (unorderedElemsAre [eq 1, eq 2, eq 3]) [1, 3]
False

each :: MonoFoldable t => Predicate (Element t) -> Predicate t Source #

A Predicate that accepts data structures whose elements each match the child Predicate.

>>> accept (each (gt 5)) [4, 5, 6]
False
>>> accept (each (gt 5)) [6, 7, 8]
True
>>> accept (each (gt 5)) []
True

contains :: MonoFoldable t => Predicate (Element t) -> Predicate t Source #

A Predicate that accepts data structures which contain at least one element matching the child Predicate.

>>> accept (contains (gt 5)) [3, 4, 5]
False
>>> accept (contains (gt 5)) [4, 5, 6]
True
>>> accept (contains (gt 5)) []
False

containsAll :: MonoFoldable t => [Predicate (Element t)] -> Predicate t Source #

A Predicate that accepts data structures which contain an element satisfying each of the child predicates. containsAll [p1, p2, ..., pn] is equivalent to contains p1 `andP` contains p2 `andP` ... `andP` contains pn.

>>> accept (containsAll [eq "foo", eq "bar"]) ["bar", "foo"]
True
>>> accept (containsAll [eq "foo", eq "bar"]) ["foo"]
False
>>> accept (containsAll [eq "foo", eq "bar"]) ["foo", "bar", "qux"]
True

containsOnly :: MonoFoldable t => [Predicate (Element t)] -> Predicate t Source #

A Predicate that accepts data structures whose elements all satisfy at least one of the child predicates. containsOnly [p1, p2, ..., pn] is equivalent to each (p1 `orP` p2 `orP` ... `orP` pn).

>>> accept (containsOnly [eq "foo", eq "bar"]) ["foo", "foo"]
True
>>> accept (containsOnly [eq "foo", eq "bar"]) ["foo", "bar"]
True
>>> accept (containsOnly [eq "foo", eq "bar"]) ["foo", "qux"]
False

containsKey :: (IsList t, Item t ~ (k, v)) => Predicate k -> Predicate t Source #

A Predicate that accepts map-like structures which contain a key matching the child Predicate.

>>> accept (containsKey (eq "foo")) [("foo", 1), ("bar", 2)]
True
>>> accept (containsKey (eq "foo")) [("bar", 1), ("qux", 2)]
False

containsEntry :: (IsList t, Item t ~ (k, v)) => Predicate k -> Predicate v -> Predicate t Source #

A Predicate that accepts map-like structures which contain a key/value pair matched by the given child Predicates (one for the key, and one for the value).

>>> accept (containsEntry (eq "foo") (gt 10)) [("foo", 12), ("bar", 5)]
True
>>> accept (containsEntry (eq "foo") (gt 10)) [("foo", 5), ("bar", 12)]
False
>>> accept (containsEntry (eq "foo") (gt 10)) [("bar", 12)]
False

keysAre :: (IsList t, Item t ~ (k, v)) => [Predicate k] -> Predicate t Source #

A Predicate that accepts map-like structures whose keys are exactly those matched by the given list of Predicates, in any order.

>>> accept (keysAre [eq "a", eq "b", eq "c"]) [("a", 1), ("b", 2), ("c", 3)]
True
>>> accept (keysAre [eq "a", eq "b", eq "c"]) [("c", 1), ("b", 2), ("a", 3)]
True
>>> accept (keysAre [eq "a", eq "b", eq "c"]) [("a", 1), ("c", 3)]
False
>>> accept (keysAre [eq "a", eq "b"]) [("a", 1), ("b", 2), ("c", 3)]
False

entriesAre :: (IsList t, Item t ~ (k, v)) => [(Predicate k, Predicate v)] -> Predicate t Source #

A Predicate that accepts map-like structures whose entries are exactly those matched by the given list of Predicate pairs, in any order.

>>> accept (entriesAre [(eq 1, eq 2), (eq 3, eq 4)]) [(1, 2), (3, 4)]
True
>>> accept (entriesAre [(eq 1, eq 2), (eq 3, eq 4)]) [(3, 4), (1, 2)]
True
>>> accept (entriesAre [(eq 1, eq 2), (eq 3, eq 4)]) [(1, 4), (3, 2)]
False
>>> accept (entriesAre [(eq 1, eq 2), (eq 3, eq 4)]) [(1, 2), (3, 4), (5, 6)]
False

approxEq :: (RealFloat a, Show a) => a -> Predicate a Source #

A Predicate that accepts values of RealFloat types that are close to the given number. The expected precision is scaled based on the target value, so that reasonable rounding error is accepted but grossly inaccurate results are not.

The following naive use of eq fails due to rounding:

>>> accept (eq 1.0) (sum (replicate 100 0.01))
False

The solution is to use approxEq, which accounts for rounding error. However, approxEq doesn't accept results that are far enough off that they likely arise from incorrect calculations instead of rounding error.

>>> accept (approxEq 1.0) (sum (replicate 100 0.01))
True
>>> accept (approxEq 1.0) (sum (replicate 100 0.009999))
False

finite :: RealFloat a => Predicate a Source #

A Predicate that accepts finite numbers of any RealFloat type.

>>> accept finite 1.0
True
>>> accept finite (0 / 0)
False
>>> accept finite (1 / 0)
False

infinite :: RealFloat a => Predicate a Source #

A Predicate that accepts infinite numbers of any RealFloat type.

>>> accept infinite 1.0
False
>>> accept infinite (0 / 0)
False
>>> accept infinite (1 / 0)
True

nAn :: RealFloat a => Predicate a Source #

A Predicate that accepts NaN values of any RealFloat type.

>>> accept nAn 1.0
False
>>> accept nAn (0 / 0)
True
>>> accept nAn (1 / 0)
False

is :: HasCallStack => (a -> Bool) -> Predicate a Source #

A conversion from a -> Bool to Predicate. This is a fallback that can be used to build a Predicate that checks anything at all. However, its description will be less helpful than standard Predicates.

>>> accept (is even) 3
False
>>> accept (is even) 4
True

qIs :: HasCallStack => ExpQ -> ExpQ Source #

A Template Haskell splice that acts like is, but receives a quoted expression at compile time and has a more helpful description for error messages.

>>> accept $(qIs [| even |]) 3
False
>>> accept $(qIs [| even |]) 4
True
>>> show $(qIs [| even |])
"even"

with :: HasCallStack => (a -> b) -> Predicate b -> Predicate a Source #

A combinator to lift a Predicate to work on a property or computed value of the original value.

>>> accept (with abs (gt 5)) (-6)
True
>>> accept (with abs (gt 5)) (-5)
False
>>> accept (with reverse (eq "olleh")) "hello"
True
>>> accept (with reverse (eq "olleh")) "goodbye"
False

qWith :: ExpQ -> ExpQ Source #

A Template Haskell splice that acts like is, but receives a quoted typed expression at compile time and has a more helpful description for error messages.

>>> accept ($(qWith [| abs |]) (gt 5)) (-6)
True
>>> accept ($(qWith [| abs |]) (gt 5)) (-5)
False
>>> accept ($(qWith [| reverse |]) (eq "olleh")) "hello"
True
>>> accept ($(qWith [| reverse |]) (eq "olleh")) "goodbye"
False
>>> show ($(qWith [| abs |]) (gt 5))
"abs: > 5"

qMatch :: PatQ -> ExpQ Source #

A Template Haskell splice that turns a quoted pattern into a predicate that accepts values that match the pattern.

>>> accept $(qMatch [p| Just (Left _) |]) Nothing
False
>>> accept $(qMatch [p| Just (Left _) |]) (Just (Left 5))
True
>>> accept $(qMatch [p| Just (Left _) |]) (Just (Right 5))
False
>>> show $(qMatch [p| Just (Left _) |])
"Just (Left _)"

typed :: forall a b. (Typeable a, Typeable b) => Predicate a -> Predicate b Source #

Converts a Predicate to a new type. Typically used with visible type application, as in the examples below.

>>> accept (typed @String anything) "foo"
True
>>> accept (typed @String (sizeIs (gt 5))) "foo"
False
>>> accept (typed @String anything) (42 :: Int)
False