             [clj-http.client :as client]
             [clojure
              [data :as data]
-             [string :as str]]
+             [string :as str]
+             [test :refer [deftest is run-tests testing]]]
             [clojure.data.csv :as csv]
             [clojure.java.io :as io]
             [clojure.tools.logging :as log])

               (and (not= status exp-status)
                    (str "status " status " not equal to expected " exp-status))
               (some (fn [[header value]]
                        (if (not= value (headers header))
                          (str "header " header " was " (headers header) " expected " value))) exp-headers)
               (if-let [diff (and (not-empty exp-body) (first (data/diff exp-body body*)))]
                 (->> diff json/generate-string (str "expected body missing:" ))))]
    (if error [error resp])))

(defn test-all [suites]
  (for [{:keys[suite tests]} suites
        :let [results (doall (map #(future [(% :test)
                                            (verify-response (mk-request %) %)]) tests))]]
    {:suite suite
     :results results
     :total (count results)
     :failures (count (filter #(second @%) results))}))

(defn print-test-results [suites]
  (let [total (reduce + (map :total suites))
        fail-count (reduce + (map :failures suites))]
    (println "=============================================================")
    (println "Test cases:" total ", failed:" fail-count)
    (doseq [{:keys [suite results]} suites]
      (println suite)
      (doseq [result results :let [[test result] @result]][]
        (print (if result "\u001B[31m [x] " "\u001B[32m [v] "))
        (println test "\t" (or (first result) :OK) "\u001B[0m")))))

(defn -main
  "Give me a CSV with API rest cases and I will verify them"
  [& args]
  (let [opts (apply hash-map (map-indexed #(if (even? %1) (subs %2 1) %2) (rest args)))]
    (println "running with arguments:" opts)
    (try
      (print-test-results (test-all (tests-from (first args) opts)))
      (finally
        (shutdown-agents)))))

   (if-not (str/blank? s)
     (->> (str/split s #"\s*,\s*") (map #(let [[k v] (str/split % sep 2)]
                                           [k (replace-opts v opts)])) (into {})))))
(defn- diff* [a b]
  (cond
    (= a b) nil
    (map? a) (if (map? b)
               (let [d (filter #(diff* (second %) (b (first %))) a)]
                 (if (empty? d) nil (into {} d)))
               a)
    (vector? a) (if (vector? b)
                  (let [e (filter (fn [x] (every? #(diff* x %) b)) a)]
                    (if (empty? e) nil (vec e)))
                  a)
    (string? a) (and (= \# (first a)) (not (re-matches (re-pattern (subs a 1)) (str b)))
                     a)
    :else a))

(defn load-tests-from [file opts]
  (with-open [in-file (io/reader file)]
    (reduce
     (fn [suites [suite test url verb headers payload params exp-status exp-body exp-headers]]
       (let [test-case {:test test :url (replace-opts url opts) :verb verb
                        :headers (str->map headers #":" opts)
                        :params (str->map params #"\s*=\s*" opts)
