refinery-0.4.0.0: test/Spec/PropertyTests.hs
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wredundant-constraints #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Spec.PropertyTests where
import Control.Applicative
import Control.Monad
import Control.Monad.State.Strict (StateT (..))
import Control.Monad.State.Class
import Data.Function
import Data.Functor.Identity
import Data.Monoid (Sum (..))
import Refinery.ProofState
import Refinery.Tactic
import Refinery.Tactic.Internal
import Test.Hspec
import Test.QuickCheck hiding (Failure)
import Test.QuickCheck.Checkers
import Test.QuickCheck.Classes
import Checkers
import Data.Foldable
testBatch :: TestBatch -> Spec
testBatch (batchName, tests) = describe ("laws for: " ++ batchName) $
traverse_ (uncurry it) tests
instance (EqProp ext, EqProp meta, EqProp s, EqProp jdg) => EqProp (Proof s meta jdg ext) where
instance (MonadExtract meta ext err s m, EqProp (m (Either [err] [Proof s meta a ext])), Arbitrary s)
=> EqProp (ProofStateT ext ext err s m a) where
(=-=) a b = property $ do
s <- arbitrary
pure $ ((=-=) `on` proofs s) a b
instance ( MonadExtract meta ext err s m
, Arbitrary jdg
, EqProp (m (Either [err] [Proof s meta jdg ext]))
, Show s
, Arbitrary s
, Show jdg
)
=> EqProp (TacticT jdg ext err s m a) where
(=-=) = (=-=) `on` runTacticT . (() <$)
instance ( Arbitrary jdg
, EqProp (m (Either [err] [Proof s meta jdg ext]))
, MonadExtract meta ext err s m
, Arbitrary s
, Show s , Show jdg
)
=> EqProp (RuleT jdg ext err s m ext) where
(=-=) = (=-=) `on` rule . const
instance MonadExtract Int Int String Int Identity where
hole = do
i <- get
modify (+1)
pure (i, 0)
unsolvableHole _ = do
i <- get
modify (+1)
pure (i, 0)
instance ( CoArbitrary ext'
, Arbitrary ext
, CoArbitrary err
, Arbitrary err
, Arbitrary a
, Arbitrary (m (ProofStateT ext' ext err s m a))
, Arbitrary (m err)
, CoArbitrary s
, Arbitrary s
)
=> Arbitrary (ProofStateT ext' ext err s m a) where
arbitrary = getSize >>= \case
n | n <= 1 -> oneof small
_ -> oneof $
[ Subgoal <$> decayArbitrary 2 <*> decayArbitrary 2
, Effect <$> arbitrary
, Interleave <$> decayArbitrary 2 <*> decayArbitrary 2
, Alt <$> decayArbitrary 2 <*> decayArbitrary 2
, Stateful <$> arbitrary
, Failure <$> arbitrary <*> decayArbitrary 2
, Handle <$> decayArbitrary 2 <*> arbitrary
] ++ small
where
small =
[ pure Empty
, Axiom <$> arbitrary
]
shrink = genericShrink
instance (Arbitrary (m (a, s)), CoArbitrary s) => Arbitrary (StateT s m a) where
arbitrary = StateT <$> arbitrary
instance ( CoArbitrary jdg
, Arbitrary a
, Arbitrary ext
, CoArbitrary err
, Arbitrary err
, CoArbitrary ext
, Arbitrary jdg
, Arbitrary (m (ProofStateT ext ext err s m (a, jdg)))
, Arbitrary (m err)
, CoArbitrary s
, Arbitrary s
)
=> Arbitrary (TacticT jdg ext err s m a) where
arbitrary = fmap (TacticT . StateT) arbitrary
shrink = genericShrink
instance ( Arbitrary a
, CoArbitrary err
, Arbitrary err
, CoArbitrary ext
, Arbitrary jdg
, Arbitrary (m (ProofStateT ext a err s m jdg))
, Arbitrary (m err)
, CoArbitrary s
, Arbitrary s
)
=> Arbitrary (RuleT jdg ext err s m a) where
arbitrary = fmap RuleT arbitrary
shrink = genericShrink
decayArbitrary :: Arbitrary a => Int -> Gen a
decayArbitrary n = scale (`div` n) arbitrary
type ProofStateTest = ProofStateT Int Int String Int Identity
type RuleTest = RuleT Int Int String Int Identity
type TacticTest = TacticT (Sum Int) Int String Int Identity
propertyTests :: Spec
propertyTests = do
describe "ProofStateT" $ do
testBatch $ functor (undefined :: ProofStateTest (Int, Int, Int))
testBatch $ applicative (undefined :: ProofStateTest (Int, Int, Int))
testBatch $ alternative (undefined :: ProofStateTest Int)
testBatch $ monad (undefined :: ProofStateTest (Int, Int, Int))
testBatch $ monadPlus (undefined :: ProofStateTest (Int, Int))
testBatch $ monadState (undefined :: ProofStateTest (Int, Int))
it "distrib put over <|>" $ property $ distribPut (undefined :: ProofStateTest Int)
describe "RuleT" $ do
testBatch $ functor (undefined :: RuleTest (Int, Int, Int))
testBatch $ applicative (undefined :: RuleTest (Int, Int, Int))
testBatch $ alternative (undefined :: RuleTest Int)
testBatch $ monad (undefined :: RuleTest (Int, Int, Int))
describe "TacticT" $ do
testBatch $ functor (undefined :: TacticTest ((), (), ()))
testBatch $ applicative (undefined :: TacticTest ((), (), ()))
testBatch $ alternative (undefined :: TacticTest ())
testBatch $ monad (undefined :: TacticTest ((), (), ()))
testBatch $ monadPlus (undefined :: TacticTest ((), ()))
testBatch $ monadState (undefined :: TacticTest ((), ()))
it "interleave - mzero" $ property $ interleaveMZero (undefined :: TacticTest Int)
it "interleave - mplus" $ property $ interleaveMPlus (undefined :: TacticTest Int)
it "distrib put over <|>" $ property $ distribPut (undefined :: TacticTest ())
-- it "constant peek" $ property $ peekConst (undefined :: TacticTest ())
leftAltBind
:: forall m a b
. (EqProp (m b), Monad m, Alternative m)
=> m a -> m a -> (a -> m b)
-> Property
leftAltBind m1 m2 f =
((m1 <|> m2) >>= f) =-= ((m1 >>= f) <|> (m2 >>= f))
rightAltBind
:: forall m a
. (EqProp (m a), Monad m, Alternative m)
=> m () -> m a -> m a
-> Property
rightAltBind m1 m2 m3 =
(m1 >> (m2 <|> m3)) =-= ((m1 >> m2) <|> (m1 >> m3))
interleaveMZero
:: forall m a meta jdg ext err s
. (MonadExtract meta ext err s m
, EqProp (m (Either [err] [Proof s meta jdg ext]))
, Show s , Show jdg
, Arbitrary jdg, Arbitrary s)
=> TacticT jdg ext err s m a -- ^ proxy
-> TacticT jdg ext err s m a
-> Property
interleaveMZero _ m =
(mzero <%> m) =-= m
interleaveMPlus
:: forall m a meta jdg ext err s
. (MonadExtract meta ext err s m
, EqProp (m (Either [err] [Proof s meta jdg ext]))
, Show s , Show jdg
, Arbitrary jdg, Arbitrary s)
=> TacticT jdg ext err s m a -- ^ proxy
-> a
-> TacticT jdg ext err s m a
-> TacticT jdg ext err s m a
-> Property
interleaveMPlus _ a m1 m2 =
((pure a <|> m1) <%> m2) =-= (pure a <|> (m2 <%> m1))
distribPut
:: forall s m a
. ( MonadState s m
, Alternative m
, EqProp (m a)
, Arbitrary (m a)
, Arbitrary s
, Show s
, Show (m a)
)
=> m a -> Property
distribPut _ = property $ do
s <- arbitrary @s
m1 <- arbitrary @(m a)
m2 <- arbitrary @(m a)
pure $
counterexample (show s) $
counterexample (show m1) $
counterexample (show m2) $
(put s >> (m1 <|> m2)) =-= ((put s >> m1) <|> (put s >> m2))
-- peekConst
-- :: forall m jdg ext err s
-- . (MonadExtract ext err m
-- , EqProp (m [Either err (Proof s jdg ext)])
-- , Show s , Show jdg
-- , Arbitrary jdg, Arbitrary s)
-- => TacticT jdg ext err s m () -- ^ proxy
-- -> TacticT jdg ext err s m ()
-- -> TacticT jdg ext err s m ()
-- -> Property
-- peekConst _ t t' =
-- peek t (const t') =-= (t' >> t)