Skip to content

Commit c538cf9

Browse files
committed
Fixes #4; adds between; fixes in (hash map); prep for 1.1.2
1 parent 7a0ea75 commit c538cf9

File tree

6 files changed

+202
-44
lines changed

6 files changed

+202
-44
lines changed

CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
# Version 1.1.2 -- 2019-12-07
2+
3+
* Adds `between` and `between'` for inclusive and exclusive range checking.
4+
* Fix `in` with a hash map to correctly detect failing cases.
5+
* Add a first round of tests (finally!). Verified support for Clojure 1.8 (without Spec expectations). Verified full support for Clojure 1.9 and 1.10.1.
6+
* Clean up `:require` .. `:refer` in README to list all public symbols. #4
7+
* Fixes links in README. PR #3 (@marekjeszka)
8+
* Add/improve docstrings. Add `^:no-doc` metadata for when cljdoc.org supports it.
9+
110
# Version 1.1.1 -- 2019-01-14
211

312
* An expectation can now use a qualified keyword spec to test conformance of the actual value. Failures are reported with the spec explanation. #2

README.md

+30-15
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ A `clojure.test`-compatible version of the [classic Expectations testing library
44

55
## Where?
66

7-
[![Clojars Project](https://clojars.org/expectations/clojure-test/latest-version.svg)](https://clojars.org/expectations/clojure-test)
7+
[![Clojars Project](https://clojars.org/expectations/clojure-test/latest-version.svg)](https://clojars.org/expectations/clojure-test) [![cljdoc badge](https://cljdoc.org/badge/expectations/clojure-test)](https://cljdoc.org/d/expectations/clojure-test/CURRENT)
88

99
Try it out:
1010

@@ -20,18 +20,25 @@ macro. This library has no dependencies, other than `clojure.test` itself, and
2020
should be compatible with all existing `clojure.test`-based tooling in editors
2121
and command-line tools.
2222

23+
Works with Clojure 1.8 and later. Spec expectations are only available on
24+
Clojure 1.9 and later.
25+
2326
You can either use `deftest` from `clojure.test`, or `defexpect` from
2427
this library to wrap your tests.
2528

2629
```clojure
2730
(ns my.cool.project-test
28-
(:require [clojure.test :refer [deftest is]]
29-
[expectations.clojure.test :refer :all]))
31+
(:require [clojure.spec.alpha :as s]
32+
[clojure.test :refer [deftest is]]
33+
[expectations.clojure.test
34+
:refer [defexpect expect expecting
35+
approximately between between' functionally
36+
side-effects]]))
3037

3138
;; mix'n'match libraries:
3239

3340
(deftest mixed
34-
(is 2 (+ 1 1))
41+
(is (= 2 (+ 1 1)))
3542
(expect even? (+ 1 1)))
3643

3744
;; simple equality tests:
@@ -61,9 +68,8 @@ this library to wrap your tests.
6168

6269
(defexpect named String (name :foo))
6370

64-
;; the expected outcome can be a Spec:
71+
;; the expected outcome can be a Spec (require Clojure 1.9 or later):
6572

66-
;; assumes (require '[clojure.spec.alpha :as s])
6773
(s/def ::value (s/and pos-int? #(< % 100)))
6874
(defexpect small-value
6975
(expect ::value (* 13 4)))
@@ -108,9 +114,9 @@ user=> (defexpect inequality (* 2 21) (+ 13 13 13))
108114
#'user/inequality
109115
user=> (inequality)
110116

111-
FAIL in (inequality) (.../README.md:67)
117+
FAIL in (inequality) (.../README.md:113)
112118
expected: (=? (* 2 21) (+ 13 13 13))
113-
actual: 39
119+
actual: (not (=? 42 39))
114120
nil
115121
```
116122

@@ -124,7 +130,7 @@ user=> (defexpect indivisible odd? (+ 1 1))
124130
#'user/indivisible
125131
user=> (indivisible)
126132

127-
FAIL in (indivisible) (.../README.md:83)
133+
FAIL in (indivisible) (.../README.md:129)
128134
expected: (=? odd? (+ 1 1))
129135
actual: (not (odd? 2))
130136
nil
@@ -164,11 +170,11 @@ well-maintained, stable plugins for Leiningen and Boot, as well as an Emacs mode
164170
the reality is that Clojure tooling is constantly evolving and most of those
165171
tools -- such as the excellent [CIDER](https://cider.readthedocs.io/en/latest/),
166172
[Cursive](https://cursive-ide.com/),
167-
and the more recent [ProtoREPL](https://atom.io/packages/proto-repl)
168-
and [Chlorine](https://atom.io/packages/chlorine) (both for Atom) --
173+
[Chlorine](https://atom.io/packages/chlorine) (for Atom),
174+
and [Cognitect's `test-runner`](https://github.com/cognitect-labs/test-runner) --
169175
are going to focus on Clojure's built-in testing library first.
170176
Support for the original form of Expectations, using unnamed tests, is
171-
non-existent in Cursive, and can be problematic in other editors.
177+
non-existent in Cursive, and can be problematic in other editors and tooling.
172178

173179
A whole ecosystem
174180
of tooling has grown up around `clojure.test` and to take advantage of
@@ -195,17 +201,26 @@ to be aware of:
195201
* Because of that, tests run when you decide, not at JVM shutdown (which is the default with Expectations).
196202
* If you have [Paul Stadig's Humane Test Output](https://github.com/pjstadig/humane-test-output) on your classpath, it will be activated and failures reported by `=?` will be compatible with it, providing better reporting.
197203
* Instead of the `in-context`, `before-run`, `after-run` machinery of Expectations, you can just use `clojure.test`'s fixtures machinery (`use-fixtures`).
198-
* Instead of Expectations' concept of "focused" test, you can use metadata on tests and tell your test runner to "select" tests as needed (e.g., Leiningen's "test selectors", Boot's "filters").
204+
* Instead of Expectations' concept of "focused" test, you can use metadata on tests and tell your test runner to "select" tests as needed (e.g., Leiningen's "test selectors", Boot's "filters", and `test-runner`'s `-i`/`-e` options).
199205
* `freeze-time` and `redef-state` are not (yet) implemented.
200206
* The undocumented `CustomPred` protocol is not implemented -- you can use plain `is` and extend `clojure.test`'s `assert-expr` multimethod if you need that level of control.
201207

202208
## Test & Development
203209

204-
To test, run `clj -A:test:runner`.
210+
To test, run `clj -A:test:runner` (tests against Clojure 1.8).
211+
212+
Multi-version testing:
213+
214+
```
215+
for v in 1.8 1.9 1.10
216+
do
217+
clojure -A:test:runner:$v
218+
done
219+
```
205220

206221
## TODO
207222

208-
Add tests(!) and more examples.
223+
Add proper documentation for cljdoc.org.
209224

210225
## License & Copyright
211226

deps.edn

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
1-
{:aliases
2-
{:test {:extra-paths ["test"]}
1+
{:deps {org.clojure/clojure {:mvn/version "1.8.0"}}
2+
:aliases
3+
{:1.8 {:override-deps {org.clojure/clojure {:mvn/version "1.8.0"}}}
4+
:1.9 {:override-deps {org.clojure/clojure {:mvn/version "1.9.0"}}}
5+
:1.10 {:override-deps {org.clojure/clojure {:mvn/version "1.10.1"}}}
6+
:test {:extra-paths ["test"]}
37
:humane {:extra-deps {pjstadig/humane-test-output {:mvn/version "RELEASE"}}}
48
:runner
59
{:extra-deps {com.cognitect/test-runner

pom.xml

+2-10
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
<modelVersion>4.0.0</modelVersion>
44
<groupId>expectations</groupId>
55
<artifactId>clojure-test</artifactId>
6-
<version>1.1.1</version>
6+
<version>1.1.2</version>
77
<name>exp-clojure-test</name>
8-
98
<description>A clojure.test-compatible version of the classic Expectations testing library.</description>
109
<url>https://github.com/clojure-expectations/clojure-test</url>
1110
<licenses>
@@ -14,32 +13,27 @@
1413
<url>http://www.eclipse.org/legal/epl-v10.html</url>
1514
</license>
1615
</licenses>
17-
1816
<developers>
1917
<developer>
2018
<name>Sean Corfield</name>
2119
</developer>
2220
</developers>
23-
2421
<scm>
2522
<connection>scm:git:[email protected]:clojure-expectations/clojure-test.git</connection>
2623
<developerConnection>scm:git:[email protected]:clojure-expectations/clojure-test.git</developerConnection>
2724
<url>https://github.com/clojure-expectations/clojure-test</url>
2825
<tag>5f0c9139245fbd320cbe787fcd76ef96007b29a4</tag>
2926
</scm>
30-
3127
<dependencies>
3228
<dependency>
3329
<groupId>org.clojure</groupId>
3430
<artifactId>clojure</artifactId>
35-
<version>1.10.0</version>
31+
<version>1.8.0</version>
3632
</dependency>
3733
</dependencies>
38-
3934
<build>
4035
<sourceDirectory>src</sourceDirectory>
4136
</build>
42-
4337
<repositories>
4438
<repository>
4539
<id>clojars</id>
@@ -50,13 +44,11 @@
5044
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
5145
</repository>
5246
</repositories>
53-
5447
<distributionManagement>
5548
<repository>
5649
<id>clojars</id>
5750
<name>Clojars repository</name>
5851
<url>https://clojars.org/repo</url>
5952
</repository>
6053
</distributionManagement>
61-
6254
</project>

src/expectations/clojure/test.clj

+56-16
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@
2525
(defn- bad-usage [s]
2626
`(throw (IllegalArgumentException.
2727
(str ~s " should only be used inside expect"))))
28-
(defmacro in [& _] (bad-usage "in"))
29-
(defmacro from-each [& _] (bad-usage "from-each"))
30-
(defmacro more-of [& _] (bad-usage "more-of"))
31-
(defmacro more-> [& _] (bad-usage "more->"))
32-
(defmacro more [& _] (bad-usage "more"))
28+
(defmacro ^:no-doc in [& _] (bad-usage "in"))
29+
(defmacro ^:no-doc from-each [& _] (bad-usage "from-each"))
30+
(defmacro ^:no-doc more-of [& _] (bad-usage "more-of"))
31+
(defmacro ^:no-doc more-> [& _] (bad-usage "more->"))
32+
(defmacro ^:no-doc more [& _] (bad-usage "more"))
3333

34-
(defn spec? [e]
34+
(defn ^:no-doc spec? [e]
3535
(and (keyword? e)
3636
(try
3737
(require 'clojure.spec.alpha)
@@ -78,15 +78,15 @@
7878
(list '~'not (list '~'=? e# a#)))}))
7979
r#)))
8080

81-
(defmacro ?
81+
(defmacro ^:no-doc ?
8282
"Wrapper for forms that might throw an exception so exception class names
8383
can be used as predicates. This is only needed for more-> so that you can
8484
thread exceptions into code that can parse information out of them, to be
8585
used with various expect predicates."
8686
[form]
8787
`(try ~form (catch Throwable t# t#)))
8888

89-
(defn all-report
89+
(defn ^:no-doc all-report
9090
"Given an atom in which to accumulate results, return a function that
9191
can be used in place of clojure.test/do-report, which simply remembers
9292
all the reported results.
@@ -97,7 +97,28 @@
9797
(swap! store update (:type m) (fnil conj []) m)))
9898

9999
(defmacro expect
100-
"Translate Expectations DSL to clojure.test language."
100+
"Translate Expectations DSL to clojure.test language.
101+
102+
These are approximate translations for the most basic forms:
103+
104+
`(expect actual)` => `(is actual)`
105+
`(expect expected actual)` => `(is (= expected actual))`
106+
`(expect predicate actual)` => `(is (predicate actual))`
107+
`(expect regex actual)` => `(is (re-find regex actual))`
108+
`(expect ClassName actual)` => `(is (instance? ClassName actual))`
109+
`(expect ExceptionType actual)` => `(is (thrown? ExceptionType actual))`
110+
`(expect spec actual)` => `(is (s/valid? spec actual))`
111+
112+
In addition, `actual` can be `(from-each [x coll] (computation-of x))`
113+
or `(in set-of-results)` or `(in larger-hash-map)`.
114+
115+
Also, `expect` can be one of `(more predicate1 .. predicateN)`,
116+
`(more-> exp1 expr1 .. expN exprN)` where `actual` is threaded through
117+
each expression `exprX` and checked with the expected value `expX`,
118+
or `(more-of binding exp1 val1 .. expN valN)` where `actual` is
119+
destructured using the `binding` and then each expected value `expX`
120+
is used to check each `valX` -- expressions based on symbols in the
121+
`binding`."
101122
([a] `(t/is ~a))
102123
([e a] `(expect ~e ~a true ~e))
103124
([e a ex?] `(expect ~e ~a ~ex? ~e))
@@ -120,8 +141,7 @@
120141
(let [form `(~'expect ~e ~a)]
121142
`(let [a# ~(second a)]
122143
(cond (or (sequential? a#) (set? a#))
123-
(let [report# t/do-report
124-
all-reports# (atom nil)]
144+
(let [all-reports# (atom nil)]
125145
(with-redefs [t/do-report (all-report all-reports#)]
126146
(doseq [~'x a#]
127147
;; TODO: really want x evaluated here!
@@ -135,7 +155,7 @@
135155
(doseq [r# (:fail @all-reports#)] (t/do-report r#)))))
136156
(map? a#)
137157
(let [e# ~e]
138-
(expect e# (select-keys e# (keys a#)) ~ex? ~form))
158+
(expect e# (select-keys a# (keys e#)) ~ex? ~form))
139159
:else
140160
(throw (IllegalArgumentException. "'in' requires map or sequence")))))
141161

@@ -195,8 +215,8 @@
195215
"Given a name (a symbol that may include metadata) and a test body,
196216
produce a standard 'clojure.test' test var (using 'deftest').
197217
198-
(defexpect name expected actual) is a special case shorthand for
199-
(defexpect name (expect expected actual)) provided as an easy way to migrate
218+
`(defexpect name expected actual)` is a special case shorthand for
219+
`(defexpect name (expect expected actual))` provided as an easy way to migrate
200220
legacy Expectation tests to the 'clojure.test' compatibility version."
201221
[n & body]
202222
(if (and (>= 2 (count body))
@@ -205,12 +225,20 @@
205225
`(t/deftest ~n ~@body)))
206226

207227
(defmacro expecting
208-
"The Expectations version of clojure.test/testing."
228+
"The Expectations version of `clojure.test/testing`."
209229
[string & body]
210230
`(t/testing ~string ~@body))
211231

212232
;; DSL functions copied from Expectations:
213-
(defmacro side-effects [fn-vec & forms]
233+
(defmacro side-effects
234+
"Given a vector of functions to track calls to, execute the body.
235+
236+
Returns a vector of each set of arguments used in calls to those
237+
functions. The specified functions will not actually be called:
238+
only their arguments will be tracked, and the tracking versions of
239+
those functions will not return useful values (so they should be
240+
purely side-effecting functions, whose results are not used!)."
241+
[fn-vec & forms]
214242
(when-not (vector? fn-vec)
215243
(throw (IllegalArgumentException.
216244
"side-effects requires a vector as its first argument")))
@@ -227,6 +255,18 @@
227255
([^double v ^double d]
228256
(fn [x] (<= (- v (Math/abs d)) x (+ v (Math/abs d))))))
229257

258+
(defn between
259+
"Given a pair of (numeric) values, return a predicate that expects its
260+
argument to be be those values or between them -- inclusively."
261+
[a b]
262+
(fn [x] (<= a x b)))
263+
264+
(defn between'
265+
"Given a pair of (numeric) values, return a predicate that expects its
266+
argument to be (strictly) between those values -- exclusively."
267+
[a b]
268+
(fn [x] (< a x b)))
269+
230270
(defn functionally
231271
"Given a pair of functions, return a custom predicate that checks that they
232272
return the same result when applied to a value. May optionally accept a

0 commit comments

Comments
 (0)