 
 (defn roundtrip-edn [proc edn encoding]
   (try
-    (let [transit-out (write-transit edn encoding)
-          result (roundtrip-transit proc transit-out encoding)]
-      (if (not (or (= (:status result) :error)
-                   (= edn (:data-actual result) (:data-expected result))))
-        (assoc result :status :warning :edn edn)
-        result))
+    (let [transit-out (write-transit edn encoding)]
+      (roundtrip-transit proc transit-out encoding))
     (catch Throwable e
       (if (= (-> e ex-data :status) :timeout)
         (throw (ex-info "Response timeout" (assoc (ex-data e) :edn edn)))
         (throw e)))))
 
+(defn test-transit [transits proc encoding]
+  (mapv #(roundtrip-transit proc % encoding) transits))
+
+(defn test-edn [forms proc encoding]
+  (mapv #(roundtrip-edn proc % encoding) forms))
+
+(defn test-timing [transits proc encoding]
+  (println "collecting timing information...")
+  (dotimes [x 10000]
+    (mapv #(roundtrip-transit proc % encoding) transits))
+  (let [start (System/currentTimeMillis)]
+    (mapv #(roundtrip-transit proc % encoding) transits)
+    (- (System/currentTimeMillis) start)))
+
 (def extension {:json ".json"
                 :msgpack ".mp"})
 
-(defn test-exemplar-files [proc encoding]
-  (let [files (filter #(and (.isFile %) (.endsWith (.getName %) (extension encoding)))
-                      (file-seq (io/file "../transit/simple-examples")))]
-    (mapv #(roundtrip-transit proc (read-bytes %) encoding)
-          files)))
-
-(defn test-corners-of-edn [proc encoding]
-  (mapv #(roundtrip-edn proc % encoding) cc/forms))
-
-(defn test-corners-of-transit-json [proc encoding]
-  (mapv #(roundtrip-transit proc (.getBytes %) encoding) cc/transit-json))
-
-(defn test-generated-edn [forms proc encoding]
-  (mapv #(roundtrip-edn proc % encoding) forms))
+(defn exemplar-transit [encoding]
+  (map #(read-bytes %)
+       (filter #(and (.isFile %) (.endsWith (.getName %) (extension encoding)))
+               (file-seq (io/file "../transit/simple-examples")))))
+
+(defn filter-tests [proc encoding opts]
+  (let [transit-exemplars (exemplar-transit encoding)]
+    (filter #((:pred %) proc encoding opts)
+            [{:pred (constantly true)
+              :path [:tests :exemplar-file]
+              :test #(test-transit transit-exemplars proc encoding)}
+             {:pred (constantly true)
+              :path [:tests :corner-case-edn]
+              :test #(test-edn cc/forms proc encoding)}
+             {:pred (fn [_ e _] (= e :json))
+              :path [:tests :corner-case-transit-json]
+              :test #(test-transit (map (fn [s] (.getBytes s)) cc/transit-json) proc encoding)}
+             {:pred (fn [_ _ o] (:gen o))
+              :path [:tests :generated-edn]
+              :test #(test-edn (:generated-forms opts) proc encoding)}
+             {:pred (fn [_ _ o] (:time o))
+              :path [:time]
+              :test #(let [ms (test-timing transit-exemplars proc encoding)]
+                       {:ms ms
+                        :count (count transit-exemplars)
+                        :encoding encoding})}])))
 
 (defn verify-impl-encoding [command encoding opts]
   (assert (contains? extension encoding)

(ns transit.verify
  (:require [transit.read :as r]
            [transit.write :as w]
            [clojure.java.io :as io]
            [transit.generators :as gen]
            [transit.corner-cases :as cc])
  (:import [java.io PrintStream ByteArrayOutputStream ByteArrayInputStream
            BufferedInputStream BufferedOutputStream FileInputStream]
           [java.util Arrays]
           [org.apache.commons.codec.binary Hex]))

(def TIMEOUT 10000)

(def ^:dynamic *color* false)

(def colors {:reset "[0m"
             :red "[31m"
             :yellow "[33m"
             :green "[32m"
             :bright "[1m"})

(defn with-color [color & strs]
  (let [s (apply str (interpose " " strs))]
    (if (and *color* (not= color :none))
      (str \u001b (color colors) s \u001b (:reset colors))
      s)))

(defn read-bytes [file]
  (assert (.exists file) "file must exist")
  (assert (.isFile file) "file must actually be a file")
  (let [size (.length file)
        bytes (make-array Byte/TYPE size)
        in (BufferedInputStream. (FileInputStream. file))]
    (loop [g (.read in bytes 0 size)
           r 0]
      (if (or (= g -1) (= (+ g r) size))
        bytes
        (let [offset (+ g r)
              size (- size offset)]
          (recur (.read in bytes offset size) offset))))))

(defn write-transit [o encoding]
  (let [out (ByteArrayOutputStream.)
        w (w/writer out encoding)]
    (w/write w o)
    (.toByteArray out)))

(defn read-transit [bytes encoding]
  (try
    (let [in (ByteArrayInputStream. bytes)
          r (r/reader in encoding)]


(defn roundtrip-transit [proc transit-out encoding]
  (write-to-stream proc transit-out)
  (let [data-in (read-response proc transit-out TIMEOUT)
        data-out (read-transit transit-out encoding)]
    {:transit-expected (String. transit-out)
     :data-expected data-out
     :data-actual data-in
     ;; only checks the top level type
