nonempty-vector-0.3: test/Test/Data/Vector/NonEmpty/Elementwise.hs
-- |
-- Module : Test.Data.Vector.NonEmpty.Elementwise
-- Copyright : (c) 2019-2026 Emily Pillmore
-- License : BSD-style
--
-- Maintainer : Emily Pillmore <emilypi@cohomolo.gy>
-- Stability : experimental
-- Portability : non-portable
--
-- Properties for indexing, mapping, zipping, and unzipping.
--
-- Monadic operations run in a writer-style @([w], -)@ monad so that the
-- order and number of effects are observable.
--
module Test.Data.Vector.NonEmpty.Elementwise
( tests
) where
import qualified Data.List as List
import Data.Vector.NonEmpty (NonEmptyVector)
import qualified Data.Vector.NonEmpty as NEV
import Test.Data.Vector.NonEmpty.Util
import Test.QuickCheck
import Test.Tasty
import Test.Tasty.QuickCheck
tests :: TestTree
tests = testGroup "Elementwise"
[ testGroup "Indexing"
[ testProperty "prop_indexed" prop_indexed
]
, testGroup "Mapping"
[ testProperty "prop_map" prop_map
, testProperty "prop_imap" prop_imap
, testProperty "prop_concatMap" prop_concatMap
]
, testGroup "Monadic mapping"
[ testProperty "prop_mapM" prop_mapM
, testProperty "prop_imapM" prop_imapM
, testProperty "prop_mapM_" prop_mapM_
, testProperty "prop_imapM_" prop_imapM_
, testProperty "prop_forM" prop_forM
, testProperty "prop_forM_" prop_forM_
]
, testGroup "Zipping"
[ testProperty "prop_zipWith" prop_zipWith
, testProperty "prop_zipWith3" prop_zipWith3
, testProperty "prop_zipWith4" prop_zipWith4
, testProperty "prop_zipWith5" prop_zipWith5
, testProperty "prop_zipWith6" prop_zipWith6
, testProperty "prop_izipWith" prop_izipWith
, testProperty "prop_izipWith3" prop_izipWith3
, testProperty "prop_izipWith4" prop_izipWith4
, testProperty "prop_izipWith5" prop_izipWith5
, testProperty "prop_izipWith6" prop_izipWith6
, testProperty "prop_zip" prop_zip
, testProperty "prop_zip3" prop_zip3
, testProperty "prop_zip4" prop_zip4
, testProperty "prop_zip5" prop_zip5
, testProperty "prop_zip6" prop_zip6
]
, testGroup "Monadic zipping"
[ testProperty "prop_zipWithM" prop_zipWithM
, testProperty "prop_zipWithM_" prop_zipWithM_
, testProperty "prop_izipWithM" prop_izipWithM
, testProperty "prop_izipWithM_" prop_izipWithM_
]
, testGroup "Unzipping"
[ testProperty "prop_unzip" prop_unzip
, testProperty "prop_unzip3" prop_unzip3
, testProperty "prop_unzip4" prop_unzip4
, testProperty "prop_unzip5" prop_unzip5
, testProperty "prop_unzip6" prop_unzip6
]
]
type V = NonEmptyVector Int
-- ---------------------------------------------------------------------- --
-- Indexing
prop_indexed :: V -> Property
prop_indexed v = elems (NEV.indexed v) === List.zip [0 ..] (elems v)
-- ---------------------------------------------------------------------- --
-- Mapping
prop_map :: Fun Int Int -> V -> Property
prop_map (Fn f) v = elems (NEV.map f v) === List.map f (elems v)
prop_imap :: Fun (Int, Int) Int -> V -> Property
prop_imap (Fn2 f) v = elems (NEV.imap f v) === List.zipWith f [0 ..] (elems v)
prop_concatMap :: Fun Int V -> V -> Property
prop_concatMap (Fn f) v =
elems (NEV.concatMap f v) === List.concatMap (elems . f) (elems v)
-- ---------------------------------------------------------------------- --
-- Monadic mapping
prop_mapM :: Fun Int Int -> V -> Property
prop_mapM (Fn f) v =
fmap elems (NEV.mapM (\a -> logged a (f a)) v)
=== (elems v, List.map f (elems v))
prop_imapM :: Fun (Int, Int) Int -> V -> Property
prop_imapM (Fn2 f) v =
fmap elems (NEV.imapM (\i a -> logged i (f i a)) v)
=== (is, List.zipWith f is (elems v))
where
is = [0 .. NEV.length v - 1]
prop_mapM_ :: V -> Property
prop_mapM_ v = NEV.mapM_ (\a -> logged a a) v === (elems v, ())
prop_imapM_ :: V -> Property
prop_imapM_ v =
NEV.imapM_ (\i a -> logged (i, a) a) v
=== (List.zip [0 ..] (elems v), ())
prop_forM :: Fun Int Int -> V -> Property
prop_forM (Fn f) v =
fmap elems (NEV.forM v (\a -> logged a (f a)))
=== (elems v, List.map f (elems v))
prop_forM_ :: V -> Property
prop_forM_ v = NEV.forM_ v (\a -> logged a a) === (elems v, ())
-- ---------------------------------------------------------------------- --
-- Zipping
--
-- The higher arities collect their arguments in order, so the models
-- detect both truncation to the shortest input and argument order.
prop_zipWith :: Fun (Int, Int) Int -> V -> V -> Property
prop_zipWith (Fn2 f) a b =
elems (NEV.zipWith f a b) === List.zipWith f (elems a) (elems b)
prop_zipWith3 :: Fun (Int, Int, Int) Int -> V -> V -> V -> Property
prop_zipWith3 (Fn3 f) a b c =
elems (NEV.zipWith3 f a b c)
=== List.zipWith3 f (elems a) (elems b) (elems c)
prop_zipWith4 :: V -> V -> V -> V -> Property
prop_zipWith4 a b c d =
elems (NEV.zipWith4 k a b c d)
=== List.zipWith4 k (elems a) (elems b) (elems c) (elems d)
where
k p q r s = [p, q, r, s]
prop_zipWith5 :: V -> V -> V -> V -> V -> Property
prop_zipWith5 a b c d e =
elems (NEV.zipWith5 k a b c d e)
=== List.zipWith5 k (elems a) (elems b) (elems c) (elems d) (elems e)
where
k p q r s t = [p, q, r, s, t]
prop_zipWith6 :: V -> V -> V -> V -> V -> V -> Property
prop_zipWith6 a b c d e f =
elems (NEV.zipWith6 k a b c d e f)
=== List.zipWith6 k
(elems a) (elems b) (elems c) (elems d) (elems e) (elems f)
where
k p q r s t u = [p, q, r, s, t, u]
prop_izipWith :: V -> V -> Property
prop_izipWith a b =
elems (NEV.izipWith k a b) === List.zipWith3 k [0 ..] (elems a) (elems b)
where
k i p q = [i, p, q]
prop_izipWith3 :: V -> V -> V -> Property
prop_izipWith3 a b c =
elems (NEV.izipWith3 k a b c)
=== List.zipWith4 k [0 ..] (elems a) (elems b) (elems c)
where
k i p q r = [i, p, q, r]
prop_izipWith4 :: V -> V -> V -> V -> Property
prop_izipWith4 a b c d =
elems (NEV.izipWith4 k a b c d)
=== List.zipWith5 k [0 ..] (elems a) (elems b) (elems c) (elems d)
where
k i p q r s = [i, p, q, r, s]
prop_izipWith5 :: V -> V -> V -> V -> V -> Property
prop_izipWith5 a b c d e =
elems (NEV.izipWith5 k a b c d e)
=== List.zipWith6 k [0 ..]
(elems a) (elems b) (elems c) (elems d) (elems e)
where
k i p q r s t = [i, p, q, r, s, t]
prop_izipWith6 :: V -> V -> V -> V -> V -> V -> Property
prop_izipWith6 a b c d e f =
elems (NEV.izipWith6 k a b c d e f)
=== List.zipWith7 k [0 ..]
(elems a) (elems b) (elems c) (elems d) (elems e) (elems f)
where
k i p q r s t u = [i, p, q, r, s, t, u]
prop_zip :: V -> V -> Property
prop_zip a b = elems (NEV.zip a b) === List.zip (elems a) (elems b)
prop_zip3 :: V -> V -> V -> Property
prop_zip3 a b c =
elems (NEV.zip3 a b c) === List.zip3 (elems a) (elems b) (elems c)
prop_zip4 :: V -> V -> V -> V -> Property
prop_zip4 a b c d =
elems (NEV.zip4 a b c d)
=== List.zip4 (elems a) (elems b) (elems c) (elems d)
prop_zip5 :: V -> V -> V -> V -> V -> Property
prop_zip5 a b c d e =
elems (NEV.zip5 a b c d e)
=== List.zip5 (elems a) (elems b) (elems c) (elems d) (elems e)
prop_zip6 :: V -> V -> V -> V -> V -> V -> Property
prop_zip6 a b c d e f =
elems (NEV.zip6 a b c d e f)
=== List.zip6 (elems a) (elems b) (elems c) (elems d) (elems e) (elems f)
-- ---------------------------------------------------------------------- --
-- Monadic zipping
prop_zipWithM :: Fun (Int, Int) Int -> V -> V -> Property
prop_zipWithM (Fn2 f) a b =
fmap elems (NEV.zipWithM (\p q -> logged (p, q) (f p q)) a b)
=== (ps, List.map (uncurry f) ps)
where
ps = List.zip (elems a) (elems b)
prop_zipWithM_ :: V -> V -> Property
prop_zipWithM_ a b =
NEV.zipWithM_ (\p q -> logged (p, q) p) a b
=== (List.zip (elems a) (elems b), ())
prop_izipWithM :: Fun (Int, Int, Int) Int -> V -> V -> Property
prop_izipWithM (Fn3 f) a b =
fmap elems (NEV.izipWithM (\i p q -> logged i (f i p q)) a b)
=== (List.map fst ips, List.map (\(i, (p, q)) -> f i p q) ips)
where
ips = List.zip [0 ..] (List.zip (elems a) (elems b))
prop_izipWithM_ :: V -> V -> Property
prop_izipWithM_ a b =
NEV.izipWithM_ (\i p q -> logged (i, p, q) p) a b
=== (List.zip3 [0 ..] (elems a) (elems b), ())
-- ---------------------------------------------------------------------- --
-- Unzipping
prop_unzip :: NonEmptyVector (Int, Int) -> Property
prop_unzip v = (elems a, elems b) === List.unzip (elems v)
where
(a, b) = NEV.unzip v
prop_unzip3 :: NonEmptyVector (Int, Int, Int) -> Property
prop_unzip3 v = (elems a, elems b, elems c) === List.unzip3 (elems v)
where
(a, b, c) = NEV.unzip3 v
prop_unzip4 :: NonEmptyVector (Int, Int, Int, Int) -> Property
prop_unzip4 v =
(elems a, elems b, elems c, elems d) === List.unzip4 (elems v)
where
(a, b, c, d) = NEV.unzip4 v
prop_unzip5 :: NonEmptyVector (Int, Int, Int, Int, Int) -> Property
prop_unzip5 v =
(elems a, elems b, elems c, elems d, elems e) === List.unzip5 (elems v)
where
(a, b, c, d, e) = NEV.unzip5 v
prop_unzip6 :: NonEmptyVector (Int, Int, Int, Int, Int, Int) -> Property
prop_unzip6 v =
(elems a, elems b, elems c, elems d, elems e, elems f)
=== List.unzip6 (elems v)
where
(a, b, c, d, e, f) = NEV.unzip6 v