packages feed

monoidmap-0.0.4.0: components/monoidmap-test/Data/MonoidMap/FilterSpec.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.FilterSpec
    ( spec
    ) where

import Prelude

import Control.Monad
    ( forM_ )
import Data.Function
    ( (&) )
import Data.MonoidMap
    ( MonoidMap, nonNullCount )
import Data.Proxy
    ( Proxy (..) )
import GHC.Exts
    ( IsList (..) )
import Test.Common
    ( Key
    , Test
    , TestValueType (TestValueType)
    , makeSpec
    , property
    , testValueTypesAll
    )
import Test.Hspec
    ( Spec, describe, it )
import Test.QuickCheck
    ( Fun (..), Property, applyFun, applyFun2, cover, (===) )

import qualified Data.List as List
import qualified Data.MonoidMap as MonoidMap

spec :: Spec
spec = describe "Filtering" $ do

    forM_ testValueTypesAll $
        \(TestValueType p) -> specFor (Proxy @Key) p

specFor :: forall k v. Test k v => Proxy k -> Proxy v -> Spec
specFor = makeSpec $ do

    it "prop_filter_get" $
        prop_filter_get
            @k @v & property
    it "prop_filter_asList" $
        prop_filter_asList
            @k @v & property
    it "prop_filterKeys_get" $
        prop_filterKeys_get
            @k @v & property
    it "prop_filterKeys_asList" $
        prop_filterKeys_asList
            @k @v & property
    it "prop_filterWithKey_get" $
        prop_filterWithKey_get
            @k @v & property
    it "prop_filterWithKey_asList" $
        prop_filterWithKey_asList
            @k @v & property

prop_filter_get
    :: Test k v => Fun v Bool -> k -> MonoidMap k v -> Property
prop_filter_get (applyFun -> f) k m =
    MonoidMap.get k (MonoidMap.filter f m)
        ===
        (MonoidMap.get k m & \v -> if f v then v else mempty)
    & cover 2
        (MonoidMap.nullKey k m && f (MonoidMap.get k m))
        "MonoidMap.nullKey k m && f (MonoidMap.get k m)"
    & cover 2
        (MonoidMap.nullKey k m && not (f (MonoidMap.get k m)))
        "MonoidMap.nullKey k m && not (f (MonoidMap.get k m))"
    & cover 2
        (MonoidMap.nonNullKey k m && f (MonoidMap.get k m))
        "MonoidMap.nonNullKey k m && f (MonoidMap.get k m)"
    & cover 2
        (MonoidMap.nonNullKey k m && not (f (MonoidMap.get k m)))
        "MonoidMap.nonNullKey k m && not (f (MonoidMap.get k m))"

prop_filter_asList
    :: Test k v => Fun v Bool -> MonoidMap k v -> Property
prop_filter_asList (applyFun -> f) m =
    n === fromList (List.filter (f . snd) (toList m))
    & cover 2
        (MonoidMap.nonNull n && nonNullCount n == nonNullCount m)
        "MonoidMap.nonNull n && nonNullCount n == nonNullCount m"
    & cover 2
        (MonoidMap.nonNull n && nonNullCount n /= nonNullCount m)
        "MonoidMap.nonNull n && nonNullCount n /= nonNullCount m"
  where
    n = MonoidMap.filter f m

prop_filterKeys_get
    :: Test k v => Fun k Bool -> k -> MonoidMap k v -> Property
prop_filterKeys_get (applyFun -> f) k m =
    MonoidMap.get k (MonoidMap.filterKeys f m)
        ===
        (if f k then MonoidMap.get k m else mempty)
    & cover 2
        (MonoidMap.nullKey k m && f k)
        "MonoidMap.nullKey k m && f k"
    & cover 2
        (MonoidMap.nullKey k m && not (f k))
        "MonoidMap.nullKey k m && not (f k)"
    & cover 2
        (MonoidMap.nonNullKey k m && f k)
        "MonoidMap.nonNullKey k m && f k"
    & cover 2
        (MonoidMap.nonNullKey k m && not (f k))
        "MonoidMap.nonNullKey k m && not (f k)"

prop_filterKeys_asList
    :: Test k v => Fun k Bool -> MonoidMap k v -> Property
prop_filterKeys_asList (applyFun -> f) m =
    n === MonoidMap.fromList (List.filter (f . fst) (toList m))
    & cover 2
        (MonoidMap.nonNull n && nonNullCount n == nonNullCount m)
        "MonoidMap.nonNull n && nonNullCount n == nonNullCount m"
    & cover 2
        (MonoidMap.nonNull n && nonNullCount n /= nonNullCount m)
        "MonoidMap.nonNull n && nonNullCount n /= nonNullCount m"
  where
    n = MonoidMap.filterKeys f m

prop_filterWithKey_get
    :: Test k v => Fun (k, v) Bool -> k -> MonoidMap k v -> Property
prop_filterWithKey_get (applyFun2 -> f) k m =
    MonoidMap.get k (MonoidMap.filterWithKey f m)
        ===
        (MonoidMap.get k m & \v -> if f k v then v else mempty)
    & cover 2
        (MonoidMap.nullKey k m && f k (MonoidMap.get k m))
        "MonoidMap.nullKey k m && f k (MonoidMap.get k m)"
    & cover 2
        (MonoidMap.nullKey k m && not (f k (MonoidMap.get k m)))
        "MonoidMap.nullKey k m && not (f k (MonoidMap.get k m))"
    & cover 2
        (MonoidMap.nonNullKey k m && f k (MonoidMap.get k m))
        "MonoidMap.nonNullKey k m && f k (MonoidMap.get k m)"
    & cover 2
        (MonoidMap.nonNullKey k m && not (f k (MonoidMap.get k m)))
        "MonoidMap.nonNullKey k m && not (f k (MonoidMap.get k m))"

prop_filterWithKey_asList
    :: Test k v => Fun (k, v) Bool -> MonoidMap k v -> Property
prop_filterWithKey_asList (applyFun2 -> f) m =
    n === MonoidMap.fromList (List.filter (uncurry f) (toList m))
    & cover 2
        (MonoidMap.nonNull n && nonNullCount n == nonNullCount m)
        "MonoidMap.nonNull n && nonNullCount n == nonNullCount m"
    & cover 2
        (MonoidMap.nonNull n && nonNullCount n /= nonNullCount m)
        "MonoidMap.nonNull n && nonNullCount n /= nonNullCount m"
  where
    n = MonoidMap.filterWithKey f m