     (catch Throwable e
       ::read-error)))
 
-(defn start-process [command encoding]
+(defn start-process
+  "Given a command and enconding, start a process which can roundtrip
+  transit data. The command is the path to any program which will
+  start a roundtrip process. The enconding must be either `:json` or
+  `:msgpack`. Returns a map (process map) with keys `:out` the output
+  stream which can be used to send data to the process, `:p` the
+  process and `:reader` a transit reader."
+  [command encoding]
   ;; TODO: what if there is exception here? need to report that we
   ;; couldn't start the process?
   ;; TODO: how do we communicate that the encoding is not supported?

      (println "WARNING! Exception while stopping process.")
      (println (.toString e)))))

;; TODO: failure to write means that the process has died
;; catch and throw the way we do with read-response
(defn write-to-stream [proc transit-data]
  (.write (:out proc) transit-data 0 (count transit-data))
  (.flush (:out proc)))

(defn read-response [proc transit-out timeout-ms]
  (let [f (future (r/read @(:reader proc)))]
    (let [response (deref f timeout-ms ::timeout)]
      (if (= response ::timeout)
        (throw (ex-info "Response timeout" {:status :timeout :p proc :transit transit-out}))
        response))))

(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
     :status (if (and (= (type data-out) (type data-in))
                      (= data-out data-in))
               :success
               :error)}))

(defn roundtrip-edn [proc edn encoding]
  (try
    (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 100]
    (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 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)

(ns transit.verify
  "Provides tools for testing all transit implementations at
  once. Tests each implementaion with several sources of data:
  exemplar files, problem EDN data, problem transit data and generated
  data. In addition, it can capture comparative timing results.

  From the REPL, the main entry point is `verify-all` which takes an
