From 5034855718b4ccd64dfbeb203afeababe6987ec3 Mon Sep 17 00:00:00 2001
From: Colin Okay <okay@toyful.space>
Date: Thu, 2 Sep 2021 17:09:56 -0500
Subject: readme

---
 README.md | 106 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file 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.
 
 
-- 
cgit v1.2.3