diff options
| author | 2025-08-03 21:08:09 -0400 | |
|---|---|---|
| committer | 2025-08-03 21:08:09 -0400 | |
| commit | 6c04c5dd1c90df2e485e0bab626dc9f7efa6fd34 (patch) | |
| tree | 183d168b3998881968e90368d9976db5b19a8787 /README.md | |
add conspire, with most meta-tests passed
Diffstat (limited to 'README.md')
| -rw-r--r-- | README.md | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/README.md b/README.md new file mode 100644 index 0000000..9d00465 --- /dev/null +++ b/README.md @@ -0,0 +1,187 @@ +# Conspire + +Conspire is an experiment in providing a portable R6RS/R7RS testing +library. It uses purely functional data structures in a mutable parameter +object, allowing for procedural programming inside of a dynamic extent +to not affect the rest of the test system. + +## API + +### `test-info` procedures + + `test-info` + +What SRFI-64 would call the "test runner" is in Conspire the `test-info`, +which contains a pure SRFI-225 dictionary with an associated DTO. The +dictionary must map at least symbols to values (including procedures). + +Whenever a test group or a test is entered, a new dynamic extent is +entered with a new test-info object. Destructive updates to the new test +info are not reflected in the test info of the call. + +The `test-info` is a parameter and can be modified with the `parameterize` +form. The inputs to `test-info` must be one of: + +* `copy`: Return an unchanged copy of the `test-info` +* `replace dict [dto]`: In the new dynamic extent, the dictionary is + replaced with `dict`, optionally with new dto `dto`. + + test-set! + test-update! + test-update/default! + test-delete-all! + test-contains? + test-ref + test-ref/default + test-update/default + +These procedures are the same as their SRFI-225 equivalents, except +that the DTO and dictionary arguments are not needed, and that the +mutating procedures return unspecified values. For instance, + + (test-set! key value) + +is equivalent to `(dict-set! dto dict key value)`. + + (modify-test-info! proc) + +Evaluates `(proc dto dict)`, where `dto` is the current `test-info` DTO +and `dict` is the current `test-info` dict. The procedure must return +a dict satisfying the same DTO. This dictionary is set as the current +`test-info` dictionary within the dynamic extent. + + (inspect-test-info proc) + +Evaluates `(proc dto dict)`, where `dto` is the current `test-info` DTO +and `dict` is the current `test-info` dict, and returns the result. + +### `test-info` Standard Procedure Keys + + before-test (default-before-test name) + +A procedure with one argument (the name of the test). +Called in the dynamic extent of the caller of the test. If it returns +false, then the test is skipped. + + test-setup (test-setup) + +A procedure of zero arguments. Called in the dynamic extent of a +test. Used to set up parts of a test. + + after-test (default-after-test dto dict) + +A procedure of two arguments (the DTO and dictionary of the test). Called +in the dynamic extent of the caller. Used to report information about +the test, and to merge desired information into the calling test info. + + report-test (default-report-test dto dict) + +A procedure of two arguments (the DTO and dictionary of the test). Used by +`default-after-test` to report the result of the test to the user. + + group-begin (default-group-begin name) + +A procedure of one argument (the name of the group). Called in the dynamic +extent of the group. Used to set up common information for a whole group. + + group-end (default-group-end dto dict) + +A procedure of two arguments (the DTO and the dictionary of the +test). Called in the dynamic extent containing the group. Used to report +information about the group and merge it with the containing test info. + +### `test-info` Standard Keys + +* `success?`: Truthy if the test passed. +* `exception`: The caught exception, if any. +* `tests`: Number of run tests. +* `passed`: Number of passed tests. +* `failed`: Number of failed tests. +* `skipped`: Number of skipped tests. +* `verbose?`: Used by the default test setups. If false, only failures are + printed. Otherwise all test case information is printed. + +### Test Procedures and Forms + +If `test-name` is `#f`, then the test is not given a name. Every procedure +here is implemented using `call-as-test`. + + (call-as-test test-name thunk) + +Call `thunk` with the test name `test-name`. + +First executes the procedure stored in `before-test` in the `test-info` of +the caller. If that returns non-false, then it creates a new `test-info` +inheriting from the `test-info` of the caller, and runs the procedure +stored in `test-setup` (in the new `test-info`). Then `thunk` will +be executed in this dynamic extent. If `thunk` throws an exception, +it will be caught. Afterwards, the procedure stored in `after-test` +will be run with the `test-info` of the caller. + +The test will set + +* `success?`: Will be set to `#f` if an exception was caught. +* `exception`: Only set if an exception was caught. The value is the + caught exception. + + (test-application test-name (name expr) ...) + +The `name` must be symbols that are mutually not `bound-identifier=?`. +Runs a test with `test-name` that evaluates `(expr ...)`. + +The test will set (in addition to `call-as-test`): + +* `name`: To be the passed `expr` quoted. +* `application`: A list `(expr ...)`, where each is evaluated. +* `success?`: If `(expr ...)` evaluates to not false. + + (with-test-assert test-name body ...) + +Execute `body` in a test with `test-name`. + +The test will set (in addition to `call-as-test`): + +* `success?`: The returned value of `body` (if an exception is not caught). + + (test-eq name %expected %actual) + (test-eqv name %expected %actual) + (test-equal name %expected %actual) + +Convienence wrappers for + + (test-application test-name ((procedure <procedure>) + (expected %expected) + (actual %actual))) + + (test-approximate X Y eps) + +Tests that + + |X - Y| <= eps + +The test will set (in addition to `call-as-test`): + +* `procedure`: to be `%test-approximate` (this is an implementation detail). +* `expected`: to be `X`, quoted. +* `actual`: to be `Y`, quoted. +* `error`: to be `eps`, quoted. +* `application`: The `car` is `%test-approximate`, and the `cdr` is + `expected`, `actual`, and `error,` evaluated. + + (with-test-error name error-predicate body ...) + +Evaluates `body ...` in a test. This test will set + +* `success?`: False if evaluation does not throw an exception. Otherwise + the return value of `error-predicate` on the thrown exception. + +## Porting Guide + +This library requires `make-parameter` and `parameterize` to work like +in R7RS. Most R6RS implementations should support dynamic parameters out +of the box. + +Multi-threaded implementations must export an SRFI-18 compatible +interface for mutexes. Single threaded implementations can use the +`compat.single-threaded.sld` (`compat.single-threaded.sls` for R6RS) +implementations. |
