The hamcrest Reference Manual

This is the hamcrest Reference Manual, version 0.4.4, generated automatically by Declt version 4.0 beta 2 "William Riker" on Sat Dec 03 20:15:09 2022 GMT+0.

Table of Contents


1 Introduction


2 Systems

The main system appears first, followed by any subsystem dependency.


2.1 hamcrest

A set of helpers to make your unittests more readable by using Hamcrest assertions.

Author

Alexander Artemenko

License

New BSD License

Long Description

=============
cl-hamcrest
=============

.. image:: https://circleci.com/gh/40ants/cl-hamcrest.svg?style=svg
:target: https://circleci.com/gh/40ants/cl-hamcrest

.. include-from

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:

.. code-block:: common-lisp

(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:

.. code-block:: common-lisp

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

But error message will be quite cumbersome:

.. code-block:: none

× 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 (GUARD
(PROPERTY :|@message| M)
(EQUAL M "Some"))
(PROPERTY :|@timestamp| _) (NOT
(PROPERTY :|@fields|
_)))). (expected: :NON-ERROR)

CL-HAMCREST is more concise and clear
————————————-

With “cl-hamcrest“ test becomes more readable:

.. code-block:: common-lisp

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

As well, as output about the failure:

.. code-block:: none

× 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:

.. code-block:: common-lisp

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

And it’s output:

.. code-block:: none

