{"id":33237144,"url":"https://github.com/40ants/cl-hamcrest","last_synced_at":"2026-01-16T20:21:50.468Z","repository":{"id":15177416,"uuid":"77704607","full_name":"40ants/cl-hamcrest","owner":"40ants","description":"This library makes your CL unittests more readable.","archived":false,"fork":false,"pushed_at":"2025-02-24T13:30:05.000Z","size":971,"stargazers_count":18,"open_issues_count":1,"forks_count":0,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-02-24T13:38:17.283Z","etag":null,"topics":["hamcrest","prove","unittesting"],"latest_commit_sha":null,"homepage":"http://40ants.com/cl-hamcrest/","language":"Common Lisp","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/40ants.png","metadata":{"files":{"readme":"README.md","changelog":"ChangeLog.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-12-30T18:56:12.000Z","updated_at":"2025-02-24T13:30:10.000Z","dependencies_parsed_at":"2023-01-11T19:02:05.977Z","dependency_job_id":"056352bb-f7ac-4cdd-bf93-657e34a68a8d","html_url":"https://github.com/40ants/cl-hamcrest","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/40ants/cl-hamcrest","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/40ants%2Fcl-hamcrest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/40ants%2Fcl-hamcrest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/40ants%2Fcl-hamcrest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/40ants%2Fcl-hamcrest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/40ants","download_url":"https://codeload.github.com/40ants/cl-hamcrest/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/40ants%2Fcl-hamcrest/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28482267,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["hamcrest","prove","unittesting"],"created_at":"2025-11-16T19:00:28.322Z","updated_at":"2026-01-16T20:21:50.456Z","avatar_url":"https://github.com/40ants.png","language":"Common Lisp","readme":"\u003ca id=\"x-28HAMCREST-DOCS-2FINDEX-3A-40README-2040ANTS-DOC-2FLOCATIVES-3ASECTION-29\"\u003e\u003c/a\u003e\n\n# Implementation of Hamcrest for Common Lisp\n\n\u003ca id=\"hamcrest-asdf-system-details\"\u003e\u003c/a\u003e\n\n## HAMCREST ASDF System Details\n\n* Description: A set of helpers to make your unittests more readable by using Hamcrest assertions.\n* Licence: New `BSD` License\n* Author: Alexander Artemenko\n* Bug tracker: [https://github.com/40ants/cl-hamcrest/issues][eafb]\n* Source control: [GIT][46fe]\n* Depends on: [alexandria][8236], [cl-ppcre][49b9], [iterate][7d7b], [split-sequence][3dcd]\n\n[![](https://github-actions.40ants.com/40ants/cl-hamcrest/matrix.svg)][3156]\n\n![](http://quickdocs.org/badge/cl-hamcrest.svg)\n\n\u003ca id=\"x-28HAMCREST-DOCS-2FINDEX-3A-3A-40INSTALLATION-2040ANTS-DOC-2FLOCATIVES-3ASECTION-29\"\u003e\u003c/a\u003e\n\n## Installation\n\nYou can install this library from Quicklisp, but you want to receive updates quickly, then install it from Ultralisp.org:\n\n```\n(ql-dist:install-dist \"http://dist.ultralisp.org/\"\n                      :prompt nil)\n(ql:quickload :hamcrest)\n```\n\u003ca id=\"x-28HAMCREST-DOCS-2FINDEX-3A-3A-40INTRODUCTION-2040ANTS-DOC-2FLOCATIVES-3ASECTION-29\"\u003e\u003c/a\u003e\n\n## Introduction\n\nThis is an implementation of [Hamcrest][2b96] for Common Lisp.\n\nIt simplifes unittests and make them more readable. Hamcrest uses\nidea of pattern-matching, to construct matchers from different pieces and\nto apply them to the data.\n\n\u003ca id=\"here-is-a-simple-example\"\u003e\u003c/a\u003e\n\n### Here is a simple example\n\n```\n(assert-that\n  log-item\n  (has-plist-entries :|@message| \"Some\"\n                     :|@timestamp| _)\n  (hasnt-plist-keys :|@fields|))\n```\n\u003ca id=\"x-28HAMCREST-DOCS-2FINDEX-3A-3A-40WHY-NOT-PATTERNMATCHING-2040ANTS-DOC-2FLOCATIVES-3ASECTION-29\"\u003e\u003c/a\u003e\n\n## Why not pattern-matching library?\n\nYou may ask: \"Why dont use a pattern-matching library, like [Optima][d992]?\"\n\nHere is another example from another library `log4cl-json`, where I want\nto check that some fields in plist have special values and other key is not\npresent. Here is the data:\n\n```\n(defvar log-item '(:|@message| \"Some\"\n                   :|@timestamp| 122434342\n                   ;; this field is wrong and\n                   ;; shouldn't be here\n                   :|@fields| nil))\n```\nWith [Optima][d992] I could write this code to match the data:\n\n```\n(ok (ematch\n      log-item\n    ((and (guard (property :|@message| m)\n                 (equal m \"Some\"))\n          (property :|@timestamp| _)\n          (not (property :|@fields| _)))\n     t))\n  \"Log entry has message, timestamp, but not fields\")\n```\nBut error message will be quite cumbersome:\n\n```\n× Aborted due to an error in subtest \"Simple match\"\n  Raised an error Can't match ((:|@fields| NIL :|@timestamp|\n                                \"2017-01-03T16:42:00.991444Z\" :|@message|\n                                \"Some\")) with ((COMMON-LISP:AND\n                                                (GUARD\n                                                 (PROPERTY :|@message| M)\n                                                 (EQUAL M \"Some\"))\n                                                (PROPERTY :|@timestamp|\n                                                 _)\n                                                (NOT\n                                                 (PROPERTY :|@fields|\n                                                  _)))). (expected: :NON-ERROR)\n```\n\u003ca id=\"cl-hamcrest-is-more-concise-and-clear\"\u003e\u003c/a\u003e\n\n### CL-HAMCREST is more concise and clear\n\nWith `cl-hamcrest` test becomes more readable:\n\n```\n(assert-that\n      log-item\n      (has-plist-entries :|@message| \"Some\"\n                         :|@timestamp| _)\n      (hasnt-plist-keys :|@fields|))\n```\nAs well, as output about the failure:\n\n```\n× Key :|@fields| is present in object, but shouldn't\n```\nThat is because `cl-hamcrest` tracks the context and works\ntogether with testing framework, to output all information\nto let you understand where the problem is.\n\n\u003ca id=\"why-not-just-use-prove-s-assertions\"\u003e\u003c/a\u003e\n\n### Why not just use Prove's assertions?\n\nTo draw a full picture, here is test, written in plain Prove's\nassertions:\n\n```\n(ok (member :|@message| log-item))\n(is (getf log-item :|@message|)\n    \"Some\")\n(ok (member :|@timestamp| log-item))\n(ok (not (member :|@fields| log-item)))\n```\nAnd it's output:\n\n```\n✓ (:|@message| \"Some\") is expected to be T \n✓ \"Some\" is expected to be \"Some\" \n✓ (:|@timestamp| \"2017-01-03T16:57:17.988810Z\" :|@message| \"Some\") is expected to be T \n× NIL is expected to be T \n```\nis not as clear, if you'll try to figure out\nwhat does `NIL is expected to be T` mean.\n\nDescription of all supported matchers, you can find in the\n[`Matchers library`][60ce] section.\n\n\u003ca id=\"x-28HAMCREST-DOCS-2FMATCHERS-3A-3A-40MATCHERS-2040ANTS-DOC-2FLOCATIVES-3ASECTION-29\"\u003e\u003c/a\u003e\n\n## Matchers library\n\nHere you will find all matchers, supported by `CL-HAMCREST`, grouped by\ntheir purpose.\n\n\u003ca id=\"x-28HAMCREST-DOCS-2FMATCHERS-3A-3A-40OBJECT-2040ANTS-DOC-2FLOCATIVES-3ASECTION-29\"\u003e\u003c/a\u003e\n\n### Object matchers\n\nThis kind of matchers checks some sort of properties on an object. In\nthis case objects are not only the `CLOS` objects but also, hashmaps,\nalists and property lists.\n\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AHAS-PLIST-ENTRIES-20-2840ANTS-DOC-2FLOCATIVES-3AMACRO-29-29\"\u003e\u003c/a\u003e\n\n#### [macro](f0a1) `hamcrest/matchers:has-plist-entries` \u0026rest entries\n\nMatches plist entries:\n\n```\nTEST\u003e (let ((obj '(:foo :bar)))\n        (assert-that obj\n                     (has-plist-entries :foo \"bar\"\n                                        :blah \"minor\")))\n  × Key :FOO has :BAR value, but \"bar\" was expected\n```\nThis way you can test any number of plist's entries.\n\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AHASNT-PLIST-KEYS-20-2840ANTS-DOC-2FLOCATIVES-3AMACRO-29-29\"\u003e\u003c/a\u003e\n\n#### [macro](0a83) `hamcrest/matchers:hasnt-plist-keys` \u0026rest keys\n\nChecks if given keys are missing from an object:\n\n```\nTEST\u003e (let ((obj '(:foo \"bar\")))\n        (assert-that obj\n                     (hasnt-plist-keys :blah :minor)))\n  ✓ Keys :BLAH, :MINOR are absent\n```\nAssertion fails if at least one key is present in the object:\n\n```\nTEST\u003e (let ((obj '(:foo \"bar\")))\n        (assert-that obj\n                     (hasnt-plist-keys :blah :foo)))\n  × Key :FOO is present in object, but shouldn't.\n```\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AHAS-ALIST-ENTRIES-20-2840ANTS-DOC-2FLOCATIVES-3AMACRO-29-29\"\u003e\u003c/a\u003e\n\n#### [macro](a59e) `hamcrest/matchers:has-alist-entries` \u0026rest entries\n\nMatches alist entries:\n\n```\nTEST\u003e (let ((obj '((:the-key . \"value\"))))\n        (assert-that obj\n                     (has-alist-entries :the-key \"value\")))\n\n  ✓ Has alist entries:\n      :THE-KEY = \"value\"\n\nTEST\u003e (let ((obj '((:the-key . \"value\"))))\n        (assert-that obj\n                     (has-alist-entries :the-key \"value\"\n                                        :missing-key \"value\")))\n\n  × Key :MISSING-KEY is missing\n\nTEST\u003e (let ((obj '((:the-key . \"value\"))))\n        (assert-that obj\n                     (has-alist-entries :the-key \"other-value\")))\n\n  × Key :THE-KEY has \"value\" value, but \"other-value\" was expected\n```\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AHAS-HASH-ENTRIES-20-2840ANTS-DOC-2FLOCATIVES-3AMACRO-29-29\"\u003e\u003c/a\u003e\n\n#### [macro](7747) `hamcrest/matchers:has-hash-entries` \u0026rest entries\n\nMatches hash entries:\n\n```\nTEST\u003e (let ((obj (make-hash-table)))\n        (setf (gethash 'the-key obj) \"value\")\n        (assert-that obj\n                     (has-hash-entries 'the-key \"value\")))\n\n  ✓ Has hash entries:\n      THE-KEY = \"value\"\n\nTEST\u003e (let ((obj (make-hash-table)))\n        (setf (gethash 'the-key obj) \"value\")\n        (assert-that obj\n                     (has-hash-entries 'missing-key \"value\")))\n\n  × Key MISSING-KEY is missing\n\nTEST\u003e (let ((obj (make-hash-table)))\n        (setf (gethash 'the-key obj) \"value\")\n        (assert-that obj\n                     (has-hash-entries 'the-key \"other-value\")))\n\n  × Key THE-KEY has \"value\" value, but \"other-value\" was expected\n```\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AHAS-PROPERTIES-20-2840ANTS-DOC-2FLOCATIVES-3AMACRO-29-29\"\u003e\u003c/a\u003e\n\n#### [macro](7bb6) `hamcrest/matchers:has-properties` \u0026rest entries\n\nMatches object properties:\n\n```\nTEST\u003e (defvar the-object)\nTHE-OBJECT\nTEST\u003e (setf (getf the-object :tags) '(one two))\nTEST\u003e (assert-that 'the-object\n                   (has-properties :tags '(one two)))\n  ✓ Has properties:\n      :TAGS = (ONE TWO)\n\nTEST\u003e (assert-that 'the-object\n                   (has-properties :tags 'wrong-value))\n  × Property :TAGS has (ONE TWO) value, but WRONG-VALUE was expected\n\nTEST\u003e (assert-that 'the-object\n                   (has-properties :missing-property '(one two)))\n  × Property :MISSING-PROPERTY is missing\n```\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AHAS-SLOTS-20-2840ANTS-DOC-2FLOCATIVES-3AMACRO-29-29\"\u003e\u003c/a\u003e\n\n#### [macro](f096) `hamcrest/matchers:has-slots` \u0026rest entries\n\nMatches object slots:\n\n```\nTEST\u003e (defstruct task\n        title\n        description)\n\nTEST\u003e (defvar task (make-task :title \"The title \"))\n\nTEST\u003e (assert-that task\n                   (has-slots 'title \"The title \"))\n  ✓ Has slots:\n      TITLE = \"The title \"\n\nTEST\u003e (assert-that task\n                   (has-slots 'title \"Wrong title \"))\n  × Slot TITLE has \"The title \" value, but \"Wrong title \" was expected\n\nTEST\u003e (assert-that task\n                   (has-slots 'description nil))\n  ✓ Has slots:\n      DESCRIPTION = NIL\n```\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AHAS-TYPE-20FUNCTION-29\"\u003e\u003c/a\u003e\n\n#### [function](5cfe) `hamcrest/matchers:has-type` expected-type\n\nChecks if a list have specivied length.\n\n```\nTEST\u003e (matcher-description (has-type 'cons))\n\"Has type CONS\"\n\nTEST\u003e (funcall (has-type 'cons) 100500)\n; Debugger entered on #\u003cASSERTION-ERROR 100500 has type (INTEGER 0 4611686018427387903), but CONS was expected\u003e\n```\n\u003ca id=\"x-28HAMCREST-DOCS-2FMATCHERS-3A-3A-40SEQUENCE-2040ANTS-DOC-2FLOCATIVES-3ASECTION-29\"\u003e\u003c/a\u003e\n\n### Sequence matchers\n\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AHAS-LENGTH-20FUNCTION-29\"\u003e\u003c/a\u003e\n\n#### [function](ad36) `hamcrest/matchers:has-length` expected-length\n\nChecks if a list have specivied length.\n\n```\nTEST\u003e (assert-that 'nil (has-length 0))\n  ✓ Has length of 0\n\nTEST\u003e (assert-that '(a b c d) (has-length 4))\n  ✓ Has length of 4\n\nTEST\u003e (assert-that '(a b c d) (has-length 100500))\n  × List (A B C D) has length of 4, but 100500 was expected\n```\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3ACONTAINS-20-2840ANTS-DOC-2FLOCATIVES-3AMACRO-29-29\"\u003e\u003c/a\u003e\n\n#### [macro](8e69) `hamcrest/matchers:contains` \u0026rest entries\n\nChecks if each item from a list matches to given matchers.\n\nContains can accept as raw values, as another matchers:\n\n```\nTEST\u003e (assert-that '(:foo\n                     (a b c)\n                     d)\n                   (contains :foo\n                             (has-length 3)\n                             'd))\n  ✓ Contains all given values\n```\nGiven list should have a length equal to count of matchers:\n\n```\nTEST\u003e (assert-that '(:foo\n                     (a b c)\n                     d)\n                   (contains :foo))\n  × Expected value is shorter than result\n```\nYou can ignore value of some list items, by using `(any)` matcher:\n\n```\nTEST\u003e (assert-that '(:foo\n                     (a b c)\n                     d)\n                   (contains :foo (any) (any)))\n  ✓ Contains all given values\n```\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3ACONTAINS-IN-ANY-ORDER-20-2840ANTS-DOC-2FLOCATIVES-3AMACRO-29-29\"\u003e\u003c/a\u003e\n\n#### [macro](b896) `hamcrest/matchers:contains-in-any-order` \u0026rest entries\n\nSame as `contains`, but items in the sequence can be in any order:\n\n```\nTEST\u003e (assert-that '(:foo\n                     (a b c)\n                     d)\n                   (contains-in-any-order\n                    (has-length 3)\n                    'd\n                    :foo))\n\n  ✓ Contains all given values\n```\n\u003ca id=\"x-28HAMCREST-DOCS-2FMATCHERS-3A-3A-40BOOLEAN-2040ANTS-DOC-2FLOCATIVES-3ASECTION-29\"\u003e\u003c/a\u003e\n\n### Boolean matchers\n\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AANY-20FUNCTION-29\"\u003e\u003c/a\u003e\n\n#### [function](ac51) `hamcrest/matchers:any`\n\nAssertion is passed regardles of value of the object:\n\n```\nTEST\u003e (assert-that 1 (any))\n  ✓ Any value if good enough\n\nTEST\u003e (assert-that \"the-string\" (any))\n  ✓ Any value if good enough\n\nTEST\u003e (assert-that 'the-symbol (any))\n  ✓ Any value if good enough\n\nTEST\u003e (assert-that '(1 2 3) (any))\n  ✓ Any value if good enough\n```\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AHAS-ALL-20FUNCTION-29\"\u003e\u003c/a\u003e\n\n#### [function](6504) `hamcrest/matchers:has-all` \u0026rest matchers\n\nMakes a matcher which groups another matchers with `AND` logic.\n\nThis way we can check if plist has one key and hasn't another.\nAnd if all matchers succeed, then `has-all` succeed as well:\n\n```\nTEST\u003e (assert-that '(:foo \"bar\")\n                   (has-all (has-plist-entries :foo \"bar\")\n                            (hasnt-plist-keys :blah)))\n  ✓ All checks are passed\n```\nIf at least one check is failed, then `has-all` fails too:\n\n```\nTEST\u003e (assert-that '(:foo \"bar\" :blah \"minor\")\n                   (has-all (has-plist-entries :foo \"bar\")\n                            (hasnt-plist-keys :blah)))\n  × Key :BLAH is present in object, but shouldn't\n```\n\u003ca id=\"x-28HAMCREST-DOCS-2FMATCHERS-3A-3A-40UTILS-2040ANTS-DOC-2FLOCATIVES-3ASECTION-29\"\u003e\u003c/a\u003e\n\n### Utility functions\n\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3A-5F-20FUNCTION-29\"\u003e\u003c/a\u003e\n\n#### [function](d4e6) `hamcrest/matchers:_`\n\nSymbol _ should be used as is not as a function.\n\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AMATCHER-DESCRIPTION-20FUNCTION-29\"\u003e\u003c/a\u003e\n\n#### [function](408c) `hamcrest/matchers:matcher-description` fn\n\nReturns description of a given matcher function.\n\nCan be used to print nested matchers in a nicely indented,\nhuman readable way:\n\n```\nTEST\u003e (matcher-description (has-length 100500))\n\"Has length of 100500 \"\n\nTEST\u003e (matcher-description (contains\n                            (has-plist-entries :foo \"bar \")\n                            (has-plist-entries :foo \"minor \")))\n\"Contains all given values \"\n\nTEST\u003e (matcher-description (has-plist-entries\n                            :foo \"bar \"\n                            :blah (has-hash-entries :minor \"again \")))\n\"Has plist entries:\n  :FOO = \"bar\"\n  :BLAH = Has hash entries:\n            :MINOR = \"again\"\"\n```\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AMATCHER-FORM-20FUNCTION-29\"\u003e\u003c/a\u003e\n\n#### [function](db4f) `hamcrest/matchers:matcher-form` fn\n\nReturns description of a given matcher function.\n\nCan be used to print nested matchers in a nicely indented,\nhuman readable way:\n\n```\nTEST\u003e (matcher-description (has-length 100500))\n\"Has length of 100500 \"\n\nTEST\u003e (matcher-description (contains\n                            (has-plist-entries :foo \"bar \")\n                            (has-plist-entries :foo \"minor \")))\n\"Contains all given values \"\n\nTEST\u003e (matcher-description (has-plist-entries\n                            :foo \"bar \"\n                            :blah (has-hash-entries :minor \"again \")))\n\"Has plist entries:\n  :FOO = \"bar\"\n  :BLAH = Has hash entries:\n            :MINOR = \"again\"\"\n```\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AASSERTION-ERROR-20CONDITION-29\"\u003e\u003c/a\u003e\n\n#### [condition](b31e) `hamcrest/matchers:assertion-error` (error)\n\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AASSERTION-ERROR-REASON-20-2840ANTS-DOC-2FLOCATIVES-3AREADER-20HAMCREST-2FMATCHERS-3AASSERTION-ERROR-29-29\"\u003e\u003c/a\u003e\n\n#### [reader](b31e) `hamcrest/matchers:assertion-error-reason` (assertion-error) (:reason)\n\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AASSERTION-CONTEXT-20-2840ANTS-DOC-2FLOCATIVES-3AREADER-20HAMCREST-2FMATCHERS-3AASSERTION-ERROR-29-29\"\u003e\u003c/a\u003e\n\n#### [reader](b31e) `hamcrest/matchers:assertion-context` (assertion-error) (= '(copy-list \\*context\\*))\n\n\u003ca id=\"x-28HAMCREST-2FMATCHERS-3AASSERTION-ERROR-REASON-WITH-CONTEXT-20FUNCTION-29\"\u003e\u003c/a\u003e\n\n#### [function](a601) `hamcrest/matchers:assertion-error-reason-with-context` condition \u0026key (indent-spaces 2)\n\nReturns a multiline string where error reason is nested into the context\nlike that:\n\nItem with index 1:\n  Alist entry with key `:NAME`\n    Alist entry with key `:FIRST` is required\n\nParameter :indent-spaces could be specified to control number of spaces\nfor each indentation level.\n\n\u003ca id=\"x-28HAMCREST-DOCS-2FPROVE-3A-3A-40PROVE-2040ANTS-DOC-2FLOCATIVES-3ASECTION-29\"\u003e\u003c/a\u003e\n\n## Integration with Prove\n\n`CL-HAMCREST` has integration with [Prove][653f].\n\n```\nTEST\u003e (ql:quickload :hamcrest-prove)\nTEST\u003e (use-package :hamcrest.prove)\nTEST\u003e (let ((obj (make-hash-table)))\n        (assert-that\n         obj\n         (has-hash-entries :foo :bar)))\n  × Key :FOO is missing\nT\nTEST\u003e (let ((obj (make-hash-table)))\n        (setf (gethash :foo obj) :bar)\n\n        (assert-that\n         obj\n         (has-hash-entries :foo :bar)))\n  ✓ Has hash entries:\n      :FOO = :BAR\nT\nTEST\u003e (let ((obj (make-hash-table)))\n        (setf (gethash :foo obj) :bar)\n\n        (assert-that\n         obj\n         (has-hash-entries :foo :some-value)))\n  × Key :FOO has :BAR value, but :SOME-VALUE was expected\nT\n```\nThis is the simple case, but nested objects can be checked too.\n\nAll available matchers are described in the hamcrest-docs/matchers:@matchers section.\n\n\u003ca id=\"x-28HAMCREST-2FPROVE-3AASSERT-THAT-20-2840ANTS-DOC-2FLOCATIVES-3AMACRO-29-29\"\u003e\u003c/a\u003e\n\n### [macro](ef78) `hamcrest/prove:assert-that` value \u0026rest matchers\n\nMain macro to test values agains matchers.\n\n\u003ca id=\"x-28HAMCREST-DOCS-2FINDEX-3A-3A-40ROADMAP-2040ANTS-DOC-2FLOCATIVES-3ASECTION-29\"\u003e\u003c/a\u003e\n\n## Roadmap\n\n* Logical matchers:\n* `any-of` – Matches if any of the given matchers evaluate to True.\n* `is-not` – Inverts the given matcher to its logical negation (think if\nwe need it, and how to show the results, here are results\nhow it works [in PyHamcrest][931c]\n– it just sees that matcher returned True and raises Assertion error with full object's content and\nmatcher's description with prepended 'not' particle).\n* Object matchers:\n* Add `hasnt-some-keys` matchers, corresponding to\n`has-some-entries`.\n* Make `has-alist-entries` work with keys other than keyword\nright now it uses `eql` to compare keys.\n* Sequence matchers:\n* `is-in` – Matches if evaluated object is present in a given sequence.\n* Other features:\n* Use uniq CommonLisp feature to restart signaled conditions to collect\nall problems with data when there are few problems with keys.\n\n\n[60ce]: #x-28HAMCREST-DOCS-2FMATCHERS-3A-3A-40MATCHERS-2040ANTS-DOC-2FLOCATIVES-3ASECTION-29\n[2b96]: http://hamcrest.org/\n[931c]: https://gist.github.com/svetlyak40wt/fbe480384e9e3f75b10523aa0b4fb6ce\n[46fe]: https://github.com/40ants/cl-hamcrest\n[3156]: https://github.com/40ants/cl-hamcrest/actions\n[b31e]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L123\n[a601]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L141\n[d4e6]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L224\n[f0a1]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L339\n[a59e]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L367\n[7747]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L408\n[408c]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L44\n[7bb6]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L450\n[f096]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L487\n[0a83]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L533\n[ac51]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L575\n[6504]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L602\n[ad36]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L645\n[8e69]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L681\n[db4f]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L76\n[b896]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L764\n[5cfe]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/matchers.lisp#L828\n[ef78]: https://github.com/40ants/cl-hamcrest/blob/cd17c96d7e6c1ee5d876ddc2bf63133862989476/src/prove.lisp#L43\n[eafb]: https://github.com/40ants/cl-hamcrest/issues\n[653f]: https://github.com/fukamachi/prove\n[8236]: https://quickdocs.org/alexandria\n[49b9]: https://quickdocs.org/cl-ppcre\n[7d7b]: https://quickdocs.org/iterate\n[d992]: https://quickdocs.org/optima\n[3dcd]: https://quickdocs.org/split-sequence\n\n* * *\n###### [generated by [40ANTS-DOC](https://40ants.com/doc/)]\n","funding_links":[],"categories":["Online editors ##"],"sub_categories":["Third-party APIs"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F40ants%2Fcl-hamcrest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2F40ants%2Fcl-hamcrest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2F40ants%2Fcl-hamcrest/lists"}