lattices-1.4: test/Tests.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE KindSignatures #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Main (main) where
#if MIN_VERSION_base(4,8,0)
#else
import Control.Applicative
import Data.Foldable
#endif
import Data.Functor.Compose
import Data.Functor.Identity
import Data.Monoid
import Data.Traversable
import Control.Monad (ap)
import Test.QuickCheck.Function
import Test.Tasty
import Test.Tasty.QuickCheck as QC
import qualified Algebra.Lattice.Dropped as D
import qualified Algebra.Lattice.Lifted as U
import qualified Algebra.Lattice.Levitated as L
-- For old GHC to work
data Proxy1 (a :: * -> *) = Proxy1
main :: IO ()
main = defaultMain tests
tests :: TestTree
tests = testGroup "Tests" [theseProps]
theseProps :: TestTree
theseProps = testGroup "These"
[ functorLaws "Dropped" (Proxy1 :: Proxy1 D.Dropped)
, functorLaws "Lifted" (Proxy1 :: Proxy1 U.Lifted)
, functorLaws "Leviated" (Proxy1 :: Proxy1 L.Levitated)
, traversableLaws "Dropped" (Proxy1 :: Proxy1 D.Dropped)
, traversableLaws "Lifted" (Proxy1 :: Proxy1 U.Lifted)
, traversableLaws "Levitated" (Proxy1 :: Proxy1 L.Levitated)
, monadLaws "Dropped" (Proxy1 :: Proxy1 D.Dropped)
, monadLaws "Lifted" (Proxy1 :: Proxy1 U.Lifted)
, monadLaws "Levitated" (Proxy1 :: Proxy1 L.Levitated)
]
functorLaws :: forall (f :: * -> *). ( Functor f
, Arbitrary (f Int)
, Eq (f Int)
, Show (f Int))
=> String
-> Proxy1 f
-> TestTree
functorLaws name _ = testGroup ("Functor laws: " <> name)
[ QC.testProperty "identity" identityProp
, QC.testProperty "composition" compositionProp
]
where
identityProp :: f Int -> Property
identityProp x = fmap id x === x
compositionProp :: f Int -> Fun Int Int -> Fun Int Int -> Property
compositionProp x (Fun _ f) (Fun _ g) = fmap g (fmap f x) === fmap (g . f) x
traversableLaws :: forall (t :: * -> *). ( Traversable t
, Arbitrary (t Int)
, Eq (t Int)
, Show (t Int))
=> String
-> Proxy1 t
-> TestTree
traversableLaws name _ = testGroup ("Traversable laws: " <> name)
[ QC.testProperty "identity" identityProp
, QC.testProperty "composition" compositionProp
, QC.testProperty "functor" functorProp
, QC.testProperty "foldable" foldableProp
]
where
identityProp :: t Int -> Property
identityProp x = traverse Identity x === Identity x
compositionProp :: t Int -> Fun Int (Maybe Int) -> Fun Int ([] Int) -> Property
compositionProp x (Fun _ f) (Fun _ g) = traverse (Compose . fmap g . f) x === (Compose . fmap (traverse g) . traverse f $ x)
functorProp :: t Int -> Fun Int Int -> Property
functorProp x (Fun _ f) = fmap f x === fmapDefault f x
foldableProp :: t Int -> Fun Int [Int] -> Property
foldableProp x (Fun _ f) = foldMap f x === foldMapDefault f x
monadLaws :: forall (m :: * -> *). ( Monad m
#if !MIN_VERSION_base(4, 8, 0)
, Applicative m
#endif
, Arbitrary (m Int)
, Eq (m Int)
, Show (m Int)
, Arbitrary (m (Fun Int Int))
, Show (m (Fun Int Int)))
=> String
-> Proxy1 m
-> TestTree
monadLaws name _ = testGroup ("Monad laws: " <> name)
[ QC.testProperty "left identity" leftIdentityProp
, QC.testProperty "right identity" rightIdentityProp
, QC.testProperty "composition" compositionProp
, QC.testProperty "Applicative pure" pureProp
, QC.testProperty "Applicative ap" apProp
]
where
leftIdentityProp :: Int -> Fun Int (m Int) -> Property
leftIdentityProp x (Fun _ k) = (return x >>= k) === k x
rightIdentityProp :: m Int -> Property
rightIdentityProp m = (m >>= return) === m
compositionProp :: m Int -> Fun Int (m Int) -> Fun Int (m Int) -> Property
compositionProp m (Fun _ k) (Fun _ h) = (m >>= (\x -> k x >>= h)) === ((m >>= k) >>= h)
pureProp :: Int -> Property
pureProp x = pure x === (return x :: m Int)
apProp :: m (Fun Int Int) -> m Int -> Property
apProp f x = (f' <*> x) === ap f' x
where f' = apply <$> f
-- Orphan instances
instance Arbitrary a => Arbitrary (D.Dropped a) where
arbitrary = frequency [ (1, pure D.Top)
, (9, D.Drop <$> arbitrary)
]
instance Arbitrary a => Arbitrary (U.Lifted a) where
arbitrary = frequency [ (1, pure U.Bottom)
, (9, U.Lift <$> arbitrary)
]
instance Arbitrary a => Arbitrary (L.Levitated a) where
arbitrary = frequency [ (1, pure L.Top)
, (1, pure L.Bottom)
, (9, L.Levitate <$> arbitrary)
]