packages feed

crdt-3.0: test/LWW.hs

{-# OPTIONS_GHC -Wno-missing-signatures #-}

{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

module LWW
    ( genUniquelyTimedLWW
    , prop_Cm
    , prop_assign
    , prop_merge_with_former
    , test_Cv
    ) where

import           Control.Monad.State.Strict (StateT, lift)
import           Data.Semigroup ((<>))
import           Data.Set (Set)
import qualified Data.Set as Set
import           Test.QuickCheck (Arbitrary, Gen, arbitrary, (===))

import           CRDT.LamportClock (LamportTime, runLamportClock, runProcess)
import           CRDT.LWW (LWW (LWW), assign, initial, query)

import           Laws (cmrdtLaw, cvrdtLaws)
import           QCUtil (genUnique)

prop_Cm = cmrdtLaw @(LWW Char)

test_Cv = cvrdtLaws @(LWW Char) $ Just (genUniquelyTimedLWW, Set.empty)

prop_assign pid1 pid2 (formerValue :: Char) latterValue = runLamportClock $ do
    state1 <- runProcess pid1 $ initial formerValue
    state2 <- runProcess pid2 $ assign latterValue state1
    pure $ query state2 === latterValue

prop_merge_with_former pid1 pid2 (formerValue :: Char) latterValue =
    runLamportClock $ do
        state1 <- runProcess pid1 $ initial formerValue
        state2 <- runProcess pid2 $ assign latterValue state1
        pure $ query (state1 <> state2) === latterValue

-- | Generate specified number of 'LWW' with unique timestamps
genUniquelyTimedLWW :: Arbitrary a => StateT (Set LamportTime) Gen (LWW a)
genUniquelyTimedLWW = LWW <$> lift arbitrary <*> genUnique