{"id":16866044,"url":"https://github.com/ulidtko/cabal-doctest","last_synced_at":"2025-04-04T16:13:52.113Z","repository":{"id":39658650,"uuid":"80498604","full_name":"ulidtko/cabal-doctest","owner":"ulidtko","description":"A Setup.hs shim for running doctests","archived":false,"fork":false,"pushed_at":"2024-11-22T15:05:49.000Z","size":132,"stargazers_count":31,"open_issues_count":11,"forks_count":24,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-28T15:07:02.145Z","etag":null,"topics":["doctest","haskell"],"latest_commit_sha":null,"homepage":"https://hackage.haskell.org/package/cabal-doctest","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ulidtko.png","metadata":{"files":{"readme":"README.md","changelog":"changelog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-01-31T07:01:31.000Z","updated_at":"2024-11-22T14:56:27.000Z","dependencies_parsed_at":"2025-01-18T16:06:24.762Z","dependency_job_id":"6e667c63-1723-428c-9878-7a39cfd5b8b2","html_url":"https://github.com/ulidtko/cabal-doctest","commit_stats":{"total_commits":97,"total_committers":11,"mean_commits":8.818181818181818,"dds":0.5463917525773196,"last_synced_commit":"d83ea3cbbc7089d233163c87be7a5ac4946789a1"},"previous_names":["ulidtko/cabal-doctest","haskellari/cabal-doctest"],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ulidtko%2Fcabal-doctest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ulidtko%2Fcabal-doctest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ulidtko%2Fcabal-doctest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ulidtko%2Fcabal-doctest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ulidtko","download_url":"https://codeload.github.com/ulidtko/cabal-doctest/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247208141,"owners_count":20901570,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["doctest","haskell"],"created_at":"2024-10-13T14:49:19.736Z","updated_at":"2025-04-04T16:13:52.073Z","avatar_url":"https://github.com/ulidtko.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"cabal-doctest\n=============\n\n[![Hackage](https://img.shields.io/hackage/v/cabal-doctest.svg)](https://hackage.haskell.org/package/cabal-doctest) [![Haskell-CI](https://github.com/ulidtko/cabal-doctest/actions/workflows/haskell-ci.yml/badge.svg?branch=master)](https://github.com/ulidtko/cabal-doctest/actions/workflows/haskell-ci.yml) [![stack test](https://github.com/ulidtko/cabal-doctest/actions/workflows/stack-test.yml/badge.svg)](https://github.com/ulidtko/cabal-doctest/actions/workflows/stack-test.yml)\n\nA `Setup.hs` helper for running [doctests][doctest].\n\n[doctest]: https://github.com/sol/doctest#readme\n\nWhy this exists\n---------------\n\n**Doctesting** is a nifty technique that stimulates 3 good things to happen:\n\n * library documentation gains *runnable code examples* that are also tested;\n * library test suite gains *documented usage examples* as \"tests for free\";\n * get both of the above for the price of one.\n\nThat's what the [doctest][] tool does — not this package! — just for clarity.\nOff the shelf, `doctest` doesn't require any package management mumbo-jumbo:\nyou just run it on a source file with haddocks with doctests.\n\nIssues come in when library authors and maintainers wish to integrate doctests\ninto CI pipelines. When doctests start to require dependencies or non-default\ncompiler flags: that's when it gets hairy. There, if you want `stack test` and/or\n`cabal test` to run doctests too with minimal shenanigans, then read on.\n\nAmong different available approaches, this package `cabal-doctest` helps with\none, which is known as [custom setup][], `build-type: Custom` more precisely.\nYou should stick to the default `build-type: Simple`, unless you know what\nyou're doing.\n\nIn a nutshell, this custom Setup.hs shim generates a module `Build_doctests`\nthat allows your doctest driver `test-suite` to look like this:\n\n```haskell\nmodule Main where\n\nimport Build_doctests (flags, pkgs, module_sources)\nimport Test.Doctest (doctest)\n\nmain :: IO ()\nmain = doctest (flags ++ pkgs ++ module_sources)\n```\n\nMore detailed examples below.\n\nRegardless of the name, this **also works with Stack**.\n\nFor old versions of stack, cabal-install, GHC, see [caveats](#notes) below.\n\n[custom setup]: https://cabal.readthedocs.io/en/stable/cabal-package-description-file.html#pkg-field-build-type\n\n\nSimple example\n--------------\n\n[simple example]: https://github.com/ulidtko/cabal-doctest/tree/master/simple-example\n[simple-example.cabal]: https://github.com/ulidtko/cabal-doctest/tree/master/simple-example/simple-example.cabal\n\nFollow [simple example][] for the common case of a single-library `.cabal` package with doctests.\n\nTo recap the example's code:\n\n1. specify `build-type: Custom` in your `.cabal` file;\n\n2. declare dependencies of `Setup.hs`:\n\n   ```\n   custom-setup\n    setup-depends:\n      base \u003e= 4 \u0026\u0026 \u003c5,\n      cabal-doctest \u003e= 1 \u0026\u0026 \u003c1.1\n   ```\n\n   See [Notes](#notes) below for a caveat with cabal-install \u003c 2.4.\n\n3. Populate `Setup.hs` like so:\n\n   ```haskell\n   module Main where\n\n   import Distribution.Extra.Doctest (defaultMainWithDoctests)\n\n   main :: IO ()\n   main = defaultMainWithDoctests \"doctests\"\n   ```\n\n   Assuming your test-suite is called `doctests`, this `Setup` will generate a `Build_doctests`\n   module during package build. If your test-suite goes by name `foo`,\n   `defaultMainWithDoctests \"foo\"` creates a `Build_foo` module.\n\n4. Use the generated module in a testsuite, simply like so:\n\n   ```haskell\n   module Main where\n\n   import Build_doctests (flags, pkgs, module_sources)\n   import Data.Foldable (traverse_)\n   import System.Environment (unsetEnv)\n   import Test.DocTest (doctest)\n\n   main :: IO ()\n   main = do\n       traverse_ putStrLn args -- optionally print arguments\n       unsetEnv \"GHC_ENVIRONMENT\" -- see 'Notes'; you may not need this\n       doctest args\n     where\n       args = flags ++ pkgs ++ module_sources\n   ```\n\nUltimately, `cabal test` or `stack test` should run the doctests of your package.\n\nExample with multiple cabal components\n--------------------------------------\n\n`cabal-doctest` also supports more exotic use cases where a `.cabal` file\ncontains more components with doctests than just the main library, including:\n\n* doctests in executables,\n* doctests in internal libraries (if using `Cabal-2.0` or later).\n\nUnlike the simple example shown above, these examples involve _named_\ncomponents. You don't need to change the `Setup.hs` script to support\nthis use case. However, in this scenario `Build_doctests` will generate extra\ncopies of the `flags`, `pkgs`, and `module_sources` values for each additional\nnamed component.\n\nThe simplest approach is to use `x-doctest-components` field in `.cabal`:\n```\nx-doctest-components: lib lib:internal exe:example\n```\n\nIn that case, the test driver is generally:\n\n```haskell\nmodule Main where\n\nimport Build_doctests (Component (..), components)\nimport Data.Foldable (for_)\nimport System.Environment (unsetEnv)\nimport Test.DocTest (doctest)\n\nmain :: IO ()\nmain = for_ components $ \\(Component name flags pkgs sources) -\u003e do\n    print name\n    putStrLn \"----------------------------------------\"\n    let args = flags ++ pkgs ++ sources\n    for_ args putStrLn\n    unsetEnv \"GHC_ENVIRONMENT\"\n    doctest args\n```\n\nThere is also a more explicit approach: if you have an executable named `foo`, then\n`Build_doctest` will contain `flags_exe_foo`, `pkgs_exe_foo`, and `module_sources_exe_foo`.\nIf the name has hyphens in it (e.g., `my-exe`), `cabal-doctest` will convert them to\nunderscores (e.g., you'd get `flags_my_exe`, `pkgs_my_exe`, `module_sources_my_exe`).\nInternal library `bar` values will have a `_lib_bar` suffix.\n\nAn example testsuite driver for this use case might look like this:\n\n```haskell\nmodule Main where\n\nimport Build_doctests\n       (flags,            pkgs,            module_sources,\n        flags_exe_my_exe, pkgs_exe_my_exe, module_sources_exe_my_exe)\nimport Data.Foldable (traverse_)\nimport System.Environment (unsetEnv)\nimport Test.DocTest\n\nmain :: IO ()\nmain = do\n    unsetEnv \"GHC_ENVRIONMENT\"\n    -- doctests for library\n    traverse_ putStrLn libArgs\n    doctest libArgs\n\n    -- doctests for executable\n    traverse_ putStrLn exeArgs\n    doctest exeArgs\n  where\n    libArgs = flags            ++ pkgs            ++ module_sources\n    exeArgs = flags_exe_my_exe ++ pkgs_exe_my_exe ++ module_sources_exe_my_exe\n```\n\nSee the [multiple-components-example][].\n\n[multiple-components-example]: https://github.com/ulidtko/cabal-doctest/tree/master/multiple-components-example\n\n\nAdditional configuration\n------------------------\n\nThe `cabal-doctest` based `Setup.hs` supports a few extensions fields\nin `pkg.cabal` files to customize the `doctest` runner behavior, without\ncustomizing the default `doctest.hs`.\n\n```\ntest-suite doctests:\n  if impl(ghc \u003e= 8.0)\n    x-doctest-options: -fdiagnostics-color=never\n  x-doctest-source-dirs: test\n  x-doctest-modules: Servant.Utils.LinksSpec\n```\n\n* `x-doctest-options` Additional arguments passed into `doctest` command.\n* `x-doctest-modules` Additional modules to `doctest`. May be useful if you\n  have doctests in tests or executables (i.e not the default library component).\n* `x-doctest-src-dirs` Additional source directories to look for the modules.\n\nNotes\n-----\n\n* If support for cabal-install \u003c 2.4 is required, you'll have to\n  add `Cabal` to `setup-depends`; see issue [haskell/cabal#4288][].\n\n* Some versions of `Cabal` (for instance, 2.0) can choose to build a\n  package's `doctest` test suite _before_ the library. However, in order for\n  `cabal-doctest` to work correctly, the library _must_ be built first, as\n  `doctest` relies on the presence of generated files that are only created\n  when the library is built. See [#19][].\n\n  A hacky workaround for this problem is to depend on the library itself in a\n  `doctests` test suite. See [simple-example.cabal][]\n  for a demonstration. (This assumes that the test suite has the ability to\n  read build artifacts from the library, a separate build component. In\n  practice, this assumption holds, which is why this library works at all.)\n\n* `custom-setup` section is supported starting from `cabal-install-1.24`.\n  For older `cabal-install's` you have to install custom setup dependencies\n  manually.\n\n* `stack` respects `custom-setup` starting from version 1.3.3. Before that\n  you have to use `explicit-setup-deps` setting in your `stack.yaml`;\n  [stack#2094][].\n\n* With base \u003c 4.7 (GHC \u003c 7.8, pre-2014), `System.Environment.unsetEnv` function\n  will need to be imported from `base-compat` library. It is already in transitive\n  dependencies of `doctest`. Simply declare the dependency upon `base-compat`, and\n  then `import System.Environment.Compat (unsetEnv)` if you need that old GHC.\n\n* You can use `x-doctest-options` field in `test-suite doctests` to\n  pass additional flags to the `doctest`.\n\n* For `build-type: Configure` packages, you can use\n  `defaultMainAutoconfWithDoctests` function to make custom `Setup.hs` script.\n\n* If you use the default `.` in `hs-source-dirs`, then running `doctests`\n  might fail with weird errors (ambiguous module errors). Workaround is\n  to move sources under `src/` or some non-top-level directory.\n\n* The `extensions:` field isn't supported. Upgrade your `.cabal` file to use at least\n  `cabal-version: \u003e= 1.10` and use `default-extensions` or `other-extensions`.\n\n* If you use QuickCheck properties (`prop\u003e`) in your doctests,\n  the `test-suite doctest` should depend on `QuickCheck` and `template-haskell`.\n  This is a little HACK: These dependencies aren't needed to build the\n  `doctests` test-suite executable.  However, as we let `Cabal` resolve\n  dependencies, we can pass the resolved (and installed!) package identifiers to\n  to the `doctest` command.  This way, `QuickCheck` and `template-haskell` are\n  available to `doctest`, otherwise you'll get errors like:\n\n  ```\n    Variable not in scope:\n      mkName\n        :: [Char]\n           -\u003e template-haskell-2.11.1.0:Language.Haskell.TH.Syntax.Name\n  ```\n\n  or\n\n  ```\n    Variable not in scope:\n      polyQuickCheck\n        :: Language.Haskell.TH.Syntax.Name -\u003e Language.Haskell.TH.Lib.ExpQ\n  ```\n\n* From version 2, Stack sets the `GHC_ENVIRONMENT` variable, and GHC\n  (as invoked by `doctest`) will pick that up. This is undesirable:\n  `cabal-doctest` passes all the necessary information on the command\n  line already, and can lead to ambiguous module errors as GHC will\n  load the environment in addition to what `cabal-doctest` instructs\n  it to.\n\n  Hence, `cabal-doctest` tells GHC to ignore package environments\n  altogether on the command line. However, this is only possible since\n  GHC 8.2. If you are using `cabal-doctest` with Stack 2 and GHC 8.0\n  or earlier and seeing ambiguous module errors or other mysterious\n  failures, try manually unsetting `GHC_ENVIRONMENT` before invoking\n  `doctest`.\n\n * If you are on Nix. `doctest` will not pick up your version of GHC if you\n   don't point it towards it, and therefore will result in \"cannot satisfy -package-id\" errors.\n   You will need to set `NIX_GHC` and `NIX_GHC_LIBDIR` within your environment in order\n   for doctest to pick up your GHC. Put the following in `shell.nix` and run `nix-shell`.\n\n   ```nix\n   # shell.nix\n   { pkgs ? import \u003cnixpkgs\u003e {} }:\n   let\n     myHaskell = (pkgs.haskellPackages.ghcWithHoogle (p: with p; [\n       # Put your dependencies here\n       containers\n       hslogger\n     ]));\n   in\n   pkgs.mkShell {\n     name = \"myPackage\";\n\n     # These environment variables are important. Without these,\n     # doctest doesn't pick up nix's version of ghc, and will fail\n     # claiming it can't find your dependencies\n     shellHook = ''\n       export NIX_GHC=${myHaskell}/bin/ghc\n       export NIX_GHC_LIBDIR=${myHaskell}/lib/ghc-8.10.7\n     '';\n     buildInputs = with pkgs; [\n       myHaskell\n     ];\n   }\n   ```\n\n[#19]: https://github.com/ulidtko/cabal-doctest/issues/19\n[haskell/cabal#4288]: https://github.com/haskell/cabal/issues/4288\n[stack#2094]: https://github.com/commercialhaskell/stack/issues/2094\n\nCopyright\n---------\n\nCopyright 2017 Oleg Grenrus.\n\nWith contributions from:\n * Ryan Scott\n * Andreas Abel\n * Max Ulidtko\n\nAvailable under the BSD 3-clause license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fulidtko%2Fcabal-doctest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fulidtko%2Fcabal-doctest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fulidtko%2Fcabal-doctest/lists"}