critbit-0.1.0.0: tests/Properties/Common.hs
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, IncoherentInstances #-}
{-# LANGUAGE OverloadedStrings, Rank2Types #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Properties.Common
(
Small(..)
, qc
, Props
, Eq'(..)
, SameAs(..)
, (=?=)
, (=??=)
, (=*=)
, (=?*=)
, (=??*=)
, (=**=)
, (=*==)
, notEmpty
, prepends
, kf
) where
import Control.Applicative ((<$>))
import qualified Data.ByteString.Char8 as B
import Data.CritBit.Map.Lazy (CritBitKey, byteCount)
import Data.Monoid (Monoid, mappend)
import Data.String (IsString, fromString)
import qualified Data.Text as T
import qualified Data.Vector.Generic as G
import qualified Data.Vector.Unboxed as U
import Data.Word
import Test.Framework (Test)
import Test.QuickCheck (Arbitrary(..), Args(..), quickCheckWith, stdArgs)
import Test.QuickCheck.Gen (Gen, resize, sized)
import Test.QuickCheck.Property (Property, Testable, (===), (.&&.), (.||.))
instance IsString (U.Vector Word8) where
fromString = fromStringV
instance IsString (U.Vector Word16) where
fromString = fromStringV
instance IsString (U.Vector Word32) where
fromString = fromStringV
instance IsString (U.Vector Word64) where
fromString = fromStringV
instance IsString (U.Vector Word) where
fromString = fromStringV
instance IsString (U.Vector Char) where
fromString = G.fromList
fromStringV :: (G.Vector v a, Integral a) => String -> v a
fromStringV = G.fromList . map (fromIntegral . fromEnum)
instance Arbitrary B.ByteString where
arbitrary = B.pack <$> arbitrary
shrink = map B.pack . shrink . B.unpack
instance Arbitrary T.Text where
arbitrary = T.pack <$> arbitrary
shrink = map T.pack . shrink . T.unpack
instance Arbitrary (U.Vector Word8) where
arbitrary = arbitraryV
shrink = shrinkV
instance Arbitrary (U.Vector Word16) where
arbitrary = arbitraryV
shrink = shrinkV
instance Arbitrary (U.Vector Word32) where
arbitrary = arbitraryV
shrink = shrinkV
instance Arbitrary (U.Vector Word64) where
arbitrary = arbitraryV
shrink = shrinkV
instance Arbitrary (U.Vector Word) where
arbitrary = arbitraryV
shrink = shrinkV
instance Arbitrary (U.Vector Char) where
arbitrary = arbitraryV
shrink = shrinkV
arbitraryV :: (G.Vector v a, Arbitrary a) => Gen (v a)
arbitraryV = G.fromList <$> arbitrary
shrinkV :: (G.Vector v a, Arbitrary a) => v a -> [v a]
shrinkV = map G.fromList . shrink . G.toList
newtype Small a = Small { fromSmall :: a }
deriving (Eq, Ord, Show)
instance (Show a, Arbitrary a) => Arbitrary (Small a) where
arbitrary = Small <$> (sized $ \n -> resize (smallish n) arbitrary)
where
smallish = round . (sqrt :: Double -> Double) . fromIntegral . abs
shrink = map Small . shrink . fromSmall
type Props k = (Arbitrary k, CritBitKey k, Ord k, IsString k, Monoid k, Show k) => k -> [Test]
infix 4 =^=, =?=, =??=
-- | Compares heterogeneous values
class (Show f, Show g) => Eq' f g where
(=^=) :: f -> g -> Property
instance (Show t, Eq t) => Eq' t t where
(=^=) = (===)
instance (Eq' a1 b1, Eq' a2 b2, Eq' a3 b3) => Eq' (a1, a2, a3) (b1, b2, b3)
where (a1, a2, a3) =^= (b1, b2, b3) = a1 =^= b1 .&&. a2 =^= b2 .&&. a3 =^= b3
-- | Compares functions taking one scalar
(=?=) :: Eq' a b => (t -> a) -> (t -> b) -> k -> t -> Property
f =?= g = const $ \t -> f t =^= g t
-- | Compares functions taking two scalars
(=??=) :: Eq' a b => (t -> s -> a) -> (t -> s -> b) -> k -> t -> s -> Property
f =??= g = const $ \t s -> f t s =^= g t s
infix 4 =*=, =?*=, =*==
-- | Types 'f' and 'g' have same behavior and common represenation 'r'.
data SameAs f g r = SameAs {
toF :: r -> f
, fromF :: f -> r
, toG :: r -> g
, fromG :: g -> r
}
-- | Compares two functions taking one container
(=*=) :: (Eq' a b) => (f -> a) -> (g -> b)
-> SameAs f g r -> r -> Property
(f =*= g) sa i = f (toF sa i) =^= g (toG sa i)
-- | Compares two functions taking one scalar and one container
(=?*=) :: (Eq' a b) => (t -> f -> a) -> (t -> g -> b)
-> SameAs f g r -> r -> t -> Property
(f =?*= g) sa i t = (f t =*= g t) sa i
-- | Compares functions taking two scalars and one container
(=??*=) :: (Eq' a b) => (t -> s -> f -> a) -> (t -> s -> g -> b)
-> SameAs f g r -> r -> t -> s -> Property
(f =??*= g) sa i t s = (f t s =*= g t s) sa i
-- | Compares two functions taking two containers
(=**=) :: (Eq' a b) => (f -> f -> a) -> (g -> g -> b)
-> SameAs f g r -> r -> r -> Property
(f =**= g) sa i = (f (toF sa i) =*= g (toG sa i)) sa
-- | Compares two functions taking one container with preprocessing
(=*==) :: (Eq' f g) => (z -> f) -> (z -> g) -> (p -> z)
-> SameAs f g r -> p -> Property
(f =*== g) p _ i = f i' =^= g i'
where i' = p i
-- | Input litst is non-empty
notEmpty :: (SameAs c1 c2 [i] -> [i] -> Property)
-> SameAs c1 c2 [i] -> [i] -> Property
notEmpty f t items = null items .||. f t items
prepends :: (IsString k, Monoid k) => k -> k
prepends = mappend "test"
-- | Keys mapping function
kf :: (CritBitKey k, IsString k, Monoid k) => k -> k
kf k = fromString (show (byteCount k)) `mappend` k
-- Handy functions for fiddling with from ghci.
qc :: Testable prop => Int -> prop -> IO ()
qc n = quickCheckWith stdArgs { maxSuccess = n }