delta-store-1.0.0.0: test/unit/Data/StoreSpec.hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
-- |
-- Copyright: © 2023 IOHK
-- License: Apache-2.0
module Data.StoreSpec
( spec
) where
import Prelude
import Data.Delta
( Delta (..)
)
import Data.Store
( Store (..)
, UpdateStore
, newCachedStore
, newStore
)
import Test.Data.Store
( prop_StoreUpdate
)
import Test.Hspec
( Spec
, describe
, it
)
import Test.QuickCheck
( elements
, generate
, (===)
)
import Test.QuickCheck.Gen
( Gen
, listOf
)
import Test.QuickCheck.Monadic
( monadicIO
, run
)
spec :: Spec
spec = do
describe "CachedStore" $ do
it "respects store laws" $
let setupStore = do
testStore <- newTestStore
resetTestStoreBase testStore
newCachedStore testStore
in prop_StoreUpdate
id
setupStore
(pure emptyTestStore)
$ const genTestStoreDeltas
it "behaves like the cached one" $ monadicIO $ run $ do
das <- generate $ listOf genTestStoreDeltas
testStore <- newTestStore
cachedStore <- newCachedStore testStore
resetTestStoreBase testStore
updateStore cachedStore das
Right cachedFinal <- loadS cachedStore
resetTestStoreBase testStore
updateStore testStore das
Right originalFinal <- loadS testStore
pure $ cachedFinal === originalFinal
newTestStore :: IO (UpdateStore IO TestStoreDelta)
newTestStore = newStore
updateStore :: Monad m => Store m qa da -> [da] -> m ()
updateStore store = mapM_ (updateS store Nothing)
genTestStoreDeltas :: Gen TestStoreDelta
genTestStoreDeltas = elements [AddOne, AddTwo, RemoveOne]
resetTestStoreBase :: (Base da ~ TestStoreBase) => Store m qa da -> m ()
resetTestStoreBase store = writeS store emptyTestStore
emptyTestStore :: TestStoreBase
emptyTestStore = TestStoreBase []
newtype TestStoreBase = TestStoreBase [Int]
deriving (Show, Eq)
data TestStoreDelta
= AddOne
| AddTwo
| RemoveOne
deriving (Show, Eq)
instance Delta TestStoreDelta where
type Base TestStoreDelta = TestStoreBase
apply AddOne = overTestStoreBase (1:)
apply AddTwo = overTestStoreBase (2:)
apply RemoveOne = overTestStoreBase (drop 1)
overTestStoreBase :: ([Int] -> [Int]) -> TestStoreBase -> TestStoreBase
overTestStoreBase f (TestStoreBase xs) = TestStoreBase (f xs)