aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Okay <okay@toyful.space>2021-09-02 17:09:56 -0500
committerColin Okay <okay@toyful.space>2021-09-02 17:09:56 -0500
commit5034855718b4ccd64dfbeb203afeababe6987ec3 (patch)
treedf5102b25b0d2427544cccec81e6919891008042
parent81a662a77ebbd687535e233d349e189d73f53903 (diff)
readme
-rw-r--r--README.md106
1 files changed, 104 insertions, 2 deletions
diff --git a/README.md b/README.md
index 59a1378..b8e0620 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,111 @@
+A [testiere](https://www.vocabulary.com/dictionary/testiere) is armor
+for the head of a horse.
+
+Testiere is a Common Lisp library for putting "protection" (tests) in
+the "head" of functions.
+
# testiere
-Embed tests inside function defintions. Signal errors on compilation if they do not pass.
+Embed tests inside function defintions. Tests are run when you compile
+a function, signalling errors when they fail. Great for running tests
+during interactive development!
+
+A work in progress. But here is the basic idea:
+
+ (defun+ fibble (x y &key (z 10))
+ "Hey, a docstring."
+ :tests
+ (= (1 2) 13)
+ (>= (1 2 :z 1) -5)
+ (:outputp (0 0 :z 0) (lambda (result) (equalp result 0)))
+ (:fails ("strings" "ain't" :z "numbers"))
+ :end
+ (+ x y z))
+
+
+Here we define a function with four embedded tests. If any of these
+tests fail, *the function is not defined*. If the funtion is already
+defined, it is not redefined.
+
+## basic tests
+
+The most basic tests look like
+
+ (COMPARATOR (ARG1 ARG2 ...) VALUE)
+
+Which will call the function with the provided arguments are compare
+it to a VALUE.
+
+For example, `(>= (1 2 :z 1) -5)` runs the test
+
+ (assert (>= (fibble 1 2 :z 1) -5))
+
+
+## additional tests
+
+
+In addition to basic assertions on the output of functions, testire
+supports additional vocubulary for embedding tests. Most of these look
+like:
+
+ (KEYWORD (ARG1 ARG2 ...) TERM)
+
+Where `TERM` varies according to the `KEYWORD` supplied.
+
+A few of these are
+
+- `(:outputp (..ARGS...) PREDICATE)` asserts that the output passes the
+ one-argument predicate.
+- `(:afterp (...ARGS...) THUNK)` asserts that the thunk should return
+ non-nil after the function has run. Good for testing values of
+ dynamic variables that the function might interact with.
+- `(:fails (...ARGS...))` asserts that the function will produce an
+ error with the given arguments.
+- `(:signals (...ARGS...) CONDITION)` where `CONDITION` is the name of
+ a condition. Asserts that the function will signal a condition of
+ the supplied type when called with the provided arguments.
+
+
+## Stubs and Bindings
+
+Tests can also embed bindings or mock-functions aka stubs.
+
+Binding variables looks like
+
+ (:with-bindings LET-BINDINGS TESTS)
+
+and are useful for binding dynamic variables for use during a set of
+tests.
-A work in progress.
+For example
+ (defvar *count*)
+
+ (defun+ increment-count ()
+ "Increments the *count* variable."
+ :tests
+ (:with-bindings ((*count* 4))
+ (:afterp () (lambda () (= *count* 5))) ; 5 after the first call
+ (= () 6) ; 6 after the second
+ (:outputp () (lambda (x) (= x 7)))) ; and 7 after the third
+ :end
+ (incf *count*))
+
+The `:with-stubs` form is similar, except that it binds temporary
+values to functions that might be called by the form in
+questions. Useful for mocking.
+ (defun just-a-function ()
+ (print "Just a function."))
+
+ (defun+ call-just-a-function ()
+ "Calls JUST-A-FUNCTION."
+ :tests
+ (:with-stubs ((just-a-function () (print "TEMP JUST-A-FUNCTION.")))
+ (equal () "TEMP JUST-A-FUNCTION."))
+ :end
+ (just-a-function))
+
+In the above, the temporary redefinition of JUST-A-FUNCTION is used.