packages feed

doctest 0.20.0 → 0.20.1

raw patch · 16 files changed

+629/−678 lines, 16 filesdep ~ghcPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: ghc

API changes (from Hackage documentation)

Files

CHANGES.markdown view
@@ -1,3 +1,6 @@+Changes in 0.20.1+  - GHC 9.4 compatibility. (#382)+ Changes in 0.20.0   - Allow doctest to be invoked via `cabal repl --with-ghc=doctest`   - Include `ghc --info` output in `--info`
LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2009-2018 Simon Hengel <sol@typeful.net>+Copyright (c) 2009-2022 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.markdown
@@ -1,479 +0,0 @@-# Doctest: Test interactive Haskell examples--`doctest` is a small program, that checks [examples in Haddock comments](http://www.haskell.org/haddock/doc/html/ch03s08.html#id566093).  It is similar-to the [popular Python module with the same name](http://docs.python.org/library/doctest.html).---## Installation--`doctest` is available from-[Hackage](http://hackage.haskell.org/cgi-bin/hackage-scripts/package/doctest).-Install it, by typing:--    cabal install doctest--Make sure that Cabal's `bindir` is on your `PATH`.--On Linux:--    export PATH="$HOME/.cabal/bin:$PATH"--On Mac OS X:--    export PATH="$HOME/Library/Haskell/bin:$PATH"--On Windows:--    set PATH="%AppData%\cabal\bin\;%PATH%"--For more information, see the [section on paths in the Cabal User Guide](http://www.haskell.org/cabal/users-guide/installing-packages.html#paths-in-the-simple-build-system).--## Usage--Below is a small Haskell module.-The module contains a Haddock comment with some examples of interaction.-The examples demonstrate how the module is supposed to be used.--```haskell-module Fib where---- | Compute Fibonacci numbers------ Examples:------ >>> fib 10--- 55------ >>> fib 5--- 5-fib :: Int -> Int-fib 0 = 0-fib 1 = 1-fib n = fib (n - 1) + fib (n - 2)-```--(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)-prints to `stdout` and `stderr` when evaluating that expression.)--With `doctest` you may check whether the implementation satisfies the given examples, by typing:--    doctest Fib.hs--You may produce Haddock documentation for that module with:--    haddock -h Fib.hs -o doc/--`doctest` will fail on comments that `haddock` also doesn't like.-Sometimes (e.g., [#251](https://github.com/sol/doctest/issues/251)), this means that `doctest` will fail on input that GHC accepts.--`doctest` likes UTF-8. If you are running it with, e.g., `LC_ALL=C`,-you may need to invoke `doctest` with `LC_ALL=C.UTF-8`.--### Example groups--Examples from a single Haddock comment are grouped together and share the same-scope.  E.g. the following works:--```haskell--- |--- >>> let x = 23--- >>> x + 42--- 65-```--If an example fails, subsequent examples from the same group are skipped.  E.g.-for--```haskell--- |--- >>> let x = 23--- >>> let n = x + y--- >>> print n-```--`print n` is not tried, because `let n = x + y` fails (`y` is not in scope!).--#### A note on performance--By default, `doctest` calls `:reload` between each group to clear GHCi's scope-of any local definitions. This ensures that previous examples cannot influence-later ones. However, it can lead to performance penalties if you are using-`doctest` in a project with many modules. One possible remedy is to pass the-`--fast` flag to `doctest`, which disables calling `:reload` between groups.-If `doctest`s are running too slowly, you might consider using `--fast`.-(With the caveat that the order in which groups appear now matters!)--However, note that due to a-[bug on GHC 8.2.1 or later](https://ghc.haskell.org/trac/ghc/ticket/14052),-the performance of `--fast` suffers significantly when combined with the-`--preserve-it` flag (which keeps the value of GHCi's `it` value between-examples).--### Setup code--You can put setup code in a [named chunk][named-chunks] with the name `$setup`.-The setup code is run before each example group.  If the setup code produces-any errors/failures, all tests from that module are skipped.--Here is an example:--```haskell-module Foo where--import Bar.Baz---- $setup--- >>> let x = 23 :: Int---- |--- >>> foo + x--- 65-foo :: Int-foo = 42-```--Note that you should not place setup code inbetween the module header (`module-...  where`) and import declarations. GHC will not be able to parse it ([issue- #167](https://github.com/sol/doctest/issues/167)). It is best to place setup-code right after import declarations, but due to its declarative nature you can-place it anywhere inbetween top level declarations as well.---### Multi-line input-GHCi supports commands which span multiple lines, and the same syntax works for doctest:--```haskell--- |--- >>> :{---  let---    x = 1---    y = 2---  in x + y + multiline--- :}--- 6-multiline = 3-```--Note that `>>>` can be left off for the lines following the first: this is so that-haddock does not strip leading whitespace. The expected output has whitespace-stripped relative to the :}.--Some peculiarities on the ghci side mean that whitespace at the very start is lost.-This breaks the example `broken`, since the x and y aren't aligned from ghci's-perspective.  A workaround is to avoid leading space, or add a newline such-that the indentation does not matter:--```haskell-{- | >>> :{-let x = 1-    y = 2-  in x + y + works-:}-6--}-works = 3--{- | >>> :{- let x = 1-     y = 2-  in x + y + broken-:}-3--}-broken = 3-```--### Multi-line output-If there are no blank lines in the output, multiple lines are handled-automatically.--```haskell--- | >>> putStr "Hello\nWorld!"--- Hello--- World!-```--If however the output contains blank lines, they must be noted-explicitly with `<BLANKLINE>`. For example,--```haskell-import Data.List ( intercalate )---- | Double-space a paragraph.------   Examples:------   >>> let s1 = "\"Every one of whom?\""---   >>> let s2 = "\"Every one of whom do you think?\""---   >>> let s3 = "\"I haven't any idea.\""---   >>> let paragraph = unlines [s1,s2,s3]---   >>> putStrLn $ doubleSpace paragraph---   "Every one of whom?"---   <BLANKLINE>---   "Every one of whom do you think?"---   <BLANKLINE>---   "I haven't any idea."----doubleSpace :: String -> String-doubleSpace = (intercalate "\n\n") . lines-```--### Matching arbitrary output-Any lines containing only three dots (`...`) will match one or more lines with-arbitrary content. For instance,--```haskell--- |--- >>> putStrLn "foo\nbar\nbaz"--- foo--- ...--- baz-```--If a line contains three dots and additional content, the three dots will match-anything *within that line*:--```haskell--- |--- >>> putStrLn "foo bar baz"--- foo ... baz-```--### QuickCheck properties--Haddock (since version 2.13.0) has markup support for properties.  Doctest can-verify properties with QuickCheck.  A simple property looks like this:--```haskell--- |--- prop> \xs -> sort xs == (sort . sort) (xs :: [Int])-```--The lambda abstraction is optional and can be omitted:--```haskell--- |--- prop> sort xs == (sort . sort) (xs :: [Int])-```--A complete example that uses setup code is below:--```haskell-module Fib where---- $setup--- >>> import Control.Applicative--- >>> import Test.QuickCheck--- >>> newtype Small = Small Int deriving Show--- >>> instance Arbitrary Small where arbitrary = Small . (`mod` 10) <$> arbitrary---- | Compute Fibonacci numbers------ The following property holds:------ prop> \(Small n) -> fib n == fib (n + 2) - fib (n + 1)-fib :: Int -> Int-fib 0 = 0-fib 1 = 1-fib n = fib (n - 1) + fib (n - 2)-```--If you see an error like the following, ensure that-[QuickCheck](http://hackage.haskell.org/package/QuickCheck) is a dependency-of the test-suite or executable running `doctest`.--```haskell-<interactive>:39:3:-    Not in scope: ‘polyQuickCheck’-    In the splice: $(polyQuickCheck (mkName "doctest_prop"))--<interactive>:39:3:-    GHC stage restriction:-      ‘polyQuickCheck’ is used in a top-level splice or annotation,-      and must be imported, not defined locally-    In the expression: polyQuickCheck (mkName "doctest_prop")-    In the splice: $(polyQuickCheck (mkName "doctest_prop"))-```--### Hiding examples from Haddock--You can put examples into [named chunks][named-chunks], and not refer to them-in the export list.  That way they will not be part of the generated Haddock-documentation, but Doctest will still find them.--```haskell--- $--- >>> 1 + 1--- 2-```--[named-chunks]: http://www.haskell.org/haddock/doc/html/ch03s05.html--### Using GHC extensions--There's two sets of GHC extensions involved when running Doctest:--1. The set of GHC extensions that are active when compiling the module code-(excluding the doctest examples). The easiest way to specify these extensions-is through [LANGUAGE pragmas][language-pragma] in your source files.-(Doctest will not look at your cabal file.)-2. The set of GHC extensions that are active when executing the Doctest-examples. (These are not influenced by the LANGUAGE pragmas in the file.) The-recommended way to enable extensions for Doctest examples is to switch them-on like this:--```haskell--- |--- >>> :set -XTupleSections--- >>> fst' $ (1,) 2--- 1-fst' :: (a, b) -> a-fst' = fst-```--Alternatively you can pass any GHC options to Doctest, e.g.:--    doctest -XCPP Foo.hs--These options will affect both the loading of the module and the execution of-the Doctest examples.--If you want to omit the information which language extensions are enabled from-the Doctest examples you can use the method described in [Hiding examples from-Haddock](#hiding-examples-from-haddock), e.g.:--```haskell--- $--- >>> :set -XTupleSections-```--[language-pragma]: http://www.haskell.org/ghc/docs/latest/html/users_guide/pragmas.html#language-pragma--### Limitations--Due to [a GHC bug](https://gitlab.haskell.org/ghc/ghc/-/issues/20670), running-`:set -XTemplateHaskell` within `ghci` may unload any modules that were-specified on the command line.--To address this `doctest >= 0.19.0` does two things:--1. Doctest always enables `-XTemplateHaskell`.  So it is safe to use Template-   Haskell in examples without enabling the extension explicitly.-1. Doctest filters out `-XTemplateHaskell` from single-line `:set`-statements.-   So it is still safe to include `:set -XTemplateHaskell` in examples for-   documentation purposes.  It may just not work as intended in `ghci` due to-   that GHC bug.--Doctest does not filter out `-XTemplateHaskell` from multi-line-`:set`-statements.  So if you e.g. use--```->>> :{-:set -XTemplateHaskell-:}-```-then you are on your own.---### Cabal integration--Doctest provides both, an executable and a library.  The library exposes a-function `doctest` of type:--```haskell-doctest :: [String] -> IO ()-```--Doctest's own `main` is simply:--```haskell-main = getArgs >>= doctest-```--Consequently, it is possible to create a custom executable for a project, by-passing all command-line arguments that are required for that project to-`doctest`.  A simple example looks like this:--```haskell--- file doctests.hs-import Test.DocTest-main = doctest ["-isrc", "src/Main.hs"]-```--And a corresponding Cabal test suite section like this:--    test-suite doctests-      type:          exitcode-stdio-1.0-      ghc-options:   -threaded-      main-is:       doctests.hs-      build-depends: base, doctest >= 0.8--## Doctest in the wild--You can find real world examples of `Doctest` being used below:--  * [base Data/Maybe.hs](https://github.com/ghc/ghc/blob/669cbef03c220de43b0f88f2b2238bf3c02ed64c/libraries/base/Data/Maybe.hs#L36-L79)-  * [base Data/Functor.hs](https://github.com/ghc/ghc/blob/669cbef03c220de43b0f88f2b2238bf3c02ed64c/libraries/base/Data/Functor.hs#L34-L64)---## Doctest extensions--  * [doctest-discover](https://github.com/karun012/doctest-discover)--## Development [![Build Status](https://secure.travis-ci.org/sol/doctest.png)](http://travis-ci.org/sol/doctest)--Join in at `#hspec` on freenode.--Discuss your ideas first, ideally by opening an issue on GitHub.--Add tests for new features, and make sure that the test suite passes with your-changes.--    cabal configure --enable-tests && cabal build && cabal exec cabal test---## Contributors-- * Adam Vogt- * Alan Zimmerman- * Alexander Bernauer- * Alexandre Esteves- * Anders Persson- * Andreas Abel- * Ankit Ahuja- * Artyom Kazak- * Edward Kmett- * Gabor Greif- * 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--For up-to-date list, query--    git shortlog -s
+ README.md view
@@ -0,0 +1,533 @@+# Doctest: Test interactive Haskell examples++`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)+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).++* [Getting started](#getting-started)+   * [Installation](#installation)+   * [A basic example](#a-basic-example)+   * [Running doctest for a Cabal package](#running-doctest-for-a-cabal-package)+* [Writing examples and properties](#writing-examples-and-properties)+   * [Example groups](#example-groups)+      * [A note on performance](#a-note-on-performance)+   * [Setup code](#setup-code)+   * [Multi-line input](#multi-line-input)+   * [Multi-line output](#multi-line-output)+   * [Matching arbitrary output](#matching-arbitrary-output)+   * [QuickCheck properties](#quickcheck-properties)+   * [Hiding examples from Haddock](#hiding-examples-from-haddock)+   * [Using GHC extensions](#using-ghc-extensions)+* [Limitations](#limitations)+* [Doctest in the wild](#doctest-in-the-wild)+* [Development](#development)+* [Contributors](#contributors)+++# Getting started++## Installation++`doctest` is available from+[Hackage](http://hackage.haskell.org/cgi-bin/hackage-scripts/package/doctest).+Install it with:++    cabal update && cabal install doctest++Make sure that Cabal's `bindir` is on your `PATH`.++On Linux:++    export PATH="$HOME/.cabal/bin:$PATH"++On Mac OS X:++    export PATH="$HOME/Library/Haskell/bin:$PATH"++On Windows:++    set PATH="%AppData%\cabal\bin\;%PATH%"++## A basic example++Below is a small Haskell module.+The module contains a Haddock comment with some examples of interaction.+The examples demonstrate how the module is supposed to be used.++```haskell+-- src/Fib.hs+module Fib where++-- | Compute Fibonacci numbers+--+-- Examples:+--+-- >>> fib 10+-- 55+--+-- >>> fib 5+-- 5+fib :: Int -> Int+fib 0 = 0+fib 1 = 1+fib n = fib (n - 1) + fib (n - 2)++```++(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)+prints to `stdout` and `stderr` when evaluating that expression.)++With `doctest` you can check whether the implementation satisfies the given+examples:++```+doctest src/Fib.hs+```+++## Running `doctest` for a Cabal package++The easiest way to run `doctest` for a Cabal package is via `cabal repl --with-ghc=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+will pass any required GHC options to `doctest`.++A simple `.cabal` file for `Fib` looks like this:++```cabal+-- fib.cabal+cabal-version: 1.12++name:           fib+version:        0.0.0+build-type:     Simple++library+  build-depends: base == 4.*+  hs-source-dirs: src+  exposed-modules: Fib+  default-language: Haskell2010++```++With a `.cabal` file in place, it is possible to run `doctest` via `cabal repl`:++```+$ cabal repl --with-ghc=doctest+...+Examples: 2  Tried: 2  Errors: 0  Failures: 0+```+++Notes:++- If you use properties you need to pass `--build-depends=QuickCheck` and+  `--build-depends=template-haskell` to `cabal repl`.++- `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`+  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`).++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+```++(This is what you want to use on CI.)+++# Writing examples and properties++## Example groups++Examples from a single Haddock comment are grouped together and share the same+scope.  E.g. the following works:++```haskell+-- |+-- >>> let x = 23+-- >>> x + 42+-- 65+```++If an example fails, subsequent examples from the same group are skipped.  E.g.+for++```haskell+-- |+-- >>> let x = 23+-- >>> let n = x + y+-- >>> print n+```++`print n` is skipped, because `let n = x + y` fails (as `y` is not in scope).++### A note on performance++By default, `doctest` calls `:reload` between each group to clear GHCi's scope+of any local definitions. This ensures that previous examples cannot influence+later ones. However, it can lead to performance penalties if you are using+`doctest` in a project with many modules. One possible remedy is to pass the+`--fast` flag to `doctest`, which disables calling `:reload` between groups.+If `doctest`s are running too slowly, you might consider using `--fast`.+(With the caveat that the order in which groups appear now matters!)++However, note that due to a+[bug on GHC 8.2.1 or later](https://ghc.haskell.org/trac/ghc/ticket/14052),+the performance of `--fast` suffers significantly when combined with the+`--preserve-it` flag (which keeps the value of GHCi's `it` value between+examples).++## Setup code++You can put setup code in a [named chunk][named-chunks] with the name `$setup`.+The setup code is run before each example group.  If the setup code produces+any errors/failures, all tests from that module are skipped.++Here is an example:++```haskell+module Foo where++import Bar.Baz++-- $setup+-- >>> let x = 23 :: Int++-- |+-- >>> foo + x+-- 65+foo :: Int+foo = 42+```++Note that you should not place setup code inbetween the module header (`module+...  where`) and import declarations. GHC will not be able to parse it ([issue+ #167](https://github.com/sol/doctest/issues/167)). It is best to place setup+code right after import declarations, but due to its declarative nature you can+place it anywhere inbetween top level declarations as well.+++## Multi-line input+GHCi supports commands which span multiple lines, and the same syntax works for doctest:++```haskell+-- |+-- >>> :{+--  let+--    x = 1+--    y = 2+--  in x + y + multiline+-- :}+-- 6+multiline = 3+```++Note that `>>>` can be left off for the lines following the first: this is so that+haddock does not strip leading whitespace. The expected output has whitespace+stripped relative to the :}.++Some peculiarities on the ghci side mean that whitespace at the very start is lost.+This breaks the example `broken`, since the x and y aren't aligned from ghci's+perspective.  A workaround is to avoid leading space, or add a newline such+that the indentation does not matter:++```haskell+{- | >>> :{+let x = 1+    y = 2+  in x + y + works+:}+6+-}+works = 3++{- | >>> :{+ let x = 1+     y = 2+  in x + y + broken+:}+3+-}+broken = 3+```++## Multi-line output+If there are no blank lines in the output, multiple lines are handled+automatically.++```haskell+-- | >>> putStr "Hello\nWorld!"+-- Hello+-- World!+```++If however the output contains blank lines, they must be noted+explicitly with `<BLANKLINE>`. For example,++```haskell+import Data.List ( intercalate )++-- | Double-space a paragraph.+--+--   Examples:+--+--   >>> let s1 = "\"Every one of whom?\""+--   >>> let s2 = "\"Every one of whom do you think?\""+--   >>> let s3 = "\"I haven't any idea.\""+--   >>> let paragraph = unlines [s1,s2,s3]+--   >>> putStrLn $ doubleSpace paragraph+--   "Every one of whom?"+--   <BLANKLINE>+--   "Every one of whom do you think?"+--   <BLANKLINE>+--   "I haven't any idea."+--+doubleSpace :: String -> String+doubleSpace = (intercalate "\n\n") . lines+```++## Matching arbitrary output+Any lines containing only three dots (`...`) will match one or more lines with+arbitrary content. For instance,++```haskell+-- |+-- >>> putStrLn "foo\nbar\nbaz"+-- foo+-- ...+-- baz+```++If a line contains three dots and additional content, the three dots will match+anything *within that line*:++```haskell+-- |+-- >>> putStrLn "foo bar baz"+-- foo ... baz+```++## QuickCheck properties++Haddock has markup support for properties.  Doctest can verify properties with+QuickCheck.  A simple property looks like this:++```haskell+-- |+-- prop> \xs -> sort xs == (sort . sort) (xs :: [Int])+```++The lambda abstraction is optional and can be omitted:++```haskell+-- |+-- prop> sort xs == (sort . sort) (xs :: [Int])+```++A complete example that uses setup code is below:++```haskell+module Fib where++-- $setup+-- >>> import Control.Applicative+-- >>> import Test.QuickCheck+-- >>> newtype Small = Small Int deriving Show+-- >>> instance Arbitrary Small where arbitrary = Small . (`mod` 10) <$> arbitrary++-- | Compute Fibonacci numbers+--+-- The following property holds:+--+-- prop> \(Small n) -> fib n == fib (n + 2) - fib (n + 1)+fib :: Int -> Int+fib 0 = 0+fib 1 = 1+fib n = fib (n - 1) + fib (n - 2)+```++If you see an error like the following, ensure that+[QuickCheck](http://hackage.haskell.org/package/QuickCheck) is visible to+`doctest` (e.g. by passing `--build-depends=QuickCheck` to `cabal repl`).++```haskell+<interactive>:39:3:+    Not in scope: ‘polyQuickCheck’+    In the splice: $(polyQuickCheck (mkName "doctest_prop"))++<interactive>:39:3:+    GHC stage restriction:+      ‘polyQuickCheck’ is used in a top-level splice or annotation,+      and must be imported, not defined locally+    In the expression: polyQuickCheck (mkName "doctest_prop")+    In the splice: $(polyQuickCheck (mkName "doctest_prop"))+```++## Hiding examples from Haddock++You can put examples into [named chunks][named-chunks], and not refer to them+in the export list.  That way they will not be part of the generated Haddock+documentation, but Doctest will still find them.++```haskell+-- $+-- >>> 1 + 1+-- 2+```++[named-chunks]: http://www.haskell.org/haddock/doc/html/ch03s05.html++## Using GHC extensions++There's two sets of GHC extensions involved when running Doctest:++1. The set of GHC extensions that are active when compiling the module code+   (excluding the doctest examples). The easiest way to specify these+   extensions is through [LANGUAGE pragmas][language-pragma] in your source+   files.++1. The set of GHC extensions that are active when executing the Doctest+   examples. (These are not influenced by the LANGUAGE pragmas in the file.)+   The recommended way to enable extensions for Doctest examples is to switch+   them on like this:++```haskell+-- |+-- >>> :set -XTupleSections+-- >>> fst' $ (1,) 2+-- 1+fst' :: (a, b) -> a+fst' = fst+```++Alternatively you can pass any GHC options to Doctest, e.g.:++    doctest -XCPP Foo.hs++These options will affect both the loading of the module and the execution of+the Doctest examples.++If you want to omit the information which language extensions are enabled from+the Doctest examples you can use the method described in [Hiding examples from+Haddock](#hiding-examples-from-haddock), e.g.:++```haskell+-- $+-- >>> :set -XTupleSections+```++[language-pragma]: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/exts/pragmas.html#language-pragma++# Limitations+++- Doctests only works on platforms that have support for GHC's `--interactive` mode (`ghci`).+++- Due to [a GHC bug](https://gitlab.haskell.org/ghc/ghc/-/issues/20670), running+  `:set -XTemplateHaskell` within `ghci` may unload any modules that were+  specified on the command-line.++  To address this `doctest >= 0.19.0` does two things:++  1. Doctest always enables `-XTemplateHaskell`.  So it is safe to use Template+    Haskell in examples without enabling the extension explicitly.+  1. Doctest filters out `-XTemplateHaskell` from single-line `:set`-statements.+    So it is still safe to include `:set -XTemplateHaskell` in examples for+    documentation purposes.  It may just not work as intended in `ghci` due to+    that GHC bug.++  Doctest does not filter out `-XTemplateHaskell` from multi-line+  `:set`-statements.  So if you e.g. use++  ```+  >>> :{+  :set -XTemplateHaskell+  :}+  ```+  then you are on your own.++  Note that all platforms that support `--interactive` also support+  `-XTemplateHaskell`.  So this approach does not reduce Doctest's platform+  support.++- Modules that are rejected by `haddock` will not work with `doctest`.  This+  can mean that `doctest` fails on input that is accepted by GHC (e.g.+  [#251](https://github.com/sol/doctest/issues/251)).++- Doctest works best with UTF-8.  If your locale is e.g. `LC_ALL=C`, you may+  want to invoke `doctest` with `LC_ALL=C.UTF-8`.++# Doctest in the wild++You can find real world examples of `Doctest` being used below:++  * [base Data/Maybe.hs](https://github.com/ghc/ghc/blob/669cbef03c220de43b0f88f2b2238bf3c02ed64c/libraries/base/Data/Maybe.hs#L36-L79)+  * [base Data/Functor.hs](https://github.com/ghc/ghc/blob/669cbef03c220de43b0f88f2b2238bf3c02ed64c/libraries/base/Data/Functor.hs#L34-L64)+++# Development++Discuss your ideas first, ideally by opening an issue on GitHub.++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+++# Contributors++ * Adam Vogt+ * Alan Zimmerman+ * Alexander Bernauer+ * Alexandre Esteves+ * Anders Persson+ * Andreas Abel+ * Ankit Ahuja+ * Artyom Kazak+ * Edward Kmett+ * Gabor Greif+ * 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++For up-to-date list, query++    git shortlog -s
doctest.cabal view
@@ -1,14 +1,16 @@ cabal-version: 1.12 --- This file has been generated from package.yaml by hpack version 0.34.4.+-- This file has been generated from package.yaml by hpack version 0.35.0. -- -- see: https://github.com/sol/hpack  name:           doctest-version:        0.20.0+version:        0.20.1 synopsis:       Test interactive Haskell examples-description:    The doctest program checks examples in source code comments.  It is modeled-                after doctest for Python (<https://docs.python.org/3/library/doctest.html>).+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)+                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).                 .                 Documentation is at <https://github.com/sol/doctest#readme>. category:       Testing@@ -16,7 +18,7 @@ homepage:       https://github.com/sol/doctest#readme license:        MIT license-file:   LICENSE-copyright:      (c) 2009-2018 Simon Hengel+copyright:      (c) 2009-2022 Simon Hengel author:         Simon Hengel <sol@typeful.net> maintainer:     quasicomputational@gmail.com, Andreas Abel build-type:     Simple@@ -99,7 +101,7 @@     test/integration/with-cbits/Bar.hs     test/integration/with-cbits/foo.c     CHANGES.markdown-    README.markdown+    README.md  source-repository head   type: git@@ -136,7 +138,7 @@     , directory     , exceptions     , filepath-    , ghc >=7.0 && <9.3+    , ghc >=8.0 && <9.5     , ghc-paths >=0.1.0.9     , process     , syb >=0.3@@ -159,7 +161,7 @@     , doctest     , exceptions     , filepath-    , ghc >=7.0 && <9.3+    , ghc >=8.0 && <9.5     , ghc-paths >=0.1.0.9     , process     , syb >=0.3@@ -220,7 +222,7 @@     , directory     , exceptions     , filepath-    , ghc >=7.0 && <9.3+    , ghc >=8.0 && <9.5     , ghc-paths >=0.1.0.9     , hspec >=2.3.0     , hspec-core >=2.3.0
src/Extract.hs view
@@ -3,23 +3,14 @@  import           Prelude hiding (mod, concat) import           Control.Monad-#if __GLASGOW_HASKELL__ < 710-import           Control.Applicative-#endif import           Control.Exception import           Data.List (partition, isSuffixOf) import           Data.Maybe-#if __GLASGOW_HASKELL__ < 710-import           Data.Foldable (concat)-#endif  import           Control.DeepSeq (deepseq, NFData(rnf)) import           Data.Generics -#if __GLASGOW_HASKELL__ < 707-import           GHC hiding (flags, Module, Located)-import           MonadUtils (liftIO, MonadIO)-#elif __GLASGOW_HASKELL__ < 900+#if __GLASGOW_HASKELL__ < 900 import           GHC hiding (Module, Located) import           DynFlags import           MonadUtils (liftIO)@@ -41,11 +32,6 @@ import           System.Directory import           System.FilePath -#if __GLASGOW_HASKELL__ < 710-import           NameSet (NameSet)-import           Coercion (Coercion)-#endif- #if __GLASGOW_HASKELL__ < 805 import           FastString (unpackFS) #endif@@ -137,15 +123,11 @@     modifySessionDynFlags :: (DynFlags -> DynFlags) -> Ghc ()     modifySessionDynFlags f = do       dflags <- getSessionDynFlags-#if __GLASGOW_HASKELL__ < 707-      _ <- setSessionDynFlags (f dflags)-#else       -- GHCi 7.7 now uses dynamic linking.       let dflags' = case lookup "GHC Dynamic" (compilerInfo dflags) of             Just "YES" -> gopt_set dflags Opt_BuildDynamicToo             _          -> dflags       _ <- setSessionDynFlags (f dflags')-#endif       return ()      withTempOutputDir :: Ghc a -> Ghc a@@ -181,11 +163,7 @@       _ <- setSessionDynFlags (GHC.ms_hspp_opts modsum)       hsc_env <- getSession -# if __GLASGOW_HASKELL__ >= 903-      hsc_env' <- liftIO (initializePlugins hsc_env Nothing)-      setSession hsc_env'-      return $ modsum-# elif __GLASGOW_HASKELL__ >= 901+# if __GLASGOW_HASKELL__ >= 902       hsc_env' <- liftIO (initializePlugins hsc_env)       setSession hsc_env'       return $ modsum@@ -225,6 +203,11 @@     (setup, docs) = partition isSetup (docStringsFromModule m)     name = (moduleNameString . GHC.moduleName . ms_mod . pm_mod_summary) m +#if __GLASGOW_HASKELL__ >= 904+unpackHDS :: HsDocString -> String+unpackHDS = renderHsDocString+#endif+ -- | Extract all docstrings from given module. docStringsFromModule :: ParsedModule -> [(Maybe String, Located String)] docStringsFromModule mod = map (fmap (toLocated . fmap unpackHDS)) docs@@ -232,66 +215,58 @@     source   = (unLoc . pm_parsed_source) mod      -- we use dlist-style concatenation here+    docs :: [(Maybe String, LHsDocString)]     docs     = header ++ exports ++ decls      -- We process header, exports and declarations separately instead of     -- traversing the whole source in a generic way, to ensure that we get     -- everything in source order.+#if __GLASGOW_HASKELL__ >= 904+    header  = [(Nothing, hsDocString <$> x) | Just x <- [hsmodHaddockModHeader source]]+#else     header  = [(Nothing, x) | Just x <- [hsmodHaddockModHeader source]]+#endif+    exports :: [(Maybe String, LHsDocString)]+#if __GLASGOW_HASKELL__ >= 904+    exports = [ (Nothing, L (locA loc) (hsDocString (unLoc doc)))+#else     exports = [ (Nothing, L (locA loc) doc)-#if __GLASGOW_HASKELL__ < 710-              | L loc (IEDoc doc) <- concat (hsmodExports source)-#elif __GLASGOW_HASKELL__ < 805+#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) -type Selector a = a -> ([(Maybe String, LHsDocString)], Bool)--#if __GLASGOW_HASKELL__ < 710--- | Ignore a subtree.-ignore :: Selector a-ignore = const ([], True)-#endif---- | Collect given value and descend into subtree.-select :: a -> ([a], Bool)-select x = ([x], False)- -- | Extract all docstrings from given value. extractDocStrings :: Data a => a -> [(Maybe String, LHsDocString)]-extractDocStrings = everythingBut (++) (([], False) `mkQ` fromLHsDecl-  `extQ` fromLDocDecl-  `extQ` fromLHsDocString-#if __GLASGOW_HASKELL__ < 710-  `extQ` (ignore :: Selector NameSet)-  `extQ` (ignore :: Selector PostTcKind)--  -- HsExpr never contains any documentation, but it may contain error thunks.-  ---  -- Problematic are (non comprehensive):-  ---  --  * parallel list comprehensions-  --  * infix operators-  ---  `extQ` (ignore :: Selector (HsExpr RdrName))--  -- undefined before type checking-  `extQ` (ignore :: Selector Coercion)+extractDocStrings d =+#if __GLASGOW_HASKELL__ >= 904+  let+    docStrs = extractAll extractDocDocString d+    docStrNames = catMaybes $ extractAll extractDocName d+  in+    flip fmap docStrs $ \docStr -> (lookup (getLoc docStr) docStrNames, docStr)+  where+    extractAll z = everything (++) ((mkQ [] ((:[]) . z))) -#if __GLASGOW_HASKELL__ >= 706-  -- hswb_kvs and hswb_tvs may be error thunks-  `extQ` (ignore :: Selector (HsWithBndrs [LHsType RdrName]))-  `extQ` (ignore :: Selector (HsWithBndrs [LHsType Name]))-  `extQ` (ignore :: Selector (HsWithBndrs (LHsType RdrName)))-  `extQ` (ignore :: Selector (HsWithBndrs (LHsType Name)))-#endif+    extractDocDocString :: LHsDoc GhcPs -> LHsDocString+    extractDocDocString = fmap hsDocString -#endif-  )+    extractDocName :: DocDecl GhcPs -> Maybe (SrcSpan, String)+    extractDocName docDecl = case docDecl of+      DocCommentNamed name y ->+        Just (getLoc y, name)+      _ ->+        Nothing+#else+  everythingBut (++) (([], False) `mkQ` fromLHsDecl+  `extQ` fromLDocDecl+  `extQ` fromLHsDocString+  ) d   where     fromLHsDecl :: Selector (LHsDecl GhcPs)     fromLHsDecl (L loc decl) = case decl of@@ -323,6 +298,13 @@     fromDocDecl loc x = case x of       DocCommentNamed name doc -> (Just name, L loc doc)       _                        -> (Nothing, L loc $ docDeclDoc x)++type Selector a = a -> ([(Maybe String, LHsDocString)], Bool)++-- | 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.
src/GhcUtil.hs view
@@ -2,18 +2,12 @@ module GhcUtil (withGhc) where  import           GHC.Paths (libdir)-#if __GLASGOW_HASKELL__ < 707-import           Control.Exception-import           GHC hiding (flags)-import           DynFlags (dopt_set)-#else import           GHC #if __GLASGOW_HASKELL__ < 900 import           DynFlags (gopt_set) #else import           GHC.Driver.Session (gopt_set) #endif-#endif  #if __GLASGOW_HASKELL__ < 900 import           Panic (throwGhcException)@@ -29,50 +23,26 @@  import           System.Exit (exitFailure) -#if __GLASGOW_HASKELL__ < 702-import           StaticFlags (v_opt_C_ready)-import           Data.IORef (writeIORef)-#elif __GLASGOW_HASKELL__ < 707-import           StaticFlags (saveStaticFlagGlobals, restoreStaticFlagGlobals)-#elif __GLASGOW_HASKELL__ < 801+#if __GLASGOW_HASKELL__ < 801 import           StaticFlags (discardStaticFlags) #endif ---- | Save static flag globals, run action, and restore them.-bracketStaticFlags :: IO a -> IO a-#if __GLASGOW_HASKELL__ < 702--- GHC < 7.2 does not provide saveStaticFlagGlobals/restoreStaticFlagGlobals,--- so we need to modifying v_opt_C_ready directly-bracketStaticFlags action = action `finally` writeIORef v_opt_C_ready False-#elif __GLASGOW_HASKELL__ < 707-bracketStaticFlags action = bracket saveStaticFlagGlobals restoreStaticFlagGlobals (const action)-#else-bracketStaticFlags action = action-#endif- -- Catch GHC source errors, print them and exit. handleSrcErrors :: Ghc a -> Ghc a handleSrcErrors action' = flip handleSourceError action' $ \err -> do-#if __GLASGOW_HASKELL__ < 702-  printExceptionAndWarnings err-#else   printException err-#endif   liftIO exitFailure  -- | Run a GHC action in Haddock mode withGhc :: [String] -> ([String] -> Ghc a) -> IO a-withGhc flags action = bracketStaticFlags $ do+withGhc flags action = do   flags_ <- handleStaticFlags flags    runGhc (Just libdir) $ do     handleDynamicFlags flags_ >>= handleSrcErrors . action  handleStaticFlags :: [String] -> IO [Located String]-#if __GLASGOW_HASKELL__ < 707-handleStaticFlags flags = fst `fmap` parseStaticFlags (map noLoc flags)-#elif __GLASGOW_HASKELL__ < 801+#if __GLASGOW_HASKELL__ < 801 handleStaticFlags flags = return $ map noLoc $ discardStaticFlags flags #else handleStaticFlags flags = return $ map noLoc $ flags@@ -98,11 +68,7 @@     _       -> return srcs  setHaddockMode :: DynFlags -> DynFlags-#if __GLASGOW_HASKELL__ < 707-setHaddockMode dynflags = (dopt_set dynflags Opt_Haddock) {-#else setHaddockMode dynflags = (gopt_set dynflags Opt_Haddock) {-#endif #if __GLASGOW_HASKELL__ >= 901       backend   = NoBackend #else
src/Interpreter.hs view
@@ -16,9 +16,6 @@  import           System.Process import           System.Directory (getPermissions, executable)-#if __GLASGOW_HASKELL__ < 710-import           Control.Applicative-#endif import           Control.Monad import           Control.Exception hiding (handle) import           Data.Char
src/Location.hs view
@@ -13,10 +13,6 @@ import           GHC.Data.FastString (unpackFS) #endif -#if __GLASGOW_HASKELL__ < 702-import           Outputable (showPpr)-#endif- -- | A thing with a location attached. data Located a = Located Location a   deriving (Eq, Show, Functor)@@ -61,13 +57,7 @@  -- | Convert a GHC source span to a location. toLocation :: SrcSpan -> Location-#if __GLASGOW_HASKELL__ < 702-toLocation loc-  | isGoodSrcLoc start = Location (unpackFS $ srcLocFile start) (srcLocLine start)-  | otherwise          = (UnhelpfulLocation . showPpr) start-  where-    start = srcSpanStart loc-#elif __GLASGOW_HASKELL__ < 900+#if __GLASGOW_HASKELL__ < 900 toLocation loc = case loc of   UnhelpfulSpan str -> UnhelpfulLocation (unpackFS str)   RealSrcSpan sp    -> Location (unpackFS . srcSpanFile $ sp) (srcSpanStartLine sp)
src/PackageDBs.hs view
@@ -1,14 +1,12 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE PatternGuards #-} -- | Manage GHC package databases-module PackageDBs-    ( PackageDBs (..)-    , ArgStyle (..)-    , dbArgs-    , buildArgStyle-    , getPackageDBsFromEnv-    , getPackageDBArgs-    ) where+module PackageDBs (+  getPackageDBArgs+#ifdef TEST+, PackageDBs (..)+, getPackageDBsFromEnv+#endif+) where  import System.Environment (getEnvironment) import System.FilePath (splitSearchPath, searchPathSeparator)@@ -16,42 +14,24 @@ -- | Full stack of GHC package databases data PackageDBs = PackageDBs     { includeUser :: Bool-    -- | Unsupported on GHC < 7.6     , includeGlobal :: Bool     , extraDBs :: [FilePath]     }     deriving (Show, Eq) --- | Package database handling switched between GHC 7.4 and 7.6-data ArgStyle = Pre76 | Post76-    deriving (Show, Eq)- -- | Determine command line arguments to be passed to GHC to set databases correctly ----- >>> dbArgs Post76 (PackageDBs False True [])+-- >>> dbArgs (PackageDBs False True []) -- ["-no-user-package-db"] ----- >>> dbArgs Pre76 (PackageDBs True True ["somedb"])--- ["-package-conf","somedb"]-dbArgs :: ArgStyle -> PackageDBs -> [String]-dbArgs Post76 (PackageDBs user global extras) =+-- >>> dbArgs (PackageDBs True True ["somedb"])+-- ["-package-db","somedb"]+dbArgs :: PackageDBs -> [String]+dbArgs (PackageDBs user global extras) =     (if user then id else ("-no-user-package-db":)) $     (if global then id else ("-no-global-package-db":)) $     concatMap (\extra -> ["-package-db", extra]) extras-dbArgs Pre76 (PackageDBs _ False _) =-    error "Global package database must be included with GHC < 7.6"-dbArgs Pre76 (PackageDBs user True extras) =-    (if user then id else ("-no-user-package-conf":)) $-    concatMap (\extra -> ["-package-conf", extra]) extras --- | The argument style to be used with the current GHC version-buildArgStyle :: ArgStyle-#if __GLASGOW_HASKELL__ >= 706-buildArgStyle = Post76-#else-buildArgStyle = Pre76-#endif- -- | Determine the PackageDBs based on the environment. getPackageDBsFromEnv :: IO PackageDBs getPackageDBsFromEnv = do@@ -79,4 +59,4 @@ getPackageDBArgs :: IO [String] getPackageDBArgs = do       dbs <- getPackageDBsFromEnv-      return $ dbArgs buildArgStyle dbs+      return $ dbArgs dbs
src/Parse.hs view
@@ -1,6 +1,5 @@ {-# LANGUAGE PatternGuards #-} {-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE CPP #-} module Parse (   Module (..) , DocTest (..)@@ -21,9 +20,6 @@ import           Data.List (isPrefixOf, stripPrefix) import           Data.Maybe import           Data.String-#if __GLASGOW_HASKELL__ < 710-import           Control.Applicative-#endif import           Extract import           Location 
src/Property.hs view
@@ -67,7 +67,5 @@      -- | Remove quotes from given name, if any.     unquote ('`':xs)     = init xs-#if __GLASGOW_HASKELL__ >= 707     unquote ('\8216':xs) = init xs-#endif     unquote xs           = xs
src/Runner.hs view
@@ -13,11 +13,6 @@  import           Prelude hiding (putStr, putStrLn, error) -#if __GLASGOW_HASKELL__ < 710-import           Data.Monoid hiding ((<>))-import           Control.Applicative-#endif- import           Control.Monad hiding (forM_) import           Text.Printf (printf) import           System.IO (hPutStrLn, hPutStr, stderr, hIsTerminalDevice)@@ -50,11 +45,11 @@ -- | Sum up summaries. instance Monoid Summary where   mempty = Summary 0 0 0 0-#if MIN_VERSION_base(4,11,0)+#if __GLASGOW_HASKELL__ < 804+  mappend+#else instance Semigroup Summary where   (<>)-#else-  mappend #endif     (Summary x1 x2 x3 x4) (Summary y1 y2 y3 y4) = Summary (x1 + y1) (x2 + y2) (x3 + y3) (x4 + y4) 
test/PropertySpec.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE CPP, OverloadedStrings #-}+{-# LANGUAGE OverloadedStrings #-} module PropertySpec (main, spec) where  import           Test.Hspec@@ -30,17 +30,10 @@       runProperty repl "(reverse . reverse) xs == (xs :: [Int])" `shouldReturn` Success      it "runs an implicitly quantified property even with GHC 7.4" $-#if __GLASGOW_HASKELL__ == 702-      pendingWith "This triggers a bug in GHC 7.2.*."-      -- try e.g.-      -- >>> 23-      -- >>> :t is-#else       -- ghc will include a suggestion (did you mean `id` instead of `is`) in       -- the error message       withInterpreter [] $ \repl -> do         runProperty repl "foldr (+) 0 is == sum (is :: [Int])" `shouldReturn` Success-#endif      it "runs an explicitly quantified property" $ withInterpreter [] $ \repl -> do       runProperty repl "\\xs -> (reverse . reverse) xs == (xs :: [Int])" `shouldReturn` Success
test/RunSpec.hs view
@@ -8,8 +8,10 @@ import           System.Exit  import qualified Control.Exception as E+import           System.FilePath import           System.Directory (getCurrentDirectory, setCurrentDirectory) import           Data.List.Compat (isPrefixOf, sort)+import           Data.Char  import           System.IO.Silently import           System.IO (stderr)@@ -126,24 +128,14 @@        it "prints a useful error message" $ do         (r, _) <- hCapture [stderr] (E.try action :: IO (Either ExitCode Summary))-#if __GLASGOW_HASKELL__ < 706-        r `shouldBe` "\nFoo.hs:6:1: parse error (possibly incorrect indentation)\n"-#else--#if __GLASGOW_HASKELL__ < 800-        r `shouldBe` "\nFoo.hs:6:1:\n    parse error (possibly incorrect indentation or mismatched brackets)\n"-#else-        removeLoadedPackageEnvironment r `shouldBe` "\nFoo.hs:6:1: error:\n    parse error (possibly incorrect indentation or mismatched brackets)\n"-#endif--#endif+        stripAnsiColors (removeLoadedPackageEnvironment r) `shouldBe` "\nFoo.hs:6:1: error:\n    parse error (possibly incorrect indentation or mismatched brackets)\n"    describe "expandDirs" $ do     it "expands a directory" $ do       res <- expandDirs "example"       sort res `shouldBe`-        [ "example/src/Example.hs"-        , "example/test/doctests.hs"+        [ "example" </> "src" </> "Example.hs"+        , "example" </> "test" </> "doctests.hs"         ]     it "ignores files" $ do       res <- expandDirs "doctest.cabal"@@ -152,3 +144,10 @@       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
@@ -3,10 +3,6 @@  import           Test.Hspec -#if __GLASGOW_HASKELL__ < 710-import           Data.Monoid-#endif- import           System.IO import           System.IO.Silently (hCapture) import           Control.Monad.Trans.State