packages feed

serokell-util-0.9.0: test/Test/Serokell/Util/GroupSpec.hs

module Test.Serokell.Util.GroupSpec
       ( spec
       ) where

import Universum

import Data.List.Extra (nubOn)
import Test.Hspec (Spec, describe)
import Test.Hspec.QuickCheck (prop)
import Test.QuickCheck.Instances ()

import Serokell.Util.Group

spec :: Spec
spec =
    describe "Group" $ do
        describe "'groupBy' doesn't throw elements away" $ do
            prop "with id"   groupByIdProp
            prop "with even" groupByEvenProp
            prop "with mod"  groupByModProp
            prop "with fst"  groupByFstProp
        describe "'groupMapBy' behaves like 'nubOn'" $ do
            prop "with id"   groupMapByIdProp
            prop "with even" groupMapByEvenProp
            prop "with mod"  groupMapByModProp
            prop "with fst"  groupMapByFstProp


----------------------------------------------------------------------------
-- GroupBy
----------------------------------------------------------------------------

-- | Check that 'groupBy' doesn't throw elements away
groupByProp :: (Ord a, Eq b, Hashable b) => (a -> b) -> NonEmpty a -> Bool
groupByProp f l = foldMap toList (elems (groupBy f l)) ~=~ toList l

groupByIdProp, groupByEvenProp, groupByModProp :: NonEmpty Int -> Bool
groupByIdProp   = groupByProp id
groupByEvenProp = groupByProp even
groupByModProp  = groupByProp (`mod` 100)

groupByFstProp :: NonEmpty (Int, Int) -> Bool
groupByFstProp = groupByProp fst

----------------------------------------------------------------------------
-- GroupMapBy
----------------------------------------------------------------------------

-- | Checks that 'groupMapBy' behaves like 'nubOn'.
groupMapByProp :: (Ord a, Eq b, Hashable b) => (a -> b) -> [a] -> Bool
groupMapByProp f l = elems (groupMapBy f l) ~=~ nubOn f l

groupMapByIdProp, groupMapByEvenProp, groupMapByModProp :: [Int] -> Bool
groupMapByIdProp   = groupMapByProp id
groupMapByEvenProp = groupMapByProp even
groupMapByModProp  = groupMapByProp (`mod` 100)

groupMapByFstProp :: [(Int, Int)] -> Bool
groupMapByFstProp = groupMapByProp fst

----------------------------------------------------------------------------

-- | Sorts lists before comparing them.
infix 4 ~=~
(~=~) :: (Ord a) => [a] -> [a] -> Bool
l1 ~=~ l2 = sort l1 == sort l2