Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add --fail-fast #455

Merged
merged 37 commits into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
da89e81
implement stop on fail mode
tgdwyer Sep 30, 2024
c91656f
Merge remote-tracking branch 'upstream/main' into stopOnFail
tgdwyer Oct 2, 2024
fae77e6
cleanup for fail-fast
tgdwyer Oct 2, 2024
5c4c557
minor
tgdwyer Oct 2, 2024
922a81e
grammar
tgdwyer Oct 2, 2024
b636d70
rename
tgdwyer Oct 2, 2024
3ea017c
help message for fail-fast
tgdwyer Oct 2, 2024
c57791a
grammar
tgdwyer Oct 2, 2024
5e02a21
minor
tgdwyer Oct 2, 2024
6163d14
fix tests
tgdwyer Oct 2, 2024
1d30f53
add fail-fast test to cabal file
tgdwyer Oct 3, 2024
9c18474
fail-fast across modules
tgdwyer Oct 3, 2024
4869344
Merge branch 'stopOnFail' of https:/tgdwyer/doctest into …
tgdwyer Oct 3, 2024
43ff72e
separate multimodules test
tgdwyer Oct 4, 2024
a660e95
in fail-fast test, force module processing order with an import, fix…
tgdwyer Oct 4, 2024
1cb85da
fix hpack order
tgdwyer Oct 4, 2024
bbe00c6
Use `MaybeT`
sol Oct 15, 2024
b4a777c
Implement fail-fast behavior
sol Oct 15, 2024
7ce7caf
MaybeT for fast-fail
tgdwyer Oct 18, 2024
5b03c92
fail-fast after preserveIt
tgdwyer Oct 18, 2024
97efed1
fail-fast after preserve-it
tgdwyer Oct 18, 2024
d1abb1f
typo
tgdwyer Oct 18, 2024
3e90a6f
clean up tests
tgdwyer Oct 18, 2024
cf4a4c7
Update MainSpec.hs
sol Oct 19, 2024
0eb1be7
Update MainSpec.hs
sol Oct 19, 2024
364d238
Update MainSpec.hs
sol Oct 19, 2024
286bdac
Update MainSpec.hs
sol Oct 19, 2024
e1f6a41
Update doctest.cabal
sol Oct 19, 2024
7c100f6
Update Foo.hs
sol Oct 19, 2024
3023bb5
Update Bar.hs
sol Oct 19, 2024
29ecd57
Update Foo.hs
sol Oct 19, 2024
c7c23ec
Update Bar.hs
sol Oct 19, 2024
cf9b0b0
Update Foo.hs
sol Oct 19, 2024
4ecd2aa
Update Foo.hs
sol Oct 19, 2024
15deacc
Update CHANGES.markdown
sol Oct 19, 2024
3e33d0b
Update package.yaml
sol Oct 19, 2024
f03a676
Update doctest.cabal
sol Oct 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions doctest.cabal

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion src/Options.hs
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ import Info
usage :: String
usage = unlines [
"Usage:"
, " doctest [ --fast | --preserve-it | --no-magic | --verbose | GHC OPTION | MODULE ]..."
, " doctest [ --fast | --preserve-it | --no-magic | --fail-fast | --verbose | GHC OPTION | MODULE ]..."
tgdwyer marked this conversation as resolved.
Show resolved Hide resolved
, " doctest --help"
, " doctest --version"
, " doctest --info"
, ""
, "Options:"
, " --fast disable :reload between example groups"
, " --preserve-it preserve the `it` variable between examples"
, " --fail-fast abort on first failure"
, " --no-magic disable magic mode"
sol marked this conversation as resolved.
Show resolved Hide resolved
sol marked this conversation as resolved.
Show resolved Hide resolved
, " --verbose print each test as it is run"
, " --help display this help and exit"
, " --version output version information and exit"
Expand All @@ -57,6 +59,7 @@ data Config = Config {
ghcOptions :: [String]
, fastMode :: Bool
, preserveIt :: Bool
, failFast :: Bool
sol marked this conversation as resolved.
Show resolved Hide resolved
, verbose :: Bool
, repl :: (String, [String])
} deriving (Eq, Show)
Expand All @@ -66,6 +69,7 @@ defaultConfig = Config {
ghcOptions = []
, fastMode = False
, preserveIt = False
, failFast = False
sol marked this conversation as resolved.
Show resolved Hide resolved
, verbose = False
, repl = (ghc, ["--interactive"])
}
Expand Down Expand Up @@ -99,6 +103,9 @@ setOptions ghcOptions run@Run{..} = run { runConfig = runConfig { ghcOptions } }
setMagicMode :: Bool -> Run -> Run
setMagicMode magic run = run { runMagicMode = magic }

setFailFastMode :: Bool -> Run -> Run
setFailFastMode failFast run@Run{..} = run { runConfig = runConfig { failFast } }
tgdwyer marked this conversation as resolved.
Show resolved Hide resolved

setFastMode :: Bool -> Run -> Run
setFastMode fastMode run@Run{..} = run { runConfig = runConfig { fastMode } }

Expand All @@ -119,6 +126,7 @@ parseOptions args
| otherwise = runRunOptionsParser args defaultRun {runMagicMode = True} $ do
commonRunOptions
parseFlag "--no-magic" (setMagicMode False)
parseFlag "--fail-fast" (setFailFastMode True)
tgdwyer marked this conversation as resolved.
Show resolved Hide resolved
parseOptGhc
where
on option = option `elem` args
Expand Down
1 change: 1 addition & 0 deletions src/Run.hs
Original file line number Diff line number Diff line change
Expand Up @@ -158,5 +158,6 @@ runDocTests Config{..} modules = do
runModules
(if fastMode then FastMode else NoFastMode)
(if preserveIt then PreserveIt else NoPreserveIt)
(if failFast then FailFast else NoFailFast)
sol marked this conversation as resolved.
Show resolved Hide resolved
(if verbose then Verbose else NonVerbose)
interpreter modules
29 changes: 22 additions & 7 deletions src/Runner.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ module Runner (
runModules
, FastMode(..)
, PreserveIt(..)
, FailFast(..)
, Verbose(..)
, Summary(..)
, formatSummary
Expand Down Expand Up @@ -66,8 +67,8 @@ withLineBuffering h action = bracket (hGetBuffering h) (hSetBuffering h) $ \ _ -
action

-- | Run all examples from a list of modules.
runModules :: FastMode -> PreserveIt -> Verbose -> Interpreter -> [Module [Located DocTest]] -> IO Summary
runModules fastMode preserveIt verbose repl modules = withLineBuffering stderr $ do
runModules :: FastMode -> PreserveIt -> FailFast -> Verbose -> Interpreter -> [Module [Located DocTest]] -> IO Summary
runModules fastMode preserveIt failFast verbose repl modules = withLineBuffering stderr $ do

interactive <- hIsTerminalDevice stderr <&> \ case
False -> NonInteractive
Expand All @@ -84,7 +85,7 @@ runModules fastMode preserveIt verbose repl modules = withLineBuffering stderr $
run :: IO ()
run = flip evalStateT (ReportState interactive verbose summary) $ do
reportProgress
forM_ modules $ runModule fastMode preserveIt repl
forM_ modules $ runModule fastMode preserveIt failFast repl
verboseReport "# Final summary:"

run `finally` reportFinalResult
Expand All @@ -105,6 +106,8 @@ data FastMode = NoFastMode | FastMode

data Verbose = NonVerbose | Verbose

data FailFast = NoFailFast | FailFast

data ReportState = ReportState {
reportStateInteractive :: Interactive
, reportStateVerbose :: Verbose
Expand All @@ -131,8 +134,8 @@ reportTransient msg = gets reportStateInteractive >>= \ case
hPutStr stderr $ '\r' : (replicate (length msg) ' ') ++ "\r"

-- | Run all examples from given module.
runModule :: FastMode -> PreserveIt -> Interpreter -> Module [Located DocTest] -> Report ()
runModule fastMode preserveIt repl (Module module_ setup examples) = do
runModule :: FastMode -> PreserveIt -> FailFast -> Interpreter -> Module [Located DocTest] -> Report ()
runModule fastMode preserveIt failFast repl (Module module_ setup examples) = do

Summary _ _ e0 f0 <- getSummary

Expand All @@ -143,8 +146,7 @@ runModule fastMode preserveIt repl (Module module_ setup examples) = do

-- only run tests, if setup does not produce any errors/failures
when (e0 == e1 && f0 == f1) $
forM_ examples $
runTestGroup preserveIt repl setup_
runExamples examples
where
reload :: IO ()
reload = do
Expand All @@ -169,6 +171,19 @@ runModule fastMode preserveIt repl (Module module_ setup examples) = do
Property _ -> return ()
Example e _ -> void $ safeEvalWith preserveIt repl e

-- run examples - optionally aborting if in stopOnFail mode and a failure occurs
runExamples :: [[Located DocTest]] -> Report ()
runExamples [] = return ()
runExamples (testGroup:moreGroups) = do
failures <- sFailures <$> getSummary
case failFast of
FailFast -> when (failures == 0) runAndContinue
sol marked this conversation as resolved.
Show resolved Hide resolved
NoFailFast -> runAndContinue
where
runAndContinue = do
runTestGroup preserveIt repl setup_ testGroup
runExamples moreGroups

reportStart :: Location -> Expression -> String -> Report ()
reportStart loc expression testType = do
verboseReport (printf "### Started execution at %s.\n### %s:\n%s" (show loc) testType expression)
Expand Down
20 changes: 14 additions & 6 deletions test/MainSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ withCurrentDirectory workingDir action = do

-- | Construct a doctest specific 'Assertion'.
doctest :: HasCallStack => FilePath -> [String] -> Summary -> Assertion
doctest = doctestWithPreserveIt False
doctest = doctestWithPreserveIt False False

doctestWithPreserveIt :: HasCallStack => Bool -> FilePath -> [String] -> Summary -> Assertion
doctestWithPreserveIt preserveIt workingDir ghcOptions expected = do
actual <- withCurrentDirectory ("test/integration" </> workingDir) (hSilence [stderr] $ doctestWithResult defaultConfig {ghcOptions, preserveIt})
doctestWithPreserveIt :: HasCallStack => Bool -> Bool -> FilePath -> [String] -> Summary -> Assertion
doctestWithPreserveIt preserveIt failFast workingDir ghcOptions expected = do
actual <- withCurrentDirectory ("test/integration" </> workingDir) (hSilence [stderr] $ doctestWithResult defaultConfig {ghcOptions, preserveIt, failFast})
assertEqual label (formatSummary expected) (formatSummary actual)
where
label = workingDir ++ " " ++ show ghcOptions
Expand All @@ -44,11 +44,11 @@ spec = do
(cases 1)

it "it-variable" $ do
doctestWithPreserveIt True "." ["it/Foo.hs"]
doctestWithPreserveIt True False "." ["it/Foo.hs"]
(cases 5)

it "it-variable in $setup" $ do
doctestWithPreserveIt True "." ["it/Setup.hs"]
doctestWithPreserveIt True False "." ["it/Setup.hs"]
(cases 5)

it "failing" $ do
Expand All @@ -59,6 +59,14 @@ spec = do
doctest "." ["failing-multiple/Foo.hs"]
(cases 4) {sTried = 2, sFailures = 1}

it "runs subsequent groups after an example in earlier group fails" $
tgdwyer marked this conversation as resolved.
Show resolved Hide resolved
doctest "." ["fail-fast/Foo.hs"]
(cases 3) {sTried = 3, sFailures = 1}

it "in --fail-fast mode, does not run subsequent groups after an example in earlier group fails" $
doctestWithPreserveIt False True "." ["fail-fast/Foo.hs","fail-fast/Bar.hs"]
(cases 4) {sTried = 2, sFailures = 1}

it "testImport" $ do
doctest "testImport" ["ModuleA.hs"]
(cases 3)
Expand Down
11 changes: 10 additions & 1 deletion test/OptionsSpec.hs
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,18 @@ spec = do
fastMode . runConfig <$> parseOptions [] `shouldBe` Result False

context "with --fast" $ do
it "enabled fast mode" $ do
it "enable fast mode" $ do
tgdwyer marked this conversation as resolved.
Show resolved Hide resolved
fastMode . runConfig <$> parseOptions ["--fast"] `shouldBe` Result True

describe "--fail-fast" $ do
sol marked this conversation as resolved.
Show resolved Hide resolved
context "without --fail-fast" $ do
it "disables fail-fast mode" $ do
failFast . runConfig <$> parseOptions [] `shouldBe` Result False

context "with --fail-fast" $ do
it "enable fail-fast mode" $ do
sol marked this conversation as resolved.
Show resolved Hide resolved
tgdwyer marked this conversation as resolved.
Show resolved Hide resolved
failFast . runConfig <$> parseOptions ["--fail-fast"] `shouldBe` Result True

describe "--preserve-it" $ do
context "without --preserve-it" $ do
it "does not preserve the `it` variable" $ do
Expand Down
8 changes: 8 additions & 0 deletions test/integration/fail-fast/Bar.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module Bar where

-- | bar
-- a passing test
-- >>> bar
-- 42
bar :: Int
bar = 42
22 changes: 22 additions & 0 deletions test/integration/fail-fast/Foo.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module Foo where

-- | A passing example
--
-- >>> 23
-- 23
test1 :: a
test1 = undefined

-- | A failing example
--
-- >>> 23
-- 42
test2 :: a
test2 = undefined

-- | Another passing example
--
-- >>> 23
-- 23
test3 :: a
test3 = undefined
Loading