-
Notifications
You must be signed in to change notification settings - Fork 120
Expand file tree
/
Copy pathtest.hs
More file actions
143 lines (128 loc) · 5.14 KB
/
test.hs
File metadata and controls
143 lines (128 loc) · 5.14 KB
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
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Control.Concurrent (threadDelay)
import Test.Tasty
import Test.Tasty.Options
import Test.Tasty.Providers as Tasty
import Test.Tasty.Runners as Tasty
import Test.Tasty.QuickCheck
import Test.Tasty.HUnit
import Test.QuickCheck.Random (QCGen)
import Text.Printf
import qualified Text.Regex.TDFA as Regex
(=~), (!~)
:: String -- ^ text
-> String -- ^ regex
-> Assertion
text =~ regexStr =
let
msg = printf "Expected /%s/, got %s" regexStr (show text)
-- NB show above the intentional -- to add quotes around the string and
-- escape newlines etc.
in assertBool msg $ text Regex.=~ regexStr
text !~ regexStr =
let
msg = printf "Did not expect /%s/, got %s" regexStr (show text)
in assertBool msg $ not $ text Regex.=~ regexStr
main :: IO ()
main =
defaultMain $
testGroup "Unit tests for Test.Tasty.QuickCheck"
[ testCase "Success" $ do
Result{..} <- run' $ \x -> x >= (x :: Int)
-- there is no instance Show Outcome(
-- (because there is no instance Show SomeException),
-- so we can't use @?= for this
case resultOutcome of
Tasty.Success -> return ()
_ -> assertFailure $ show resultOutcome
resultDescription =~ "OK, passed 100 tests"
resultDescription !~ "Use .* to reproduce"
, testCase "Success, replay requested" $ do
Result{..} <- runReplay $ \x -> x >= (x :: Int)
-- there is no instance Show Outcome(
-- (because there is no instance Show SomeException),
-- so we can't use @?= for this
case resultOutcome of
Tasty.Success -> return ()
_ -> assertFailure $ show resultOutcome
resultDescription =~ "OK, passed 100 tests"
resultDescription =~ "Use .* to reproduce"
, testCase "Unexpected failure" $ do
Result{..} <- run' $ \x -> x > (x :: Int)
case resultOutcome of
Tasty.Failure {} -> return ()
_ -> assertFailure $ show resultOutcome
resultDescription =~ "Failed"
resultDescription =~ "Use .* to reproduce"
, testCase "Replay unexpected failure" $ do
Result{..} <- runMaxSized 3 $ \x -> x /= (2 :: Int)
case resultOutcome of
Tasty.Failure {} -> return ()
_ -> assertFailure $ show resultOutcome
resultDescription =~ "Failed"
resultDescription =~ "Use --quickcheck-replay=.* to reproduce."
let firstResultDescription = resultDescription
Just seedSz <- return (parseSeed resultDescription)
Result{..} <- runReplayWithSeed seedSz $ \x -> x /= (2 :: Int)
case resultOutcome of
Tasty.Failure {} -> return ()
_ -> assertFailure $ show resultOutcome
resultDescription =~ "Failed"
-- Compare the last lines reporting the replay seed.
let lastLine = concat . take 1 . reverse . lines
lastLine resultDescription =~ "Use --quickcheck-replay=.* to reproduce."
lastLine resultDescription @?= lastLine firstResultDescription
-- Exactly one test is executed
resultDescription =~ "Falsified \\(after 1 test\\)"
, testCase "Gave up" $ do
Result{..} <- run' $ \x -> x > x ==> x > (x :: Int)
case resultOutcome of
Tasty.Failure {} -> return ()
_ -> assertFailure $ show resultOutcome
resultDescription =~ "Gave up"
resultDescription =~ "Use .* to reproduce"
, testCase "No expected failure" $ do
Result{..} <- run' $ expectFailure $ \x -> x >= (x :: Int)
case resultOutcome of
Tasty.Failure {} -> return ()
_ -> assertFailure $ show resultOutcome
resultDescription =~ "Failed.*expected failure"
resultDescription =~ "Use .* to reproduce"
-- Run the test suite manually and check that progress does not go beyond 100%
, testProperty "Percent Complete" $
withNumTests 1000 $ \(_ :: Int) -> ioProperty $ threadDelay 10000
, testProperty "Number of shrinks" $
expectFailure $ withMaxSize 1000 $ \(Large (x :: Int)) ->
ioProperty $ threadDelay 100000 >> pure (x <= 100)
]
run' :: Testable p => p -> IO Result
run' p =
run
mempty -- options
(QC $ property p)
(const $ return ()) -- callback
runReplay :: Testable p => p -> IO Result
runReplay p =
run
(singleOption $ QuickCheckShowReplay True)
(QC $ property p)
(const $ return ())
runMaxSized :: Testable p => Int -> p -> IO Result
runMaxSized sz p =
run
(singleOption $ QuickCheckMaxSize sz)
(QC $ property p)
(const $ return ())
runReplayWithSeed :: Testable p => (QCGen, Int) -> p -> IO Result
runReplayWithSeed seedSz p =
run
(singleOption $ QuickCheckReplay seedSz)
(QC $ property p)
(const $ return ())
-- | Reads a seed from a message like
--
-- > "Use --quickcheck-single-replay=\"(SMGen 2909028190965759779 12330386376379709109,0)\" to reproduce."
--
parseSeed :: String -> Maybe (QCGen, Int)
parseSeed = safeRead . takeWhile (/= '\"') . drop 1 . dropWhile (/='\"')