Spec {{instrument}} does not work on protocol methods. Invalid arguments will be accepted silently with no error. Protocol vars are included in the return value of {{(instrument)}}.
Steps to reproduce
`
(require
'[clojure.spec :as s]
'[clojure.spec.test :as test])
(defprotocol P
(method [this arg]))
(defrecord R []
P
(method [this arg]
(str "R.method called with " (pr-str arg))))
(s/fdef method
:args (s/cat :this any?
:arg number?))
(defn wrapped [this arg]
(method this arg))
(s/fdef wrapped
:args (s/cat :this any?
:arg number?))
(test/instrument)
(println (method (->R) "not a number"))
(println (wrapped (->R) "not a number"))
`
This code produces the output:
R.method called with "not a number"
clojure.lang.ExceptionInfo: Call to #'user/wrapped did not conform to spec:
In: [1] val: "not a number" fails at: [:args :arg] predicate: number?
...
Possible resolutions
- Add support to {{instrument}} for protocol methods
- Document that {{instrument}} does not work on protocol methods, do not return protocol method Vars from {{(instrument)}}, throw exception if protocol method Vars are included in the symbols passed to {{(instrument syms)}}
See also
CLJ-1941 describes a different case where {{instrument}} does not work. This issue was identified in a (link: http://dev.clojure.org/jira/browse/CLJ-1941?focusedCommentId=43084&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-43084 text: comment).
Workarounds
This issue can be avoided by wrapping protocol methods in normal functions and spec'ing the functions. This is already common practice.