packages feed

incremental-maps-0.0.0.0: src/test-suites/MapTests.hs

module MapTests where

-- Prelude

import Prelude hiding (id, (.))

-- Control

import Control.Category
import Control.Applicative

-- Data

import           Data.Foldable (toList)
import           Data.MultiChange (MultiChange)
import qualified Data.MultiChange               as MultiChange
import           Data.Map (Map)
import qualified Data.Map                       as Map
import           Data.Incremental               
import qualified Data.Incremental.Tuple         as Tuple
import qualified Data.Incremental.Map           as IncMap

import Test.QuickCheck.Function
import Distribution.TestSuite.QuickCheck
import Test.QuickCheck
import Test.QuickCheck.Poly

instance Arbitrary a => Arbitrary (PrimitiveChange a) where

    arbitrary = frequency [(1, keepGen), (5, replaceGen)] where

        keepGen = return Keep

        replaceGen = fmap ReplaceBy arbitrary

    shrink Keep            = []
    shrink (ReplaceBy val) = Keep : map ReplaceBy (shrink val)

instance Arbitrary p => Arbitrary (MultiChange p) where

    arbitrary = fmap MultiChange.fromList arbitrary

    shrink change = map MultiChange.fromList (shrink (toList change))

-- Pair changes
deriving instance (Show (DefaultChange a), Show (DefaultChange b)) =>
                  Show (Tuple.AtomicChange a b)

instance (Arbitrary (DefaultChange a), Arbitrary (DefaultChange b)) =>
         Arbitrary (Tuple.AtomicChange a b) where

    arbitrary = oneof [firstGen, secondGen] where

        firstGen = fmap Tuple.First arbitrary

        secondGen = fmap Tuple.Second arbitrary

    shrink (Tuple.First change)  = map Tuple.First (shrink change)
    shrink (Tuple.Second change) = map Tuple.Second (shrink change)

