Skip to content

Commit 466f343

Browse files
author
dnolen
committed
copy over unstrument/instrument wip
1 parent 48b83d9 commit 466f343

2 files changed

Lines changed: 85 additions & 0 deletions

File tree

src/main/cljs/cljs/spec/test.cljc

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,70 @@
3535
(when raw# (set! ~s raw#))
3636
'~(:name v)))))
3737

38+
(defmacro instrument
39+
"Instruments the vars named by sym-or-syms, a symbol or collection
40+
of symbols, or all instrumentable vars if sym-or-syms is not
41+
specified.
42+
43+
If a var has an :args fn-spec, sets the var's root binding to a
44+
fn that checks arg conformance (throwing an exception on failure)
45+
before delegating to the original fn.
46+
47+
The opts map can be used to override registered specs, and/or to
48+
replace fn implementations entirely. Opts for symbols not included
49+
in sym-or-syms are ignored. This facilitates sharing a common
50+
options map across many different calls to instrument.
51+
52+
The opts map may have the following keys:
53+
54+
:spec a map from var-name symbols to override specs
55+
:stub a set of var-name symbols to be replaced by stubs
56+
:gen a map from spec names to generator overrides
57+
:replace a map from var-name symbols to replacement fns
58+
59+
:spec overrides registered fn-specs with specs your provide. Use
60+
:spec overrides to provide specs for libraries that do not have
61+
them, or to constrain your own use of a fn to a subset of its
62+
spec'ed contract.
63+
64+
:stub replaces a fn with a stub that checks :args, then uses the
65+
:ret spec to generate a return value.
66+
67+
:gen overrides are used only for :stub generation.
68+
69+
:replace replaces a fn with a fn that checks args conformance, then
70+
invokes the fn you provide, enabling arbitrary stubbing and mocking.
71+
72+
:spec can be used in combination with :stub or :replace.
73+
74+
Returns a collection of syms naming the vars instrumented."
75+
([]
76+
`(instrument (instrumentable-syms)))
77+
([sym-or-syms]
78+
`(instrument ~sym-or-syms nil))
79+
([sym-or-syms opts]
80+
`(into
81+
[]
82+
(comp (filter (instrumentable-syms opts))
83+
(distinct)
84+
(map #(instrument-1* % opts))
85+
(remove nil?))
86+
(collectionize sym-or-syms))))
87+
88+
(defmacro unstrument
89+
"Undoes instrument on the vars named by sym-or-syms, specified
90+
as in instrument. With no args, unstruments all instrumented vars.
91+
Returns a collection of syms naming the vars unstrumented."
92+
([]
93+
`(unstrument (map ->sym (keys @instrumented-vars))))
94+
([sym-or-syms]
95+
`(into
96+
[]
97+
(comp (filter symbol?)
98+
(map unstrument-1*)
99+
(remove nil?))
100+
(collectionize sym-or-syms))))
101+
38102
(defmacro run-tests
39103
"Like run-all-tests, but scoped to specific namespaces, or to
40104
*ns* if no ns-sym are specified."

src/main/cljs/cljs/spec/test.cljs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,27 @@
138138
(when (= wrapped current)
139139
raw)))))
140140

141+
(defn- fn-spec-name?
142+
[s]
143+
(symbol? s))
144+
145+
(defn- collectionize
146+
[x]
147+
(if (symbol? x)
148+
(list x)
149+
x))
150+
151+
(defn instrumentable-syms
152+
"Given an opts map as per instrument, returns the set of syms
153+
that can be instrumented."
154+
([] (instrumentable-syms nil))
155+
([opts]
156+
(assert (every? ident? (keys (:gen opts))) "instrument :gen expects ident keys")
157+
(reduce into #{} [(filter fn-spec-name? (keys (s/registry)))
158+
(keys (:spec opts))
159+
(:stub opts)
160+
(keys (:replace opts))])))
161+
141162
;; wrap and unwrap spec failure data in an exception so that
142163
;; quick-check will treat it as a failure.
143164
(defn- wrap-failing

0 commit comments

Comments
 (0)