{"id":17774932,"url":"https://github.com/fnogatz/tap","last_synced_at":"2026-01-11T01:41:34.068Z","repository":{"id":8904115,"uuid":"10627306","full_name":"fnogatz/tap","owner":"fnogatz","description":"Write TAP tests with SWI-Prolog","archived":false,"fork":false,"pushed_at":"2023-01-19T23:47:43.000Z","size":57,"stargazers_count":13,"open_issues_count":1,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-12-02T16:23:56.423Z","etag":null,"topics":["prolog","swi-prolog","tap"],"latest_commit_sha":null,"homepage":null,"language":"Prolog","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/fnogatz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2013-06-11T17:56:23.000Z","updated_at":"2025-11-17T21:45:23.000Z","dependencies_parsed_at":"2023-02-10T07:00:49.738Z","dependency_job_id":null,"html_url":"https://github.com/fnogatz/tap","commit_stats":null,"previous_names":["mndrix/tap"],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/fnogatz/tap","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fnogatz%2Ftap","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fnogatz%2Ftap/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fnogatz%2Ftap/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fnogatz%2Ftap/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fnogatz","download_url":"https://codeload.github.com/fnogatz/tap/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fnogatz%2Ftap/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27779846,"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","status":"online","status_checked_at":"2025-12-17T02:00:08.291Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["prolog","swi-prolog","tap"],"created_at":"2024-10-26T21:54:11.589Z","updated_at":"2025-12-17T08:02:46.317Z","avatar_url":"https://github.com/fnogatz.png","language":"Prolog","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Synopsis\n\n```prolog\n:- use_module(to_be_tested).\n% define helper predicates here\n\n:- use_module(library(tap)).\n% define test predicates here\n\n'two plus two is four' :-\n    4 is 2+2.\n\n'zero not equal to one'(fail) :-\n    0 =:= 1.\n\n6 is 3*2.\n```\n\nRun tests with standard TAP tools like prove:\n\n```shell\n$ prove -v -e 'swipl -q -t main -s' test/examples.pl\nTAP version 13\n1..4\nok 1 - simplest possible test case\nok 2 - simplest failing test case\nok 3 - generates a diagnostic message\n# I'm a diagnostic message\nok 4 - long-running test case\n\n# time=1.0ms\n# tests 4\n# pass  4\n```\n\n# Description\n\nThe [Test Anything Protocol](http://testanything.org/) is a text-based interface between test scripts and a test harness. A wide range of tools exist for running, rendering and analyzing test results. By writing your Prolog tests with TAP, you get access to all this testing infrastructure. For example, [interactive HTML output](http://www.spurkis.org/TAP-Formatter-HTML/test-output.html).\n\nTAP tests traditionally reside in a t/ directory in your project's root. Each file beneath t/ encapsulates a collection of tests related to a specific topic. During development, one can run all test files or just an interesting subset. In its most basic form, a test file is a script which generates TAP output. library(tap) helps you write these scripts.\n\nTo write a test file with library(tap), load all code that you'll need for testing. Define any helper predicates. Then load library(tap). All predicates defined after loading library(tap) are considered test cases. The predicate's name is the test name. By default, a predicate must succeed without leaving any choicepoints for the test to pass. See [Arguments section](#arguments) below to change that behavior.\n\nFor small tests (see `6 is 3*2` above), the name can be omitted. The test body is then used as the test name.\n\nlibrary(tap) does not yet support the entire TAP specification and is missing many features found in PlUnit. Both are temporary shortcomings. I expect the library to fill these gaps eventually.\n\n# \u003ca name=\"arguments\"\u003e\u003c/a\u003eArguments\n\nA test predicate can optionally include arguments to change TAP's expectations about the test. Arguments look like this:\n\n```prolog\n'test with arguments'(Arg1, Arg2, ...) :-\n    ...\n```\n\nAcceptable arguments are:\n\n  * `error(E)` - same as `throws(E)`. Supported for symmetry with PlUnit.\n  * `fail` - test is expected to fail\n  * `fixme(Reason)` - same as `todo(Reason)`. Supported for symmetry with PlUnit.\n  * `todo(Reason)` - test is known to fail but report it in TAP output as \"TODO Reason\". TAP tools treat these tests differently.\n  * `todo` - same as `todo('')`\n  * `throws(E)` - throws exception `E`\n\n# \u003ca name=\"macros\"\u003e\u003c/a\u003eMacros that write tests\n\nIt's common for each test case in a test file to follow a similar pattern. For example, we might have tests for the length/2 predicate:\n\n```prolog\n:- use_module(library(tap)).\n'length([a,b,c],3)' :-\n    length([a,b,c], N),\n    N = 3.\n'length([a,b],2)' :-\n    length([a,b], N),\n    N = 2.\n...\n```\n\nBecause of all the similarity, that's tedious to write and tedious to read. We can factor out the redundancy by creating a macro:\n\n```prolog\n% ... macro definition goes here ...\n\n:- use_module(library(tap)).\n[a,b,c] -\u003e 3.\n[a,b] -\u003e 2.\n```\n\nThat's much better. A regular term_expansion/2 macro that calls tap:register_test/1 does the job:\n\n```prolog\nterm_expansion(List -\u003e Length, (Head :- Test)) :-\n    format(atom(Head), 'length(~w, ~w)', [List, Length]),\n    Test = (\n        length(List, Len),\n        Len = Length\n    ),\n    tap:register_test(Head).\n```\n\nWithout registering, our nicely constructed test case won't run. Macros are especially convenient when testing multiple modes of a single predicate. You can decribe the relationship once and have the macro write a separate test case for each mode.\n\n# Installation\n\nUsing SWI-Prolog 7.1 or later:\n\n```prolog\n?- pack_install(tap).\n```\n\nSource code available and pull requests accepted at https://github.com/fnogatz/tap\n\nThis module uses [semantic versioning](http://semver.org/).\n\n# Projects using library(tap)\n\nHere is a non-exhaustive list of projects that use library(tap). Most of them use [the macro approach](#macros), so they can be a good inspiration on how to define tests in Prolog:\n\n- [cli_table](https://github.com/fnogatz/cli_table)\n- [date_time](https://github.com/fnogatz/date_time)\n- [dcg4pt](https://github.com/fnogatz/dcg4pt)\n- [plammar](https://github.com/fnogatz/plammar)\n- [regex](https://github.com/mndrix/regex)\n\nPlease open an issue if you want to have your project listed here.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffnogatz%2Ftap","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffnogatz%2Ftap","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffnogatz%2Ftap/lists"}