-- Map changes
instance (Arbitrary k, Arbitrary v) =>
         Arbitrary (IncMap.AtomicChange k v) where

    arbitrary = oneof [delete, insert] where

        insert = liftA2 IncMap.Insert arbitrary arbitrary

        delete = liftA IncMap.Delete arbitrary

    shrink (IncMap.Insert k v)
        = [IncMap.Insert k' v'
              | (k', v') <- shrink (k, v)]
    shrink (IncMap.Delete k)
        = [IncMap.Delete k'
              | k' <- shrink k]

newtype AtomicAChange = DoubleAndAdd Integer deriving (Show, Arbitrary)

instance Change AtomicAChange where

    type Value AtomicAChange = A

    DoubleAndAdd diff $$ A integer = A (2 * integer + diff)

deriving instance Ord A

newtype AtomicBChange = TripleAndAdd Integer deriving (Show, Arbitrary)

instance Change AtomicBChange where

    type Value AtomicBChange = B

    TripleAndAdd diff $$ B integer = B (3 * integer + diff)

deriving instance Ord B

newtype AtomicCChange = QuadrupleAndAdd Integer deriving (Show, Arbitrary)

instance Change AtomicCChange where

    type Value AtomicCChange = C

    QuadrupleAndAdd diff $$ C integer = C (4 * integer + diff)

deriving instance Ord C

-- * Tests
prop_lookupTest :: A -> (Map A B, [MultiChange (IncMap.AtomicChange A B)]) -> Bool
prop_lookupTest k valAndChanges = prop valAndChanges where
        prop valAndChanges = map (Map.lookup k) (applyChanges valAndChanges) == applyChanges valAndChanges' where
        valAndChanges' = runTrans (IncMap.lookup k) valAndChanges

prop_memberTest :: A -> (Map A B, [MultiChange (IncMap.AtomicChange A B)]) -> Bool
prop_memberTest k valAndChanges = prop valAndChanges where
        prop valAndChanges = map (Map.member k) (applyChanges valAndChanges) == applyChanges valAndChanges' where
        valAndChanges' = runTrans (IncMap.member k) valAndChanges

prop_filterTest :: Fun B Bool -> (Map A B, [MultiChange (IncMap.AtomicChange A B)]) -> Bool
prop_filterTest fun valAndChanges = prop valAndChanges where
        prop valAndChanges = map (Map.filter f) (applyChanges valAndChanges) == applyChanges valAndChanges' where
        valAndChanges' = runTrans (IncMap.filter f) valAndChanges
        f = apply fun

prop_mapTest :: Fun B C -> (Map A B, [MultiChange (IncMap.AtomicChange A B)]) -> Bool
prop_mapTest fun valAndChanges = prop valAndChanges where
        prop valAndChanges = map (Map.map f) (applyChanges valAndChanges) == applyChanges valAndChanges' where
        valAndChanges' = runTrans (IncMap.map f) valAndChanges
        f = apply fun

prop_partitionTest :: Fun B Bool -> (Map A B, [MultiChange (IncMap.AtomicChange A B)]) -> Bool
prop_partitionTest fun valAndChanges = prop valAndChanges where
        prop valAndChanges = map (Map.partition f) (applyChanges valAndChanges) == applyChanges valAndChanges' where
        valAndChanges' = runTrans (IncMap.partition f) valAndChanges
        f = apply fun

prop_unionTest :: ((Map A B,Map A B), [MultiChange (Tuple.AtomicChange (Map A B) (Map A B))]) -> Bool
prop_unionTest valAndChanges = prop valAndChanges where
        prop valAndChanges = map (uncurry Map.union) (applyChanges valAndChanges) == applyChanges valAndChanges' where
        valAndChanges' = runTrans (IncMap.union) valAndChanges

prop_differenceTest :: ((Map A B,Map A B), [MultiChange (Tuple.AtomicChange (Map A B) (Map A B))]) -> Bool
prop_differenceTest valAndChanges = prop valAndChanges where
        prop valAndChanges = map (uncurry Map.difference) (applyChanges valAndChanges) == applyChanges valAndChanges' where
        valAndChanges' = runTrans (IncMap.difference) valAndChanges

prop_intersectionTest :: ((Map A B,Map A B), [MultiChange (Tuple.AtomicChange (Map A B) (Map A B))]) -> Bool
prop_intersectionTest valAndChanges = prop valAndChanges where
        prop valAndChanges = map (uncurry Map.intersection) (applyChanges valAndChanges) == applyChanges valAndChanges' where
        valAndChanges' = runTrans (IncMap.intersection) valAndChanges

prop_keysSetTest :: ((Map A B), [MultiChange (IncMap.AtomicChange A B)]) -> Bool
prop_keysSetTest valAndChanges = prop valAndChanges where
        prop valAndChanges = map (Map.keysSet) (applyChanges valAndChanges) == applyChanges valAndChanges' where
        valAndChanges' = runTrans (IncMap.keysSet) valAndChanges

prop_submapOfTest :: ((Map A B,Map A B), [MultiChange (Tuple.AtomicChange (Map A B) (Map A B))]) -> Bool
prop_submapOfTest valAndChanges = prop valAndChanges where
        prop valAndChanges = map (uncurry Map.isSubmapOf) (applyChanges valAndChanges) == applyChanges valAndChanges' where
        valAndChanges' = runTrans (IncMap.isSubmapOf) valAndChanges

prop_splitTest :: A -> ((Map A B), [MultiChange (IncMap.AtomicChange A B)]) -> Bool
prop_splitTest key valAndChanges = prop valAndChanges where
        prop valAndChanges = map (Map.split key) (applyChanges valAndChanges) == applyChanges valAndChanges' where
        valAndChanges' = runTrans (IncMap.split key) valAndChanges

prop_mapKeysTest :: Fun A C -> ((Map A B), [MultiChange (IncMap.AtomicChange A B)]) -> Bool
prop_mapKeysTest fun valAndChanges = prop valAndChanges where
        prop valAndChanges = map (Map.mapKeys f) (applyChanges valAndChanges) == applyChanges valAndChanges' where
        valAndChanges' = (runTrans (IncMap.mapKeys f) valAndChanges)
        f = apply fun

applyChanges :: (Change p) => (Value p, [p]) -> [Value p]
applyChanges (val, changes) = scanl (flip ($$)) val changes


tests :: IO [Test]
tests = return
    [ 
      testProperty "lookup" prop_lookupTest
    , testProperty "member" prop_memberTest
    , testProperty "filter" prop_filterTest
    , testProperty "map" prop_mapTest
    , testProperty "partition" prop_partitionTest
    , testProperty "union" prop_unionTest
    , testProperty "difference" prop_differenceTest
    , testProperty "intersection" prop_intersectionTest
    , testProperty "keysSet" prop_keysSetTest
    , testProperty "isSubmapOf" prop_submapOfTest
    , testProperty "split" prop_splitTest
    , testProperty "mapKeys" prop_mapKeysTest
    ]