Run doctests on arbitrary markdown files.
As of Elixir 1.15, this dependency can be replaced by using the
doctest_file/1,2 macro
provided by ExUnit itself, see #11 (thanks @axelson for pointing this out). To use this
on a range of files, you can create a simple test module in your test/
directory:
defmodule DocTest do
use ExUnit.Case
# You could also use a wildcard below
for file <- ["README.md"] do
doctest_file(file)
end
end
$ mix docception markdown-files
See the example/
project on how to use an alias in mix.exs
to run Docception with mix test
.
def deps do
[
{:docception, "~> 0.3", runtime: false}
]
end
This tool executes any Elixir doctest it encounters (think eval
). Ensure that it does not
encounter any harmful code!
This file can also be checked with docception. The following example is run through doctest and results in an error:
iex> :hello
:crash
$ mix docception README.md
** (ExUnit.AssertionError)
Doctest failed
code: :hello === :crash
left: :hello
right: :crash
The following example works:
iex> :hello
:hello
-
Clean up temporary directory where
.beam
files are stored -
Do not hard-code the temporary directory
-
Fix "wrong indent" warnings for heredocs
-
Try to fix wrong line number reports (the offset is always the same!)
-
Check if this also works when a doctest refers to dependencies of the project
-
Document how to use it with an alias in order to simplify running it in CI
-
Publish
-
Determine how to ensure that errors are written before the task ends; avoid sleeping in mix task.
The root cause of this is `ExUnit.CLIFormatter`. The formatter writes the error message. Docception can possibly exit before the formatter is done writing. This could be solvable by using a wrapper around `ExUnit.CLIFormatter` as a custom formatter instead. This custom formatter would then be shut down manually. Alas, I did not find a way to inject such a custom formatter.
-
Check if anybody is actually interested in this
Docception's approach is pretty simple:
- Read in a markdown file
- Create an Erlang Form that makes the file
look like something that can be executed.
- Add a module attribute
- Export an
__info__/1
function which wrapsmodule_info/1
- Compile that thing into a binary
- Store the resulting
.beam
in the filesystem to makeCode.fetch_docs/1
work - Call into the undocumented-and-totally-not-for-public-use
ExUnit.DocTest.__doctests__/1
function - For each of the quoted doctests, spawn a process and call let it run the quoted doctest
- Gather the results and raise on error
So, except for calling into __doctests__/1
, this is pretty straight forward. Note that the
implementation relies heavily on the hard work that went into elixir_erl.erl
from Elixir itself.
Docception needs to create a binary where the 'Docs'
chunk matches such chunks as generated by
elixir_erl.erl
.