diff --git a/docs/GENERATORS.md b/docs/GENERATORS.md new file mode 100644 index 000000000..c963c4cd2 --- /dev/null +++ b/docs/GENERATORS.md @@ -0,0 +1,68 @@ +# Generators + +The Clojure track uses a [test generator](https://exercism.org/docs/building/tooling/test-generators) to auto-generate practice exercise tests. +It uses the fact that most exercises defined in the [problem-specifications repo](https://github.com/exercism/problem-specifications/) also have a `canonical-data.json` file, which contains standardized test inputs and outputs that can be used to implement the exercise. + +## Steps + +To generate a practice exercise's tests, the test generator: + +1. Reads the exercise's test cases from its [`canonical-data.json` file] +2. Uses `tests.toml` file to omit and excluded test cases +3. Transforms the test cases (optional) +4. Renders the test cases using the exercise's generator template +5. Writes the rendered template to the exercise's test file + +### Step 1: read `canonical-data.json` file + +The test generator parses the test cases from the exercise's `canonical-data.json` using the [clojure/data.json library](https://github.com/clojure/data.json). + +Since some canonical data uses nesting, the parsed test case includes an additional `path` field that contains the `description` properties of any parent elements, as well as the test case's own `description` property. + +Note: keys are parsed as keywords. + +### Step 2: omit excluded tests from `tests.toml` file + +Each exercise has a `tests.toml` file, in which individual tests can be excluded/disabled. +The test generator will remove any test cases that are marked as excluded (`include = false`). + +### Step 3: transform the test cases (optional) + +Some exercises might need some tweaks before rendering the data. +For example, you might want to make the description less verbose. + +To tweak the test cases, define a `.meta/generator.clj` file with a `-generator` namespace . +Then, define a function called `transform` that takes a single argument — the parsed test cases — and returns the transformed test cases. + +Example: + +```clojure +(ns difference-of-squares-generator) + +(defn- update-path [path] + (take-last 1 path)) + +(defn transform [test-cases] + (map #(update % :path update-path) test-cases)) +``` + +This step is entirely optional. + +### Step 4: render the test cases + +The (potentially transformed) test cases are then passed to the `.meta/generator.tpl` file, which defines how the tests should be rendered based on those test cases. + +### Step 5: write the rendered template to the exercise's test file + +Finally, the output of the rendered template is written to the exercise's test file. + +## Templates + +The templates are rendered using the [hbs library](https://github.com/sunng87/hbs), which supports handlebars syntax (using [handlebars.java](https://github.com/jknack/handlebars.java/)). + +## Command-line interface + +There are two ways in which the test generator can be run: + +1. `bin/generate-tests`: generate the tests for all exercises that have a generator template +2. `bin/generate-tests `: generate the tests for the specified exercise, if it has a generator template diff --git a/docs/config.json b/docs/config.json index 3abffac53..f1e29be50 100644 --- a/docs/config.json +++ b/docs/config.json @@ -27,6 +27,13 @@ "path": "docs/RESOURCES.md", "title": "Useful Clojure resources", "blurb": "A collection of useful resources to help you master Clojure" + }, + { + "uuid": "b091add0-0047-42ad-ae0c-adeebf984365", + "slug": "generators", + "path": "docs/GENERATORS.md", + "title": "Learn about test generators", + "blurb": "Learn how the Clojure track uses test generators to generate tests for exercises" } ] }