2018-03-18 18:24:52 +03:00
|
|
|
{-# LANGUAGE TemplateHaskell #-}
|
|
|
|
{-# LANGUAGE TypeFamilies #-}
|
|
|
|
|
|
|
|
import Control.Applicative
|
2018-12-05 14:20:15 +03:00
|
|
|
import Data.Bool (bool)
|
2018-12-06 13:38:26 +03:00
|
|
|
import Data.Traversable (sequenceA)
|
2018-12-05 14:20:15 +03:00
|
|
|
import System.Exit (exitFailure, exitSuccess)
|
|
|
|
|
2018-03-18 18:24:52 +03:00
|
|
|
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
|
|
|
|
|
2018-12-06 13:38:26 +03:00
|
|
|
import qualified List
|
2022-07-01 04:54:30 +03:00
|
|
|
import qualified Render
|
2018-12-06 13:38:26 +03:00
|
|
|
|
2018-03-18 18:24:52 +03:00
|
|
|
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
|
2021-03-15 23:19:22 +03:00
|
|
|
prop_applicativeIdentity v = (id <$> v) == v
|
2018-03-18 18:24:52 +03:00
|
|
|
|
|
|
|
prop_applicativeComposition :: IMap (O -> O) -> IMap (O -> O) -> IMap O -> Bool
|
2021-03-15 23:19:22 +03:00
|
|
|
prop_applicativeComposition u v w = ((.) <$> u <*> v <*> w) == (u <*> (v <*> w))
|
2018-03-18 18:24:52 +03:00
|
|
|
|
|
|
|
prop_applicativeHomomorphism :: (O -> O) -> O -> Bool
|
2021-03-15 23:19:22 +03:00
|
|
|
prop_applicativeHomomorphism f x = (f <$> pure x :: I) == pure (f x)
|
2018-03-18 18:24:52 +03:00
|
|
|
|
|
|
|
prop_applicativeInterchange :: IMap (O -> O) -> O -> Bool
|
2021-03-15 23:19:22 +03:00
|
|
|
prop_applicativeInterchange u y = (u <*> pure y) == (($ y) <$> u)
|
2018-03-18 18:24:52 +03:00
|
|
|
|
|
|
|
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)
|
|
|
|
|
2018-03-18 19:22:40 +03:00
|
|
|
prop_restrict :: Int -> Run () -> I -> Bool
|
|
|
|
prop_restrict k r m = lower (IMap.restrict k r m) == IntMap.intersection (lower m) (lowerRun k r)
|
2018-03-18 18:24:52 +03:00
|
|
|
|
|
|
|
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 []
|
|
|
|
|
2018-12-05 14:20:15 +03:00
|
|
|
main :: IO ()
|
2018-12-06 13:38:26 +03:00
|
|
|
main =
|
2022-07-01 04:54:30 +03:00
|
|
|
(all id <$> sequenceA [$quickCheckAll, List.main, Render.main])
|
2018-12-06 13:38:26 +03:00
|
|
|
>>= bool exitFailure exitSuccess
|