eftest icon indicating copy to clipboard operation
eftest copied to clipboard

Fix NPE when `pretty/report` called outside test

Open ryfow opened this issue 7 years ago • 4 comments

report can be run from code fixtures which caused pretty/testing-vars-str to throw a NullPointerException because testing-vars is nil inside fixtures.

ryfow avatar Jan 30 '18 23:01 ryfow

Can you provide an example of what you mean?

weavejester avatar Jan 30 '18 23:01 weavejester

In a project I maintain, I do some cleanup work in a fixture. If there's a problem, I call report with a specific file/line based on my stack because the file/line of the cleanup job isn't really that interesting.

I can't give you my project, but here's an example of the sort of think I'm doing:

(ns eftest.fixture-fail
  (:require [clojure.test :refer :all]))

(defn failing-fixture [f]
  (f)
  (clojure.test/report  {:type :fail :message "This fixture noticed a problem"
                         :file "file_name.clj"
                         :line 10}))

(use-fixtures :each failing-fixture)

(deftest foo
  (is (= 1 1)))

If I run this with lein test, I get the following:

FAIL in clojure.lang.PersistentList$EmptyList@1 (file_name.clj:10)
This fixture noticed a problem
expected: nil
  actual: nil

If I run it with lein-eftest, I get:

% lein eftest
WARNING: humane-test-output not activated because clojure is version 1.7.0

Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.NullPointerException, compiling:(/private/var/folders/2q/tk7cywk93217_d4pxn_5kft40000gn/T/form-init4376671560466612395.clj:1:125)
        at clojure.lang.Compiler.load(Compiler.java:7239)
        at clojure.lang.Compiler.loadFile(Compiler.java:7165)
        at clojure.main$load_script.invoke(main.clj:275)
        at clojure.main$init_opt.invoke(main.clj:280)
        at clojure.main$initialize.invoke(main.clj:308)
        at clojure.main$null_opt.invoke(main.clj:343)
        at clojure.main$main.doInvoke(main.clj:421)
        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.util.concurrent.ExecutionException: java.lang.NullPointerException
        at java.util.concurrent.FutureTask.report(FutureTask.java:122)
        at java.util.concurrent.FutureTask.get(FutureTask.java:192)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at clojure.lang.Reflector.invokeMatchingMethod(Reflector.java:93)
        at clojure.lang.Reflector.invokeNoArgInstanceMember(Reflector.java:313)
        at eftest.runner$run_in_parallel$fn__2460.invoke(runner.clj:49)
        at clojure.core$map$fn__4553.invoke(core.clj:2622)
        at clojure.lang.LazySeq.sval(LazySeq.java:40)
        at clojure.lang.LazySeq.seq(LazySeq.java:49)
        at clojure.lang.RT.seq(RT.java:507)
        at clojure.core$seq__4128.invoke(core.clj:137)
        at clojure.core$dorun.invoke(core.clj:3009)
        at eftest.runner$run_in_parallel.invoke(runner.clj:46)
        at eftest.runner$test_vars$fn__2475.invoke(runner.clj:75)
        at clojure.test$default_fixture.invoke(test.clj:674)
        at eftest.runner$test_vars.invoke(runner.clj:70)
        at eftest.runner$test_ns$fn__2490$fn__2491.invoke(runner.clj:83)
        at clojure.core$with_redefs_fn.invoke(core.clj:7209)
        at eftest.runner$test_ns$fn__2490.invoke(runner.clj:83)
        at eftest.runner$test_ns.invoke(runner.clj:83)
        at eftest.runner$test_all$fn__2498.invoke(runner.clj:90)
        at clojure.core$map$fn__4553.invoke(core.clj:2624)
        at clojure.lang.LazySeq.sval(LazySeq.java:40)
        at clojure.lang.LazySeq.seq(LazySeq.java:49)
        at clojure.lang.Cons.next(Cons.java:39)
        at clojure.lang.RT.boundedLength(RT.java:1735)
        at clojure.lang.RestFn.applyTo(RestFn.java:130)
        at clojure.core$apply.invoke(core.clj:632)
        at eftest.runner$test_all.invoke(runner.clj:91)
        at eftest.runner$run_tests.invoke(runner.clj:148)
        at user$eval2617$fn__2699.invoke(form-init4376671560466612395.clj:1)
        at user$eval2617$fn__2669.invoke(form-init4376671560466612395.clj:1)
        at user$eval2617.invoke(form-init4376671560466612395.clj:1)
        at clojure.lang.Compiler.eval(Compiler.java:6782)
        at clojure.lang.Compiler.eval(Compiler.java:6772)
        at clojure.lang.Compiler.load(Compiler.java:7227)
        ... 11 more
Caused by: java.lang.NullPointerException
        at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
        at clojure.lang.Namespace.find(Namespace.java:188)
        at clojure.core$find_ns.invoke(core.clj:3976)
        at clojure.core$the_ns.invoke(core.clj:4008)
        at clojure.core$ns_name.invoke(core.clj:4015)
        at eftest.report.pretty$testing_vars_str.invoke(pretty.clj:35)
        at eftest.report.pretty$eval2316$fn__2318.invoke(pretty.clj:109)
        at clojure.lang.MultiFn.invoke(MultiFn.java:229)
        at eftest.report.progress$eval2407$fn__2408$fn__2409.invoke(progress.clj:47)
        at eftest.report.progress$eval2407$fn__2408.invoke(progress.clj:47)
        at clojure.lang.MultiFn.invoke(MultiFn.java:229)
        at eftest.fixture_fail$failing_fixture.invoke(fixture_fail.clj:6)
        at clojure.test$compose_fixtures$fn__7664$fn__7665.invoke(test.clj:681)
        at clojure.test$default_fixture.invoke(test.clj:674)
        at clojure.test$compose_fixtures$fn__7664.invoke(test.clj:681)
        at eftest.runner$test_vars$fn__2467.invoke(runner.clj:62)
        at eftest.runner$wrap_test_with_timer$fn__2451.invoke(runner.clj:30)
        at clojure.lang.AFn.applyToHelper(AFn.java:154)
        at clojure.lang.AFn.applyTo(AFn.java:144)
        at clojure.core$apply.invoke(core.clj:630)
        at clojure.core$with_bindings_STAR_.doInvoke(core.clj:1868)
        at clojure.lang.RestFn.applyTo(RestFn.java:142)
        at clojure.core$apply.invoke(core.clj:634)
        at clojure.core$bound_fn_STAR_$fn__4439.doInvoke(core.clj:1890)
        at clojure.lang.RestFn.invoke(RestFn.java:408)
        at eftest.runner$test_vars$fn__2475$fn__2476$fn__2477.invoke(runner.clj:75)
        at clojure.lang.AFn.run(AFn.java:22)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)
Tests failed.

ryfow avatar Jan 31 '18 00:01 ryfow

Should report be used for this? The documentation for clojure.test explicitly says that:

the vars being tested will be a list in "*testing-vars*"

weavejester avatar Jan 31 '18 00:01 weavejester

I guess you could argue that. In my case, I have a function in my test code that checks status codes and calls report if it sees something fishy so I don't have to have status-checking code everywhere. That function gets called from fixtures during cleanup and sometimes something fishy crops up during cleanup.

I could wrap my (report) calls with a *testing-vars* but it seems nicer if eftest would use the information it has to generate a message.

I updated the test to set *testing-vars* to [] instead of nil because that's what's actually happening in real life.

ryfow avatar Jan 31 '18 00:01 ryfow