Skip to content
Switch branches/tags

Latest commit


Git stats


Failed to load latest commit information.
Latest commit message
Commit time


It is implementation of Hamcrest idea in Common Lisp.

It simplifes unittests and make them more readable. Hamcrest uses idea of pattern-matching, to construct matchers from different pieces and to apply them to the data.

Why not pattern-matching library?

You may ask: "Why dont use a pattern-matching library, like Optima?"

Here is another example from another library log4cl-json, where I want to check that some fields in plist have special values and other key is not present. Here is the data:

(defvar log-item '(:|@message| "Some"
                   :|@timestamp| 122434342
                   ;; this field is wrong and
                   ;; shouldn't be here
                   :|@fields| nil))

With Optima I could write this code to match the data:

(ok (ematch
    ((and (guard (property :|@message| m)
                 (equal m "Some"))
          (property :|@timestamp| _)
          (not (property :|@fields| _)))
  "Log entry has message, timestamp, but not fields")

But error message will be quite cumbersome:

× Aborted due to an error in subtest "Simple match"
  Raised an error Can't match ((:|@fields| NIL :|@timestamp|
                                "2017-01-03T16:42:00.991444Z" :|@message|
                                "Some")) with ((COMMON-LISP:AND
                                                 (PROPERTY :|@message| M)
                                                 (EQUAL M "Some"))
                                                (PROPERTY :|@timestamp|
                                                 (PROPERTY :|@fields|
                                                  _)))). (expected: :NON-ERROR)

CL-HAMCREST is more concise and clear

With cl-hamcrest test becomes more readable:

      (has-plist-entries :|@message| "Some"
                         :|@timestamp| _)
      (hasnt-plist-keys :|@fields|))

As well, as output about the failure:

× Key :|@fields| is present in object, but shouldn't

That is because cl-hamcrest tracks the context and works together with testing framework, to output all information to let you understand where the problem is.

Why not just use Prove's assertions?

To draw a full picture, here is test, written in plain Prove's assertions:

(ok (member :|@message| log-item))
(is (getf log-item :|@message|)
(ok (member :|@timestamp| log-item))
(ok (not (member :|@fields| log-item)))

And it's output:

✓ (:|@message| "Some") is expected to be T
✓ "Some" is expected to be "Some"
✓ (:|@timestamp| "2017-01-03T16:57:17.988810Z" :|@message| "Some") is expected to be T
× NIL is expected to be T

is not as clear, if you'll try to figure out what does NIL is expected to be T mean.

Description of all supported matchers, you can find in the documentation.


  • Logical matchers:
    • any-of – Matches if any of the given matchers evaluate to True.
    • is-not – Inverts the given matcher to its logical negation (think if we need it, and how to show the results, here are results how it works in PyHamcrest – it just sees that matcher returned True and raises Assertion error with full object's content and matcher's description with prepended 'not' particle).
  • Object matchers:
    • Add hasnt-some-keys matchers, corresponding to has-some-entries.
    • Make has-alist-entries work with keys other than keyword right now it uses eql to compare keys.
  • Sequence matchers:
    • is-in – Matches if evaluated object is present in a given sequence.
  • Other features:
    • Use uniq CommonLisp feature to restart signaled conditions to collect all problems with data when there are few problems with keys.

Building Documentation


Python packages

sphinx sphinxcontrib-cldomain ( pygments-cl-repl sphinx-bootstrap-theme


cl-launch (

To build

cd docs && make html


This library makes your CL unittests more readable.





No packages published