I have an assertion that checks key correctness at compile time:
(defn assert-keys [check-map valid-keys]
(let [k (set (keys check-map))]
(when-not (set/subset? k valid-keys)
(throw (ex-info "Function call contains invalid key." {:submitted-keys k
:valid-keys valid-keys})))))
It is invoked in a macro:
(defmacro with-hooks [{:keys [read write] :as options} & body]
(assert-keys options #{:read :write})
`(binding [*read-hook* (or ~read *read-hook*)
*write-hook* (or ~write *write-hook*)]
~@body))
In this case it will check that the options map may contain the keys :read
and :write
, and nothing more.
The thing is, I'd like to write a test for this. The code will cause a compiler error on macro expand if there's an invalid key. Is there any way of catching this error in a test?
This is the solution I found. Create a macro for testing:
(defmacro catch-assert [body]
(try
(eval body)
0
(catch clojure.lang.Compiler$CompilerException e
(if (re-find #"Function call contains invalid key"
(str e))
1
-1))
(catch Exception _e
-1)))
It returns: 0, call didn't produce exception. 1, compiler exception being tested for. -1, other exceptions.
Then I call in my test:
(deftest valid-keys
(testing "Valid hook keys"
(is (= 0 (catch-assert
(with-hooks {:read ()
:write ()})))))
(testing "Invalid hook key"
(is (= 1 (catch-assert
(with-hooks {:rea ()}))))))