✓ (:|@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 <http://cl-hamcrest.40ants.com>‘_.

Roadmap
=======

* 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 <https://gist.github.com/svetlyak40wt/fbe480384e9e3f75b10523aa0b4fb6ce>‘_ – 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.

.. _Hamcrest: http://hamcrest.org
.. _Optima: http://quickdocs.org/optima/

.. include-to

Building Documentation
======================

Requirements
————

Python packages
~~~~~~~~~~~~~~~

sphinx
sphinxcontrib-cldomain (https://github.com/russell/sphinxcontrib-cldomain)
pygments-cl-repl
sphinx-bootstrap-theme

Lisp
~~~~

cl-launch (http://www.cliki.net/CL-Launch)

To build
——–

cd docs && make html

Version

0.4.4

Dependencies
Source

hamcrest.asd.


2.2 hamcrest/utils

Author

Alexander Artemenko

License

New BSD License

Dependencies
  • iterate (system).
  • split-sequence (system).
  • cl-ppcre (system).
Source

hamcrest.asd.


2.3 hamcrest/matchers

Author

Alexander Artemenko

License

New BSD License

Dependencies
Source

hamcrest.asd.


3 Files

Files are sorted by type and then listed depth-first from the systems components trees.


3.1 Lisp


3.1.1 hamcrest/hamcrest.asd

Source

hamcrest.asd.

Parent Component

hamcrest (system).

ASDF Systems

3.1.2 hamcrest/utils/file-type.lisp

Source

hamcrest.asd.

Parent Component

hamcrest/utils (system).

Packages

hamcrest/utils.

Public Interface
Internals

3.1.3 hamcrest/matchers/file-type.lisp

Source

hamcrest.asd.

Parent Component

hamcrest/matchers (system).

Packages

hamcrest/matchers.

Public Interface
Internals

4 Packages

Packages are listed by definition order.


4.1 hamcrest/matchers

Source

file-type.lisp.

Use List
  • common-lisp.
  • iterate.
Public Interface
Internals

4.2 hamcrest/utils

Source

file-type.lisp.

Use List
  • common-lisp.
  • iterate.
Public Interface
Internals

5 Definitions

Definitions are sorted by export status, category, package, and then by lexicographic order.


5.1 Public Interface


5.1.1 Macros

Macro: contains (&rest entries)

Checks if each item from a list matches to given matchers.

Contains can accept as raw values, as another matchers:

.. code-block:: common-lisp-repl

TEST> (assert-that ’(:foo
(a b c)
d)
(contains :foo
(has-length 3) ’d))
✓ Contains all given values

Given list should have a length equal to count of matchers:

.. code-block:: common-lisp-repl

TEST> (assert-that ’(:foo
(a b c)
d)
(contains :foo))
× Expected value is shorter than result

You can ignore value of some list items, by using “(any)“ matcher:

.. code-block:: common-lisp-repl

TEST> (assert-that ’(:foo
(a b c)
d)
(contains :foo (any) (any)))
✓ Contains all given values

Package

hamcrest/matchers.

Source

file-type.lisp.

Macro: contains-in-any-order (&rest entries)

Same as “contains“, but items in the sequence can be in any order:

.. code-block:: common-lisp-repl

TEST> (assert-that ’(:foo
(a b c)
d) (contains-in-any-order
(has-length 3)
’d
:foo))

✓ Contains all given values

Package

hamcrest/matchers.

Source

file-type.lisp.

Macro: has-alist-entries (&rest entries)

Matches alist entries:

.. code-block:: common-lisp-repl

TEST> (let ((obj ’((:the-key . "value"))))
(assert-that obj
(has-alist-entries :the-key "value")))
✓ Has alist entries:
:THE-KEY = "value"

TEST> (let ((obj ’((:the-key . "value"))))
(assert-that obj
(has-alist-entries :the-key "value" :missing-key "value")))
× Key :MISSING-KEY is missing

TEST> (let ((obj ’((:the-key . "value"))))
(assert-that obj
(has-alist-entries :the-key "other-value")))
× Key :THE-KEY has "value" value, but "other-value" was expected

Package

hamcrest/matchers.

Source

file-type.lisp.

Macro: has-hash-entries (&rest entries)

Matches hash entries:

.. code-block:: common-lisp-repl

TEST> (let ((obj (make-hash-table)))
(setf (gethash ’the-key obj) "value")
(assert-that obj
(has-hash-entries ’the-key "value")))
✓ Has hash entries:
THE-KEY = "value"

TEST> (let ((obj (make-hash-table)))
(setf (gethash ’the-key obj) "value")
(assert-that obj
(has-hash-entries ’missing-key "value")))
× Key MISSING-KEY is missing

TEST> (let ((obj (make-hash-table)))
(setf (gethash ’the-key obj) "value")
(assert-that obj
(has-hash-entries ’the-key "other-value")))
× Key THE-KEY has "value" value, but "other-value" was expected

Package

hamcrest/matchers.

Source

file-type.lisp.

Macro: has-plist-entries (&rest entries)

Matches plist entries:

.. code-block:: common-lisp-repl

TEST> (let ((obj ’(:foo :bar)))
(assert-that obj
(has-plist-entries :foo "bar" :blah "minor"))) × Key :FOO has :BAR value, but "bar" was expected

This way you can test any number of plist’s entries.

Package

hamcrest/matchers.

Source

file-type.lisp.

Macro: has-properties (&rest entries)

Matches object properties:

.. code-block:: common-lisp-repl

TEST> (defvar the-object)
THE-OBJECT
TEST> (setf (getf the-object :tags) ’(one two))
TEST> (assert-that ’the-object
(has-properties :tags ’(one two)))
✓ Has properties:
:TAGS = (ONE TWO)

TEST> (assert-that ’the-object
(has-properties :tags ’wrong-value))
× Property :TAGS has (ONE TWO) value, but WRONG-VALUE was expected
TEST> (assert-that ’the-object
(has-properties :missing-property ’(one two))) × Property :MISSING-PROPERTY is missing

Package

hamcrest/matchers.

Source

file-type.lisp.

Macro: has-slots (&rest entries)

Matches object slots:

.. code-block:: common-lisp-repl

TEST> (defstruct task
title
description)

TEST> (defvar task (make-task :title "The title "))

TEST> (assert-that task
(has-slots ’title "The title "))
✓ Has slots:
TITLE = "The title "

TEST> (assert-that task
(has-slots ’title "Wrong title "))
× Slot TITLE has "The title " value, but "Wrong title " was expected
TEST> (assert-that task
(has-slots ’description nil))
✓ Has slots:
DESCRIPTION = NIL

Package

hamcrest/matchers.

Source

file-type.lisp.

Macro: hasnt-plist-keys (&rest keys)

Checks if given keys are missing from an object:

.. code-block:: common-lisp-repl

TEST> (let ((obj ’(:foo "bar")))
(assert-that obj
(hasnt-plist-keys :blah :minor))) ✓ Keys :BLAH, :MINOR are absent

Assertion fails if at least one key is present in the object:

.. code-block:: common-lisp-repl

TEST> (let ((obj ’(:foo "bar")))
(assert-that obj
(hasnt-plist-keys :blah :foo)))
× Key :FOO is present in object, but shouldn’t.

Package

hamcrest/matchers.

Source

file-type.lisp.


5.1.2 Setf expanders

Setf Expander: (setf matcher-description) (fn)
Package

hamcrest/matchers.

Source

file-type.lisp.

Reader

matcher-description (function).

Setf Expander: (setf matcher-form) (fn)
Package

hamcrest/matchers.

Source

file-type.lisp.

Reader

matcher-form (function).


5.1.3 Ordinary functions

Function: alistp (value)

Checks if give value is a proper alist.

Package

hamcrest/utils.

Source

file-type.lisp.

Function: any ()

Assertion is passed regardles of value of the object:

.. code-block:: common-lisp-repl

TEST> (assert-that 1 (any))
✓ Any value if good enough

TEST> (assert-that "the-string" (any))
✓ Any value if good enough

TEST> (assert-that ’the-symbol (any))
✓ Any value if good enough

TEST> (assert-that ’(1 2 3) (any))
✓ Any value if good enough

Package

hamcrest/matchers.

Source

file-type.lisp.

Function: assertion-error-reason-with-context (condition &key indent-spaces)

Returns a multiline string where error reason is nested into the context like that:

Item with index 1:
Alist entry with key :NAME
Alist entry with key :FIRST is required

Parameter :indent-spaces could be specified to control number of spaces for each indentation level.

Package

hamcrest/matchers.

Source

file-type.lisp.

Function: deindent (text)

Removes empty new lines at the begining and at the end of the text, and removes common number of whitespaces from rest of the lines.

Package

hamcrest/utils.

Source

file-type.lisp.

Function: has-all (&rest matchers)

Makes a matcher which groups another matchers with AND logic.

This way we can check if plist has one key and hasn’t another. And if all matchers succeed, then “has-all“ succeed as well:

.. code-block:: common-lisp-repl

TEST> (assert-that ’(:foo "bar")
(has-all (has-plist-entries :foo "bar") (hasnt-plist-keys :blah))) ✓ All checks are passed

If at least one check is failed, then “has-all“ fails too:

.. code-block:: common-lisp-repl

TEST> (assert-that ’(:foo "bar" :blah "minor")
(has-all (has-plist-entries :foo "bar") (hasnt-plist-keys :blah))) × Key :BLAH is present in object, but shouldn’t

Package

hamcrest/matchers.

Source

file-type.lisp.

Function: has-length (expected-length)

Checks if a list have specivied length.

.. code-block:: common-lisp-repl

TEST> (assert-that ’nil (has-length 0))
✓ Has length of 0

TEST> (assert-that ’(a b c d) (has-length 4))
✓ Has length of 4

TEST> (assert-that ’(a b c d) (has-length 100500))
× List (A B C D) has length of 4, but 100500 was expected

Package

hamcrest/matchers.

Source

file-type.lisp.

Function: has-type (expected-type)

Checks if a list have specivied length.

.. code-block:: common-lisp-repl

TEST> (matcher-description (has-type ’cons))
"Has type CONS"

TEST> (funcall (has-type ’cons) 100500)
; Debugger entered on #<ASSERTION-ERROR 100500 has type (INTEGER 0 4611686018427387903), but CONS was expected>

Package

hamcrest/matchers.

Source

file-type.lisp.

Function: indent (space &optional count)

Creates a string with a number of spaces to indent new line of a test report.

Package

hamcrest/utils.

Source

file-type.lisp.

Function: matcher-description (fn)

Returns description of a given matcher function.

Can be used to print nested matchers in a nicely indented,
human readable way:

.. code-block:: common-lisp-repl

TEST> (matcher-description (has-length 100500))
"Has length of 100500 "

TEST> (matcher-description (contains
(has-plist-entries :foo "bar ") (has-plist-entries :foo "minor "))) "Contains all given values "

TEST> (matcher-description (has-plist-entries
:foo "bar "
:blah (has-hash-entries :minor "again "))) "Has plist entries:
:FOO = "bar"
:BLAH = Has hash entries:
:MINOR = "again""

Package

hamcrest/matchers.

Source

file-type.lisp.

Setf expander for this function

(setf matcher-description).

Function: matcher-form (fn)

Returns description of a given matcher function.

Can be used to print nested matchers in a nicely indented,
human readable way:

.. code-block:: common-lisp-repl

TEST> (matcher-description (has-length 100500))
"Has length of 100500 "

TEST> (matcher-description (contains
(has-plist-entries :foo "bar ") (has-plist-entries :foo "minor "))) "Contains all given values "

TEST> (matcher-description (has-plist-entries
:foo "bar "
:blah (has-hash-entries :minor "again "))) "Has plist entries:
:FOO = "bar"
:BLAH = Has hash entries:
:MINOR = "again""

Package

hamcrest/matchers.

Source

file-type.lisp.

Setf expander for this function

(setf matcher-form).

Function: shift-rest-lines (text indent)

Adds text from ’indent’ to all lines from the ’text’ except the first one.

Package

hamcrest/utils.

Source

file-type.lisp.


5.1.4 Generic functions

Generic Reader: assertion-context (condition)
Package

hamcrest/matchers.

Methods
Reader Method: assertion-context ((condition assertion-error))
Source

file-type.lisp.

Target Slot

context.

Generic Reader: assertion-error-reason (condition)
Package

hamcrest/matchers.

Methods
Reader Method: assertion-error-reason ((condition assertion-error))
Source

file-type.lisp.

Target Slot

reason.


5.1.5 Standalone methods

Method: print-object ((obj assertion-error) stream)

Returns assertion error representation along with it’s reason.

Source

file-type.lisp.


5.1.6 Conditions

Condition: assertion-error
Package

hamcrest/matchers.

Source

file-type.lisp.

Direct superclasses

error.

Direct methods
Direct slots
Slot: reason
Initargs

:reason

Readers

assertion-error-reason.

Writers

This slot is read-only.

Slot: context
Initform

(quote (copy-list hamcrest/matchers::*context*))

Readers

assertion-context.

Writers

This slot is read-only.


5.2 Internals


5.2.1 Special variables

Special Variable: *context*

Context description for nested matchers.

When some matcher calls another, it should push it’s description to this list. And after successful matching to pop item from the list.

Package

hamcrest/matchers.

Source

file-type.lisp.

Special Variable: *matcher-descriptions*

In some implementation it is impossible to have documentation in functions created with flet, labels or lambda, that is why we’ll store their docstrings in this cache

Package

hamcrest/matchers.

Source

file-type.lisp.

Special Variable: *matcher-forms*

TODO: ..

Package

hamcrest/matchers.

Source

file-type.lisp.


5.2.2 Macros

Macro: def-has-macro (macro-name documentation &key check-obj-type get-key-value format-error-message format-matcher-description)

Defines a new macro to check if object has some properties.

Package

hamcrest/matchers.

Source

file-type.lisp.

Macro: format-expected-entries (prefix-text)

This macro is for formatting description of matchers which expect some key/value entries, like (has-plist-entries :foo 1 :bar 2).

Package

hamcrest/matchers.

Source

file-type.lisp.

Macro: with-context (description &body body)

Manages *context* stack when calling nested matchers.

Package

hamcrest/matchers.

Source

file-type.lisp.


5.2.3 Ordinary functions

Function: check-if-alist (value)

A little helper, to check types in matchers

Package

hamcrest/matchers.

Source

file-type.lisp.

Function: check-if-has-slots (object)

A little helper, to check if object is instance of a class and has slots.

Package

hamcrest/matchers.

Source

file-type.lisp.

Function: check-if-hash (value)

A little helper, to check types in matchers

Package

hamcrest/matchers.

Source

file-type.lisp.

Function: check-if-list (value)

A little helper, to check types in matchers

Package

hamcrest/matchers.

Source

file-type.lisp.

Function: check-if-symbol (value)

A little helper, to check types in matchers.

Package

hamcrest/matchers.

Source

file-type.lisp.

Function: empty-line-p (line)

Checks if line of text is empty.

Package

hamcrest/utils.

Source

file-type.lisp.

Function: get-indentation (line)

Returns numbers of leading spaces for the line.

Package

hamcrest/utils.

Source

file-type.lisp.

Function: left-remove-if (items predicate)

Returns list skipping leftmost items which match a predicate.

Package

hamcrest/utils.

Source

file-type.lisp.

Function: quote-underline (value)
Package

hamcrest/matchers.

Source

file-type.lisp.

Function: right-remove-if (items predicate)

Returns a new list, without rightmost items which match a predicate.

Package

hamcrest/utils.

Source

file-type.lisp.


Appendix A Indexes


A.1 Concepts


A.2 Functions

Jump to:   (  
A   C   D   E   F   G   H   I   L   M   P   Q   R   S   W  
Index Entry  Section

(
(setf matcher-description): Public setf expanders
(setf matcher-form): Public setf expanders

A
alistp: Public ordinary functions
any: Public ordinary functions
assertion-context: Public generic functions
assertion-context: Public generic functions
assertion-error-reason: Public generic functions
assertion-error-reason: Public generic functions
assertion-error-reason-with-context: Public ordinary functions

C
check-if-alist: Private ordinary functions
check-if-has-slots: Private ordinary functions
check-if-hash: Private ordinary functions
check-if-list: Private ordinary functions
check-if-symbol: Private ordinary functions
contains: Public macros
contains-in-any-order: Public macros

D
def-has-macro: Private macros
deindent: Public ordinary functions

E
empty-line-p: Private ordinary functions

F
format-expected-entries: Private macros
Function, alistp: Public ordinary functions
Function, any: Public ordinary functions
Function, assertion-error-reason-with-context: Public ordinary functions
Function, check-if-alist: Private ordinary functions
Function, check-if-has-slots: Private ordinary functions
Function, check-if-hash: Private ordinary functions
Function, check-if-list: Private ordinary functions
Function, check-if-symbol: Private ordinary functions
Function, deindent: Public ordinary functions
Function, empty-line-p: Private ordinary functions
Function, get-indentation: Private ordinary functions
Function, has-all: Public ordinary functions
Function, has-length: Public ordinary functions
Function, has-type: Public ordinary functions
Function, indent: Public ordinary functions
Function, left-remove-if: Private ordinary functions
Function, matcher-description: Public ordinary functions
Function, matcher-form: Public ordinary functions
Function, quote-underline: Private ordinary functions
Function, right-remove-if: Private ordinary functions
Function, shift-rest-lines: Public ordinary functions

G
Generic Function, assertion-context: Public generic functions
Generic Function, assertion-error-reason: Public generic functions
get-indentation: Private ordinary functions

H
has-alist-entries: Public macros
has-all: Public ordinary functions
has-hash-entries: Public macros
has-length: Public ordinary functions
has-plist-entries: Public macros
has-properties: Public macros
has-slots: Public macros
has-type: Public ordinary functions
hasnt-plist-keys: Public macros

I
indent: Public ordinary functions

L
left-remove-if: Private ordinary functions

M
Macro, contains: Public macros
Macro, contains-in-any-order: Public macros
Macro, def-has-macro: Private macros
Macro, format-expected-entries: Private macros
Macro, has-alist-entries: Public macros
Macro, has-hash-entries: Public macros
Macro, has-plist-entries: Public macros
Macro, has-properties: Public macros
Macro, has-slots: Public macros
Macro, hasnt-plist-keys: Public macros
Macro, with-context: Private macros
matcher-description: Public ordinary functions
matcher-form: Public ordinary functions
Method, assertion-context: Public generic functions
Method, assertion-error-reason: Public generic functions
Method, print-object: Public standalone methods

P
print-object: Public standalone methods

Q
quote-underline: Private ordinary functions

R
right-remove-if: Private ordinary functions

S
Setf Expander, (setf matcher-description): Public setf expanders
Setf Expander, (setf matcher-form): Public setf expanders
shift-rest-lines: Public ordinary functions

W
with-context: Private macros