I'm trying to include midje "facts" alongside my source code in a project which uses aot. Trying to access the repl or run the project results in the following error, I've included a minimal sample project which reproduces the issue. Thanks for any help!
project.clj
(defproject test-midje "0.1.1"
:description "Why doesn't midje work?"
:min-lein-version "2.0.0"
:source-paths ["src/clj"]
:repl-options {
:timeout 120000
}
:main org.midjetest.core
:profiles {:dev {:dependencies [[midje "1.5.0"]]}}
:aot [org.midjetest.core])
src/clj/org/midjetest/core.clj
(ns org.midjetest.core
(:require [midje.sweet :refer [fact facts]]))
(defn addtwo [a] (+ 2 a))
(fact "addtwo adds two to numbers"
(addtwo 3) => 5)
(defn -main
"testing with main"
([] (println (addtwo 5))))
lein run
or lein repl
give the following error:
$ lein repl
Compiling org.midjetest.core
Exception in thread "main" java.lang.ExceptionInInitializerError
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:270)
at clojure.lang.RT.loadClassForName(RT.java:2056)
at clojure.lang.RT.load(RT.java:419)
at clojure.lang.RT.load(RT.java:400)
at clojure.core$load$fn__4890.invoke(core.clj:5415)
at clojure.core$load.doInvoke(core.clj:5414)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5227)
at clojure.core$load_lib.doInvoke(core.clj:5264)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:603)
at clojure.core$load_libs.doInvoke(core.clj:5298)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:603)
at clojure.core$require.doInvoke(core.clj:5381)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at org.midjetest.core$loading__4784__auto__.invoke(core.clj:1)
at org.midjetest.core__init.load(Unknown Source)
at org.midjetest.core__init.<clinit>(Unknown Source)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:270)
at clojure.lang.RT.loadClassForName(RT.java:2056)
at clojure.lang.RT.load(RT.java:419)
at clojure.lang.RT.load(RT.java:400)
at clojure.core$load$fn__4890.invoke(core.clj:5415)
at clojure.core$load.doInvoke(core.clj:5414)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invoke(core.clj:5227)
at clojure.core$load_lib.doInvoke(core.clj:5264)
at clojure.lang.RestFn.applyTo(RestFn.java:142)
at clojure.core$apply.invoke(core.clj:603)
at clojure.core$load_libs.doInvoke(core.clj:5298)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.core$apply.invoke(core.clj:603)
at clojure.core$require.doInvoke(core.clj:5381)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at user$eval5.invoke(form-init9180276290836069038.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:6511)
at clojure.lang.Compiler.eval(Compiler.java:6500)
at clojure.lang.Compiler.eval(Compiler.java:6500)
at clojure.lang.Compiler.load(Compiler.java:6952)
at clojure.lang.Compiler.loadFile(Compiler.java:6912)
at clojure.main$load_script.invoke(main.clj:283)
at clojure.main$init_opt.invoke(main.clj:288)
at clojure.main$initialize.invoke(main.clj:316)
at clojure.main$null_opt.invoke(main.clj:349)
at clojure.main$main.doInvoke(main.clj:427)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:419)
at clojure.lang.AFn.applyToHelper(AFn.java:163)
at clojure.lang.Var.applyTo(Var.java:532)
at clojure.main.main(main.java:37)
Caused by: java.lang.NullPointerException
at java.util.concurrent.ConcurrentHashMap.hash(ConcurrentHashMap.java:333)
at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:988)
at clojure.lang.Namespace.find(Namespace.java:188)
at clojure.core$find_ns.invoke(core.clj:3659)
at clojure.core$the_ns.invoke(core.clj:3691)
at clojure.core$ns_name.invoke(core.clj:3698)
at midje.Bootstrap$bootstrap.invoke(Bootstrap.clj:8)
at midje.sweet__init.load(Unknown Source)
at midje.sweet__init.<clinit>(Unknown Source)
... 53 more
Exception in thread "Thread-4" clojure.lang.ExceptionInfo: Subprocess failed {:exit-code 1}
at clojure.core$ex_info.invoke(core.clj:4327)
at leiningen.core.eval$fn__3532.invoke(eval.clj:226)
at clojure.lang.MultiFn.invoke(MultiFn.java:231)
at leiningen.core.eval$eval_in_project.invoke(eval.clj:326)
at clojure.lang.AFn.applyToHelper(AFn.java:167)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:619)
at leiningen.repl$server$fn__7443.invoke(repl.clj:201)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.AFn.applyTo(AFn.java:151)
at clojure.core$apply.invoke(core.clj:617)
at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1788)
at clojure.lang.RestFn.invoke(RestFn.java:425)
at clojure.lang.AFn.applyToHelper(AFn.java:163)
at clojure.lang.RestFn.applyTo(RestFn.java:132)
at clojure.core$apply.invoke(core.clj:621)
at clojure.core$bound_fn_STAR_$fn__4102.doInvoke(core.clj:1810)
at clojure.lang.RestFn.invoke(RestFn.java:397)
at clojure.lang.AFn.run(AFn.java:24)
at java.lang.Thread.run(Thread.java:744)
The root problem here is that Bootstrap.clj is just not going to work when AOT-ed; it depends on some namespace being loaded before it is; however the static initializers for clojure AOTed classes are more or less equivalent to:
(binding [clojure.core/*ns* nil
clojure.core/*fn-loader* loader
clojure.core/*read-eval* true]
(my.class/load))
Since Bootstrap/bootstrap is called before midje.sweet defines it's own ns (https://github.com/marick/Midje/blob/master/src/midje/sweet.clj#L2), *ns*
stays null, and (ns-name *ns*)
crashes.
I don't think you can make this work, unless the bootstrap code for midje changes. I'd recommend putting your tests into separate files, and not aot-ing those.