packages feed

doctest 0.22.2 → 0.25.0

raw patch · 35 files changed

Files

CHANGES.markdown view
@@ -1,3 +1,51 @@+Changes in 0.25.0+  - Full GHC 9.14 compatibility / `-unit`-support++Changes in 0.24.3+  - Allow building with GHC 9.14 (#478)++Changes in 0.24.2+  - Use `GHC.ResponseFile.expandResponse`++Changes in 0.24.1+  - Interpret GHC response files++Changes in 0.24.0+  - cabal-doctest: Add support for cabal-install 3.14.*++Changes in 0.23.0+  - Add `--fail-fast`++Changes in 0.22.10+  - Make progress reporting more robust++Changes in 0.22.9+  - Use `-fprint-error-index-links=never` for GHC `>=9.10`++Changes in 0.22.8+  - cabal-doctest: Fix handling of options with optional arguments++Changes in 0.22.7+  - cabal-doctest: Accept component+  - cabal-doctest: Get rid of separate `cabal build` step+  - cabal-doctest: Add support for `--list-options`++Changes in 0.22.6+  - cabal-doctest: Take `with-compiler:` from `cabal-project` into account+  - cabal-doctest: Add support for `--with-compiler`+  - cabal-doctest: Fix `ghc-pkg` discovery logic+  - cabal-doctest: Cache `doctest` executables++Changes in 0.22.5+  - Add (experimental) `cabal-doctest` executable.  This is guarded behind a+    flag for now, use `cabal install doctest -f cabal-doctest` to install it.++Changes in 0.22.4+  - Use `-Wno-unused-packages` for GHC `8.10` / `9.0` / `9.2`++Changes in 0.22.3+  - Use `-Wno-unused-packages` when extracting comments+ Changes in 0.22.2   - GHC 9.8 compatibility @@ -17,7 +65,7 @@   - GHC 9.4 compatibility. (#382)  Changes in 0.20.0-  - Allow doctest to be invoked via `cabal repl --with-ghc=doctest`+  - Allow doctest to be invoked via `cabal repl --with-compiler=doctest`   - Include `ghc --info` output in `--info`   - Make `--info` output formatting consistent with GHC 
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2009-2023 Simon Hengel <sol@typeful.net>+Copyright (c) 2009-2026 Simon Hengel <sol@typeful.net>  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal
README.md view
@@ -1,9 +1,9 @@ # Doctest: Test interactive Haskell examples  `doctest` is a tool that checks-[examples](https://www.haskell.org/haddock/doc/html/ch03s08.html#idm140354810775744)+[examples](https://haskell-haddock.readthedocs.io/latest/markup.html#examples) and-[properties](https://www.haskell.org/haddock/doc/html/ch03s08.html#idm140354810771856)+[properties](https://haskell-haddock.readthedocs.io/latest/markup.html#properties) in Haddock comments. It is similar in spirit to the [popular Python module with the same name](https://docs.python.org/3/library/doctest.html). @@ -12,6 +12,7 @@    * [A basic example](#a-basic-example) * [Running doctest for a Cabal package](#running-doctest-for-a-cabal-package)    * [Passing doctest options to cabal repl](#passing-doctest-options-to-cabal-repl)+   * [Cabal integration](#cabal-integration) * [Writing examples and properties](#writing-examples-and-properties)    * [Example groups](#example-groups)       * [A note on performance](#a-note-on-performance)@@ -33,24 +34,30 @@ ## Installation  `doctest` is available from-[Hackage](http://hackage.haskell.org/cgi-bin/hackage-scripts/package/doctest).+[Hackage](https://hackage.haskell.org/package/doctest). Install it with: -    cabal update && cabal install doctest--Make sure that Cabal's `bindir` is on your `PATH`.--On Linux:+    cabal update && cabal install --ignore-project doctest -    export PATH="$HOME/.cabal/bin:$PATH"+Make sure that Cabal's `installdir` is on your `PATH`. -On Mac OS X:+On Linux / macOS / BSD: -    export PATH="$HOME/Library/Haskell/bin:$PATH"+```bash+ # requires cabal-install version 3.12, or later+export PATH="$(cabal -v0 path --installdir):$PATH"+```+or+```bash+export PATH="$HOME/.local/bin:$PATH"+``` -On Windows:+On Windows with PowerShell: -    set PATH="%AppData%\cabal\bin\;%PATH%"+```pwsh+# requires cabal-install version 3.12, or later+$Env:PATH = "$(cabal -v0 path --installdir)" + ";" + $Env:PATH+```  ## A basic example @@ -81,7 +88,7 @@ (A comment line starting with `>>>` denotes an _expression_. All comment lines following an expression denote the _result_ of that expression. Result is defined by what a-[REPL](http://en.wikipedia.org/wiki/Read-eval-print_loop) (e.g. ghci)+[REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop) (e.g. ghci) prints to `stdout` and `stderr` when evaluating that expression.)  With `doctest` you can check whether the implementation satisfies the given@@ -94,7 +101,7 @@  # Running `doctest` for a Cabal package -The easiest way to run `doctest` for a Cabal package is via `cabal repl --with-ghc=doctest`.+The easiest way to run `doctest` for a Cabal package is via `cabal repl --with-compiler=doctest`.  This doesn't make a big difference for a simple package, but in more involved situations `cabal` will make sure that all dependencies are available and it@@ -120,8 +127,8 @@  With a `.cabal` file in place, it is possible to run `doctest` via `cabal repl`: -```-$ cabal repl --with-ghc=doctest+```bash+$ cabal repl --with-compiler=doctest ... Examples: 2  Tried: 2  Errors: 0  Failures: 0 ```@@ -132,19 +139,22 @@ - If you use properties you need to pass `--build-depends=QuickCheck` and   `--build-depends=template-haskell` to `cabal repl`. +- You likely want to reset the warning strategy for `cabal repl` with+  `--repl-options='-w -Wdefault'`.+ - `doctest` always uses the version of GHC it was compiled with.  Reinstalling   `doctest` with `cabal install doctest --overwrite-policy=always` before each   invocation ensures that it uses the same version of GHC as is on the `PATH`. -- Technically, `cabal build` is not necessary. `cabal repl --with-ghc=doctest`+- Technically, `cabal build` is not necessary. `cabal repl --with-compiler=doctest`   will build any dependencies as needed.  However, it's more robust to run   `cabal build` first (specifically it is not a good idea to build-  `ghc-paths` with `--with-ghc=doctest`).+  `ghc-paths` with `--with-compiler=doctest`).  So a more robust way to call `doctest` is as follows:  ```-cabal install doctest --overwrite-policy=always && cabal build && cabal repl --build-depends=QuickCheck --build-depends=template-haskell --with-ghc=doctest+cabal install doctest --ignore-project --overwrite-policy=always && cabal build && cabal repl --build-depends=QuickCheck --build-depends=template-haskell --with-compiler=doctest --repl-options='-w -Wdefault' ```  (This is what you want to use on CI.)@@ -156,8 +166,45 @@  Example: +```bash+$ cabal repl --with-compiler=doctest --repl-options=--verbose+### Started execution at src/Fib.hs:7.+### example:+fib 10+### Successful!++### Started execution at src/Fib.hs:10.+### example:+fib 5+### Successful!++# Final summary:+Examples: 2  Tried: 2  Errors: 0  Failures: 0 ```-$ cabal repl --with-ghc=doctest --repl-options=--verbose++## Cabal integration++***NOTE:*** This feature is experimental.++***NOTE:*** This feature requires `cabal-install` version 3.12 or later.+++```bash+$ cabal install --ignore-project doctest --flag cabal-doctest+```++```bash+$ cabal doctest+Examples: 2  Tried: 2  Errors: 0  Failures: 0+```++```bash+$ cabal doctest -w ghc-8.6.5+Examples: 2  Tried: 2  Errors: 0  Failures: 0+```++```bash+$ cabal doctest --repl-options=--verbose ### Started execution at src/Fib.hs:7. ### example: fib 10@@ -172,6 +219,11 @@ Examples: 2  Tried: 2  Errors: 0  Failures: 0 ``` +```bash+$ cabal doctest --build-depends transformers+Examples: 2  Tried: 2  Errors: 0  Failures: 0+```+ # Writing examples and properties  ## Example groups@@ -384,7 +436,7 @@ ```  If you see an error like the following, ensure that-[QuickCheck](http://hackage.haskell.org/package/QuickCheck) is visible to+[QuickCheck](https://hackage.haskell.org/package/QuickCheck) is visible to `doctest` (e.g. by passing `--build-depends=QuickCheck` to `cabal repl`).  ```haskell@@ -412,7 +464,7 @@ -- 2 ``` -[named-chunks]: http://www.haskell.org/haddock/doc/html/ch03s05.html+[named-chunks]: https://haskell-haddock.readthedocs.io/latest/markup.html#named-chunks  ## Using GHC extensions @@ -430,7 +482,7 @@  ```haskell -- |--- >>> :set -XTupleSections+-- >>> :seti -XTupleSections -- >>> fst' $ (1,) 2 -- 1 fst' :: (a, b) -> a@@ -450,10 +502,10 @@  ```haskell -- $--- >>> :set -XTupleSections+-- >>> :seti -XTupleSections ``` -[language-pragma]: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/pragmas.html#language-pragma+[language-pragma]: https://downloads.haskell.org/ghc/latest/docs/users_guide/exts/pragmas.html#language-pragma  # Limitations @@ -510,45 +562,48 @@ Add tests for new features, and make sure that the test suite passes with your changes. -    cabal build --enable-tests && cabal exec -- cabal test --test-show-details=direct+    cabal build && cabal exec $(cabal list-bin spec)   # Contributors + * Simon Hengel+ * quasicomputational+ * Kazu Yamamoto+ * Andreas Abel+ * Michael Snoyman+ * Michael Orlitzky+ * Sakari Jokinen  * Adam Vogt+ * Ryan Scott+ * Oleg Grenrus+ * Sönke Hahn+ * Edward Kmett+ * Elliot Marsden+ * Greg Pfeil+ * Ignat Insarov+ * Julian K. Arni+ * Takano Akio+ * Joachim Breitner  * Alan Zimmerman  * Alexander Bernauer  * Alexandre Esteves  * Anders Persson- * Andreas Abel  * Ankit Ahuja  * Artyom Kazak- * Edward Kmett  * Gabor Greif+ * Guillaume Bouchard  * Hiroki Hattori- * Ignat Insarov  * Jens Petersen- * Joachim Breitner  * John Chee  * João Cristóvão- * Julian Arni- * Kazu Yamamoto  * Leon Schoorl  * Levent Erkok  * Luke Murphy  * Matvey Aksenov- * Michael Orlitzky- * Michael Snoyman  * Mitchell Rosen  * Nick Smallbone  * Nikos Baxevanis- * Oleg Grenrus- * quasicomputational- * Ryan Scott- * Sakari Jokinen- * Simon Hengel- * Sönke Hahn- * Takano Akio  * Tamar Christina  * Veronika Romashkina 
doctest.cabal view
@@ -1,11 +1,11 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.36.0.+-- This file has been generated from package.yaml by hpack version 0.39.1. -- -- see: https://github.com/sol/hpack  name:           doctest-version:        0.22.2+version:        0.25.0 synopsis:       Test interactive Haskell examples description:    `doctest` is a tool that checks [examples](https://www.haskell.org/haddock/doc/html/ch03s08.html#idm140354810775744)                 and [properties](https://www.haskell.org/haddock/doc/html/ch03s08.html#idm140354810771856)@@ -18,7 +18,7 @@ homepage:       https://github.com/sol/doctest#readme license:        MIT license-file:   LICENSE-copyright:      (c) 2009-2023 Simon Hengel+copyright:      (c) 2009-2026 Simon Hengel author:         Simon Hengel <sol@typeful.net> maintainer:     Simon Hengel <sol@typeful.net> build-type:     Simple@@ -67,6 +67,10 @@     test/integration/custom-package-conf/foo/doctest-foo.cabal     test/integration/custom-package-conf/foo/Foo.hs     test/integration/dos-line-endings/Fib.hs+    test/integration/fail-fast/Bar.hs+    test/integration/fail-fast/Foo.hs+    test/integration/fail-fast/SetupBar.hs+    test/integration/fail-fast/SetupFoo.hs     test/integration/failing-multiple/Foo.hs     test/integration/failing/Foo.hs     test/integration/it/Foo.hs@@ -107,6 +111,11 @@   type: git   location: https://github.com/sol/doctest +flag cabal-doctest+  description: Install (experimental) cabal-doctest executable+  manual: True+  default: False+ library   ghc-options: -Wall   hs-source-dirs:@@ -122,7 +131,12 @@       Test.DocTest.Internal.Location       Test.DocTest.Internal.Parse       Test.DocTest.Internal.Run+      Test.DocTest.Internal.Cabal   other-modules:+      Cabal+      Cabal.Options+      Cabal.Paths+      Cabal.ReplOptions       Extract       GhcUtil       Imports@@ -140,53 +154,73 @@       Util       Paths_doctest   build-depends:-      base >=4.5 && <5+      base >=4.12 && <5     , code-page >=0.1+    , containers     , deepseq     , directory     , exceptions     , filepath-    , ghc >=8.0 && <9.10+    , ghc >=8.6 && <9.16     , ghc-paths >=0.1.0.9     , process     , syb >=0.3+    , temporary     , transformers   default-language: Haskell2010+  if impl(ghc >= 9.0)+    ghc-options: -fwarn-unused-packages   if impl(ghc >= 9.8)     ghc-options: -fno-warn-x-partial +executable cabal-doctest+  main-is: driver/cabal-doctest.hs+  other-modules:+      Paths_doctest+  default-extensions:+      NamedFieldPuns+      RecordWildCards+      DeriveFunctor+      NoImplicitPrelude+  ghc-options: -Wall -threaded+  build-depends:+      base >=4.12 && <5+    , doctest+  default-language: Haskell2010+  if impl(ghc >= 9.0)+    ghc-options: -fwarn-unused-packages+  if impl(ghc >= 9.8)+    ghc-options: -fno-warn-x-partial+  if flag(cabal-doctest)+    buildable: True+  else+    buildable: False+ executable doctest-  main-is: Main.hs+  main-is: driver/doctest.hs   other-modules:       Paths_doctest   ghc-options: -Wall -threaded-  hs-source-dirs:-      driver   default-extensions:       NamedFieldPuns       RecordWildCards       DeriveFunctor       NoImplicitPrelude   build-depends:-      base >=4.5 && <5-    , code-page >=0.1-    , deepseq-    , directory+      base >=4.12 && <5     , doctest-    , exceptions-    , filepath-    , ghc >=8.0 && <9.10-    , ghc-paths >=0.1.0.9-    , process-    , syb >=0.3-    , transformers   default-language: Haskell2010+  if impl(ghc >= 9.0)+    ghc-options: -fwarn-unused-packages   if impl(ghc >= 9.8)     ghc-options: -fno-warn-x-partial  test-suite spec   main-is: Spec.hs   other-modules:+      Cabal.OptionsSpec+      Cabal.PathsSpec+      Cabal.ReplOptionsSpec       ExtractSpec       InfoSpec       InterpreterSpec@@ -201,6 +235,10 @@       RunnerSpec       RunSpec       UtilSpec+      Cabal+      Cabal.Options+      Cabal.Paths+      Cabal.ReplOptions       Extract       GhcUtil       Imports@@ -216,6 +254,7 @@       Runner       Runner.Example       Test.DocTest+      Test.DocTest.Internal.Cabal       Test.DocTest.Internal.Extract       Test.DocTest.Internal.Location       Test.DocTest.Internal.Parse@@ -240,23 +279,26 @@   build-depends:       HUnit     , QuickCheck >=2.13.1-    , base >=4.5 && <5+    , base >=4.12 && <5     , code-page >=0.1+    , containers     , deepseq     , directory     , exceptions     , filepath-    , ghc >=8.0 && <9.10+    , ghc >=8.6 && <9.16     , ghc-paths >=0.1.0.9     , hspec >=2.3.0     , hspec-core >=2.3.0     , mockery     , process-    , setenv     , silently >=1.2.4     , stringbuilder >=0.4     , syb >=0.3+    , temporary     , transformers   default-language: Haskell2010+  if impl(ghc >= 9.0)+    ghc-options: -fwarn-unused-packages   if impl(ghc >= 9.8)     ghc-options: -fno-warn-x-partial
− driver/Main.hs
@@ -1,8 +0,0 @@-module Main (main) where--import           Prelude-import           Test.DocTest-import           System.Environment (getArgs)--main :: IO ()-main = getArgs >>= doctest
+ driver/cabal-doctest.hs view
@@ -0,0 +1,8 @@+module Main (main) where++import           Prelude+import qualified Test.DocTest.Internal.Cabal as Cabal+import           System.Environment (getArgs)++main :: IO ()+main = getArgs >>= Cabal.doctest
+ driver/doctest.hs view
@@ -0,0 +1,8 @@+module Main (main) where++import           Prelude+import           Test.DocTest+import           System.Environment (getArgs)++main :: IO ()+main = getArgs >>= doctest
+ src/Cabal.hs view
@@ -0,0 +1,77 @@+{-# LANGUAGE LambdaCase #-}+module Cabal (externalCommand) where++import           Imports++import           Data.List+import           Data.Version (makeVersion)+import           System.IO+import           System.IO.Temp+import           System.Environment+import           System.Directory+import           System.FilePath+import           System.Process++import qualified Info+import           Cabal.Paths+import           Cabal.Options++externalCommand :: [String] -> IO ()+externalCommand args = do+  lookupEnv "CABAL" >>= \ case+    Nothing -> run "cabal" args+    Just cabal -> run cabal (drop 1 args)++run :: String -> [String] -> IO ()+run cabal args = do+  rejectUnsupportedOptions args++  Paths{..} <- paths cabal (discardReplOptions args)++  let+    doctest = cache </> "doctest" <> "-" <> Info.version+    script = cache </> "init-ghci-" <> Info.version++  doesFileExist doctest >>= \ case+    True -> pass+    False -> callProcess cabal [+        "install" , "doctest-" <> Info.version+      , "--flag", "-cabal-doctest"+      , "--ignore-project"+      , "--installdir", cache+      , "--program-suffix", "-" <> Info.version+      , "--install-method=copy"+      , "--with-compiler", ghc+      ]++  doesFileExist script >>= \ case+    True -> pass+    False -> writeFileAtomically script ":seti -w -Wdefault"++  callProcess doctest ["--version"]++  let+    repl extraArgs = call cabal ("repl"+      : "--build-depends=QuickCheck"+      : "--build-depends=template-haskell"+      : ("--repl-options=-ghci-script=" <> script)+      : args ++ extraArgs)++  case ghcVersion < makeVersion [9,4] of+    True -> do+      callProcess cabal ("build" : "--only-dependencies" : discardReplOptions args)+      repl ["--with-compiler", doctest, "--with-hc-pkg", ghcPkg]++    False -> do+      withSystemTempDirectory "cabal-doctest" $ \ dir -> do+        repl ["--keep-temp-files", "--repl-multi-file", dir]+        files <- filter (isSuffixOf "-inplace") <$> listDirectory dir+        let options = concatMap (\ file -> ["-unit", '@' : dir </> file]) files+        call doctest ("--no-magic" : options)++writeFileAtomically :: FilePath -> String -> IO ()+writeFileAtomically name contents = do+  (tmp, h) <- openTempFile (takeDirectory name) (takeFileName name)+  hPutStr h contents+  hClose h+  renameFile tmp name
+ src/Cabal/Options.hs view
@@ -0,0 +1,78 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+module Cabal.Options (+  rejectUnsupportedOptions+, discardReplOptions++#ifdef TEST+, replOnlyOptions+#endif+) where++import           Imports++import           System.Exit+import           System.Console.GetOpt++import           Data.Set (Set)+import qualified Data.Set as Set++import qualified Cabal.ReplOptions as Repl++replOnlyOptions :: Set String+replOnlyOptions = Set.fromList [+    "-z"+  , "--ignore-project"+  , "--repl-no-load"+  , "--repl-options"+  , "--repl-multi-file"+  , "-b"+  , "--build-depends"+  , "--no-transitive-deps"+  , "--enable-multi-repl"+  , "--disable-multi-repl"+  , "--with-repl"+  ]++rejectUnsupportedOptions :: [String] -> IO ()+rejectUnsupportedOptions args = case getOpt' Permute options args of+  (xs, _, _, _) | ListOptions `elem` xs -> do+    let+      names :: [String]+      names = concat [map (\ c -> ['-', c]) short ++ map ("--" <> ) long | Option short long _ _ <- documentedOptions]+    putStr (unlines names)+    exitSuccess+  (_, _, unsupported : _, _) -> do+    die $ "Error: cabal: unrecognized 'doctest' option `" <> unsupported <> "'"+  _ -> pass++data Argument = Argument String (Maybe String) | ListOptions+  deriving (Eq, Show)++options :: [OptDescr Argument]+options =+    Option [] ["list-options"] (NoArg ListOptions) ""+  : documentedOptions++documentedOptions :: [OptDescr Argument]+documentedOptions = map toOptDescr Repl.options+  where+    toOptDescr :: Repl.Option -> OptDescr Argument+    toOptDescr (Repl.Option long short arg help) = Option (maybeToList short) [long] (toArgDescr long arg) help++    toArgDescr :: String -> Repl.Argument -> ArgDescr Argument+    toArgDescr long = \ case+      Repl.Argument name -> ReqArg (argument . Just) name+      Repl.NoArgument -> NoArg (argument Nothing)+      Repl.OptionalArgument name -> OptArg argument name+      where+        argument :: Maybe String -> Argument+        argument value = Argument ("--" <> long) value++discardReplOptions :: [String] -> [String]+discardReplOptions args = case getOpt Permute options args of+  (xs, _, _) -> [renderArgument name value | Argument name value <- xs, Set.notMember name replOnlyOptions]+  where+    renderArgument name = \ case+      Nothing -> name+      Just value -> name <> "=" <> value
+ src/Cabal/Paths.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE StrictData #-}+module Cabal.Paths (+  Paths(..)+, paths+) where++import           Imports++import           Data.Char+import           Data.Tuple+import           Data.Version hiding (parseVersion)+import qualified Data.Version as Version+import           System.Exit hiding (die)+import           System.Directory+import           System.FilePath+import           System.IO+import           System.Process+import           Text.ParserCombinators.ReadP++data Paths = Paths {+  ghcVersion :: Version+, ghc  :: FilePath+, ghcPkg :: FilePath+, cache :: FilePath+} deriving (Eq, Show)++paths :: FilePath -> [String] -> IO Paths+paths cabal args = do+  cabalVersion <- strip <$> readProcess cabal ["--numeric-version"] ""++  let+    required :: Version+    required = makeVersion [3, 12]++  when (parseVersion cabalVersion < Just required) $ do+    die $ "'cabal-install' version " <> showVersion required <> " or later is required, but 'cabal --numeric-version' returned " <> cabalVersion <> "."++  values <- parseFields <$> readProcess cabal ("path" : args ++ ["-v0"]) ""++  let+    getPath :: String -> String -> IO FilePath+    getPath subject key = case lookup key values of+      Nothing -> die $ "Cannot determine the path to " <> subject <> ". Running 'cabal path' did not return a value for '" <> key <> "'."+      Just path -> canonicalizePath path++  ghc <- getPath "'ghc'" "compiler-path"++  ghcVersionString <- strip <$> readProcess ghc ["--numeric-version"] ""++  ghcVersion <- case parseVersion ghcVersionString of+    Nothing -> die $ "Cannot determine GHC version from '" <> ghcVersionString <> "'."+    Just version -> return version++  let+    ghcPkg :: FilePath+    ghcPkg = takeDirectory ghc </> "ghc-pkg-" <> ghcVersionString+#ifdef mingw32_HOST_OS+      <.> "exe"+#endif++  doesFileExist ghcPkg >>= \ case+    True -> pass+    False -> die $ "Cannot determine the path to 'ghc-pkg' from '" <> ghc <> "'. File '" <> ghcPkg <> "' does not exist."++  abi <- strip <$> readProcess ghcPkg ["--no-user-package-db", "field", "base", "abi", "--simple-output"] ""++  cache_home <- getPath "Cabal's cache directory" "cache-home"+  let cache = cache_home </> "doctest" </> "ghc-" <> ghcVersionString <> "-" <> abi++  createDirectoryIfMissing True cache++  return Paths {+    ghcVersion+  , ghc+  , ghcPkg+  , cache+  }+  where+    parseFields :: String -> [(String, FilePath)]+    parseFields = map parseField . lines++    parseField :: String -> (String, FilePath)+    parseField input = case break (== ':') input of+      (key, ':' : value) -> (key, dropWhile isSpace value)+      (key, _) -> (key, "")++die :: String -> IO a+die message = do+  hPutStrLn stderr "Error: [cabal-doctest]"+  hPutStrLn stderr message+  exitFailure++parseVersion :: String -> Maybe Version+parseVersion = lookup "" . map swap . readP_to_S Version.parseVersion
+ src/Cabal/ReplOptions.hs view
@@ -0,0 +1,195 @@+module Cabal.ReplOptions (+  Option(..)+, Argument(..)+, options+) where++import           Imports++data Option = Option {+  optionName :: String+, optionShortName :: Maybe Char+, optionArgument :: Argument+, optionHelp :: String+} deriving (Eq, Show)++data Argument = Argument String | NoArgument | OptionalArgument String+  deriving (Eq, Show)++options :: [Option]+options = [+    Option "help" (Just 'h') NoArgument "Show this help text"+  , Option "verbose" (Just 'v') (OptionalArgument "n") "Control verbosity (n is 0--3, default verbosity level is 1)"+  , Option "builddir" Nothing (Argument "DIR") "The directory where Cabal puts generated build files (default dist)"+  , Option "keep-temp-files" Nothing NoArgument "Keep temporary files."+  , Option "ghc" (Just 'g') NoArgument "compile with GHC"+  , Option "ghcjs" Nothing NoArgument "compile with GHCJS"+  , Option "uhc" Nothing NoArgument "compile with UHC"+  , Option "with-compiler" (Just 'w') (Argument "PATH") "give the path to a particular compiler"+  , Option "with-hc-pkg" Nothing (Argument "PATH") "give the path to the package tool"+  , Option "prefix" Nothing (Argument "DIR") "bake this prefix in preparation of installation"+  , Option "bindir" Nothing (Argument "DIR") "installation directory for executables"+  , Option "libdir" Nothing (Argument "DIR") "installation directory for libraries"+  , Option "libsubdir" Nothing (Argument "DIR") "subdirectory of libdir in which libs are installed"+  , Option "dynlibdir" Nothing (Argument "DIR") "installation directory for dynamic libraries"+  , Option "libexecdir" Nothing (Argument "DIR") "installation directory for program executables"+  , Option "libexecsubdir" Nothing (Argument "DIR") "subdirectory of libexecdir in which private executables are installed"+  , Option "datadir" Nothing (Argument "DIR") "installation directory for read-only data"+  , Option "datasubdir" Nothing (Argument "DIR") "subdirectory of datadir in which data files are installed"+  , Option "docdir" Nothing (Argument "DIR") "installation directory for documentation"+  , Option "htmldir" Nothing (Argument "DIR") "installation directory for HTML documentation"+  , Option "haddockdir" Nothing (Argument "DIR") "installation directory for haddock interfaces"+  , Option "sysconfdir" Nothing (Argument "DIR") "installation directory for configuration files"+  , Option "program-prefix" Nothing (Argument "PREFIX") "prefix to be applied to installed executables"+  , Option "program-suffix" Nothing (Argument "SUFFIX") "suffix to be applied to installed executables"+  , Option "enable-library-vanilla" Nothing NoArgument "Enable Vanilla libraries"+  , Option "disable-library-vanilla" Nothing NoArgument "Disable Vanilla libraries"+  , Option "enable-library-profiling" (Just 'p') NoArgument "Enable Library profiling"+  , Option "disable-library-profiling" Nothing NoArgument "Disable Library profiling"+  , Option "enable-shared" Nothing NoArgument "Enable Shared library"+  , Option "disable-shared" Nothing NoArgument "Disable Shared library"+  , Option "enable-static" Nothing NoArgument "Enable Static library"+  , Option "disable-static" Nothing NoArgument "Disable Static library"+  , Option "enable-executable-dynamic" Nothing NoArgument "Enable Executable dynamic linking"+  , Option "disable-executable-dynamic" Nothing NoArgument "Disable Executable dynamic linking"+  , Option "enable-executable-static" Nothing NoArgument "Enable Executable fully static linking"+  , Option "disable-executable-static" Nothing NoArgument "Disable Executable fully static linking"+  , Option "enable-profiling" Nothing NoArgument "Enable Executable and library profiling"+  , Option "disable-profiling" Nothing NoArgument "Disable Executable and library profiling"+  , Option "enable-profiling-shared" Nothing NoArgument "Enable Build profiling shared libraries"+  , Option "disable-profiling-shared" Nothing NoArgument "Disable Build profiling shared libraries"+  , Option "enable-executable-profiling" Nothing NoArgument "Enable Executable profiling (DEPRECATED)"+  , Option "disable-executable-profiling" Nothing NoArgument "Disable Executable profiling (DEPRECATED)"+  , Option "profiling-detail" Nothing (Argument "level") "Profiling detail level for executable and library (default, none, exported-functions, toplevel-functions, all-functions, late)."+  , Option "library-profiling-detail" Nothing (Argument "level") "Profiling detail level for libraries only."+  , Option "enable-optimization" (Just 'O') (OptionalArgument "n") "Build with optimization (n is 0--2, default is 1)"+  , Option "disable-optimization" Nothing NoArgument "Build without optimization"+  , Option "enable-debug-info" Nothing (OptionalArgument "n") "Emit debug info (n is 0--3, default is 0)"+  , Option "disable-debug-info" Nothing NoArgument "Don't emit debug info"+  , Option "enable-build-info" Nothing NoArgument "Enable build information generation during project building"+  , Option "disable-build-info" Nothing NoArgument "Disable build information generation during project building"+  , Option "enable-library-for-ghci" Nothing NoArgument "Enable compile library for use with GHCi"+  , Option "disable-library-for-ghci" Nothing NoArgument "Disable compile library for use with GHCi"+  , Option "enable-split-sections" Nothing NoArgument "Enable compile library code such that unneeded definitions can be dropped from the final executable (GHC 7.8+)"+  , Option "disable-split-sections" Nothing NoArgument "Disable compile library code such that unneeded definitions can be dropped from the final executable (GHC 7.8+)"+  , Option "enable-split-objs" Nothing NoArgument "Enable split library into smaller objects to reduce binary sizes (GHC 6.6+)"+  , Option "disable-split-objs" Nothing NoArgument "Disable split library into smaller objects to reduce binary sizes (GHC 6.6+)"+  , Option "enable-executable-stripping" Nothing NoArgument "Enable strip executables upon installation to reduce binary sizes"+  , Option "disable-executable-stripping" Nothing NoArgument "Disable strip executables upon installation to reduce binary sizes"+  , Option "enable-library-stripping" Nothing NoArgument "Enable strip libraries upon installation to reduce binary sizes"+  , Option "disable-library-stripping" Nothing NoArgument "Disable strip libraries upon installation to reduce binary sizes"+  , Option "configure-option" Nothing (Argument "OPT") "Extra option for configure"+  , Option "user" Nothing NoArgument "Enable doing a per-user installation"+  , Option "global" Nothing NoArgument "Disable doing a per-user installation"+  , Option "package-db" Nothing (Argument "DB") "Append the given package database to the list of package databases used (to satisfy dependencies and register into). May be a specific file, 'global' or 'user'. The initial list is ['global'], ['global', 'user'], or ['global', $sandbox], depending on context. Use 'clear' to reset the list to empty. See the user guide for details."+  , Option "flags" (Just 'f') (Argument "FLAGS") "Force values for the given flags in Cabal conditionals in the .cabal file. E.g., --flags=\"debug -usebytestrings\" forces the flag \"debug\" to true and \"usebytestrings\" to false."+  , Option "extra-include-dirs" Nothing (Argument "PATH") "A list of directories to search for header files"+  , Option "enable-deterministic" Nothing NoArgument "Enable Try to be as deterministic as possible (used by the test suite)"+  , Option "disable-deterministic" Nothing NoArgument "Disable Try to be as deterministic as possible (used by the test suite)"+  , Option "ipid" Nothing (Argument "IPID") "Installed package ID to compile this package as"+  , Option "cid" Nothing (Argument "CID") "Installed component ID to compile this component as"+  , Option "extra-lib-dirs" Nothing (Argument "PATH") "A list of directories to search for external libraries"+  , Option "extra-lib-dirs-static" Nothing (Argument "PATH") "A list of directories to search for external libraries when linking fully static executables"+  , Option "extra-framework-dirs" Nothing (Argument "PATH") "A list of directories to search for external frameworks (OS X only)"+  , Option "extra-prog-path" Nothing (Argument "PATH") "A list of directories to search for required programs (in addition to the normal search locations)"+  , Option "instantiate-with" Nothing (Argument "NAME=MOD") "A mapping of signature names to concrete module instantiations."+  , Option "enable-tests" Nothing NoArgument "Enable dependency checking and compilation for test suites listed in the package description file."+  , Option "disable-tests" Nothing NoArgument "Disable dependency checking and compilation for test suites listed in the package description file."+  , Option "enable-coverage" Nothing NoArgument "Enable build package with Haskell Program Coverage. (GHC only)"+  , Option "disable-coverage" Nothing NoArgument "Disable build package with Haskell Program Coverage. (GHC only)"+  , Option "enable-library-coverage" Nothing NoArgument "Enable build package with Haskell Program Coverage. (GHC only) (DEPRECATED)"+  , Option "disable-library-coverage" Nothing NoArgument "Disable build package with Haskell Program Coverage. (GHC only) (DEPRECATED)"+  , Option "enable-benchmarks" Nothing NoArgument "Enable dependency checking and compilation for benchmarks listed in the package description file."+  , Option "disable-benchmarks" Nothing NoArgument "Disable dependency checking and compilation for benchmarks listed in the package description file."+  , Option "enable-relocatable" Nothing NoArgument "Enable building a package that is relocatable. (GHC only)"+  , Option "disable-relocatable" Nothing NoArgument "Disable building a package that is relocatable. (GHC only)"+  , Option "disable-response-files" Nothing NoArgument "enable workaround for old versions of programs like \"ar\" that do not support @file arguments"+  , Option "allow-depending-on-private-libs" Nothing NoArgument "Allow depending on private libraries. If set, the library visibility check MUST be done externally."+  , Option "coverage-for" Nothing (Argument "UNITID") "A list of unit-ids of libraries to include in the Haskell Program Coverage report."+  , Option "ignore-build-tools" Nothing NoArgument "Ignore build tool dependencies. If set, declared build tools needn't be found for compilation to proceed."+  , Option "cabal-lib-version" Nothing (Argument "VERSION") "Select which version of the Cabal lib to use to build packages (useful for testing)."+  , Option "enable-append" Nothing NoArgument "Enable appending the new config to the old config file"+  , Option "disable-append" Nothing NoArgument "Disable appending the new config to the old config file"+  , Option "enable-backup" Nothing NoArgument "Enable the backup of the config file before any alterations"+  , Option "disable-backup" Nothing NoArgument "Disable the backup of the config file before any alterations"+  , Option "constraint" (Just 'c') (Argument "CONSTRAINT") "Specify constraints on a package (version, installed/source, flags)"+  , Option "preference" Nothing (Argument "CONSTRAINT") "Specify preferences (soft constraints) on the version of a package"+  , Option "solver" Nothing (Argument "SOLVER") "Select dependency solver to use (default: modular). Choices: modular."+  , Option "allow-older" Nothing (OptionalArgument "DEPS") "Ignore lower bounds in all dependencies or DEPS"+  , Option "allow-newer" Nothing (OptionalArgument "DEPS") "Ignore upper bounds in all dependencies or DEPS"+  , Option "write-ghc-environment-files" Nothing (Argument "always|never|ghc8.4.4+") "Whether to create a .ghc.environment file after a successful build (v2-build only)"+  , Option "enable-documentation" Nothing NoArgument "Enable building of documentation"+  , Option "disable-documentation" Nothing NoArgument "Disable building of documentation"+  , Option "doc-index-file" Nothing (Argument "TEMPLATE") "A central index of haddock API documentation (template cannot use $pkgid)"+  , Option "dry-run" Nothing NoArgument "Do not install anything, only print what would be installed."+  , Option "only-download" Nothing NoArgument "Do not build anything, only fetch the packages."+  , Option "max-backjumps" Nothing (Argument "NUM") "Maximum number of backjumps allowed while solving (default: 4000). Use a negative number to enable unlimited backtracking. Use 0 to disable backtracking completely."+  , Option "reorder-goals" Nothing NoArgument "Try to reorder goals according to certain heuristics. Slows things down on average, but may make backtracking faster for some packages."+  , Option "count-conflicts" Nothing NoArgument "Try to speed up solving by preferring goals that are involved in a lot of conflicts (default)."+  , Option "fine-grained-conflicts" Nothing NoArgument "Skip a version of a package if it does not resolve the conflicts encountered in the last version, as a solver optimization (default)."+  , Option "minimize-conflict-set" Nothing NoArgument "When there is no solution, try to improve the error message by finding a minimal conflict set (default: false). May increase run time significantly."+  , Option "independent-goals" Nothing NoArgument "Treat several goals on the command line as independent. If several goals depend on the same package, different versions can be chosen."+  , Option "prefer-oldest" Nothing NoArgument "Prefer the oldest (instead of the latest) versions of packages available. Useful to determine lower bounds in the build-depends section."+  , Option "shadow-installed-packages" Nothing NoArgument "If multiple package instances of the same version are installed, treat all but one as shadowed."+  , Option "strong-flags" Nothing NoArgument "Do not defer flag choices (this used to be the default in cabal-install <= 1.20)."+  , Option "allow-boot-library-installs" Nothing NoArgument "Allow cabal to install base, ghc-prim, integer-simple, integer-gmp, and template-haskell."+  , Option "reject-unconstrained-dependencies" Nothing (Argument "none|all") "Require these packages to have constraints on them if they are to be selected (default: none)."+  , Option "reinstall" Nothing NoArgument "Install even if it means installing the same version again."+  , Option "avoid-reinstalls" Nothing NoArgument "Do not select versions that would destructively overwrite installed packages."+  , Option "force-reinstalls" Nothing NoArgument "Reinstall packages even if they will most likely break other installed packages."+  , Option "upgrade-dependencies" Nothing NoArgument "Pick the latest version for all dependencies, rather than trying to pick an installed version."+  , Option "only-dependencies" Nothing NoArgument "Install only the dependencies necessary to build the given packages"+  , Option "dependencies-only" Nothing NoArgument "A synonym for --only-dependencies"+  , Option "index-state" Nothing (Argument "STATE") "Use source package index state as it existed at a previous time. Accepts unix-timestamps (e.g. '@1474732068'), ISO8601 UTC timestamps (e.g. '2016-09-24T17:47:48Z'), or 'HEAD' (default: 'HEAD')."+  , Option "root-cmd" Nothing (Argument "COMMAND") "(No longer supported, do not use.)"+  , Option "build-summary" Nothing (Argument "TEMPLATE") "Save build summaries to file (name template can use $pkgid, $compiler, $os, $arch)"+  , Option "build-log" Nothing (Argument "TEMPLATE") "Log all builds to file (name template can use $pkgid, $compiler, $os, $arch)"+  , Option "remote-build-reporting" Nothing (Argument "LEVEL") "Generate build reports to send to a remote server (none, anonymous or detailed)."+  , Option "report-planning-failure" Nothing NoArgument "Generate build reports when the dependency solver fails. This is used by the Hackage build bot."+  , Option "enable-per-component" Nothing NoArgument "Enable Per-component builds when possible"+  , Option "disable-per-component" Nothing NoArgument "Disable Per-component builds when possible"+  , Option "run-tests" Nothing NoArgument "Run package test suites during installation."+  , Option "semaphore" Nothing NoArgument "Use a semaphore so GHC can compile components in parallel"+  , Option "jobs" (Just 'j') (OptionalArgument "NUM") "Run NUM jobs simultaneously (or '$ncpus' if no NUM is given)."+  , Option "keep-going" Nothing NoArgument "After a build failure, continue to build other unaffected packages."+  , Option "offline" Nothing NoArgument "Don't download packages from the Internet."+  , Option "haddock-hoogle" Nothing NoArgument "Generate a hoogle database"+  , Option "haddock-html" Nothing NoArgument "Generate HTML documentation (the default)"+  , Option "haddock-html-location" Nothing (Argument "URL") "Location of HTML documentation for pre-requisite packages"+  , Option "haddock-for-hackage" Nothing NoArgument "Collection of flags to generate documentation suitable for upload to hackage"+  , Option "haddock-executables" Nothing NoArgument "Run haddock for Executables targets"+  , Option "haddock-tests" Nothing NoArgument "Run haddock for Test Suite targets"+  , Option "haddock-benchmarks" Nothing NoArgument "Run haddock for Benchmark targets"+  , Option "haddock-all" Nothing NoArgument "Run haddock for all targets"+  , Option "haddock-internal" Nothing NoArgument "Run haddock for internal modules and include all symbols"+  , Option "haddock-css" Nothing (Argument "PATH") "Use PATH as the haddock stylesheet"+  , Option "haddock-hyperlink-source" Nothing NoArgument "Hyperlink the documentation to the source code"+  , Option "haddock-quickjump" Nothing NoArgument "Generate an index for interactive documentation navigation"+  , Option "haddock-hscolour-css" Nothing (Argument "PATH") "Use PATH as the HsColour stylesheet"+  , Option "haddock-contents-location" Nothing (Argument "URL") "Bake URL in as the location for the contents page"+  , Option "haddock-base-url" Nothing (Argument "URL") "Base URL for static files."+  , Option "haddock-resources-dir" Nothing (Argument "DIR") "location of Haddocks static / auxiliary files"+  , Option "haddock-output-dir" Nothing (Argument "DIR") "Generate haddock documentation into this directory. This flag is provided as a technology preview and is subject to change in the next releases."+  , Option "haddock-use-unicode" Nothing NoArgument "Pass --use-unicode option to haddock"+  , Option "test-log" Nothing (Argument "TEMPLATE") "Log all test suite results to file (name template can use $pkgid, $compiler, $os, $arch, $test-suite, $result)"+  , Option "test-machine-log" Nothing (Argument "TEMPLATE") "Produce a machine-readable log file (name template can use $pkgid, $compiler, $os, $arch, $result)"+  , Option "test-show-details" Nothing (Argument "FILTER") "'always': always show results of individual test cases. 'never': never show results of individual test cases. 'failures': show results of failing test cases. 'streaming': show results of test cases in real time.'direct': send results of test cases in real time; no log file."+  , Option "test-keep-tix-files" Nothing NoArgument "keep .tix files for HPC between test runs"+  , Option "test-wrapper" Nothing (Argument "FILE") "Run test through a wrapper."+  , Option "test-fail-when-no-test-suites" Nothing NoArgument "Exit with failure when no test suites are found."+  , Option "test-options" Nothing (Argument "TEMPLATES") "give extra options to test executables (split on spaces, use \"\" to prevent splitting; name templates can use $pkgid, $compiler, $os, $arch, $test-suite)"+  , Option "test-option" Nothing (Argument "TEMPLATE") "give extra option to test executables (passed directly as a single argument; name template can use $pkgid, $compiler, $os, $arch, $test-suite)"+  , Option "benchmark-options" Nothing (Argument "TEMPLATES") "give extra options to benchmark executables (split on spaces, use \"\" to prevent splitting; name templates can use $pkgid, $compiler, $os, $arch, $benchmark)"+  , Option "benchmark-option" Nothing (Argument "TEMPLATE") "give extra option to benchmark executables (passed directly as a single argument; name template can use $pkgid, $compiler, $os, $arch, $benchmark)"+  , Option "project-dir" Nothing (Argument "DIR") "Set the path of the project directory"+  , Option "project-file" Nothing (Argument "FILE") "Set the path of the cabal.project file (relative to the project directory when relative)"+  , Option "ignore-project" (Just 'z') NoArgument "Ignore local project configuration (unless --project-dir or --project-file is also set)"+  , Option "repl-no-load" Nothing NoArgument "Disable loading of project modules at REPL startup."+  , Option "repl-options" Nothing (Argument "FLAG") "Use the option(s) for the repl"+  , Option "repl-multi-file" Nothing (Argument "DIR") "Write repl options to this directory rather than starting repl mode"+  , Option "with-repl" Nothing (Argument "PATH") "Give the path to a program to use for REPL"+  , Option "build-depends" (Just 'b') (Argument "DEPENDENCIES") "Include additional packages in the environment presented to GHCi."+  , Option "no-transitive-deps" Nothing NoArgument "Don't automatically include transitive dependencies of requested packages."+  , Option "enable-multi-repl" Nothing NoArgument "Enable multi-component repl sessions"+  , Option "disable-multi-repl" Nothing NoArgument "Disable multi-component repl sessions"+  ]
src/Extract.hs view
@@ -1,11 +1,8 @@ {-# LANGUAGE CPP #-} module Extract (Module(..), extract) where -import           Prelude hiding (mod, concat)-import           Control.Monad-import           Control.Exception+import           Imports hiding (mod, concat) import           Data.List (partition, isSuffixOf)-import           Data.Maybe  import           Control.DeepSeq (deepseq, NFData(rnf)) import           Data.Generics@@ -32,10 +29,6 @@ import           System.Directory import           System.FilePath -#if __GLASGOW_HASKELL__ < 805-import           FastString (unpackFS)-#endif- import           System.Posix.Internals (c_getpid)  import           GhcUtil (withGhc)@@ -44,13 +37,11 @@ import           Util (convertDosLineEndings) import           PackageDBs (getPackageDBArgs) -#if __GLASGOW_HASKELL__ >= 806 #if __GLASGOW_HASKELL__ < 900 import           DynamicLoading (initializePlugins) #else import           GHC.Runtime.Loader (initializePlugins) #endif-#endif  #if __GLASGOW_HASKELL__ >= 901 import           GHC.Unit.Module.Graph@@ -58,7 +49,9 @@  -- | A wrapper around `SomeException`, to allow for a custom `Show` instance. newtype ExtractError = ExtractError SomeException+#if __GLASGOW_HASKELL__ < 912   deriving Typeable+#endif  instance Show ExtractError where   show (ExtractError e) =@@ -88,15 +81,6 @@ instance NFData a => NFData (Module a) where   rnf (Module name setup content) = name `deepseq` setup `deepseq` content `deepseq` () -#if __GLASGOW_HASKELL__ < 803-type GhcPs = RdrName-#endif--#if __GLASGOW_HASKELL__ < 805-addQuoteInclude :: [String] -> [String] -> [String]-addQuoteInclude includes new = new ++ includes-#endif- -- | Parse a list of modules. parse :: [String] -> IO [ParsedModule] parse args = withGhc args $ \modules_ -> withTempOutputDir $ do@@ -111,7 +95,11 @@                 Nothing)   mods <- depanal [] False -  let sortedMods = flattenSCCs+  let sortedMods =+#if __GLASGOW_HASKELL__ >= 914+                   mapMaybe maybeModSummaryFromModuleNodeInfo $+#endif+                   flattenSCCs #if __GLASGOW_HASKELL__ >= 901                      $ filterToposortToModules #endif@@ -157,7 +145,6 @@       , includePaths = addQuoteInclude (includePaths d) [f]       } -#if __GLASGOW_HASKELL__ >= 806     -- Since GHC 8.6, plugins are initialized on a per module basis     loadModPlugins modsum = do       _ <- setSessionDynFlags (GHC.ms_hspp_opts modsum)@@ -166,14 +153,11 @@ # if __GLASGOW_HASKELL__ >= 902       hsc_env' <- liftIO (initializePlugins hsc_env)       setSession hsc_env'-      return $ modsum+      return modsum # else       dynflags' <- liftIO (initializePlugins hsc_env (GHC.ms_hspp_opts modsum))       return $ modsum { ms_hspp_opts = dynflags' } # endif-#else-    loadModPlugins = return-#endif  -- | Extract all docstrings from given list of files/modules. --@@ -182,7 +166,15 @@ extract :: [String] -> IO [Module (Located String)] extract args = do   packageDBArgs <- getPackageDBArgs-  let args'  = args ++ packageDBArgs+  let+    args' = args +++#if __GLASGOW_HASKELL__ >= 810+      -- `ghci` ignores unused packages in certain situation.  This ensures+      -- that we don't fail in situations where `ghci` would not.+      "-Wno-unused-packages" :+#endif+      packageDBArgs+   mods <- parse args'   let docs = map (fmap (fmap convertDosLineEndings) . extractFromModule) mods @@ -203,6 +195,13 @@     (setup, docs) = partition isSetup (docStringsFromModule m)     name = (moduleNameString . GHC.moduleName . ms_mod . pm_mod_summary) m +#if __GLASGOW_HASKELL__ >= 914+maybeModSummaryFromModuleNodeInfo :: ModuleNodeInfo -> Maybe ModSummary+maybeModSummaryFromModuleNodeInfo i = case i of+  ModuleNodeCompile summary -> Just summary+  ModuleNodeFixed _ _ -> Nothing+#endif+ #if __GLASGOW_HASKELL__ >= 904 unpackHDS :: HsDocString -> String unpackHDS = renderHsDocString@@ -234,11 +233,7 @@ #else     exports = [ (Nothing, L (locA loc) doc) #endif-#if __GLASGOW_HASKELL__ < 805-              | L loc (IEDoc doc) <- maybe [] unLoc (hsmodExports source)-#else               | L loc (IEDoc _ doc) <- maybe [] unLoc (hsmodExports source)-#endif               ]     decls :: [(Maybe String, LHsDocString)]     decls   = extractDocStrings (hsmodDecls source)@@ -253,7 +248,7 @@   in     flip fmap docStrs $ \docStr -> (lookup (getLoc docStr) docStrNames, docStr)   where-    extractAll z = everything (++) ((mkQ [] ((:[]) . z)))+    extractAll z = everything (++) (mkQ [] ((:[]) . z))      extractDocDocString :: LHsDoc GhcPs -> LHsDocString     extractDocDocString = fmap hsDocString@@ -276,11 +271,7 @@       -- Top-level documentation has to be treated separately, because it has       -- no location information attached.  The location information is       -- attached to HsDecl instead.-#if __GLASGOW_HASKELL__ < 805-      DocD x-#else       DocD _ x-#endif                -> select (fromDocDecl (locA loc) x)        _ -> (extractDocStrings decl, True)@@ -306,12 +297,6 @@ -- | Collect given value and descend into subtree. select :: a -> ([a], Bool) select x = ([x], False)-#endif--#if __GLASGOW_HASKELL__ < 805--- | Convert a docstring to a plain string.-unpackHDS :: HsDocString -> String-unpackHDS (HsDocString s) = unpackFS s #endif  #if __GLASGOW_HASKELL__ < 901
src/GhcUtil.hs view
@@ -1,5 +1,6 @@ {-# LANGUAGE CPP #-}-module GhcUtil (withGhc) where+{-# LANGUAGE LambdaCase #-}+module GhcUtil (withGhc, expandUnits) where  import           Imports @@ -23,12 +24,9 @@ import           GHC.Utils.Monad (liftIO) #endif +import           GHC.ResponseFile (expandResponse) import           System.Exit (exitFailure) -#if __GLASGOW_HASKELL__ < 801-import           StaticFlags (discardStaticFlags)-#endif- -- Catch GHC source errors, print them and exit. handleSrcErrors :: Ghc a -> Ghc a handleSrcErrors action' = flip handleSourceError action' $ \err -> do@@ -37,20 +35,17 @@  -- | Run a GHC action in Haddock mode withGhc :: [String] -> ([String] -> Ghc a) -> IO a-withGhc flags action = do-  flags_ <- handleStaticFlags flags--  runGhc (Just libdir) $ do-    handleDynamicFlags flags_ >>= handleSrcErrors . action+withGhc flags action = runGhc (Just libdir) $ do+  liftIO (expandUnits flags) >>= handleDynamicFlags >>= handleSrcErrors . action -handleStaticFlags :: [String] -> IO [Located String]-#if __GLASGOW_HASKELL__ < 801-handleStaticFlags flags = return $ map noLoc $ discardStaticFlags flags-#else-handleStaticFlags flags = return $ map noLoc $ flags-#endif+expandUnits :: [String] -> IO [String]+expandUnits = \ case+  [] -> return []+  "-unit" : file@('@' : _) : args -> (++) <$> expandResponse [file] <*> expandUnits args+  file@('@' : _) : args -> (++) <$> expandResponse [file] <*> expandUnits args+  x : xs -> (:) x <$> expandUnits xs -handleDynamicFlags :: GhcMonad m => [Located String] -> m [String]+handleDynamicFlags :: GhcMonad m => [String] -> m [String] handleDynamicFlags flags = do #if __GLASGOW_HASKELL__ >= 901   logger <- getLogger@@ -58,7 +53,7 @@ #else   let parseDynamicFlags' = parseDynamicFlags #endif-  (dynflags, locSrcs, _) <- (setHaddockMode `fmap` getSessionDynFlags) >>= (`parseDynamicFlags'` flags)+  (dynflags, locSrcs, _) <- (setHaddockMode `fmap` getSessionDynFlags) >>= (`parseDynamicFlags'` map noLoc flags)   _ <- setSessionDynFlags dynflags    -- We basically do the same thing as `ghc/Main.hs` to distinguish
src/Imports.hs view
@@ -1,5 +1,34 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-} module Imports (module Imports) where  import           Prelude as Imports import           Data.Monoid as Imports-import           Control.Monad as Imports+import           Data.Maybe as Imports+import           Control.Monad as Imports hiding (forM_)+import           Control.Exception as Imports+import           Data.Foldable as Imports (forM_)+import           Control.Arrow as Imports++import           Data.Char+import           System.Exit+import           System.Process++import           Data.Functor as Imports ((<&>))++pass :: Monad m => m ()+pass = return ()++equals :: Eq a => a -> a -> Bool+equals = (==)++strip :: String -> String+strip = reverse . dropWhile isSpace . reverse . dropWhile isSpace++call :: FilePath -> [FilePath] -> IO ()+call name args = rawSystem name args >>= \ case+  ExitSuccess -> pass+  err -> exitWith err++exec :: FilePath -> [FilePath] -> IO ()+exec name args = rawSystem name args >>= exitWith
src/Info.hs view
@@ -2,6 +2,7 @@ module Info (   versionInfo , info+, version #ifdef TEST , formatInfo #endif@@ -19,13 +20,22 @@ import           GHC.Settings.Config as GHC #endif +import           Interpreter (ghc)++#ifdef TEST++version :: String+version = "0.0.0"++#else+ import           Data.Version (showVersion) import qualified Paths_doctest -import           Interpreter (ghc)- version :: String version = showVersion Paths_doctest.version++#endif  ghcVersion :: String ghcVersion = GHC.cProjectVersion
src/Interpreter.hs view
@@ -1,8 +1,9 @@ {-# LANGUAGE CPP #-} module Interpreter (   Interpreter+, PreserveIt(..) , safeEval-, safeEvalIt+, safeEvalWith , withInterpreter , ghc , interpreterSupported@@ -17,8 +18,6 @@  import           System.Process import           System.Directory (getPermissions, executable)-import           Control.Exception hiding (handle)-import           Data.Char import           GHC.Paths (ghc)  import           Language.Haskell.GhciWrapper@@ -37,7 +36,7 @@   unless (executable x) $ do     fail $ ghc ++ " is not executable!" -  maybe False (== "YES") . lookup haveInterpreterKey <$> ghcInfo+  (== Just "YES") . lookup haveInterpreterKey <$> ghcInfo  withInterpreter   :: (String, [String])@@ -47,10 +46,14 @@   let     args = flags ++ [         xTemplateHaskell-#if __GLASGOW_HASKELL__ >= 802       , "-fdiagnostics-color=never"       , "-fno-diagnostics-show-caret"+#if __GLASGOW_HASKELL__ >= 810 && __GLASGOW_HASKELL__ < 904+      , "-Wno-unused-packages" #endif+#if __GLASGOW_HASKELL__ >= 910+      , "-fprint-error-index-links=never"+#endif       ]   bracket (new defaultConfig{configGhci = command} args) close action @@ -61,10 +64,10 @@ -- -- An exception may e.g. be caused on unterminated multiline expressions. safeEval :: Interpreter -> String -> IO (Either String String)-safeEval repl = either (return . Left) (fmap Right . eval repl) . filterExpression+safeEval = safeEvalWith NoPreserveIt -safeEvalIt :: Interpreter -> String -> IO (Either String String)-safeEvalIt repl = either (return . Left) (fmap Right . evalIt repl) . filterExpression+safeEvalWith :: PreserveIt -> Interpreter -> String -> IO (Either String String)+safeEvalWith preserveIt repl = either (return . Left) (fmap Right . evalWith preserveIt repl) . filterExpression  filterExpression :: String -> Either String String filterExpression e =@@ -75,9 +78,6 @@         firstLine = strip $ head l         lastLine  = strip $ last l         err = Left "unterminated multi-line command"-  where-    strip :: String -> String-    strip = dropWhile isSpace . reverse . dropWhile isSpace . reverse  filterXTemplateHaskell :: String -> String filterXTemplateHaskell input = case words input of
src/Language/Haskell/GhciWrapper.hs view
@@ -1,11 +1,13 @@+{-# LANGUAGE ViewPatterns #-} module Language.Haskell.GhciWrapper (   Interpreter , Config(..) , defaultConfig+, PreserveIt(..) , new , close , eval-, evalIt+, evalWith , evalEcho ) where @@ -14,9 +16,7 @@ import           System.IO hiding (stdin, stdout, stderr) import           System.Process import           System.Exit-import           Control.Exception import           Data.List (isSuffixOf)-import           Data.Maybe  data Config = Config {   configGhci :: String@@ -31,6 +31,9 @@ , configIgnoreDotGhci = True } +data PreserveIt = NoPreserveIt | PreserveIt+  deriving Eq+ -- | Truly random marker, used to separate expressions. -- -- IMPORTANT: This module relies upon the fact that this marker is unique.  It@@ -111,8 +114,8 @@   when (e /= ExitSuccess) $ do     throwIO (userError $ "Language.Haskell.GhciWrapper.close: Interpreter exited with an error (" ++ show e ++ ")") -putExpression :: Interpreter -> Bool -> String -> IO ()-putExpression Interpreter{hIn = stdin} preserveIt e = do+putExpression :: Interpreter -> PreserveIt -> String -> IO ()+putExpression Interpreter{hIn = stdin} (equals PreserveIt -> preserveIt) e = do   hPutStrLn stdin e   when preserveIt $ hPutStrLn stdin $ "let " ++ itMarker ++ " = it"   hPutStrLn stdin (marker ++ " :: Data.String.String")@@ -142,18 +145,16 @@  -- | Evaluate an expression eval :: Interpreter -> String -> IO String-eval repl expr = do-  putExpression repl False expr-  getResult False repl+eval = evalWith NoPreserveIt  -- | Like 'eval', but try to preserve the @it@ variable-evalIt :: Interpreter -> String -> IO String-evalIt repl expr = do-  putExpression repl True expr+evalWith :: PreserveIt -> Interpreter -> String -> IO String+evalWith preserveIt repl expr = do+  putExpression repl preserveIt expr   getResult False repl  -- | Evaluate an expression evalEcho :: Interpreter -> String -> IO String evalEcho repl expr = do-  putExpression repl False expr+  putExpression repl NoPreserveIt expr   getResult True repl
src/Options.hs view
@@ -28,7 +28,7 @@ usage :: String usage = unlines [     "Usage:"-  , "  doctest [ --fast | --preserve-it | --no-magic | --verbose | GHC OPTION | MODULE ]..."+  , "  doctest [ --fast | --preserve-it | --fail-fast | --no-magic | --verbose | GHC OPTION | MODULE ]..."   , "  doctest --help"   , "  doctest --version"   , "  doctest --info"@@ -36,6 +36,8 @@   , "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"   , "  --verbose      print each test as it is run"   , "  --help         display this help and exit"   , "  --version      output version information and exit"@@ -57,6 +59,7 @@   ghcOptions :: [String] , fastMode :: Bool , preserveIt :: Bool+, failFast :: Bool , verbose :: Bool , repl :: (String, [String]) } deriving (Eq, Show)@@ -66,6 +69,7 @@   ghcOptions = [] , fastMode = False , preserveIt = False+, failFast = False , verbose = False , repl = (ghc, ["--interactive"]) }@@ -105,6 +109,9 @@ setPreserveIt :: Bool -> Run -> Run setPreserveIt preserveIt run@Run{..} = run { runConfig = runConfig { preserveIt } } +setFailFastMode :: Bool -> Run -> Run+setFailFastMode failFast run@Run{..} = run { runConfig = runConfig { failFast } }+ setVerbose :: Bool -> Run -> Run setVerbose verbose run@Run{..} = run { runConfig = runConfig { verbose } } @@ -134,6 +141,7 @@ commonRunOptions = do   parseFlag "--fast" (setFastMode True)   parseFlag "--preserve-it" (setPreserveIt True)+  parseFlag "--fail-fast" (setFailFastMode True)   parseFlag "--verbose" (setVerbose True)  parseFlag :: String -> (Run -> Run) -> RunOptionsParser
src/Parse.hs view
@@ -21,7 +21,6 @@  import           Data.Char (isSpace) import           Data.List (isPrefixOf, stripPrefix)-import           Data.Maybe import           Data.String import           Extract import           Location@@ -175,8 +174,3 @@           then (0, c : replicate count '.' ++ acc, res)           else (0, c : acc, res)     finish (count, acc, res) = mkChunk (replicate count '.' ++ acc) ++ res----- | Remove leading and trailing whitespace.-strip :: String -> String-strip = dropWhile isSpace . reverse . dropWhile isSpace . reverse
src/Property.hs view
@@ -11,7 +11,6 @@ import           Imports  import           Data.List-import           Data.Maybe import           Data.Foldable  import           Util
src/Run.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-} module Run (   doctest , doctestWithRepl@@ -9,6 +10,7 @@  , Result , Summary(..)+, formatSummary , isSuccess , evaluateResult , doctestWithResult@@ -27,7 +29,6 @@ import           System.FilePath ((</>), takeExtension) import           System.IO import           System.IO.CodePage (withCP65001)-import           System.Process (rawSystem)  import qualified Control.Exception as E @@ -37,6 +38,10 @@ import           GHC.Utils.Panic #endif +#if __GLASGOW_HASKELL__ < 904+import           GhcUtil (expandUnits)+#endif+ import           PackageDBs import           Parse import           Options hiding (Result(..))@@ -62,8 +67,14 @@ doctest = doctestWithRepl (repl defaultConfig)  doctestWithRepl :: (String, [String]) -> [String] -> IO ()-doctestWithRepl repl args0 = case parseOptions args0 of-  Options.ProxyToGhc args -> rawSystem Interpreter.ghc args >>= E.throwIO+#if __GLASGOW_HASKELL__ < 904+-- GHC versions prior to 9.4.1 don't support response files.  For that reason+-- we want to expand early, so that GHCi gets expanded args.+doctestWithRepl repl = expandUnits >=> parseOptions >>> \ case+#else+doctestWithRepl repl = parseOptions >>> \ case+#endif+  Options.ProxyToGhc args -> exec Interpreter.ghc args   Options.Output s -> putStr s   Options.Result (Run warnings magicMode config) -> do     mapM_ (hPutStrLn stderr) warnings@@ -115,10 +126,7 @@ getAddDistArgs :: IO ([String] -> [String]) getAddDistArgs = do     env <- getEnvironment-    let dist =-            case lookup "HASKELL_DIST_DIR" env of-                Nothing -> "dist"-                Just x -> x+    let dist = fromMaybe "dist" $ lookup "HASKELL_DIST_DIR" env         autogen = dist ++ "/build/autogen/"         cabalMacros = autogen ++ "cabal_macros.h" @@ -139,11 +147,8 @@  type Result = Summary -isSuccess :: Result -> Bool-isSuccess s = sErrors s == 0 && sFailures s == 0- evaluateResult :: Result -> IO ()-evaluateResult r = when (not $ isSuccess r) exitFailure+evaluateResult r = unless (isSuccess r) exitFailure  doctestWithResult :: Config -> IO Result doctestWithResult config = do@@ -158,4 +163,9 @@ runDocTests :: Config -> [Module [Located DocTest]] -> IO Result runDocTests Config{..} modules = do   Interpreter.withInterpreter ((<> ghcOptions) <$> repl) $ \ interpreter -> withCP65001 $ do-    runModules fastMode preserveIt verbose interpreter modules+    runModules+      (if fastMode then FastMode else NoFastMode)+      (if preserveIt then PreserveIt else NoPreserveIt)+      (if failFast then FailFast else NoFailFast)+      (if verbose then Verbose else NonVerbose)+      interpreter modules
src/Runner.hs view
@@ -1,27 +1,39 @@ {-# LANGUAGE CPP #-}+{-# LANGUAGE LambdaCase #-} module Runner (   runModules+, FastMode(..)+, PreserveIt(..)+, FailFast(..)+, Verbose(..) , Summary(..)+, isSuccess+, formatSummary  #ifdef TEST , Report-, ReportState (..)+, ReportState(..)+, runReport+, Interactive(..) , report-, report_+, reportTransient #endif ) where -import           Prelude hiding (putStr, putStrLn, error)+import           Prelude ()+import           Imports hiding (putStr, putStrLn, error) -import           Control.Monad hiding (forM_) import           Text.Printf (printf)-import           System.IO (hPutStrLn, hPutStr, stderr, hIsTerminalDevice)-import           Data.Foldable (forM_)+import           System.IO hiding (putStr, putStrLn) -import           Control.Monad.Trans.State+import           Control.Monad.Trans.Class+import           Control.Monad.Trans.Maybe+import           Control.Monad.Trans.State (StateT, evalStateT)+import qualified Control.Monad.Trans.State as State import           Control.Monad.IO.Class+import           Data.IORef -import           Interpreter (Interpreter)+import           Interpreter (Interpreter, PreserveIt(..), safeEvalWith) import qualified Interpreter import           Parse import           Location@@ -30,115 +42,137 @@  -- | Summary of a test run. data Summary = Summary {-  sExamples :: Int-, sTried    :: Int-, sErrors   :: Int-, sFailures :: Int+  sExamples :: !Int+, sTried    :: !Int+, sErrors   :: !Int+, sFailures :: !Int } deriving Eq --- | Format a summary. instance Show Summary where-  show (Summary examples tried errors failures) =-    printf "Examples: %d  Tried: %d  Errors: %d  Failures: %d" examples tried errors failures+  show = formatSummary +isSuccess :: Summary -> Bool+isSuccess s = sErrors s == 0 && sFailures s == 0 +formatSummary :: Summary -> String+formatSummary (Summary examples tried errors failures) =+  printf "Examples: %d  Tried: %d  Errors: %d  Failures: %d" examples tried errors failures+ -- | Sum up summaries. instance Monoid Summary where   mempty = Summary 0 0 0 0-#if __GLASGOW_HASKELL__ < 804-  mappend-#else instance Semigroup Summary where-  (<>)-#endif-    (Summary x1 x2 x3 x4) (Summary y1 y2 y3 y4) = Summary (x1 + y1) (x2 + y2) (x3 + y3) (x4 + y4)+  Summary x1 x2 x3 x4 <> Summary y1 y2 y3 y4 = Summary (x1 + y1) (x2 + y2) (x3 + y3) (x4 + y4) +withLineBuffering :: Handle -> IO c -> IO c+withLineBuffering h action = bracket (hGetBuffering h) (hSetBuffering h) $ \ _ -> do+  hSetBuffering h LineBuffering+  action+ -- | Run all examples from a list of modules.-runModules :: Bool -> Bool -> Bool -> Interpreter -> [Module [Located DocTest]] -> IO Summary-runModules fastMode preserveIt verbose repl modules = do-  isInteractive <- hIsTerminalDevice stderr-  ReportState _ _ _ s <- (`execStateT` ReportState 0 isInteractive verbose mempty {sExamples = c}) $ do-    forM_ modules $ runModule fastMode preserveIt repl+runModules :: FastMode -> PreserveIt -> FailFast -> Verbose -> Interpreter -> [Module [Located DocTest]] -> IO Summary+runModules fastMode preserveIt failFast verbose repl modules = withLineBuffering stderr $ do -    verboseReport "# Final summary:"-    gets (show . reportStateSummary) >>= report+  interactive <- hIsTerminalDevice stderr <&> \ case+    False -> NonInteractive+    True -> Interactive -  return s+  summary <- newIORef mempty {sExamples = n}++  let+    reportFinalResult :: IO ()+    reportFinalResult = do+      final <- readIORef summary+      hPutStrLn stderr (formatSummary final)++    run :: IO ()+    run = runReport (ReportState interactive failFast verbose summary) $ do+      reportProgress+      forM_ modules $ runModule fastMode preserveIt repl+      verboseReport "# Final summary:"++  run `finally` reportFinalResult++  readIORef summary   where-    c = (sum . map count) modules+    n :: Int+    n = sum (map countExpressions modules) --- | Count number of expressions in given module.-count :: Module [Located DocTest] -> Int-count (Module _ setup tests) = sum (map length tests) + maybe 0 length setup+countExpressions :: Module [Located DocTest] -> Int+countExpressions (Module _ setup tests) = sum (map length tests) + maybe 0 length setup --- | A monad for generating test reports.-type Report = StateT ReportState IO+type Report = MaybeT (StateT ReportState IO) +data Interactive = NonInteractive | Interactive++data FastMode = NoFastMode | FastMode++data FailFast = NoFailFast | FailFast++data Verbose = NonVerbose | Verbose+ data ReportState = ReportState {-  reportStateCount        :: Int     -- ^ characters on the current line-, reportStateInteractive  :: Bool    -- ^ should intermediate results be printed?-, reportStateVerbose      :: Bool-, reportStateSummary      :: Summary -- ^ test summary+  reportStateInteractive :: Interactive+, reportStateFailFast :: FailFast+, reportStateVerbose :: Verbose+, reportStateSummary :: IORef Summary } +runReport :: ReportState -> Report () -> IO ()+runReport st = void . flip evalStateT st . runMaybeT++getSummary :: Report Summary+getSummary = gets reportStateSummary >>= liftIO . readIORef++gets :: (ReportState -> a) -> Report a+gets = lift . State.gets+ -- | Add output to the report. report :: String -> Report ()-report msg = do-  overwrite msg--  -- add a newline, this makes the output permanent-  liftIO $ hPutStrLn stderr ""-  modify (\st -> st {reportStateCount = 0})+report = liftIO . hPutStrLn stderr  -- | Add intermediate output to the report. -- -- This will be overwritten by subsequent calls to `report`/`report_`. -- Intermediate out may not contain any newlines.-report_ :: String -> Report ()-report_ msg = do-  f <- gets reportStateInteractive-  when f $ do-    overwrite msg-    modify (\st -> st {reportStateCount = length msg})---- | Add output to the report, overwrite any intermediate out.-overwrite :: String -> Report ()-overwrite msg = do-  n <- gets reportStateCount-  let str | 0 < n     = "\r" ++ msg ++ replicate (n - length msg) ' '-          | otherwise = msg-  liftIO (hPutStr stderr str)+reportTransient :: String -> Report ()+reportTransient msg = gets reportStateInteractive >>= \ case+  NonInteractive -> pass+  Interactive -> liftIO $ do+    hPutStr stderr msg+    hFlush stderr+    hPutStr stderr $ '\r' : (replicate (length msg) ' ') ++ "\r"  -- | Run all examples from given module.-runModule :: Bool -> Bool -> Interpreter -> Module [Located DocTest] -> Report ()+runModule :: FastMode -> PreserveIt -> Interpreter -> Module [Located DocTest] -> Report () runModule fastMode preserveIt repl (Module module_ setup examples) = do -  Summary _ _ e0 f0 <- gets reportStateSummary+  Summary _ _ e0 f0 <- getSummary    forM_ setup $     runTestGroup preserveIt repl reload -  Summary _ _ e1 f1 <- gets reportStateSummary+  Summary _ _ e1 f1 <- getSummary    -- only run tests, if setup does not produce any errors/failures   when (e0 == e1 && f0 == f1) $-    forM_ examples $-      runTestGroup preserveIt repl setup_+    forM_ examples $ runTestGroup preserveIt repl setup_   where     reload :: IO ()     reload = do-      unless fastMode $-        -- NOTE: It is important to do the :reload first! See-        -- https://gitlab.haskell.org/ghc/ghc/-/issues/5904, which results in a-        -- panic on GHC 7.4.1 if you do the :reload second.-        void $ Interpreter.safeEval repl ":reload"+      case fastMode of+        NoFastMode -> void $ Interpreter.safeEval repl ":reload"+        FastMode -> pass       void $ Interpreter.safeEval repl $ ":m *" ++ module_ -      when preserveIt $-        -- Evaluate a dumb expression to populate the 'it' variable NOTE: This is-        -- one reason why we cannot have safeEval = safeEvalIt: 'it' isn't set in-        -- a fresh GHCi session.-        void $ Interpreter.safeEval repl $ "()"+      case preserveIt of+        NoPreserveIt -> pass+        PreserveIt -> do+          -- Evaluate a dumb expression to populate the 'it' variable.+          --+          -- NOTE: This is one reason why we cannot just always use PreserveIt:+          -- 'it' isn't set in a fresh GHCi session.+          void $ Interpreter.safeEval repl $ "()"      setup_ :: IO ()     setup_ = do@@ -171,29 +205,35 @@   updateSummary (Summary 0 1 0 0)  verboseReport :: String -> Report ()-verboseReport xs = do-  verbose <- gets reportStateVerbose-  when verbose $ report xs+verboseReport msg = gets reportStateVerbose >>= \ case+  NonVerbose -> pass+  Verbose -> report msg  updateSummary :: Summary -> Report () updateSummary summary = do-  ReportState n f v s <- get-  put (ReportState n f v $ s `mappend` summary)+  ref <- gets reportStateSummary+  liftIO $ modifyIORef' ref $ mappend summary+  reportProgress+  gets reportStateFailFast >>= \ case+    NoFailFast -> pass+    FailFast -> unless (isSuccess summary) abort +abort :: Report ()+abort = MaybeT $ return Nothing+ reportProgress :: Report ()-reportProgress = do-  verbose <- gets reportStateVerbose-  when (not verbose) $ gets (show . reportStateSummary) >>= report_+reportProgress = gets reportStateVerbose >>= \ case+  NonVerbose -> do+    summary <- getSummary+    reportTransient (formatSummary summary)+  Verbose -> pass  -- | Run given test group. -- -- The interpreter state is zeroed with @:reload@ first.  This means that you -- can reuse the same 'Interpreter' for several test groups.-runTestGroup :: Bool -> Interpreter -> IO () -> [Located DocTest] -> Report ()+runTestGroup :: PreserveIt -> Interpreter -> IO () -> [Located DocTest] -> Report () runTestGroup preserveIt repl setup tests = do--  reportProgress-   liftIO setup   runExampleGroup preserveIt repl examples @@ -220,7 +260,7 @@ -- | -- Execute all expressions from given example in given 'Interpreter' and verify -- the output.-runExampleGroup :: Bool -> Interpreter -> [Located Interaction] -> Report ()+runExampleGroup :: PreserveIt -> Interpreter -> [Located Interaction] -> Report () runExampleGroup preserveIt repl = go   where     go ((Located loc (expression, expected)) : xs) = do@@ -236,8 +276,3 @@             reportSuccess             go xs     go [] = return ()--safeEvalWith :: Bool -> Interpreter -> String -> IO (Either String String)-safeEvalWith preserveIt-  | preserveIt = Interpreter.safeEvalIt-  | otherwise  = Interpreter.safeEval
+ src/Test/DocTest/Internal/Cabal.hs view
@@ -0,0 +1,10 @@+module Test.DocTest.Internal.Cabal (+  doctest+) where++import           Imports++import qualified Cabal++doctest :: [String] -> IO ()+doctest = Cabal.externalCommand
+ test/Cabal/OptionsSpec.hs view
@@ -0,0 +1,60 @@+{-# LANGUAGE CPP #-}+module Cabal.OptionsSpec (spec) where++import           Imports++import           Test.Hspec++import           System.IO+import           System.IO.Silently+import           System.Exit+import           System.Process+import           Data.Set ((\\))+import qualified Data.Set as Set++import qualified Cabal.ReplOptionsSpec as Repl++import           Cabal.Options++spec :: Spec+spec = do+  describe "replOnlyOptions" $ do+    it "is the set of options that are unique to 'cabal repl'" $ do+      build <- Set.fromList . lines <$> readProcess "cabal" ["build", "--list-options"] ""+      repl <- Set.fromList . lines <$> readProcess "cabal" ["repl", "--list-options"] ""+      Set.toList replOnlyOptions `shouldMatchList` Set.toList (repl \\ build)++  describe "rejectUnsupportedOptions" $ do+    it "produces error messages that are consistent with 'cabal repl'" $ do+      let+        shouldFail :: HasCallStack => String -> IO a -> Expectation+        shouldFail command action = do+          hCapture_ [stderr] (action `shouldThrow` (== ExitFailure 1))+            `shouldReturn` "Error: cabal: unrecognized '" <> command <> "' option `--installdir'\n"++#ifndef mingw32_HOST_OS+      shouldFail "repl" $ call "cabal" ["repl", "--installdir"]+#endif+      shouldFail "doctest" $ rejectUnsupportedOptions ["--installdir"]++    context "with --list-options" $ do+      it "lists supported command-line options" $ do+        repl <- Set.fromList . lines <$> readProcess "cabal" ["repl", "--list-options"] ""+        doctest <- Set.fromList . lines <$> capture_ (rejectUnsupportedOptions ["--list-options"] `shouldThrow` (== ExitSuccess))+        Set.toList (doctest \\ repl) `shouldMatchList` []+        Set.toList (repl \\ doctest) `shouldMatchList` Set.toList Repl.unsupported++  describe "discardReplOptions" $ do+    it "discards 'cabal repl'-only options" $ do+      discardReplOptions [+          "-w", "ghc-9.10"+        , "--build-depends=foo"+        , "--build-depends", "foo"+        , "-bfoo"+        , "-b", "foo"+        , "--disable-optimization"+        , "--enable-multi-repl"+        , "--repl-options", "foo"+        , "--repl-options=foo"+        , "--allow-newer"+        ] `shouldBe` ["--with-compiler=ghc-9.10", "--disable-optimization", "--allow-newer"]
+ test/Cabal/PathsSpec.hs view
@@ -0,0 +1,22 @@+module Cabal.PathsSpec (spec) where++import           Imports++import           Test.Hspec++import           System.Directory++import           Cabal ()+import           Cabal.Paths++spec :: Spec+spec = do+  describe "paths" $ do+    it "returns the path to 'ghc'" $ do+      (paths "cabal" [] >>= doesFileExist . ghc) `shouldReturn` True++    it "returns the path to 'ghc-pkg'" $ do+      (paths "cabal" [] >>= doesFileExist . ghcPkg) `shouldReturn` True++    it "returns the path to Cabal's cache directory" $ do+      (paths "cabal" [] >>= doesDirectoryExist . cache) `shouldReturn` True
+ test/Cabal/ReplOptionsSpec.hs view
@@ -0,0 +1,99 @@+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE ViewPatterns #-}+module Cabal.ReplOptionsSpec (spec, unsupported) where++import           Imports++import           Test.Hspec++import           Data.List+import           System.Process+import           Data.Set (Set)+import qualified Data.Set as Set++import           Cabal.ReplOptions++phony :: [String]+phony = [+    "with-PROG"+  , "PROG-option"+  , "PROG-options"+  ]++undocumented :: Set String+undocumented = Set.fromList [+    "--enable-optimisation"+  , "--disable-optimisation"+  , "--haddock-hyperlink-sources"+  , "--haddock-hyperlinked-source"+  ]++unsupported :: Set String+unsupported = undocumented <> Set.fromList (map ("--" <>) phony)++spec :: Spec+spec = do+  describe "options" $ do+    it "is the list of documented 'repl' options" $ do+      documentedOptions <- parseOptions <$> readProcess "cabal" ["help", "repl"] ""+      options `shouldBe` filter (optionName >>> (`notElem` phony)) documentedOptions++    it "is consistent with 'cabal repl --list-options'" $ do+      let+        optionNames :: Option -> [String]+        optionNames option = reverse $ "--" <> optionName option : case optionShortName option of+          Nothing -> []+          Just c -> [['-', c]]+  +      repl <- filter (`Set.notMember` unsupported) . lines <$> readProcess "cabal" ["repl", "--list-options"] ""+      concatMap optionNames options `shouldBe` repl++parseOptions :: String -> [Option]+parseOptions = map parseOption . takeOptions+  where+    parseOption :: String -> Option+    parseOption input = case input of+      longAndHelp@('-':'-':_) -> parseLongOption Nothing longAndHelp+      '-':short:',':' ':longAndHelp -> parseLongOption (Just short) longAndHelp+      '-':short:'[':(breakOn ']' ->+        (_arg, ']':',':' ':longAndHelp)) -> parseLongOption (Just short) longAndHelp+      '-':short:' ':(breakOn ' ' ->+        (arg, ' ':'o':'r':' ':(stripPrefix ('-':short:arg) ->+          Just (',':' ':longAndHelp)))) -> parseLongOption (Just short) longAndHelp+      _ -> err+      where+        parseLongOption :: Maybe Char -> String -> Option+        parseLongOption short longAndHelp = case breakOnAny " [=" longAndHelp of+          ('-':'-':long, ' ':help) -> accept long NoArgument help+          ('-':'-':long, '[':'=': (breakOn ']' ->+            (arg, ']':help))) -> accept long (OptionalArgument arg) help+          ('-':'-':long, '=':(breakOn ' ' ->+            (arg, ' ':help))) -> accept long (Argument arg) help+          _ -> err+          where+            accept :: String -> Argument -> String -> Option+            accept long arg help = Option long short arg (strip help)++        err :: HasCallStack => Option+        err = error input++        breakOn c = break (== c)+        breakOnAny xs = break (`elem` xs)++    takeOptions :: String -> [String]+    takeOptions input = map strip . joinLines $ case break (== "Flags for repl:") (lines input) of+      (_, "Flags for repl:" : xs) -> case break (== "") xs of+        (ys, "" : _) -> ys+        _ -> undefined+      _ -> undefined++    joinLines :: [String] -> [String]+    joinLines = go+      where+        go = \ case+          x : y : ys | isOption y  -> x : go (y : ys)+          x : y : ys -> go $ (x ++ ' ' : strip y) : ys+          x : xs -> x : xs+          [] -> []++        isOption = isPrefixOf " -"
test/Language/Haskell/GhciWrapperSpec.hs view
@@ -6,10 +6,9 @@ import           Test.Hspec import           System.IO.Silently -import           Control.Exception import           Data.List -import           Language.Haskell.GhciWrapper (Interpreter, Config(..), defaultConfig)+import           Language.Haskell.GhciWrapper (Interpreter, Config(..), defaultConfig, PreserveIt(..)) import qualified Language.Haskell.GhciWrapper as Interpreter  main :: IO ()@@ -31,11 +30,12 @@       withInterpreterConfig defaultConfig [] $ \ghci -> do         (capture $ Interpreter.evalEcho ghci ("putStr" ++ show "foo\nbar")) `shouldReturn` ("foo\nbar", "foo\nbar") -  describe "evalIt" $ do-    it "preserves it" $ do-      withInterpreterConfig defaultConfig [] $ \ghci -> do-        Interpreter.evalIt ghci "23" `shouldReturn` "23\n"-        Interpreter.eval ghci "it" `shouldReturn` "23\n"+  describe "evalWith" $ do+    context "with PreserveIt" $ do+      it "preserves it" $ do+        withInterpreterConfig defaultConfig [] $ \ghci -> do+          Interpreter.evalWith PreserveIt ghci "23" `shouldReturn` "23\n"+          Interpreter.eval ghci "it" `shouldReturn` "23\n"    describe "eval" $ do     it "shows literals" $ withInterpreter $ \ghci -> do@@ -78,20 +78,19 @@      it "shows exceptions" $ withInterpreter $ \ghci -> do       ghci "import Control.Exception" `shouldReturn` ""+#if __GLASGOW_HASKELL__ >= 912+      ghci "throwIO DivideByZero" `shouldReturn` "*** Exception: divide by zero\n\nHasCallStack backtrace:\n  throwIO, called at <interactive>:25:1 in interactive:Ghci22\n\n"+#else       ghci "throwIO DivideByZero" `shouldReturn` "*** Exception: divide by zero\n"+#endif      it "shows exceptions (ExitCode)" $ withInterpreter $ \ghci -> do       ghci "import System.Exit" `shouldReturn` ""       ghci "exitWith $ ExitFailure 10" `shouldReturn` "*** Exception: ExitFailure 10\n"      it "gives an error message for identifiers that are not in scope" $ withInterpreter $ \ghci -> do-#if __GLASGOW_HASKELL__ >= 800       ghci "foo" >>= (`shouldSatisfy` isInfixOf "Variable not in scope: foo")-#elif __GLASGOW_HASKELL__ >= 707-      ghci "foo" >>= (`shouldSatisfy` isSuffixOf "Not in scope: \8216foo\8217\n")-#else-      ghci "foo" >>= (`shouldSatisfy` isSuffixOf "Not in scope: `foo'\n")-#endif+     context "when configVerbose is True" $ do       it "prints prompt" $ do         withInterpreterConfig defaultConfig{configVerbose = True} [] $ \ghci -> do@@ -102,7 +101,7 @@      context "with -XOverloadedStrings, -Wall and -Werror" $ do       it "does not fail on marker expression (bug fix)" $ withInterpreter $ \ghci -> do-        ghci ":set -XOverloadedStrings -Wall -Werror" `shouldReturn` ""+        ghci ":seti -XOverloadedStrings -Wall -Werror" `shouldReturn` ""         ghci "putStrLn \"foo\"" `shouldReturn` "foo\n"      context "with NoImplicitPrelude" $ do
test/MainSpec.hs view
@@ -7,10 +7,9 @@ import           Test.Hspec import           Test.HUnit (assertEqual, Assertion) -import           Control.Exception import           System.Directory (getCurrentDirectory, setCurrentDirectory) import           System.FilePath-import           Run hiding (doctest)+import           Run hiding (doctest, doctestWith) import           System.IO.Silently import           System.IO @@ -20,14 +19,19 @@     setCurrentDirectory workingDir     action --- | Construct a doctest specific 'Assertion'. doctest :: HasCallStack => FilePath -> [String] -> Summary -> Assertion-doctest = doctestWithPreserveIt False+doctest = doctestWith 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})-  assertEqual label expected actual+doctestWithPreserveIt :: HasCallStack => FilePath -> [String] -> Summary -> Assertion+doctestWithPreserveIt = doctestWith True False++doctestWithFailFast :: HasCallStack => FilePath -> [String] -> Summary -> Assertion+doctestWithFailFast = doctestWith False True++doctestWith :: HasCallStack => Bool -> Bool -> FilePath -> [String] -> Summary -> Assertion+doctestWith 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 @@ -45,20 +49,34 @@         (cases 1)      it "it-variable" $ do-      doctestWithPreserveIt True "." ["it/Foo.hs"]+      doctestWithPreserveIt "." ["it/Foo.hs"]         (cases 5)      it "it-variable in $setup" $ do-      doctestWithPreserveIt True "." ["it/Setup.hs"]+      doctestWithPreserveIt "." ["it/Setup.hs"]         (cases 5)      it "failing" $ do       doctest "." ["failing/Foo.hs"]         (cases 1) {sFailures = 1} -    it "skips subsequent examples from the same group if an example fails" $+    it "skips subsequent examples from the same group if an example fails" $ do       doctest "." ["failing-multiple/Foo.hs"]         (cases 4) {sTried = 2, sFailures = 1}++    context "without --fail-fast" $ do+      it "continuous even if some tests fail" $ do+        doctest "fail-fast" ["Foo.hs"]+          (cases 4) {sTried = 4, sFailures = 1}++    context "with --fail-fast" $ do+      it "stops after the first failure" $ do+        doctestWithFailFast "fail-fast" ["Foo.hs"]+          (cases 4) {sTried = 2, sFailures = 1}++      it "stops after failures in $setup" $ do+        doctestWithFailFast "fail-fast" ["SetupFoo.hs"]+          (cases 6) {sTried = 1, sFailures = 1}      it "testImport" $ do       doctest "testImport" ["ModuleA.hs"]
test/OptionsSpec.hs view
@@ -65,7 +65,7 @@           fastMode . runConfig <$> parseOptions [] `shouldBe` Result False        context "with --fast" $ do-        it "enabled fast mode" $ do+        it "enables fast mode" $ do           fastMode . runConfig <$> parseOptions ["--fast"] `shouldBe` Result True      describe "--preserve-it" $ do@@ -76,6 +76,15 @@       context "with --preserve-it" $ do         it "preserves the `it` variable" $ do           preserveIt . runConfig <$> parseOptions ["--preserve-it"] `shouldBe` Result True++    describe "--fail-fast" $ do+      context "without --fail-fast" $ do+        it "disables fail-fast mode" $ do+          failFast . runConfig <$> parseOptions [] `shouldBe` Result False++      context "with --fail-fast" $ do+        it "enables fail-fast mode" $ do+          failFast . runConfig <$> parseOptions ["--fail-fast"] `shouldBe` Result True      context "with --help" $ do       it "outputs usage information" $ do
test/RunSpec.hs view
@@ -9,8 +9,8 @@ import qualified Control.Exception as E import           System.FilePath import           System.Directory (getCurrentDirectory, setCurrentDirectory)+import           System.IO.Temp (withSystemTempDirectory) import           Data.List (isPrefixOf, sort)-import           Data.Char  import           System.IO.Silently import           System.IO (stderr)@@ -35,6 +35,17 @@ removeLoadedPackageEnvironment = id #endif +verboseFibOutput :: String+verboseFibOutput = unlines [+    "### Started execution at test/integration/testSimple/Fib.hs:5."+  , "### example:"+  , "fib 10"+  , "### Successful!"+  , ""+  , "# Final summary:"+  , "Examples: 1  Tried: 1  Errors: 0  Failures: 0"+  ]+ spec :: Spec spec = do   describe "doctest" $ do@@ -70,17 +81,18 @@         , "Try `doctest --help' for more information."         ] +    it "interprets GHC response files" $ do+      withSystemTempDirectory "hspec" $ \ dir -> do+        let file = dir </> "response-file"+        writeFile file $ unlines [+            "test/integration/testSimple/Fib.hs"+          ]+        (r, ()) <- hCapture [stderr] $ doctest ["--verbose", '@':file]+        removeLoadedPackageEnvironment r `shouldBe` verboseFibOutput+     it "prints verbose description of a specification" $ do       (r, ()) <- hCapture [stderr] $ doctest ["--verbose", "test/integration/testSimple/Fib.hs"]-      removeLoadedPackageEnvironment r `shouldBe` unlines [-          "### Started execution at test/integration/testSimple/Fib.hs:5."-        , "### example:"-        , "fib 10"-        , "### Successful!"-        , ""-        , "# Final summary:"-        , "Examples: 1  Tried: 1  Errors: 0  Failures: 0"-        ]+      removeLoadedPackageEnvironment r `shouldBe` verboseFibOutput      it "prints verbose description of a property" $ do       (r, ()) <- hCapture [stderr] $ doctest ["--verbose", "test/integration/property-bool/Foo.hs"]@@ -118,23 +130,46 @@   describe "doctestWithResult" $ do     context "on parse error" $ do       let+        action :: IO Result         action = withCurrentDirectory "test/integration/parse-error" $ do-          doctestWithResult defaultConfig { ghcOptions = ["Foo.hs"] }+          doctestWithResult defaultConfig {+              ghcOptions = [+                  "Foo.hs" +                -- This is necessary due to:+                --+                -- https://gitlab.haskell.org/ghc/ghc/-/commit/88f38b03025386f0f1e8f5861eed67d80495168a+                --+                -- It will be fixed by:+                --+                -- https://gitlab.haskell.org/ghc/ghc/-/merge_requests/15995+                --+                , "-fdiagnostics-color=never"+#if __GLASGOW_HASKELL__ >= 910+                , "-fprint-error-index-links=never"+#endif+                ]+            }+       it "aborts with (ExitFailure 1)" $ do         hSilence [stderr] action `shouldThrow` (== ExitFailure 1)        it "prints a useful error message" $ do         (r, _) <- hCapture [stderr] (E.try action :: IO (Either ExitCode Summary))-        stripAnsiColors (removeLoadedPackageEnvironment r) `shouldBe` unlines [-            ""+        removeLoadedPackageEnvironment r `shouldBe` unlines (+#if __GLASGOW_HASKELL__ < 910+          "" :+#endif #if __GLASGOW_HASKELL__ >= 906-          , "Foo.hs:6:1: error: [GHC-58481]"+          [ "Foo.hs:6:1: error: [GHC-58481]" #else-          , "Foo.hs:6:1: error:"+          [ "Foo.hs:6:1: error:" #endif           , "    parse error (possibly incorrect indentation or mismatched brackets)"-          ]+#if __GLASGOW_HASKELL__ >= 910+          , ""+#endif+          ])    describe "expandDirs" $ do     it "expands a directory" $ do@@ -150,10 +185,3 @@       let x = "foo bar baz bin"       res <- expandDirs x       res `shouldBe` [x]--stripAnsiColors :: String -> String-stripAnsiColors xs = case xs of-  '\ESC' : '[' : ';' : ys | 'm' : zs <- dropWhile isNumber ys -> stripAnsiColors zs-  '\ESC' : '[' : ys | 'm' : zs <- dropWhile isNumber ys -> stripAnsiColors zs-  y : ys -> y : stripAnsiColors ys-  [] -> []
test/RunnerSpec.hs view
@@ -1,89 +1,44 @@ {-# LANGUAGE CPP, OverloadedStrings #-}-module RunnerSpec (main, spec) where+module RunnerSpec (spec) where  import           Imports  import           Test.Hspec +import           Data.IORef import           System.IO-import           System.IO.Silently (hCapture)-import           Control.Monad.Trans.State+import           System.IO.Silently (hCapture_) import           Runner -main :: IO ()-main = hspec spec--capture :: Report a -> IO String-capture = fmap fst . hCapture [stderr] . (`execStateT` ReportState 0 True False mempty)---- like capture, but with interactivity set to False-capture_ :: Report a -> IO String-capture_ = fmap fst . hCapture [stderr] . (`execStateT` ReportState 0 False False mempty)+capture :: Interactive -> Report () -> IO String+capture interactive action = do+  ref <- newIORef mempty+  hCapture_ [stderr] (runReport (ReportState interactive NoFailFast NonVerbose ref) action)  spec :: Spec spec = do-   describe "report" $ do-     context "when mode is interactive" $ do-       it "writes to stderr" $ do-        capture $ do+        capture Interactive $ do           report "foobar"         `shouldReturn` "foobar\n" -      it "overwrites any intermediate output" $ do-        capture $ do-          report_ "foo"-          report  "bar"-        `shouldReturn` "foo\rbar\n"--      it "blank out intermediate output if necessary" $ do-        capture $ do-          report_ "foobar"-          report  "baz"-        `shouldReturn` "foobar\rbaz   \n"-     context "when mode is non-interactive" $ do       it "writes to stderr" $ do-        capture_ $ do+        capture NonInteractive $ do           report "foobar"         `shouldReturn` "foobar\n"    describe "report_" $ do-     context "when mode is interactive" $ do-      it "writes intermediate output to stderr" $ do-        capture $ do-          report_ "foobar"-        `shouldReturn` "foobar"--      it "overwrites any intermediate output" $ do-        capture $ do-          report_ "foo"-          report_ "bar"-        `shouldReturn` "foo\rbar"--      it "blank out intermediate output if necessary" $ do-        capture $ do-          report_ "foobar"-          report_  "baz"-        `shouldReturn` "foobar\rbaz   "+      it "writes transient output to stderr" $ do+        capture Interactive $ do+          reportTransient "foobar"+        `shouldReturn` "foobar\r      \r"      context "when mode is non-interactive" $ do       it "is ignored" $ do-        capture_ $ do-          report_ "foobar"+        capture NonInteractive $ do+          reportTransient "foobar"         `shouldReturn` ""--      it "does not influence a subsequent call to `report`" $ do-        capture_ $ do-          report_ "foo"-          report  "bar"-        `shouldReturn` "bar\n"--      it "does not require `report` to blank out any intermediate output" $ do-        capture_ $ do-          report_ "foobar"-          report  "baz"-        `shouldReturn` "baz\n"
+ test/integration/fail-fast/Bar.hs view
@@ -0,0 +1,8 @@+module Bar where++-- | bar+-- a passing test+-- >>> bar+-- 42+bar :: Int+bar = 42
+ test/integration/fail-fast/Foo.hs view
@@ -0,0 +1,24 @@+module Foo where++import Bar++-- | 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
+ test/integration/fail-fast/SetupBar.hs view
@@ -0,0 +1,12 @@+module SetupBar where++-- $setup+-- >>> 23+-- 23++-- | bar+-- a passing test+-- >>> bar+-- 42+bar :: Int+bar = 42
+ test/integration/fail-fast/SetupFoo.hs view
@@ -0,0 +1,29 @@+module SetupFoo where++import SetupBar+++-- $setup+-- >>> 24+-- 23++-- | 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