{"id":27261332,"url":"https://github.com/datkt/tape","last_synced_at":"2026-05-02T20:35:23.397Z","repository":{"id":57106246,"uuid":"150316413","full_name":"datkt/tape","owner":"datkt","description":"Simple Test Anything Protocol implementation based on tape by @substack","archived":false,"fork":false,"pushed_at":"2018-11-19T20:31:58.000Z","size":82,"stargazers_count":1,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-26T01:49:02.925Z","etag":null,"topics":["assertions","clib","ghi","kotlin","kotlin-library","node","npm","tap","tape","test","test-anything-protocol","test-runner"],"latest_commit_sha":null,"homepage":null,"language":"Kotlin","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/datkt.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":"2018-09-25T19:10:34.000Z","updated_at":"2025-05-25T11:57:37.000Z","dependencies_parsed_at":"2022-08-21T02:31:07.212Z","dependency_job_id":null,"html_url":"https://github.com/datkt/tape","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/datkt/tape","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datkt%2Ftape","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datkt%2Ftape/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datkt%2Ftape/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datkt%2Ftape/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/datkt","download_url":"https://codeload.github.com/datkt/tape/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/datkt%2Ftape/sbom","scorecard":{"id":325031,"data":{"date":"2025-08-11","repo":{"name":"github.com/datkt/tape","commit":"6de69645c89073f8b3829f1732635c13f90d07e2"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-18T02:13:19.293Z","repository_id":57106246,"created_at":"2025-08-18T02:13:19.294Z","updated_at":"2025-08-18T02:13:19.294Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32549380,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-02T19:18:06.202Z","status":"ssl_error","status_checked_at":"2026-05-02T19:16:21.335Z","response_time":132,"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":["assertions","clib","ghi","kotlin","kotlin-library","node","npm","tap","tape","test","test-anything-protocol","test-runner"],"created_at":"2025-04-11T05:29:33.624Z","updated_at":"2026-05-02T20:35:23.380Z","avatar_url":"https://github.com/datkt.png","language":"Kotlin","funding_links":[],"categories":[],"sub_categories":[],"readme":"datkt.tape\n==========\n\nTAP [1] output producing test runner for Kotlin mostly ported from\n[@substack's](https://github.com/substack)\n[tape](https://github.com/substack/tape) module for Node.js [2]. This\npackage is installable with NPM [3], IMS [4], clib [5], GHI [6], and of\ncourse, from [source][#install-from-source]\n\n## Installation\n\nThe `datkt.tape` package an be installed with various package managers.\n\n### From NPM\n\n```sh\n$ npm install @datkt/tape\n```\n\n**Note:** *This will install **tape** into `node_modules/@datkt/tape`*\n\n### From clib\n\n```sh\n$ clib install datkt/tape\n```\n\n**Note:** *This will install **tape** into `deps/tape`*\n\n### From GHI\n\n```sh\n$ ghi install datkt/tape\n```\n\n### Install From Source\n\n```sh\n$ git clone git@github.com:datkt/tape.git\n$ cd tape\n$ make build # or make klib\n$ make install\n```\n\n## Compiling\n\n### From NPM Installation\n\n```sh\n$ konanc -r node_modules/@datkt -l tape/tape test.kt -o test\n```\n\n### From clib Installation\n\n```sh\n$ konanc deps/@datkt/tape/*.kt test.kt -o test\n```\n\n### From Source Installation\n\n```sh\n$ konanc -l tape test.kt -o test ## library should be installed in ~/.konan/klib\n```\n\n## Usage\n\n```kotlin\nimport datkt.tape.collect\nimport datkt.tape.test\nimport lerp.*\n\nfun main(args: Array\u003cString\u003e) {\n  test(\"lerp(a, b, c)\", fun(t: Test) {\n    val x = 1.0\n    val y = 2.0\n    val z = lerp(x, y, 1.0)\n\n    t.plan(1)\n    t.ok(2.0 == z, \"lerp compute fail :shrug:\")\n    t.end()\n  })\n\n  collect() // collects results and prints to stdout\n}\n```\n\n## API\n\nThe `datkt.tape` package exports a public API documented in this section.\n\n### `test(name: String, callback: (t: Test) -\u003e Any?): Test`\n\nCreates and returns a new named scoped test. The test callback\nwill not be invoked if null is given.\n\n```kotlin\nimport datkt.tape.test\ntest(\"function test\", fun(t: Test) {\n  t.plan(1)\n  t.ok(true, \"we're okay\")\n  t.end()\n})\n```\n\n### `skip(name: String, callback: Callback?): Test`\n\nCreates and returns a new skipped scoped test. The test callback\nwill not be invoked if null is given.\n\n```kotlin\nimport datkt.tape.skip\nskip(\"skipped test\", fun(t: Test) {\n  t.end(Error(\"This should never run\"))\n})\n```\n\n### `collect(): Results?`\n\nCloses results container and writes results to underlying\nwrite stream.\n\n```kotlin\nimport datkt.tape.collect\nval results = datkt.tape.collect()\n```\n\n### `class Test(name: String?, skip: Boolean, callback: Callback?, stream: Stream?)`\n\nThe `Test` class represents a named test that is invoked in a\nfunction callback. When a test is running, it will call various function hooks\nand write TAP formatted output to a stream.\n\n```kotlin\nt = Test(\"thing\", false, fun(t: Test) {\n  t.end\n})\n\nt.run()\n```\n\n#### `t.onBeforeRun(callback: (Test) -\u003e Any?)`\n\nAdd a callback that will be invoked before the test is ran.\n\n```kotlin\nt.onBeforeRun({\n  // do something before the tests is ran\n})\n```\n\n#### `t.onAfterRun(callback: (Test) -\u003e Any?)`\n\nAdd a callback that will be invoked after the test is ran.\n\n```kotlin\nt.onAferRun({\n  // do something after the tests is ran\n})\n```\n\n#### `t.onResult(callback: (Test, Any?) -\u003e Any?)`\n\nAdd a callback that will be invoked when there\nis a test result. It could be a `String` or `AssertionResult`.\n\n```kotlin\nt.onResult(fun(_, result: Any?) {\n  if (result is String) {\n    // do something with result string\n  } else if (result is AssertionResult) {\n    // do something with assertion result\n  }\n})\n```\n\n#### `t.onPlan(callback: (Test, Int?) -\u003e Any?)`\n\nAdd a callback that will be invoked when a plan\nhas been set.\n\n```kotlin\nt.onPlan(fun(_, plan: Int?) {\n  if (null != plan) {\n    // do something with plan\n  }\n})\n```\n\n#### `t.onEnd(callback: (Test) -\u003e Any?)`\n\nAdd a callback that will be invoked when the test\nhas ended.\n\n```kotlin\nt.onEnd({\n  // do something when test ends\n})\n```\n\n#### `t.run(): Test`\n\nRuns the test runner invoking the runner callback\ngiven to the constructor if the test is not skipped.\n\n```kotlin\nt.run() // will call test callback, if test is not skipped\n```\n\n#### `t.plan(count: Int): Test`\n\nEnsure a planned assertion count for a test. Will throw `Error` if\n`count` is `0`.\n\n```kotlin\nt.plan(4)\n```\n\n#### `t.comment(comment: String): Test`\n\nEmit a comment\n\n```kotlin\nt.comment(\"@TODO(jwerle): Fix this\")\n```\n\n#### `t.end(err: Error?): Test`\n\nEnds the test runner with an optional error that\nwill generate an error assertion.\n\n```kotlin\nt.end()\n```\n\nor with an `Error`\n\n```kotlin\nt.end(Error(\"oops\"))\n```\n\n#### `t.assert(ok: Any?, opts: AssertionOptions?): AssertionResult`\n\nAsserts that input is truthy based on some optional assertion options.\n\n```kotlin\nt.assert(true)\nt.assert(1234)\nt.assert(\"okay\")\nt.assert(::println)\nt.assert({ 1 + 1 })\n```\n\n#### `ok(ok: Any?, msg: String?, opts: AssertionOptions?): AssertionResult`\n\nAsserts that input is \"ok\" based on some optional assertion options.\n\n```kotlin\nt.ok(null == err)\nt.ok(thing is Thing)\nt.ok(string.length)\n```\n\n#### `notOk(ok: Any?, msg: String?, opts: AssertionOptions?): AssertionResult`\n\nAsserts that input is \"not ok\" based on some optional assertion options.\n\n```kotlin\nt.notOk(err)\nt.notOk(thing is That)\nt.notOk(array.count)\n```\n\n#### `error(err: Error?, msg: String?, opts: AssertionOptions?): AssertionResult`\n\nAsserts that an error is falsy. If an error is given\nthe message is used in the assertion.\n\n```kotlin\nt.error(Error(\"oops\")) // failing assertion\nt.error(null) // passing\n```\n\n#### `t.fail(msg: String?, opts: AssertionOptions?) : AssertionResult`\n\nCreates a failing assertion with an optional message.\n\n```kotlin\nt.fail(\"well, that didn't work\")\n```\n\n#### `t.pass( msg: String?, opts: AssertionOptions?) : AssertionResult`\n\nCreates a passing assertion with an optional message.\n\n```kotlin\nt.pass(\"well done!\")\n```\n\n#### `t.skip(msg: String?, opts: AssertionOptions?) : AssertionResult`\n\nCreates a skipping assertion with an optional message.\n\n```kotlin\nt.skip(\"we'll come back to shit\")\n```\n\n#### `t.equal(a: Any?, b: Any?, msg: String?, opts: AssertionOptions?): AssertionResult\n\nCreates an equality assertion for two values with an optional\nassertion error message.\n\n```kotlin\nt.equal(\"hello\", \"hello\", \"hello == hello\")\nt.equal(\"good\", \"food\", \"good != food\")\n```\n\n#### `t.throws(fn: () -\u003e Unit, expected: Any?, msg: String?, opts: AssertionOptions?): AssertionResult\n\nCreates an assertion that checks for an error to be thrown\ninside of a given function.\n\n```kotlin\nt.throws({ throw Error(\"oops\") }) // passes\nt.throws({ throw Exception(\"yikes\") }, Error, \"Expection != Error\")\n```\n\n## Building\n\nThe `tape` package can be built from source into various targets.\n\n### Kotlin Library\n\n`tape.klib`, a Kotlin library that can be linked with `konanc` can be\nbuilt from source.\n\n```sh\n$ make klib\n```\n\nwhich will produce `build/lib/tape.klib`. The library can be installed\nwith `klib` by running `make install`\n\n### Static Library\n\n`libtape.a`, a static library that can be linked with `konanc` can be\nbuilt from source.\n\n```sh\n$ make static\n```\n\nwhich will produce `build/lib/libtape.a` and C header files in\n`build/include`. The library can be installed into your system by\nrunning `make install`. The path prefix can be set by defining the\n`PREFIX` environment or `make` variable. It defaults to\n`PREFIX=/usr/local`\n\n### Shared Library\n\n`libtape.so`, a shared library that can be linked with `konanc` can be\nbuilt from source.\n\n```sh\n$ make shared\n```\n\nwhich will produce `build/lib/libtape.so` and C header files in\n`build/include`. The library can be installed into your system by\nrunning `make install`. The path prefix can be set by defining the\n`PREFIX` environment or `make` variable. It defaults to\n`PREFIX=/usr/local`\n\n## Tests\n\n- ✔ assert [pass: 21, fail: 0, duration: 0ms]\n- ✔ constants [pass: 13, fail: 0, duration: 0ms]\n- ✔ context [pass: 6, fail: 0, duration: 0ms]\n- ✔ options [pass: 6, fail: 0, duration: 0ms]\n- ✔ result [pass: 5, fail: 0, duration: 0ms]\n- ✔ results [pass: 0, fail: 0, duration: 1ms]\n- ✔ simple [pass: 0, fail: 0, duration: 0ms]\n- ✔ simple [pass: 2, fail: 0, duration: 0ms]\n- ✔ stream [pass: 8, fail: 0, duration: 0ms]\n- ✔ test [pass: 36, fail: 0, duration: 0ms]\n- ✔ truthy [pass: 11, fail: 0, duration: 3ms]\n\n### Summary\n\n- duration: 4ms\n- planned: 108\n- assertions: 108\n- pass: 108\n- fail: 0\n\n## References\n\n1. TAP - https://en.wikipedia.org/wiki/Test_Anything_Protocol\n2. Node.js - https://nodejs.org/en/\n3. NPM - https://www.npmjs.com/\n4. IMS - https://github.com/mafintosh/ims\n5. clib - https://github.com/clibs/clib\n6. GHI - https://github.com/stephenmathieson/ghi\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatkt%2Ftape","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdatkt%2Ftape","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdatkt%2Ftape/lists"}