cabal-doctest: A Setup.hs helper for running doctests

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

As of now (end of 2021), there isn't cabal doctest command. Yet, to properly work, doctest needs plenty of configuration. This library provides the common bits for writing a custom Setup.hs.


[Skip to Readme]

Properties

Versions 1, 1.0.1, 1.0.2, 1.0.3, 1.0.4, 1.0.5, 1.0.6, 1.0.7, 1.0.8, 1.0.9, 1.0.9
Change log ChangeLog.md
Dependencies base (>=4.3 && <4.17), Cabal (>=1.10 && <3.8), directory, filepath [details]
License BSD-3-Clause
Copyright (c) 2017 Oleg Grenrus
Author Oleg Grenrus <oleg.grenrus@iki.fi>
Maintainer Andreas Abel
Category Distribution
Home page https://github.com/haskellari/cabal-doctest
Source repo head: git clone https://github.com/haskellari/cabal-doctest
Uploaded by AndreasAbel at 2021-11-07T22:10:42Z

Modules

[Index]

Downloads

Maintainer's Corner

For package maintainers and hackage trustees


Readme for cabal-doctest-1.0.9

[back to package description]

cabal-doctest

Hackage Haskell-CI

A Setup.hs helper for running doctests.

Simple example

For the typical use case, namely a .cabal file with a single library containing doctests, adapting the simple example will be sufficient.

To use this library in your Setup.hs, you should specify a custom-setup section in your .cabal file. For example:

custom-setup
 setup-depends:
   base >= 4 && <5,
   Cabal,
   cabal-doctest >= 1 && <1.1

Note: The Cabal dependency is only needed for cabal-install < 2.4 (see issue haskell/cabal#4288).

You'll also need to specify build-type: Custom at the top of the .cabal file. Now put this into your Setup.hs file:

module Main where

import Distribution.Extra.Doctest (defaultMainWithDoctests)

main :: IO ()
main = defaultMainWithDoctests "doctests"

When you build your project, this Setup will generate a Build_doctests module. To use it in a testsuite, simply do this:

module Main where

import Build_doctests (flags, pkgs, module_sources)
import Data.Foldable (traverse_)
import System.Environment.Compat (unsetEnv)
import Test.DocTest (doctest)

main :: IO ()
main = do
    traverse_ putStrLn args -- optionally print arguments
    unsetEnv "GHC_ENVIRONMENT" -- see 'Notes'; you may not need this
    doctest args
  where
    args = flags ++ pkgs ++ module_sources

(The System.Environment.Compat module is from the base-compat package. That's already in the transitive closure of doctest's dependencies. System.Environment.unsetEnv was added with GHC 7.8 so, if you don't need to support versions of GHC older than 7.8, you can use System.Environment from base instead.)

Example with multiple .cabal components

cabal-doctest also supports more exotic use cases where a .cabal file contains more components with doctests than just the main library, including:

Unlike the simple example shown above, these examples involve named components. You don't need to change the Setup.hs script to support this use case. However, in this scenario Build_doctests will generate extra copies of the flags, pkgs, and module_sources values for each additional named component.

Simplest approach is to use x-doctest-components field, for example:

x-doctest-components: lib lib:internal exe:example

In that case, the test driver is generally:

module Main where

import Build_doctests (Component (..), components)
import Data.Foldable (for_)
import System.Environment.Compat (unsetEnv)
import Test.DocTest (doctest)

main :: IO ()
main = for_ components $ \(Component name flags pkgs sources) -> do
    print name
    putStrLn "----------------------------------------"
    let args = flags ++ pkgs ++ sources
    for_ args putStrLn
    unsetEnv "GHC_ENVIRONMENT"
    doctest args

There is also a more explicit approach: if you have an executable named foo, then separate values named flags_exe_foo, pkgs_exe_foo, and module_sources_exe_foo will be generated in Build_doctests. If the name has hyphens in it (e.g., my-exe), then cabal-doctest will convert those hyphens to underscores (e.g., you'd get flags_my_exe, pkgs_my_exe, and module_sources_my_exe). Internal library bar values will have a _lib_bar suffix.

An example testsuite driver for this use case might look like this:

module Main where

import Build_doctests
       (flags,            pkgs,            module_sources,
        flags_exe_my_exe, pkgs_exe_my_exe, module_sources_exe_my_exe)
import Data.Foldable (traverse_)
import System.Environment.Compat (unsetEnv)
import Test.DocTest

main :: IO ()
main = do
    unsetEnv "GHC_ENVRIONMENT"
    -- doctests for library
    traverse_ putStrLn libArgs
    doctest libArgs

    -- doctests for executable
    traverse_ putStrLn exeArgs
    doctest exeArgs
  where
    libArgs = flags            ++ pkgs            ++ module_sources
    exeArgs = flags_exe_my_exe ++ pkgs_exe_my_exe ++ module_sources_exe_my_exe

See this example for more details.

Additional configuration

The cabal-doctest based Setup.hs supports few extensions fields in pkg.cabal files to customise the doctest runner behaviour, without customising the default doctest.hs.

test-suite doctests:
  if impl(ghc >= 8.0)
    x-doctest-options: -fdiagnostics-color=never
  x-doctest-source-dirs: test
  x-doctest-modules: Servant.Utils.LinksSpec

  ...

Notes

    Variable not in scope:
      mkName
        :: [Char]
           -> template-haskell-2.11.1.0:Language.Haskell.TH.Syntax.Name

or

    Variable not in scope:
      polyQuickCheck
        :: Language.Haskell.TH.Syntax.Name -> Language.Haskell.TH.Lib.ExpQ

Copyright 2017 Oleg Grenrus.

Available under the BSD 3-clause license.