packages feed

nonempty-vector-1.0: test/Test/Data/Vector/NonEmpty/GroupingU.hs

module Test.Data.Vector.NonEmpty.GroupingU
( tests
) where


import qualified Data.List as List
import qualified Data.List.NonEmpty as NonEmpty
import Data.Vector.NonEmpty.Unboxed (NonEmptyUVector)
import Data.Vector.Unboxed (Unbox)
import qualified Data.Vector.NonEmpty.Unboxed as NEV

import Test.Data.Vector.NonEmpty.Util
import Test.QuickCheck
import Test.Tasty
import Test.Tasty.QuickCheck


tests :: TestTree
tests = testGroup "Grouping (unboxed)"
    [ testGroup "group"
      [ testProperty "prop_group" prop_group
      , testProperty "prop_group_singleton" prop_group_singleton
      , testProperty "prop_group_all_equal" prop_group_all_equal
      , testProperty "prop_group_distinct" prop_group_distinct
      , testProperty "prop_group_runs" prop_group_runs
      ]
    , testGroup "groupBy"
      [ testProperty "prop_groupBy" prop_groupBy
      , testProperty "prop_groupBy_singleton" prop_groupBy_singleton
      , testProperty "prop_groupBy_all_true" prop_groupBy_all_true
      , testProperty "prop_groupBy_all_false" prop_groupBy_all_false
      , testProperty "prop_groupBy_equivalence" prop_groupBy_equivalence
      , testProperty "prop_groupBy_nontransitive" prop_groupBy_nontransitive
      , testProperty "prop_groupBy_asymmetric" prop_groupBy_asymmetric
      ]
    ]

groupElems :: Unbox element => NonEmpty.NonEmpty (NonEmptyUVector element) -> [[element]]
groupElems = List.map elemsU . NonEmpty.toList

prop_group :: NonEmptyUVector Int -> Property
prop_group input =
    groupElems (NEV.group (vecU values)) === List.group values
  where
    values = List.map (`mod` 4) (elemsU input)

prop_group_singleton :: Int -> Property
prop_group_singleton value =
    groupElems (NEV.group (vecU [value])) === [[value]]

prop_group_all_equal :: Int -> Positive Int -> Property
prop_group_all_equal value (Positive count) =
    groupElems (NEV.group (vecU values)) === [values]
  where
    values = List.replicate count value

prop_group_distinct :: NonEmptyUVector Int -> Property
prop_group_distinct input =
    groupElems (NEV.group (vecU values)) === List.map (: []) values
  where
    values = List.nub (elemsU input)

prop_group_runs :: Property
prop_group_runs = once $
    groupElems (NEV.group (vecU "Mississippi"))
      === ["M", "i", "ss", "i", "ss", "i", "pp", "i"]

prop_groupBy :: Fun (Int, Int) Bool -> NonEmptyUVector Int -> Property
prop_groupBy (Fn2 predicate) input =
    groupElems (NEV.groupBy predicate (vecU values))
      === List.groupBy predicate values
  where
    values = List.map (`mod` 4) (elemsU input)

prop_groupBy_singleton :: Int -> Property
prop_groupBy_singleton value =
    groupElems (NEV.groupBy predicate (vecU [value])) === [[value]]
  where
    predicate _ _ = error "groupBy evaluated its predicate on a singleton"

prop_groupBy_all_true :: NonEmptyUVector Int -> Property
prop_groupBy_all_true input =
    groupElems (NEV.groupBy (\_ _ -> True) input) === [elemsU input]

prop_groupBy_all_false :: NonEmptyUVector Int -> Property
prop_groupBy_all_false input =
    groupElems (NEV.groupBy (\_ _ -> False) input)
      === List.map (: []) (elemsU input)

prop_groupBy_equivalence :: NonEmptyUVector Int -> Property
prop_groupBy_equivalence input =
    groupElems (NEV.groupBy sameParity input)
      === List.groupBy sameParity (elemsU input)
  where
    sameParity first second = even first == even second

prop_groupBy_nontransitive :: Property
prop_groupBy_nontransitive = once $
    groupElems (NEV.groupBy nearby (vecU [1, 2, 3, 4] :: NonEmptyUVector Int))
      === [[1, 2], [3, 4]]
  where
    nearby first second = abs (first - second) <= 1

prop_groupBy_asymmetric :: Property
prop_groupBy_asymmetric = once $
    groupElems (NEV.groupBy (<) (vecU [1, 2, 1, 3, 0, 4] :: NonEmptyUVector Int))
      === [[1, 2], [1, 3], [0, 4]]