crjdt-haskell-0.1.0.0: test/Data/CrjdtSpec.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
module Data.CrjdtSpec where
import Test.Hspec
import Hedgehog
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import Data.Map as M hiding (empty)
import Data.Either (isRight)
import Data.Maybe
import Data.Bifunctor
import Data.Foldable
import Data.Functor
import Control.Applicative (liftA2)
import Control.Monad
import Data.Crjdt
import Data.Crjdt.Internal
eitherToMaybe :: Either x a -> Maybe a
eitherToMaybe (Right a) = Just a
eitherToMaybe _ = Nothing
-- allProps :: IO ()
-- allProps = traverse_ check [property_let, property_var]
twenty = Range.linear 0 20
keyGen :: Monad m => Gen m BasicKey
keyGen = Gen.choice $ (pure <$> [Head, Tail, DocKey]) ++
[ I . Id <$> (liftA2 (fmap (bimap toInteger toInteger) . (,)) naturals naturals)
, Str <$> Gen.text twenty Gen.hexit
]
naturals :: Monad m => Gen m Int
naturals = Gen.int (Range.linear 0 1000)
exprGen :: Gen IO Expr
exprGen = Gen.recursive Gen.choice terminal nonterminal
where
terminal = [pure doc]
letVar = Gen.text twenty Gen.hexit >>= \t -> Let t <$> exprGen
nonterminal =
[ iter <$> exprGen
, next <$> exprGen
, key <$> (Key <$> keyGen) <*> exprGen
]
property_let :: Property
property_let = property $ do
expr <- forAll exprGen
name <- Variable <$> (forAll $ Gen.text twenty Gen.hexit)
let (result, state) = run 1 $ execute $ bind (getName name) expr
when (isRight result) $ do
let Just cursor = M.lookup name $ variables $ state
Right expectedCursor = evalEval 1 expr
cursor === expectedCursor
property_var :: Property
property_var = property $ do
expr <- forAll exprGen
x <- Variable <$> (forAll $ Gen.text twenty Gen.hexit)
let (result, c) = run 1 $ execute (bind (getName x) expr) *> eval (Var x)
v = M.lookup x (variables c)
v === eitherToMaybe result
property_get :: Property
property_get = property $ do
expr <- forAll exprGen
k <- forAll keyGen
let cursor = evalEval 1 (GetKey expr $ Key k)
when (k /= Head && isRight cursor) $ fmap finalKey cursor === Right (Key k)
checkH :: Property -> IO ()
checkH = void . check
spec :: Spec
spec = describe "Crjdt Specs" $
describe "Expr evaluation" $ do
it "DOC" $ evalEval 1 Doc `shouldBe` Right (Cursor mempty (Key DocKey))
it "LET" $ checkH property_let
it "VAR" $ checkH property_var
it "GET" $ checkH property_get