bytestring-0.12.1.0: tests/QuickCheckUtils.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
module QuickCheckUtils
( Char8(..)
, String8(..)
, CByteString(..)
, Sqrt(..)
, int64OK
) where
import Test.Tasty.QuickCheck
import Text.Show.Functions
import Control.Monad ( liftM2 )
import Data.Char
import Data.Word
import Data.Int
import System.IO
import Foreign.C (CChar)
import GHC.TypeLits (TypeError, ErrorMessage(..))
import qualified Data.ByteString.Short as SB
import qualified Data.ByteString as P
import qualified Data.ByteString.Lazy as L
import qualified Data.ByteString.Char8 as PC
import qualified Data.ByteString.Lazy.Char8 as LC
------------------------------------------------------------------------
sizedByteString n = do m <- choose(0, n)
fmap P.pack $ vectorOf m arbitrary
instance Arbitrary P.ByteString where
arbitrary = do
bs <- sized sizedByteString
n <- choose (0, 2)
return (P.drop n bs) -- to give us some with non-0 offset
shrink = map P.pack . shrink . P.unpack
instance CoArbitrary P.ByteString where
coarbitrary s = coarbitrary (P.unpack s)
instance Arbitrary L.ByteString where
arbitrary = sized $ \n -> do numChunks <- choose (0, n)
if numChunks == 0
then return L.empty
else fmap (L.fromChunks .
filter (not . P.null)) $
vectorOf numChunks
(sizedByteString
(n `div` numChunks))
instance CoArbitrary L.ByteString where
coarbitrary s = coarbitrary (L.unpack s)
newtype CByteString = CByteString P.ByteString
deriving Show
instance Arbitrary CByteString where
arbitrary = fmap (CByteString . P.pack . map fromCChar)
arbitrary
where
fromCChar :: NonZero CChar -> Word8
fromCChar = fromIntegral . getNonZero
-- | 'Char', but only representing 8-bit characters.
--
newtype Char8 = Char8 Char
deriving (Eq, Ord, Show)
instance Arbitrary Char8 where
arbitrary = fmap (Char8 . toChar) arbitrary
where
toChar :: Word8 -> Char
toChar = toEnum . fromIntegral
shrink (Char8 c) = fmap Char8 (shrink c)
instance CoArbitrary Char8 where
coarbitrary (Char8 c) = coarbitrary c
-- | 'Char', but only representing 8-bit characters.
--
newtype String8 = String8 String
deriving (Eq, Ord, Show)
instance Arbitrary String8 where
arbitrary = fmap (String8 . map toChar) arbitrary
where
toChar :: Word8 -> Char
toChar = toEnum . fromIntegral
shrink (String8 xs) = fmap String8 (shrink xs)
-- | If a test takes O(n^2) time or memory, it's useful to wrap its inputs
-- into 'Sqrt' so that increasing number of tests affects run time linearly.
newtype Sqrt a = Sqrt { unSqrt :: a }
deriving (Eq, Show)
instance Arbitrary a => Arbitrary (Sqrt a) where
arbitrary = Sqrt <$> sized
(\n -> resize (round @Double $ sqrt $ fromIntegral @Int n) arbitrary)
shrink = map Sqrt . shrink . unSqrt
sizedShortByteString :: Int -> Gen SB.ShortByteString
sizedShortByteString n = do m <- choose(0, n)
fmap SB.pack $ vectorOf m arbitrary
instance Arbitrary SB.ShortByteString where
arbitrary = sized sizedShortByteString
shrink = map SB.pack . shrink . SB.unpack
instance CoArbitrary SB.ShortByteString where
coarbitrary s = coarbitrary (SB.unpack s)
-- | This /poison instance/ exists to make accidental mis-use
-- of the @Arbitrary Int64@ instance a bit less likely.
instance {-# OVERLAPPING #-}
TypeError (Text "Found a test taking a raw Int64 argument."
:$$: Text "'instance Arbitrary Int64' by default is likely to"
:$$: Text "produce very large numbers after the first few tests,"
:$$: Text "which doesn't make great indices into a LazyByteString."
:$$: Text "For indices, try 'intToIndexTy' in Properties/ByteString.hs."
:$$: Text ""
:$$: Text "If very few small-numbers tests is OK, use"
:$$: Text "'int64OK' to bypass this poison-instance."
) => Testable (Int64 -> prop) where
property = error "poison instance Testable (Int64 -> prop)"
-- | Use this to bypass the poison instance for @Testable (Int64 -> prop)@
-- defined in "QuickCheckUtils".
int64OK :: (Arbitrary a, Show a, Testable b) => (a -> b) -> Property
int64OK f = propertyForAllShrinkShow arbitrary shrink (\v -> [show v]) f