Skip to content

Commit 4ded7fc

Browse files
committed
Hedgehog Integration (WIP)
1 parent 0008eab commit 4ded7fc

File tree

5 files changed

+274
-118
lines changed

5 files changed

+274
-118
lines changed

clash-testbench/src/Clash/Testbench/Generate.hs

+78-36
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ Maintainer: QBayLogic B.V. <[email protected]>
66
Use generators to create signal data.
77
-}
88

9+
{-# LANGUAGE RecursiveDo #-}
10+
{-# LANGUAGE OverloadedStrings #-}
911
module Clash.Testbench.Generate where
1012

1113
import Hedgehog
@@ -25,27 +27,29 @@ import Clash.Testbench.Internal.Monad
2527
generate ::
2628
forall dom a.
2729
(NFDataX a, BitPack a, KnownDomain dom) =>
28-
a -> Gen a -> TB (TBSignal dom a)
29-
generate def gen = do
30+
Gen a -> TB (TBSignal dom a)
31+
generate gen = do
3032
TBDomain{..} <- tbDomain @dom
3133

32-
vRef <- liftIO $ newIORef def
33-
simStepCache <- liftIO (readIORef simStepRef >>= newIORef)
34+
vRef <- liftIO $ newIORef undefined
35+
checkForProgress <- progressCheck simStepRef True
36+
signalHistory <- newHistory
3437

3538
mind SomeSignal IOInput
3639
{ signalId = NoID
3740
, signalCurVal = const $ do
38-
v <- readIORef simStepRef
39-
v' <- readIORef simStepCache
41+
progress <- checkForProgress
4042

41-
if v == v'
42-
then readIORef vRef
43-
else do
43+
if progress
44+
then do
4445
x <- sample gen
4546
writeIORef vRef x
46-
writeIORef simStepCache v
47+
memorize signalHistory x
4748
return x
49+
else
50+
readIORef vRef
4851
, signalPrint = Nothing
52+
,..
4953
}
5054

5155
-- | Extended version of 'generate', which allows to generate a finite
@@ -60,32 +64,33 @@ generateN def gen = do
6064
TBDomain{..} <- tbDomain @dom
6165

6266
vRef <- liftIO $ newIORef [def]
63-
simStepCache <- liftIO (readIORef simStepRef >>= newIORef)
67+
checkForProgress <- progressCheck simStepRef False
68+
signalHistory <- newHistory
6469

6570
mind SomeSignal IOInput
6671
{ signalId = NoID
6772
, signalCurVal = const $ do
68-
v <- readIORef simStepRef
69-
v' <- readIORef simStepCache
70-
71-
if v == v'
72-
then readIORef vRef >>= \case
73-
x : _ -> return x
74-
[] -> do
75-
x : xr <- sample gen
76-
writeIORef vRef (x : xr)
77-
return x
73+
progress <- checkForProgress
7874

79-
else do
80-
writeIORef simStepCache v
75+
if progress
76+
then
8177
readIORef vRef >>= \case
82-
_ : x : xr -> do
78+
h : x : xr -> do
79+
memorize signalHistory h
8380
writeIORef vRef (x : xr)
8481
return x
85-
_ -> do
82+
[h] -> do
83+
memorize signalHistory h
8684
x : xr <- sample gen
8785
writeIORef vRef (x : xr)
8886
return x
87+
_ -> error "unreachable"
88+
else readIORef vRef >>= \case
89+
x : _ -> return x
90+
[] -> do
91+
x : xr <- sample gen
92+
writeIORef vRef (x : xr)
93+
return x
8994
, signalPrint = Nothing
9095
, ..
9196
}
@@ -102,6 +107,7 @@ matchIOGen expectedOutput gen = do
102107

103108
vRef <- liftIO $ newIORef undefined
104109
checkForProgress <- progressCheck simStepRef False
110+
signalHistory <- newHistory
105111

106112
mind SomeSignal $ IOInput
107113
{ signalId = NoID
@@ -119,6 +125,7 @@ matchIOGen expectedOutput gen = do
119125
else
120126
readIORef vRef
121127
, signalPrint = Nothing
128+
, ..
122129
}
123130

124131
where
@@ -138,35 +145,40 @@ matchIOGenN ::
138145
forall dom i o.
139146
(NFDataX i, BitPack i, KnownDomain dom, Eq o, Show o, Show i) =>
140147
TBSignal dom o -> Gen [(i, o)] -> TB (TBSignal dom i)
141-
matchIOGenN expectedOutput gen = do
148+
matchIOGenN checkedOutput gen = mdo
142149
TBDomain{..} <- tbDomain @dom
143150

144151
xs <- liftIO $ sample gen
145152
modify $ \st@ST{..} -> st { simSteps = max simSteps $ length xs }
153+
liftIO $ Prelude.print xs
146154

147155
vRef <- liftIO $ newIORef xs
148156
checkForProgress <- progressCheck simStepRef False
157+
signalHistory <- newHistory
149158

150-
mind SomeSignal $ IOInput
159+
s <- mind SomeSignal $ IOInput
151160
{ signalId = NoID
152161
, signalCurVal = const $ do
153162
progress <- checkForProgress
154163

155164
readIORef vRef >>=
156165
if progress
157166
then \case
158-
_ : (i, o) : xr -> do
167+
(h, _) : (i, o) : xr -> do
168+
memorize signalHistory h
159169
writeIORef vRef ((i, o) : xr)
160170
curStep <- readIORef simStepRef
161-
signalExpect expectedOutput $ Expectation (curStep, verify o)
171+
signalExpect checkedOutput $ Expectation (curStep, verify s i o)
162172
return i
163-
_ -> do
173+
[(h, _)] -> do
174+
memorize signalHistory h
164175
(i, o) : xr <- sample gen
165176

166177
writeIORef vRef ((i, o) : xr)
167178
curStep <- readIORef simStepRef
168-
signalExpect expectedOutput $ Expectation (curStep, verify o)
179+
signalExpect checkedOutput $ Expectation (curStep, verify s i o)
169180
return i
181+
_ -> error "unreachable"
170182
else \case
171183
(i, _) : _ -> return i
172184
[] -> do
@@ -175,11 +187,41 @@ matchIOGenN expectedOutput gen = do
175187
Prelude.print $ (i, o) : xr
176188
return i
177189
, signalPrint = Nothing
190+
, ..
178191
}
179192

193+
return s
194+
180195
where
181-
verify x y = do
182-
when (x /= y)
183-
$ footnote
184-
$ "Expected '" <> show x <> "' but the output is '" <> show y <> "'"
185-
x === x
196+
verify generatedInput currentInput expectedOutput observedOutput = do
197+
when (expectedOutput /= observedOutput) $ do
198+
xs <-
199+
(<> [(currentInput, observedOutput)])
200+
<$> (zip <$> history generatedInput <*> history checkedOutput)
201+
202+
let
203+
cHeading = "Cycle"
204+
iHeading = "Input"
205+
oHeading = "Output"
206+
cLen = length cHeading
207+
iLen = maximum $ (length iHeading :) $ fmap (length . show . fst) xs
208+
oLen = maximum $ (length oHeading :) $ fmap (length . show . snd) xs
209+
210+
footnote $ unlines $
211+
[ "Expected to see the output '" <> show expectedOutput <> "',"
212+
, "but the observed output is '" <> show observedOutput <> "'."
213+
, ""
214+
, "I/O History:"
215+
, ""
216+
, cHeading <>
217+
replicate (iLen - length iHeading + 2) ' ' <> iHeading <>
218+
replicate (oLen - length oHeading + 2) ' ' <> oHeading
219+
, replicate (cLen + iLen + oLen + 4) '-'
220+
] <>
221+
[ replicate (cLen - length (show c)) ' ' <> show c <>
222+
replicate (iLen - length (show i) + 2) ' ' <> show i <>
223+
replicate (oLen - length (show o) + 2) ' ' <> show o
224+
| (c, (i, o)) <- zip [0 :: Int,1..] xs
225+
]
226+
227+
failure

clash-testbench/src/Clash/Testbench/Input.hs

+22-19
Original file line numberDiff line numberDiff line change
@@ -51,27 +51,30 @@ fromList mode xs = do
5151

5252
vRef <- liftIO $ newIORef xs
5353
checkForProgress <- progressCheck simStepRef False
54+
signalHistory <- newHistory
55+
56+
let
57+
signalCurVal m = do
58+
x : xr <- readIORef vRef >>= return . \case
59+
[] -> case mode of
60+
Repeat -> xs
61+
Default v -> [v]
62+
IsInfinite -> error $ "Clash.Testbench.Input.fromList: "
63+
<> "end of list reached"
64+
yr -> yr
65+
66+
progress <- checkForProgress
67+
68+
if progress
69+
then do
70+
memorize signalHistory x
71+
writeIORef vRef xr
72+
signalCurVal m
73+
else
74+
return x
5475

5576
mind SomeSignal $ IOInput
5677
{ signalId = NoID
5778
, signalPrint = Nothing
58-
, signalCurVal = const $ do
59-
readIORef vRef >>= \case
60-
[] -> case mode of
61-
Repeat -> do
62-
let (x : xr) = xs
63-
writeIORef vRef xr
64-
return x
65-
Default v ->
66-
return v
67-
IsInfinite ->
68-
error $ "Clash.Testbench.Input.fromList: "
69-
<> "End of list reached."
70-
x : xr -> do
71-
progress <- checkForProgress
72-
73-
when progress $
74-
writeIORef vRef xr
75-
76-
return x
79+
, ..
7780
}

0 commit comments

Comments
 (0)