-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathUnitTests.hs
280 lines (238 loc) · 8.83 KB
/
UnitTests.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
module Main (main) where
import qualified Data.Either as P
import Data.Functor.Identity (Identity (..))
import qualified Data.List as P
import qualified Data.Maybe as P
import Data.Monoid
import Data.Primitive
import qualified Data.Primitive.Contiguous as C
import qualified Data.Vector as V
import qualified GHC.Exts as Exts
import Test.QuickCheck
import Test.QuickCheck.Instances ()
import Prelude
import qualified Prelude as P
main :: IO ()
main = unitTests
unitTests :: IO ()
unitTests =
mapM_
testC
[ quiet "Contiguous.filter = Data.List.filter" prop_filter
, quiet "Contiguous.mapMaybe = Data.Maybe.mapMaybe" prop_mapMaybe
, quiet "Reverse: reverse . reverse = id" prop_reverse1
, quiet "Contiguous.reverse = Data.List.reverse" prop_reverse2
, quiet "Contiguous.map = Data.List.map" prop_map
, quiet "Contiguous.unfoldr = Data.List.unfoldr" prop_unfoldr
, quiet "Contiguous.unfoldrN = Data.Vector.unfoldrN" prop_unfoldrN
, quiet "Contiguous.traverse = Data.Traversable.traverse" prop_traverse
, quiet "Contiguous.find = Data.Foldable.find" prop_find
, quiet "Contiguous.scanl = Data.List.scanl" prop_scanl
, quiet "Contiguous.scanl' = Data.List.scanl'" prop_scanl'
, quiet "Contiguous.prescanl = Data.Vector.prescanl" prop_prescanl
, quiet "Contiguous.prescanl' = Data.Vector.prescanl'" prop_prescanl'
, quiet "Contiguous.generate = Data.Vector.generate" prop_generate
, quiet "Contiguous.generateM = Data.Vector.generateM" prop_generateM
, quiet "Contiguous.minimum = Data.Foldable.minimum" prop_minimum
, quiet "Contiguous.maximum = Data.Foldable.maximum" prop_maximum
, quiet "Contiguous.zipWith = Data.List.zipWith" prop_zipWith
, quiet "Contiguous.zip = Data.List.zip" prop_zip
, quiet "Contiguous.lefts = Data.Either.lefts" prop_lefts
, quiet "Contiguous.rights = Data.Either.rights" prop_rights
, quiet "Contiguous.partitionEithers = Data.Either.partitionEithers" prop_partitionEithers
]
-- Verbosity with which to run tests.
data Verbosity = Quiet | Verbose
-- | Hide the prop type.
data Prop = forall prop. (Testable prop) => Prop prop
-- hack to let us get away with stuffing different
-- prop types in a list
data CTest = CTest
{ _verbosity :: Verbosity
, _label :: String
, _prop :: Prop
}
-- quiet output of a test
quiet :: (Testable prop) => String -> prop -> CTest
quiet l p = CTest Quiet l (Prop p)
-- verbose output of a test
-- Useful for failing tests
_verbose :: (Testable prop) => String -> prop -> CTest
_verbose l p = CTest Verbose l (Prop p)
testC :: CTest -> IO ()
testC (CTest v lbl (Prop p)) = do
putStrLn $ P.replicate (length lbl + 6) '-'
putStrLn $ "-- " ++ lbl ++ " --"
putStrLn $ P.replicate (length lbl + 6) '-'
putStr "\n"
($ p) $ case v of Verbose -> verboseCheck; Quiet -> quickCheck
putStr "\n"
newtype Arr = Arr (Array L)
deriving (Eq, Show)
newtype L = L [Int]
deriving (Eq, Ord, Exts.IsList)
instance Show L where
show (L x) = show x
instance Arbitrary L where
arbitrary = do
j <- choose (1, 6)
fmap L $ vectorOf j arbitrary
instance Arbitrary Arr where
arbitrary = do
k <- choose (2, 20)
fmap (Arr . Exts.fromList) $ vectorOf k arbitrary
shrink (Arr xs) = fmap Arr (fmap Exts.fromList $ shrink $ Exts.toList xs)
mean :: forall t a. (Foldable t, Integral a) => t a -> a
mean xs =
let (sum_ :: Sum a, len_ :: Sum a) = foldMap (\x -> (Sum x, Sum 1)) xs
in (round :: Double -> a) $ (fromIntegral (getSum sum_) / fromIntegral (getSum len_))
prop_filter :: Arr -> Property
prop_filter (Arr arr) =
property $
let arrList = C.toList arr
p = \(L xs) -> all even xs
in P.filter p arrList == C.toList (C.filter p arr)
prop_mapMaybe :: Arr -> Property
prop_mapMaybe (Arr arr) =
property $
let arrList = C.toList arr
p = \(L xs) -> if all even xs then Just () else Nothing
in P.mapMaybe p arrList == C.toList (C.mapMaybe p arr :: Array ())
prop_reverse1 :: Arr -> Property
prop_reverse1 (Arr arr) =
property $
C.reverse (C.reverse arr) == arr
prop_reverse2 :: Arr -> Property
prop_reverse2 (Arr arr) =
property $
let arrList = C.toList arr
in P.reverse arrList == C.toList (C.reverse arr)
prop_map :: Arr -> Property
prop_map (Arr arr) =
property $
let arrList = C.toList arr
f = \(L xs) -> mean xs
in P.map f arrList == C.toList (C.map f arr :: Array Int)
prop_unfoldr :: Property
prop_unfoldr =
property $
let f = \n -> if n == 0 then Nothing else Just (n, n - 1)
sz = 10
in P.unfoldr f sz == C.toList (C.unfoldr f sz :: Array Int)
prop_unfoldrN :: Property
prop_unfoldrN =
property $
let f = \n -> if n == 0 then Nothing else Just (n, n - 1)
sz = 100
in V.toList (V.unfoldrN sz f 10) == C.toList (C.unfoldrN sz f 10 :: Array Int)
prop_traverse :: Arr -> Property
prop_traverse (Arr arr) =
property $
let arrList = C.toList arr
f = \(L xs) -> Identity (sum xs)
in runIdentity (P.traverse f arrList) == C.toList (runIdentity (C.traverse f arr :: Identity (Array Int)))
prop_generate :: Property
prop_generate =
property $
let f = \i -> if even i then Just i else Nothing
in V.toList (V.generate 20 f) == C.toList (C.generate 20 f :: Array (Maybe Int))
prop_generateM :: Property
prop_generateM =
property $
let f = \i -> if even i then Just i else Nothing
in fmap V.toList (V.generateM 20 f) == fmap C.toList (C.generateM 20 f :: Maybe (Array Int))
{-
prop_postscanl :: Arr -> Property
prop_postscanl (Arr arr) = property $
let arrList = V.fromList (C.toList arr)
f = \b (L a) -> b ++ a
in V.toList (V.postscanl f [] arrList) == C.toList (C.postscanl f [] arr :: Array [Int])
-}
prop_prescanl :: Arr -> Property
prop_prescanl (Arr arr) =
property $
let arrList = V.fromList (C.toList arr)
f = \b (L a) -> b ++ a
in V.toList (V.prescanl f [] arrList) == C.toList (C.prescanl f [] arr :: Array [Int])
prop_prescanl' :: Arr -> Property
prop_prescanl' (Arr arr) =
property $
let arrList = V.fromList (C.toList arr)
f = \b (L a) -> b ++ a
in V.toList (V.prescanl' f [] arrList) == C.toList (C.prescanl' f [] arr :: Array [Int])
prop_find :: Arr -> Property
prop_find (Arr arr) =
property $
let arrList = C.toList arr
f = \(L xs) -> even (sum xs)
in P.find f arrList == C.find f arr
prop_zipWith :: Arr -> Arr -> Property
prop_zipWith (Arr arr1) (Arr arr2) =
property $
let arrList1 = C.toList arr1
arrList2 = C.toList arr2
f = \(L xs) (L ys) -> xs ++ ys
in P.zipWith f arrList1 arrList2 == C.toList (C.zipWith f arr1 arr2 :: Array [Int])
prop_zip :: Arr -> Arr -> Property
prop_zip (Arr arr1) (Arr arr2) =
property $
let arrList1 = C.toList arr1
arrList2 = C.toList arr2
in P.zip arrList1 arrList2 == C.toList (C.zip arr1 arr2 :: Array (L, L))
prop_scanl :: Arr -> Property
prop_scanl (Arr arr) =
property $
let arrList = C.toList arr
f = \b (L a) -> b ++ a
in P.scanl f [] arrList == C.toList (C.scanl f [] arr :: Array [Int])
prop_scanl' :: Arr -> Property
prop_scanl' (Arr arr) =
property $
let arrList = C.toList arr
f = \b (L a) -> b ++ a
in P.scanl' f [] arrList == C.toList (C.scanl' f [] arr :: Array [Int])
prop_partitionEithers :: Array' (Either Int Bool) -> Property
prop_partitionEithers (Array' arr) =
property $
let arrList = C.toList arr
rhs = case C.partitionEithers arr of (as, bs) -> (C.toList as, C.toList bs)
in P.partitionEithers arrList == rhs
prop_rights :: Array' (Either Int Bool) -> Property
prop_rights (Array' arr) =
property $
let arrList = C.toList arr
in P.rights arrList == C.toList (C.rights arr)
prop_lefts :: Array' (Either Int Bool) -> Property
prop_lefts (Array' arr) =
property $
let arrList = C.toList arr
in P.lefts arrList == C.toList (C.lefts arr)
prop_minimum :: Arr -> Property
prop_minimum (Arr arr) =
property $
let arrList = C.toList arr
in Just (minimum arrList) == C.minimum arr
prop_maximum :: Arr -> Property
prop_maximum (Arr arr) =
property $
let arrList = C.toList arr
in Just (maximum arrList) == C.maximum arr
newtype Array' a = Array' {getArray' :: Array a}
deriving (Eq, Show, Exts.IsList)
instance (Arbitrary a) => Arbitrary (Array' a) where
arbitrary = do
k <- choose (2, 20)
fmap Exts.fromList $ vectorOf k arbitrary
shrink xs = fmap Exts.fromList $ shrink $ Exts.toList xs
-- Get around quickcheck not generating multiple arrays
-- newtype GenArrM = GenArr { getGenArrM :: Array Int }
-- deriving (Eq, Show, Exts.IsList)
-- instance Arbitrary GenArrM where
-- arbitrary = do
-- k <- choose (2,20)
-- GenArrM <$> C.generateM k (const arbitrary)
-- shrink xs = fmap Exts.fromList $ shrink $ Exts.toList xs