text-0.8.0.0: tests/QuickCheckUtils.hs
{-# LANGUAGE FlexibleInstances #-}
module QuickCheckUtils where
import Control.Arrow (first)
import Data.Char (chr)
import Data.Bits ((.&.))
import Data.Int (Int64)
import Data.Word (Word8, Word16, Word32)
import Data.String (IsString, fromString)
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import System.Random (Random(..), RandomGen)
import Test.QuickCheck hiding ((.&.))
import qualified Data.ByteString as B
instance Random Int64 where
randomR = integralRandomR
random = randomR (minBound,maxBound)
instance Arbitrary Int64 where
arbitrary = choose (minBound,maxBound)
instance Random Word8 where
randomR = integralRandomR
random = randomR (minBound,maxBound)
instance Arbitrary Word8 where
arbitrary = choose (minBound,maxBound)
instance Arbitrary B.ByteString where
arbitrary = B.pack `fmap` arbitrary
instance Random Word16 where
randomR = integralRandomR
random = randomR (minBound,maxBound)
instance Arbitrary Word16 where
arbitrary = choose (minBound,maxBound)
instance Random Word32 where
randomR = integralRandomR
random = randomR (minBound,maxBound)
instance Arbitrary Word32 where
arbitrary = choose (minBound,maxBound)
genUnicode :: IsString a => Gen a
genUnicode = fmap fromString string where
string = sized $ \n ->
do k <- choose (0,n)
sequence [ char | _ <- [1..k] ]
excluding :: [a -> Bool] -> Gen a -> Gen a
excluding bad gen = loop
where
loop = do
x <- gen
if or (map ($ x) bad)
then loop
else return x
reserved = [lowSurrogate, highSurrogate, noncharacter]
lowSurrogate c = c >= 0xDC00 && c <= 0xDFFF
highSurrogate c = c >= 0xD800 && c <= 0xDBFF
noncharacter c = masked == 0xFFFE || masked == 0xFFFF
where
masked = c .&. 0xFFFF
ascii = choose (0,0x7F)
plane0 = choose (0xF0, 0xFFFF)
plane1 = oneof [ choose (0x10000, 0x10FFF)
, choose (0x11000, 0x11FFF)
, choose (0x12000, 0x12FFF)
, choose (0x13000, 0x13FFF)
, choose (0x1D000, 0x1DFFF)
, choose (0x1F000, 0x1FFFF)
]
plane2 = oneof [ choose (0x20000, 0x20FFF)
, choose (0x21000, 0x21FFF)
, choose (0x22000, 0x22FFF)
, choose (0x23000, 0x23FFF)
, choose (0x24000, 0x24FFF)
, choose (0x25000, 0x25FFF)
, choose (0x26000, 0x26FFF)
, choose (0x27000, 0x27FFF)
, choose (0x28000, 0x28FFF)
, choose (0x29000, 0x29FFF)
, choose (0x2A000, 0x2AFFF)
, choose (0x2B000, 0x2BFFF)
, choose (0x2F000, 0x2FFFF)
]
plane14 = choose (0xE0000, 0xE0FFF)
planes = [ascii, plane0, plane1, plane2, plane14]
char = chr `fmap` excluding reserved (oneof planes)
-- For tests that have O(n^2) running times or input sizes, resize
-- their inputs to the square root of the originals.
unsquare :: (Arbitrary a, Show a, Testable b) => (a -> b) -> Property
unsquare = forAll smallArbitrary
smallArbitrary :: (Arbitrary a, Show a) => Gen a
smallArbitrary = sized $ \n -> resize (smallish n) arbitrary
where smallish = round . (sqrt :: Double -> Double) . fromIntegral . abs
instance Arbitrary T.Text where
arbitrary = T.pack `fmap` arbitrary
instance Arbitrary TL.Text where
arbitrary = (TL.fromChunks . map notEmpty) `fmap` smallArbitrary
newtype NotEmpty a = NotEmpty { notEmpty :: a }
deriving (Eq, Ord)
instance Show a => Show (NotEmpty a) where
show (NotEmpty a) = show a
instance Functor NotEmpty where
fmap f (NotEmpty a) = NotEmpty (f a)
instance Arbitrary a => Arbitrary (NotEmpty [a]) where
arbitrary = sized (\n -> NotEmpty `fmap` (choose (1,n+1) >>= vector))
instance Arbitrary (NotEmpty T.Text) where
arbitrary = (fmap T.pack) `fmap` arbitrary
instance Arbitrary (NotEmpty TL.Text) where
arbitrary = (fmap TL.pack) `fmap` arbitrary
instance Arbitrary (NotEmpty B.ByteString) where
arbitrary = (fmap B.pack) `fmap` arbitrary
data Small = S0 | S1 | S2 | S3 | S4 | S5 | S6 | S7
| S8 | S9 | S10 | S11 | S12 | S13 | S14 | S15
| S16 | S17 | S18 | S19 | S20 | S21 | S22 | S23
| S24 | S25 | S26 | S27 | S28 | S29 | S30 | S31
deriving (Eq, Ord, Enum, Bounded)
small :: Small -> Int
small = fromEnum
intf f a b = toEnum ((fromEnum a `f` fromEnum b) `mod` 32)
instance Show Small where
show = show . fromEnum
instance Read Small where
readsPrec n = map (first toEnum) . readsPrec n
instance Num Small where
fromInteger = toEnum . fromIntegral
signum _ = 1
abs = id
(+) = intf (+)
(-) = intf (-)
(*) = intf (*)
instance Real Small where
toRational = toRational . fromEnum
instance Integral Small where
toInteger = toInteger . fromEnum
quotRem a b = (toEnum x, toEnum y)
where (x, y) = fromEnum a `quotRem` fromEnum b
instance Random Small where
randomR = integralRandomR
random = randomR (minBound,maxBound)
instance Arbitrary Small where
arbitrary = choose (minBound,maxBound)
integralRandomR :: (Integral a, RandomGen g) => (a,a) -> g -> (a,g)
integralRandomR (a,b) g = case randomR (fromIntegral a :: Integer,
fromIntegral b :: Integer) g of
(x,h) -> (fromIntegral x, h)