Skip to content

Fixed tests after resolving git conflict issues #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
[org.clojure/clojure "1.5.0"]
[clj-stacktrace "0.2.5"]
[org.clojure/core.incubator "0.1.2"]
;[trammel "0.7.0"]
;[org.clojure/core.contracts "0.0.4"]
[seesaw "1.4.3"]]
:main intro.core)
:main intro.core
)
59 changes: 46 additions & 13 deletions src/errors/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,62 @@
[errors.messageobj]
[seesaw.core]))

;;(def ignore-nses #"(clojure|java)\..*")
;; Ignore stack trace entries beginning with user, clojure, or java
(def ignore-nses #"(user|clojure|java)\..*")

;; Gets the first match out of the error dictionary
;; based on the exception class and the message
(defn- first-match [e message]
(println (str (class e) " " message)) ; debugging print
;(println (str (class e) " " message)) ; debugging print
(first (filter #(and (instance? (:class %) e) (re-matches (:match %) message))
error-dictionary)))

;; Putting together a message (perhaps should be moved to errors.dictionaries? )
(defn- get-pretty-message [e]
(let [m (.getMessage e)
message (if m m "")] ; converting an empty message from nil to ""
(if-let [entry (first-match e message)]
((:make-preobj entry) (re-matches (:match entry) message))
(make-preobj-hashes message))))
message (if m m "")] ; converting an empty message from nil to ""
(if-let [entry (first-match e message)]
((:make-preobj entry) (re-matches (:match entry) message))
(make-preobj-hashes message))))

;; Returns true if a :trace-elems element is meaningful to the student
(defn- is-meaningful-elem? [elem]
(and
(:clojure elem)
(not (re-matches ignore-nses (:ns elem))))
)

;; Takes in a single :trace-elems entry and produces a string for
;; our filtered stacktrace
(defn- create-error-str [err-elem]
(str
"\t"
(:ns err-elem)
"/"
(:fn err-elem)
" ("
(:file err-elem)
" line "
(:line err-elem)
")"
)
)

;; Creates the pre-object from a filtered stack trace
(defn- create-pre-obj [errstrs]
(make-preobj-hashes (str "\nSequence of function calls:\n" (join "\n" errstrs)) :causes)
)

;; Creates the full error object that is to be displayed
(defn- create-error-obj [e preobj]
(make-obj (concat (make-preobj-hashes "ERROR: " :err)
(get-pretty-message e)
preobj)))

;; All together:
(defn prettify-exception [e]
(let [info (stacktrace/parse-exception e)
cljerrs (filter #(and (:clojure %) (not (re-matches ignore-nses (:ns %))))
(:trace-elems info))
errstrs (map #(str "\t" (:ns %) "/" (:fn %) " (" (:file %) " line " (:line %) ")") cljerrs)]
(show-error (make-obj (concat (make-preobj-hashes "ERROR: " :err) (get-pretty-message e)
(make-preobj-hashes (str "\nSequence of function calls:\n" (join "\n" errstrs)) :causes)))
e)))
(let [preobj (->> e stacktrace/parse-exception
(#(filter is-meaningful-elem? (:trace-elems %)))
(map create-error-str)
(create-pre-obj))]
(show-error (create-error-obj e preobj) e)))
9 changes: 6 additions & 3 deletions src/errors/dictionaries.clj
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@
:make-preobj (fn [matches] (make-preobj-hashes "There is an unmatched parameter in declaration of "
(nth matches 1) :arg))}
{:class IllegalArgumentException
; TODO New message:
; (nth matches 1) "'s must be pairs, you passed an odd number of parameters to " (nth matches 1) " on line " (nth matches 3) " in the file " (nth matches 2)
:match #"(.*) requires an even number of forms in binding vector in (.*):(.*)"
:make-preobj (fn [matches] (make-preobj-hashes "A parameter for a " (nth matches 1)
" is missing a binding on line "
Expand Down Expand Up @@ -221,7 +223,8 @@
:match #"Unsupported binding form: (.*)"
:make-preobj (fn [matches] (make-preobj-hashes "You cannot use " (nth matches 1) :arg
" as a variable."))}
;; Compilation errors
;; Compilation errors
;; These next two exceptions about wrong # of args will only be thrown by macros NOT functions
{:class clojure.lang.Compiler$CompilerException
:match #"(.+): Too many arguments to (.+), compiling:(.+)"
;:replace "Compilation error: too many arguments to $2 while compiling $3"
Expand All @@ -237,11 +240,11 @@
{:class clojure.lang.Compiler$CompilerException
:match #"(.+): EOF while reading, starting at line (.+), compiling:(.+)"
:replace "Compilation error: end of file, starting at line $2, while compiling $3.\nProbabbly a non-closing parentheses or bracket."
:make-preobj make-mock-preobj}
:make-preobj make-mock-preobj} ; TODO Make preobj function
{:class clojure.lang.Compiler$CompilerException
:match #"(.+): Unmatched delimiter: (.+), compiling:(.+)"
;:replace "Compilation error: a closing $2 without a matching opening one while compiling $3."
:make-preobj make-mock-preobj}
:make-preobj make-mock-preobj} ; TODO Make preobj function
{:class clojure.lang.Compiler$CompilerException
:match #"(.+): Unable to resolve symbol: (.+) in this context, compiling:\((.+)\)"
;:replace "Compilation error: name $2 is undefined in this context, while compiling $3."
Expand Down
47 changes: 24 additions & 23 deletions src/errors/messageobj.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
(ns errors.messageobj)
;(:refer corefn/core :only [add-fisrt add-last]))
;; Functions related to a message object. Message object
;; is a vector of parts of a message (in order). Each
;; part is a hash map that contains the message text :msg,
Expand All @@ -8,40 +8,41 @@
;; A message pre-object doesn't have :start

(defn make-msg-preobj-hash
"creates a hash map for a msg pre-object out of a msg and style"
([msg style] (let [m (str msg)]
{:msg m :stylekey style :length (count m)}))
([msg] (let [m (str msg)]
{:msg m :stylekey :reg :length (count m)})))
"creates a hash map for a msg pre-object out of a msg and style"
([msg style] (let [m (str msg)]
{:msg m :stylekey style :length (count m)}))
([msg] (let [m (str msg)]
{:msg m :stylekey :reg :length (count m)})))

(defn- make-msg-preobj-hashes-helper [messages result]
(if (empty? messages) result
(let [next (second messages)]
(if (keyword? next) (recur (rest (rest messages))
(conj result (make-msg-preobj-hash (first messages) next)))
(recur (rest messages)
(conj result (make-msg-preobj-hash (first messages))))))))
(if (empty? messages) result
(let [next (second messages)]
(if (keyword? next) (recur (rest (rest messages))
(conj result (make-msg-preobj-hash (first messages) next)))
;ELSE CASE
(recur (rest messages)
(conj result (make-msg-preobj-hash (first messages))))))))

