           {}
           (partition-all 2 (partition-by #(.startsWith % "-") args))))
 
-(def ^:dynamic *style* false)
-
 (defn -main [& args]
   (binding [*style* true]
-    (verify-all (read-options args))
+    (verify (read-options args))
     (shutdown-agents)))
 
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Reporting
 
-(def styles {:reset "[0m"
-             :red "[31m"
-             :green "[32m"
-             :bright "[1m"})
-
-(defn with-style [style & strs]
-  (let [s (apply str (interpose " " strs))]
-    (if (and *style* (not= style :none))
-      (str \u001b (style styles) s \u001b (:reset styles))
-      s)))
-
-(defn result-type [results]
-  (cond (= (:status (ex-data (:exception results))) :timeout)
-        :timeout
-        (= (:status (ex-data (:exception results))) :disconnected)
-        :disconnected
-        (:exception results)
-        :exception
-        (every? #(= (:data-actual %) ::read-error) (apply concat (vals (:tests results))))
-        :not-implemented))
-
-(defmulti print-report (fn [results opts] (result-type results)))
-
-(defmethod print-report :timeout [results opts]
-  (let [timeout-form (-> results :exception ex-data :edn)
-        [prev curr] (first (filter #(= (last %) timeout-form)
-                                   ;; TODO: timeout could occur
-                                   ;; in other kinds of tests
-                                   (partition 2 1 (:generated-forms opts))))]
-    (println (with-style :red "Response Timeout"))
-    (println (with-style :red "Timeout while processing:"))
-    (println (pr-str timeout-form))
-    (println (with-style :red "Previous form was:"))
-    (println (pr-str prev))))
-
-(defmethod print-report :disconnected [results opts]
-  (let [error-form (-> results :exception ex-data :transit)]
-    (println (with-style :red "Implementation Disconnected"))
-    (println (with-style :red "Disconnect when sending:"))
-    (println (pr-str (String. error-form)))))
-
-(defmethod print-report :exception [results opts]
-  (do (println results)
-      (.printStackTrace (:exception results))))
-
-(defmethod print-report :not-implemented [results opts]
-  (println (with-style :red "Not Implemented")))
-
-(defmethod print-report :default [results opts]
-  ;; TODO: need to do something better for printing transit data
-  ;; (when bytes)
-  (doseq [[k v] (:tests results)]
-    (let [errors (filter #(= (:status %) :error) v)
-          ecnt (count errors)
-          pcnt (- (count v) ecnt)
-          style (if (pos? ecnt) :red :green)]
-      (println (with-style style (format "Testing with %s %s inputs"
-                                         (count v) k)))
-      (println (with-style style (format "Summary: passed: %s, errors: %s"
-                                         pcnt ecnt)))
-      (when (pos? ecnt)
-        (do (doseq [error errors]
-              (println "Sent Transit:" (pr-str (:transit-expected error)))
-              (println "Expected:    " (pr-str (:data-expected error)))
-              (println "Actual:      " (pr-str (:data-actual error)))))))))
-
-(defn report [{:keys [project command encoding tests time] :as results} opts]
-  (println (with-style :bright "Project: " project))
+(defn error-report [message errors]
+  (doseq [error errors]
+    (println (with-style :red message))
+    (when (:cause error)
+      (println (with-style :red "Cause: " (.toString (:cause error)))))
+    (println (with-style :red "Error when sending:"))
+    (println (pr-str (-> error :data :edn)))
+    (println (with-style :red "Previous sent form was:"))
+    (println (pr-str (-> error :prev-data :edn)))))
+
+(defmulti print-report (fn [type results] type))
+
+(defmethod print-report :timeout [_ results]
+  (error-report "Response Timeout" results))
+
+(defmethod print-report :disconnected [_ results ]
+  (error-report "Disconnected" results))
+
+(defmethod print-report :read-error [_ results]
+  (error-report "Read Error" results))
+
+(defn plural [things w]
+  (if (= (count things) 1) w (str w "s")))
+
+(defmethod print-report :success [_ results]
+  (println (with-style :green (format "%s successful %s"
+                                      (count results)
+                                      (plural results "roundtrip")))))
+
+(defmethod print-report :error [_ results]
+  (println (with-style :red (format "%s roundtrip %s"
+                                    (count results)
+                                    (plural results "error"))))
+  (doseq [error results]
+    (println "Sent edn:    " (pr-str (-> error :data :edn)))
+    (println "     bytes:  " (-> error :data :hex))
+    (println "     string: " (pr-str (:transit-string error)))
+    (println "Expected:    " (pr-str (:data-expected error)))
+    (println (with-style :red "Actual:      " (pr-str (:data-actual error))))))
+
+(defmethod print-report :default [type results]
+  (pp/pprint results))
+
+(defn report [{:keys [project command encoding time tests] :as results}]
+  (println (with-style :bright "Project: " project "/" (name encoding)))
   (println "Command: " command)
-  (println "Encoding:" encoding)
   (when time
     (println (with-style :bright
                (format "Time: %s ms to roundtrip %s %s exemplar files"
                        (:ms time)
                        (:count time)
                        (name (:encoding time))))))
-  (print-report results opts))
+  (doseq [[k v] tests]
+    (println "Results for test:" (name k))
+    (doseq [[type results] (group-by :status v)]
+      (print-report type results))))

  (doseq [e (if enc [enc] [:json :msgpack])]
    (run-test project e opts)))

(defn verify-all
  "Given user provided options, run all tests specified by the
  options. If options is an empty map then run all tests against all
  implementations for both encodings."

        testable-impls (keep #(let [script (io/file root (str % "/bin/roundtrip"))]
                                (when (.exists script) %))
                             (.list root))
        ;; Generate n random forms. Use the same set for all tests.
        forms (when-let [n (:gen opts)]
                (take n (repeatedly gen/ednable)))]
    (doseq [impl testable-impls]
      (when (or (not impls)
                (contains? impls impl))
        (verify-encodings impl (assoc opts :generated-forms forms))))))

(defn read-options
  "Given a sequence of strings which are the command line arguments,
