{-# LANGUAGE CPP #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} module Main (main) where import Control.Applicative (Const (..)) import Data.Foldable (toList) import Data.Functor.Identity (Identity (..)) import Data.Monoid (Endo (..), Monoid (..)) import Test.QuickCheck (Arbitrary, CoArbitrary, Fun, Function, Property, applyFun, (===)) import Test.QuickCheck.Poly (A, B) import Test.Tasty (TestTree, defaultMain, testGroup) import Test.Tasty.QuickCheck (testProperty) import qualified Data.HashMap.Lazy as HM import qualified Data.Map as Map import qualified Data.Sequence as Seq import qualified Data.Vector as V #if MIN_VERSION_containers(0,6,3) -- traverseWithKey and Foldable broken before import qualified Data.IntMap as IntMap #endif import Data.Functor.WithIndex.Instances () import Test.QuickCheck.Instances () import Data.Foldable.WithIndex import Data.Functor.WithIndex import Data.Traversable.WithIndex #if MIN_VERSION_base(4,7,0) import Data.Typeable (Typeable, typeRep) #else import Data.Typeable (TypeRep, Typeable1, typeOf1) #define Typeable Typeable1 typeRep :: forall f i. Typeable1 f => Tests i f -> TypeRep typeRep _ = typeOf1 (undefined :: f Int) #endif ------------------------------------------------------------------------------- -- Main ------------------------------------------------------------------------------- main :: IO () main = defaultMain $ testGroup "tests" [ battery $ mkT $ zipWith const [0 ..] , battery $ mkT (Map.keys :: forall a. Map.Map I a -> [I]) , battery $ mkT (HM.keys :: forall a. HM.HashMap I a -> [I]) , battery $ mkT (zipWith const [0 ..] . toList :: forall a. Seq.Seq a -> [Int]) , battery $ mkT $ zipWith const [0 ..] . V.toList #if MIN_VERSION_containers(0,6,3) , battery $ mkT IntMap.keys #endif ] ------------------------------------------------------------------------------- -- Test battery ------------------------------------------------------------------------------- data Tests i f = T { indices :: forall a. f a -> [i] } mkT :: FunctorWithIndex i f => (forall a. f a -> [i]) -> Tests i f mkT = T type I = Int battery :: forall f i. (Typeable f, TraversableWithIndex i f , Arbitrary (f A), Show (f A) , Show (f B), Eq (f B) , Function i, CoArbitrary i, Show i, Eq i ) => Tests i f -> TestTree battery t = testGroup name [ testProperty "imapDefault" $ let prop :: Fun (i, A) B -> f A -> Property prop f' xs = imap f xs === imapDefault f xs where f i a = applyFun f' (i, a) in prop , testProperty "ifoldMapDefault" $ let prop :: Fun (i, A) [B] -> f A -> Property prop f' xs = ifoldMap f xs === ifoldMapDefault f xs where f i a = applyFun f' (i, a) in prop , testProperty "ifoldrDefault" $ let prop :: Fun (i, A, B) B -> B -> f A -> Property prop f' b xs = ifoldr f b xs === ifoldrDefault f b xs where f i x y = applyFun f' (i, x, y) in prop , testProperty "ifoldl'Default" $ let prop :: Fun (i, B, A) B -> B -> f A -> Property prop f' b xs = ifoldl' f b xs === ifoldl'Default f b xs where f i x y = applyFun f' (i, x, y) in prop , testProperty "toList" $ let prop :: f A -> Property prop xs = toList xs === map snd (itoList xs) in prop , testProperty "indices" $ let prop :: f A -> Property prop xs = indices t xs === map fst (itoList xs) in prop ] where name = show (typeRep t) ------------------------------------------------------------------------------- -- Defaults ------------------------------------------------------------------------------- ifoldrDefault :: FoldableWithIndex i f => (i -> a -> b -> b) -> b -> f a -> b ifoldrDefault f z t = appEndo (ifoldMap (\i -> Endo . f i) t) z ifoldl'Default :: FoldableWithIndex i f => (i -> b -> a -> b) -> b -> f a -> b ifoldl'Default f z0 xs = ifoldr f' id xs z0 where f' i x k z = k $! f i z x