Skip to content

Commit

Permalink
CLJ-1716: print ex-data on throwables
Browse files Browse the repository at this point in the history
Also added tests for the existing exception printing
behavior, and the new behavior.

Signed-off-by: Stuart Halloway <stu@cognitect.com>
  • Loading branch information
gfredericks authored and stuarthalloway committed May 12, 2015
1 parent 49baf1e commit 01b4228
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 7 deletions.
29 changes: 22 additions & 7 deletions src/clj/clojure/core_print.clj
Expand Up @@ -415,28 +415,43 @@

(defn Throwable->map [^Throwable o]
(let [base (fn [^Throwable t]
{:type (class t)
:message (.getLocalizedMessage t)
:at (get (.getStackTrace t) 0)})
(let [m {:type (class t)
:message (.getLocalizedMessage t)
:at (get (.getStackTrace t) 0)}
data (ex-data t)]
(if data
(assoc m :data data)
m)))
via (loop [via [], ^Throwable t o]
(if t
(recur (conj via t) (.getCause t))
via))]
{:cause (.getLocalizedMessage ^Throwable (last via))
via))
^Throwable root (peek via)
m {:cause (.getLocalizedMessage root)
:via (vec (map base via))
:trace (vec (.getStackTrace (or ^Throwable (last via) o)))}))
:trace (vec (.getStackTrace ^Throwable (or root o)))}
data (ex-data root)]
(if data
(assoc m :data data)
m)))

(defn- print-throwable [^Throwable o ^Writer w]
(.write w "#error {\n :cause ")
(let [{:keys [cause via trace]} (Throwable->map o)
(let [{:keys [cause data via trace]} (Throwable->map o)
print-via #(do (.write w "{:type ")
(print-method (:type %) w)
(.write w "\n :message ")
(print-method (:message %) w)
(when-let [data (:data %)]
(.write w "\n :data ")
(print-method data w))
(.write w "\n :at ")
(print-method (:at %) w)
(.write w "}"))]
(print-method cause w)
(when data
(.write w "\n :data ")
(print-method data w))
(when via
(.write w "\n :via\n [")
(when-let [fv (first via)]
Expand Down
22 changes: 22 additions & 0 deletions test/clojure/test_clojure/errors.clj
Expand Up @@ -58,3 +58,25 @@
(catch Throwable t
(is (= {:foo 1} (ex-data t)))))
(is (nil? (ex-data (RuntimeException. "example non ex-data")))))

(deftest Throwable->map-test
(testing "base functionality"
(let [{:keys [cause via trace]} (Throwable->map
(Exception. "I am a string literal"))]
(is (= cause "I am a string literal"))
(is (= 1 (count via)))
(is (vector? via))
(is (= ["I am a string literal"] (map :message via)))))
(testing "causes"
(let [{:keys [cause via trace]} (Throwable->map
(Exception. "I am not a number"
(Exception. "double two")))]
(is (= cause "double two"))
(is (= ["I am not a number" "double two"]
(map :message via)))))
(testing "ex-data"
(let [{[{:keys [data]}] :via
data-top-level :data}
(Throwable->map (ex-info "ex-info"
{:some "data"}))]
(is (= data data-top-level {:some "data"})))))
32 changes: 32 additions & 0 deletions test/clojure/test_clojure/printer.clj
Expand Up @@ -119,3 +119,35 @@
#'var-with-meta "#'clojure.test-clojure.printer/var-with-meta"
#'var-with-type "#'clojure.test-clojure.printer/var-with-type"))

(defn ^:private ednize-stack-trace-element
[^StackTraceElement ste]
[(symbol (.getClassName ste))
(symbol (.getMethodName ste))
(.getFileName ste)
(.getLineNumber ste)])

(defn ^:private ednize-throwable-data
[throwable-data]
(-> throwable-data
(update :via (fn [vias]
(map (fn [via]
(-> via
(update :type #(symbol (.getName %)))
(update :at ednize-stack-trace-element)))
vias)))
(update :trace #(map ednize-stack-trace-element %))))

(deftest print-throwable
(binding [*data-readers* {'error identity}]
(are [e] (= (-> e Throwable->map ednize-throwable-data)
(-> e pr-str read-string))
(Exception. "heyo")
(Throwable. "I can a throwable"
(Exception. "chain 1"
(Exception. "chan 2")))
(ex-info "an ex-info" {:with "its" :data 29})
(Exception. "outer"
(ex-info "an ex-info" {:with "data"}
(Error. "less outer"
(ex-info "the root"
{:with "even" :more 'data})))))))

0 comments on commit 01b4228

Please sign in to comment.