mirror of
https://github.com/iritmaximus/haskell.git
synced 2026-10-12 19:13:39 +03:00
230 lines
8.6 KiB
Haskell
230 lines
8.6 KiB
Haskell
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, StandaloneDeriving #-}
|
|
|
|
module Set13aTest where
|
|
|
|
import Mooc.Test
|
|
import Mooc.Th
|
|
|
|
import Control.Monad.State
|
|
import Data.Char
|
|
import Data.List
|
|
import qualified Data.Map as Map
|
|
import Test.QuickCheck
|
|
|
|
import Examples.Bank
|
|
import Set13a
|
|
|
|
main = score tests
|
|
|
|
tests = [(1,"readNames",[ex1_ok, ex1_fail])
|
|
,(2,"winner",[ex2_small, ex2_big, ex2_fail])
|
|
,(3,"selectSum",[ex3_ok, ex3_fail])
|
|
,(4,"countAndLog",[ex4])
|
|
,(5,"balance",[ex5_balance_examples, ex5_balance_ok, ex5_balance_nok])
|
|
,(6,"rob",[ex6_rob_examples, ex6_rob])
|
|
,(7,"State update",[ex7])
|
|
,(8,"parensMatch",[ex8_paren, ex8_parensMatch])
|
|
,(9,"State count",[ex9])
|
|
,(10,"State occurrences",[ex10_1, ex10_2])
|
|
]
|
|
|
|
-- -- -- -- -- -- --
|
|
|
|
word = do fst <- choose ('A','Z')
|
|
rest <- listOf (choose ('a','z'))
|
|
return $ fst:rest
|
|
|
|
bad = do a <- choose ('A','Z')
|
|
b <- word
|
|
c <- elements "0123456789"
|
|
d <- word
|
|
return $ a:b++c:d
|
|
|
|
ex1_ok =
|
|
forAllBlind word $ \for ->
|
|
forAllBlind word $ \sur ->
|
|
let str = for++" "++sur
|
|
in $(testing [|readNames str|])
|
|
(?==Just (for,sur))
|
|
|
|
m_ex1_fail s =
|
|
$(testing [|readNames s|]) (?== Nothing)
|
|
|
|
ex1_fail =
|
|
forAllBlind word $ \for ->
|
|
forAllBlind word $ \sur ->
|
|
forAllBlind bad $ \b ->
|
|
conjoin [m_ex1_fail (for ++ sur),
|
|
m_ex1_fail (map toLower for ++ " " ++ sur),
|
|
m_ex1_fail (for ++ " " ++ map toLower sur),
|
|
m_ex1_fail (for ++ b ++ " " ++ sur),
|
|
m_ex1_fail (for ++ " " ++ sur ++ b)]
|
|
|
|
ex2_small =
|
|
forAllBlind word $ \p1 ->
|
|
forAllBlind (word `suchThat` (/=p1)) $ \p2 ->
|
|
forAllBlind (choose (1,20)) $ \s1 ->
|
|
forAllBlind (choose (0,s1)) $ \s2 ->
|
|
forAllBlind (shuffle [(p1,s1),(p2,s2)]) $ \inp ->
|
|
conjoin [$(testing [|winner inp p1 p2|]) (?==Just p1)
|
|
,s2 < s1 ==> $(testing [|winner inp p2 p1|]) (?==Just p1)]
|
|
|
|
ex2_big =
|
|
forAllBlind word $ \w ->
|
|
forAllBlind (choose (10,100)) $ \s ->
|
|
forAllBlind (nub <$> listOf1 (word`suchThat`(/=w))) $ \names ->
|
|
forAllBlind (vectorOf (length names) (choose (0,s-1))) $ \scores ->
|
|
forAllBlind (elements names) $ \other ->
|
|
forAllBlind (shuffle ((w,s):zip names scores)) $ \inp ->
|
|
conjoin [$(testing [|winner inp other w|]) (?==Just w)
|
|
,$(testing [|winner inp w other|]) (?==Just w)]
|
|
|
|
ex2_fail =
|
|
forAllBlind (nub <$> listOf1 word) $ \names ->
|
|
forAllBlind (vectorOf (length names) (choose (0,100))) $ \scores ->
|
|
forAllBlind (elements names) $ \ok ->
|
|
forAllBlind (word `suchThat` (not.flip elem names)) $ \nok1 ->
|
|
forAllBlind (word `suchThat` (not.flip elem names)) $ \nok2 ->
|
|
let inp = zip names scores
|
|
in conjoin $[$(testing [|winner inp ok nok1|]) (?==Nothing)
|
|
,$(testing [|winner inp nok1 ok|]) (?==Nothing)
|
|
,$(testing [|winner inp nok1 nok2|]) (?==Nothing)]
|
|
|
|
ex3_ok = forAll_ $ \(as::[Int]) ->
|
|
forAllBlind (shuffle (zip [0..] as)) $ \pairs ->
|
|
forAllShrink_ (sublistOf pairs) $ \selected ->
|
|
$(testing [|selectSum as (map fst selected)|]) (?==Just (sum $ map snd selected))
|
|
|
|
ex3_fail = property $ do
|
|
as <- arbitrary :: Gen [Int]
|
|
is <- listOf (choose (0,length as - 1))
|
|
b <- elements [-1,length as]
|
|
inp <- shuffle (b:is)
|
|
return $ $(testing [|selectSum as inp|]) (?==Nothing)
|
|
|
|
ex4 = property $ do
|
|
i <- choose (0::Int,10)
|
|
is <- listOf (choose (0,10) `suchThat` (/=i))
|
|
n <- choose (0,5)
|
|
input <- shuffle (replicate n i ++ is)
|
|
return $ counterexample ("countAndLog (=="++show i++") "++show input) $
|
|
countAndLog (==i) input ?== Logger (replicate n (show i)) n
|
|
|
|
ex5_balance_examples =
|
|
conjoin [$(testing' [|runBankOp (balance "harry") exampleBank|]) (?==(10,exampleBank))
|
|
,$(testing' [|runBankOp (balance "sean") exampleBank|]) (?==(0,exampleBank))]
|
|
|
|
bank = do
|
|
names <- nub <$> listOf1 word
|
|
bals <- vectorOf (length names) (choose (0,100))
|
|
return $ Map.fromList (zip names bals)
|
|
|
|
ex5_balance_ok = forAllBlind bank $ \b ->
|
|
forAllBlind (elements (Map.keys b)) $ \account ->
|
|
let bank = Bank b
|
|
in $(testing' [|runBankOp (balance account) bank|]) $ \out ->
|
|
counterexample (" with bank = " ++ show bank++"\n account = "++show account) $
|
|
out?==(b Map.! account, bank)
|
|
|
|
ex5_balance_nok = forAllBlind bank $ \b ->
|
|
forAllBlind (word `suchThat` (not.flip elem (Map.keys b))) $ \account ->
|
|
let bank = Bank b
|
|
in $(testing' [|runBankOp (balance account) bank|]) $ \out ->
|
|
counterexample (" with bank = " ++ show bank++"\n account = "++show account) $
|
|
out?==(0,bank)
|
|
|
|
ex6_rob_examples =
|
|
conjoin [$(testing' [|runBankOp (rob "cedric" "ginny") exampleBank|])
|
|
(?==((),Bank (Map.fromList [("cedric",0),("ginny",8),("harry",10)])))
|
|
,$(testing' [|runBankOp (rob "sean" "ginny") exampleBank|])
|
|
(?==((),Bank (Map.fromList [("cedric",7),("ginny",1),("harry",10)])))]
|
|
|
|
ex6_rob = property $ do
|
|
from <- word
|
|
to <- word `suchThat` (/=from)
|
|
others <- listOf (word `suchThat` (not.flip elem [from,to]))
|
|
balf <- choose (0,100)
|
|
balt <- choose (0,100)
|
|
bals <- vectorOf (length others) (choose (0,100))
|
|
let run from to bank exp = $(testing' [|runBankOp (rob from to) bank|]) $ \out ->
|
|
counterexample (" with bank = " ++ show bank++"\n from = "++show from++"\n to = "++show to) $
|
|
out ?== ((),exp)
|
|
return $ conjoin [run from to
|
|
(Bank . Map.fromList $ (from,balf):(to,balt):zip others bals)
|
|
(Bank . Map.fromList $ (from,0):(to,balf+balt):zip others bals)
|
|
,run from to
|
|
(Bank . Map.fromList $ (to,balt):zip others bals)
|
|
(Bank . Map.fromList $ (to,balt):zip others bals)]
|
|
|
|
ex7 = forAll_ $ \i ->
|
|
counterexample ("runState update "++show i) $
|
|
runState update i ?== ((),2*i+1)
|
|
|
|
ex8_paren =
|
|
forAll_ $ \(NonNegative i) ->
|
|
conjoin [counterexample ("runState (paren '(') "++show i) $
|
|
runState (paren '(') i ?== ((),i+1)
|
|
,counterexample ("runState (paren ')') "++show i) $
|
|
runState (paren ')') i ?== ((),i-1)
|
|
,$(testing' [|runState (paren '(') (-1)|]) (?==((),-1))
|
|
,$(testing' [|runState (paren ')') (-1)|]) (?==((),-1))]
|
|
|
|
genMatch = frequency [(3,return "()"),
|
|
(1,(\x -> "("++x++")") <$> genMatch),
|
|
(1,(++) <$> genMatch <*> genMatch)]
|
|
|
|
flop ')' = '('
|
|
flop '(' = ')'
|
|
|
|
breakMatch s = do i <- choose (0,length s - 1)
|
|
let (pre,x:suf) = splitAt i s
|
|
elements [pre++suf, pre++flop x:suf]
|
|
|
|
filterMatch s = do x <- elements "()"
|
|
n <- choose (1,length s)
|
|
return $ s \\ replicate n x
|
|
|
|
ex8_parensMatch =
|
|
forAllBlind genMatch $ \match ->
|
|
conjoin [$(testing [|parensMatch match|]) (?==True)
|
|
,forAllBlind (breakMatch match) $ \broken -> $(testing [|parensMatch broken|]) (?==False)
|
|
,forAllBlind (filterMatch match) $ \broken -> $(testing [|parensMatch broken|]) (?==False)]
|
|
|
|
ex9 = property $ do
|
|
is <- fmap nub $ listOf1 (choose ('a','z') :: Gen Char)
|
|
fs <- vectorOf (length is) (choose (1,2048))
|
|
let assocs = zip is fs
|
|
x <- elements is
|
|
y <- choose ('0','z') `suchThat` \y -> not (elem y is)
|
|
let Just cx = lookup x assocs
|
|
s x = counterexample ("runState (count "++show x++") "++show assocs) . counterexample " Final state"
|
|
return $ conjoin [s y $
|
|
hasElements ((y,1):assocs) (execState (count y) assocs)
|
|
,s x $
|
|
hasElements ((x,cx+1):delete (x,cx) assocs) (execState (count x) assocs)]
|
|
|
|
ex10_1 =
|
|
forAllShrink_ (nub <$> listOf (choose ('a','z'))) $ \cs ->
|
|
forAllBlind (vectorOf (length cs) (choose (1,3))) $ \ns ->
|
|
let expanded = concat (zipWith replicate ns cs)
|
|
in forAllBlind (shuffle expanded) $ \input ->
|
|
counterexample ("runState (occurrences "++show input++") []") $
|
|
let out@(x,s) = runState (occurrences input) []
|
|
in counterexample (" Was: " ++ show out) $
|
|
conjoin [counterexample "Produced value" $ x ?== length cs
|
|
,counterexample "Final state" $ hasElements (zip cs ns) s]
|
|
|
|
ex10_2 =
|
|
forAllShrink_ (nub <$> listOf (choose (10,100))) $ \xs ->
|
|
forAllBlind (vectorOf (length xs) (choose (1,3))) $ \ns ->
|
|
forAllBlind (choose (0::Int,9)) $ \x ->
|
|
forAllBlind (choose (1,20)) $ \n0 ->
|
|
forAllBlind (choose (1,20)) $ \n ->
|
|
let state = zip xs ns++[(x,n0)]
|
|
input = replicate n x
|
|
in counterexample ("runState (occurrences "++show input++") "++show state) $
|
|
let out@(ret,s) = runState (occurrences input) state
|
|
in counterexample (" Was: " ++ show out) $
|
|
conjoin [counterexample "Produced value" $ ret ?== length xs + 1
|
|
,counterexample "Final state" $ hasElements ((x,n+n0):zip xs ns) s]
|