packages feed

brick-0.43: tests/Main.hs

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}

import Control.Applicative
import Data.Bool (bool)
import System.Exit (exitFailure, exitSuccess)

import Data.IMap (IMap, Run(Run))
import Data.IntMap (IntMap)
import Test.QuickCheck
import qualified Data.IMap as IMap
import qualified Data.IntMap as IntMap

instance Arbitrary v => Arbitrary (Run v) where
    arbitrary = liftA2 (\(Positive n) -> Run n) arbitrary arbitrary

instance Arbitrary v => Arbitrary (IMap v) where
    arbitrary = IMap.fromList <$> arbitrary

instance (a ~ Ordering, Show b) => Show (a -> b) where
    show f = show [f x | x <- [minBound .. maxBound]]

lower :: IMap v -> IntMap v
lower m = IntMap.fromDistinctAscList
    [ (base+offset, v)
    | (base, Run n v) <- IMap.unsafeToAscList m
    , offset <- [0..n-1]
    ]

raise :: Eq v => IntMap v -> IMap v
raise = IMap.fromList . rle . map singletonRun . IntMap.toAscList where
    singletonRun (k, v) = (k, Run 1 v)

    rle ((k, Run n v):(k', Run n' v'):kvs)
        | k+n == k' && v == v' = rle ((k, Run (n+n') v):kvs)
    rle (kv:kvs) = kv:rle kvs
    rle [] = []

lowerRun :: Int -> Run v -> IntMap v
lowerRun k r = IntMap.fromAscList [(k+offset, IMap.val r) | offset <- [0..IMap.len r-1]]

type O = Ordering
type I = IMap Ordering

-- These next two probably have overflow bugs that QuickCheck can't reasonably
-- notice. Hopefully they don't come up in real use cases...
prop_raiseLowerFaithful :: IntMap O -> Bool
prop_raiseLowerFaithful m = m == lower (raise m)

prop_equalityReflexive :: I -> Bool
prop_equalityReflexive m = m == raise (lower m)

prop_equality :: I -> I -> Bool
prop_equality l r = (l == r) == (lower l == lower r)

prop_compare :: I -> I -> Bool
prop_compare l r = compare l r == compare (lower l) (lower r)

prop_applicativeIdentity :: I -> Bool
prop_applicativeIdentity v = (pure id <*> v) == v

prop_applicativeComposition :: IMap (O -> O) -> IMap (O -> O) -> IMap O -> Bool
prop_applicativeComposition u v w = (pure (.) <*> u <*> v <*> w) == (u <*> (v <*> w))

prop_applicativeHomomorphism :: (O -> O) -> O -> Bool
prop_applicativeHomomorphism f x = (pure f <*> pure x :: I) == pure (f x)

prop_applicativeInterchange :: IMap (O -> O) -> O -> Bool
prop_applicativeInterchange u y = (u <*> pure y) == (pure ($ y) <*> u)

prop_empty :: Bool
prop_empty = lower (IMap.empty :: I) == IntMap.empty

prop_singleton :: Int -> Run O -> Bool
prop_singleton k r = lower (IMap.singleton k r) == lowerRun k r

prop_insert :: Int -> Run O -> I -> Bool
prop_insert k r m = lower (IMap.insert k r m) == IntMap.union (lowerRun k r) (lower m)

prop_delete :: Int -> Run () -> I -> Bool
prop_delete k r m = lower (IMap.delete k r m) == lower m IntMap.\\ lowerRun k r

prop_splitLE :: Int -> I -> Bool
prop_splitLE k m = (lower le, lower gt) == (le', gt') where
    (le, gt) = IMap.splitLE k m
    (lt, eq, gt') = IntMap.splitLookup k (lower m)
    le' = maybe id (IntMap.insert k) eq lt

prop_intersectionWith :: (O -> O -> O) -> I -> I -> Bool
prop_intersectionWith f l r = lower (IMap.intersectionWith f l r) == IntMap.intersectionWith f (lower l) (lower r)

prop_addToKeys :: Int -> I -> Bool
prop_addToKeys n m = lower (IMap.addToKeys n m) == IntMap.mapKeysMonotonic (n+) (lower m)

prop_lookup :: Int -> I -> Bool
prop_lookup k m = IMap.lookup k m == IntMap.lookup k (lower m)

prop_restrict :: Int -> Run () -> I -> Bool
prop_restrict k r m = lower (IMap.restrict k r m) == IntMap.intersection (lower m) (lowerRun k r)

prop_mapMaybe :: (O -> Maybe O) -> I -> Bool
prop_mapMaybe f m = lower (IMap.mapMaybe f m) == IntMap.mapMaybe f (lower m)

prop_null :: I -> Bool
prop_null m = IMap.null m == IntMap.null (lower m)

return []

main :: IO ()
main = $quickCheckAll >>= bool exitFailure exitSuccess