{"id":15056328,"url":"https://github.com/williamthome/doctest","last_synced_at":"2026-03-04T21:31:00.795Z","repository":{"id":239043237,"uuid":"798372720","full_name":"williamthome/doctest","owner":"williamthome","description":"A library to test Erlang documentation ","archived":false,"fork":false,"pushed_at":"2025-04-03T21:52:25.000Z","size":3005,"stargazers_count":14,"open_issues_count":2,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-03T20:44:08.475Z","etag":null,"topics":["doctest","erlang","erlang-library","erlang-otp","otp"],"latest_commit_sha":null,"homepage":"https://hex.pm/packages/doctest","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/williamthome.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.md","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},"funding":{"github":["williamthome"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":["https://www.buymeacoffee.com/williamthome"]}},"created_at":"2024-05-09T16:40:44.000Z","updated_at":"2025-08-12T08:28:38.000Z","dependencies_parsed_at":"2024-05-28T07:37:30.795Z","dependency_job_id":"7fd0e9c4-d587-489b-9159-3bd74a1d4cbf","html_url":"https://github.com/williamthome/doctest","commit_stats":null,"previous_names":["williamthome/doctest"],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/williamthome/doctest","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/williamthome%2Fdoctest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/williamthome%2Fdoctest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/williamthome%2Fdoctest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/williamthome%2Fdoctest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/williamthome","download_url":"https://codeload.github.com/williamthome/doctest/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/williamthome%2Fdoctest/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30093690,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-04T20:42:30.420Z","status":"ssl_error","status_checked_at":"2026-03-04T20:42:30.057Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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","erlang","erlang-library","erlang-otp","otp"],"created_at":"2024-09-24T21:49:57.441Z","updated_at":"2026-03-04T21:31:00.770Z","avatar_url":"https://github.com/williamthome.png","language":"Erlang","funding_links":["https://github.com/sponsors/williamthome","https://www.buymeacoffee.com/williamthome"],"categories":[],"sub_categories":[],"readme":"# doctest\n\nAn Erlang library to test `@doc` tags and `-moduledoc` and `-doc` attributes.\n\nIt is compatible with the [doctests syntax introduced in OTP-28](https://github.com/erlang/otp/pull/9315).\n\n\u003e [!NOTE]\n\u003e\n\u003e The `-moduledoc` and `-doc` attributes were introduced in [OTP 27](https://www.erlang.org/docs/27/system/documentation).\n\n## Installation\n\n```erlang\n% rebar.config\n% {minimum_otp_vsn, \"24\"}.\n{profiles, [\n    {test, [\n        % 'debug_info' is required to extract doc chunks.\n        {erl_opts, [debug_info]},\n        {deps, [{doctest, \"~\u003e 0.13\"}]}\n    ]}\n]}.\n% 'doctest_eunit_report' is required to pretty print and correctly displays the failed Eunit tests.\n{eunit_opts, [no_tty, {report, {doctest_eunit_report, []}}]}.\n```\n\n\u003e [!IMPORTANT]\n\u003e\n\u003e `doctest` won't run any test when `cover` is enabled, for example:\n\u003e\n\u003e ```erlang\n\u003e {profiles, [\n\u003e     {test, [\n\u003e         {cover_enabled, true},\n\u003e         % ...\n\u003e     ]}\n\u003e ]}.\n\u003e ```\n\u003e\n\u003e There is an open [PR](https://github.com/erlang/otp/pull/9433) to fix this bug in the OTP repository.\n\n## Overview\n\nErlang documentation can be written:\n\n- Via [EDoc](https://www.erlang.org/doc/apps/edoc/chapter) by using the `@doc` tag, e.g.:\n\n  ````erlang\n  %% @doc Prints \"Hello, Joe!\".\n  %%\n  %% Example:\n  %%\n  %% ```\n  %% \u003e print().\n  %% \"Hello, Joe!\"\n  %% '''\n  print() -\u003e \"Hello, Joe!\".\n  ````\n\n- Or via [ExDoc](https://hexdocs.pm/ex_doc/readme.html), by using the `-moduledoc` and\n`-doc` attributes [introduced in OTP 27](https://www.erlang.org/doc/system/documentation), e.g.:\n\n  ````erlang\n  -doc \"\"\"\n  Prints \"Hello, Joe!\".\n\n  Example:\n\n  ```\n  \u003e print().\n  \"Hello, Joe!\"\n  ```\n  \"\"\".\n  print() -\u003e \"Hello, Joe!\".\n  ````\n\nThere are some rules to test documentation. One rule is that only code blocks\nare testable. Via `EDoc/tags`, code blocks are code between ` ``` ` and `'''`\n(triple backticks and triple single quotes), and via `ExDoc/attributes`,\nthey are code between ` ``` ` and ` ``` ` (triple quotes and triple quotes).\nThe code of the code blocks follows the same rules as the current Erlang shell, for example:\n\n```erlang\n\u003e % - Comments and multiline expressions are allowed;\n  % - Multiline expressions must be aligned;\n  % - Invalid syntaxes are skipped.\n  print().\n\"Hello, Joe!\"\n\u003e % All tests compare the equality between the expression and the result.\n  % The example below is translated to an `?assertEqual` macro result:\n  % \u003e ?assertEqual(true, print() =/= \"Hello, World\").\n  print() =/= \"Hello, World!\".\ntrue\n```\n\n### Optionally\n\n1. Variable outputs can be skipped by replacing the right side (result) by an\n   underscore (`_`) or without giving a result to it by starting a new expression\n2. The `erlang` language in code blocks is not required\n3. The syntax can contains the line numbers and dots between multiple lines,\n   like in the erlang shell\n\nFor example:\n\n````erlang\n-doc \"\"\"\n```erlang\n1\u003e A =\n.. 1.\n_\n2\u003e B = 1. % It's not required to show the result\n3\u003e A + B.\n2\n```\n\"\"\".\nfoo(Foo) -\u003e Foo.\n````\n\n## Usage\n\n````erlang\n-module(mymodule).\n-export([sum/2]).\n\n-ifdef(TEST).\n-include_lib(\"eunit/include/eunit.hrl\").\n\n% The EUnit header will automatically export this function because it ends with \"_test\"\ndoctest_test() -\u003e\n    doctest:module(?MODULE, #{\n        % Default options:\n\n        % Enable or turn off module doc tests.\n        % Spec: boolean()\n        moduledoc =\u003e true,\n\n        % Enable or turn off functions doc tests or define a list of functions to be tested.\n        % Spec: boolean() | [{atom(), arity()}].\n        doc =\u003e true,\n\n        % Set the EUnit options. 'rebar3_config' tries to resolve the options defined in the rebar3.\n        % Spec: rebar3_config | [term()]\n        eunit_opts =\u003e rebar3_config,\n\n        % Overrides the code blocks extractors. See the 'doctest_extract' behavior.\n        % Custom extractors are allowed.\n        % Spec: [module()]\n        extractors =\u003e [doctest_extract_attr], % OTP \u003c 27 =\u003e [doctest_extract_tag]\n\n        % Bind value to variables. Could be a proplist or a map.\n        % Spec: erl_eval:binding_struct()\n        bindings =\u003e #{},\n\n        % Define records to be expanded/compiled to tuple expressions.\n        % Spec: [{Name :: atom(), Fields :: [atom()]}]\n        % Example: [{RecName, record_info(fields, RecName)}]\n        records =\u003e []\n    }).\n-endif.\n\n% The `sum/2` will be tested by default because it contains a valid Markdown\n% code block. Multiple Markdown code blocks can be defined.\n-doc \"\"\"\n```\n\u003e mymodule:sum(1, 1).\n2\n```\n\"\"\".\nsum(A, B) -\u003e\n    A + B.\n````\n\n\u003e [!NOTE]\n\u003e\n\u003e Please see the [rebar documentation](https://rebar3.org/docs/testing/eunit/#eunit_opts)\n\u003e for more information about the EUnit options.\n\n## Example\n\n\u003e [!IMPORTANT]\n\u003e\n\u003e If the OTP version is below 27, please only consider the `@doc` tags inside comments as a valid code.\n\u003e The `-moduledoc` and `-doc` attributes are valid if the OTP version is equal to or above 27.\n\nTake this module:\n\n````erlang\n 1 │ -module(greeting).\n 2 │ -moduledoc \"\"\"\n 3 │ Module documentation are testable.\n 4 │\n 5 │ ```\n 6 │ \u003e greeting:print() =:= \"Hello, Joe!\".\n 7 │ true\n 8 │ ```\n 9 │ \"\"\".\n10 │\n11 │ -export([print/0]).\n12 │\n13 │ -ifdef(TEST).\n14 │ -include_lib(\"eunit/include/eunit.hrl\").\n15 │  doctest_test() -\u003e\n16 │      doctest:module(?MODULE).\n17 │ -endif.\n18 │\n19 │ -doc \"\"\"\n20 │ ```\n21 │ \u003e greeting:print().\n22 │ \"Hello, World!\"\n23 │ ```\n24 │ \"\"\".\n25 │ print() -\u003e\n26 │     \"Hello, Joe!\".\n````\n\nRunning the EUnit test via rebar3:\n\n```bash\n$ rebar3 eunit --module greeting\n===\u003e Verifying dependencies...\n===\u003e Analyzing applications...\n===\u003e Compiling doctest\n===\u003e Performing EUnit tests...\n PASS  ./src/greeting.erl:6 -moduledoc\n FAIL  ./src/greeting.erl:21 -doc\n\n ❌ assertEqual\n\n    │\n 21 │ \u003e greeting:print().\n 22 │ \"Hello, World!\"\n    │\n    └── at ./src/greeting.erl:21\n\nExpected:\n\"Hello, World!\"\n\nReceived:\n\"Hello, Joe!\"\n\n\n\nTests: 1 failed, 1 passed, 2 total\n Time: 0.003 seconds\n\n\n\n\nTests: 1 passed, 1 total\n Time: 0.0 seconds\n```\n\n\u003e [!NOTE]\n\u003e\n\u003e The output above is by using the `doctest_eunit_report` as the EUnit report.\n\nIt is fine to put the `doctest_test` function in a Common Test module, for example:\n\n```erlang\n-module(greeting_SUITE).\n-ifdef(TEST).\n-include_lib(\"eunit/include/eunit.hrl\").\n doctest_test() -\u003e\n     doctest:module(greeting).\n-endif.\n```\n\n\u003e [!NOTE]\n\u003e\n\u003e The `doctest_test` function name could be any name of your choice.\n\n## Doctest EUnit Reporter\n\nThere is a built-in EUnit reporter called `doctest_eunit_report` to display the\ntests results correctly. Set it in the EUnit options of the project options, e.g.:\n\n```erlang\n% rebar3.config\n{eunit_opts, [\n    no_tty,\n    {report, {doctest_eunit_report, [\n        % Default options\n\n        % Change the default depth of the output result.\n        % Spec: pos_integer()\n        {print_depth, 15}\n    ]}}\n]}.\n```\n\nAn example of the `doctest_eunit_report` output:\n![doctest_eunit_report](/assets/reporter-go-to-definition.gif)\n\n## Sponsors\n\nIf you like this tool, please consider [sponsoring me](https://github.com/sponsors/williamthome).\nI'm thankful for your never-ending support :heart:\n\nI also accept coffees :coffee:\n\n[![\"Buy Me A Coffee\"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/williamthome)\n\n## Contributing\n\n### Issues\n\nFeel free to [submit an issue on Github](https://github.com/williamthome/doctest/issues/new).\n\n## License\n\nCopyright (c) 2024 [William Fank Thomé](https://github.com/williamthome)\n\n`doctest` is 100% open source and community-driven. All components are available under the Apache 2 License on [GitHub](https://github.com/williamthome/doctest).\n\nSee [LICENSE.md](LICENSE.md) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilliamthome%2Fdoctest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwilliamthome%2Fdoctest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilliamthome%2Fdoctest/lists"}