packages feed

storablevector-0.2.9: tests/Test/Utility.hs

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
module Test.Utility where

import Test.QuickCheck (Property, (==>), )
import Text.Show.Functions ()

import Data.Word (Word8)
import Data.Int (Int64)

import qualified Data.ByteString      as P
import qualified Data.StorableVector  as V

import qualified Data.ByteString.Char8 as PC


{- |
Class allows to compare StorableVector implementation
with implementations for similar data structures,
here ByteString and [Word8].
-}
class Model a b where
   model :: a -> b

instance Model P [W]    where model = P.unpack
instance Model P [Char] where model = PC.unpack
instance Model V [W]    where model = V.unpack
instance Model V P      where model = P.pack . V.unpack

instance Model Bool  Bool         where model = id
instance Model Int   Int          where model = id
instance Model Int64 Int64        where model = id
instance Model Int64 Int          where model = fromIntegral
instance Model Word8 Word8        where model = id
instance Model Ordering Ordering  where model = id
instance Model Char Char          where model = id

instance (Model x y) => Model (a -> x) (a -> y) where
   model f = model . f

instance (Model x y) => Model (Maybe x) (Maybe y) where
   model = fmap model

instance (Model x y) => Model [x] [y] where
   model = fmap model

instance
   (Model x0 y0, Model x1 y1) =>
      Model (x0,x1) (y0,y1) where
   model (x0,x1) = (model x0, model x1)


type X = Int
type W = Word8
type P = P.ByteString
type V = V.Vector Word8


infixl 0 `applyId`, `applyModel`

applyId :: (a -> x, a -> y) -> a -> (x,y)
applyId (f,g) a = (f a, g a)

applyModel :: (Model x0 y0) => (x0 -> x, y0 -> y) -> x0 -> (x,y)
applyModel (f,g) x = (f x, g $ model x)


{-
These comparison functions handle wrapping and equality automatically.
-}
eq0 ::
   (Model x y, Eq y) =>
   x -> y -> Bool

eq1 ::
   (Model x1 y1, Model x y, Eq y) =>
   (x1 -> x) -> (y1 -> y) -> x1 -> Bool

eq2 ::
   (Model x2 y2, Model x1 y1, Model x y, Eq y) =>
   (x2 -> x1 -> x) -> (y2 -> y1 -> y) -> x2 -> x1 -> Bool

eq3 ::
   (Model x3 y3, Model x2 y2, Model x1 y1, Model x y, Eq y) =>
   (x3 -> x2 -> x1 -> x) -> (y3 -> y2 -> y1 -> y) -> x3 -> x2 -> x1 -> Bool

eq4 ::
   (Model x4 y4, Model x3 y3, Model x2 y2, Model x1 y1, Model x y, Eq y) =>
   (x4 -> x3 -> x2 -> x1 -> x) ->
   (y4 -> y3 -> y2 -> y1 -> y) ->
   x4 -> x3 -> x2 -> x1 -> Bool

eq5 ::
   (Model x5 y5, Model x4 y4, Model x3 y3, Model x2 y2, Model x1 y1, Model x y, Eq y) =>
   (x5 -> x4 -> x3 -> x2 -> x1 -> x) ->
   (y5 -> y4 -> y3 -> y2 -> y1 -> y) ->
   x5 -> x4 -> x3 -> x2 -> x1 -> Bool


infix 4 `eq1`, `eq2`, `eq3`, `eq4`, `eq5`

eq0 f g =
    model  f            == g
eq1 f g = \a         ->
    model (f a)         == g (model a)
eq2 f g = \a b       ->
    model (f a b)       == g (model a) (model b)
eq3 f g = \a b c     ->
    model (f a b c)     == g (model a) (model b) (model c)
eq4 f g = \a b c d   ->
    model (f a b c d)   == g (model a) (model b) (model c) (model d)
eq5 f g = \a b c d e ->
    model (f a b c d e) == g (model a) (model b) (model c) (model d) (model e)


{-
Handle functions that require non-empty input.
-}
eqnotnull1 ::
   (Model x y, Model x1 y1, IsNull x1, Eq y) =>
   (x1 -> x) -> (y1 -> y) -> x1 -> Property

eqnotnull2 ::
   (Model x y, Model x1 y1, Model x2 y2, IsNull x1, Eq y) =>
   (x2 -> x1 -> x) -> (y2 -> y1 -> y) -> x2 -> x1 -> Property

eqnotnull3 ::
   (Model x y, Model x1 y1, Model x2 y2, Model x3 y3, IsNull x1,
    Eq y) =>
   (x3 -> x2 -> x1 -> x) ->
   (y3 -> y2 -> y1 -> y) ->
   x3 -> x2 -> x1 -> Property

eqnotnull1 f g = \x     -> not (isNull x) ==> eq1 f g x
eqnotnull2 f g = \x y   -> not (isNull y) ==> eq2 f g x y
eqnotnull3 f g = \x y z -> not (isNull z) ==> eq3 f g x y z

class    IsNull t            where isNull :: t -> Bool
instance IsNull P.ByteString where isNull = P.null
instance IsNull V            where isNull = V.null