monoidmap-0.0.2.0: src/test/Data/MonoidMap/ConversionSpec.hs
{- HLINT ignore "Redundant bracket" -}
{- HLINT ignore "Use camelCase" -}
{- HLINT ignore "Use null" -}
-- |
-- Copyright: © 2022–2025 Jonathan Knowles
-- License: Apache-2.0
--
module Data.MonoidMap.ConversionSpec
( spec
) where
import Prelude
import Control.Monad
( forM_ )
import Data.Function
( (&) )
import Data.Map.Strict
( Map )
import Data.MonoidMap
( MonoidMap, nonNullCount )
import Data.Proxy
( Proxy (..) )
import Data.Set
( Set )
import Test.Common
( Key, Test, TestType (TestType), makeSpec, property, testTypesMonoidNull )
import Test.Hspec
( Spec, describe, it )
import Test.QuickCheck
( Fun (..), Property, applyFun, applyFun2, cover, (===) )
import qualified Data.Foldable as F
import qualified Data.List as List
import qualified Data.List.NonEmpty as NE
import qualified Data.Map.Strict as Map
import qualified Data.Monoid.Null as Null
import qualified Data.MonoidMap as MonoidMap
import qualified Data.Set as Set
spec :: Spec
spec = describe "Conversions" $ do
forM_ testTypesMonoidNull $ \(TestType p) -> specFor (Proxy @Key) p
specFor :: forall k v. Test k v => Proxy k -> Proxy v -> Spec
specFor = makeSpec $ do
describe "Conversion to and from lists" $ do
it "prop_fromList_get" $
prop_fromList_get
@k @v & property
it "prop_fromList_toMap" $
prop_fromList_toMap
@k @v & property
it "prop_fromList_toList" $
prop_fromList_toList
@k @v & property
it "prop_toList_fromList" $
prop_toList_fromList
@k @v & property
it "prop_toList_sort" $
prop_toList_sort
@k @v & property
it "prop_fromListWith_get" $
prop_fromListWith_get
@k @v & property
describe "Conversion to and from ordinary maps" $ do
it "prop_fromMap_toMap" $
prop_fromMap_toMap
@k @v & property
it "prop_toMap_fromMap" $
prop_toMap_fromMap
@k @v & property
describe "Conversion from sets" $ do
it "prop_fromSet_get" $
prop_fromSet_get
@k @v & property
--------------------------------------------------------------------------------
-- Conversion to and from lists
--------------------------------------------------------------------------------
prop_fromList_get
:: Test k v => [(k, v)] -> k -> Property
prop_fromList_get kvs k =
MonoidMap.get k (MonoidMap.fromList kvs)
===
F.foldMap snd (filter ((== k) . fst) kvs)
& cover 2
(matchingKeyCount == 0)
"matchingKeyCount == 0"
& cover 2
(matchingKeyCount == 1)
"matchingKeyCount == 1"
& cover 2
(matchingKeyCount == 2)
"matchingKeyCount == 2"
& cover 2
(matchingKeyCount >= 3)
"matchingKeyCount >= 3"
where
matchingKeyCount =
length $ filter ((== k) . fst) kvs
prop_fromList_toMap
:: Test k v => [(k, v)] -> Property
prop_fromList_toMap kvs =
MonoidMap.toMap m === Map.filter (/= mempty) o
& cover 2
(MonoidMap.nonNull m && nonNullCount m /= Map.size o)
"MonoidMap.nonNull m && nonNullCount m /= Map.size o"
& cover 2
(MonoidMap.nonNull m && nonNullCount m == Map.size o)
"MonoidMap.nonNull m && nonNullCount m == Map.size o"
where
m = MonoidMap.fromList kvs
o = Map.fromListWith (flip (<>)) kvs
prop_fromList_toList
:: Test k v => [(k, v)] -> Property
prop_fromList_toList kvs =
MonoidMap.toList m === Map.toList (Map.filter (/= mempty) o)
& cover 2
(MonoidMap.nonNull m && nonNullCount m /= Map.size o)
"MonoidMap.nonNull m && nonNullCount m /= Map.size o"
& cover 2
(MonoidMap.nonNull m && nonNullCount m == Map.size o)
"MonoidMap.nonNull m && nonNullCount m == Map.size o"
where
m = MonoidMap.fromList kvs
o = Map.fromListWith (flip (<>)) kvs
prop_toList_fromList
:: Test k v => MonoidMap k v -> Property
prop_toList_fromList m =
MonoidMap.fromList (MonoidMap.toList m) === m
& cover 2
(MonoidMap.nonNull m)
"MonoidMap.nonNull m"
prop_toList_sort
:: Test k v => MonoidMap k v -> Property
prop_toList_sort m =
List.sortOn fst (MonoidMap.toList m) === MonoidMap.toList m
& cover 2
(MonoidMap.nonNull m)
"MonoidMap.nonNull m"
prop_fromListWith_get
:: Test k v => Fun (v, v) v -> [(k, v)] -> k -> Property
prop_fromListWith_get (applyFun2 -> f) kvs k =
MonoidMap.get k (MonoidMap.fromListWith f kvs)
===
maybe mempty
(F.foldl1 f)
(NE.nonEmpty (snd <$> filter ((== k) . fst) kvs))
& cover 2
(matchingKeyCount == 0)
"matchingKeyCount == 0"
& cover 2
(matchingKeyCount == 1)
"matchingKeyCount == 1"
& cover 2
(matchingKeyCount == 2)
"matchingKeyCount == 2"
& cover 2
(matchingKeyCount >= 3)
"matchingKeyCount >= 3"
where
matchingKeyCount =
length $ filter ((== k) . fst) kvs
--------------------------------------------------------------------------------
-- Conversion to and from ordinary maps
--------------------------------------------------------------------------------
prop_fromMap_toMap
:: Test k v => Map k v -> Property
prop_fromMap_toMap o =
MonoidMap.toMap m === Map.filter (/= mempty) o
& cover 2
(MonoidMap.nonNull m && nonNullCount m /= Map.size o)
"MonoidMap.nonNull m && nonNullCount m /= Map.size o"
& cover 2
(MonoidMap.nonNull m && nonNullCount m == Map.size o)
"MonoidMap.nonNull m && nonNullCount m == Map.size o"
where
m = MonoidMap.fromMap o
prop_toMap_fromMap
:: Test k v => MonoidMap k v -> Property
prop_toMap_fromMap m =
MonoidMap.fromMap (MonoidMap.toMap m) === m
--------------------------------------------------------------------------------
-- Conversion from sets
--------------------------------------------------------------------------------
prop_fromSet_get
:: Test k v => Fun k v -> Set k -> k -> Property
prop_fromSet_get (applyFun -> f) ks k =
MonoidMap.get k (MonoidMap.fromSet f ks)
===
(if Set.member k ks then f k else mempty)
& cover 0.2
(Set.member k ks && Null.null (f k))
"Set.member k ks && Null.null (f k)"
& cover 8.0
(Set.member k ks && not (Null.null (f k)))
"Set.member k ks && not (Null.null (f k))"
& cover 0.2
(not (Set.member k ks) && Null.null (f k))
"not (Set.member k ks) && Null.null (f k)"
& cover 8.0
(not (Set.member k ks) && not (Null.null (f k)))
"not (Set.member k ks) && not (Null.null (f k))"