Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add generator docs #739

Merged
merged 9 commits into from
Jan 12, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 68 additions & 0 deletions docs/GENERATORS.md
Original file line number Diff line number Diff line change
@@ -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 `<slug>-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 <slug>`: generate the tests for the specified exercise, if it has a generator template
7 changes: 7 additions & 0 deletions docs/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
]
}