crdt-8.0: test/RGA.hs
{-# OPTIONS_GHC -Wno-missing-signatures #-}
{-# LANGUAGE ParallelListComp #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE TypeApplications #-}
module RGA where
import Control.Monad.State.Strict (execStateT, runStateT)
import Data.Maybe (isJust)
import qualified Data.Vector as Vector
import Test.QuickCheck (conjoin, counterexample, (===))
import CRDT.Cm (apply, initial, makeAndApplyOp, makeOp)
import CRDT.Cm.RGA (RGA (OpAddAfter), RgaIntent (AddAfter),
fromString, load, toString)
import CRDT.LamportClock (LamportTime (LamportTime), Pid (Pid),
advance)
import CRDT.LamportClock.Simulation (ProcessSim, runLamportClockSim,
runProcessSim)
import Laws (cmrdtLaw)
import Util (pattern (:-), expectRightK)
prop_makeOp =
isJust
(makeOp @(RGA Char) (AddAfter Nothing 'a') (initial @(RGA Char))
:: Maybe (ProcessSim (RGA Char)))
prop_makeAndApplyOp = conjoin
[ counterexample "result3" $ result3 === Right (op3, payload3)
, counterexample "result2" $ result2 === Right (op2, payload2)
, counterexample "result1" $ result1 === Right (op1, payload1)
, counterexample "result12" $ result12 === payload12
, counterexample "results=" $ result21 === result12
]
where
time1 = LamportTime 4 $ Pid 1
time2 = LamportTime 4 $ Pid 2
time3 = LamportTime 3 $ Pid 3
op1 = OpAddAfter Nothing '1' time1
op2 = OpAddAfter Nothing '2' time2
op3 = OpAddAfter Nothing '3' time3
payload3 = load $ Vector.singleton (time3 :- Just '3')
payload1 = load $ Vector.fromList [time1 :- Just '1', time3 :- Just '3']
payload2 = load $ Vector.fromList [time2 :- Just '2', time3 :- Just '3']
payload12 = load $ Vector.fromList
[time2 :- Just '2', time1 :- Just '1', time3 :- Just '3']
result3 =
runLamportClockSim .
runProcessSim (Pid 3) .
(`runStateT` initial @(RGA Char)) $ do
advance 2
makeAndApplyOp @(RGA Char) (AddAfter Nothing '3')
result2 =
runLamportClockSim . runProcessSim (Pid 2) . (`runStateT` payload3) $ do
advance 1
makeAndApplyOp @(RGA Char) (AddAfter Nothing '2')
result1 =
runLamportClockSim . runProcessSim (Pid 1) . (`runStateT` payload3) $
makeAndApplyOp @(RGA Char) (AddAfter Nothing '1')
result12 = apply op2 payload1
result21 = apply op1 payload2
prop_fromString s pid =
result ===
Right (load $ Vector.fromList
[LamportTime t pid :- Just c | t <- [1..] | c <- s])
where
result =
runLamportClockSim .
runProcessSim pid .
(`execStateT` initial @(RGA Char)) $
fromString s
prop_fromString_toString s pid =
expectRightK result $ \s' -> toString s' === s
where
result =
runLamportClockSim .
runProcessSim pid .
(`execStateT` initial @(RGA Char)) $
fromString s
prop_Cm = cmrdtLaw @(RGA Char)