I have the following code and it works when I go through and step through it in Cider, but when I run it straight through on the command line I get the following error:
Exception in thread "main" java.lang.IllegalStateException: Attempting to call unbound fn: #'clojure-todo.todo/execute-todo-cmd, compiling:(/private/var/folders/d_/b8gmsvl16sgdg70m15gx20l40000gn/T/form-init6080372317525706515.clj:1:125)
at clojure.lang.Compiler.load(Compiler.java:7391)
at clojure.lang.Compiler.loadFile(Compiler.java:7317)
at clojure.main$load_script.invokeStatic(main.clj:275)
at clojure.main$init_opt.invokeStatic(main.clj:277)
at clojure.main$init_opt.invoke(main.clj:277)
at clojure.main$initialize.invokeStatic(main.clj:308)
at clojure.main$null_opt.invokeStatic(main.clj:342)
at clojure.main$null_opt.invoke(main.clj:339)
at clojure.main$main.invokeStatic(main.clj:421)
at clojure.main$main.doInvoke(main.clj:384)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:383)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)
Caused by: java.lang.IllegalStateException: Attempting to call unbound fn: #'clojure-todo.todo/execute-todo-cmd
Here is the code. I guess it's a namespace error, but I'm confused as to how it could be a namespace issue if it's working in cider.
(ns clojure-todo.todo
(:gen-class))
///// Other Code here
(defn print-msg-list [list]
(doseq [item list] (print-msg item)))
(defn create-todo [todo-string] (hash-map :todo-content todo-string :checked false))
(defn list-todos [todos]
(doseq [single-todo todos]
(do
(print (get single-todo :todo-content))
(let [is-checked (get single-todo :checked)]
(if is-checked
(print-msg :is-checked)
(print-msg :is-unchecked))))))
(defn add-todo []
(do
(print-msg :add-todo-message)
(let [todo-string (read-line) the-todo-created (create-todo todo-string)]
(def the-todos (conj the-todos the-todo-created))
(list-todos the-todos)))
(def todo-fns {"1" add-todo "2" delete-todo "3" list-todos "4" check-todo})
(defn execute-todo-cmd [command]
(get todo-fns command nil)))
(defn take-todo-command [backup-fn]
(let [command (read-line)]
(if (= command "q")
(print-msg :goodbye)
(let [todo-fn (execute-todo-cmd command)]
(if todo-fn
(todo-fn)
(do
(print-msg :sorry)
(print-msg :border)
(backup-fn)))))))
(defn run-app []
(do
(print-msg :welcome)
(print-msg-list '(:add-todo :list-todos :delete-todo :check-todo :quit))
;; The take-todo-command fn takes a backup in case the user types in
;; a command that's not supported by the application. In this case we just
;; want the app to restart
(take-todo-command run-app)))
This was just missing a close paren in add-todo, and there is an extra close paren in execute-todo-cmd. So execute-todo-cmd does not exist until add-todo is run, which is why it yields an unbound-fn error.
Related
Is there anyway to include clojure.spec'd functions in a generalized test suite? I know we can register specs and directly spec functions.
(ns foo
(:require [clojure.spec :as s]
[clojure.spec.test :as stest]))
(defn average [list-sum list-count]
(/ list-sum list-count))
(s/fdef average
:args (s/and (s/cat :list-sum float? :list-count integer?)
#(not (zero? (:list-count %))))
:ret number?)
And later, if I want to run generative tests against that spec'd function, I can use stest/check.
=> (stest/check `average)
({:spec #object[clojure.spec$fspec_impl$reify__14282 0x68e9f37c "clojure.spec$fspec_impl$reify__14282#68e9f37c"], :clojure.spec.test.check/ret {:result true, :num-tests 1000, :seed 1479587517232}, :sym edgar.core.analysis.lagging/average})
But i) is there anyway to include these test runs in my general test suite? I'm thinking of the kind of clojure.test integration that test.check has. The closest thing that I can see ii) is the stest/instrument (see here) function. But that seems to just let us turn on checking at the repl. Not quite what I want. Also, iii) are function specs registered?
(defspec foo-test
100
;; NOT this
#_(prop/for-all [v ...]
(= v ...))
;; but THIS
(stest/some-unknown-spec-fn foo))
Ok, solved this one. Turns out there's no solution out of the box. But some people on the clojure-spec slack channel have put together a defspec-test solution for clojure.spec.test and clojure.test.
So given the code in the question. You can A) define the defspec-test macro that takes your test name and a list of spec'd functions. You can then B) use it in your test suite.
Thanks Clojure community!! And hopefully such a utility function makes it into the core library.
A)
(ns foo.test
(:require [clojure.test :as t]
[clojure.string :as str]))
(defmacro defspec-test
([name sym-or-syms] `(defspec-test ~name ~sym-or-syms nil))
([name sym-or-syms opts]
(when t/*load-tests*
`(def ~(vary-meta name assoc
:test `(fn []
(let [check-results# (clojure.spec.test/check ~sym-or-syms ~opts)
checks-passed?# (every? nil? (map :failure check-results#))]
(if checks-passed?#
(t/do-report {:type :pass
:message (str "Generative tests pass for "
(str/join ", " (map :sym check-results#)))})
(doseq [failed-check# (filter :failure check-results#)
:let [r# (clojure.spec.test/abbrev-result failed-check#)
failure# (:failure r#)]]
(t/do-report
{:type :fail
:message (with-out-str (clojure.spec/explain-out failure#))
:expected (->> r# :spec rest (apply hash-map) :ret)
:actual (if (instance? Throwable failure#)
failure#
(:clojure.spec.test/val failure#))})))
checks-passed?#)))
(fn [] (t/test-var (var ~name)))))))
B)
(ns foo-test
(:require [foo.test :refer [defspec-test]]
[foo]))
(defspec-test test-average [foo/average])
The above example can fail in the case where :failure is false due to how stest/abbrev-result tests for failure. See CLJ-2246 for more details. You can work around this by defining your own version of abbrev-result. Also, the formatting of failure data has changed.
(require
'[clojure.string :as str]
'[clojure.test :as test]
'[clojure.spec.alpha :as s]
'[clojure.spec.test.alpha :as stest])
;; extracted from clojure.spec.test.alpha
(defn failure-type [x] (::s/failure (ex-data x)))
(defn unwrap-failure [x] (if (failure-type x) (ex-data x) x))
(defn failure? [{:keys [:failure]}] (not (or (true? failure) (nil? failure))))
;; modified from clojure.spec.test.alpha
(defn abbrev-result [x]
(let [failure (:failure x)]
(if (failure? x)
(-> (dissoc x ::stc/ret)
(update :spec s/describe)
(update :failure unwrap-failure))
(dissoc x :spec ::stc/ret))))
(defn throwable? [x]
(instance? Throwable x))
(defn failure-report [failure]
(let [expected (->> (abbrev-result failure) :spec rest (apply hash-map) :ret)]
(if (throwable? failure)
{:type :error
:message "Exception thrown in check"
:expected expected
:actual failure}
(let [data (ex-data (get-in failure
[::stc/ret
:result-data
:clojure.test.check.properties/error]))]
{:type :fail
:message (with-out-str (s/explain-out data))
:expected expected
:actual (::s/value data)}))))
(defn check?
[msg [_ body :as form]]
`(let [results# ~body
failures# (filter failure? results#)]
(if (empty? failures#)
[{:type :pass
:message (str "Generative tests pass for "
(str/join ", " (map :sym results#)))}]
(map failure-report failures#))))
(defmethod test/assert-expr 'check?
[msg form]
`(dorun (map test/do-report ~(check? msg form))))
Here's a slightly modified version of grzm's excellent answer that works with [org.clojure/test.check "0.10.0-alpha4"]. It uses the new :pass? key that comes from this PR: https://github.com/clojure/test.check/commit/09927b64a60c8bfbffe2e4a88d76ee4046eef1bc#diff-5eb045ad9cf20dd057f8344a877abd89R1184.
(:require [clojure.test :as t]
[clojure.string :as str]
[clojure.spec.alpha :as s]
[clojure.spec.test.alpha :as stest])
(alias 'stc 'clojure.spec.test.check)
;; extracted from clojure.spec.test.alpha
(defn failure-type [x] (::s/failure (ex-data x)))
(defn unwrap-failure [x] (if (failure-type x) (ex-data x) x))
;; modified from clojure.spec.test.alpha
(defn abbrev-result [x]
(if (-> x :stc/ret :pass?)
(dissoc x :spec ::stc/ret)
(-> (dissoc x ::stc/ret)
(update :spec s/describe)
(update :failure unwrap-failure))))
(defn throwable? [x]
(instance? Throwable x))
(defn failure-report [failure]
(let [abbrev (abbrev-result failure)
expected (->> abbrev :spec rest (apply hash-map) :ret)
reason (:failure abbrev)]
(if (throwable? reason)
{:type :error
:message "Exception thrown in check"
:expected expected
:actual reason}
(let [data (ex-data (get-in failure
[::stc/ret
:shrunk
:result-data
:clojure.test.check.properties/error]))]
{:type :fail
:message (with-out-str (s/explain-out data))
:expected expected
:actual (::s/value data)}))))
(defn check?
[msg [_ body :as form]]
`(let [results# ~body
failures# (remove (comp :pass? ::stc/ret) results#)]
(if (empty? failures#)
[{:type :pass
:message (str "Generative tests pass for "
(str/join ", " (map :sym results#)))}]
(map failure-report failures#))))
(defmethod t/assert-expr 'check?
[msg form]
`(dorun (map t/do-report ~(check? msg form))))
Usage:
(deftest whatever-test
(is (check? (stest/check `whatever
;; optional
{:clojure.spec.test.check/opts {:num-tests 10000}})))
Here's my core code (sorry, some parts are in Portuguese)
(ns prova1-ed.core
(:gen-class))
(use 'clojure.java.io)
(defn getFile []
(let [filename (read-line)]
(if (.exists (java.io.File. filename))
filename
(do
(println "Nome de arquivo inválido. Digite novamente:")
(recur)))))
(defn getFileLines [^String filename]
(defn lista '())
(with-open [rdr (reader filename)]
(doseq [line (line-seq rdr)]
(if-not (= "" line)
(concat lista '(line)))
))
lista)
(defn -main [& args]
(println "Olá! Digite um arquivo contendo as contas bancárias:")
(getFileLines (getFile)))
prova1-ed.core> (-main)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: -main in this context, compiling:(C:\Users\Tiago\AppData\Local\Temp\form-init296650600503762010.clj:1:1)
I'm using cider, lein and Emacs. I haven't changed the project.clj. It was working yesterday (really).
If needed, I may provide more datails.
Edit
I tried lein run as suggested and I received
Unable to resolve symbol: filename in this context, compiling:(prova1_ed/core.clj:8:18)
filename was supposed to be the read-line result.
The error is on (defn lista '()). It should be (def lista '()).
It's working know.
(It's hard to debug using Emacs)
Thanks!
I have a Ring handler which uses several functions to build the response. If any of these functions throw an exception, it should be caught so a custom response body can be written before returning a 500.
I'm writing the unit test for the handler, and I want to ensure that an exception thrown by any of these functions will be handled as described above. My instinct was to use with-redefs inside a doseq:
(doseq [f [ns1/fn1 ns1/fn2 ns2/fn1]]
(with-redefs [f (fn [& args] (throw (RuntimeException. "fail!"))]
(let [resp (app (request :get "/foo")))))]
(is (= (:status resp) 500))
(is (= (:body resp) "Something went wrong")))))
Of course, given that with-redefs wants to change the root bindings of vars, it is treating f as a symbol. Is there any way to get it to rebind the var referred to by f? I suspect that I'm going to need a macro to accomplish this, but I'm hoping that someone can come up with a clever solution.
with-redefs is just sugar over repeated calls to alter-var-root, so you can just write the desugared form yourself, something like:
(doseq [v [#'ns1/fn1 #'ns1/fn2 #'ns2/fn1]]
(let [old #v]
(try
(alter-var-root v (constantly (fn [& args]
(throw (RuntimeException. "fail!")))))
(let [resp (app (request :get "/foo")))
(is (= (:status resp) 500))
(is (= (:body resp) "Something went wrong")))
(finally (alter-var-root v (constantly old))))))
Following on from amalloy's great answer, here's a utility function that I wrote to use in my tests:
(defn with-mocks
"Iterates through a list of functions to-mock, rebinding each to mock-fn, and calls
test-fn with the optional test-args.
Example:
(defn foobar [a b]
(try (+ (foo a) (bar b))
(catch Exception _ 1)))
(deftest test-foobar
(testing \"Exceptions are handled\"
(with-mocks
[#'foo #'bar]
(fn [& _] (throw (RuntimeException. \"\")))
(fn [a b] (is (= 1 (foobar a b)))) 1 2)))"
[to-mock mock-fn test-fn & test-args]
(doseq [f to-mock]
(let [real-fn #f]
(try
(alter-var-root f (constantly mock-fn))
(apply test-fn test-args)
(finally
(alter-var-root f (constantly real-fn)))))))
So, in my core.clj file I have:
(def page-buffer (BufferedReader. (InputStreamReader. (clojure.java.io/input-stream (clojure.java.io/resource "mitochondria.html")))))
(def parsed-page (atom ""))
and then later:
(defn -main [& args]
(let [port (Integer/parseInt (first args))]
(swap! parsed-page (with-open []
(.toString (reduce #(.append %1 %2)
(StringBuffer.) (line-seq page-buffer)))))
(println "Server is starting")
(println "port: " port)
(run-server port)))
This compiles and then I turn it into an uberjar. But when I run it I get the line with swap! blows up:
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn
at clojure.core$swap_BANG_.invoke(core.clj:2106)
at serve_pages_from_memory.core$_main.doInvoke(core.clj:29)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at serve_pages_from_memory.core.main(Unknown Source)
I tried this without using an atom and everything worked just fine (using a var defined with "def" to be a string) but eventually I want to send this var to multiple threads, so I need for this to be an atom or agent.
What have I done wrong?
UPDATE:
Jeremy Heiler, thanks. Fixed, but the result is ugly as sin:
(defn parse-buffer [& everything-else]
(with-open []
(.toString (reduce #(.append %1 %2)
(StringBuffer.) (line-seq page-buffer)))))
(defn -main [& args]
(let [port (Integer/parseInt (first args))]
(swap! parsed-page parse-buffer)
(println "Server is starting")
(println "port: " port)
(run-server port)))
I have to give an argument to parse-buffer or I get an error. But I do not use the argument, so this is ugly. I must be writing this wrong, yes?
You need to pass a function to swap!. Right now you are passing it a value.
(let [foo (atom 1)]
(swap! foo + 2)
#foo)
The above expression will return 3. The passed in function takes the current value of the atom, and the return value becomes the new value of the atom. Any extra arguments are passed to the given function.
To comment on your update: Yes, you do need to give an argument to the function used in swap!. The first argument is the current value of the the atom. However, you don't need to hack parse-buffer in order to make it work. You can just wrap it with an anonymous function.
Also, parse-buffer can be simplified greatly. Since line-seq returns a sequence of lines from the given reader, and str uses a StringBuilder internally, you can just apply it over the sequence.
(defn parse-buffer []
(with-open [buf page-buffer]
(apply str (line-seq buf))))
(defn -main [& args]
(let [port (Integer/parseInt (first args))]
(swap! parsed-page (fn [cur-val] (parse-buffer)))
(println "Server is starting")
(println "port: " port)
(run-server port)))
I want a map in an atom that can keep track of times as Unix time stamps.
So, in my main function I have:
(defn -main [& args]
(println "Server is starting")
(def port (Integer/parseInt (first args)))
(def registry (atom {}))
(run-server port who-is-here registry))
And inside of run-server I have a call to add-to-logged-in-registry:
(defn add-to-logged-in-registry
[registry]
(let [moments (Date.)
right-now (.getTime moments)]
(swap! registry conj right-now)))
This last line gives me this error:
Exception in thread "main" java.lang.IllegalArgumentException: Don't know how to create ISeq from: java.lang.Long
at clojure.lang.RT.seqFrom(RT.java:487)
at clojure.lang.RT.seq(RT.java:468)
at clojure.lang.APersistentMap.cons(APersistentMap.java:39)
at clojure.lang.RT.conj(RT.java:544)
at clojure.core$conj.invoke(core.clj:83)
at clojure.lang.Atom.swap(Atom.java:51)
at clojure.core$swap_BANG_.invoke(core.clj:2107)
at who_is_logged_in.core$add_to_logged_in_registry.invoke(core.clj:39)
at who_is_logged_in.core$listen_and_respond.invoke(core.clj:42)
at who_is_logged_in.core$run_server.invoke(core.clj:52)
at who_is_logged_in.core$_main.doInvoke(core.clj:76)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at who_is_logged_in.core.main(Unknown Source)
What does this mean?
When I try this at the REPL in emacs, this works perfectly:
user> (def registry (atom []))
#'user/registry
user> (let [moments (Date.)
right-now (.getTime moments)]
(swap! registry conj right-now))
[1345698128988]
user> (let [moments (Date.)
right-now (.getTime moments)]
(swap! registry conj right-now))
[1345698128988 1345698132472]
conj behaves differently depending on the type of collection it is adding elements to. In your first example it is adding elements to a map and needs A key and a value in a collection. In your REPL example it is adding elements to a vector and needs only a single value.
swap!ing into a map:
(def registry (atom{}))
(let [moments (java.util.Date.)
right-now (.getTime moments)]
(swap! registry conj [:time right-now]))
{:time 1345700872898}