4 - This is a test framework for Arrays, using QuickCheck
10 import Monad ( liftM2, liftM3, liftM4 )
22 forAll genBounds $ \ (b :: (Int,Int)) ->
23 forAll (genIVPs b 10) $ \ (vs :: [(Int,Int)]) ->
28 forAll genBounds $ \ (b :: (Int,Int)) ->
29 forAll (vector (length [fst b..snd b]))
31 Array.listArray b vs == Array.array b (zipWith (\ a b -> (a,b))
35 forAll genBounds $ \ (b :: (Int,Int)) ->
36 forAll (genIVPs b 10) $ \ (vs :: [(Int,Int)]) ->
37 let arr = Array.array b vs
38 in Array.indices arr == ((Array.range . Array.bounds) arr)
41 forAll genBounds $ \ (b :: (Int,Int)) ->
42 forAll (genIVPs b 10) $ \ (vs :: [(Int,Int)]) ->
43 let arr = Array.array b vs
44 in Array.elems arr == [arr Array.! i | i <- Array.indices arr]
47 forAll genBounds $ \ (b :: (Int,Int)) ->
48 forAll (genIVPs b 10) $ \ (vs :: [(Int,Int)]) ->
49 let arr = Array.array b vs
50 in Array.assocs arr == [(i, arr Array.! i) | i <- Array.indices arr]
53 forAll genBounds $ \ (b :: (Int,Int)) ->
54 forAll (genIVPs b 10) $ \ (vs :: [(Int,Int)]) ->
55 let arr = Array.array b vs
57 in arr Array.// us == Array.array (Array.bounds arr)
59 | i <- Array.indices arr \\ [i | (i,_) <- us]]
62 forAll genBounds $ \ (b :: (Int,Int)) ->
63 forAll (genIVPs b 10) $ \ (vs :: [(Int,Int)]) ->
65 forAll (genIVPs b 10) $ \ (us :: [(Int,Int)]) ->
66 forAll (choose (0,length us))
68 let us' = take n us in
69 forAll arbitrary $ \ (fn :: Int -> Int -> Int) ->
70 let arr = Array.array b vs
71 in Array.accum fn arr us'
72 == foldl (\a (i,v) -> a Array.// [(i,fn (a Array.! i) v)]) arr us'
75 forAll arbitrary $ \ (f :: Int -> Int -> Int) ->
76 forAll arbitrary $ \ (z :: Int) ->
77 forAll genBounds $ \ (b :: (Int,Int)) ->
78 forAll (genIVPs b 10) $ \ (vs :: [(Int,Int)]) ->
79 Array.accumArray f z b vs == Array.accum f
80 (Array.array b [(i,z) | i <- Array.range b]) vs
83 same_arr :: (Eq b) => Array.Array Int b -> Array Int b -> Bool
84 same_arr a1 a2 = a == c && b == d
85 && all (\ n -> (a1 Array.! n) == (a2 ! n)) [a..b]
86 where (a,b) = Array.bounds a1 :: (Int,Int)
87 (c,d) = bounds a2 :: (Int,Int)
89 genBounds :: Gen (Int,Int)
90 genBounds = do m <- choose (0,20)
91 n <- choose (minBound,maxBound-m)
94 genIVP :: Arbitrary a => (Int,Int) -> Gen (Int,a)
95 genIVP b = do { i <- choose b
100 genIVPs :: Arbitrary a => (Int,Int) -> Int -> Gen [(Int,a)]
101 genIVPs b@(low,high) s
102 = do { let is = [low..high]
103 ; vs <- vector (length is)
104 ; shuffle s (zip is vs)
107 prop_id = forAll genBounds $ \ (b :: (Int,Int)) ->
108 forAll (genIVPs b 10) $ \ (ivps :: [(Int,Int)]) ->
109 label (show (ivps :: [(Int,Int)])) True
111 -- rift takes a list, split it (using an Int argument),
112 -- and then rifts together the split lists into one.
113 -- Think: rifting a pack of cards.
114 rift :: Int -> [a] -> [a]
115 rift n xs = comb (drop n xs) (take n xs)
117 comb (a:as) (b:bs) = a : b : comb as bs
118 comb (a:as) [] = a : as
119 comb [] (b:bs) = b : bs
123 -- suffle makes n random rifts. Typically after
124 -- log n rifts, the list is in a pretty random order.
125 -- (where n is the number of elements in the list)
127 shuffle :: Int -> [a] -> Gen [a]
128 shuffle 0 m = return m
129 shuffle n m = do { r <- choose (1,length m)
130 ; shuffle (n-1) (rift r m)
133 forAll (shuffle 10 [1..10::Int]) $ \ lst ->
134 label (show lst) True
136 ------------------------------------------------------------------------------
138 main = do test prop_array
148 instance Show (a -> b) where { show _ = "<FN>" }
150 ------------------------------------------------------------------------------
152 data (Ix a) => Array a b = MkArray (a,a) (a -> b) deriving ()
154 array :: (Ix a) => (a,a) -> [(a,b)] -> Array a b
156 if and [inRange b i | (i,_) <- ivs]
158 (\j -> case [v | (i,v) <- ivs, i == j] of
160 [] -> error "Array.!: \
161 \undefined array element"
162 _ -> error "Array.!: \
163 \multiply defined array element")
164 else error "Array.array: out-of-range array association"
166 listArray :: (Ix a) => (a,a) -> [b] -> Array a b
167 listArray b vs = array b (zipWith (\ a b -> (a,b)) (range b) vs)
169 (!) :: (Ix a) => Array a b -> a -> b
170 (!) (MkArray _ f) = f
172 bounds :: (Ix a) => Array a b -> (a,a)
173 bounds (MkArray b _) = b
175 indices :: (Ix a) => Array a b -> [a]
176 indices = range . bounds
178 elems :: (Ix a) => Array a b -> [b]
179 elems a = [a!i | i <- indices a]
181 assocs :: (Ix a) => Array a b -> [(a,b)]
182 assocs a = [(i, a!i) | i <- indices a]
184 (//) :: (Ix a) => Array a b -> [(a,b)] -> Array a b
185 a // us = array (bounds a)
186 ([(i,a!i) | i <- indices a \\ [i | (i,_) <- us]]
189 accum :: (Ix a) => (b -> c -> b) -> Array a b -> [(a,c)]
191 accum f = foldl (\a (i,v) -> a // [(i,f (a!i) v)])
193 accumArray :: (Ix a) => (b -> c -> b) -> b -> (a,a) -> [(a,c)]
195 accumArray f z b = accum f (array b [(i,z) | i <- range b])
197 ixmap :: (Ix a, Ix b) => (a,a) -> (a -> b) -> Array b c
199 ixmap b f a = array b [(i, a ! f i) | i <- range b]
201 instance (Ix a) => Functor (Array a) where
202 fmap fn (MkArray b f) = MkArray b (fn . f)
204 instance (Ix a, Eq b) => Eq (Array a b) where
205 a == a' = assocs a == assocs a'
207 instance (Ix a, Ord b) => Ord (Array a b) where
208 a <= a' = assocs a <= assocs a'
210 instance (Ix a, Show a, Show b) => Show (Array a b) where
211 showsPrec p a = showParen (p > 9) (
212 showString "array " .
213 shows (bounds a) . showChar ' ' .
216 instance (Ix a, Read a, Read b) => Read (Array a b) where
217 readsPrec p = readParen (p > 9)
218 (\r -> [(array b as, u) | ("array",s) <- lex r,
221 --------------------------------------------------------------------
224 -- DRAFT implementation; last update 000104.
225 -- Koen Claessen, John Hughes.
226 -- This file represents work in progress, and might change at a later date.
229 --------------------------------------------------------------------
233 = Gen (Int -> StdGen -> a)
235 sized :: (Int -> Gen a) -> Gen a
236 sized fgen = Gen (\n r -> let Gen m = fgen n in m n r)
238 resize :: Int -> Gen a -> Gen a
239 resize n (Gen m) = Gen (\_ r -> m n r)
242 rand = Gen (\n r -> r)
244 promote :: (a -> Gen b) -> Gen (a -> b)
245 promote f = Gen (\n r -> \a -> let Gen m = f a in m n r)
247 variant :: Int -> Gen a -> Gen a
248 variant v (Gen m) = Gen (\n r -> m n (rands r !! (v+1)))
250 rands r0 = r1 : rands r2 where (r1, r2) = split r0
252 generate :: Int -> StdGen -> Gen a -> a
253 generate n rnd (Gen m) = m size rnd'
255 (size, rnd') = randomR (0, n) rnd
257 instance Functor Gen where
258 fmap f m = m >>= return . f
260 instance Monad Gen where
261 return a = Gen (\n r -> a)
263 Gen (\n r0 -> let (r1,r2) = split r0
269 --choose :: Random a => (a, a) -> Gen a
270 choose bounds = ((fst . randomR bounds) `fmap` rand)
272 elements :: [a] -> Gen a
273 elements xs = (xs !!) `fmap` choose (0, length xs - 1)
275 vector :: Arbitrary a => Int -> Gen [a]
276 vector n = sequence [ arbitrary | i <- [1..n] ]
278 oneof :: [Gen a] -> Gen a
279 oneof gens = elements gens >>= id
281 frequency :: [(Int, Gen a)] -> Gen a
282 frequency xs = choose (1, tot) >>= (`pick` xs)
284 tot = sum (map fst xs)
288 | otherwise = pick (n-k) xs
292 two :: Monad m => m a -> m (a, a)
293 two m = liftM2 (,) m m
295 three :: Monad m => m a -> m (a, a, a)
296 three m = liftM3 (,,) m m m
298 four :: Monad m => m a -> m (a, a, a, a)
299 four m = liftM4 (,,,) m m m m
301 --------------------------------------------------------------------
304 class Arbitrary a where
306 coarbitrary :: a -> Gen b -> Gen b
308 instance Arbitrary () where
309 arbitrary = return ()
310 coarbitrary _ = variant 0
312 instance Arbitrary Bool where
313 arbitrary = elements [True, False]
314 coarbitrary b = if b then variant 0 else variant 1
316 instance Arbitrary Int where
317 arbitrary = sized $ \n -> choose (-n,n)
318 coarbitrary n = variant (if n >= 0 then 2*n else 2*(-n) + 1)
320 instance Arbitrary Integer where
321 arbitrary = sized $ \n -> choose (-fromIntegral n,fromIntegral n)
322 coarbitrary n = variant (fromInteger (if n >= 0 then 2*n else 2*(-n) + 1))
324 instance Arbitrary Float where
325 arbitrary = liftM3 fraction arbitrary arbitrary arbitrary
326 coarbitrary x = coarbitrary (decodeFloat x)
328 instance Arbitrary Double where
329 arbitrary = liftM3 fraction arbitrary arbitrary arbitrary
330 coarbitrary x = coarbitrary (decodeFloat x)
332 fraction a b c = fromInteger a + (fromInteger b / (abs (fromInteger c) + 1))
334 instance (Arbitrary a, Arbitrary b) => Arbitrary (a, b) where
335 arbitrary = liftM2 (,) arbitrary arbitrary
336 coarbitrary (a, b) = coarbitrary a . coarbitrary b
338 instance (Arbitrary a, Arbitrary b, Arbitrary c) => Arbitrary (a, b, c) where
339 arbitrary = liftM3 (,,) arbitrary arbitrary arbitrary
340 coarbitrary (a, b, c) = coarbitrary a . coarbitrary b . coarbitrary c
342 instance (Arbitrary a, Arbitrary b, Arbitrary c, Arbitrary d)
343 => Arbitrary (a, b, c, d)
345 arbitrary = liftM4 (,,,) arbitrary arbitrary arbitrary arbitrary
346 coarbitrary (a, b, c, d) =
347 coarbitrary a . coarbitrary b . coarbitrary c . coarbitrary d
349 instance Arbitrary a => Arbitrary [a] where
350 arbitrary = sized (\n -> choose (0,n) >>= vector)
351 coarbitrary [] = variant 0
352 coarbitrary (a:as) = coarbitrary a . variant 1 . coarbitrary as
354 instance (Arbitrary a, Arbitrary b) => Arbitrary (a -> b) where
355 arbitrary = promote (`coarbitrary` arbitrary)
356 coarbitrary f gen = arbitrary >>= ((`coarbitrary` gen) . f)
358 --------------------------------------------------------------------
362 = Result { ok :: Maybe Bool, stamp :: [String], arguments :: [String] }
365 nothing = Result{ ok = Nothing, stamp = [], arguments = [] }
370 result :: Result -> Property
371 result res = Prop (return res)
373 evaluate :: Testable a => a -> Gen Result
374 evaluate a = gen where Prop gen = property a
376 class Testable a where
377 property :: a -> Property
379 instance Testable () where
380 property _ = result nothing
382 instance Testable Bool where
383 property b = result (nothing{ ok = Just b })
385 instance Testable Result where
386 property res = result res
388 instance Testable Property where
391 instance (Arbitrary a, Show a, Testable b) => Testable (a -> b) where
392 property f = forAll arbitrary f
394 forAll :: (Show a, Testable b) => Gen a -> (a -> b) -> Property
395 forAll gen body = Prop $
397 res <- evaluate (body a)
398 return (argument a res)
400 argument a res = res{ arguments = show a : arguments res }
402 (==>) :: Testable a => Bool -> a -> Property
403 True ==> a = property a
404 False ==> a = property ()
406 label :: Testable a => String -> a -> Property
407 label s a = Prop (add `fmap` evaluate a)
409 add res = res{ stamp = s : stamp res }
411 classify :: Testable a => Bool -> String -> a -> Property
412 classify True name = label name
413 classify False _ = property
415 trivial :: Testable a => Bool -> a -> Property
416 trivial = (`classify` "trivial")
418 collect :: (Show a, Testable b) => a -> b -> Property
419 collect v = label (show v)
421 --------------------------------------------------------------------
425 { configMaxTest :: Int
426 , configMaxFail :: Int
427 , configSize :: Int -> Int
428 , configEvery :: Int -> [String] -> String
433 { configMaxTest = 100
434 , configMaxFail = 1000
435 , configSize = (+ 3) . (`div` 2)
436 , configEvery = \n args -> let s = show n in s ++ ","
441 { configEvery = \n args -> show n ++ ":\n" ++ unlines args
444 test, quickCheck, verboseCheck :: Testable a => a -> IO ()
446 quickCheck = check quick
447 verboseCheck = check verbose
449 check :: Testable a => Config -> a -> IO ()
452 tests config (evaluate a) rnd 0 0 []
454 tests :: Config -> Gen Result -> StdGen -> Int -> Int -> [[String]] -> IO ()
455 tests config gen rnd0 ntest nfail stamps
456 | ntest == configMaxTest config = do done "OK, passed" ntest stamps
457 | nfail == configMaxFail config = do done "Arguments exhausted after" ntest stamps
459 do putStr (configEvery config ntest (arguments result))
462 tests config gen rnd1 ntest (nfail+1) stamps
464 tests config gen rnd1 (ntest+1) nfail (stamp result:stamps)
466 putStr ( "Falsifiable, after "
469 ++ unlines (arguments result)
472 result = generate (configSize config ntest) rnd2 gen
473 (rnd1,rnd2) = split rnd0
475 done :: String -> Int -> [[String]] -> IO ()
476 done mesg ntest stamps =
477 do putStr ( mesg ++ " " ++ show ntest ++ " tests" ++ table )
486 . filter (not . null)
490 display [x] = " (" ++ x ++ ").\n"
491 display xs = ".\n" ++ unlines (map (++ ".") xs)
493 pairLength xss@(xs:_) = (length xss, xs)
494 entry (n, xs) = percentage n ntest
496 ++ concat (intersperse ", " xs)
498 percentage n m = show ((100 * n) `div` m) ++ "%"
500 --------------------------------------------------------------------
504 instance Observable StdGen where { observer = observeBase }
506 instance Observable a => Observable (Gen a) where
507 observer (Gen a) = send "Gen" (return (Gen) << a)