packages feed

persist-0.1: tests/GetTests.hs

{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeApplications #-}

module GetTests (tests) where

import           Control.Applicative
import           Control.Monad
import           Data.Word
import           Data.Function
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LB
import           Data.Persist
import           Test.Framework (Test(),testGroup)
import           Test.Framework.Providers.QuickCheck2 (testProperty)
import           Test.QuickCheck as QC


-- Data to express Get parser to generate
data GetD
  = Get8
  | Eof
  | Get16be
  | Get32be
  | Get64be
  | Get16le
  | Get32le
  | Get64le
  | GetD  :*>   GetD
  | Skip Int
  deriving Show

-- Get parser generator
buildGet :: GetD -> Get ()
buildGet = d  where
  d Get8           =  get @Word8    *> pure ()
  d Eof            =  eof
  d Get16be        =  getBE @Word16 *> pure ()
  d Get32be        =  getBE @Word32 *> pure ()
  d Get64be        =  getBE @Word64 *> pure ()
  d Get16le        =  getLE @Word16 *> pure ()
  d Get32le        =  getLE @Word32 *> pure ()
  d Get64le        =  getLE @Word64 *> pure ()
  d (x :*>  y)     =  d x *>  d y
  d (Skip i)       =  skip i

-- Randomly generate parser
genGetD :: Gen GetD
genGetD =
    oneof $
    [ pure g
    | g <- [ Get8, Eof
           , Get16be, Get32be, Get64be
           , Get16le, Get32le, Get64le
           ]
    ] <>
    [ (:*>)     <$> genGetD <*> genGetD
    , Skip      <$> choose (0, 10)
    ]

instance Arbitrary GetD where
  arbitrary = genGetD

instance Arbitrary (Get ()) where
  arbitrary = buildGet <$> genGetD

newtype R a =
  R { unR :: Either String a }
  deriving Show


-- Ignore equality of error message string
instance Eq a => Eq (R a) where
  (==)  =  (==) `on` either (const Nothing) Just . unR

data Chunks = Chunks [[Word8]] deriving (Eq, Show)

mkChunks :: Word -> Chunks
mkChunks n = Chunks . take (fromIntegral n) $ cycle [ [x] | x <- [0 .. 255] ]

instance Arbitrary Chunks where
  arbitrary = mkChunks <$> choose (0, 512)


testLength :: Word
testLength = 255

(==!) :: Eq a => Get a -> Get a -> Property
p1 ==! p2 =
  conjoin
  [ counterexample (show s) $ R (runGet p1 s) == R (runGet p2 s)
  | n <- [0 .. testLength]
  , let Chunks in0 = mkChunks n
        s = BS.pack $ concat in0
  ]

infix 2 ==!

monadIdL' :: GetD -> Property
monadIdL' getD =
    (return () >>= const x) ==! x
  where
    x = buildGet getD

monadIdR' :: GetD -> Property
monadIdR' getD =
    (x >>= return) ==! x
  where
    x = buildGet getD

monadAssoc' :: GetD -> GetD -> GetD -> Property
monadAssoc' p1 p2 p3 =
    (x >> (y >> z)) ==! (x >> y >> z)
  where
    x = buildGet p1
    y = buildGet p2
    z = buildGet p3

tests :: Test
tests  = testGroup "GetTests"
  [ testProperty "monad left id"          monadIdL'
  , testProperty "monad right id"         monadIdR'
  , testProperty "monad assoc"            monadAssoc'
  ]