Liking cljdoc? Tell your friends :D

license codecov build deploy clojars cljdoc

equalizer

Clojure(Script) library for data-driven tests.

Quick Start Guide

Add the following dependency in your project:

;; project.clj or build.boot
[equalizer "RELEASE"]

;; deps.edn
{:deps {equalizer {:mvn/version "RELEASE"}}}

Examples

Test case

(ns awesome.app-test
  "Simple example."
  (:require
    [clojure.test :refer :all]
    #?(:clj  [equalizer.core :as eq]
       :cljs [equalizer.core :as eq :include-macros true])
    [awesome.app :as sut]))

;; old way
(deftest test-old-way
  (testing "should return a created user"
    (let [new-user {:username "john", :email "john@doe.com", :password "secret"}
          response (sut/http-post new-user)
          status   (:status response)
          user     (get-in response [:body :data])
          user-id  (:id user)
          email    (:email user)]
      (is (= 201 status))
      (is (uuid? user-id))
      (is (some? (re-find #".+@.+\.com" email))))))


;; new way
(deftest test-new-way
  (testing "should return a created user"
    (let [new-user {:username "john", :email "john@doe.com", :password "secret"}
          response (sut/http-post new-user)]
      (eq/match response
        {:status 201,
         :body   {:data {:id uuid?, :email #".+@.+\.com"}}}))))

One predicate

;; nil
(eq/match nil nil)
(eq/match nil nil?)

;; number
(eq/match 1 1)
(eq/match 1 odd?)
(eq/match 1.0 1.0)
(eq/match 1.0 number?)
(eq/match 1/2 1/2)
(eq/match 1/2 ratio?) ;; clojure only

;; char
(eq/match \a \a)
(eq/match \a char?)

;; string
(eq/match "abc" "abc")
(eq/match "abc" string?)
(eq/match "abc" #"\w+")

;; symbol
(eq/match 'a 'a)
(eq/match 'a simple-symbol?)
(eq/match 'a/b 'a/b)
(eq/match 'a/b qualified-symbol?)

;; keyword
(eq/match :a :a)
(eq/match :a/b :a/b)
(eq/match :a simple-keyword?)
(eq/match :a/b qualified-keyword?)

;; list
(eq/match '() '())
(eq/match '() list?)
(eq/match '(1 2 3) '(1 2 3))
(eq/match '(1 2 3) (list odd? even? odd?)) ;; compare by pairs
(eq/match '(1 2 3) (list odd? #{2 4 8} odd?))

;; vector
(eq/match [] [])
(eq/match [] vector?)
(eq/match [1 2 3] [1 2 3])
(eq/match [1 2 3] [odd? even? odd?])
(eq/match [1 2 3] [odd? #{2 4 8} odd?])

;; set
(eq/match #{} #{})
(eq/match #{} set?)
(eq/match #{1 2 3} #{1 2 3})
(eq/match #{1 2 3} #{1}) ;; subset?
(eq/match [{:c 3} {:b 2} {:a 1}]
  #{{:a odd?} {:b even?}}) ;; compare all elements

;; map
(eq/match {} {})
(eq/match {} map?)
(eq/match {:a 1} {:a 1})
(eq/match {:a 1} {:a odd?})
(eq/match {:a 1, :b 2, :c {:d 3, :e 4}}
  {:a 1, :b number?, :c {:d #{3 5 7}, :e even?}})

Many predicates

;; Same as with one predicate.

(eq/match 1
  1 odd? number?)

(eq/match [{:a 1} {:b 2} {:c #uuid "cc5161ac-f57e-4e7a-9b9e-6bac0b840229"}]
  #(= 3 (count %))
  [{:a odd?} {:b even?} {:c uuid?}])

Notes (Roadmap)

  • Write documentation in source code

  • Improve integration with clojure.test, cljs.test

  • The current API looks good. Improve performance:

    • rewrite all core functions, because match must be fast

    • maybe allow the _ character (symbol) to skip the comparison (same as in the let form)?

    • add explain and use only when match failed?

(eq/explain data predicate1 predicate2)
  • add composable predicates something like that?

;; and
(eq/match data
  (eq/and predicate1 predicate2))

;; or
(eq/match data
  (eq/or
    (eq/and predicate1 predicate2)
    predicate3))

;; not
(eq/match data
  (eq/or
    (eq/and predicate1 predicate2)
    (eq/not predicate3)
    predicate4))
  • add inferred predicates?

(eq/provide {:a 1})
;; => {:a int?}
  • add opts to match:

;; opts:
;; 1. :fail-fast?
;;    - true/false (by default - `true` for performance)
;; 2. :providers
;;    - :equalizer (by default)
;;    - :spec1
;;    - :spec2
;;    - :malli

;; override global configuration
(eq/configure! opts)

;; for spec1 and spec2
(eq/configure! {:fail-fast? false, :providers #{:spec1 :spec2}})

(spec1/def ::id int?)
(spec2/def ::age (spec2/and int? #(>= % 18)))

(eq/match data
  {:id ::id, :age ::age})

;; or override directly
(eq/match {:providers #{:spec1 :spec2}}
  data
  {:id ::id, :age ::age})

;; for malli
(eq/configure! {:fail-fast? false, :providers #{:malli}})

(def id int?)
(def age [:and int? [:>= 18]])

(eq/match data
  {:id id, :age age})

Development

# Run nREPL & connect from your IDE
$ make repl
nREPL server started on port 7888 on host localhost - nrepl://localhost:7888

Testing

# Run Clojure & ClojureScript tests
$ make test

Deploy

# create a new git tag (available types `minor`, `major`)
$ make patch

# push a new git tag to Github then wait for GitHub Actions
# start to deploy the new version to clojars
$ git push origin --tags

Available commands

$ make help
help                           Show help
repl                           Run nREPL
clean                          Clean
lint                           Run linter
test                           Run tests
build                          Build jar
init                           Init first version
patch                          Increment patch version
minor                          Increment minor version
major                          Increment major version
install                        Install locally
deploy                         Deploy to clojars

Can you improve this documentation?Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close