Mercurial > lasercutter
diff src/clojure/contrib/mock.clj.rej @ 10:ef7dbbd6452c
added clojure source goodness
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 21 Aug 2010 06:25:44 -0400 |
parents | |
children |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/contrib/mock.clj.rej Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,569 @@ 1.4 +diff a/src/main/clojure/clojure/contrib/mock.clj b/src/main/clojure/clojure/contrib/mock.clj (rejected hunks) 1.5 +@@ -1,285 +1,282 @@ 1.6 +-;;; clojure.contrib.mock.clj: mocking/expectation framework for Clojure 1.7 +- 1.8 +-;; by Matt Clark 1.9 +- 1.10 +-;; Copyright (c) Matt Clark, 2009. All rights reserved. The use 1.11 +-;; and distribution terms for this software are covered by the Eclipse 1.12 +-;; Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php). 1.13 +-;; By using this software in any fashion, you are 1.14 +-;; agreeing to be bound by the terms of this license. You must not 1.15 +-;; remove this notice, or any other, from this software. 1.16 +-;;------------------------------------------------------------------------------ 1.17 +- 1.18 +-(comment 1.19 +- ;; This is a simple function mocking library I accidentally wrote as a side 1.20 +- ;; effect of trying to write an opengl library in clojure. This is loosely 1.21 +- ;; based on various ruby and java mocking frameworks I have used in the past 1.22 +- ;; such as mockito, easymock, and whatever rspec uses. 1.23 +- ;; 1.24 +- ;; expect uses bindings to wrap the functions that are being tested and 1.25 +- ;; then validates the invocation count at the end. The expect macro is the 1.26 +- ;; main entry point and it is given a vector of binding pairs. 1.27 +- ;; The first of each pair names the dependent function you want to override, 1.28 +- ;; while the second is a hashmap containing the mock description, usually 1.29 +- ;; created via the simple helper methods described below. 1.30 +- ;; 1.31 +- ;; Usage: 1.32 +- ;; 1.33 +- ;; there are one or more dependent functions: 1.34 +- 1.35 +- (defn dep-fn1 [] "time consuming calculation in 3rd party library") 1.36 +- (defn dep-fn2 [x] "function with undesirable side effects while testing") 1.37 +- 1.38 +- ;; then we have the code under test that calls these other functions: 1.39 +- 1.40 +- (defn my-code-under-test [] (dep-fn1) (dep-fn2 "a") (+ 2 2)) 1.41 +- 1.42 +- ;; to test this code, we simply surround it with an expect macro within 1.43 +- ;; the test: 1.44 +- 1.45 +- (expect [dep-fn1 (times 1) 1.46 +- dep-fn2 (times 1 (has-args [#(= "a" %)]))] 1.47 +- (my-code-under-test)) 1.48 +- 1.49 +- ;; When an expectation fails during execution of the function under test, 1.50 +- ;; an error condition function is called with the name of the function 1.51 +- ;; being mocked, the expected form and the actual value. These 1.52 +- ;; error functions can be overridden to allow easy integration into 1.53 +- ;; test frameworks such as test-is by reporting errors in the function 1.54 +- ;; overrides. 1.55 +- 1.56 +- ) ;; end comment 1.57 +- 1.58 +-(ns clojure.contrib.mock 1.59 +- ^{:author "Matt Clark", 1.60 +- :doc "function mocking/expectations for Clojure" } 1.61 +- (:use [clojure.contrib.seq :only (positions)] 1.62 +- [clojure.contrib.def :only (defmacro-)])) 1.63 +- 1.64 +- 1.65 +-;;------------------------------------------------------------------------------ 1.66 +-;; These are the error condition functions. Override them to integrate into 1.67 +-;; the test framework of your choice, or to simply customize error handling. 1.68 +- 1.69 +-(defn report-problem 1.70 +- {:dynamic true} 1.71 +- ([function expected actual] 1.72 +- (report-problem function expected actual "Expectation not met.")) 1.73 +- ([function expected actual message] 1.74 +- (prn (str message " Function name: " function 1.75 +- " expected: " expected " actual: " actual)))) 1.76 +- 1.77 +-(defn no-matching-function-signature 1.78 +- {:dynamic true} 1.79 +- [function expected actual] 1.80 +- (report-problem function expected actual 1.81 +- "No matching real function signature for given argument count.")) 1.82 +- 1.83 +-(defn unexpected-args 1.84 +- {:dynamic true} 1.85 +- [function expected actual i] 1.86 +- (report-problem function expected actual 1.87 +- (str "Argument " i " has an unexpected value for function."))) 1.88 +- 1.89 +-(defn incorrect-invocation-count 1.90 +- {:dynamic true} 1.91 +- [function expected actual] 1.92 +- (report-problem function expected actual "Unexpected invocation count.")) 1.93 +- 1.94 +- 1.95 +-;;------------------------------------------------------------------------------ 1.96 +-;; Internal Functions - ignore these 1.97 +- 1.98 +- 1.99 +-(defn- has-arg-count-match? 1.100 +- "Given the sequence of accepted argument vectors for a function, 1.101 +-returns true if at least one matches the given-count value." 1.102 +- [arg-lists given-count] 1.103 +- (some #(let [[ind] (positions #{'&} %)] 1.104 +- (if ind 1.105 +- (>= given-count ind) 1.106 +- (= (count %) given-count))) 1.107 +- arg-lists)) 1.108 +- 1.109 +- 1.110 +-(defn has-matching-signature? 1.111 +- "Calls no-matching-function-signature if no match is found for the given 1.112 +-function. If no argslist meta data is available for the function, it is 1.113 +-not called." 1.114 +- [fn-name args] 1.115 +- (let [arg-count (count args) 1.116 +- arg-lists (:arglists (meta (resolve fn-name)))] 1.117 +- (if (and arg-lists (not (has-arg-count-match? arg-lists arg-count))) 1.118 +- (no-matching-function-signature fn-name arg-lists args)))) 1.119 +- 1.120 +- 1.121 +-(defn make-arg-checker 1.122 +- "Creates the argument verifying function for a replaced dependency within 1.123 +-the expectation bound scope. These functions take the additional argument 1.124 +-of the name of the replaced function, then the rest of their args. It is 1.125 +-designed to be called from the mock function generated in the first argument 1.126 +-of the mock info object created by make-mock." 1.127 +- [arg-preds arg-pred-forms] 1.128 +- (let [sanitized-preds (map (fn [v] (if (fn? v) v #(= v %))) arg-preds)] 1.129 +- (fn [fn-name & args] 1.130 +- (every? true? 1.131 +- (map (fn [pred arg pred-form i] (if (pred arg) true 1.132 +- (unexpected-args fn-name pred-form arg i))) 1.133 +- sanitized-preds args arg-pred-forms (iterate inc 0)))))) 1.134 +- 1.135 +- 1.136 +-(defn make-count-checker 1.137 +- "creates the count checker that is invoked at the end of an expectation, after 1.138 +-the code under test has all been executed. The function returned takes the 1.139 +-name of the associated dependency and the invocation count as arguments." 1.140 +- [pred pred-form] 1.141 +- (let [pred-fn (if (integer? pred) #(= pred %) pred)] 1.142 +- (fn [fn-name v] (if (pred-fn v) true 1.143 +- (incorrect-invocation-count fn-name pred-form v))))) 1.144 +- 1.145 +-; Borrowed from clojure core. Remove if this ever becomes public there. 1.146 +-(defmacro- assert-args 1.147 +- [fnname & pairs] 1.148 +- `(do (when-not ~(first pairs) 1.149 +- (throw (IllegalArgumentException. 1.150 +- ~(str fnname " requires " (second pairs))))) 1.151 +- ~(let [more (nnext pairs)] 1.152 +- (when more 1.153 +- (list* `assert-args fnname more))))) 1.154 +- 1.155 +-(defn make-mock 1.156 +- "creates a vector containing the following information for the named function: 1.157 +-1. dependent function replacement - verifies signature, calls arg checker, 1.158 +-increases count, returns return value. 1.159 +-2. an atom containing the invocation count 1.160 +-3. the invocation count checker function 1.161 +-4. a symbol of the name of the function being replaced." 1.162 +- [fn-name expectation-hash] 1.163 +- (assert-args make-mock 1.164 +- (map? expectation-hash) "a map of expectations") 1.165 +- (let [arg-checker (or (expectation-hash :has-args) (fn [& args] true)) 1.166 +- count-atom (atom 0) 1.167 +- ret-fn (or 1.168 +- (expectation-hash :calls) 1.169 +- (fn [& args] (expectation-hash :returns)))] 1.170 +- [(fn [& args] 1.171 +- (has-matching-signature? fn-name args) 1.172 +- (apply arg-checker fn-name args) 1.173 +- (swap! count-atom inc) 1.174 +- (apply ret-fn args)) 1.175 +- count-atom 1.176 +- (or (expectation-hash :times) (fn [fn-name v] true)) 1.177 +- fn-name])) 1.178 +- 1.179 +- 1.180 +-(defn validate-counts 1.181 +- "given the sequence of all mock data for the expectation, simply calls the 1.182 +-count checker for each dependency." 1.183 +- [mock-data] (doseq [[mfn i checker fn-name] mock-data] (checker fn-name @i))) 1.184 +- 1.185 +-(defn ^{:private true} make-bindings [expect-bindings mock-data-sym] 1.186 +- `[~@(interleave (map #(first %) (partition 2 expect-bindings)) 1.187 +- (map (fn [i] `(nth (nth ~mock-data-sym ~i) 0)) 1.188 +- (range (quot (count expect-bindings) 2))))]) 1.189 +- 1.190 +- 1.191 +-;;------------------------------------------------------------------------------ 1.192 +-;; These are convenience functions to improve the readability and use of this 1.193 +-;; library. Useful in expressions such as: 1.194 +-;; (expect [dep-fn1 (times (more-than 1) (returns 15)) etc) 1.195 +- 1.196 +-(defn once [x] (= 1 x)) 1.197 +- 1.198 +-(defn never [x] (zero? x)) 1.199 +- 1.200 +-(defn more-than [x] #(< x %)) 1.201 +- 1.202 +-(defn less-than [x] #(> x %)) 1.203 +- 1.204 +-(defn between [x y] #(and (< x %) (> y %))) 1.205 +- 1.206 +- 1.207 +-;;------------------------------------------------------------------------------ 1.208 +-;; The following functions can be used to build up the expectation hash. 1.209 +- 1.210 +-(defn returns 1.211 +- "Creates or associates to an existing expectation hash the :returns key with 1.212 +-a value to be returned by the expectation after a successful invocation 1.213 +-matching its expected arguments (if applicable). 1.214 +-Usage: 1.215 +-(returns ret-value expectation-hash?)" 1.216 +- 1.217 +- ([val] (returns val {})) 1.218 +- ([val expectation-hash] (assoc expectation-hash :returns val))) 1.219 +- 1.220 +- 1.221 +-(defn calls 1.222 +- "Creates or associates to an existing expectation hash the :calls key with a 1.223 +-function that will be called with the given arguments. The return value from 1.224 +-this function will be returned returned by the expected function. If both this 1.225 +-and returns are specified, the return value of \"calls\" will have precedence. 1.226 +-Usage: 1.227 +-(calls some-fn expectation-hash?)" 1.228 +- 1.229 +- ([val] (calls val {})) 1.230 +- ([val expectation-hash] (assoc expectation-hash :calls val))) 1.231 +- 1.232 +- 1.233 +-(defmacro has-args 1.234 +- "Creates or associates to an existing expectation hash the :has-args key with 1.235 +-a value corresponding to a function that will either return true if its 1.236 +-argument expectations are met or throw an exception with the details of the 1.237 +-first failed argument it encounters. 1.238 +-Only specify as many predicates as you are interested in verifying. The rest 1.239 +-of the values are safely ignored. 1.240 +-Usage: 1.241 +-(has-args [arg-pred-1 arg-pred-2 ... arg-pred-n] expectation-hash?)" 1.242 +- 1.243 +- ([arg-pred-forms] `(has-args ~arg-pred-forms {})) 1.244 +- ([arg-pred-forms expect-hash-form] 1.245 +- (assert-args has-args 1.246 +- (vector? arg-pred-forms) "a vector of argument predicates") 1.247 +- `(assoc ~expect-hash-form :has-args 1.248 +- (make-arg-checker ~arg-pred-forms '~arg-pred-forms)))) 1.249 +- 1.250 +- 1.251 +-(defmacro times 1.252 +- "Creates or associates to an existing expectation hash the :times key with a 1.253 +-value corresponding to a predicate function which expects an integer value. 1.254 +-This function can either be specified as the first argument to times or can be 1.255 +-the result of calling times with an integer argument, in which case the 1.256 +-predicate will default to being an exact match. This predicate is called at 1.257 +-the end of an expect expression to validate that an expected dependency 1.258 +-function was called the expected number of times. 1.259 +-Usage: 1.260 +-(times n) 1.261 +-(times #(> n %)) 1.262 +-(times n expectation-hash)" 1.263 +- ([times-fn] `(times ~times-fn {})) 1.264 +- ([times-fn expectation-hash] 1.265 +- `(assoc ~expectation-hash :times (make-count-checker ~times-fn '~times-fn)))) 1.266 +- 1.267 +- 1.268 +-;------------------------------------------------------------------------------- 1.269 +-; The main expect macro. 1.270 +-(defmacro expect 1.271 +- "Use expect to redirect calls to dependent functions that are made within the 1.272 +-code under test. Instead of calling the functions that would normally be used, 1.273 +-temporary stubs are used, which can verify function parameters and call counts. 1.274 +-Return values can also be specified as needed. 1.275 +-Usage: 1.276 +-(expect [dep-fn (has-args [arg-pred1] (times n (returns x)))] 1.277 +- (function-under-test a b c))" 1.278 +- 1.279 +- [expect-bindings & body] 1.280 +- (assert-args expect 1.281 +- (vector? expect-bindings) "a vector of expectation bindings" 1.282 +- (even? (count expect-bindings)) 1.283 +- "an even number of forms in expectation bindings") 1.284 +- (let [mock-data (gensym "mock-data_")] 1.285 +- `(let [~mock-data (map (fn [args#] 1.286 +- (apply clojure.contrib.mock/make-mock args#)) 1.287 +- ~(cons 'list (map (fn [[n m]] (vector (list 'quote n) m)) 1.288 +- (partition 2 expect-bindings))))] 1.289 +- (binding ~(make-bindings expect-bindings mock-data) ~@body) 1.290 +- (clojure.contrib.mock/validate-counts ~mock-data) true))) 1.291 ++;;; clojure.contrib.mock.clj: mocking/expectation framework for Clojure 1.292 ++ 1.293 ++;; by Matt Clark 1.294 ++ 1.295 ++;; Copyright (c) Matt Clark, 2009. All rights reserved. The use and 1.296 ++;; distribution terms for this software are covered by the Eclipse Public 1.297 ++;; License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can 1.298 ++;; be found in the file epl-v10.html at the root of this distribution. By 1.299 ++;; using this software in any fashion, you are agreeing to be bound by the 1.300 ++;; terms of this license. You must not remove this notice, or any other 1.301 ++;; from this software. 1.302 ++;;------------------------------------------------------------------------------ 1.303 ++ 1.304 ++(comment 1.305 ++ ;; Mock is a function mocking utility loosely based on various ruby and java 1.306 ++ ;; mocking frameworks such as mockito, easymock, and rspec yet adapted to 1.307 ++ ;; fit the functional style of clojure. 1.308 ++ ;; 1.309 ++ ;; Mock uses bindings to wrap the functions that are being tested and 1.310 ++ ;; then validates the invocation count at the end. The expect macro is the 1.311 ++ ;; main entry point and it is given a vector of binding pairs. 1.312 ++ ;; The first of each pair names the dependent function you want to override 1.313 ++ ;; while the second is a hashmap containing the mock description, usually 1.314 ++ ;; created via the simple helper methods described below. 1.315 ++ ;; 1.316 ++ ;; Usage: 1.317 ++ ;; 1.318 ++ ;; there are one or more dependent functions: 1.319 ++ 1.320 ++ (defn dep-fn1 [] "time consuming calculation in 3rd party library") 1.321 ++ (defn dep-fn2 [x] "function with undesirable side effects while testing") 1.322 ++ 1.323 ++ ;; then we have the code under test that calls these other functions: 1.324 ++ 1.325 ++ (defn my-code-under-test [] (dep-fn1) (dep-fn2 "a") (+ 2 2)) 1.326 ++ 1.327 ++ ;; to test this code, we simply surround it with an expect macro within 1.328 ++ ;; the test: 1.329 ++ 1.330 ++ (expect [dep-fn1 (times 1) 1.331 ++ dep-fn2 (times 1 (has-args [#(= "a" %)]))] 1.332 ++ (my-code-under-test)) 1.333 ++ 1.334 ++ ;; When an expectation fails during execution of the function under test 1.335 ++ ;; an error condition function is called with the name of the function 1.336 ++ ;; being mocked, the expected form and the actual value. These 1.337 ++ ;; error functions can be overridden to allow easy integration into 1.338 ++ ;; test frameworks such as test-is by reporting errors in the function 1.339 ++ ;; overrides. 1.340 ++ 1.341 ++ ) ;; end comment 1.342 ++ 1.343 ++(ns clojure.contrib.mock 1.344 ++ ^{:author "Matt Clark" 1.345 ++ :doc "function mocking/expectations for Clojure" } 1.346 ++ (:use [clojure.contrib.seq :only (positions)] 1.347 ++ [clojure.contrib.def :only (defmacro-)])) 1.348 ++ 1.349 ++ 1.350 ++;;------------------------------------------------------------------------------ 1.351 ++;; These are the error condition functions. Override them to integrate into 1.352 ++;; the test framework of your choice, or to simply customize error handling. 1.353 ++ 1.354 ++(defn report-problem 1.355 ++ {:dynamic true} 1.356 ++ ([function expected actual] 1.357 ++ (report-problem function expected actual "Expectation not met.")) 1.358 ++ ([function expected actual message] 1.359 ++ (prn (str message " Function name: " function 1.360 ++ " expected: " expected " actual: " actual)))) 1.361 ++ 1.362 ++(defn no-matching-function-signature 1.363 ++ {:dynamic true} 1.364 ++ [function expected actual] 1.365 ++ (report-problem function expected actual 1.366 ++ "No matching real function signature for given argument count.")) 1.367 ++ 1.368 ++(defn unexpected-args 1.369 ++ {:dynamic true} 1.370 ++ [function expected actual i] 1.371 ++ (report-problem function expected actual 1.372 ++ (str "Argument " i " has an unexpected value for function."))) 1.373 ++ 1.374 ++(defn incorrect-invocation-count 1.375 ++ {:dynamic true} 1.376 ++ [function expected actual] 1.377 ++ (report-problem function expected actual "Unexpected invocation count.")) 1.378 ++ 1.379 ++ 1.380 ++;;------------------------------------------------------------------------------ 1.381 ++;; Internal Functions - ignore these 1.382 ++ 1.383 ++ 1.384 ++(defn- has-arg-count-match? 1.385 ++ "Given the sequence of accepted argument vectors for a function 1.386 ++returns true if at least one matches the given-count value." 1.387 ++ [arg-lists given-count] 1.388 ++ (some #(let [[ind] (positions #{'&} %)] 1.389 ++ (if ind 1.390 ++ (>= given-count ind) 1.391 ++ (= (count %) given-count))) 1.392 ++ arg-lists)) 1.393 ++ 1.394 ++ 1.395 ++(defn has-matching-signature? 1.396 ++ "Calls no-matching-function-signature if no match is found for the given 1.397 ++function. If no argslist meta data is available for the function, it is 1.398 ++not called." 1.399 ++ [fn-name args] 1.400 ++ (let [arg-count (count args) 1.401 ++ arg-lists (:arglists (meta (resolve fn-name)))] 1.402 ++ (if (and arg-lists (not (has-arg-count-match? arg-lists arg-count))) 1.403 ++ (no-matching-function-signature fn-name arg-lists args)))) 1.404 ++ 1.405 ++ 1.406 ++(defn make-arg-checker 1.407 ++ "Creates the argument verifying function for a replaced dependency within 1.408 ++the expectation bound scope. These functions take the additional argument 1.409 ++of the name of the replaced function, then the rest of their args. It is 1.410 ++designed to be called from the mock function generated in the first argument 1.411 ++of the mock info object created by make-mock." 1.412 ++ [arg-preds arg-pred-forms] 1.413 ++ (let [sanitized-preds (map (fn [v] (if (fn? v) v #(= v %))) arg-preds)] 1.414 ++ (fn [fn-name & args] 1.415 ++ (every? true? 1.416 ++ (map (fn [pred arg pred-form i] (if (pred arg) true 1.417 ++ (unexpected-args fn-name 1.418 ++ pred-form arg i))) 1.419 ++ sanitized-preds args arg-pred-forms (iterate inc 0)))))) 1.420 ++ 1.421 ++ 1.422 ++(defn make-count-checker 1.423 ++ "creates the count checker that is invoked at the end of an expectation, after 1.424 ++the code under test has all been executed. The function returned takes the 1.425 ++name of the associated dependency and the invocation count as arguments." 1.426 ++ [pred pred-form] 1.427 ++ (let [pred-fn (if (integer? pred) #(= pred %) pred)] 1.428 ++ (fn [fn-name v] (if (pred-fn v) true 1.429 ++ (incorrect-invocation-count fn-name pred-form v))))) 1.430 ++ 1.431 ++(defn make-mock 1.432 ++ "creates a vector containing the following information for the named function: 1.433 ++1. dependent function replacement - verifies signature, calls arg checker 1.434 ++increases count, returns return value. 1.435 ++2. an atom containing the invocation count 1.436 ++3. the invocation count checker function 1.437 ++4. a symbol of the name of the function being replaced." 1.438 ++ [fn-name expectation-hash] 1.439 ++ {:pre [(map? expectation-hash) 1.440 ++ (symbol? fn-name)]} 1.441 ++ (let [arg-checker (or (expectation-hash :has-args) (fn [& args] true)) 1.442 ++ count-atom (atom 0) 1.443 ++ ret-fn (or 1.444 ++ (expectation-hash :calls) 1.445 ++ (fn [& args] (expectation-hash :returns)))] 1.446 ++ [(fn [& args] 1.447 ++ (has-matching-signature? fn-name args) 1.448 ++ (apply arg-checker fn-name args) 1.449 ++ (swap! count-atom inc) 1.450 ++ (apply ret-fn args)) 1.451 ++ count-atom 1.452 ++ (or (expectation-hash :times) (fn [fn-name v] true)) 1.453 ++ fn-name])) 1.454 ++ 1.455 ++ 1.456 ++(defn validate-counts 1.457 ++ "given the sequence of all mock data for the expectation, simply calls the 1.458 ++count checker for each dependency." 1.459 ++ [mock-data] (doseq [[mfn i checker fn-name] mock-data] (checker fn-name @i))) 1.460 ++ 1.461 ++(defn- make-bindings [expect-bindings mock-data-sym] 1.462 ++ `[~@(interleave (map #(first %) (partition 2 expect-bindings)) 1.463 ++ (map (fn [i] `(nth (nth ~mock-data-sym ~i) 0)) 1.464 ++ (range (quot (count expect-bindings) 2))))]) 1.465 ++ 1.466 ++ 1.467 ++;;------------------------------------------------------------------------------ 1.468 ++;; These are convenience functions to improve the readability and use of this 1.469 ++;; library. Useful in expressions such as: 1.470 ++;; (expect [dep-fn1 (times (more-than 1) (returns 15)) etc) 1.471 ++ 1.472 ++;; best used in the times function 1.473 ++(defn once [x] (= 1 x)) 1.474 ++ 1.475 ++(defn never [x] (zero? x)) 1.476 ++ 1.477 ++(defn more-than [x] #(< x %)) 1.478 ++ 1.479 ++(defn less-than [x] #(> x %)) 1.480 ++ 1.481 ++(defn between [x y] #(and (< x %) (> y %))) 1.482 ++ 1.483 ++;;best used in the has-args function 1.484 ++(defn anything [x] true) 1.485 ++ 1.486 ++ 1.487 ++;;------------------------------------------------------------------------------ 1.488 ++;; The following functions can be used to build up the expectation hash. 1.489 ++ 1.490 ++(defn returns 1.491 ++ "Creates or associates to an existing expectation hash the :returns key with 1.492 ++a value to be returned by the expectation after a successful invocation 1.493 ++matching its expected arguments (if applicable). 1.494 ++Usage: 1.495 ++(returns ret-value expectation-hash?)" 1.496 ++ 1.497 ++ ([val] (returns val {})) 1.498 ++ ([val expectation-hash] 1.499 ++ {:pre [(map? expectation-hash)]} 1.500 ++ (assoc expectation-hash :returns val))) 1.501 ++ 1.502 ++ 1.503 ++(defn calls 1.504 ++ "Creates or associates to an existing expectation hash the :calls key with a 1.505 ++function that will be called with the given arguments. The return value from 1.506 ++this function will be returned by the expected function. If both this 1.507 ++and returns are specified, the return value of \"calls\" will have precedence. 1.508 ++Usage: 1.509 ++(calls some-fn expectation-hash?)" 1.510 ++ 1.511 ++ ([val] (calls val {})) 1.512 ++ ([val expectation-hash] 1.513 ++ {:pre [(map? expectation-hash)]} 1.514 ++ (assoc expectation-hash :calls val))) 1.515 ++ 1.516 ++ 1.517 ++(defmacro has-args 1.518 ++ "Creates or associates to an existing expectation hash the :has-args key with 1.519 ++a value corresponding to a function that will either return true if its 1.520 ++argument expectations are met or throw an exception with the details of the 1.521 ++first failed argument it encounters. 1.522 ++Only specify as many predicates as you are interested in verifying. The rest 1.523 ++of the values are safely ignored. 1.524 ++Usage: 1.525 ++(has-args [arg-pred-1 arg-pred-2 ... arg-pred-n] expectation-hash?)" 1.526 ++ 1.527 ++ ([arg-pred-forms] `(has-args ~arg-pred-forms {})) 1.528 ++ ([arg-pred-forms expectation-hash] 1.529 ++ {:pre [(vector? arg-pred-forms) 1.530 ++ (map? expectation-hash)]} 1.531 ++ `(assoc ~expectation-hash :has-args 1.532 ++ (make-arg-checker ~arg-pred-forms '~arg-pred-forms)))) 1.533 ++ 1.534 ++ 1.535 ++(defmacro times 1.536 ++ "Creates or associates to an existing expectation hash the :times key with a 1.537 ++value corresponding to a predicate function which expects an integer value. 1.538 ++Also, an integer can be specified, in which case the times will only be an 1.539 ++exact match. The times check is called at the end of an expect expression to 1.540 ++validate that an expected dependency function was called the expected 1.541 ++number of times. 1.542 ++Usage: 1.543 ++(times n) 1.544 ++(times #(> n %)) 1.545 ++(times n expectation-hash)" 1.546 ++ ([times-fn] `(times ~times-fn {})) 1.547 ++ ([times-fn expectation-hash] 1.548 ++ {:pre [(map? expectation-hash)]} 1.549 ++ `(assoc ~expectation-hash :times (make-count-checker ~times-fn '~times-fn)))) 1.550 ++ 1.551 ++ 1.552 ++;------------------------------------------------------------------------------- 1.553 ++; The main expect macro. 1.554 ++(defmacro expect 1.555 ++ "Use expect to redirect calls to dependent functions that are made within the 1.556 ++code under test. Instead of calling the functions that would normally be used 1.557 ++temporary stubs are used, which can verify function parameters and call counts. 1.558 ++Return values of overridden functions can also be specified as needed. 1.559 ++Usage: 1.560 ++(expect [dep-fn (has-args [arg-pred1] (times n (returns x)))] 1.561 ++ (function-under-test a b c))" 1.562 ++ 1.563 ++ [expect-bindings & body] 1.564 ++ {:pre [(vector? expect-bindings) 1.565 ++ (even? (count expect-bindings))]} 1.566 ++ (let [mock-data (gensym "mock-data_")] 1.567 ++ `(let [~mock-data (map (fn [args#] 1.568 ++ (apply clojure.contrib.mock/make-mock args#)) 1.569 ++ ~(cons 'list (map (fn [[n m]] (vector (list 'quote n) m)) 1.570 ++ (partition 2 expect-bindings))))] 1.571 ++ (binding ~(make-bindings expect-bindings mock-data) ~@body) 1.572 ++ (clojure.contrib.mock/validate-counts ~mock-data) true)))