summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNickSmallbone <>2018-09-12 15:53:00 (GMT)
committerhdiff <hdiff@hdiff.luite.com>2018-09-12 15:53:00 (GMT)
commit3eca1114443d7ca35616c72356009bf4cc656e61 (patch)
tree0a290d7814ef7afa657f40ad4a13dbde0c852414
parentfd3313ac4f777784e0cc7c63ba7d169afbf7a31c (diff)
version 2.12.32.12.3
-rw-r--r--QuickCheck.cabal4
-rw-r--r--Test/QuickCheck.hs1
-rw-r--r--Test/QuickCheck/Arbitrary.hs72
-rw-r--r--changelog14
-rw-r--r--tests/Generators.hs6
5 files changed, 62 insertions, 35 deletions
diff --git a/QuickCheck.cabal b/QuickCheck.cabal
index ee623cf..5536293 100644
--- a/QuickCheck.cabal
+++ b/QuickCheck.cabal
@@ -1,5 +1,5 @@
Name: QuickCheck
-Version: 2.12.2
+Version: 2.12.3
Cabal-Version: >= 1.8
Build-type: Simple
License: BSD3
@@ -55,7 +55,7 @@ source-repository head
source-repository this
type: git
location: https://github.com/nick8325/quickcheck
- tag: 2.12.2
+ tag: 2.12.3
flag templateHaskell
Description: Build Test.QuickCheck.All, which uses Template Haskell.
diff --git a/Test/QuickCheck.hs b/Test/QuickCheck.hs
index 57d5c5c..ba85738 100644
--- a/Test/QuickCheck.hs
+++ b/Test/QuickCheck.hs
@@ -80,6 +80,7 @@ module Test.QuickCheck
, shrinkMapBy
, shrinkIntegral
, shrinkRealFrac
+ , shrinkDecimal
-- ** Lifting of 'Arbitrary' to unary and binary type constructors
, Arbitrary1(..)
diff --git a/Test/QuickCheck/Arbitrary.hs b/Test/QuickCheck/Arbitrary.hs
index 7fd4e6c..fbc5b75 100644
--- a/Test/QuickCheck/Arbitrary.hs
+++ b/Test/QuickCheck/Arbitrary.hs
@@ -66,6 +66,7 @@ module Test.QuickCheck.Arbitrary
, shrinkMapBy -- :: (a -> b) -> (b -> a) -> (a -> [a]) -> b -> [b]
, shrinkIntegral -- :: Integral a => a -> [a]
, shrinkRealFrac -- :: RealFrac a => a -> [a]
+ , shrinkDecimal -- :: RealFrac a => a -> [a]
-- ** Helper functions for implementing coarbitrary
, coarbitraryIntegral -- :: Integral a => a -> Gen b -> Gen b
, coarbitraryReal -- :: Real a => a -> Gen b -> Gen b
@@ -492,7 +493,7 @@ instance (RealFloat a, Arbitrary a) => Arbitrary (Complex a) where
#ifndef NO_FIXED
instance HasResolution a => Arbitrary (Fixed a) where
arbitrary = arbitrarySizedFractional
- shrink = shrinkRealFrac
+ shrink = shrinkDecimal
#endif
instance Arbitrary2 (,) where
@@ -676,11 +677,11 @@ instance Arbitrary Char where
instance Arbitrary Float where
arbitrary = arbitrarySizedFractional
- shrink = shrinkRealFrac
+ shrink = shrinkDecimal
instance Arbitrary Double where
arbitrary = arbitrarySizedFractional
- shrink = shrinkRealFrac
+ shrink = shrinkDecimal
instance Arbitrary CChar where
arbitrary = arbitrarySizedBoundedIntegral
@@ -782,11 +783,11 @@ instance Arbitrary CSUSeconds where
instance Arbitrary CFloat where
arbitrary = arbitrarySizedFractional
- shrink = shrinkRealFrac
+ shrink = shrinkDecimal
instance Arbitrary CDouble where
arbitrary = arbitrarySizedFractional
- shrink = shrinkRealFrac
+ shrink = shrinkDecimal
-- Arbitrary instances for container types
instance (Ord a, Arbitrary a) => Arbitrary (Set.Set a) where
@@ -1096,29 +1097,46 @@ shrinkIntegral x =
(True, False) -> a + b < 0
(False, True) -> a + b > 0
--- | Shrink a fraction, via continued-fraction approximations.
+-- | Shrink a fraction, preferring numbers with smaller
+-- numerators or denominators. See also 'shrinkDecimal'.
shrinkRealFrac :: RealFrac a => a -> [a]
-shrinkRealFrac a = shrinkRealFracToPrecision (abs a*1e-6) a
-
-shrinkRealFracToPrecision :: RealFrac a
- => a -- ^ "Epsilon" – the minimum deviation we consider
- -> a -- ^ Value to shrink
- -> [a]
-shrinkRealFracToPrecision eps x
- | x < 0 = 0 : ([id, negate] <*> filter (>0) (shrinkRealFracToPrecision eps $ -x))
- | x < eps = [0 | x /= 0]
- | not (x==x) = []
- | not (2*x>x) = 0 : takeWhile (<x) ((2^).(^2)<$>[0..])
- | (x-intgPart>eps)
- = filter (/= x) $
- intgShrinks ++ [intgPart]
- ++ map ((intgPart+) . recip)
- (filter (>0)
- . shrinkRealFracToPrecision (eps/(x-intgPart))
- $ 1/(x-intgPart))
- | otherwise = intgShrinks
- where intgPart = fromInteger $ truncate x
- intgShrinks = map fromInteger . shrinkIntegral $ truncate x
+shrinkRealFrac x
+ | not (x == x) = 0 : take 10 (iterate (*2) 0) -- NaN
+ | not (2*x+1>x) = 0 : takeWhile (<x) (iterate (*2) 0) -- infinity
+ | x < 0 = negate x:map negate (shrinkRealFrac (negate x))
+ | otherwise =
+ -- To ensure termination
+ filter (\y -> abs y < abs x) $
+ -- Try shrinking to an integer first
+ map fromInteger (shrink (truncate x) ++ [truncate x]) ++
+ -- Shrink the numerator
+ [fromRational (num' % denom) | num' <- shrink num] ++
+ -- Shrink the denominator, and keep the fraction as close
+ -- to the original as possible, rounding towards zero
+ [fromRational (truncate (num * denom' % denom) % denom')
+ | denom' <- shrink denom, denom' /= 0 ]
+ where
+ num = numerator (toRational x)
+ denom = denominator (toRational x)
+
+-- | Shrink a real number, preferring numbers with shorter
+-- decimal representations. See also 'shrinkRealFrac'.
+shrinkDecimal :: RealFrac a => a -> [a]
+shrinkDecimal x
+ | not (x == x) = 0 : take 10 (iterate (*2) 0) -- NaN
+ | not (2*x+1>x) = 0 : takeWhile (<x) (iterate (*2) 0) -- infinity
+ | otherwise =
+ -- e.g. shrink pi =
+ -- shrink 3 ++ map (/ 10) (shrink 31) ++
+ -- map (/ 100) (shrink 314) + ...,
+ -- where the inner calls to shrink use integer shrinking.
+ [ y
+ | precision <- take 6 (iterate (*10) 1),
+ let m = truncate (toRational x * precision),
+ m `mod` 10 /= 0, -- don't allow shrinking to increase digits
+ n <- m:shrink m,
+ let y = fromRational (fromInteger n / precision),
+ abs y < abs x ]
--------------------------------------------------------------------------
-- ** CoArbitrary
diff --git a/changelog b/changelog
index 8989ad4..95ec863 100644
--- a/changelog
+++ b/changelog
@@ -1,4 +1,12 @@
-QuickCheck 2.12.2 (released 2018-09-06)
+QuickCheck 2.12.3 (released 2018-09-12)
+ * Shrinking for Float and Decimal now works by reducing the number
+ of digits in the number. The new function shrinkDecimal
+ implements this shrinking behaviour.
+ * Shrinking for Rational now tries to make the numerator and
+ denominator of the number smaller. Previously it tried to reduce
+ the magnitude of the number.
+
+QuickCheck 2.12.2 (released 2018-09-10)
* Fix infinite shrinking loop for fractional types.
* Add SortedList modifier.
@@ -22,7 +30,7 @@ QuickCheck 2.12 (released 2018-09-03)
case distribution more flexibly than label.
- When label is called multiple times in a property, each call
produces a separate table of frequencies.
-
+
* New functions:
- (=/=): like (/=), but prints a counterexample
(thanks to tom-bop)
@@ -50,7 +58,7 @@ QuickCheck 2.12 (released 2018-09-03)
argument is not evaluated and the whole disjunction is
considered to have a false precondition
- Bug fix: suchThatMaybe always increased size to at least 1
-
+
* Miscellaneous API changes:
- Result type has changed a bit:
- InsufficientCovered constructor is gone
diff --git a/tests/Generators.hs b/tests/Generators.hs
index 51e9b56..749968a 100644
--- a/tests/Generators.hs
+++ b/tests/Generators.hs
@@ -14,14 +14,14 @@ newtype Path a = Path [a] deriving (Show, Functor)
instance Arbitrary a => Arbitrary (Path a) where
arbitrary = do
x <- arbitrary
- fmap Path (pathFrom x)
+ fmap Path (pathFrom 100 x)
where
- pathFrom x = sized $ \n ->
+ pathFrom n x =
fmap (x:) $
case shrink x of
[] -> return []
_ | n == 0 -> return []
- ys -> oneof [resize (n-1) (pathFrom y) | y <- ys]
+ ys -> oneof [pathFrom (n-1) y | y <- ys]
shrink (Path xs) = map Path [ ys | ys <- inits xs, length ys > 0 && length ys < length xs ]