@@ -74,7 +74,7 @@ import Roboservant.Types
7474import Servant (Endpoints, Proxy (Proxy), Server, ServerError (..))
7575import System.Random (StdGen, mkStdGen, randomR)
7676import qualified Type.Reflection as R
77−
77+import qualified Data.IntSet as IntSet
7878
7979data RoboservantException
8080 = RoboservantException
@@ -101,7 +101,7 @@ data FuzzOp
101101
102102data Config
103103 = Config
104− { seed :: [Dynamic],
104+ { seed :: [(Dynamic,Int)],
105105 maxRuntime :: Double, -- seconds to test for
106106 maxReps :: Integer,
107107 rngSeed :: Int,
@@ -120,7 +120,7 @@ data EndpointOption
120120 = forall as.
121121 (V.RecordToList as, V.RMap as) =>
122122 EndpointOption
123− { eoCall :: V.Curried as (IO (Either ServerError (NonEmpty Dynamic))),
123+ { eoCall :: V.Curried as (IO (Either ServerError (NonEmpty (Dynamic,Int)))),
124124 eoArgs :: V.Rec (TypedF StashValue) as
125125 }
126126
@@ -206,7 +206,7 @@ fuzz server Config {..} checker = handle (pure . Just . formatException) $ do
206206 ( forall as.
207207 (V.RecordToList as, V.RMap as) =>
208208 FuzzOp ->
209− V.Curried as (IO (Either ServerError (NonEmpty Dynamic))) ->
209+ V.Curried as (IO (Either ServerError (NonEmpty (Dynamic,Int)))) ->
210210 V.Rec (TypedF V.Identity) as ->
211211 m r
212212 ) ->
@@ -216,7 +216,7 @@ fuzz server Config {..} checker = handle (pure . Just . formatException) $ do
216216 (offset, EndpointOption {..}) <- elementOrFail . options =<< get
217217 r <-
218218 V.rtraverse
219− ( \(tr :*: StashValue svs) ->
219+ ( \(tr :*: StashValue svs _) ->
220220 elementOrFail $
221221 zipWith
222222 (\i xy -> V.Const i :*: tr :*: xy)
@@ -247,19 +247,19 @@ fuzz server Config {..} checker = handle (pure . Just . formatException) $ do
247247 execute ::
248248 (MonadState FuzzState m, MonadIO m, V.RecordToList as, V.RMap as) =>
249249 FuzzOp ->
250− V.Curried as (IO (Either ServerError (NonEmpty Dynamic))) ->
250+ V.Curried as (IO (Either ServerError (NonEmpty (Dynamic,Int)))) ->
251251 V.Rec (TypedF V.Identity) as ->
252252 m ()
253253 execute fuzzop func args = do
254254 (liftIO . print . (fuzzop,) . stash ) =<< get
255255 st <- get
256− let showable = unlines $ ("args":map show argTypes)
257− <> ["fuzzop"
258− , show fuzzop
259− -- ,"dyncall"
260− -- ,show (dynTypeRep dyncall)
261− ,"state"
262− ]
256+ -- let showable = unlines $ ("args":map show argTypes)
257+ -- <> ["fuzzop"
258+ -- , show fuzzop
259+ -- -- ,"dyncall"
260+ -- -- ,show (dynTypeRep dyncall)
261+ -- ,"state"
262+ -- ]
263263 -- liftIO $ putStrLn showable
264264 liftIO (V.runcurry' func argVals) >>= \case
265265 -- parameterise this
@@ -268,7 +268,7 @@ fuzz server Config {..} checker = handle (pure . Just . formatException) $ do
268268 500 -> throw serverError
269269 _ -> do
270270 liftIO $ print ("ignoring non-500 error", serverError)
271− Right (dyn :: NEL.NonEmpty Dynamic) -> do
271+ Right (dyn :: NEL.NonEmpty (Dynamic,Int)) -> do
272272 -- liftIO $ print ("storing", fmap dynTypeRep dyn)
273273 modify' (\fs@FuzzState{..} ->
274274 fs { stash = addToStash (NEL.toList dyn) stash } )
@@ -289,14 +289,15 @@ fuzz server Config {..} checker = handle (pure . Just . formatException) $ do
289289 (\(e :: SomeException) -> throw . RoboservantException CheckerFailed (Just e) =<< get)
290290
291291addToStash ::
292− [Dynamic] ->
292+ [(Dynamic,Int)] ->
293293 Stash ->
294294 Stash
295295addToStash result stash =
296296 foldr
297− ( \(Dynamic tr x) (Stash dict) ->
297+ ( \(Dynamic tr x,hashed) (Stash dict) ->
298298 Stash $
299− DM.insertWith renumber tr (StashValue (([Provenance (R.SomeTypeRep tr) 0], x) :| [])) dict
299+ DM.insertWith renumber tr
300+ (StashValue (([Provenance (R.SomeTypeRep tr) 0], x) :| []) (IntSet.singleton hashed)) dict
300301 )
301302 stash
302303 result
@@ -305,11 +306,17 @@ addToStash result stash =
305306 StashValue a ->
306307 StashValue a ->
307308 StashValue a
308− renumber (StashValue singleDyn) (StashValue l) = StashValue $ case NEL.toList singleDyn of
309− [([Provenance tr _], dyn)] ->
310− l
311− <> pure ([Provenance tr (length (NEL.last l) + 1)], dyn)
312− _ -> error "should be impossible"
309+ renumber (StashValue singleDyn singleHash) orig@(StashValue l intSet)
310+ | not $ IntSet.null (singleHash `IntSet.intersection` intSet) = orig
311+ | otherwise =
312+ StashValue
313+ (case NEL.toList singleDyn of
314+ [([Provenance tr _], dyn)] ->
315+ l
316+ <> pure (([Provenance tr (length (NEL.last l) + 1)], dyn))
317+ _ -> error "should be impossible")
318+
319+ (IntSet.union singleHash intSet)
313320
314321-- why isn't this in vinyl?
315322recordToList' ::