@@ -21,9 +21,10 @@ module Test.Mutagen.Test.State
2121 , updateDiscardedQueue
2222 , setFragmentStore
2323 , updateFragmentStore
24- , incNumTraceLogResets
24+ , incNumTraceStoreResets
2525 , incNumPassed
2626 , incNumDiscarded
27+ , incNumFailed
2728 , incNumGenerated
2829 , incNumMutatedFromPassed
2930 , incNumMutatedFromDiscarded
@@ -36,10 +37,13 @@ module Test.Mutagen.Test.State
3637 -- * State-related utilities
3738 , timedOut
3839 , computeSize
40+ , nextCounterexamplePath
3941 )
4042where
4143
44+ import Data.List (elemIndex )
4245import Data.Time.Clock.POSIX (POSIXTime , getPOSIXTime )
46+ import System.FilePath ((<.>) )
4347import Test.Mutagen.Config (Config (.. ), DebugMode (.. ))
4448import Test.Mutagen.Fragment
4549 ( FragmentStore
@@ -97,6 +101,10 @@ data MutagenState
97101 -- ^ Mirrored from 'Config.filterFragments'
98102 , stMaxTraceLength :: ! (Maybe Int )
99103 -- ^ Mirrored from 'Config.maxTraceLength'
104+ , stKeepGoing :: ! Bool
105+ -- ^ Mirrored from 'Config.keepGoing'
106+ , stSaveCounterexamples :: ! (Maybe FilePath )
107+ -- ^ Mirrored from 'Config.saveCounterexamples'
100108 , stChatty :: ! Bool
101109 -- ^ Mirrored from 'Config.chatty'
102110 , stDebug :: ! DebugMode
@@ -143,14 +151,16 @@ data MutagenState
143151 -- ^ Number of passed test cases
144152 , stNumDiscarded :: ! Int
145153 -- ^ Number of discarded test cases
154+ , stNumFailed :: ! Int
155+ -- ^ Number of failed test cases (only useful when 'keepGoing' is enabled)
146156 , stNumInteresting :: ! Int
147157 -- ^ Number of interesting test cases
148158 , stNumBoring :: ! Int
149159 -- ^ Number of boring test cases
150160 , stNumTestsSinceLastInteresting :: ! Int
151161 -- ^ Number of test cases since the last interesting one
152- , stNumTraceLogResets :: ! Int
153- -- ^ Number of times the trace logs have been reset
162+ , stNumTraceStoreResets :: ! Int
163+ -- ^ Number of times the trace store have been reset
154164 }
155165
156166-- | Initialize the internal state
@@ -189,6 +199,8 @@ initMutagenState cfg (Property gen runner) = do
189199 , stUseFragments = useFragments cfg
190200 , stFilterFragments = filterFragments cfg
191201 , stMaxTraceLength = maxTraceLength cfg
202+ , stKeepGoing = keepGoing cfg
203+ , stSaveCounterexamples = saveCounterexamples cfg
192204 , stChatty = chatty cfg || debug cfg /= NoDebug
193205 , stDebug = debug cfg
194206 , stTui = tui cfg
@@ -212,11 +224,12 @@ initMutagenState cfg (Property gen runner) = do
212224 , stNumRandMutants = 0
213225 , stNumFragMutants = 0
214226 , stNumPassed = 0
227+ , stNumFailed = 0
215228 , stNumDiscarded = 0
216229 , stNumInteresting = 0
217230 , stNumBoring = 0
218231 , stNumTestsSinceLastInteresting = 0
219- , stNumTraceLogResets = 0
232+ , stNumTraceStoreResets = 0
220233 }
221234 where
222235 fragmentStoreFromExamples =
@@ -276,9 +289,9 @@ updateFragmentStore f st =
276289
277290-- ** Incrementers
278291
279- incNumTraceLogResets :: MutagenState -> MutagenState
280- incNumTraceLogResets st =
281- st{stNumTraceLogResets = stNumTraceLogResets st + 1 }
292+ incNumTraceStoreResets :: MutagenState -> MutagenState
293+ incNumTraceStoreResets st =
294+ st{stNumTraceStoreResets = stNumTraceStoreResets st + 1 }
282295
283296incNumPassed :: MutagenState -> MutagenState
284297incNumPassed st =
@@ -288,6 +301,10 @@ incNumDiscarded :: MutagenState -> MutagenState
288301incNumDiscarded st =
289302 st{stNumDiscarded = stNumDiscarded st + 1 }
290303
304+ incNumFailed :: MutagenState -> MutagenState
305+ incNumFailed st =
306+ st{stNumFailed = stNumFailed st + 1 }
307+
291308incNumGenerated :: MutagenState -> MutagenState
292309incNumGenerated st =
293310 st{stNumGenerated = stNumGenerated st + 1 }
@@ -359,3 +376,19 @@ computeSize st
359376 `min` stMaxGenSize st
360377 where
361378 roundTo n m = (n `div` m) * m
379+
380+ -- | Compute the path for the next counterexample to be saved.
381+ --
382+ -- If no counterexamples are to be saved, returns 'Nothing'. If a path template
383+ -- is provided (containing '@'), replaces '@' with the current failure counter.
384+ -- Otherwise, appends the counter to the given path.
385+ nextCounterexamplePath :: MutagenState -> Maybe FilePath
386+ nextCounterexamplePath st
387+ | Just path <- stSaveCounterexamples st =
388+ case elemIndex ' @' path of
389+ Just n -> Just (replace n (show (stNumFailed st + 1 )) path)
390+ Nothing -> Just (path <.> show (stNumFailed st + 1 ))
391+ | otherwise = Nothing
392+ where
393+ replace n s str =
394+ let (before, after) = splitAt n str in before <> s <> drop 1 after
0 commit comments