testing-feat-0.3: Test/Feat/Modifiers.hs
{-# LANGUAGE DeriveDataTypeable #-}
-- | Modifiers for types, i.e. newtype wrappers where the values satisfy some
-- constraint (non-empty, positive etc.). Suggestions on useful types are
-- appreciated.
--
-- To apply the modifiers types you can use the record label. For instance:
--
-- @
-- data C a = C [a] [a] deriving 'Typeable'
-- instance 'Enumerable' a => 'Enumerable' (C a) where
-- 'enumerate' = 'unary' $ 'funcurry' $
-- \xs ys -> C ('nonEmpty' xs) ('nonEmpty' ys)
-- @
--
-- Alternatively you can put everything in pattern postition:
--
-- @
-- instance 'Enumerable' a => 'Enumerable' (C a) where
-- 'enumerate' = 'unary' $ 'funcurry' $
-- \('Free' ('NonEmpty' xs,'NonEmpty' ys)) -> C xs ys)
-- @
--
-- The first approach has the advantage of being usable with a
-- point free style: @ \xs -> C ('nonEmpty' xs) . 'nonEmpty' @.
module Test.Feat.Modifiers(
-- ** List modifiers
NonEmpty(..),
mkNonEmpty,
-- ** Numeric modifiers
Infinite(..),
Nat(..),
NonZero(..),
-- ** Character and string modifiers
Unicode(..),
unicodes,
Printable(..),
printables
) where
-- testing-feat
import Test.Feat.Enumerate
import Test.Feat.Class
import Test.Feat.Internals.Newtypes
-- quickcheck -- Should be made compatible at some point.
-- import Test.QuickCheck.Modifiers
-- | A type of non empty lists.
newtype NonEmpty a = NonEmpty {nonEmpty :: [a]}
deriving (Typeable, Show)
mkNonEmpty :: (a,[a]) -> NonEmpty a
mkNonEmpty (x,xs) = NonEmpty $ x:xs
instance Enumerable a => Enumerable (NonEmpty a) where
enumerate = unary $ mkNonEmpty
enumerateBounded :: (Enum a) => Int -> Int -> Enumerate a
enumerateBounded from to = let e = Enumerate prts (return e) in e
where
prts = toRev$ map (\p -> Finite (crd p) (sel p)) [0..]
crd p
| p <= 0 = 0
| p == 1 = 1
| 2^(p-1) > num = max 0 (num - 2^(p-2))
| otherwise = 2^(p-2)
sel 1 0 = toEnum from
sel p i = toEnum $ 2^(p-2) + fromInteger i + from
num = toInteger $ to - from
-- | Any unicode character.
newtype Unicode = Unicode {unicode :: Char}
deriving (Typeable, Show, Eq, Ord)
instance Enumerable Unicode where
enumerate = fmap Unicode $ enumerateBounded
(fromEnum (minBound :: Char))
(fromEnum (maxBound :: Char))
-- | Smart constructor for unicode strings.
unicodes :: [Unicode] -> String
unicodes = map unicode
-- | Printable ASCII characters
newtype Printable = Printable {printable :: Char}
deriving (Typeable, Show)
instance Enumerable Printable where
enumerate = fmap Printable $ enumerateBounded 32 126
-- | Smart constructor for printable ASCII strings
printables :: [Printable] -> String
printables = map printable