 (ns com.stuartsierra.lazytest2)
+
+;;; PROTOCOLS
+
+(defprotocol TestInvokable
+  (invoke-test [t active]))
+
+(defprotocol Successful
+  (success? [r]))
+
+
+;;; Results
+
+(deftype TestResults [source children]
+  Successful (success? [] (every? success? children)))
+
+(deftype TestPassed [source states]
+  Successful (success? [] true))
+
+(deftype TestFailed [source states]
+  Successful (success? [] false))
+
+(deftype TestThrown [source states throwable]
+  Successful (success? [] false))
+
+
+;;; Contexts
 
 (deftype Context [parents before after])
 

     (TestResults this (map #(invoke-test % active) children))
     (catch Throwable t
       (TestThrown this active t)))))

(defn- has-after?
  "True if Context c or any of its parents has an :after function."
  [c]
  (or (:after c)
      (some has-after? (:parents c))))

(deftype ContextualContainer [contexts children] :as this
  TestInvokable

                          ~@after))]
        `(def ~name (Context ~contexts ~before-fn ~after-fn '~m nil))))))

(defn- has-after?
  "True if Context c or any of its parents has an :after function."
  [c]
  (or (:after c)
      (some has-after? (:parents c))))


;;; Assertion types

(deftype SimpleAssertion [pred] :as this
  TestInvokable
    (invoke-test [active]
      (try
        (if (pred)
          (TestPassed this nil)
          (TestFailed this nil))
        (catch Throwable t
          (TestThrown this nil t)))))

(deftype ContextualAssertion [contexts pred] :as this
  TestInvokable
