1{-# LANGUAGE ConstraintKinds #-}
2module Tests.Vector.Property
3  ( CommonContext
4  , VanillaContext
5  , VectorContext
6  , testSanity
7  , testPolymorphicFunctions
8  , testTuplyFunctions
9  , testOrdFunctions
10  , testEnumFunctions
11  , testMonoidFunctions
12  , testFunctorFunctions
13  , testMonadFunctions
14  , testApplicativeFunctions
15  , testAlternativeFunctions
16  , testSequenceFunctions
17  , testBoolFunctions
18  , testNumFunctions
19  , testNestedVectorFunctions
20  , testDataFunctions
21  -- re-exports
22  , Data
23  , Random
24  , Test
25  ) where
26
27import Boilerplater
28import Utilities as Util hiding (limitUnfolds)
29
30import Control.Monad
31import Data.Functor.Identity
32import qualified Data.Traversable as T (Traversable(..))
33import Data.Foldable (Foldable(foldMap))
34import Data.Orphans ()
35
36import qualified Data.Vector.Generic as V
37import qualified Data.Vector.Fusion.Bundle as S
38
39import Test.QuickCheck
40
41import Test.Tasty
42import Test.Tasty.QuickCheck hiding (testProperties)
43
44import Text.Show.Functions ()
45import Data.List
46
47import Data.Monoid
48
49import qualified Control.Applicative as Applicative
50import System.Random       (Random)
51
52import Data.Functor.Identity
53import Control.Monad.Trans.Writer
54
55import Control.Monad.Zip
56
57import Data.Data
58
59import qualified Data.List.NonEmpty as DLE
60import Data.Semigroup (Semigroup(..))
61
62type CommonContext  a v = (VanillaContext a, VectorContext a v)
63type VanillaContext a   = ( Eq a , Show a, Arbitrary a, CoArbitrary a
64                          , TestData a, Model a ~ a, EqTest a ~ Property)
65type VectorContext  a v = ( Eq (v a), Show (v a), Arbitrary (v a), CoArbitrary (v a)
66                          , TestData (v a), Model (v a) ~ [a],  EqTest (v a) ~ Property, V.Vector v a)
67
68-- | migration hack for moving from TestFramework to Tasty
69type Test = TestTree
70-- TODO: implement Vector equivalents of list functions for some of the commented out properties
71
72-- TODO: add tests for the other extra functions
73-- IVector exports still needing tests:
74--  copy,
75--  new,
76--  unsafeSlice, unsafeIndex,
77
78testSanity :: forall a v. (CommonContext a v) => v a -> [Test]
79{-# INLINE testSanity #-}
80testSanity _ = [
81        testProperty "fromList.toList == id" prop_fromList_toList,
82        testProperty "toList.fromList == id" prop_toList_fromList,
83        testProperty "unstream.stream == id" prop_unstream_stream,
84        testProperty "stream.unstream == id" prop_stream_unstream
85    ]
86  where
87    prop_fromList_toList (v :: v a)        = (V.fromList . V.toList)                        v == v
88    prop_toList_fromList (l :: [a])        = ((V.toList :: v a -> [a]) . V.fromList)        l == l
89    prop_unstream_stream (v :: v a)        = (V.unstream . V.stream)                        v == v
90    prop_stream_unstream (s :: S.Bundle v a) = ((V.stream :: v a -> S.Bundle v a) . V.unstream) s == s
91
92testPolymorphicFunctions :: forall a v. (CommonContext a v, VectorContext Int v) => v a -> [Test]
93-- FIXME: inlining of unboxed properties blows up the memory during compilation. See #272
94--{-# INLINE testPolymorphicFunctions #-}
95testPolymorphicFunctions _ = $(testProperties [
96        'prop_eq,
97
98        -- Length information
99        'prop_length, 'prop_null,
100
101        -- Indexing
102        'prop_index, 'prop_safeIndex, 'prop_head, 'prop_last,
103        'prop_unsafeIndex, 'prop_unsafeHead, 'prop_unsafeLast,
104
105        -- Monadic indexing (FIXME)
106        {- 'prop_indexM, 'prop_headM, 'prop_lastM,
107        'prop_unsafeIndexM, 'prop_unsafeHeadM, 'prop_unsafeLastM, -}
108
109        -- Subvectors (FIXME)
110        'prop_slice, 'prop_init, 'prop_tail, 'prop_take, 'prop_drop,
111        'prop_splitAt,
112        {- 'prop_unsafeSlice, 'prop_unsafeInit, 'prop_unsafeTail,
113        'prop_unsafeTake, 'prop_unsafeDrop, -}
114
115        -- Initialisation (FIXME)
116        'prop_empty, 'prop_singleton, 'prop_replicate,
117        'prop_generate, 'prop_iterateN, 'prop_iterateNM,
118        'prop_generateM, 'prop_replicateM,
119
120        -- Monadic initialisation (FIXME)
121        'prop_create, 'prop_createT,
122
123        -- Unfolding
124        'prop_unfoldr, 'prop_unfoldrN, 'prop_unfoldrExactN,
125        'prop_unfoldrM, 'prop_unfoldrNM, 'prop_unfoldrExactNM,
126        'prop_constructN, 'prop_constructrN,
127
128        -- Concatenation (FIXME)
129        'prop_cons, 'prop_snoc, 'prop_append,
130        'prop_concat,
131
132        -- Restricting memory usage
133        'prop_force,
134
135
136        -- Bulk updates (FIXME)
137        'prop_upd,
138        {- 'prop_update_,
139        'prop_unsafeUpd, 'prop_unsafeUpdate, 'prop_unsafeUpdate_, -}
140
141        -- Accumulations (FIXME)
142        'prop_accum,
143        {- 'prop_accumulate, 'prop_accumulate_,
144        'prop_unsafeAccum, 'prop_unsafeAccumulate, 'prop_unsafeAccumulate_, -}
145
146        -- Permutations
147        'prop_reverse, 'prop_backpermute,
148        {- 'prop_unsafeBackpermute, -}
149
150        -- Mapping
151        'prop_map, 'prop_imap, 'prop_concatMap,
152
153        -- Monadic mapping
154        'prop_mapM, 'prop_mapM_, 'prop_forM, 'prop_forM_,
155        'prop_imapM, 'prop_imapM_,
156
157        -- Zipping
158        'prop_zipWith, 'prop_zipWith3,
159        'prop_izipWith, 'prop_izipWith3,
160        'prop_izipWithM, 'prop_izipWithM_,
161
162        -- Monadic zipping
163        'prop_zipWithM, 'prop_zipWithM_,
164
165        -- Filtering
166        'prop_filter, 'prop_ifilter, 'prop_filterM,
167        'prop_uniq,
168        'prop_mapMaybe, 'prop_imapMaybe,
169        'prop_takeWhile, 'prop_dropWhile,
170
171        -- Paritioning
172        'prop_partition, {- 'prop_unstablePartition, -}
173        'prop_partitionWith,
174        'prop_span, 'prop_break,
175
176        -- Searching
177        'prop_elem, 'prop_notElem,
178        'prop_find, 'prop_findIndex, 'prop_findIndexR, 'prop_findIndices,
179        'prop_elemIndex, 'prop_elemIndices,
180
181        -- Folding
182        'prop_foldl, 'prop_foldl1, 'prop_foldl', 'prop_foldl1',
183        'prop_foldr, 'prop_foldr1, 'prop_foldr', 'prop_foldr1',
184        'prop_ifoldl, 'prop_ifoldl', 'prop_ifoldr, 'prop_ifoldr',
185        'prop_ifoldM, 'prop_ifoldM', 'prop_ifoldM_, 'prop_ifoldM'_,
186
187        -- Specialised folds
188        'prop_all, 'prop_any,
189
190        -- Scans
191        'prop_prescanl, 'prop_prescanl',
192        'prop_postscanl, 'prop_postscanl',
193        'prop_scanl, 'prop_scanl', 'prop_scanl1, 'prop_scanl1',
194        'prop_iscanl, 'prop_iscanl',
195
196        'prop_prescanr, 'prop_prescanr',
197        'prop_postscanr, 'prop_postscanr',
198        'prop_scanr, 'prop_scanr', 'prop_scanr1, 'prop_scanr1',
199        'prop_iscanr, 'prop_iscanr'
200    ])
201  where
202    -- Prelude
203    prop_eq :: P (v a -> v a -> Bool) = (==) `eq` (==)
204
205    prop_length :: P (v a -> Int)     = V.length `eq` length
206    prop_null   :: P (v a -> Bool)    = V.null `eq` null
207
208    prop_empty  :: P (v a)            = V.empty `eq` []
209    prop_singleton :: P (a -> v a)    = V.singleton `eq` Util.singleton
210    prop_replicate :: P (Int -> a -> v a)
211              = (\n _ -> n < 1000) ===> V.replicate `eq` replicate
212    prop_replicateM :: P (Int -> Writer [a] a -> Writer [a] (v a))
213              = (\n _ -> n < 1000) ===> V.replicateM `eq` replicateM
214    prop_cons      :: P (a -> v a -> v a) = V.cons `eq` (:)
215    prop_snoc      :: P (v a -> a -> v a) = V.snoc `eq` snoc
216    prop_append    :: P (v a -> v a -> v a) = (V.++) `eq` (++)
217    prop_concat    :: P ([v a] -> v a) = V.concat `eq` concat
218    prop_force     :: P (v a -> v a)        = V.force `eq` id
219    prop_generate  :: P (Int -> (Int -> a) -> v a)
220              = (\n _ -> n < 1000) ===> V.generate `eq` Util.generate
221    prop_generateM  :: P (Int -> (Int -> Writer [a] a) -> Writer [a] (v a))
222              = (\n _ -> n < 1000) ===> V.generateM `eq` Util.generateM
223    prop_iterateN  :: P (Int -> (a -> a) -> a -> v a)
224              = (\n _ _ -> n < 1000) ===> V.iterateN `eq` (\n f -> take n . iterate f)
225    prop_iterateNM :: P (Int -> (a -> Writer [Int] a) -> a -> Writer [Int] (v a))
226              = (\n _ _ -> n < 1000) ===> V.iterateNM `eq` Util.iterateNM
227    prop_create :: P (v a -> v a)
228    prop_create = (\v -> V.create (V.thaw v)) `eq` id
229    prop_createT :: P ((a, v a) -> (a, v a))
230    prop_createT = (\v -> V.createT (T.mapM V.thaw v)) `eq` id
231
232    prop_head      :: P (v a -> a) = not . V.null ===> V.head `eq` head
233    prop_last      :: P (v a -> a) = not . V.null ===> V.last `eq` last
234    prop_index        = \xs ->
235                        not (V.null xs) ==>
236                        forAll (choose (0, V.length xs-1)) $ \i ->
237                        unP prop xs i
238      where
239        prop :: P (v a -> Int -> a) = (V.!) `eq` (!!)
240    prop_safeIndex :: P (v a -> Int -> Maybe a) = (V.!?) `eq` fn
241      where
242        fn xs i = case drop i xs of
243                    x:_ | i >= 0 -> Just x
244                    _            -> Nothing
245    prop_unsafeHead  :: P (v a -> a) = not . V.null ===> V.unsafeHead `eq` head
246    prop_unsafeLast  :: P (v a -> a) = not . V.null ===> V.unsafeLast `eq` last
247    prop_unsafeIndex  = \xs ->
248                        not (V.null xs) ==>
249                        forAll (choose (0, V.length xs-1)) $ \i ->
250                        unP prop xs i
251      where
252        prop :: P (v a -> Int -> a) = V.unsafeIndex `eq` (!!)
253
254    prop_slice        = \xs ->
255                        forAll (choose (0, V.length xs))     $ \i ->
256                        forAll (choose (0, V.length xs - i)) $ \n ->
257                        unP prop i n xs
258      where
259        prop :: P (Int -> Int -> v a -> v a) = V.slice `eq` slice
260
261    prop_tail :: P (v a -> v a) = not . V.null ===> V.tail `eq` tail
262    prop_init :: P (v a -> v a) = not . V.null ===> V.init `eq` init
263    prop_take :: P (Int -> v a -> v a) = V.take `eq` take
264    prop_drop :: P (Int -> v a -> v a) = V.drop `eq` drop
265    prop_splitAt :: P (Int -> v a -> (v a, v a)) = V.splitAt `eq` splitAt
266
267    prop_accum = \f xs ->
268                 forAll (index_value_pairs (V.length xs)) $ \ps ->
269                 unP prop f xs ps
270      where
271        prop :: P ((a -> a -> a) -> v a -> [(Int,a)] -> v a)
272          = V.accum `eq` accum
273
274    prop_upd        = \xs ->
275                        forAll (index_value_pairs (V.length xs)) $ \ps ->
276                        unP prop xs ps
277      where
278        prop :: P (v a -> [(Int,a)] -> v a) = (V.//) `eq` (//)
279
280    prop_backpermute  = \xs ->
281                        forAll (indices (V.length xs)) $ \is ->
282                        unP prop xs (V.fromList is)
283      where
284        prop :: P (v a -> v Int -> v a) = V.backpermute `eq` backpermute
285
286    prop_reverse :: P (v a -> v a) = V.reverse `eq` reverse
287
288    prop_map :: P ((a -> a) -> v a -> v a) = V.map `eq` map
289    prop_mapM :: P ((a -> Identity a) -> v a -> Identity (v a))
290            = V.mapM `eq` mapM
291    prop_mapM_ :: P ((a -> Writer [a] ()) -> v a -> Writer [a] ())
292            = V.mapM_ `eq` mapM_
293    prop_forM :: P (v a -> (a -> Identity a) -> Identity (v a))
294            = V.forM `eq` forM
295    prop_forM_ :: P (v a -> (a -> Writer [a] ()) -> Writer [a] ())
296            = V.forM_ `eq` forM_
297    prop_zipWith :: P ((a -> a -> a) -> v a -> v a -> v a) = V.zipWith `eq` zipWith
298    prop_zipWith3 :: P ((a -> a -> a -> a) -> v a -> v a -> v a -> v a)
299             = V.zipWith3 `eq` zipWith3
300    prop_imap :: P ((Int -> a -> a) -> v a -> v a) = V.imap `eq` imap
301    prop_imapM :: P ((Int -> a -> Identity a) -> v a -> Identity (v a))
302            = V.imapM `eq` imapM
303    prop_imapM_ :: P ((Int -> a -> Writer [a] ()) -> v a -> Writer [a] ())
304            = V.imapM_ `eq` imapM_
305    prop_izipWith :: P ((Int -> a -> a -> a) -> v a -> v a -> v a) = V.izipWith `eq` izipWith
306    prop_zipWithM :: P ((a -> a -> Identity a) -> v a -> v a -> Identity (v a))
307            = V.zipWithM `eq` zipWithM
308    prop_zipWithM_ :: P ((a -> a -> Writer [a] ()) -> v a -> v a -> Writer [a] ())
309            = V.zipWithM_ `eq` zipWithM_
310    prop_izipWithM :: P ((Int -> a -> a -> Identity a) -> v a -> v a -> Identity (v a))
311            = V.izipWithM `eq` izipWithM
312    prop_izipWithM_ :: P ((Int -> a -> a -> Writer [a] ()) -> v a -> v a -> Writer [a] ())
313            = V.izipWithM_ `eq` izipWithM_
314    prop_izipWith3 :: P ((Int -> a -> a -> a -> a) -> v a -> v a -> v a -> v a)
315             = V.izipWith3 `eq` izipWith3
316
317    prop_filter :: P ((a -> Bool) -> v a -> v a) = V.filter `eq` filter
318    prop_ifilter :: P ((Int -> a -> Bool) -> v a -> v a) = V.ifilter `eq` ifilter
319    prop_filterM :: P ((a -> Writer [a] Bool) -> v a -> Writer [a] (v a)) = V.filterM `eq` filterM
320    prop_mapMaybe :: P ((a -> Maybe a) -> v a -> v a) = V.mapMaybe `eq` mapMaybe
321    prop_imapMaybe :: P ((Int -> a -> Maybe a) -> v a -> v a) = V.imapMaybe `eq` imapMaybe
322    prop_takeWhile :: P ((a -> Bool) -> v a -> v a) = V.takeWhile `eq` takeWhile
323    prop_dropWhile :: P ((a -> Bool) -> v a -> v a) = V.dropWhile `eq` dropWhile
324    prop_partition :: P ((a -> Bool) -> v a -> (v a, v a))
325      = V.partition `eq` partition
326    prop_partitionWith :: P ((a -> Either a a) -> v a -> (v a, v a))
327      = V.partitionWith `eq` partitionWith
328    prop_span :: P ((a -> Bool) -> v a -> (v a, v a)) = V.span `eq` span
329    prop_break :: P ((a -> Bool) -> v a -> (v a, v a)) = V.break `eq` break
330
331    prop_elem    :: P (a -> v a -> Bool) = V.elem `eq` elem
332    prop_notElem :: P (a -> v a -> Bool) = V.notElem `eq` notElem
333    prop_find    :: P ((a -> Bool) -> v a -> Maybe a) = V.find `eq` find
334    prop_findIndex :: P ((a -> Bool) -> v a -> Maybe Int)
335      = V.findIndex `eq` findIndex
336    prop_findIndexR :: P ((a -> Bool) -> v a -> Maybe Int)
337      = V.findIndexR `eq` \p l -> case filter (p . snd) . reverse $ zip [0..] l of
338                                     (i,_):_ -> Just i
339                                     []      -> Nothing
340    prop_findIndices :: P ((a -> Bool) -> v a -> v Int)
341        = V.findIndices `eq` findIndices
342    prop_elemIndex :: P (a -> v a -> Maybe Int) = V.elemIndex `eq` elemIndex
343    prop_elemIndices :: P (a -> v a -> v Int) = V.elemIndices `eq` elemIndices
344
345    prop_foldl :: P ((a -> a -> a) -> a -> v a -> a) = V.foldl `eq` foldl
346    prop_foldl1 :: P ((a -> a -> a) -> v a -> a)     = notNull2 ===>
347                        V.foldl1 `eq` foldl1
348    prop_foldl' :: P ((a -> a -> a) -> a -> v a -> a) = V.foldl' `eq` foldl'
349    prop_foldl1' :: P ((a -> a -> a) -> v a -> a)     = notNull2 ===>
350                        V.foldl1' `eq` foldl1'
351    prop_foldr :: P ((a -> a -> a) -> a -> v a -> a) = V.foldr `eq` foldr
352    prop_foldr1 :: P ((a -> a -> a) -> v a -> a)     = notNull2 ===>
353                        V.foldr1 `eq` foldr1
354    prop_foldr' :: P ((a -> a -> a) -> a -> v a -> a) = V.foldr' `eq` foldr
355    prop_foldr1' :: P ((a -> a -> a) -> v a -> a)     = notNull2 ===>
356                        V.foldr1' `eq` foldr1
357    prop_ifoldl :: P ((a -> Int -> a -> a) -> a -> v a -> a)
358        = V.ifoldl `eq` ifoldl
359    prop_ifoldl' :: P ((a -> Int -> a -> a) -> a -> v a -> a)
360        = V.ifoldl' `eq` ifoldl
361    prop_ifoldr :: P ((Int -> a -> a -> a) -> a -> v a -> a)
362        = V.ifoldr `eq` ifoldr
363    prop_ifoldr' :: P ((Int -> a -> a -> a) -> a -> v a -> a)
364        = V.ifoldr' `eq` ifoldr
365    prop_ifoldM :: P ((a -> Int -> a -> Identity a) -> a -> v a -> Identity a)
366        = V.ifoldM `eq` ifoldM
367    prop_ifoldM' :: P ((a -> Int -> a -> Identity a) -> a -> v a -> Identity a)
368        = V.ifoldM' `eq` ifoldM
369    prop_ifoldM_ :: P ((() -> Int -> a -> Writer [a] ()) -> () -> v a -> Writer [a] ())
370        = V.ifoldM_ `eq` ifoldM_
371    prop_ifoldM'_ :: P ((() -> Int -> a -> Writer [a] ()) -> () -> v a -> Writer [a] ())
372        = V.ifoldM'_ `eq` ifoldM_
373
374    prop_all :: P ((a -> Bool) -> v a -> Bool) = V.all `eq` all
375    prop_any :: P ((a -> Bool) -> v a -> Bool) = V.any `eq` any
376
377    prop_prescanl :: P ((a -> a -> a) -> a -> v a -> v a)
378                = V.prescanl `eq` prescanl
379    prop_prescanl' :: P ((a -> a -> a) -> a -> v a -> v a)
380                = V.prescanl' `eq` prescanl
381    prop_postscanl :: P ((a -> a -> a) -> a -> v a -> v a)
382                = V.postscanl `eq` postscanl
383    prop_postscanl' :: P ((a -> a -> a) -> a -> v a -> v a)
384                = V.postscanl' `eq` postscanl
385    prop_scanl :: P ((a -> a -> a) -> a -> v a -> v a)
386                = V.scanl `eq` scanl
387    prop_scanl' :: P ((a -> a -> a) -> a -> v a -> v a)
388               = V.scanl' `eq` scanl
389    prop_scanl1 :: P ((a -> a -> a) -> v a -> v a) = notNull2 ===>
390                 V.scanl1 `eq` scanl1
391    prop_scanl1' :: P ((a -> a -> a) -> v a -> v a) = notNull2 ===>
392                 V.scanl1' `eq` scanl1
393    prop_iscanl :: P ((Int -> a -> a -> a) -> a -> v a -> v a)
394                = V.iscanl `eq` iscanl
395    prop_iscanl' :: P ((Int -> a -> a -> a) -> a -> v a -> v a)
396               = V.iscanl' `eq` iscanl
397
398    prop_prescanr :: P ((a -> a -> a) -> a -> v a -> v a)
399                = V.prescanr `eq` prescanr
400    prop_prescanr' :: P ((a -> a -> a) -> a -> v a -> v a)
401                = V.prescanr' `eq` prescanr
402    prop_postscanr :: P ((a -> a -> a) -> a -> v a -> v a)
403                = V.postscanr `eq` postscanr
404    prop_postscanr' :: P ((a -> a -> a) -> a -> v a -> v a)
405                = V.postscanr' `eq` postscanr
406    prop_scanr :: P ((a -> a -> a) -> a -> v a -> v a)
407                = V.scanr `eq` scanr
408    prop_scanr' :: P ((a -> a -> a) -> a -> v a -> v a)
409               = V.scanr' `eq` scanr
410    prop_iscanr :: P ((Int -> a -> a -> a) -> a -> v a -> v a)
411                = V.iscanr `eq` iscanr
412    prop_iscanr' :: P ((Int -> a -> a -> a) -> a -> v a -> v a)
413               = V.iscanr' `eq` iscanr
414    prop_scanr1 :: P ((a -> a -> a) -> v a -> v a) = notNull2 ===>
415                 V.scanr1 `eq` scanr1
416    prop_scanr1' :: P ((a -> a -> a) -> v a -> v a) = notNull2 ===>
417                 V.scanr1' `eq` scanr1
418
419    prop_concatMap    = forAll arbitrary $ \xs ->
420                        forAll (sized (\n -> resize (n `div` V.length xs) arbitrary)) $ \f -> unP prop f xs
421      where
422        prop :: P ((a -> v a) -> v a -> v a) = V.concatMap `eq` concatMap
423
424    prop_uniq :: P (v a -> v a)
425      = V.uniq `eq` (map head . group)
426
427    -- Data.List
428    --prop_mapAccumL  = eq3
429    --    (V.mapAccumL :: (X -> W -> (X,W)) -> X -> B   -> (X, B))
430    --    (  mapAccumL :: (X -> W -> (X,W)) -> X -> [W] -> (X, [W]))
431    --
432    --prop_mapAccumR  = eq3
433    --    (V.mapAccumR :: (X -> W -> (X,W)) -> X -> B   -> (X, B))
434    --    (  mapAccumR :: (X -> W -> (X,W)) -> X -> [W] -> (X, [W]))
435
436    -- Because the vectors are strict, we need to be totally sure that the unfold eventually terminates. This
437    -- is achieved by injecting our own bit of state into the unfold - the maximum number of unfolds allowed.
438    limitUnfolds f (theirs, ours)
439        | ours > 0
440        , Just (out, theirs') <- f theirs = Just (out, (theirs', ours - 1))
441        | otherwise                       = Nothing
442    limitUnfoldsM f (theirs, ours)
443        | ours >  0 = do r <- f theirs
444                         return $ (\(a,b) -> (a,(b,ours - 1))) `fmap` r
445        | otherwise = return Nothing
446
447
448    prop_unfoldr :: P (Int -> (Int -> Maybe (a,Int)) -> Int -> v a)
449         = (\n f a -> V.unfoldr (limitUnfolds f) (a, n))
450           `eq` (\n f a -> unfoldr (limitUnfolds f) (a, n))
451    prop_unfoldrN :: P (Int -> (Int -> Maybe (a,Int)) -> Int -> v a)
452         = V.unfoldrN `eq` (\n f a -> unfoldr (limitUnfolds f) (a, n))
453    prop_unfoldrExactN :: P (Int -> (Int -> (a,Int)) -> Int -> v a)
454         = V.unfoldrExactN `eq` (\n f a -> unfoldr (limitUnfolds (Just . f)) (a, n))
455    prop_unfoldrM :: P (Int -> (Int -> Writer [Int] (Maybe (a,Int))) -> Int -> Writer [Int] (v a))
456         = (\n f a -> V.unfoldrM (limitUnfoldsM f) (a,n))
457           `eq` (\n f a -> Util.unfoldrM (limitUnfoldsM f) (a, n))
458    prop_unfoldrNM :: P (Int -> (Int -> Writer [Int] (Maybe (a,Int))) -> Int -> Writer [Int] (v a))
459         = V.unfoldrNM `eq` (\n f a -> Util.unfoldrM (limitUnfoldsM f) (a, n))
460    prop_unfoldrExactNM :: P (Int -> (Int -> Writer [Int] (a,Int)) -> Int -> Writer [Int] (v a))
461         = V.unfoldrExactNM `eq` (\n f a -> Util.unfoldrM (limitUnfoldsM (liftM Just . f)) (a, n))
462
463    prop_constructN  = \f -> forAll (choose (0,20)) $ \n -> unP prop n f
464      where
465        prop :: P (Int -> (v a -> a) -> v a) = V.constructN `eq` constructN []
466
467        constructN xs 0 _ = xs
468        constructN xs n f = constructN (xs ++ [f xs]) (n-1) f
469
470    prop_constructrN  = \f -> forAll (choose (0,20)) $ \n -> unP prop n f
471      where
472        prop :: P (Int -> (v a -> a) -> v a) = V.constructrN `eq` constructrN []
473
474        constructrN xs 0 _ = xs
475        constructrN xs n f = constructrN (f xs : xs) (n-1) f
476
477-- copied from GHC source code
478partitionWith :: (a -> Either b c) -> [a] -> ([b], [c])
479partitionWith _ [] = ([],[])
480partitionWith f (x:xs) = case f x of
481                         Left  b -> (b:bs, cs)
482                         Right c -> (bs, c:cs)
483    where (bs,cs) = partitionWith f xs
484
485testTuplyFunctions
486  :: forall a v. ( CommonContext a v
487                 , VectorContext (a, a)    v
488                 , VectorContext (a, a, a) v
489                 , VectorContext (Int, a)  v
490                 )
491  => v a -> [Test]
492{-# INLINE testTuplyFunctions #-}
493testTuplyFunctions _ = $(testProperties [ 'prop_zip, 'prop_zip3
494                                        , 'prop_unzip, 'prop_unzip3
495                                        , 'prop_indexed
496                                        , 'prop_update
497                                        ])
498  where
499    prop_zip     :: P (v a -> v a -> v (a, a))           = V.zip `eq` zip
500    prop_zip3    :: P (v a -> v a -> v a -> v (a, a, a)) = V.zip3 `eq` zip3
501    prop_unzip   :: P (v (a, a) -> (v a, v a))           = V.unzip `eq` unzip
502    prop_unzip3  :: P (v (a, a, a) -> (v a, v a, v a))   = V.unzip3 `eq` unzip3
503    prop_indexed :: P (v a -> v (Int, a))                = V.indexed `eq` (\xs -> [0..] `zip` xs)
504    prop_update = \xs ->
505      forAll (index_value_pairs (V.length xs)) $ \ps ->
506      unP prop xs ps
507      where
508        prop :: P (v a -> [(Int,a)] -> v a) = (V.//) `eq` (//)
509
510testOrdFunctions :: forall a v. (CommonContext a v, Ord a, Ord (v a)) => v a -> [Test]
511{-# INLINE testOrdFunctions #-}
512testOrdFunctions _ = $(testProperties
513  ['prop_compare,
514   'prop_maximum, 'prop_minimum,
515   'prop_minIndex, 'prop_maxIndex,
516   'prop_maximumBy, 'prop_minimumBy,
517   'prop_maxIndexBy, 'prop_minIndexBy,
518   'prop_ListLastMaxIndexWins, 'prop_FalseListFirstMaxIndexWins ])
519  where
520    prop_compare :: P (v a -> v a -> Ordering) = compare `eq` compare
521    prop_maximum :: P (v a -> a) = not . V.null ===> V.maximum `eq` maximum
522    prop_minimum :: P (v a -> a) = not . V.null ===> V.minimum `eq` minimum
523    prop_minIndex :: P (v a -> Int) = not . V.null ===> V.minIndex `eq` minIndex
524    prop_maxIndex :: P (v a -> Int) = not . V.null ===> V.maxIndex `eq` listMaxIndexFMW
525    prop_maximumBy :: P (v a -> a) =
526      not . V.null ===> V.maximumBy compare `eq` maximum
527    prop_minimumBy :: P (v a -> a) =
528      not . V.null ===> V.minimumBy compare `eq` minimum
529    prop_maxIndexBy :: P (v a -> Int) =
530      not . V.null ===> V.maxIndexBy compare `eq`  listMaxIndexFMW
531                                          ---   (maxIndex)
532    prop_ListLastMaxIndexWins ::  P (v a -> Int) =
533        not . V.null ===> ( maxIndex . V.toList) `eq` listMaxIndexLMW
534    prop_FalseListFirstMaxIndexWinsDesc ::  P (v a -> Int) =
535        (\x -> not $ V.null x && (V.uniq x /= x ) )===> ( maxIndex . V.toList) `eq` listMaxIndexFMW
536    prop_FalseListFirstMaxIndexWins :: Property
537    prop_FalseListFirstMaxIndexWins = expectFailure prop_FalseListFirstMaxIndexWinsDesc
538    prop_minIndexBy :: P (v a -> Int) =
539      not . V.null ===> V.minIndexBy compare `eq` minIndex
540
541listMaxIndexFMW :: Ord a => [a] -> Int
542listMaxIndexFMW  = ( fst  . extractFMW .  sconcat . DLE.fromList . fmap FMW . zip [0 :: Int ..])
543
544listMaxIndexLMW :: Ord a => [a] -> Int
545listMaxIndexLMW = ( fst  . extractLMW .  sconcat . DLE.fromList . fmap LMW . zip [0 :: Int ..])
546
547newtype LastMaxWith a i = LMW {extractLMW:: (i,a)}
548    deriving(Eq,Show,Read)
549instance (Ord a) => Semigroup  (LastMaxWith a i)   where
550    (<>) x y | snd (extractLMW x) > snd (extractLMW y) = x
551             | snd (extractLMW x) < snd (extractLMW y) = y
552             | otherwise = y
553newtype FirstMaxWith a i = FMW {extractFMW:: (i,a)}
554    deriving(Eq,Show,Read)
555instance (Ord a) => Semigroup  (FirstMaxWith a i)   where
556    (<>) x y | snd (extractFMW x) > snd (extractFMW y) = x
557             | snd (extractFMW x) < snd (extractFMW y) = y
558             | otherwise = x
559
560
561testEnumFunctions :: forall a v. (CommonContext a v, Enum a, Ord a, Num a, Random a) => v a -> [Test]
562{-# INLINE testEnumFunctions #-}
563testEnumFunctions _ = $(testProperties
564  [ 'prop_enumFromN, 'prop_enumFromThenN,
565    'prop_enumFromTo, 'prop_enumFromThenTo])
566  where
567    prop_enumFromN :: P (a -> Int -> v a)
568      = (\_ n -> n < 1000)
569        ===> V.enumFromN `eq` (\x n -> take n $ scanl (+) x $ repeat 1)
570
571    prop_enumFromThenN :: P (a -> a -> Int -> v a)
572      = (\_ _ n -> n < 1000)
573        ===> V.enumFromStepN `eq` (\x y n -> take n $ scanl (+) x $ repeat y)
574
575    prop_enumFromTo = \m ->
576                      forAll (choose (-2,100)) $ \n ->
577                      unP prop m (m+n)
578      where
579        prop  :: P (a -> a -> v a) = V.enumFromTo `eq` enumFromTo
580
581    prop_enumFromThenTo = \i j ->
582                          j /= i ==>
583                          forAll (choose (ks i j)) $ \k ->
584                          unP prop i j k
585      where
586        prop :: P (a -> a -> a -> v a) = V.enumFromThenTo `eq` enumFromThenTo
587
588        ks i j | j < i     = (i-d*100, i+d*2)
589               | otherwise = (i-d*2, i+d*100)
590          where
591            d = abs (j-i)
592
593testMonoidFunctions :: forall a v. (CommonContext a v, Monoid (v a)) => v a -> [Test]
594{-# INLINE testMonoidFunctions #-}
595testMonoidFunctions _ = $(testProperties
596  [ 'prop_mempty, 'prop_mappend, 'prop_mconcat ])
597  where
598    prop_mempty  :: P (v a)               = mempty `eq` mempty
599    prop_mappend :: P (v a -> v a -> v a) = mappend `eq` mappend
600    prop_mconcat :: P ([v a] -> v a)      = mconcat `eq` mconcat
601
602testFunctorFunctions :: forall a v. (CommonContext a v, Functor v) => v a -> [Test]
603{-# INLINE testFunctorFunctions #-}
604testFunctorFunctions _ = $(testProperties
605  [ 'prop_fmap ])
606  where
607    prop_fmap :: P ((a -> a) -> v a -> v a) = fmap `eq` fmap
608
609testMonadFunctions :: forall a v. (CommonContext a v, VectorContext (a, a) v, MonadZip v) => v a -> [Test]
610{-# INLINE testMonadFunctions #-}
611testMonadFunctions _ = $(testProperties [ 'prop_return, 'prop_bind
612                                        , 'prop_mzip, 'prop_munzip
613                                        ])
614  where
615    prop_return :: P (a -> v a) = return `eq` return
616    prop_bind   :: P (v a -> (a -> v a) -> v a) = (>>=) `eq` (>>=)
617    prop_mzip   :: P (v a -> v a -> v (a, a)) = mzip `eq` zip
618    prop_munzip :: P (v (a, a) -> (v a, v a)) = munzip `eq` unzip
619
620testSequenceFunctions
621  :: forall a v. ( CommonContext a v
622                 , Model (v (Writer [a] a)) ~ [Writer [a] a]
623                 , V.Vector v (Writer [a] a)
624                 , Arbitrary (v (Writer [a] a))
625                 , Show      (v (Writer [a] a))
626                 , TestData  (v (Writer [a] a))
627                 )
628  => v a -> [Test]
629testSequenceFunctions _ = $(testProperties [ 'prop_sequence, 'prop_sequence_
630                                           ])
631  where
632    prop_sequence :: P (v (Writer [a] a) -> Writer [a] (v a))
633      = V.sequence `eq` sequence
634    prop_sequence_ :: P (v (Writer [a] a) -> Writer [a] ())
635      = V.sequence_ `eq` sequence_
636
637testApplicativeFunctions :: forall a v. (CommonContext a v, V.Vector v (a -> a), Applicative.Applicative v) => v a -> [Test]
638{-# INLINE testApplicativeFunctions #-}
639testApplicativeFunctions _ = $(testProperties
640  [ 'prop_applicative_pure, 'prop_applicative_appl ])
641  where
642    prop_applicative_pure :: P (a -> v a)
643      = Applicative.pure `eq` Applicative.pure
644    prop_applicative_appl :: [a -> a] -> P (v a -> v a)
645      = \fs -> (Applicative.<*>) (V.fromList fs) `eq` (Applicative.<*>) fs
646
647testAlternativeFunctions :: forall a v. (CommonContext a v, Applicative.Alternative v) => v a -> [Test]
648{-# INLINE testAlternativeFunctions #-}
649testAlternativeFunctions _ = $(testProperties
650  [ 'prop_alternative_empty, 'prop_alternative_or ])
651  where
652    prop_alternative_empty :: P (v a) = Applicative.empty `eq` Applicative.empty
653    prop_alternative_or :: P (v a -> v a -> v a)
654      = (Applicative.<|>) `eq` (Applicative.<|>)
655
656testBoolFunctions :: forall v. (CommonContext Bool v) => v Bool -> [Test]
657{-# INLINE testBoolFunctions #-}
658testBoolFunctions _ = $(testProperties ['prop_and, 'prop_or])
659  where
660    prop_and :: P (v Bool -> Bool) = V.and `eq` and
661    prop_or  :: P (v Bool -> Bool) = V.or `eq` or
662
663testNumFunctions :: forall a v. (CommonContext a v, Num a) => v a -> [Test]
664{-# INLINE testNumFunctions #-}
665testNumFunctions _ = $(testProperties ['prop_sum, 'prop_product])
666  where
667    prop_sum     :: P (v a -> a) = V.sum `eq` sum
668    prop_product :: P (v a -> a) = V.product `eq` product
669
670testNestedVectorFunctions :: forall a v. (CommonContext a v) => v a -> [Test]
671{-# INLINE testNestedVectorFunctions #-}
672testNestedVectorFunctions _ = $(testProperties
673  [ 'prop_concat
674  ])
675  where
676    prop_concat :: P ([v a] -> v a) = V.concat `eq` concat
677
678testDataFunctions :: forall a v. (CommonContext a v, Data a, Data (v a)) => v a -> [Test]
679{-# INLINE testDataFunctions #-}
680testDataFunctions _ = $(testProperties ['prop_glength])
681  where
682    prop_glength :: P (v a -> Int) = glength `eq` glength
683      where
684        glength :: Data b => b -> Int
685        glength xs = gmapQl (+) 0 toA xs
686
687        toA :: Data b => b -> Int
688        toA x = maybe (glength x) (const 1) (cast x :: Maybe a)
689