mirror of
https://github.com/iritmaximus/haskell.git
synced 2026-10-12 19:13:39 +03:00
236 lines
8.5 KiB
Haskell
236 lines
8.5 KiB
Haskell
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
|
|
|
|
module Set4aTest where
|
|
|
|
import Control.Monad
|
|
import Data.Array
|
|
import Data.List
|
|
import qualified Data.Map as Map
|
|
import Test.QuickCheck
|
|
|
|
import Mooc.Th
|
|
import Mooc.Test
|
|
|
|
import Set4a
|
|
|
|
main = score tests
|
|
|
|
tests = [(1,"allEqual",[ex1, ex1_one])
|
|
,(2,"distinct",[ex2_int, ex2_char])
|
|
,(3,"middle",[ex3_char, ex3_int])
|
|
,(4,"rangeOf",[ex4_int, ex4_integer, ex4_double])
|
|
,(5,"longest",[ex5_int, ex5_char])
|
|
,(6,"incrementKey",[ex6_bool_float, ex6_char_int])
|
|
,(7,"average",[ex7])
|
|
,(8,"winner",[ex8_winner, ex8_tie])
|
|
,(9,"freqs",[ex9_bool, ex9_int])
|
|
,(10,"transfer",[ex10_success, ex10_missing, ex10_notEnough])
|
|
,(11,"swap",[ex11_swap_small, ex11_swap_large])
|
|
,(12,"maxIndex",[ex12_bool, ex12_int])]
|
|
|
|
-- -- -- -- -- -- -- --
|
|
|
|
m_ex1_true example = forAll_ $ \(cnt,v) ->
|
|
$(testing [|allEqual (replicate cnt (v `asTypeOf` example))|]) (?==True)
|
|
m_ex1_false example = forAll_ $ \(v,NonEmpty vs) ->
|
|
not (elem (v `asTypeOf` example) vs) ==> $(testing [|allEqual (v:vs)|]) (?==False)
|
|
|
|
ex1 = conjoin [m_ex1_true True
|
|
,m_ex1_true 'a'
|
|
,m_ex1_false 'a'
|
|
,m_ex1_true (1::Int)
|
|
,m_ex1_false (1::Int)]
|
|
|
|
ex1_one = forAll_ $ \(Positive cnt,x::Int,y) ->
|
|
forAllBlind (shuffle (y:replicate cnt x)) $ \xs ->
|
|
x /= y ==>
|
|
$(testing [|allEqual xs|]) (?==False)
|
|
|
|
m_ex2 domain = forAllBlind (sublistOf domain) $ \xs ->
|
|
conjoin [forAllBlind (shuffle xs) $ \xs' -> $(testing [|distinct xs'|]) (?==True)
|
|
,not (null xs) ==> forAllBlind (shuffle (head xs:xs)) $ \xs' -> $(testing [|distinct xs'|]) (?==False)]
|
|
|
|
ex2_int = m_ex2 [1::Int,2,3,4]
|
|
|
|
ex2_char = m_ex2 ['a'..'z']
|
|
|
|
|
|
|
|
m_ex3 c =
|
|
let d = succ c
|
|
e = succ d
|
|
in forAllBlind (shuffle [c,d,e]) $ \[x,y,z] ->
|
|
$(testing [|middle x y z|]) (?==d)
|
|
|
|
ex3_char = forAllBlind (choose ('a','y')) m_ex3
|
|
ex3_int = forAllBlind (choose (0::Int,20)) m_ex3
|
|
|
|
genRangeOf delta = do
|
|
base <- arbitrary
|
|
vs <- listOf1 (choose (base, base+delta))
|
|
shuffle (base:base+delta:vs)
|
|
|
|
m_ex4 delta = forAllBlind (genRangeOf delta) $ \vs ->
|
|
$(testing [|rangeOf vs|]) (?==delta)
|
|
|
|
ex4_int = forAllBlind (choose (1::Int,10)) m_ex4
|
|
ex4_integer = forAllBlind (choose (1::Integer,10)) m_ex4
|
|
ex4_double = property $ do
|
|
delta <- elements [1::Int,3,5,7,9]
|
|
vs <- genRangeOf delta
|
|
return $ $(testing [|rangeOf (map conv vs)|]) (?~=conv delta)
|
|
where conv x = fromIntegral x / 2
|
|
|
|
ex5_int =
|
|
forAllBlind (choose (2,10)) $ \l ->
|
|
forAllBlind (vectorOf l (arbitrary :: Gen Int)) $ \ans ->
|
|
forAllBlind (listOf (choose (1,l - 1) >>= vector)) $ \rest ->
|
|
forAllBlind (shuffle (ans:rest)) $ \input ->
|
|
$(testing [|longest input|]) (?==ans)
|
|
|
|
ex5_char = property $ do
|
|
c <- choose ('a','k')
|
|
d <- choose ('a','z') `suchThat` (>c)
|
|
len <- choose (1,3)
|
|
crest <- vectorOf len (choose ('a','z'))
|
|
drest <- vectorOf len (choose ('a','z'))
|
|
wrong <- vectorOf len (choose ('a','z'))
|
|
input <- shuffle [c:crest, d:drest, wrong]
|
|
return $ $(testing [|longest input|]) (?==(c:crest))
|
|
|
|
ex6_bool_float =
|
|
property $ do
|
|
c <- choose (True,False)
|
|
let f i = fromIntegral i + 0.5
|
|
i <- f <$> choose (0,10::Int)
|
|
j <- f <$> choose (0,10::Int)
|
|
let inp = [(c,i),(c,j)]
|
|
return $ $(testing [|incrementKey c inp|]) (?==[(c,i+1),(c,j+1)])
|
|
|
|
ex6_char_int =
|
|
property $ do
|
|
is <- vectorOf 5 $ choose (0,20::Int)
|
|
ks <- vectorOf 5 $ choose ('a','g')
|
|
c <- choose ('a','h')
|
|
let inp = zip ks is
|
|
out = zipWith (\k i -> if k==c then (k,succ i) else (k,i)) ks is
|
|
return $ $(testing [|incrementKey c inp|]) (?== out)
|
|
|
|
|
|
|
|
ex7 = conjoin [forAll_ $ \(Small i) -> $(testing [|average [fromIntegral i :: Float]|]) (?==fromIntegral i)
|
|
,forAllBlind (choose (1,10)) $ \n -> forAll_ $ \(i::Rational) ->
|
|
$(testing [|average (replicate n i)|]) (?==i)
|
|
,forAll_ $ \(Small i) -> let f = fromIntegral i in $(testing [|average [f-1,f,f+1]|]) (?==f)
|
|
,forAll_ $ \(Small i,Small j) ->
|
|
let x = fromIntegral i :: Double
|
|
y = fromIntegral j :: Double
|
|
in $(testing [|average (replicate 10 x ++ replicate 10 y)|]) (?~=(x+y)/2)]
|
|
|
|
ex8_winner = property $
|
|
do names <- shuffle ["Mike","Bob","Lisa","Jane"]
|
|
let (win:lose:third:_) = names
|
|
loseScore <- choose (0,10000)
|
|
diff <- choose (1,100)
|
|
thirdScore <- choose (0,20000)
|
|
let inp = Map.fromList [(win,loseScore+diff),(lose,loseScore),(third,thirdScore)]
|
|
return $ conjoin [$(testing [|winner inp win lose|]) (?==win)
|
|
,$(testing [|winner inp lose win|]) (?==win)]
|
|
|
|
ex8_tie = property $
|
|
do names <- shuffle ["Mike","Bob","Lisa","Jane"]
|
|
let (first:second:third:_) = names
|
|
score <- choose (0,10000)
|
|
thirdScore <- choose (0,20000)
|
|
let inp = Map.fromList [(first,score),(second,score),(third,thirdScore)]
|
|
return $ $(testing [|winner inp first second|]) (?==first)
|
|
|
|
ex9_bool = forAllBlind (choose (0,10)) $ \n ->
|
|
forAllBlind (vectorOf n arbitrary) $ \bs ->
|
|
$(testing [|freqs bs|]) . was $ \m ->
|
|
let (t,f) = partition id bs
|
|
ntrue = length t
|
|
nfalse = length f
|
|
out = Map.assocs m
|
|
in conjoin [counterexample (" Number of True values should be "++show ntrue) $
|
|
null t || (True,ntrue) `elem` out
|
|
,counterexample (" Number of False values should be "++show nfalse) $
|
|
null f || (False,nfalse) `elem` out]
|
|
|
|
ex9_int = forAllBlind (choose (0,15)) $ \n ->
|
|
forAllBlind (vectorOf n arbitrary) $ \(is::[Int]) ->
|
|
$(testing [|freqs is|]) . was $ \out ->
|
|
let vals = nub is
|
|
in counterexample " Number of keys" (length (Map.keys out) ?== length vals)
|
|
.&&.
|
|
conjoin (map (ck out is) vals)
|
|
where ck out vals i = let exp = length (filter (==i) vals)
|
|
in counterexample (" Should contain "++show(i,exp)) $ (i,exp) `elem` (Map.assocs out)
|
|
|
|
ex10_success = property $
|
|
do names <- shuffle ["Mike","Bob","Lisa","Jane"]
|
|
let (from:to:third:_) = names
|
|
fromBal <- choose (0,100)
|
|
toBal <- choose (0,100)
|
|
thirdBal <- choose (0,100)
|
|
amount <- choose (0,100)
|
|
let inp = Map.fromList [(from,fromBal+amount),(to,toBal),(third,thirdBal)]
|
|
let out = Map.fromList [(from,fromBal),(to,toBal+amount),(third,thirdBal)]
|
|
return $ $(testing [|transfer from to amount inp|]) (?==out)
|
|
|
|
ex10_missing = property $
|
|
do names <- shuffle ["Mike","Bob","Lisa","Jane"]
|
|
let (present:missing:third:_) = names
|
|
bal <- oneof [return 0, choose (0,100)]
|
|
thirdBal <- choose (0,100)
|
|
amount <- choose (0,100)
|
|
let inp = Map.fromList [(present,bal),(third,thirdBal)]
|
|
return $ conjoin [$(testing [|transfer present missing amount inp|]) (?==inp)
|
|
,$(testing [|transfer missing present amount inp|]) (?==inp)]
|
|
|
|
ex10_notEnough = property $
|
|
do names <- shuffle ["Mike","Bob","Lisa","Jane"]
|
|
let (from:to:third:_) = names
|
|
fromBal <- choose (0,100)
|
|
toBal <- choose (0,100)
|
|
thirdBal <- choose (0,100)
|
|
amount <- choose (1,100)
|
|
let inp = Map.fromList [(from,fromBal),(to,toBal),(third,thirdBal)]
|
|
return $ conjoin [$(testing [|transfer from to (fromBal+amount) inp|]) (?==inp)
|
|
,$(testing [|transfer from to (negate amount) inp|]) (?==inp)]
|
|
|
|
ex11_swap_small = property $
|
|
do a <- choose ('a','z')
|
|
b <- choose ('a','z')
|
|
i <- choose (0,10::Int)
|
|
let inp = listArray (i,i+1) [a,b]
|
|
out = listArray (i,i+1) [b,a]
|
|
return $ $(testing [|swap i (i+1) inp|]) (?==out)
|
|
|
|
|
|
ex11_swap_large = property $
|
|
do base <- choose (0,10::Int)
|
|
len <- choose (3,6::Int)
|
|
let max = base+len-1
|
|
vals <- shuffle (take len [0..])
|
|
~(i:j:_) <- shuffle [base..max]
|
|
let vi = vals !! (i-base)
|
|
let vj = vals !! (j-base)
|
|
let inp = listArray (base,max) (vals::[Int])
|
|
let out = listArray (base,max) (map (\x -> if x==vi then vj else if x == vj then vi else x) vals)
|
|
return $ $(testing [|swap i j inp|]) (?==out)
|
|
|
|
ex12_bool = property $
|
|
do small <- choose (0,100::Int)
|
|
diff <- choose (1,100)
|
|
return $ conjoin [$(testing [|maxIndex (array (False,True) [(False,small),(True,small+diff)])|]) (?==True)
|
|
,$(testing [|maxIndex (array (False,True) [(True,small),(False,small+diff)])|]) (?==False)]
|
|
|
|
ex12_int = property $
|
|
do low <- choose (0,100::Int)
|
|
hi <- choose (low+1,low+10)
|
|
mid <- choose (low,hi)
|
|
val <- choose (0,100::Int)
|
|
let inp = array (low,hi) [(i,if i==mid then val+1 else val) | i <- [low..hi]]
|
|
return $ $(testing [|maxIndex inp|]) (?==mid)
|