packages feed

monoidmap-0.0.0.0: src/test/Data/MonoidMap/SliceSpec.hs

{- HLINT ignore "Redundant bracket" -}
{- HLINT ignore "Use camelCase" -}
{- HLINT ignore "Use null" -}

-- |
-- Copyright: © 2022–2023 Jonathan Knowles
-- License: Apache-2.0
--
module Data.MonoidMap.SliceSpec
    ( spec
    , Slice (..)
    ) where

import Prelude

import Control.Monad
    ( forM_ )
import Data.Bifunctor
    ( Bifunctor (bimap) )
import Data.Function
    ( (&) )
import Data.Monoid.Null
    ( MonoidNull )
import Data.MonoidMap
    ( MonoidMap, nonNullCount )
import Data.Proxy
    ( Proxy (..) )
import GHC.Exts
    ( IsList (..) )
import Test.Common
    ( Key, Test, TestType (TestType), makeSpec, property, testTypesMonoidNull )
import Test.Hspec
    ( Spec, describe, it )
import Test.QuickCheck
    ( Arbitrary (..), Gen, Property, choose, cover, oneof, (===) )

import qualified Data.MonoidMap as MonoidMap

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

    forM_ testTypesMonoidNull $ \(TestType p) -> specFor (Proxy @Key) p

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

    it "prop_take_toList_fromList" $
        prop_take_toList_fromList
            @k @v & property
    it "prop_drop_toList_fromList" $
        prop_drop_toList_fromList
            @k @v & property
    it "prop_splitAt_toList_fromList" $
        prop_splitAt_toList_fromList
            @k @v & property

data Slice k v = Slice Int (MonoidMap k v)
    deriving (Eq, Show)

instance (Arbitrary k, Arbitrary v, MonoidNull v, Ord k) =>
    Arbitrary (Slice k v)
  where
    arbitrary = do
        m <- genMap
        i <- genIndex m
        pure $ Slice i m
      where
        genMap :: Gen (MonoidMap k v)
        genMap = arbitrary

        genIndex :: MonoidMap k v -> Gen Int
        genIndex m = oneof
            [ choose (negate (length m), -1)
            , pure 0
            , choose (1, length m - 1)
            , pure (length m)
            , choose (length m + 1, 2 * length m)
            ]

prop_take_toList_fromList
    :: Test k v => Slice k v -> Property
prop_take_toList_fromList (Slice i m) =
    MonoidMap.take i m
        === (fromList . Prelude.take i . toList) m
    & cover 2
        (i == 0 && 0 < nonNullCount m)
        "i == 0 && 0 < nonNullCount m"
    & cover 2
        (0 < i && i < nonNullCount m)
        "0 < i && i < nonNullCount m"
    & cover 2
        (0 < nonNullCount m && nonNullCount m == i)
        "0 < nonNullCount m && nonNullCount m == i"
    & cover 2
        (0 < nonNullCount m && nonNullCount m < i)
        "0 < nonNullCount m && nonNullCount m < i"

prop_drop_toList_fromList
    :: Test k v => Slice k v -> Property
prop_drop_toList_fromList (Slice i m) =
    MonoidMap.drop i m
        === (fromList . Prelude.drop i . toList) m
    & cover 2
        (i == 0 && 0 < nonNullCount m)
        "i == 0 && 0 < nonNullCount m"
    & cover 2
        (0 < i && i < nonNullCount m)
        "0 < i && i < nonNullCount m"
    & cover 2
        (0 < nonNullCount m && nonNullCount m == i)
        "0 < nonNullCount m && nonNullCount m == i"
    & cover 2
        (0 < nonNullCount m && nonNullCount m < i)
        "0 < nonNullCount m && nonNullCount m < i"

prop_splitAt_toList_fromList
    :: Test k v => Slice k v -> Property
prop_splitAt_toList_fromList (Slice i m) =
    MonoidMap.splitAt i m
        === (bimap fromList fromList . Prelude.splitAt i . toList) m
    & cover 2
        (i == 0 && 0 < nonNullCount m)
        "i == 0 && 0 < nonNullCount m"
    & cover 2
        (0 < i && i < nonNullCount m)
        "0 < i && i < nonNullCount m"
    & cover 2
        (0 < nonNullCount m && nonNullCount m == i)
        "0 < nonNullCount m && nonNullCount m == i"
    & cover 2
        (0 < nonNullCount m && nonNullCount m < i)
        "0 < nonNullCount m && nonNullCount m < i"