antigen 0.3.0.0 → 0.3.1.0
raw patch · 5 files changed
+42/−20 lines, 5 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Test.AntiGen: tryZapAntiGen :: Int -> AntiGen a -> Gen (Maybe a)
+ Test.AntiGen.Internal: tryZapAntiGen :: Int -> AntiGen a -> Gen (Maybe a)
Files
- CHANGELOG.md +4/−0
- antigen.cabal +2/−2
- src/Test/AntiGen.hs +8/−15
- src/Test/AntiGen/Internal.hs +12/−2
- test/Main.hs +16/−1
CHANGELOG.md view
@@ -1,5 +1,9 @@ # Revision history for antigen +## 0.3.1.0++* Add `tryZapAntiGen`+ ## 0.3.0.0 * Rename `fickle*` to `faulty*`
antigen.cabal view
@@ -1,6 +1,6 @@ cabal-version: 3.0 name: antigen-version: 0.3.0.0+version: 0.3.1.0 synopsis: Fault injection for QuickCheck description: AntiGen extends QuickCheck to allow injecting random faults into QuickCheck @@ -33,7 +33,7 @@ Test.AntiGen.Internal build-depends: base >=4.18 && <5,- QuickCheck >= 2.16.0 && < 2.18,+ QuickCheck >= 2.15.0 && < 2.18, free >= 5.2 && < 5.3, mtl >= 2.3.1 && < 2.4, random >= 1.2 && < 1.4,
src/Test/AntiGen.hs view
@@ -15,6 +15,7 @@ (||!), runAntiGen, zapAntiGen,+ tryZapAntiGen, -- * AntiGen combinators faultyNum,@@ -43,7 +44,7 @@ NonZero (..), Positive (..), )-import Test.QuickCheck.GenT (MonadGen (..), elements, frequency, listOf1, suchThat)+import Test.QuickCheck.GenT (MonadGen (..), elements, listOf1, oneof, suchThat) -- | Returns the provided number. -- Negative: returns a value that is not equal to the provided number.@@ -57,21 +58,13 @@ -- | Generates a value from the first range. -- Negative: Generates a value from the second range excluding the first range.------ Note: The second range must not be a subset of the first range! antiChoose :: (Integral a, Random a) => (a, a) -> (a, a) -> AntiGen a-antiChoose rng@(lo, hi) (boundLo, boundHi) =- choose rng- |! frequency- ( mconcat- [ [ (fromIntegral $ lo - boundLo, choose rngLo)- | lo > boundLo- ]- , [ (fromIntegral $ boundHi - hi, choose rngHi)- | boundHi > hi- ]- ]- )+antiChoose rng@(lo, hi) (boundLo, boundHi)+ | lo > boundLo || boundHi > hi =+ choose rng+ |! oneof+ ([choose rngLo | lo > boundLo] <> [choose rngHi | boundHi > hi])+ | otherwise = choose rng where rngLo = (boundLo, pred lo) rngHi = (succ hi, boundHi)
src/Test/AntiGen/Internal.hs view
@@ -14,6 +14,7 @@ AntiGen, (|!), zapAntiGen,+ tryZapAntiGen, runAntiGen, evalToPartial, evalPartial,@@ -24,7 +25,7 @@ import Control.Monad ((<=<)) import Control.Monad.Free.Church (F (..), MonadFree (..)) import Control.Monad.Free.Class (wrapT)-import Control.Monad.State.Strict (MonadState (..), StateT (..), evalStateT, modify)+import Control.Monad.State.Strict (MonadState (..), StateT (..), evalStateT, modify') import Control.Monad.Trans (MonadTrans (..)) import Test.QuickCheck (Gen, getSize) import Test.QuickCheck.GenT (GenT (..), MonadGen (..), runGenT)@@ -95,7 +96,7 @@ case dpNegativeGen of Just neg -> do d <- get- modify pred+ modify' pred if d == 0 then do -- Negate the generator@@ -127,6 +128,15 @@ -- than `n`. zapAntiGen :: Int -> AntiGen a -> Gen a zapAntiGen n = fmap evalPartial <$> zapNTimes n <=< evalToPartial++-- | Create a negative generator from an `AntiGen` by introducing at most+-- `n` mistakes. If there are no decision points, it will return `Nothing`.+tryZapAntiGen :: Int -> AntiGen a -> Gen (Maybe a)+tryZapAntiGen n ag = do+ p <- evalToPartial ag+ if countDecisionPoints p > 0+ then Just . evalPartial <$> zapNTimes n p+ else pure Nothing -- | Create a positive generator from the provided `AntiGen`. runAntiGen :: AntiGen a -> Gen a
test/Main.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} @@ -5,8 +7,10 @@ import Control.Monad (replicateM) import Data.Data (Proxy (..))+import Data.Word (Word32, Word64) import Test.AntiGen ( AntiGen,+ antiChooseBounded, antiNegative, antiNonNegative, antiNonPositive,@@ -20,7 +24,7 @@ (||!), ) import Test.AntiGen.Internal (countDecisionPoints, evalToPartial)-import Test.Hspec (Spec, describe, hspec, shouldBe)+import Test.Hspec (Spec, describe, hspec, shouldBe, shouldSatisfy) import Test.Hspec.QuickCheck (prop) import Test.QuickCheck ( Arbitrary (..),@@ -45,6 +49,7 @@ (===), ) import Test.QuickCheck.GenT (MonadGen (..), listOf1, oneof)+import Type.Reflection (Typeable, typeRep) antiGenPositive :: AntiGen Int antiGenPositive = (getPositive @Int <$> arbitrary) |! (getNonPositive <$> arbitrary)@@ -159,6 +164,12 @@ ) ] +chooseBoundedIntegralTest :: forall a. Typeable a => Spec+chooseBoundedIntegralTest =+ prop (show (typeRep @a) <> " (0, n)") $ \(Positive (n :: Word64)) -> do+ res <- zapAntiGen 1 (antiChooseBounded (0, n))+ pure $ res `shouldSatisfy` (> n)+ utilsSpec :: Spec utilsSpec = describe "utils" $ do@@ -209,6 +220,10 @@ [ ("null", null res) , ("nonpositive", length (filter (<= 0) res) == 1) ]+ describe "chooseBoundedIntegral" $ do+ chooseBoundedIntegralTest @Word64+ chooseBoundedIntegralTest @Word32+ chooseBoundedIntegralTest @Int main :: IO () main = hspec $ do