haskey-0.1.0.0: tests/Properties/Store/Page.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Properties.Store.Page where
import Test.Framework (Test, testGroup)
import Test.Framework.Providers.HUnit (testCase)
import Test.Framework.Providers.QuickCheck2 (testProperty)
import Test.HUnit hiding (Test, Node)
import Test.QuickCheck
import Control.Applicative ((<$>))
import Data.Int
import Data.List (nub)
import Data.Monoid ((<>))
import Data.Proxy
import qualified Data.Binary as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.Map as M
import qualified Data.Vector as V
import Data.BTree.Impure.Structures
import Data.BTree.Primitives
import Database.Haskey.Store.Page
--------------------------------------------------------------------------------
tests :: Test
tests = testGroup "Store.Page"
[ testProperty "binary pageType" prop_binary_pageType
, testProperty "binary emptyPage" prop_binary_emptyPage
, testProperty "binary nodePage leaf" prop_binary_leafNodePage
, testProperty "binary nodePage idx" prop_binary_indexNodePage
, testCase "zero checksum length" case_zero_checksum_length
]
prop_binary_pageType :: Property
prop_binary_pageType = forAll types $ \t ->
let bs = B.encode t in BL.length bs == 1 && B.decode bs == t
where
types = elements [TypeEmpty,
TypeConcurrentMeta,
TypeOverflow,
TypeLeafNode,
TypeIndexNode]
prop_binary_emptyPage :: Bool
prop_binary_emptyPage = case decode' emptyPage (encode EmptyPage) of
Right EmptyPage -> True
Left _ -> False
prop_binary_leafNodePage :: Property
prop_binary_leafNodePage = forAll genLeafNode $ \leaf ->
case decode' (leafNodePage zeroHeight key val)
(encode (LeafNodePage zeroHeight leaf)) of
Right (LeafNodePage h n) -> maybe False (== leaf) $ castNode h zeroHeight n
Left _ -> False
where
key = Proxy :: Proxy Int64
val = Proxy :: Proxy Bool
prop_binary_indexNodePage :: Property
prop_binary_indexNodePage = forAll genIndexNode $ \(srcHgt, idx) ->
case decode' (indexNodePage srcHgt key val)
(encode (IndexNodePage srcHgt idx)) of
Right (IndexNodePage h n) -> maybe False (== idx) $ castNode h srcHgt n
Left _ -> False
where
key = Proxy :: Proxy Int64
val = Proxy :: Proxy Bool
case_zero_checksum_length :: Assertion
case_zero_checksum_length = do
assertEqual "zero checksum should prepend 8 bytes" 8 $
BL.length withZero' - BL.length without'
assertEqual "zero checksum length should equal regular checksum lenth"
(BL.length withZero')
(BL.length with')
where
withZero' = encodeZeroChecksum pg
without' = encodeNoChecksum pg
with' = encode pg
pg = LeafNodePage zeroHeight (Leaf M.empty :: Node 'Z Int64 Int64)
decode' :: SGet t -> BL.ByteString -> Either String (Page t)
decode' x = decode x . BL.toStrict
--------------------------------------------------------------------------------
genIndexNode :: Gen (Height ('S h), Node ('S h) Int64 Bool)
genIndexNode = do
h <- genNonZeroHeight
n <- Idx <$> arbitrary
return (h, n)
genLeafNode :: Gen (Node 'Z Int64 Bool)
genLeafNode = Leaf <$> arbitrary
instance Arbitrary v => Arbitrary (LeafValue v) where
arbitrary = oneof [RawValue <$> arbitrary, OverflowValue <$> arbitrary]
instance Arbitrary TxId where
arbitrary = TxId <$> arbitrary
deriving instance Arbitrary (Height h)
genNonZeroHeight :: Gen (Height h)
genNonZeroHeight = suchThat arbitrary $ \h -> case viewHeight h of
UZero -> False
USucc _ -> True
instance (Key k, Arbitrary k, Arbitrary v) => Arbitrary (Index k v) where
arbitrary = do
keys <- V.fromList . nub <$> orderedList
vals <- V.fromList <$> vector (V.length keys + 1)
return (Index keys vals)
shrink (Index keys vals) =
[ Index newKeys newVals
| k <- [0..V.length keys - 1]
, let (preKeys,sufKeys) = V.splitAt k keys
newKeys = preKeys <> V.drop 1 sufKeys
(preVals,sufVals) = V.splitAt k vals
newVals = preVals <> V.drop 1 sufVals
]
deriving instance Arbitrary (NodeId height key val)