{"id":15289146,"url":"https://github.com/mateuszkubuszok/scala-cli-md-spec","last_synced_at":"2026-02-07T11:31:17.899Z","repository":{"id":238359491,"uuid":"796391198","full_name":"MateuszKubuszok/scala-cli-md-spec","owner":"MateuszKubuszok","description":"Turn your markdown docs into test suites running Scala CLI","archived":false,"fork":false,"pushed_at":"2024-05-18T09:30:50.000Z","size":53,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-14T12:33:24.576Z","etag":null,"topics":["markdown","scala","scala-3","scala-cli","testing"],"latest_commit_sha":null,"homepage":"","language":"Scala","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/MateuszKubuszok.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-05-05T19:47:47.000Z","updated_at":"2024-05-18T09:30:53.000Z","dependencies_parsed_at":"2024-10-14T20:00:27.301Z","dependency_job_id":"c7ebf1ee-8b44-4122-b0d9-9d48582da713","html_url":"https://github.com/MateuszKubuszok/scala-cli-md-spec","commit_stats":null,"previous_names":["mateuszkubuszok/scala-cli-md-spec"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/MateuszKubuszok/scala-cli-md-spec","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MateuszKubuszok%2Fscala-cli-md-spec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MateuszKubuszok%2Fscala-cli-md-spec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MateuszKubuszok%2Fscala-cli-md-spec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MateuszKubuszok%2Fscala-cli-md-spec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MateuszKubuszok","download_url":"https://codeload.github.com/MateuszKubuszok/scala-cli-md-spec/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MateuszKubuszok%2Fscala-cli-md-spec/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266561528,"owners_count":23948632,"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-07-22T02:00:09.085Z","response_time":66,"last_error":null,"robots_txt_status":null,"robots_txt_updated_at":null,"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":["markdown","scala","scala-3","scala-cli","testing"],"created_at":"2024-09-30T15:59:24.423Z","updated_at":"2026-02-07T11:31:17.894Z","avatar_url":"https://github.com/MateuszKubuszok.png","language":"Scala","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ScalaCLI.md Spec\n\nTurn each Scala CLI snippet from your markdown documentation into a test case and each markdown document into a test suite.\n\n## Usage\n\n### Scala CLI\n\nCreate `test-snippets.scala` (use at least Java 11!):\n\n```scala\n//\u003e using scala 3.3.6\n//\u003e using jvm temurin:1.11.0.23\n//\u003e using dep \"com.kubuszok::scala-cli-md-spec:0.2.0\"\nimport com.kubuszok.scalaclimdspec.*\n@main def run(args: String*): Unit = testSnippets(args.toArray) { cfg =\u003e\n  new Runner.Default(cfg) // or provide your own :)\n}\n```\n\nthen run it with [Scala CLI](https://scala-cli.virtuslab.org/):\n\n```bash\n# run all tests\nscala-cli run test-snippets.scala -- \"$PWD/docs\"\n# run only tests from Section in my-markdown.md\nscala-cli run test-snippets.scala -- --test-only=\"my-markdown.md#Section*\" \"$PWD/docs\"\n\n# \"dry-run\" listing all snippets - useful for checking which snippets are found and how are they called\nscala-cli run test-snippets.scala -- --list-only \"$PWD/docs\"\n# \"dry-run\" listing all snippets that match the filter - useful for checking if we typed the filter correctly\nscala-cli run test-snippets.scala -- --list-only --test-only=\"my-markdown.md#Section*\" \"$PWD/docs\"\n```\n\nTo see how one can customize the code to e.g. inject variables or use the newest library version\nin an arbitrary markdown documentation generator see [Chimney's example](https://github.com/scalalandio/chimney/blob/29cd5048bee3b66c2d4d3d81dc17e0c0d5a4a128/scripts/test-snippets.scala).\n\n### Coursier\n\nIf you are not providing any modification, you can run it straight from the [Coursier](https://get-coursier.io):\n\n```bash\n# run all tests\ncoursier launch com.kubuszok:scala-cli-md-spec_3:0.2.0 -M com.kubuszok.scalaclimdspec.testSnippets -- \"$PWD/docs\"\n# run only tests from Section in my-markdown.md\ncoursier launch com.kubuszok:scala-cli-md-spec_3:0.2.0 -M com.kubuszok.scalaclimdspec.testSnippets -- --test-only=\"my-markdown.md#Section*\" \"$PWD/docs\"\n```\n\n## Rules of the game\n\n 1. each markdown is its own test suite\n 2. by default only Scala (and Java) snipets containing `//\u003e using` are considered tests\n    * other snippets are considered pseudocode and are ignored\n\n      ```scala\n      //\u003e using scala 3.3.6\n      // will be tested\n      println(\"yolo\")\n      ```\n\n      ```scala\n      // will NOT be tested\n      println(\"yolo\")\n      ```\n\n 3. by default snippets are tested for the lack of errors\n    * by the lack of errors we mean that Scala CLI returns `0`\n\n      ```scala\n      //\u003e using scala 3.3.6\n      // should pass\n      println(\"yolo\")\n      ```\n\n      ```scala\n      //\u003e using scala 3.3.6\n      // thou shall NOT pass!\n      throw Exception(\"yolo\")\n      ```\n\n    * if there is `// expected output:` followed by inline comments in the immediate next lines,\n      the snippet will be expected to succeed and its standard **output** will be expected to contain the content provided in these comments\n\n      ```scala\n      //\u003e using scala 3.3.6\n      // should pass\n      println(\"yolo\")\n      // expected output:\n      // yolo\n      ```\n      \n      ```scala\n      //\u003e using scala 3.3.6\n      // thou shall NOT pass!\n      println(\"yolo\")\n      // expected output:\n      // eee macarena!\n      ```\n\n    * if there is `// expected error:` followed by inline comments in the immediate next lines,\n      the snippet will be expected to fail and its standard **error** will be expected to contain the content provided in these comments\n\n      ```scala\n      //\u003e using scala 3.3.6\n      // should pass\n      throw Exception(\"yolo\")\n      // expected error:\n      // yolo\n      ```\n\n      ```scala\n      //\u003e using scala 3.3.6\n      // should pass\n      summon[String]\n      // expected error:\n      // No given instance of type String was found\n      ```\n      \n      ```scala\n      // thou shall NOT pass!\n      //\u003e using scala 3.3.6\n      println(\"yolo\")\n      // expected error:\n      // yolo\n      ```\n\n 4. by default each snippet is a standalone Scala snippet, it will be tested in a separate directory, containing a single `snippet.sc` file\n    * multiple pieces of code can be combined into one multi-file snippet with:\n      `// file: [filename] - part of [example name used for grouping]` syntax - e.g. `// file: filename.scala - part of X example` would group all `X example` snippets in the same directory,\n      and use `filename.scala` as a filename for this particular piece of code\n\n      ```scala\n      // file: model.scala - part of multi-file\n      case class Model(a: Int)\n      ```\n\n      ```scala\n      // file: example.sc - part of multi-file\n      println(Model(10))\n      // expected output:\n      // Model(10)\n      ```\n\n      With multi-file `//\u003e using` is not required to consider the code as a Scala CLI test. Remember that to make it work, like with normal Scala CLI app,\n      there should be either _exactly one `.sc` file_ **or** only `.scala` files with _exactly one explicitly defined `main`_.\n\n    * if at least one file in a multi-file snippet has a name ending with `.test.scala`, contains `src/test` path, or `using scope test` directive,\n      then `scala-cli test [dirname]` will be used unstead of `scala-cli run [dirname]`\n      (useful for e.g. defining macros in the compile scope and showing them in the test scope since Scala CLI is NOT multi modular and you cannot demonstrate macros in another way)\n\n      ```scala\n      // file: macro.scala - part of macro example\n      //\u003e using scala 3.3.6\n\n      object MyMacro:\n        inline def apply[A](a: A): Unit = ${ applyImpl[A]('a) }\n\n        import scala.quoted.*\n        def applyImpl[A: Type](a: Expr[A])(using Quotes): Expr[Unit] = '{ () }\n      ```\n\n      ```scala\n      // file: macro.test.scala - part of macro example\n      //\u003e using test.dep org.scalameta::munit::1.2.0\n\n      class MacroSpec extends munit.FunSuite {\n        test(\"Macro(a) should do thing\") {\n          assert(MyMacro(\"wololo\") == ())\n        }\n      }\n      ```\n\n    * Java snippets should not only use `java` in markdown, but also define `// file: filename.java - part of ...`\n\n      ```java\n      // file: MyEnum.java - part of java enum example\n      enum MyEnum {\n        ONE, TWO;\n      }\n      ```\n\n      ```scala\n      // file: snippet.sc - part of java enum example\n      println(MyEnum.values())\n      ```\n\n 4. Cross-compilation e.g. `//\u003e using scala 2.13.16 3.3.6` is supported (together with `//\u003e using target.scala ...`).\n\n 5. if `--test-only` flag is used, only suites containing at least 1 matching snippet and, within them, only\n    the matching snippets will be run and displayed (but all markdowns still need to be read to find snippets\n    and match them against the pattern!)\n\n    ```bash\n    # quotes around * are needed in shell\n\n    # test all snippets\n    scala-cli run test-snippets.scala -- --test-only '*' \"$PWD/docs\"\n    # test all snippets in my-markdown.md\n    scala-cli run test-snippets.scala -- --test-only 'my-markdown.md#*' \"$PWD/docs\"\n    # test all snippets in my-markdown.md, in section name starting with My Section\n    scala-cli run test-snippets.scala -- --test-only 'my-markdown.md#My section*' \"$PWD/docs\"\n    ```\n  \n 6. If `--list-only` flag is used, available snippets will be listed. Can be used with combination with `--test-only`\n    to make a \"dry run\", which snippets would be tested.\n\n## Why though\n\nSome people would ask: if you need to make sure code in your documentation compiles, why not use something like [mdoc](https://scalameta.org/mdoc/)?\n\nWell, because mdoc doesn't work for my cases:\n\n * it requires picking a specific documentation tool whether or not its look'n'feel is what authors desires\n * it makes it difficult to have different `scalacOptions`, different Scala versions and different libraries available\n   in each snippet - all settings are global, so one would have to work really hard around these limitations\n * since it depends on settings provided when the code was build (`scalacOptions`, libraries) code might not be exactly\n   reproducibe by the users - if they just copy-paste the code from the docs, they might find the code not working\n   since they were not aware of some flags, libraries or compiler plugins used by authors of the example\n\nMeanwhile, there is one perfectly suitable tool for the job - [Scala CLI](https://scala-cli.virtuslab.org/). With\nits `//\u003e using` directives it is very easy to create a self-contained, perfectly reproducible snippet. As a matter\nof the fact, it even supports running snippets in [markdown files](https://scala-cli.virtuslab.org/docs/guides/power/markdown#markdown-inputs).\nIts markdown support has a downside, however, because this mode considers all snippets to be defined in the same scope (same Scala version,\nsame libraries, same compiler options - different `//\u003e using` classes are appended and may override conflicting options).\n\nThis library:\n\n - extracts snippets from markdown files\n - puts them into separate `/tmp` subdirectories\n - and runs as standalone snippets\n\nallowing each snippet to be a self-contained, reproducible example.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmateuszkubuszok%2Fscala-cli-md-spec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmateuszkubuszok%2Fscala-cli-md-spec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmateuszkubuszok%2Fscala-cli-md-spec/lists"}