(defn make-preobj-hashes [& args]
"creates a vector of hash maps out of a vector that are strings, possibly followed by optional keywords"
(make-msg-preobj-hashes-helper args []))
"creates a vector of hash maps out of a vector that are strings, possibly followed by optional keywords"
(make-msg-preobj-hashes-helper args []))

;(defn make-preobj-hashes [messages]
; "creates a vector of hash maps out of a vector of vectors of msg + optional style"
; ;; apply is needed since messages contains vectors of 1 or 2 elements
; (map #(apply make-msg-preobj-hash %) messages))
;(defn make-preobj-hashes [messages]
; "creates a vector of hash maps out of a vector of vectors of msg + optional style"
; ;; apply is needed since messages contains vectors of 1 or 2 elements
; (map #(apply make-msg-preobj-hash %) messages))

(defn make-obj [pre-obj] ; pre-obj is a vector of hashmaps
"fills in the starting points of objects in the hash maps"
(loop [hashes pre-obj start 0 res []]
(if (empty? hashes) res
(recur (rest hashes)
(+ start (:length (first hashes)))
(conj res (assoc (first hashes) :start start))))))
(recur (rest hashes)
(+ start (:length (first hashes)))
(conj res (assoc (first hashes) :start start))))))

(defn get-all-text [msg-obj]
"concatenate all text from a message object into a string"
(reduce #(str %1 (:msg %2)) "" msg-obj))
"concatenate all text from a message object into a string"
(reduce #(str %1 (:msg %2)) "" msg-obj))

(defn make-mock-preobj [matches]
"creates a test message pre-obj. Used for testing so that things don't break"
Expand Down
5 changes: 1 addition & 4 deletions src/intro/student.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
(ns intro.student
(:use [corefns.core]
[seesaw.core]
[turtle.core]))
(ns intro.student)

;; Testing compilation errors

Expand Down
18 changes: 15 additions & 3 deletions test/errors/core_test.clj
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
(ns errors.core_test
(:use [clojure.test]
[errors.core]
[errors.dictionaries]))
[errors.dictionaries]
[errors.messageobj]))

(def simple-non-match-exception (java.lang.Exception. "Test Message"))
(def get-pretty-message (ns-resolve 'errors.core 'get-pretty-message))
(def class-cast-exception (java.lang.ClassCastException. "oneType cannot be cast to anotherType"))
(def bigint-illegal-arg-ex (java.lang.IllegalArgumentException. "contains? not supported on type: clojure.lang.BigInt"))
(def best-approximation (ns-resolve 'errors.dictionaries 'best-approximation))
(def incorrect-let-exception (try (eval (read-string "(let [l 1 s] (println l))")) (catch Exception e e)))

(defn get-pretty-message-string [e]
(-> e get-pretty-message get-all-text)
)

(deftest test-best-approximation
(is (= "unrecognized type oneType" (best-approximation "oneType")))
(is (= "a number" (best-approximation "clojure.lang.BigInt")))
;(is (= "unrecognized type clojure.lang.LittleInt" (best-approximation "clojure.lang.LittleInt"))) This triggers a classNotFoundException since there are periods in the type name
)

(deftest test-get-pretty-message
(is (= "Test Message" (get-pretty-message simple-non-match-exception)))
(is (= "Attempted to use unrecognized type oneType, but unrecognized type anotherType was expected." (get-pretty-message class-cast-exception)))
(is (= "Test Message" (get-pretty-message-string simple-non-match-exception)))
(is (= "Attempted to use unrecognized type oneType, but unrecognized type anotherType was expected." (get-pretty-message-string class-cast-exception)))
(is (= "Function contains? does not allow a number as an argument" (get-pretty-message-string bigint-illegal-arg-ex)))
(is (= "A parameter for a let is missing a binding on line in the file errors.core_test" (get-pretty-message-string incorrect-let-exception)))
)