(assign show-failed-only t) (assign all-tests nil)

;; register a test to be run later by ‘run-all-tests (def register-test (test)

(push test all-tests))

(def run-all-tests (verbose)

; runs all tests that have been registered with 'register-test
(with (passed 0 failed 0)
  (with (f-pass (fn nil (assign passed (+ 1 passed)))
         f-fail (fn nil (assign failed (+ 1 failed))))
    (run-tests `(suite "all tests" ,@all-tests) f-pass f-fail verbose)
    (p "passed: " passed)
    (p "failed: " failed)
    (/ passed (+ passed failed)))))

(def run-tests (tests passf failf verbose)

(execute-test "" tests passf failf verbose))

(def execute-test (desc test passf failf verbose)

(if (eq? 'suite (car test))
    (execute-tests (+ desc " - " (cadr test)) (cddr test) passf failf verbose)
    (!eq? 'comment (car test))
    (execute-single-test desc test passf failf verbose)))

(def execute-single-test (desc test passf failf verbose)

(if verbose (p desc " - " (car test)))
(on-err (error (j "FAILED " desc " - " (car test)) (pp:nth 1 test))
        (with (expected (nth 2 test) result (eval (nth 1 test)))
              (if (iso result expected)
                  (passf)
                  (do (p desc " - " (car test) " - FAILED:
                         running  " (pp (nth 1 test)) ",
                         expected " (inspect expected) ",
                         got      " (inspect result) "\n")
                      (failf))))))

(def execute-tests (desc tests passf failf verbose)

(while tests
  (execute-test desc
                (car tests)
                passf
                failf
                verbose)
  (= tests (cdr tests))))

(mac examples-for (name . examples)

(let suite-name "examples for ~(pp name)"
  (let plain-examples (collect (fn (x) (isa 'string (car x))) examples)
    `(do (register-test '(suite ,suite-name ,@plain-examples))
         (dox-add-examples ',name ',plain-examples)))))