diff --git a/containers-tests/containers-tests.cabal b/containers-tests/containers-tests.cabal index 2ef73b036..ca31460c4 100644 --- a/containers-tests/containers-tests.cabal +++ b/containers-tests/containers-tests.cabal @@ -329,7 +329,7 @@ library test-utils IntSetValidity Utils.ArbitrarySetMap Utils.MergeFunc - Utils.NubSorted + Utils.QuickCheck Utils.QuickCheckClasses Utils.Strictness diff --git a/containers-tests/test-utils/Utils/NubSorted.hs b/containers-tests/test-utils/Utils/QuickCheck.hs similarity index 57% rename from containers-tests/test-utils/Utils/NubSorted.hs rename to containers-tests/test-utils/Utils/QuickCheck.hs index 4b29e7925..30f1f53e3 100644 --- a/containers-tests/test-utils/Utils/NubSorted.hs +++ b/containers-tests/test-utils/Utils/QuickCheck.hs @@ -1,12 +1,20 @@ -module Utils.NubSorted +{-# LANGUAGE CPP #-} + +-- | Useful newtypes with Arbitrary instances. +module Utils.QuickCheck ( NubSorted(..) , NubSortedOnFst(..) + , SortedOnFst(..) ) where import qualified Data.List as List import qualified Data.List.NonEmpty as NonEmpty import Data.Ord (comparing) import Test.QuickCheck +#if !MIN_VERSION_QuickCheck(2,17,0) +import Data.Coerce (coerce) +import Data.Ord (Down(..)) +#endif newtype NubSorted a = NubSorted { getNubSorted :: [a] } deriving Show @@ -31,3 +39,17 @@ nubSortBy cmp = map NonEmpty.head . NonEmpty.groupBy (\x y -> cmp x y == EQ) . List.sortBy cmp + +newtype SortedOnFst a b = SortedOnFst { getSortedOnFst :: [(a, b)] } + deriving Show + +instance (Ord a, Arbitrary a, Arbitrary b) => Arbitrary (SortedOnFst a b) where + arbitrary = SortedOnFst . List.sortBy (comparing fst) <$> arbitrary + shrink = + map (SortedOnFst . List.sortBy (comparing fst)) . shrink . getSortedOnFst + +#if !MIN_VERSION_QuickCheck(2,17,0) +instance Arbitrary a => Arbitrary (Down a) where + arbitrary = Down <$> arbitrary + shrink (Down x) = coerce (shrink x) +#endif diff --git a/containers-tests/tests/intmap-properties.hs b/containers-tests/tests/intmap-properties.hs index 04070a711..87e6d2928 100644 --- a/containers-tests/tests/intmap-properties.hs +++ b/containers-tests/tests/intmap-properties.hs @@ -18,6 +18,7 @@ import Control.Applicative (Applicative(..)) import Control.Arrow ((&&&)) import Control.Monad ((<=<)) import Control.Monad.Trans.Writer.Lazy +import Data.Coerce (coerce) import qualified Data.Either as Either import qualified Data.Foldable as Foldable import Data.Monoid @@ -44,6 +45,7 @@ import Test.QuickCheck.Function (apply) import Test.QuickCheck.Poly (A, B, C, OrdA) import qualified Test.QuickCheck.Classes.Base as Laws +import Utils.QuickCheck (NubSortedOnFst(..), SortedOnFst(..)) import Utils.QuickCheckClasses (testLaws) default (Int) @@ -2151,64 +2153,58 @@ prop_mapKeysMonotonic (Positive a) b m = prop_compare :: IntMap OrdA -> IntMap OrdA -> Property prop_compare m1 m2 = compare m1 m2 === compare (toList m1) (toList m2) -prop_fromAscList :: [(Int, A)] -> Property -prop_fromAscList kxs = +prop_fromAscList :: SortedOnFst Int A -> Property +prop_fromAscList (SortedOnFst kxs) = valid t .&&. - t === fromList sortedKxs + t === fromList kxs where - sortedKxs = List.sortBy (comparing fst) kxs - t = fromAscList sortedKxs + t = fromAscList kxs -prop_fromAscListWith :: Fun (A, A) A -> [(Int, A)] -> Property -prop_fromAscListWith f kxs = +prop_fromAscListWith :: Fun (A, A) A -> SortedOnFst Int A -> Property +prop_fromAscListWith f (SortedOnFst kxs) = valid t .&&. - t === fromListWith (applyFun2 f) sortedKxs + t === fromListWith (applyFun2 f) kxs where - sortedKxs = List.sortBy (comparing fst) kxs - t = fromAscListWith (applyFun2 f) sortedKxs + t = fromAscListWith (applyFun2 f) kxs -prop_fromAscListWithKey :: Fun (Int, A, A) A -> [(Int, A)] -> Property -prop_fromAscListWithKey f kxs = +prop_fromAscListWithKey :: Fun (Int, A, A) A -> SortedOnFst Int A -> Property +prop_fromAscListWithKey f (SortedOnFst kxs) = valid t .&&. - t === fromListWithKey (applyFun3 f) sortedKxs + t === fromListWithKey (applyFun3 f) kxs where - sortedKxs = List.sortBy (comparing fst) kxs - t = fromAscListWithKey (applyFun3 f) sortedKxs + t = fromAscListWithKey (applyFun3 f) kxs -prop_fromAscListUpsert :: Fun (A, Maybe B) B -> [(Int, A)] -> Property -prop_fromAscListUpsert f kxs = +prop_fromAscListUpsert :: Fun (A, Maybe B) B -> SortedOnFst Int A -> Property +prop_fromAscListUpsert f (SortedOnFst kxs) = valid t .&&. - t === fromListUpsert (applyFun2 f) sortedKxs + t === fromListUpsert (applyFun2 f) kxs where - sortedKxs = List.sortBy (comparing fst) kxs - t = fromAscListUpsert (applyFun2 f) sortedKxs + t = fromAscListUpsert (applyFun2 f) kxs -prop_fromDistinctAscList :: [(Int, A)] -> Property -prop_fromDistinctAscList kxs = +prop_fromDistinctAscList :: NubSortedOnFst Int A -> Property +prop_fromDistinctAscList (NubSortedOnFst kxs) = valid t .&&. - toList t === nubSortedKxs + t === fromList kxs .&&. + toList t === kxs where - nubSortedKxs = - List.map NE.head $ - NE.groupBy ((==) `on` fst) $ - List.sortBy (comparing fst) kxs - t = fromDistinctAscList nubSortedKxs + t = fromDistinctAscList kxs -prop_fromDescList :: [(Int, A)] -> Property -prop_fromDescList kxs = +prop_fromDescList :: SortedOnFst (Down Int) A -> Property +prop_fromDescList kxs' = valid t .&&. - t === fromList sortedKxs + t === fromList kxs where - sortedKxs = List.sortBy (comparing (Down . fst)) kxs - t = fromDescList sortedKxs + kxs = coerce kxs' :: [(Int, A)] + t = fromDescList kxs -prop_fromDescListUpsert :: Fun (A, Maybe B) B -> [(Int, A)] -> Property -prop_fromDescListUpsert f kxs = +prop_fromDescListUpsert + :: Fun (A, Maybe B) B -> SortedOnFst (Down Int) A -> Property +prop_fromDescListUpsert f kxs' = valid t .&&. - t === fromListUpsert (applyFun2 f) sortedKxs + t === fromListUpsert (applyFun2 f) kxs where - sortedKxs = List.sortBy (comparing (Down . fst)) kxs - t = fromDescListUpsert (applyFun2 f) sortedKxs + kxs = coerce kxs' :: [(Int, A)] + t = fromDescListUpsert (applyFun2 f) kxs prop_fromListWith :: Fun (A, A) A -> [(Int, A)] -> Property prop_fromListWith f kxs = diff --git a/containers-tests/tests/intmap-strictness.hs b/containers-tests/tests/intmap-strictness.hs index 3670ae5f9..8bf47cb47 100644 --- a/containers-tests/tests/intmap-strictness.hs +++ b/containers-tests/tests/intmap-strictness.hs @@ -12,9 +12,8 @@ import Data.Function (on) import Data.Functor.Compose import Data.Functor.Identity (Identity(..)) import qualified Data.List as List -import qualified Data.List.NonEmpty as NE import Data.Maybe (catMaybes, mapMaybe) -import Data.Ord (Down(..), comparing) +import Data.Ord (Down(..)) import Test.ChasingBottoms.IsBottom import Test.Tasty (TestTree, defaultMain, testGroup) import Test.Tasty.QuickCheck (testProperty) @@ -39,7 +38,7 @@ import qualified Data.IntMap.Merge.Lazy as LMerge import Data.Containers.ListUtils import Utils.MergeFunc (WhenMatchedFunc(..), WhenMissingFunc(..)) -import Utils.NubSorted (NubSortedOnFst(..)) +import Utils.QuickCheck (NubSortedOnFst(..), SortedOnFst(..)) import Utils.Strictness (Bot(..), Func, Func2, Func3, applyFunc, applyFunc2, applyFunc3) @@ -162,100 +161,102 @@ prop_lazyFromListUpsert fun kvs = isNotBottomProp (L.fromListUpsert f kvs') f = coerce (applyFunc2 fun) :: A -> Maybe B -> B kvs' = coerce kvs :: [(Key, A)] -prop_strictFromAscList :: [(Key, Bot A)] -> Property +prop_strictFromAscList :: SortedOnFst Key (Bot A) -> Property prop_strictFromAscList kvs = isBottom (M.fromAscList kvs') === isBottom (M.fromList kvs') where - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(Key, A)] + kvs' = coerce kvs :: [(Key, A)] -prop_lazyFromAscList :: [(Key, Bot A)] -> Property +prop_lazyFromAscList :: SortedOnFst Key (Bot A) -> Property prop_lazyFromAscList kvs = isNotBottomProp (L.fromAscList kvs') where - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(Key, A)] + kvs' = coerce kvs :: [(Key, A)] -prop_strictFromAscListWith :: Func2 A A (Bot A) -> [(Key, Bot A)] -> Property +prop_strictFromAscListWith + :: Func2 A A (Bot A) -> SortedOnFst Key (Bot A) -> Property prop_strictFromAscListWith fun kvs = isBottom (M.fromAscListWith f kvs') === isBottom (M.fromListWith f kvs') where f = coerce (applyFunc2 fun) - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(Key, A)] + kvs' = coerce kvs :: [(Key, A)] -prop_lazyFromAscListWith :: Func2 A A (Bot A) -> [(Key, Bot A)] -> Property +prop_lazyFromAscListWith + :: Func2 A A (Bot A) -> SortedOnFst Key (Bot A) -> Property prop_lazyFromAscListWith fun kvs = isNotBottomProp (L.fromAscListWith f kvs') where f = coerce (applyFunc2 fun) - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(Key, A)] + kvs' = coerce kvs :: [(Key, A)] prop_strictFromAscListWithKey - :: Func3 Key A A (Bot A) -> [(Key, Bot A)] -> Property + :: Func3 Key A A (Bot A) -> SortedOnFst Key (Bot A) -> Property prop_strictFromAscListWithKey fun kvs = isBottom (M.fromAscListWithKey f kvs') === isBottom (M.fromListWithKey f kvs') where f = coerce (applyFunc3 fun) - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(Key, A)] + kvs' = coerce kvs :: [(Key, A)] prop_lazyFromAscListWithKey - :: Func3 Key A A (Bot A) -> [(Key, Bot A)] -> Property + :: Func3 Key A A (Bot A) -> SortedOnFst Key (Bot A) -> Property prop_lazyFromAscListWithKey fun kvs = isNotBottomProp (L.fromAscListWithKey f kvs') where f = coerce (applyFunc3 fun) - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(Key, A)] + kvs' = coerce kvs :: [(Key, A)] prop_strictFromAscListUpsert - :: Func2 A (Maybe B) (Bot B) -> [(Key, Bot A)] -> Property + :: Func2 A (Maybe B) (Bot B) -> SortedOnFst Key (Bot A) -> Property prop_strictFromAscListUpsert fun kvs = isBottom (M.fromAscListUpsert f kvs') === isBottom (M.fromListUpsert f kvs') where f = coerce (applyFunc2 fun) :: A -> Maybe B -> B - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(Key, A)] + kvs' = coerce kvs :: [(Key, A)] prop_lazyFromAscListUpsert - :: Func2 A (Maybe B) (Bot B) -> [(Key, Bot A)] -> Property + :: Func2 A (Maybe B) (Bot B) -> SortedOnFst Key (Bot A) -> Property prop_lazyFromAscListUpsert fun kvs = isNotBottomProp (L.fromAscListUpsert f kvs') where f = coerce (applyFunc2 fun) :: A -> Maybe B -> B - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(Key, A)] + kvs' = coerce kvs :: [(Key, A)] -prop_strictFromDistinctAscList :: [(Key, Bot A)] -> Property +prop_strictFromDistinctAscList :: NubSortedOnFst Key (Bot A) -> Property prop_strictFromDistinctAscList kvs = isBottom (M.fromDistinctAscList kvs') === isBottom (M.fromList kvs') where - kvs' = uniqOn fst $ List.sortBy (comparing fst) (coerce kvs) :: [(Key, A)] + kvs' = coerce kvs :: [(Key, A)] -prop_lazyFromDistinctAscList :: [(Key, Bot A)] -> Property +prop_lazyFromDistinctAscList :: NubSortedOnFst Key (Bot A) -> Property prop_lazyFromDistinctAscList kvs = isNotBottomProp (L.fromDistinctAscList kvs') where - kvs' = uniqOn fst $ List.sortBy (comparing fst) (coerce kvs) :: [(Key, A)] + kvs' = coerce kvs :: [(Key, A)] -prop_strictFromDescList :: [(Key, Bot A)] -> Property +prop_strictFromDescList :: SortedOnFst (Down Key) (Bot A) -> Property prop_strictFromDescList kvs = isBottom (M.fromDescList kvs') === isBottom (M.fromList kvs') where - kvs' = List.sortBy (comparing (Down . fst)) (coerce kvs) :: [(Key, A)] + kvs' = coerce kvs :: [(Key, A)] -prop_lazyFromDescList :: [(Key, Bot A)] -> Property +prop_lazyFromDescList :: SortedOnFst (Down Key) (Bot A) -> Property prop_lazyFromDescList kvs = isNotBottomProp (L.fromDescList kvs') where - kvs' = List.sortBy (comparing (Down . fst)) (coerce kvs) :: [(Key, A)] + kvs' = coerce kvs :: [(Key, A)] prop_strictFromDescListUpsert - :: Func2 A (Maybe B) (Bot B) -> [(Key, Bot A)] -> Property + :: Func2 A (Maybe B) (Bot B) -> SortedOnFst (Down Key) (Bot A) -> Property prop_strictFromDescListUpsert fun kvs = isBottom (M.fromDescListUpsert f kvs') === isBottom (M.fromListUpsert f kvs') where f = coerce (applyFunc2 fun) :: A -> Maybe B -> B - kvs' = List.sortBy (comparing (Down . fst)) (coerce kvs) :: [(Key, A)] + kvs' = coerce kvs :: [(Key, A)] prop_lazyFromDescListUpsert - :: Func2 A (Maybe B) (Bot B) -> [(Key, Bot A)] -> Property + :: Func2 A (Maybe B) (Bot B) -> SortedOnFst (Down Key) (Bot A) -> Property prop_lazyFromDescListUpsert fun kvs = isNotBottomProp (L.fromDescListUpsert f kvs') where f = coerce (applyFunc2 fun) :: A -> Maybe B -> B - kvs' = List.sortBy (comparing (Down . fst)) (coerce kvs) :: [(Key, A)] + kvs' = coerce kvs :: [(Key, A)] prop_strictInsert :: Key -> Bot A -> IntMap A -> Property prop_strictInsert k (Bot x) m = isBottom (M.insert k x m) === isBottom x @@ -1186,10 +1187,6 @@ const2 x _ _ = x const3 :: a -> b -> c -> d -> a const3 x _ _ _ = x --- | Keep the first of adjacent equal elements. -uniqOn :: Eq b => (a -> b) -> [a] -> [a] -uniqOn f = map NE.head . NE.groupBy ((==) `on` f) - {-------------------------------------------------------------------- Merge stuff --------------------------------------------------------------------} diff --git a/containers-tests/tests/intset-properties.hs b/containers-tests/tests/intset-properties.hs index dd6e1903c..bac0039bf 100644 --- a/containers-tests/tests/intset-properties.hs +++ b/containers-tests/tests/intset-properties.hs @@ -1,6 +1,7 @@ {-# LANGUAGE CPP #-} import Control.Applicative (Const(..)) import Data.Bits ((.&.), popCount) +import Data.Coerce (coerce) import Data.Word (Word) import Data.IntSet import Data.List (nub,sort) @@ -8,6 +9,7 @@ import qualified Data.List as List import Data.Maybe (listToMaybe) import qualified Data.Maybe as Maybe import Data.Monoid (mempty) +import Data.Ord (Down(..)) import Data.Proxy (Proxy(..)) import Data.List.NonEmpty (NonEmpty(..)) import qualified Data.List.NonEmpty as NE @@ -20,6 +22,7 @@ import Test.Tasty.HUnit import Test.Tasty.QuickCheck hiding ((.&.)) import qualified Test.QuickCheck.Classes.Base as Laws +import Utils.QuickCheck (NubSorted(..)) import Utils.QuickCheckClasses (testLaws) main :: IO () @@ -567,31 +570,32 @@ prop_deleteMin s = toList (deleteMin s) === if null s then [] else tail (toList prop_deleteMax :: IntSet -> Property prop_deleteMax s = toList (deleteMax s) === if null s then [] else init (toList s) -prop_fromAscList :: [Int] -> Property -prop_fromAscList xs = +prop_fromAscList :: SortedList Int -> Property +prop_fromAscList (Sorted xs) = valid t .&&. - toList t === nubSortedXs + t === fromList xs .&&. + toList t === nubXs where - sortedXs = sort xs - nubSortedXs = List.map NE.head $ NE.group sortedXs - t = fromAscList sortedXs + nubXs = List.map NE.head $ NE.group xs + t = fromAscList xs -prop_fromDistinctAscList :: [Int] -> Property -prop_fromDistinctAscList xs = +prop_fromDistinctAscList :: NubSorted Int -> Property +prop_fromDistinctAscList (NubSorted xs) = valid t .&&. - toList t === nubSortedXs + t === fromList xs .&&. + toList t === xs where - nubSortedXs = List.map NE.head $ NE.group $ sort xs - t = fromDistinctAscList nubSortedXs + t = fromDistinctAscList xs -prop_fromDescList :: [Int] -> Property -prop_fromDescList xs = +prop_fromDescList :: SortedList (Down Int) -> Property +prop_fromDescList xs' = valid t .&&. - toList t === nubSortedXs + t === fromList xs .&&. + toList t === reverse nubXs where - sortedXs = sort xs - nubSortedXs = List.map NE.head $ NE.group sortedXs - t = fromDescList (reverse sortedXs) + xs = coerce xs' :: [Int] + nubXs = List.map NE.head $ NE.group xs + t = fromDescList xs prop_compareSize :: IntSet -> Int -> Property prop_compareSize t c = compareSize t c === compare (size t) c diff --git a/containers-tests/tests/intset-strictness.hs b/containers-tests/tests/intset-strictness.hs index ad4a5bab5..b85523b97 100644 --- a/containers-tests/tests/intset-strictness.hs +++ b/containers-tests/tests/intset-strictness.hs @@ -12,7 +12,7 @@ import Test.QuickCheck.Poly (B) import Data.IntSet (IntSet) import qualified Data.IntSet as S -import Utils.NubSorted (NubSorted(..)) +import Utils.QuickCheck (NubSorted(..)) import Utils.Strictness (Bot(..), Func2, applyFunc2) ------------------------------------------------------------------------ diff --git a/containers-tests/tests/map-properties.hs b/containers-tests/tests/map-properties.hs index 03ead57d2..039e8c1fd 100644 --- a/containers-tests/tests/map-properties.hs +++ b/containers-tests/tests/map-properties.hs @@ -17,6 +17,7 @@ import Control.Monad.Trans.State.Strict import Control.Monad.Trans.Class import Control.Monad.Trans.Writer.Lazy import Control.Monad ((<=<)) +import Data.Coerce (coerce) import qualified Data.Either as Either import Data.Functor.Identity (Identity(Identity, runIdentity)) import Data.Monoid @@ -34,8 +35,6 @@ import qualified Prelude import Data.List (nub,sort) import qualified Data.List as List -import Data.List.NonEmpty (NonEmpty(..)) -import qualified Data.List.NonEmpty as NE import qualified Data.Set as Set import Test.Tasty @@ -46,6 +45,7 @@ import Test.QuickCheck.Poly (A, B, C, OrdA) import qualified Test.QuickCheck.Classes.Base as Laws import Utils.ArbitrarySetMap (mkArbMap) +import Utils.QuickCheck (NubSortedOnFst(..), SortedOnFst(..)) import Utils.QuickCheckClasses (testLaws) default (Int) @@ -1386,48 +1386,48 @@ prop_list xs = (sort (nub xs) == [x | (x,()) <- toList (fromList [(x,()) | x <- prop_descList :: [Int] -> Bool prop_descList xs = (reverse (sort (nub xs)) == [x | (x,()) <- toDescList (fromList [(x,()) | x <- xs])]) -prop_fromDescList :: [(Int, A)] -> Property -prop_fromDescList kxs = +prop_fromDescList :: SortedOnFst (Down Int) A -> Property +prop_fromDescList kxs' = valid t .&&. t === fromList kxs where - downSortedKxs = List.sortBy (comparing (Down . fst)) kxs - t = fromDescList downSortedKxs + kxs = coerce kxs' :: [(Int, A)] + t = fromDescList kxs -prop_fromDescListWith :: Fun (A, A) A -> [(Int, A)] -> Property -prop_fromDescListWith f kxs = +prop_fromDescListWith :: Fun (A, A) A -> SortedOnFst (Down Int) A -> Property +prop_fromDescListWith f kxs' = valid t .&&. - t === fromListWith (apply2 f) downSortedKxs + t === fromListWith (applyFun2 f) kxs where - downSortedKxs = List.sortBy (comparing (Down . fst)) kxs - t = fromDescListWith (apply2 f) downSortedKxs + kxs = coerce kxs' :: [(Int, A)] + t = fromDescListWith (applyFun2 f) kxs -prop_fromDescListWithKey :: Fun (Int, A, A) A -> [(Int, A)] -> Property -prop_fromDescListWithKey f kxs = +prop_fromDescListWithKey + :: Fun (Int, A, A) A -> SortedOnFst (Down Int) A -> Property +prop_fromDescListWithKey f kxs' = valid t .&&. - t === fromListWithKey (apply3 f) downSortedKxs + t === fromListWithKey (applyFun3 f) kxs where - downSortedKxs = List.sortBy (comparing (Down . fst)) kxs - t = fromDescListWithKey (apply3 f) downSortedKxs + kxs = coerce kxs' :: [(Int, A)] + t = fromDescListWithKey (applyFun3 f) kxs -prop_fromDistinctDescList :: [(Int, A)] -> Property -prop_fromDistinctDescList kxs = +prop_fromDistinctDescList :: NubSortedOnFst (Down Int) A -> Property +prop_fromDistinctDescList kxs' = valid t .&&. - toList t === reverse nubDownSortedKxs + t === fromList kxs .&&. + toList t === reverse kxs where - nubDownSortedKxs = - List.map NE.head $ - NE.groupBy ((==) `on` fst) $ - List.sortBy (comparing (Down . fst)) kxs - t = fromDistinctDescList nubDownSortedKxs + kxs = coerce kxs' :: [(Int, A)] + t = fromDistinctDescList kxs -prop_fromDescListUpsert :: Fun (A, Maybe B) B -> [(Int, A)] -> Property -prop_fromDescListUpsert f kxs = +prop_fromDescListUpsert + :: Fun (A, Maybe B) B -> SortedOnFst (Down Int) A -> Property +prop_fromDescListUpsert f kxs' = valid t .&&. - t === fromListUpsert (applyFun2 f) downSortedKxs + t === fromListUpsert (applyFun2 f) kxs where - downSortedKxs = List.sortBy (comparing (Down . fst)) kxs - t = fromDescListUpsert (applyFun2 f) downSortedKxs + kxs = coerce kxs' :: [(Int, A)] + t = fromDescListUpsert (applyFun2 f) kxs prop_ascDescList :: [Int] -> Bool prop_ascDescList xs = toAscList m == reverse (toDescList m) @@ -1440,48 +1440,41 @@ prop_fromList xs t == List.foldr (uncurry insert) empty (zip xs xs) where sort_xs = sort xs -prop_fromAscList :: [(Int, A)] -> Property -prop_fromAscList kxs = +prop_fromAscList :: SortedOnFst Int A -> Property +prop_fromAscList (SortedOnFst kxs) = valid t .&&. - t === fromList sortedKxs + t === fromList kxs where - sortedKxs = List.sortBy (comparing fst) kxs - t = fromAscList sortedKxs + t = fromAscList kxs -prop_fromAscListWith :: Fun (A, A) A -> [(Int, A)] -> Property -prop_fromAscListWith f kxs = +prop_fromAscListWith :: Fun (A, A) A -> SortedOnFst Int A -> Property +prop_fromAscListWith f (SortedOnFst kxs) = valid t .&&. - t === fromListWith (apply2 f) sortedKxs + t === fromListWith (applyFun2 f) kxs where - sortedKxs = List.sortBy (comparing fst) kxs - t = fromAscListWith (apply2 f) sortedKxs + t = fromAscListWith (applyFun2 f) kxs -prop_fromAscListWithKey :: Fun (Int, A, A) A -> [(Int, A)] -> Property -prop_fromAscListWithKey f kxs = +prop_fromAscListWithKey :: Fun (Int, A, A) A -> SortedOnFst Int A -> Property +prop_fromAscListWithKey f (SortedOnFst kxs) = valid t .&&. - t === fromListWithKey (apply3 f) sortedKxs + t === fromListWithKey (applyFun3 f) kxs where - sortedKxs = List.sortBy (comparing fst) kxs - t = fromAscListWithKey (apply3 f) sortedKxs + t = fromAscListWithKey (applyFun3 f) kxs -prop_fromAscListUpsert :: Fun (A, Maybe B) B -> [(Int, A)] -> Property -prop_fromAscListUpsert f kxs = +prop_fromAscListUpsert :: Fun (A, Maybe B) B -> SortedOnFst Int A -> Property +prop_fromAscListUpsert f (SortedOnFst kxs) = valid t .&&. - t === fromListUpsert (applyFun2 f) sortedKxs + t === fromListUpsert (applyFun2 f) kxs where - sortedKxs = List.sortBy (comparing fst) kxs - t = fromAscListUpsert (applyFun2 f) sortedKxs + t = fromAscListUpsert (applyFun2 f) kxs -prop_fromDistinctAscList :: [(Int, A)] -> Property -prop_fromDistinctAscList kxs = +prop_fromDistinctAscList :: NubSortedOnFst Int A -> Property +prop_fromDistinctAscList (NubSortedOnFst kxs) = valid t .&&. - toList t === nubSortedKxs + t === fromList kxs .&&. + toList t === kxs where - nubSortedKxs = - List.map NE.head $ - NE.groupBy ((==) `on` fst) $ - List.sortBy (comparing fst) kxs - t = fromDistinctAscList nubSortedKxs + t = fromDistinctAscList kxs prop_fromListWith :: Fun (A, A) A -> [(Int, A)] -> Property prop_fromListWith f kxs = diff --git a/containers-tests/tests/map-strictness.hs b/containers-tests/tests/map-strictness.hs index ee2c5b559..ee94b8ba9 100644 --- a/containers-tests/tests/map-strictness.hs +++ b/containers-tests/tests/map-strictness.hs @@ -12,8 +12,7 @@ import Data.Function (on) import Data.Functor.Compose (Compose (..)) import Data.Functor.Identity (Identity(..)) import qualified Data.List as List -import qualified Data.List.NonEmpty as NE -import Data.Ord (Down(..), comparing) +import Data.Ord (Down(..)) import Data.Maybe (catMaybes, mapMaybe) import Data.Semigroup (Arg(..)) #if __GLASGOW_HASKELL__ < 908 @@ -39,7 +38,7 @@ import Data.Set (Set) import qualified Data.Set as Set import Utils.ArbitrarySetMap (setFromList, mapFromKeysList) -import Utils.NubSorted (NubSorted(..), NubSortedOnFst(..)) +import Utils.QuickCheck (NubSorted(..), NubSortedOnFst(..), SortedOnFst(..)) import Utils.MergeFunc (WhenMatchedFunc(..), WhenMissingFunc(..)) import Utils.Strictness (Bot(..), Func, Func2, Func3, applyFunc, applyFunc2, applyFunc3) @@ -242,146 +241,147 @@ prop_lazyFromListUpsert fun kvs = isNotBottomProp (L.fromListUpsert f kvs') f = coerce (applyFunc2 fun) :: A -> Maybe B -> B kvs' = coerce kvs :: [(OrdA, A)] -prop_strictFromAscList :: [(OrdA, Bot A)] -> Property +prop_strictFromAscList :: SortedOnFst OrdA (Bot A) -> Property prop_strictFromAscList kvs = isBottom (M.fromAscList kvs') === isBottom (M.fromList kvs') where - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] -prop_lazyFromAscList :: [(OrdA, Bot A)] -> Property +prop_lazyFromAscList :: SortedOnFst OrdA (Bot A) -> Property prop_lazyFromAscList kvs = isNotBottomProp (L.fromAscList kvs') where - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] -prop_strictFromAscListWith :: Func2 A A (Bot A) -> [(OrdA, Bot A)] -> Property +prop_strictFromAscListWith + :: Func2 A A (Bot A) -> SortedOnFst OrdA (Bot A) -> Property prop_strictFromAscListWith fun kvs = isBottom (M.fromAscListWith f kvs') === isBottom (M.fromListWith f kvs') where f = coerce (applyFunc2 fun) - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] -prop_lazyFromAscListWith :: Func2 A A (Bot A) -> [(OrdA, Bot A)] -> Property +prop_lazyFromAscListWith + :: Func2 A A (Bot A) -> SortedOnFst OrdA (Bot A) -> Property prop_lazyFromAscListWith fun kvs = isNotBottomProp (L.fromAscListWith f kvs') where f = coerce (applyFunc2 fun) - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] prop_strictFromAscListWithKey - :: Func3 OrdA A A (Bot A) -> [(OrdA, Bot A)] -> Property + :: Func3 OrdA A A (Bot A) -> SortedOnFst OrdA (Bot A) -> Property prop_strictFromAscListWithKey fun kvs = isBottom (M.fromAscListWithKey f kvs') === isBottom (M.fromListWithKey f kvs') where f = coerce (applyFunc3 fun) - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] prop_lazyFromAscListWithKey - :: Func3 OrdA A A (Bot A) -> [(OrdA, Bot A)] -> Property + :: Func3 OrdA A A (Bot A) -> SortedOnFst OrdA (Bot A) -> Property prop_lazyFromAscListWithKey fun kvs = isNotBottomProp (L.fromAscListWithKey f kvs') where f = coerce (applyFunc3 fun) - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] prop_strictFromAscListUpsert - :: Func2 A (Maybe B) (Bot B) -> [(OrdA, Bot A)] -> Property + :: Func2 A (Maybe B) (Bot B) -> SortedOnFst OrdA (Bot A) -> Property prop_strictFromAscListUpsert fun kvs = isBottom (M.fromAscListUpsert f kvs') === isBottom (M.fromListUpsert f kvs') where f = coerce (applyFunc2 fun) :: A -> Maybe B -> B - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] prop_lazyFromAscListUpsert - :: Func2 A (Maybe B) (Bot B) -> [(OrdA, Bot A)] -> Property + :: Func2 A (Maybe B) (Bot B) -> SortedOnFst OrdA (Bot A) -> Property prop_lazyFromAscListUpsert fun kvs = isNotBottomProp (L.fromAscListUpsert f kvs') where f = coerce (applyFunc2 fun) :: A -> Maybe B -> B - kvs' = List.sortBy (comparing fst) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] -prop_strictFromDistinctAscList :: [(OrdA, Bot A)] -> Property +prop_strictFromDistinctAscList :: NubSortedOnFst OrdA (Bot A) -> Property prop_strictFromDistinctAscList kvs = isBottom (M.fromDistinctAscList kvs') === isBottom (M.fromList kvs') where - kvs' = uniqOn fst $ List.sortBy (comparing fst) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] -prop_lazyFromDistinctAscList :: [(OrdA, Bot A)] -> Property +prop_lazyFromDistinctAscList :: NubSortedOnFst OrdA (Bot A) -> Property prop_lazyFromDistinctAscList kvs = isNotBottomProp (L.fromDistinctAscList kvs') where - kvs' = uniqOn fst $ List.sortBy (comparing fst) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] -prop_strictFromDescList :: [(OrdA, Bot A)] -> Property +prop_strictFromDescList :: SortedOnFst (Down OrdA) (Bot A) -> Property prop_strictFromDescList kvs = isBottom (M.fromDescList kvs') === isBottom (M.fromList kvs') where - kvs' = List.sortBy (comparing (Down . fst)) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] -prop_lazyFromDescList :: [(OrdA, Bot A)] -> Property +prop_lazyFromDescList :: SortedOnFst (Down OrdA) (Bot A) -> Property prop_lazyFromDescList kvs = isNotBottomProp (L.fromDescList kvs') where - kvs' = List.sortBy (comparing (Down . fst)) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] -prop_strictFromDescListWith :: Func2 A A (Bot A) -> [(OrdA, Bot A)] -> Property +prop_strictFromDescListWith + :: Func2 A A (Bot A) -> SortedOnFst (Down OrdA) (Bot A) -> Property prop_strictFromDescListWith fun kvs = isBottom (M.fromDescListWith f kvs') === isBottom (M.fromListWith f kvs') where f = coerce (applyFunc2 fun) - kvs' = List.sortBy (comparing (Down . fst)) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] -prop_lazyFromDescListWith :: Func2 A A (Bot A) -> [(OrdA, Bot A)] -> Property +prop_lazyFromDescListWith + :: Func2 A A (Bot A) -> SortedOnFst (Down OrdA) (Bot A) -> Property prop_lazyFromDescListWith fun kvs = isNotBottomProp (L.fromDescListWith f kvs') where f = coerce (applyFunc2 fun) - kvs' = List.sortBy (comparing (Down . fst)) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] prop_strictFromDescListWithKey - :: Func3 OrdA A A (Bot A) -> [(OrdA, Bot A)] -> Property + :: Func3 OrdA A A (Bot A) -> SortedOnFst (Down OrdA) (Bot A) -> Property prop_strictFromDescListWithKey fun kvs = isBottom (M.fromDescListWithKey f kvs') === isBottom (M.fromListWithKey f kvs') where f = coerce (applyFunc3 fun) - kvs' = List.sortBy (comparing (Down . fst)) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] prop_lazyFromDescListWithKey - :: Func3 OrdA A A (Bot A) -> [(OrdA, Bot A)] -> Property + :: Func3 OrdA A A (Bot A) -> SortedOnFst (Down OrdA) (Bot A) -> Property prop_lazyFromDescListWithKey fun kvs = isNotBottomProp (L.fromDescListWithKey f kvs') where f = coerce (applyFunc3 fun) - kvs' = List.sortBy (comparing (Down . fst)) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] prop_strictFromDescListUpsert - :: Func2 A (Maybe B) (Bot B) -> [(OrdA, Bot A)] -> Property + :: Func2 A (Maybe B) (Bot B) -> SortedOnFst (Down OrdA) (Bot A) -> Property prop_strictFromDescListUpsert fun kvs = isBottom (M.fromDescListUpsert f kvs') === isBottom (M.fromListUpsert f kvs') where f = coerce (applyFunc2 fun) :: A -> Maybe B -> B - kvs' = List.sortBy (comparing (Down . fst)) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] prop_lazyFromDescListUpsert - :: Func2 A (Maybe B) (Bot B) -> [(OrdA, Bot A)] -> Property + :: Func2 A (Maybe B) (Bot B) -> SortedOnFst (Down OrdA) (Bot A) -> Property prop_lazyFromDescListUpsert fun kvs = isNotBottomProp (L.fromDescListUpsert f kvs') where f = coerce (applyFunc2 fun) :: A -> Maybe B -> B - kvs' = List.sortBy (comparing (Down . fst)) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] -prop_strictFromDistinctDescList :: [(OrdA, Bot A)] -> Property +prop_strictFromDistinctDescList + :: NubSortedOnFst (Down OrdA) (Bot A) -> Property prop_strictFromDistinctDescList kvs = isBottom (M.fromDistinctDescList kvs') === isBottom (M.fromList kvs') where - kvs' = - uniqOn fst $ - List.sortBy (comparing (Down . fst)) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] -prop_lazyFromDistinctDescList :: [(OrdA, Bot A)] -> Property +prop_lazyFromDistinctDescList :: NubSortedOnFst (Down OrdA) (Bot A) -> Property prop_lazyFromDistinctDescList kvs = isNotBottomProp (L.fromDistinctDescList kvs') where - kvs' = - uniqOn fst $ - List.sortBy (comparing (Down . fst)) (coerce kvs) :: [(OrdA, A)] + kvs' = coerce kvs :: [(OrdA, A)] prop_strictInsert :: OrdA -> Bot A -> Map OrdA A -> Property prop_strictInsert k (Bot x) m = isBottom (M.insert k x m) === isBottom x @@ -1318,10 +1318,6 @@ const2 x _ _ = x const3 :: a -> b -> c -> d -> a const3 x _ _ _ = x --- | Keep the first of adjacent equal elements. -uniqOn :: Eq b => (a -> b) -> [a] -> [a] -uniqOn f = map NE.head . NE.groupBy ((==) `on` f) - {-------------------------------------------------------------------- Merge stuff --------------------------------------------------------------------} diff --git a/containers-tests/tests/set-properties.hs b/containers-tests/tests/set-properties.hs index d1a02e380..63c1e9da5 100644 --- a/containers-tests/tests/set-properties.hs +++ b/containers-tests/tests/set-properties.hs @@ -1,6 +1,7 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} import qualified Data.IntSet as IntSet +import Data.Coerce (coerce) import Data.List (nub, sort, sortBy) import qualified Data.List as List import Data.Maybe (isJust, fromJust) @@ -25,6 +26,7 @@ import Data.List.NonEmpty (NonEmpty(..)) import qualified Data.List.NonEmpty as NE import Utils.ArbitrarySetMap (mkArbSet, setFromList) +import Utils.QuickCheck (NubSorted(..)) import Utils.QuickCheckClasses (testLaws) main :: IO () @@ -509,39 +511,41 @@ prop_fromList xs = t === List.foldr insert empty xs where t = fromList xs -prop_fromAscList :: [Int] -> Property -prop_fromAscList xs = +prop_fromAscList :: SortedList Int -> Property +prop_fromAscList (Sorted xs) = valid t .&&. - toList t === nubSortedXs + t === fromList xs .&&. + toList t === nubXs where - sortedXs = sort xs - nubSortedXs = List.map NE.head $ NE.group sortedXs - t = fromAscList sortedXs + nubXs = List.map NE.head $ NE.group xs + t = fromAscList xs -prop_fromDistinctAscList :: [Int] -> Property -prop_fromDistinctAscList xs = +prop_fromDistinctAscList :: NubSorted Int -> Property +prop_fromDistinctAscList (NubSorted xs) = valid t .&&. - toList t === nubSortedXs + t === fromList xs .&&. + toList t === xs where - nubSortedXs = List.map NE.head $ NE.group $ sort xs - t = fromDistinctAscList nubSortedXs + t = fromDistinctAscList xs -prop_fromDescList :: [Int] -> Property -prop_fromDescList xs = +prop_fromDescList :: SortedList (Down Int) -> Property +prop_fromDescList xs' = valid t .&&. - toList t === reverse nubDownSortedXs + t === fromList xs .&&. + toList t === reverse nubXs where - downSortedXs = sortBy (comparing Down) xs - nubDownSortedXs = List.map NE.head $ NE.group downSortedXs - t = fromDescList downSortedXs + xs = coerce xs' :: [Int] + nubXs = List.map NE.head $ NE.group xs + t = fromDescList xs -prop_fromDistinctDescList :: [Int] -> Property -prop_fromDistinctDescList xs = +prop_fromDistinctDescList :: NubSorted (Down Int) -> Property +prop_fromDistinctDescList xs' = valid t .&&. - toList t === reverse nubDownSortedXs + t === fromList xs .&&. + toList t === reverse xs where - nubDownSortedXs = List.map NE.head $ NE.group $ sortBy (comparing Down) xs - t = fromDistinctDescList nubDownSortedXs + xs = coerce xs' :: [Int] + t = fromDistinctDescList xs {-------------------------------------------------------------------- Set operations are like IntSet operations diff --git a/containers-tests/tests/set-strictness.hs b/containers-tests/tests/set-strictness.hs index 642ec4ca8..b2f9bcb91 100644 --- a/containers-tests/tests/set-strictness.hs +++ b/containers-tests/tests/set-strictness.hs @@ -12,7 +12,7 @@ import Data.Set (Set) import qualified Data.Set as S import Utils.ArbitrarySetMap (setFromList) -import Utils.NubSorted (NubSorted(..)) +import Utils.QuickCheck (NubSorted(..)) import Utils.Strictness (Bot(..), Func2, applyFunc2) ------------------------------------------------------------------------