Imported Upstream version 1.8.0
SVN-Git Migration
8 years ago
0 | Full documentation: http://packages.python.org/PyHamcrest | |
1 | Latest package: http://pypi.python.org/pypi/PyHamcrest | |
2 | Latest sources: https://github.com/jonreid/PyHamcrest | |
3 | Hamcrest information: http://code.google.com/p/hamcrest | |
0 | === Version 1.8 == | |
4 | 1 | |
5 | See also: | |
6 | Objective-C version for Cocoa and iOS: https://github.com/jonreid/OCHamcrest | |
7 | Quality Coding - Tools, tips and techniques for building quality in to your iOS programs: http://jonreid.blogs.com/qualitycoding/ | |
2 | * Supported versions | |
3 | - Support for Python 2.5 and Jython 2.5 has been dropped. They may still work, but no promises. | |
4 | ||
5 | * Bug Fixes | |
6 | - [#39] is_empty was missing from the global namespace | |
7 | ||
8 | * New Features | |
9 | - Support for numpy numeric values in iscloseto (Alexander Beedie) | |
10 | - A matcher targeting exceptions and call results (Per Fagrell) | |
11 | ||
12 | === Version 1.7 == | |
13 | ||
14 | 2 Sep 2013 (Version 1.7.2) | |
15 | * Supported versions | |
16 | - As of this version, support for Python 3.1 has been dropped due to no available CI platform. | |
17 | - Added support for Python 3.3 | |
18 | ||
19 | * Bug fixes: | |
20 | - string_contains_in_order is now used in the test as it would be in an application, and is properly exported. (Romilly Cocking) | |
21 | - Fix mismatch description of containing_inanyorder (David Keijser) | |
22 | - added import of stringmatches to text/__init__.py (Eric Scheidemantle) | |
23 | - added matches_regexp to __all__ list to library/__init__.py (Eric Scheidemantle) | |
24 | ||
25 | 5 Jan 2010 (Version 1.7.1) | |
26 | * Bug fixes: | |
27 | - included a fix by jaimegildesagredo for issue #28 (has_properties was not importable) | |
28 | - included a fix by keys for contains_inanyorder | |
29 | ||
30 | 29 Dec 2012 | |
31 | (All changes by Chris Rose unless otherwise noted.) | |
32 | ||
33 | * New matchers: | |
34 | - matches_regexp matches a regular expression in a string. | |
35 | - has_properties matches an object with more than one property. | |
36 | - is_empty matches any object with length 0. | |
37 | ||
38 | * Improvements: | |
39 | - Can now do matching against old-style classes. | |
40 | - Sequence matchers handle generators, as well as actual sequences and | |
41 | pseudo-sequences. | |
42 | - README enhancements by ming13 | |
8 | 43 | |
9 | 44 | |
10 | 45 | === Version 1.6 == |
0 | 0 | Metadata-Version: 1.1 |
1 | 1 | Name: PyHamcrest |
2 | Version: 1.6 | |
2 | Version: 1.8.0 | |
3 | 3 | Summary: Hamcrest framework for matcher objects |
4 | Home-page: http://code.google.com/p/hamcrest/ | |
5 | Author: Jon Reid | |
6 | Author-email: jon.reid@mac.com | |
4 | Home-page: https://github.com/hamcrest/PyHamcrest | |
5 | Author: Chris Rose | |
6 | Author-email: offline@offby1.net | |
7 | 7 | License: New BSD |
8 | Download-URL: http://pypi.python.org/packages/source/P/PyHamcrest/PyHamcrest-1.6.tar.gz | |
9 | Description: * [Full documentation](http://packages.python.org/PyHamcrest) | |
10 | * [Latest package](http://pypi.python.org/pypi/PyHamcrest) | |
11 | * [Latest sources](https://github.com/jonreid/PyHamcrest) | |
12 | * [Hamcrest information](http://code.google.com/p/hamcrest) | |
13 | ||
14 | See also: | |
15 | ||
16 | * [OCHamcrest](https://github.com/jonreid/OCHamcrest) - Objective-C version for | |
17 | Cocoa and iOS. | |
18 | * [Quality Coding](http://jonreid.blogs.com/qualitycoding/) - Tools, tips and | |
19 | techniques for _building quality in_ to your iOS programs. | |
20 | ||
8 | Download-URL: http://pypi.python.org/packages/source/P/PyHamcrest/PyHamcrest-1.8.0.tar.gz | |
9 | Description: PyHamcrest | |
10 | ========== | |
11 | ||
12 | .. image:: https://pypip.in/v/PyHamcrest/badge.png | |
13 | :alt: Release Status | |
14 | :target: https://crate.io/packages/PyHamcrest | |
15 | .. image:: https://pypip.in/d/PyHamcrest/badge.png | |
16 | :alt: Downloads | |
17 | :target: https://crate.io/packages/PyHamcrest | |
18 | .. image:: https://travis-ci.org/hamcrest/PyHamcrest.png?branch=master | |
19 | :alt: Build Status | |
20 | :target: https://travis-ci.org/hamcrest/PyHamcrest | |
21 | 21 | |
22 | 22 | Introduction |
23 | 23 | ============ |
50 | 50 | |
51 | 51 | We'll start by writing a very simple PyUnit test, but instead of using PyUnit's |
52 | 52 | ``assertEqual`` method, we'll use PyHamcrest's ``assert_that`` construct and |
53 | the standard set of matchers:: | |
54 | ||
55 | from hamcrest import * | |
56 | import unittest | |
57 | ||
58 | class BiscuitTest(unittest.TestCase): | |
59 | def testEquals(self): | |
60 | theBiscuit = Biscuit('Ginger') | |
61 | myBiscuit = Biscuit('Ginger') | |
62 | assert_that(theBiscuit, equal_to(myBiscuit)) | |
63 | ||
64 | if __name__ == '__main__': | |
65 | unittest.main() | |
53 | the standard set of matchers: | |
54 | ||
55 | .. code:: python | |
56 | ||
57 | from hamcrest import * | |
58 | import unittest | |
59 | ||
60 | class BiscuitTest(unittest.TestCase): | |
61 | def testEquals(self): | |
62 | theBiscuit = Biscuit('Ginger') | |
63 | myBiscuit = Biscuit('Ginger') | |
64 | assert_that(theBiscuit, equal_to(myBiscuit)) | |
65 | ||
66 | if __name__ == '__main__': | |
67 | unittest.main() | |
66 | 68 | |
67 | 69 | The ``assert_that`` function is a stylized sentence for making a test |
68 | 70 | assertion. In this example, the subject of the assertion is the object |
72 | 74 | since the ``Biscuit`` class defines an ``__eq__`` method. |
73 | 75 | |
74 | 76 | If you have more than one assertion in your test you can include an identifier |
75 | for the tested value in the assertion:: | |
76 | ||
77 | assert_that(theBiscuit.getChocolateChipCount(), equal_to(10), 'chocolate chips') | |
78 | assert_that(theBiscuit.getHazelnutCount(), equal_to(3), 'hazelnuts') | |
79 | ||
80 | As a convenience, assert_that can also be used to verify a boolean condition:: | |
81 | ||
82 | assert_that(theBiscuit.isCooked(), 'cooked') | |
77 | for the tested value in the assertion: | |
78 | ||
79 | .. code:: python | |
80 | ||
81 | assert_that(theBiscuit.getChocolateChipCount(), equal_to(10), 'chocolate chips') | |
82 | assert_that(theBiscuit.getHazelnutCount(), equal_to(3), 'hazelnuts') | |
83 | ||
84 | As a convenience, assert_that can also be used to verify a boolean condition: | |
85 | ||
86 | .. code:: python | |
87 | ||
88 | assert_that(theBiscuit.isCooked(), 'cooked') | |
83 | 89 | |
84 | 90 | This is equivalent to the ``assert_`` method of unittest.TestCase, but because |
85 | 91 | it's a standalone function, it offers greater flexibility in test writing. |
92 | 98 | |
93 | 99 | * Object |
94 | 100 | |
95 | * ``equal_to`` - match equal object | |
96 | * ``has_length`` - match ``len()`` | |
97 | * ``has_property`` - match value of property with given name | |
98 | * ``has_string`` - match ``str()`` | |
99 | * ``instance_of`` - match object type | |
100 | * ``none``, ``not_none`` - match ``None``, or not ``None`` | |
101 | * ``same_instance`` - match same object | |
101 | * ``equal_to`` - match equal object | |
102 | * ``has_length`` - match ``len()`` | |
103 | * ``has_property`` - match value of property with given name | |
104 | * ``has_properties`` - match an object that has all of the given properties. | |
105 | * ``has_string`` - match ``str()`` | |
106 | * ``instance_of`` - match object type | |
107 | * ``none``, ``not_none`` - match ``None``, or not ``None`` | |
108 | * ``same_instance`` - match same object | |
102 | 109 | |
103 | 110 | * Number |
104 | 111 | |
105 | * ``close_to`` - match number close to a given value | |
106 | * ``greater_than``, ``greater_than_or_equal_to``, ``less_than``, | |
107 | ``less_than_or_equal_to`` - match numeric ordering | |
112 | * ``close_to`` - match number close to a given value | |
113 | * ``greater_than``, ``greater_than_or_equal_to``, ``less_than``, | |
114 | ``less_than_or_equal_to`` - match numeric ordering | |
108 | 115 | |
109 | 116 | * Text |
110 | 117 | |
111 | * ``contains_string`` - match part of a string | |
112 | * ``ends_with`` - match the end of a string | |
113 | * ``equal_to_ignoring_case`` - match the complete string but ignore case | |
114 | * ``equal_to_ignoring_whitespace`` - match the complete string but ignore | |
115 | extra whitespace | |
116 | * ``starts_with`` - match the beginning of a string | |
117 | * ``string_contains_in_order`` - match parts of a string, in relative order | |
118 | * ``contains_string`` - match part of a string | |
119 | * ``ends_with`` - match the end of a string | |
120 | * ``equal_to_ignoring_case`` - match the complete string but ignore case | |
121 | * ``equal_to_ignoring_whitespace`` - match the complete string but ignore extra whitespace | |
122 | * ``matches_regexp`` - match a regular expression in a string | |
123 | * ``starts_with`` - match the beginning of a string | |
124 | * ``string_contains_in_order`` - match parts of a string, in relative order | |
118 | 125 | |
119 | 126 | * Logical |
120 | 127 | |
121 | * ``all_of`` - ``and`` together all matchers | |
122 | * ``any_of`` - ``or`` together all matchers | |
123 | * ``anything`` - match anything, useful in composite matchers when you don't | |
124 | care about a particular value | |
125 | * ``is_not`` - negate the matcher | |
128 | * ``all_of`` - ``and`` together all matchers | |
129 | * ``any_of`` - ``or`` together all matchers | |
130 | * ``anything`` - match anything, useful in composite matchers when you don't care about a particular value | |
131 | * ``is_not`` - negate the matcher | |
126 | 132 | |
127 | 133 | * Sequence |
128 | 134 | |
129 | * ``contains`` - exactly match the entire sequence | |
130 | * ``contains_inanyorder`` - match the entire sequence, but in any order | |
131 | * ``has_item`` - match if given item appears in the sequence | |
132 | * ``has_items`` - match if all given items appear in the sequence, in any | |
133 | order | |
134 | * ``is_in`` - match if item appears in the given sequence | |
135 | * ``only_contains`` - match if sequence's items appear in given list | |
135 | * ``contains`` - exactly match the entire sequence | |
136 | * ``contains_inanyorder`` - match the entire sequence, but in any order | |
137 | * ``has_item`` - match if given item appears in the sequence | |
138 | * ``has_items`` - match if all given items appear in the sequence, in any order | |
139 | * ``is_in`` - match if item appears in the given sequence | |
140 | * ``only_contains`` - match if sequence's items appear in given list | |
136 | 141 | |
137 | 142 | * Dictionary |
138 | 143 | |
139 | * ``has_entries`` - match dictionary with list of key-value pairs | |
140 | * ``has_entry`` - match dictionary containing a key-value pair | |
141 | * ``has_key`` - match dictionary with a key | |
142 | * ``has_value`` - match dictionary with a value | |
144 | * ``has_entries`` - match dictionary with list of key-value pairs | |
145 | * ``has_entry`` - match dictionary containing a key-value pair | |
146 | * ``has_key`` - match dictionary with a key | |
147 | * ``has_value`` - match dictionary with a value | |
143 | 148 | |
144 | 149 | * Decorator |
145 | 150 | |
146 | * ``described_as`` - give the matcher a custom failure description | |
147 | * ``is_`` - decorator to improve readability - see `Syntactic sugar` below | |
151 | * ``calling`` - wrap a callable in a deffered object, for subsequent matching on calling behaviour | |
152 | * ``raises`` - Ensure that a deferred callable raises as expected | |
153 | * ``described_as`` - give the matcher a custom failure description | |
154 | * ``is_`` - decorator to improve readability - see `Syntactic sugar` below | |
148 | 155 | |
149 | 156 | The arguments for many of these matchers accept not just a matching value, but |
150 | 157 | another matcher, so matchers can be composed for greater flexibility. For |
157 | 164 | |
158 | 165 | PyHamcrest strives to make your tests as readable as possible. For example, the |
159 | 166 | ``is_`` matcher is a wrapper that doesn't add any extra behavior to the |
160 | underlying matcher. The following assertions are all equivalent:: | |
161 | ||
162 | assert_that(theBiscuit, equal_to(myBiscuit)) | |
163 | assert_that(theBiscuit, is_(equal_to(myBiscuit))) | |
164 | assert_that(theBiscuit, is_(myBiscuit)) | |
167 | underlying matcher. The following assertions are all equivalent: | |
168 | ||
169 | .. code:: python | |
170 | ||
171 | assert_that(theBiscuit, equal_to(myBiscuit)) | |
172 | assert_that(theBiscuit, is_(equal_to(myBiscuit))) | |
173 | assert_that(theBiscuit, is_(myBiscuit)) | |
165 | 174 | |
166 | 175 | The last form is allowed since ``is_(value)`` wraps most non-matcher arguments |
167 | 176 | with ``equal_to``. But if the argument is a type, it is wrapped with |
168 | ``instance_of``, so the following are also equivalent:: | |
169 | ||
170 | assert_that(theBiscuit, instance_of(Biscuit)) | |
171 | assert_that(theBiscuit, is_(instance_of(Biscuit))) | |
172 | assert_that(theBiscuit, is_(Biscuit)) | |
177 | ``instance_of``, so the following are also equivalent: | |
178 | ||
179 | .. code:: python | |
180 | ||
181 | assert_that(theBiscuit, instance_of(Biscuit)) | |
182 | assert_that(theBiscuit, is_(instance_of(Biscuit))) | |
183 | assert_that(theBiscuit, is_(Biscuit)) | |
173 | 184 | |
174 | 185 | *Note that PyHamcrest's ``is_`` matcher is unrelated to Python's ``is`` |
175 | 186 | operator. The matcher for object identity is ``same_instance``.* |
186 | 197 | eliminate code duplication and make your tests more readable! |
187 | 198 | |
188 | 199 | Let's write our own matcher for testing if a calendar date falls on a Saturday. |
189 | This is the test we want to write:: | |
190 | ||
191 | def testDateIsOnASaturday(self): | |
192 | d = datetime.date(2008, 04, 26) | |
193 | assert_that(d, is_(on_a_saturday())) | |
194 | ||
195 | And here's the implementation:: | |
196 | ||
197 | from hamcrest.core.base_matcher import BaseMatcher | |
198 | from hamcrest.core.helpers.hasmethod import hasmethod | |
199 | ||
200 | class IsGivenDayOfWeek(BaseMatcher): | |
201 | ||
202 | def __init__(self, day): | |
203 | self.day = day # Monday is 0, Sunday is 6 | |
204 | ||
205 | def _matches(self, item): | |
206 | if not hasmethod(item, 'weekday'): | |
207 | return False | |
208 | return item.weekday() == self.day | |
209 | ||
210 | def describe_to(self, description): | |
211 | day_as_string = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', | |
212 | 'Friday', 'Saturday', 'Sunday'] | |
213 | description.append_text('calendar date falling on ') \ | |
214 | .append_text(day_as_string[self.day]) | |
215 | ||
216 | def on_a_saturday(): | |
217 | return IsGivenDayOfWeek(5) | |
200 | This is the test we want to write: | |
201 | ||
202 | .. code:: python | |
203 | ||
204 | def testDateIsOnASaturday(self): | |
205 | d = datetime.date(2008, 04, 26) | |
206 | assert_that(d, is_(on_a_saturday())) | |
207 | ||
208 | And here's the implementation: | |
209 | ||
210 | .. code:: python | |
211 | ||
212 | from hamcrest.core.base_matcher import BaseMatcher | |
213 | from hamcrest.core.helpers.hasmethod import hasmethod | |
214 | ||
215 | class IsGivenDayOfWeek(BaseMatcher): | |
216 | ||
217 | def __init__(self, day): | |
218 | self.day = day # Monday is 0, Sunday is 6 | |
219 | ||
220 | def _matches(self, item): | |
221 | if not hasmethod(item, 'weekday'): | |
222 | return False | |
223 | return item.weekday() == self.day | |
224 | ||
225 | def describe_to(self, description): | |
226 | day_as_string = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', | |
227 | 'Friday', 'Saturday', 'Sunday'] | |
228 | description.append_text('calendar date falling on ') \ | |
229 | .append_text(day_as_string[self.day]) | |
230 | ||
231 | def on_a_saturday(): | |
232 | return IsGivenDayOfWeek(5) | |
218 | 233 | |
219 | 234 | For our Matcher implementation we implement the ``_matches`` method - which |
220 | 235 | calls the ``weekday`` method after confirming that the argument (which may not |
221 | 236 | be a date) has such a method - and the ``describe_to`` method - which is used |
222 | 237 | to produce a failure message when a test fails. Here's an example of how the |
223 | failure message looks:: | |
224 | ||
225 | assert_that(datetime.date(2008, 04, 06), is_(on_a_saturday())) | |
238 | failure message looks: | |
239 | ||
240 | .. code:: python | |
241 | ||
242 | assert_that(datetime.date(2008, 04, 06), is_(on_a_saturday())) | |
226 | 243 | |
227 | 244 | fails with the message:: |
228 | 245 | |
229 | AssertionError: | |
230 | Expected: is calendar date falling on Saturday | |
231 | got: <2008-04-06> | |
246 | AssertionError: | |
247 | Expected: is calendar date falling on Saturday | |
248 | got: <2008-04-06> | |
232 | 249 | |
233 | 250 | Let's say this matcher is saved in a module named ``isgivendayofweek``. We |
234 | could use it in our test by importing the factory function ``on_a_saturday``:: | |
235 | ||
236 | from hamcrest import * | |
237 | import unittest | |
238 | from isgivendayofweek import on_a_saturday | |
239 | ||
240 | class DateTest(unittest.TestCase): | |
241 | def testDateIsOnASaturday(self): | |
242 | d = datetime.date(2008, 04, 26) | |
243 | assert_that(d, is_(on_a_saturday())) | |
244 | ||
245 | if __name__ == '__main__': | |
246 | unittest.main() | |
251 | could use it in our test by importing the factory function ``on_a_saturday``: | |
252 | ||
253 | .. code:: python | |
254 | ||
255 | from hamcrest import * | |
256 | import unittest | |
257 | from isgivendayofweek import on_a_saturday | |
258 | ||
259 | class DateTest(unittest.TestCase): | |
260 | def testDateIsOnASaturday(self): | |
261 | d = datetime.date(2008, 04, 26) | |
262 | assert_that(d, is_(on_a_saturday())) | |
263 | ||
264 | if __name__ == '__main__': | |
265 | unittest.main() | |
247 | 266 | |
248 | 267 | Even though the ``on_a_saturday`` function creates a new matcher each time it |
249 | 268 | is called, you should not assume this is the only usage pattern for your |
250 | 269 | matcher. Therefore you should make sure your matcher is stateless, so a single |
251 | 270 | instance can be reused between matches. |
271 | ||
272 | ||
273 | More resources | |
274 | ============== | |
275 | ||
276 | * Documentation_ | |
277 | * Package_ | |
278 | * Sources_ | |
279 | * Hamcrest_ | |
280 | ||
281 | .. _Documentation: http://readthedocs.org/docs/pyhamcrest/en/V1.7.1/ | |
282 | .. _Package: http://pypi.python.org/pypi/PyHamcrest | |
283 | .. _Sources: https://github.com/hamcrest/PyHamcrest | |
284 | .. _Hamcrest: http://hamcrest.org | |
252 | 285 | |
253 | 286 | Keywords: hamcrest matchers pyunit unit test testing unittest unittesting |
254 | 287 | Platform: All |
261 | 294 | Classifier: Programming Language :: Python :: 2.5 |
262 | 295 | Classifier: Programming Language :: Python :: 2.6 |
263 | 296 | Classifier: Programming Language :: Python :: 2.7 |
264 | Classifier: Programming Language :: Python :: 3.1 | |
265 | 297 | Classifier: Programming Language :: Python :: 3.2 |
298 | Classifier: Programming Language :: Python :: 3.3 | |
266 | 299 | Classifier: Topic :: Software Development |
267 | 300 | Classifier: Topic :: Software Development :: Quality Assurance |
268 | 301 | Classifier: Topic :: Software Development :: Testing |
0 | Metadata-Version: 1.1 | |
1 | Name: PyHamcrest | |
2 | Version: 1.6 | |
3 | Summary: Hamcrest framework for matcher objects | |
4 | Home-page: http://code.google.com/p/hamcrest/ | |
5 | Author: Jon Reid | |
6 | Author-email: jon.reid@mac.com | |
7 | License: New BSD | |
8 | Download-URL: http://pypi.python.org/packages/source/P/PyHamcrest/PyHamcrest-1.6.tar.gz | |
9 | Description: * [Full documentation](http://packages.python.org/PyHamcrest) | |
10 | * [Latest package](http://pypi.python.org/pypi/PyHamcrest) | |
11 | * [Latest sources](https://github.com/jonreid/PyHamcrest) | |
12 | * [Hamcrest information](http://code.google.com/p/hamcrest) | |
13 | ||
14 | See also: | |
15 | ||
16 | * [OCHamcrest](https://github.com/jonreid/OCHamcrest) - Objective-C version for | |
17 | Cocoa and iOS. | |
18 | * [Quality Coding](http://jonreid.blogs.com/qualitycoding/) - Tools, tips and | |
19 | techniques for _building quality in_ to your iOS programs. | |
20 | ||
21 | ||
22 | Introduction | |
23 | ============ | |
24 | ||
25 | PyHamcrest is a framework for writing matcher objects, allowing you to | |
26 | declaratively define "match" rules. There are a number of situations where | |
27 | matchers are invaluable, such as UI validation, or data filtering, but it is in | |
28 | the area of writing flexible tests that matchers are most commonly used. This | |
29 | tutorial shows you how to use PyHamcrest for unit testing. | |
30 | ||
31 | When writing tests it is sometimes difficult to get the balance right between | |
32 | overspecifying the test (and making it brittle to changes), and not specifying | |
33 | enough (making the test less valuable since it continues to pass even when the | |
34 | thing being tested is broken). Having a tool that allows you to pick out | |
35 | precisely the aspect under test and describe the values it should have, to a | |
36 | controlled level of precision, helps greatly in writing tests that are "just | |
37 | right." Such tests fail when the behavior of the aspect under test deviates | |
38 | from the expected behavior, yet continue to pass when minor, unrelated changes | |
39 | to the behaviour are made. | |
40 | ||
41 | Installation | |
42 | ============ | |
43 | ||
44 | Hamcrest can be installed using the usual Python packaging tools. It depends on | |
45 | distribute, but as long as you have a network connection when you install, the | |
46 | installation process will take care of that for you. | |
47 | ||
48 | My first PyHamcrest test | |
49 | ======================== | |
50 | ||
51 | We'll start by writing a very simple PyUnit test, but instead of using PyUnit's | |
52 | ``assertEqual`` method, we'll use PyHamcrest's ``assert_that`` construct and | |
53 | the standard set of matchers:: | |
54 | ||
55 | from hamcrest import * | |
56 | import unittest | |
57 | ||
58 | class BiscuitTest(unittest.TestCase): | |
59 | def testEquals(self): | |
60 | theBiscuit = Biscuit('Ginger') | |
61 | myBiscuit = Biscuit('Ginger') | |
62 | assert_that(theBiscuit, equal_to(myBiscuit)) | |
63 | ||
64 | if __name__ == '__main__': | |
65 | unittest.main() | |
66 | ||
67 | The ``assert_that`` function is a stylized sentence for making a test | |
68 | assertion. In this example, the subject of the assertion is the object | |
69 | ``theBiscuit``, which is the first method parameter. The second method | |
70 | parameter is a matcher for ``Biscuit`` objects, here a matcher that checks one | |
71 | object is equal to another using the Python ``==`` operator. The test passes | |
72 | since the ``Biscuit`` class defines an ``__eq__`` method. | |
73 | ||
74 | If you have more than one assertion in your test you can include an identifier | |
75 | for the tested value in the assertion:: | |
76 | ||
77 | assert_that(theBiscuit.getChocolateChipCount(), equal_to(10), 'chocolate chips') | |
78 | assert_that(theBiscuit.getHazelnutCount(), equal_to(3), 'hazelnuts') | |
79 | ||
80 | As a convenience, assert_that can also be used to verify a boolean condition:: | |
81 | ||
82 | assert_that(theBiscuit.isCooked(), 'cooked') | |
83 | ||
84 | This is equivalent to the ``assert_`` method of unittest.TestCase, but because | |
85 | it's a standalone function, it offers greater flexibility in test writing. | |
86 | ||
87 | ||
88 | Predefined matchers | |
89 | =================== | |
90 | ||
91 | PyHamcrest comes with a library of useful matchers: | |
92 | ||
93 | * Object | |
94 | ||
95 | * ``equal_to`` - match equal object | |
96 | * ``has_length`` - match ``len()`` | |
97 | * ``has_property`` - match value of property with given name | |
98 | * ``has_string`` - match ``str()`` | |
99 | * ``instance_of`` - match object type | |
100 | * ``none``, ``not_none`` - match ``None``, or not ``None`` | |
101 | * ``same_instance`` - match same object | |
102 | ||
103 | * Number | |
104 | ||
105 | * ``close_to`` - match number close to a given value | |
106 | * ``greater_than``, ``greater_than_or_equal_to``, ``less_than``, | |
107 | ``less_than_or_equal_to`` - match numeric ordering | |
108 | ||
109 | * Text | |
110 | ||
111 | * ``contains_string`` - match part of a string | |
112 | * ``ends_with`` - match the end of a string | |
113 | * ``equal_to_ignoring_case`` - match the complete string but ignore case | |
114 | * ``equal_to_ignoring_whitespace`` - match the complete string but ignore | |
115 | extra whitespace | |
116 | * ``starts_with`` - match the beginning of a string | |
117 | * ``string_contains_in_order`` - match parts of a string, in relative order | |
118 | ||
119 | * Logical | |
120 | ||
121 | * ``all_of`` - ``and`` together all matchers | |
122 | * ``any_of`` - ``or`` together all matchers | |
123 | * ``anything`` - match anything, useful in composite matchers when you don't | |
124 | care about a particular value | |
125 | * ``is_not`` - negate the matcher | |
126 | ||
127 | * Sequence | |
128 | ||
129 | * ``contains`` - exactly match the entire sequence | |
130 | * ``contains_inanyorder`` - match the entire sequence, but in any order | |
131 | * ``has_item`` - match if given item appears in the sequence | |
132 | * ``has_items`` - match if all given items appear in the sequence, in any | |
133 | order | |
134 | * ``is_in`` - match if item appears in the given sequence | |
135 | * ``only_contains`` - match if sequence's items appear in given list | |
136 | ||
137 | * Dictionary | |
138 | ||
139 | * ``has_entries`` - match dictionary with list of key-value pairs | |
140 | * ``has_entry`` - match dictionary containing a key-value pair | |
141 | * ``has_key`` - match dictionary with a key | |
142 | * ``has_value`` - match dictionary with a value | |
143 | ||
144 | * Decorator | |
145 | ||
146 | * ``described_as`` - give the matcher a custom failure description | |
147 | * ``is_`` - decorator to improve readability - see `Syntactic sugar` below | |
148 | ||
149 | The arguments for many of these matchers accept not just a matching value, but | |
150 | another matcher, so matchers can be composed for greater flexibility. For | |
151 | example, ``only_contains(less_than(5))`` will match any sequence where every | |
152 | item is less than 5. | |
153 | ||
154 | ||
155 | Syntactic sugar | |
156 | =============== | |
157 | ||
158 | PyHamcrest strives to make your tests as readable as possible. For example, the | |
159 | ``is_`` matcher is a wrapper that doesn't add any extra behavior to the | |
160 | underlying matcher. The following assertions are all equivalent:: | |
161 | ||
162 | assert_that(theBiscuit, equal_to(myBiscuit)) | |
163 | assert_that(theBiscuit, is_(equal_to(myBiscuit))) | |
164 | assert_that(theBiscuit, is_(myBiscuit)) | |
165 | ||
166 | The last form is allowed since ``is_(value)`` wraps most non-matcher arguments | |
167 | with ``equal_to``. But if the argument is a type, it is wrapped with | |
168 | ``instance_of``, so the following are also equivalent:: | |
169 | ||
170 | assert_that(theBiscuit, instance_of(Biscuit)) | |
171 | assert_that(theBiscuit, is_(instance_of(Biscuit))) | |
172 | assert_that(theBiscuit, is_(Biscuit)) | |
173 | ||
174 | *Note that PyHamcrest's ``is_`` matcher is unrelated to Python's ``is`` | |
175 | operator. The matcher for object identity is ``same_instance``.* | |
176 | ||
177 | ||
178 | Writing custom matchers | |
179 | ======================= | |
180 | ||
181 | PyHamcrest comes bundled with lots of useful matchers, but you'll probably find | |
182 | that you need to create your own from time to time to fit your testing needs. | |
183 | This commonly occurs when you find a fragment of code that tests the same set | |
184 | of properties over and over again (and in different tests), and you want to | |
185 | bundle the fragment into a single assertion. By writing your own matcher you'll | |
186 | eliminate code duplication and make your tests more readable! | |
187 | ||
188 | Let's write our own matcher for testing if a calendar date falls on a Saturday. | |
189 | This is the test we want to write:: | |
190 | ||
191 | def testDateIsOnASaturday(self): | |
192 | d = datetime.date(2008, 04, 26) | |
193 | assert_that(d, is_(on_a_saturday())) | |
194 | ||
195 | And here's the implementation:: | |
196 | ||
197 | from hamcrest.core.base_matcher import BaseMatcher | |
198 | from hamcrest.core.helpers.hasmethod import hasmethod | |
199 | ||
200 | class IsGivenDayOfWeek(BaseMatcher): | |
201 | ||
202 | def __init__(self, day): | |
203 | self.day = day # Monday is 0, Sunday is 6 | |
204 | ||
205 | def _matches(self, item): | |
206 | if not hasmethod(item, 'weekday'): | |
207 | return False | |
208 | return item.weekday() == self.day | |
209 | ||
210 | def describe_to(self, description): | |
211 | day_as_string = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', | |
212 | 'Friday', 'Saturday', 'Sunday'] | |
213 | description.append_text('calendar date falling on ') \ | |
214 | .append_text(day_as_string[self.day]) | |
215 | ||
216 | def on_a_saturday(): | |
217 | return IsGivenDayOfWeek(5) | |
218 | ||
219 | For our Matcher implementation we implement the ``_matches`` method - which | |
220 | calls the ``weekday`` method after confirming that the argument (which may not | |
221 | be a date) has such a method - and the ``describe_to`` method - which is used | |
222 | to produce a failure message when a test fails. Here's an example of how the | |
223 | failure message looks:: | |
224 | ||
225 | assert_that(datetime.date(2008, 04, 06), is_(on_a_saturday())) | |
226 | ||
227 | fails with the message:: | |
228 | ||
229 | AssertionError: | |
230 | Expected: is calendar date falling on Saturday | |
231 | got: <2008-04-06> | |
232 | ||
233 | Let's say this matcher is saved in a module named ``isgivendayofweek``. We | |
234 | could use it in our test by importing the factory function ``on_a_saturday``:: | |
235 | ||
236 | from hamcrest import * | |
237 | import unittest | |
238 | from isgivendayofweek import on_a_saturday | |
239 | ||
240 | class DateTest(unittest.TestCase): | |
241 | def testDateIsOnASaturday(self): | |
242 | d = datetime.date(2008, 04, 26) | |
243 | assert_that(d, is_(on_a_saturday())) | |
244 | ||
245 | if __name__ == '__main__': | |
246 | unittest.main() | |
247 | ||
248 | Even though the ``on_a_saturday`` function creates a new matcher each time it | |
249 | is called, you should not assume this is the only usage pattern for your | |
250 | matcher. Therefore you should make sure your matcher is stateless, so a single | |
251 | instance can be reused between matches. | |
252 | ||
253 | Keywords: hamcrest matchers pyunit unit test testing unittest unittesting | |
254 | Platform: All | |
255 | Classifier: Development Status :: 5 - Production/Stable | |
256 | Classifier: Environment :: Console | |
257 | Classifier: Intended Audience :: Developers | |
258 | Classifier: License :: OSI Approved :: BSD License | |
259 | Classifier: Natural Language :: English | |
260 | Classifier: Operating System :: OS Independent | |
261 | Classifier: Programming Language :: Python :: 2.5 | |
262 | Classifier: Programming Language :: Python :: 2.6 | |
263 | Classifier: Programming Language :: Python :: 2.7 | |
264 | Classifier: Programming Language :: Python :: 3.1 | |
265 | Classifier: Programming Language :: Python :: 3.2 | |
266 | Classifier: Topic :: Software Development | |
267 | Classifier: Topic :: Software Development :: Quality Assurance | |
268 | Classifier: Topic :: Software Development :: Testing | |
269 | Provides: hamcrest |
0 | CHANGES.txt | |
1 | LICENSE.txt | |
2 | MANIFEST.in | |
3 | README.md | |
4 | setup.cfg | |
5 | setup.py | |
6 | PyHamcrest.egg-info/PKG-INFO | |
7 | PyHamcrest.egg-info/SOURCES.txt | |
8 | PyHamcrest.egg-info/dependency_links.txt | |
9 | PyHamcrest.egg-info/requires.txt | |
10 | PyHamcrest.egg-info/top_level.txt | |
11 | examples/CustomDateMatcher.py | |
12 | examples/ExampleWithAssertThat.py | |
13 | hamcrest/__init__.py | |
14 | hamcrest/core/__init__.py | |
15 | hamcrest/core/assert_that.py | |
16 | hamcrest/core/base_description.py | |
17 | hamcrest/core/base_matcher.py | |
18 | hamcrest/core/description.py | |
19 | hamcrest/core/matcher.py | |
20 | hamcrest/core/selfdescribing.py | |
21 | hamcrest/core/selfdescribingvalue.py | |
22 | hamcrest/core/string_description.py | |
23 | hamcrest/core/core/__init__.py | |
24 | hamcrest/core/core/allof.py | |
25 | hamcrest/core/core/anyof.py | |
26 | hamcrest/core/core/described_as.py | |
27 | hamcrest/core/core/is_.py | |
28 | hamcrest/core/core/isanything.py | |
29 | hamcrest/core/core/isequal.py | |
30 | hamcrest/core/core/isinstanceof.py | |
31 | hamcrest/core/core/isnone.py | |
32 | hamcrest/core/core/isnot.py | |
33 | hamcrest/core/core/issame.py | |
34 | hamcrest/core/helpers/__init__.py | |
35 | hamcrest/core/helpers/hasmethod.py | |
36 | hamcrest/core/helpers/wrap_matcher.py | |
37 | hamcrest/library/__init__.py | |
38 | hamcrest/library/collection/__init__.py | |
39 | hamcrest/library/collection/isdict_containing.py | |
40 | hamcrest/library/collection/isdict_containingentries.py | |
41 | hamcrest/library/collection/isdict_containingkey.py | |
42 | hamcrest/library/collection/isdict_containingvalue.py | |
43 | hamcrest/library/collection/isin.py | |
44 | hamcrest/library/collection/issequence_containing.py | |
45 | hamcrest/library/collection/issequence_containinginanyorder.py | |
46 | hamcrest/library/collection/issequence_containinginorder.py | |
47 | hamcrest/library/collection/issequence_onlycontaining.py | |
48 | hamcrest/library/integration/__init__.py | |
49 | hamcrest/library/integration/match_equality.py | |
50 | hamcrest/library/number/__init__.py | |
51 | hamcrest/library/number/iscloseto.py | |
52 | hamcrest/library/number/ordering_comparison.py | |
53 | hamcrest/library/object/__init__.py | |
54 | hamcrest/library/object/haslength.py | |
55 | hamcrest/library/object/hasproperty.py | |
56 | hamcrest/library/object/hasstring.py | |
57 | hamcrest/library/text/__init__.py | |
58 | hamcrest/library/text/isequal_ignoring_case.py | |
59 | hamcrest/library/text/isequal_ignoring_whitespace.py | |
60 | hamcrest/library/text/stringcontains.py | |
61 | hamcrest/library/text/stringcontainsinorder.py | |
62 | hamcrest/library/text/stringendswith.py | |
63 | hamcrest/library/text/stringstartswith.py | |
64 | hamcrest/library/text/substringmatcher.py | |
65 | hamcrest_unit_test/__init__.py | |
66 | hamcrest_unit_test/alltests.py | |
67 | hamcrest_unit_test/assert_that_test.py | |
68 | hamcrest_unit_test/base_matcher_test.py | |
69 | hamcrest_unit_test/matcher_test.py | |
70 | hamcrest_unit_test/object_import.py | |
71 | hamcrest_unit_test/string_description_test.py | |
72 | hamcrest_unit_test/collection/__init__.py | |
73 | hamcrest_unit_test/collection/isdict_containing_test.py | |
74 | hamcrest_unit_test/collection/isdict_containingentries_test.py | |
75 | hamcrest_unit_test/collection/isdict_containingkey_test.py | |
76 | hamcrest_unit_test/collection/isdict_containingvalue_test.py | |
77 | hamcrest_unit_test/collection/isin_test.py | |
78 | hamcrest_unit_test/collection/issequence_containing_test.py | |
79 | hamcrest_unit_test/collection/issequence_containinginanyorder_test.py | |
80 | hamcrest_unit_test/collection/issequence_containinginorder_test.py | |
81 | hamcrest_unit_test/collection/issequence_onlycontaining_test.py | |
82 | hamcrest_unit_test/collection/quasidict.py | |
83 | hamcrest_unit_test/collection/quasisequence.py | |
84 | hamcrest_unit_test/core/__init__.py | |
85 | hamcrest_unit_test/core/allof_test.py | |
86 | hamcrest_unit_test/core/anyof_test.py | |
87 | hamcrest_unit_test/core/described_as_test.py | |
88 | hamcrest_unit_test/core/is_test.py | |
89 | hamcrest_unit_test/core/isanything_test.py | |
90 | hamcrest_unit_test/core/isequal_test.py | |
91 | hamcrest_unit_test/core/isinstanceof_test.py | |
92 | hamcrest_unit_test/core/isnone_test.py | |
93 | hamcrest_unit_test/core/isnot_test.py | |
94 | hamcrest_unit_test/core/issame_test.py | |
95 | hamcrest_unit_test/core/nevermatch.py | |
96 | hamcrest_unit_test/integration/__init__.py | |
97 | hamcrest_unit_test/integration/match_equality_test.py | |
98 | hamcrest_unit_test/number/__init__.py | |
99 | hamcrest_unit_test/number/iscloseto_test.py | |
100 | hamcrest_unit_test/number/ordering_comparison_test.py | |
101 | hamcrest_unit_test/object/__init__.py | |
102 | hamcrest_unit_test/object/haslength_test.py | |
103 | hamcrest_unit_test/object/hasproperty_test.py | |
104 | hamcrest_unit_test/object/hasstring_test.py | |
105 | hamcrest_unit_test/text/__init__.py | |
106 | hamcrest_unit_test/text/isequal_ignoring_case_test.py | |
107 | hamcrest_unit_test/text/isequal_ignoring_whitespace_test.py | |
108 | hamcrest_unit_test/text/stringcontains_test.py | |
109 | hamcrest_unit_test/text/stringcontainsinorder_test.py | |
110 | hamcrest_unit_test/text/stringendswith_test.py | |
111 | hamcrest_unit_test/text/stringstartswith_test.py⏎ |
0 | * [Full documentation](http://packages.python.org/PyHamcrest) | |
1 | * [Latest package](http://pypi.python.org/pypi/PyHamcrest) | |
2 | * [Latest sources](https://github.com/jonreid/PyHamcrest) | |
3 | * [Hamcrest information](http://code.google.com/p/hamcrest) | |
4 | ||
5 | See also: | |
6 | ||
7 | * [OCHamcrest](https://github.com/jonreid/OCHamcrest) - Objective-C version for | |
8 | Cocoa and iOS. | |
9 | * [Quality Coding](http://jonreid.blogs.com/qualitycoding/) - Tools, tips and | |
10 | techniques for _building quality in_ to your iOS programs. | |
11 | ||
12 | ||
13 | Introduction | |
14 | ============ | |
15 | ||
16 | PyHamcrest is a framework for writing matcher objects, allowing you to | |
17 | declaratively define "match" rules. There are a number of situations where | |
18 | matchers are invaluable, such as UI validation, or data filtering, but it is in | |
19 | the area of writing flexible tests that matchers are most commonly used. This | |
20 | tutorial shows you how to use PyHamcrest for unit testing. | |
21 | ||
22 | When writing tests it is sometimes difficult to get the balance right between | |
23 | overspecifying the test (and making it brittle to changes), and not specifying | |
24 | enough (making the test less valuable since it continues to pass even when the | |
25 | thing being tested is broken). Having a tool that allows you to pick out | |
26 | precisely the aspect under test and describe the values it should have, to a | |
27 | controlled level of precision, helps greatly in writing tests that are "just | |
28 | right." Such tests fail when the behavior of the aspect under test deviates | |
29 | from the expected behavior, yet continue to pass when minor, unrelated changes | |
30 | to the behaviour are made. | |
31 | ||
32 | Installation | |
33 | ============ | |
34 | ||
35 | Hamcrest can be installed using the usual Python packaging tools. It depends on | |
36 | distribute, but as long as you have a network connection when you install, the | |
37 | installation process will take care of that for you. | |
38 | ||
39 | My first PyHamcrest test | |
40 | ======================== | |
41 | ||
42 | We'll start by writing a very simple PyUnit test, but instead of using PyUnit's | |
43 | ``assertEqual`` method, we'll use PyHamcrest's ``assert_that`` construct and | |
44 | the standard set of matchers:: | |
45 | ||
46 | from hamcrest import * | |
47 | import unittest | |
48 | ||
49 | class BiscuitTest(unittest.TestCase): | |
50 | def testEquals(self): | |
51 | theBiscuit = Biscuit('Ginger') | |
52 | myBiscuit = Biscuit('Ginger') | |
53 | assert_that(theBiscuit, equal_to(myBiscuit)) | |
54 | ||
55 | if __name__ == '__main__': | |
56 | unittest.main() | |
57 | ||
58 | The ``assert_that`` function is a stylized sentence for making a test | |
59 | assertion. In this example, the subject of the assertion is the object | |
60 | ``theBiscuit``, which is the first method parameter. The second method | |
61 | parameter is a matcher for ``Biscuit`` objects, here a matcher that checks one | |
62 | object is equal to another using the Python ``==`` operator. The test passes | |
63 | since the ``Biscuit`` class defines an ``__eq__`` method. | |
64 | ||
65 | If you have more than one assertion in your test you can include an identifier | |
66 | for the tested value in the assertion:: | |
67 | ||
68 | assert_that(theBiscuit.getChocolateChipCount(), equal_to(10), 'chocolate chips') | |
69 | assert_that(theBiscuit.getHazelnutCount(), equal_to(3), 'hazelnuts') | |
70 | ||
71 | As a convenience, assert_that can also be used to verify a boolean condition:: | |
72 | ||
73 | assert_that(theBiscuit.isCooked(), 'cooked') | |
74 | ||
75 | This is equivalent to the ``assert_`` method of unittest.TestCase, but because | |
76 | it's a standalone function, it offers greater flexibility in test writing. | |
77 | ||
78 | ||
79 | Predefined matchers | |
80 | =================== | |
81 | ||
82 | PyHamcrest comes with a library of useful matchers: | |
83 | ||
84 | * Object | |
85 | ||
86 | * ``equal_to`` - match equal object | |
87 | * ``has_length`` - match ``len()`` | |
88 | * ``has_property`` - match value of property with given name | |
89 | * ``has_string`` - match ``str()`` | |
90 | * ``instance_of`` - match object type | |
91 | * ``none``, ``not_none`` - match ``None``, or not ``None`` | |
92 | * ``same_instance`` - match same object | |
93 | ||
94 | * Number | |
95 | ||
96 | * ``close_to`` - match number close to a given value | |
97 | * ``greater_than``, ``greater_than_or_equal_to``, ``less_than``, | |
98 | ``less_than_or_equal_to`` - match numeric ordering | |
99 | ||
100 | * Text | |
101 | ||
102 | * ``contains_string`` - match part of a string | |
103 | * ``ends_with`` - match the end of a string | |
104 | * ``equal_to_ignoring_case`` - match the complete string but ignore case | |
105 | * ``equal_to_ignoring_whitespace`` - match the complete string but ignore | |
106 | extra whitespace | |
107 | * ``starts_with`` - match the beginning of a string | |
108 | * ``string_contains_in_order`` - match parts of a string, in relative order | |
109 | ||
110 | * Logical | |
111 | ||
112 | * ``all_of`` - ``and`` together all matchers | |
113 | * ``any_of`` - ``or`` together all matchers | |
114 | * ``anything`` - match anything, useful in composite matchers when you don't | |
115 | care about a particular value | |
116 | * ``is_not`` - negate the matcher | |
117 | ||
118 | * Sequence | |
119 | ||
120 | * ``contains`` - exactly match the entire sequence | |
121 | * ``contains_inanyorder`` - match the entire sequence, but in any order | |
122 | * ``has_item`` - match if given item appears in the sequence | |
123 | * ``has_items`` - match if all given items appear in the sequence, in any | |
124 | order | |
125 | * ``is_in`` - match if item appears in the given sequence | |
126 | * ``only_contains`` - match if sequence's items appear in given list | |
127 | ||
128 | * Dictionary | |
129 | ||
130 | * ``has_entries`` - match dictionary with list of key-value pairs | |
131 | * ``has_entry`` - match dictionary containing a key-value pair | |
132 | * ``has_key`` - match dictionary with a key | |
133 | * ``has_value`` - match dictionary with a value | |
134 | ||
135 | * Decorator | |
136 | ||
137 | * ``described_as`` - give the matcher a custom failure description | |
138 | * ``is_`` - decorator to improve readability - see `Syntactic sugar` below | |
139 | ||
140 | The arguments for many of these matchers accept not just a matching value, but | |
141 | another matcher, so matchers can be composed for greater flexibility. For | |
142 | example, ``only_contains(less_than(5))`` will match any sequence where every | |
143 | item is less than 5. | |
144 | ||
145 | ||
146 | Syntactic sugar | |
147 | =============== | |
148 | ||
149 | PyHamcrest strives to make your tests as readable as possible. For example, the | |
150 | ``is_`` matcher is a wrapper that doesn't add any extra behavior to the | |
151 | underlying matcher. The following assertions are all equivalent:: | |
152 | ||
153 | assert_that(theBiscuit, equal_to(myBiscuit)) | |
154 | assert_that(theBiscuit, is_(equal_to(myBiscuit))) | |
155 | assert_that(theBiscuit, is_(myBiscuit)) | |
156 | ||
157 | The last form is allowed since ``is_(value)`` wraps most non-matcher arguments | |
158 | with ``equal_to``. But if the argument is a type, it is wrapped with | |
159 | ``instance_of``, so the following are also equivalent:: | |
160 | ||
161 | assert_that(theBiscuit, instance_of(Biscuit)) | |
162 | assert_that(theBiscuit, is_(instance_of(Biscuit))) | |
163 | assert_that(theBiscuit, is_(Biscuit)) | |
164 | ||
165 | *Note that PyHamcrest's ``is_`` matcher is unrelated to Python's ``is`` | |
166 | operator. The matcher for object identity is ``same_instance``.* | |
167 | ||
168 | ||
169 | Writing custom matchers | |
170 | ======================= | |
171 | ||
172 | PyHamcrest comes bundled with lots of useful matchers, but you'll probably find | |
173 | that you need to create your own from time to time to fit your testing needs. | |
174 | This commonly occurs when you find a fragment of code that tests the same set | |
175 | of properties over and over again (and in different tests), and you want to | |
176 | bundle the fragment into a single assertion. By writing your own matcher you'll | |
177 | eliminate code duplication and make your tests more readable! | |
178 | ||
179 | Let's write our own matcher for testing if a calendar date falls on a Saturday. | |
180 | This is the test we want to write:: | |
181 | ||
182 | def testDateIsOnASaturday(self): | |
183 | d = datetime.date(2008, 04, 26) | |
184 | assert_that(d, is_(on_a_saturday())) | |
185 | ||
186 | And here's the implementation:: | |
187 | ||
188 | from hamcrest.core.base_matcher import BaseMatcher | |
189 | from hamcrest.core.helpers.hasmethod import hasmethod | |
190 | ||
191 | class IsGivenDayOfWeek(BaseMatcher): | |
192 | ||
193 | def __init__(self, day): | |
194 | self.day = day # Monday is 0, Sunday is 6 | |
195 | ||
196 | def _matches(self, item): | |
197 | if not hasmethod(item, 'weekday'): | |
198 | return False | |
199 | return item.weekday() == self.day | |
200 | ||
201 | def describe_to(self, description): | |
202 | day_as_string = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', | |
203 | 'Friday', 'Saturday', 'Sunday'] | |
204 | description.append_text('calendar date falling on ') \ | |
205 | .append_text(day_as_string[self.day]) | |
206 | ||
207 | def on_a_saturday(): | |
208 | return IsGivenDayOfWeek(5) | |
209 | ||
210 | For our Matcher implementation we implement the ``_matches`` method - which | |
211 | calls the ``weekday`` method after confirming that the argument (which may not | |
212 | be a date) has such a method - and the ``describe_to`` method - which is used | |
213 | to produce a failure message when a test fails. Here's an example of how the | |
214 | failure message looks:: | |
215 | ||
216 | assert_that(datetime.date(2008, 04, 06), is_(on_a_saturday())) | |
217 | ||
218 | fails with the message:: | |
219 | ||
220 | AssertionError: | |
221 | Expected: is calendar date falling on Saturday | |
222 | got: <2008-04-06> | |
223 | ||
224 | Let's say this matcher is saved in a module named ``isgivendayofweek``. We | |
225 | could use it in our test by importing the factory function ``on_a_saturday``:: | |
226 | ||
227 | from hamcrest import * | |
228 | import unittest | |
229 | from isgivendayofweek import on_a_saturday | |
230 | ||
231 | class DateTest(unittest.TestCase): | |
232 | def testDateIsOnASaturday(self): | |
233 | d = datetime.date(2008, 04, 26) | |
234 | assert_that(d, is_(on_a_saturday())) | |
235 | ||
236 | if __name__ == '__main__': | |
237 | unittest.main() | |
238 | ||
239 | Even though the ``on_a_saturday`` function creates a new matcher each time it | |
240 | is called, you should not assume this is the only usage pattern for your | |
241 | matcher. Therefore you should make sure your matcher is stateless, so a single | |
242 | instance can be reused between matches. |
0 | PyHamcrest | |
1 | ========== | |
2 | ||
3 | .. image:: https://pypip.in/v/PyHamcrest/badge.png | |
4 | :alt: Release Status | |
5 | :target: https://crate.io/packages/PyHamcrest | |
6 | .. image:: https://pypip.in/d/PyHamcrest/badge.png | |
7 | :alt: Downloads | |
8 | :target: https://crate.io/packages/PyHamcrest | |
9 | .. image:: https://travis-ci.org/hamcrest/PyHamcrest.png?branch=master | |
10 | :alt: Build Status | |
11 | :target: https://travis-ci.org/hamcrest/PyHamcrest | |
12 | ||
13 | Introduction | |
14 | ============ | |
15 | ||
16 | PyHamcrest is a framework for writing matcher objects, allowing you to | |
17 | declaratively define "match" rules. There are a number of situations where | |
18 | matchers are invaluable, such as UI validation, or data filtering, but it is in | |
19 | the area of writing flexible tests that matchers are most commonly used. This | |
20 | tutorial shows you how to use PyHamcrest for unit testing. | |
21 | ||
22 | When writing tests it is sometimes difficult to get the balance right between | |
23 | overspecifying the test (and making it brittle to changes), and not specifying | |
24 | enough (making the test less valuable since it continues to pass even when the | |
25 | thing being tested is broken). Having a tool that allows you to pick out | |
26 | precisely the aspect under test and describe the values it should have, to a | |
27 | controlled level of precision, helps greatly in writing tests that are "just | |
28 | right." Such tests fail when the behavior of the aspect under test deviates | |
29 | from the expected behavior, yet continue to pass when minor, unrelated changes | |
30 | to the behaviour are made. | |
31 | ||
32 | Installation | |
33 | ============ | |
34 | ||
35 | Hamcrest can be installed using the usual Python packaging tools. It depends on | |
36 | distribute, but as long as you have a network connection when you install, the | |
37 | installation process will take care of that for you. | |
38 | ||
39 | My first PyHamcrest test | |
40 | ======================== | |
41 | ||
42 | We'll start by writing a very simple PyUnit test, but instead of using PyUnit's | |
43 | ``assertEqual`` method, we'll use PyHamcrest's ``assert_that`` construct and | |
44 | the standard set of matchers: | |
45 | ||
46 | .. code:: python | |
47 | ||
48 | from hamcrest import * | |
49 | import unittest | |
50 | ||
51 | class BiscuitTest(unittest.TestCase): | |
52 | def testEquals(self): | |
53 | theBiscuit = Biscuit('Ginger') | |
54 | myBiscuit = Biscuit('Ginger') | |
55 | assert_that(theBiscuit, equal_to(myBiscuit)) | |
56 | ||
57 | if __name__ == '__main__': | |
58 | unittest.main() | |
59 | ||
60 | The ``assert_that`` function is a stylized sentence for making a test | |
61 | assertion. In this example, the subject of the assertion is the object | |
62 | ``theBiscuit``, which is the first method parameter. The second method | |
63 | parameter is a matcher for ``Biscuit`` objects, here a matcher that checks one | |
64 | object is equal to another using the Python ``==`` operator. The test passes | |
65 | since the ``Biscuit`` class defines an ``__eq__`` method. | |
66 | ||
67 | If you have more than one assertion in your test you can include an identifier | |
68 | for the tested value in the assertion: | |
69 | ||
70 | .. code:: python | |
71 | ||
72 | assert_that(theBiscuit.getChocolateChipCount(), equal_to(10), 'chocolate chips') | |
73 | assert_that(theBiscuit.getHazelnutCount(), equal_to(3), 'hazelnuts') | |
74 | ||
75 | As a convenience, assert_that can also be used to verify a boolean condition: | |
76 | ||
77 | .. code:: python | |
78 | ||
79 | assert_that(theBiscuit.isCooked(), 'cooked') | |
80 | ||
81 | This is equivalent to the ``assert_`` method of unittest.TestCase, but because | |
82 | it's a standalone function, it offers greater flexibility in test writing. | |
83 | ||
84 | ||
85 | Predefined matchers | |
86 | =================== | |
87 | ||
88 | PyHamcrest comes with a library of useful matchers: | |
89 | ||
90 | * Object | |
91 | ||
92 | * ``equal_to`` - match equal object | |
93 | * ``has_length`` - match ``len()`` | |
94 | * ``has_property`` - match value of property with given name | |
95 | * ``has_properties`` - match an object that has all of the given properties. | |
96 | * ``has_string`` - match ``str()`` | |
97 | * ``instance_of`` - match object type | |
98 | * ``none``, ``not_none`` - match ``None``, or not ``None`` | |
99 | * ``same_instance`` - match same object | |
100 | ||
101 | * Number | |
102 | ||
103 | * ``close_to`` - match number close to a given value | |
104 | * ``greater_than``, ``greater_than_or_equal_to``, ``less_than``, | |
105 | ``less_than_or_equal_to`` - match numeric ordering | |
106 | ||
107 | * Text | |
108 | ||
109 | * ``contains_string`` - match part of a string | |
110 | * ``ends_with`` - match the end of a string | |
111 | * ``equal_to_ignoring_case`` - match the complete string but ignore case | |
112 | * ``equal_to_ignoring_whitespace`` - match the complete string but ignore extra whitespace | |
113 | * ``matches_regexp`` - match a regular expression in a string | |
114 | * ``starts_with`` - match the beginning of a string | |
115 | * ``string_contains_in_order`` - match parts of a string, in relative order | |
116 | ||
117 | * Logical | |
118 | ||
119 | * ``all_of`` - ``and`` together all matchers | |
120 | * ``any_of`` - ``or`` together all matchers | |
121 | * ``anything`` - match anything, useful in composite matchers when you don't care about a particular value | |
122 | * ``is_not`` - negate the matcher | |
123 | ||
124 | * Sequence | |
125 | ||
126 | * ``contains`` - exactly match the entire sequence | |
127 | * ``contains_inanyorder`` - match the entire sequence, but in any order | |
128 | * ``has_item`` - match if given item appears in the sequence | |
129 | * ``has_items`` - match if all given items appear in the sequence, in any order | |
130 | * ``is_in`` - match if item appears in the given sequence | |
131 | * ``only_contains`` - match if sequence's items appear in given list | |
132 | ||
133 | * Dictionary | |
134 | ||
135 | * ``has_entries`` - match dictionary with list of key-value pairs | |
136 | * ``has_entry`` - match dictionary containing a key-value pair | |
137 | * ``has_key`` - match dictionary with a key | |
138 | * ``has_value`` - match dictionary with a value | |
139 | ||
140 | * Decorator | |
141 | ||
142 | * ``calling`` - wrap a callable in a deffered object, for subsequent matching on calling behaviour | |
143 | * ``raises`` - Ensure that a deferred callable raises as expected | |
144 | * ``described_as`` - give the matcher a custom failure description | |
145 | * ``is_`` - decorator to improve readability - see `Syntactic sugar` below | |
146 | ||
147 | The arguments for many of these matchers accept not just a matching value, but | |
148 | another matcher, so matchers can be composed for greater flexibility. For | |
149 | example, ``only_contains(less_than(5))`` will match any sequence where every | |
150 | item is less than 5. | |
151 | ||
152 | ||
153 | Syntactic sugar | |
154 | =============== | |
155 | ||
156 | PyHamcrest strives to make your tests as readable as possible. For example, the | |
157 | ``is_`` matcher is a wrapper that doesn't add any extra behavior to the | |
158 | underlying matcher. The following assertions are all equivalent: | |
159 | ||
160 | .. code:: python | |
161 | ||
162 | assert_that(theBiscuit, equal_to(myBiscuit)) | |
163 | assert_that(theBiscuit, is_(equal_to(myBiscuit))) | |
164 | assert_that(theBiscuit, is_(myBiscuit)) | |
165 | ||
166 | The last form is allowed since ``is_(value)`` wraps most non-matcher arguments | |
167 | with ``equal_to``. But if the argument is a type, it is wrapped with | |
168 | ``instance_of``, so the following are also equivalent: | |
169 | ||
170 | .. code:: python | |
171 | ||
172 | assert_that(theBiscuit, instance_of(Biscuit)) | |
173 | assert_that(theBiscuit, is_(instance_of(Biscuit))) | |
174 | assert_that(theBiscuit, is_(Biscuit)) | |
175 | ||
176 | *Note that PyHamcrest's ``is_`` matcher is unrelated to Python's ``is`` | |
177 | operator. The matcher for object identity is ``same_instance``.* | |
178 | ||
179 | ||
180 | Writing custom matchers | |
181 | ======================= | |
182 | ||
183 | PyHamcrest comes bundled with lots of useful matchers, but you'll probably find | |
184 | that you need to create your own from time to time to fit your testing needs. | |
185 | This commonly occurs when you find a fragment of code that tests the same set | |
186 | of properties over and over again (and in different tests), and you want to | |
187 | bundle the fragment into a single assertion. By writing your own matcher you'll | |
188 | eliminate code duplication and make your tests more readable! | |
189 | ||
190 | Let's write our own matcher for testing if a calendar date falls on a Saturday. | |
191 | This is the test we want to write: | |
192 | ||
193 | .. code:: python | |
194 | ||
195 | def testDateIsOnASaturday(self): | |
196 | d = datetime.date(2008, 04, 26) | |
197 | assert_that(d, is_(on_a_saturday())) | |
198 | ||
199 | And here's the implementation: | |
200 | ||
201 | .. code:: python | |
202 | ||
203 | from hamcrest.core.base_matcher import BaseMatcher | |
204 | from hamcrest.core.helpers.hasmethod import hasmethod | |
205 | ||
206 | class IsGivenDayOfWeek(BaseMatcher): | |
207 | ||
208 | def __init__(self, day): | |
209 | self.day = day # Monday is 0, Sunday is 6 | |
210 | ||
211 | def _matches(self, item): | |
212 | if not hasmethod(item, 'weekday'): | |
213 | return False | |
214 | return item.weekday() == self.day | |
215 | ||
216 | def describe_to(self, description): | |
217 | day_as_string = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', | |
218 | 'Friday', 'Saturday', 'Sunday'] | |
219 | description.append_text('calendar date falling on ') \ | |
220 | .append_text(day_as_string[self.day]) | |
221 | ||
222 | def on_a_saturday(): | |
223 | return IsGivenDayOfWeek(5) | |
224 | ||
225 | For our Matcher implementation we implement the ``_matches`` method - which | |
226 | calls the ``weekday`` method after confirming that the argument (which may not | |
227 | be a date) has such a method - and the ``describe_to`` method - which is used | |
228 | to produce a failure message when a test fails. Here's an example of how the | |
229 | failure message looks: | |
230 | ||
231 | .. code:: python | |
232 | ||
233 | assert_that(datetime.date(2008, 04, 06), is_(on_a_saturday())) | |
234 | ||
235 | fails with the message:: | |
236 | ||
237 | AssertionError: | |
238 | Expected: is calendar date falling on Saturday | |
239 | got: <2008-04-06> | |
240 | ||
241 | Let's say this matcher is saved in a module named ``isgivendayofweek``. We | |
242 | could use it in our test by importing the factory function ``on_a_saturday``: | |
243 | ||
244 | .. code:: python | |
245 | ||
246 | from hamcrest import * | |
247 | import unittest | |
248 | from isgivendayofweek import on_a_saturday | |
249 | ||
250 | class DateTest(unittest.TestCase): | |
251 | def testDateIsOnASaturday(self): | |
252 | d = datetime.date(2008, 04, 26) | |
253 | assert_that(d, is_(on_a_saturday())) | |
254 | ||
255 | if __name__ == '__main__': | |
256 | unittest.main() | |
257 | ||
258 | Even though the ``on_a_saturday`` function creates a new matcher each time it | |
259 | is called, you should not assume this is the only usage pattern for your | |
260 | matcher. Therefore you should make sure your matcher is stateless, so a single | |
261 | instance can be reused between matches. | |
262 | ||
263 | ||
264 | More resources | |
265 | ============== | |
266 | ||
267 | * Documentation_ | |
268 | * Package_ | |
269 | * Sources_ | |
270 | * Hamcrest_ | |
271 | ||
272 | .. _Documentation: http://readthedocs.org/docs/pyhamcrest/en/V1.7.1/ | |
273 | .. _Package: http://pypi.python.org/pypi/PyHamcrest | |
274 | .. _Sources: https://github.com/hamcrest/PyHamcrest | |
275 | .. _Hamcrest: http://hamcrest.org |
0 | from core import * | |
1 | from library import * | |
2 | ||
3 | __version__ = "1.6" | |
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" |
0 | from assert_that import assert_that | |
1 | from core import * | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" |
0 | from matcher import Matcher | |
1 | from string_description import StringDescription | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | __unittest = True | |
7 | ||
8 | ||
9 | def assert_that(arg1, arg2=None, arg3=''): | |
10 | """Asserts that actual value satisfies matcher. (Can also assert plain | |
11 | boolean condition.) | |
12 | ||
13 | :param actual: The object to evaluate as the actual value. | |
14 | :param matcher: The matcher to satisfy as the expected condition. | |
15 | :param reason: Optional explanation to include in failure description. | |
16 | ||
17 | ``assert_that`` passes the actual value to the matcher for evaluation. If | |
18 | the matcher is not satisfied, an exception is thrown describing the | |
19 | mismatch. | |
20 | ||
21 | ``assert_that`` is designed to integrate well with PyUnit and other unit | |
22 | testing frameworks. The exception raised for an unmet assertion is an | |
23 | :py:exc:`AssertionError`, which PyUnit reports as a test failure. | |
24 | ||
25 | With a different set of parameters, ``assert_that`` can also verify a | |
26 | boolean condition: | |
27 | ||
28 | .. function:: assert_that(assertion[, reason]) | |
29 | ||
30 | :param assertion: Boolean condition to verify. | |
31 | :param reason: Optional explanation to include in failure description. | |
32 | ||
33 | This is equivalent to the :py:meth:`~unittest.TestCase.assertTrue` method | |
34 | of :py:class:`unittest.TestCase`, but offers greater flexibility in test | |
35 | writing by being a standalone function. | |
36 | ||
37 | """ | |
38 | if isinstance(arg2, Matcher): | |
39 | _assert_match(actual=arg1, matcher=arg2, reason=arg3) | |
40 | else: | |
41 | _assert_bool(assertion=arg1, reason=arg2) | |
42 | ||
43 | ||
44 | def _assert_match(actual, matcher, reason): | |
45 | if not matcher.matches(actual): | |
46 | description = StringDescription() | |
47 | description.append_text(reason) \ | |
48 | .append_text('\nExpected: ') \ | |
49 | .append_description_of(matcher) \ | |
50 | .append_text('\n but: ') | |
51 | matcher.describe_mismatch(actual, description) | |
52 | description.append_text('\n') | |
53 | raise AssertionError(str(description)) | |
54 | ||
55 | ||
56 | def _assert_bool(assertion, reason=None): | |
57 | if not assertion: | |
58 | if not reason: | |
59 | reason = 'Assertion failed' | |
60 | raise AssertionError(reason) |
0 | from description import Description | |
1 | from selfdescribingvalue import SelfDescribingValue | |
2 | from helpers.hasmethod import hasmethod | |
3 | ||
4 | import warnings | |
5 | ||
6 | __author__ = "Jon Reid" | |
7 | __copyright__ = "Copyright 2011 hamcrest.org" | |
8 | __license__ = "BSD, see License.txt" | |
9 | ||
10 | ||
11 | class BaseDescription(Description): | |
12 | """Base class for all :py:class:`~hamcrest.core.description.Description` | |
13 | implementations. | |
14 | ||
15 | """ | |
16 | ||
17 | def append_text(self, text): | |
18 | self.append(text) | |
19 | return self | |
20 | ||
21 | def append_description_of(self, value): | |
22 | if hasmethod(value, 'describe_to'): | |
23 | value.describe_to(self) | |
24 | elif isinstance(value, str): | |
25 | self.append_string_in_python_syntax(value) | |
26 | elif isinstance(value, unicode): | |
27 | self.append(repr(value)) | |
28 | else: | |
29 | description = str(value) | |
30 | if description[:1] == '<' and description[-1:] == '>': | |
31 | self.append(description) | |
32 | else: | |
33 | self.append('<') | |
34 | self.append(description) | |
35 | self.append('>') | |
36 | return self | |
37 | ||
38 | def append_value(self, value): | |
39 | warnings.warn('Call append_description_of instead of append_value', | |
40 | DeprecationWarning) | |
41 | if isinstance(value, str): | |
42 | self.append_string_in_python_syntax(value) | |
43 | else: | |
44 | self.append('<') | |
45 | self.append(str(value)) | |
46 | self.append('>') | |
47 | return self | |
48 | ||
49 | def append_value_list(self, start, separator, end, list): | |
50 | warnings.warn('Call append_list instead of append_value_list', | |
51 | DeprecationWarning) | |
52 | return self.append_list(start, separator, end, | |
53 | map(SelfDescribingValue, list)) | |
54 | ||
55 | def append_list(self, start, separator, end, list): | |
56 | separate = False | |
57 | ||
58 | self.append(start) | |
59 | for item in list: | |
60 | if separate: | |
61 | self.append(separator) | |
62 | self.append_description_of(item) | |
63 | separate = True | |
64 | self.append(end) | |
65 | return self | |
66 | ||
67 | def append(self, string): | |
68 | """Append the string to the description.""" | |
69 | raise NotImplementedError('append') | |
70 | ||
71 | def append_string_in_python_syntax(self, string): | |
72 | self.append("'") | |
73 | for ch in string: | |
74 | self.append(character_in_python_syntax(ch)) | |
75 | self.append("'") | |
76 | ||
77 | ||
78 | def character_in_python_syntax(ch): | |
79 | if ch == "'": | |
80 | return "\'" | |
81 | elif ch == '\n': | |
82 | return '\\n' | |
83 | elif ch == '\r': | |
84 | return '\\r' | |
85 | elif ch == '\t': | |
86 | return '\\t' | |
87 | else: | |
88 | return ch |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from matcher import Matcher | |
5 | from string_description import tostring | |
6 | ||
7 | ||
8 | class BaseMatcher(Matcher): | |
9 | """Base class for all :py:class:`~hamcrest.core.matcher.Matcher` | |
10 | implementations. | |
11 | ||
12 | Most implementations can just implement :py:obj:`_matches`, leaving the | |
13 | handling of any mismatch description to the ``matches`` method. But if it | |
14 | makes more sense to generate the mismatch description during the matching, | |
15 | override :py:meth:`~hamcrest.core.matcher.Matcher.matches` instead. | |
16 | ||
17 | """ | |
18 | ||
19 | def __str__(self): | |
20 | return tostring(self) | |
21 | ||
22 | def _matches(self, item): | |
23 | raise NotImplementedError('_matches') | |
24 | ||
25 | def matches(self, item, mismatch_description=None): | |
26 | match_result = self._matches(item) | |
27 | if not match_result and mismatch_description: | |
28 | self.describe_mismatch(item, mismatch_description) | |
29 | return match_result | |
30 | ||
31 | def describe_mismatch(self, item, mismatch_description): | |
32 | mismatch_description.append_text('was ').append_description_of(item) |
0 | """Fundamental matchers of objects and values, and composite matchers.""" | |
1 | ||
2 | from allof import all_of | |
3 | from anyof import any_of | |
4 | from described_as import described_as | |
5 | from is_ import is_ | |
6 | from isanything import anything | |
7 | from isequal import equal_to | |
8 | from isinstanceof import instance_of | |
9 | from isnone import none, not_none | |
10 | from isnot import is_not | |
11 | from issame import same_instance | |
12 | ||
13 | __author__ = "Jon Reid" | |
14 | __copyright__ = "Copyright 2011 hamcrest.org" | |
15 | __license__ = "BSD, see License.txt" |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | class AllOf(BaseMatcher): | |
9 | ||
10 | def __init__(self, *matchers): | |
11 | self.matchers = matchers | |
12 | ||
13 | def matches(self, item, mismatch_description=None): | |
14 | for matcher in self.matchers: | |
15 | if not matcher.matches(item): | |
16 | if mismatch_description: | |
17 | mismatch_description.append_description_of(matcher) \ | |
18 | .append_text(' ') | |
19 | matcher.describe_mismatch(item, mismatch_description) | |
20 | return False | |
21 | return True | |
22 | ||
23 | def describe_mismatch(self, item, mismatch_description): | |
24 | self.matches(item, mismatch_description) | |
25 | ||
26 | def describe_to(self, description): | |
27 | description.append_list('(', ' and ', ')', self.matchers) | |
28 | ||
29 | ||
30 | def all_of(*items): | |
31 | """Matches if all of the given matchers evaluate to ``True``. | |
32 | ||
33 | :param matcher1,...: A comma-separated list of matchers. | |
34 | ||
35 | The matchers are evaluated from left to right using short-circuit | |
36 | evaluation, so evaluation stops as soon as a matcher returns ``False``. | |
37 | ||
38 | Any argument that is not a matcher is implicitly wrapped in an | |
39 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
40 | equality. | |
41 | ||
42 | """ | |
43 | return AllOf(*[wrap_matcher(item) for item in items]) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | class AnyOf(BaseMatcher): | |
9 | ||
10 | def __init__(self, *matchers): | |
11 | self.matchers = matchers | |
12 | ||
13 | def _matches(self, item): | |
14 | for matcher in self.matchers: | |
15 | if matcher.matches(item): | |
16 | return True | |
17 | return False | |
18 | ||
19 | def describe_to(self, description): | |
20 | description.append_list('(', ' or ', ')', self.matchers) | |
21 | ||
22 | ||
23 | def any_of(*items): | |
24 | """Matches if any of the given matchers evaluate to ``True``. | |
25 | ||
26 | :param matcher1,...: A comma-separated list of matchers. | |
27 | ||
28 | The matchers are evaluated from left to right using short-circuit | |
29 | evaluation, so evaluation stops as soon as a matcher returns ``True``. | |
30 | ||
31 | Any argument that is not a matcher is implicitly wrapped in an | |
32 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
33 | equality. | |
34 | ||
35 | """ | |
36 | return AnyOf(*[wrap_matcher(item) for item in items]) |
0 | import re | |
1 | ||
2 | from hamcrest.core.base_matcher import BaseMatcher | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | ARG_PATTERN = re.compile('%([0-9]+)') | |
10 | ||
11 | ||
12 | class DescribedAs(BaseMatcher): | |
13 | ||
14 | def __init__(self, description_template, matcher, *values): | |
15 | self.template = description_template | |
16 | self.matcher = matcher | |
17 | self.values = values | |
18 | ||
19 | def matches(self, item, mismatch_description=None): | |
20 | return self.matcher.matches(item, mismatch_description) | |
21 | ||
22 | def describe_mismatch(self, item, mismatch_description): | |
23 | self.matcher.describe_mismatch(item, mismatch_description) | |
24 | ||
25 | def describe_to(self, description): | |
26 | text_start = 0 | |
27 | for match in re.finditer(ARG_PATTERN, self.template): | |
28 | description.append_text(self.template[text_start:match.start()]) | |
29 | arg_index = int(match.group()[1:]) | |
30 | description.append_description_of(self.values[arg_index]) | |
31 | text_start = match.end() | |
32 | ||
33 | if text_start < len(self.template): | |
34 | description.append_text(self.template[text_start:]) | |
35 | ||
36 | ||
37 | def described_as(description, matcher, *values): | |
38 | """Adds custom failure description to a given matcher. | |
39 | ||
40 | :param description: Overrides the matcher's description. | |
41 | :param matcher: The matcher to satisfy. | |
42 | :param value1,...: Optional comma-separated list of substitution values. | |
43 | ||
44 | The description may contain substitution placeholders %0, %1, etc. These | |
45 | will be replaced by any values that follow the matcher. | |
46 | ||
47 | """ | |
48 | return DescribedAs(description, matcher, *values) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
6 | from isinstanceof import instance_of | |
7 | ||
8 | ||
9 | class Is(BaseMatcher): | |
10 | ||
11 | def __init__(self, matcher): | |
12 | self.matcher = matcher | |
13 | ||
14 | def matches(self, item, mismatch_description=None): | |
15 | return self.matcher.matches(item, mismatch_description) | |
16 | ||
17 | def describe_mismatch(self, item, mismatch_description): | |
18 | return self.matcher.describe_mismatch(item, mismatch_description) | |
19 | ||
20 | def describe_to(self, description): | |
21 | description.append_description_of(self.matcher) | |
22 | ||
23 | ||
24 | def wrap_value_or_type(x): | |
25 | if isinstance(x, type): | |
26 | return instance_of(x) | |
27 | else: | |
28 | return wrap_matcher(x) | |
29 | ||
30 | ||
31 | def is_(x): | |
32 | """Decorates another matcher, or provides shortcuts to the frequently used | |
33 | ``is(equal_to(x))`` and ``is(instance_of(x))``. | |
34 | ||
35 | :param x: The matcher to satisfy, or a type for | |
36 | :py:func:`~hamcrest.core.core.isinstanceof.instance_of` matching, or an | |
37 | expected value for :py:func:`~hamcrest.core.core.isequal.equal_to` | |
38 | matching. | |
39 | ||
40 | This matcher compares the evaluated object to the given matcher. | |
41 | ||
42 | .. note:: | |
43 | ||
44 | PyHamcrest's ``is_`` matcher is unrelated to Python's ``is`` operator. | |
45 | The matcher for object identity is | |
46 | :py:func:`~hamcrest.core.core.issame.same_instance`. | |
47 | ||
48 | If the ``x`` argument is a matcher, its behavior is retained, but the test | |
49 | may be more expressive. For example:: | |
50 | ||
51 | assert_that(value, less_than(5)) | |
52 | assert_that(value, is_(less_than(5))) | |
53 | ||
54 | If the ``x`` argument is a type, it is wrapped in an | |
55 | :py:func:`~hamcrest.core.core.isinstanceof.instance_of` matcher. This makes | |
56 | the following statements equivalent:: | |
57 | ||
58 | assert_that(cheese, instance_of(Cheddar)) | |
59 | assert_that(cheese, is_(instance_of(Cheddar))) | |
60 | assert_that(cheese, is_(Cheddar)) | |
61 | ||
62 | Otherwise, if the ``x`` argument is not a matcher, it is wrapped in an | |
63 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher. This makes the | |
64 | following statements equivalent:: | |
65 | ||
66 | assert_that(cheese, equal_to(smelly)) | |
67 | assert_that(cheese, is_(equal_to(smelly))) | |
68 | assert_that(cheese, is_(smelly)) | |
69 | ||
70 | Choose the style that makes your expression most readable. This will vary | |
71 | depending on context. | |
72 | ||
73 | """ | |
74 | return Is(wrap_value_or_type(x)) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | class IsAnything(BaseMatcher): | |
8 | ||
9 | def __init__(self, description): | |
10 | self.description = description | |
11 | if not description: | |
12 | self.description = 'ANYTHING' | |
13 | ||
14 | def _matches(self, item): | |
15 | return True | |
16 | ||
17 | def describe_to(self, description): | |
18 | description.append_text(self.description) | |
19 | ||
20 | ||
21 | def anything(description=None): | |
22 | """Matches anything. | |
23 | ||
24 | :param description: Optional string used to describe this matcher. | |
25 | ||
26 | This matcher always evaluates to ``True``. Specify this in composite | |
27 | matchers when the value of a particular element is unimportant. | |
28 | ||
29 | """ | |
30 | return IsAnything(description) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | from hamcrest.core.matcher import Matcher | |
6 | ||
7 | ||
8 | class IsEqual(BaseMatcher): | |
9 | ||
10 | def __init__(self, equals): | |
11 | self.object = equals | |
12 | ||
13 | def _matches(self, item): | |
14 | return item == self.object | |
15 | ||
16 | def describe_to(self, description): | |
17 | nested_matcher = isinstance(self.object, Matcher) | |
18 | if nested_matcher: | |
19 | description.append_text('<') | |
20 | description.append_description_of(self.object) | |
21 | if nested_matcher: | |
22 | description.append_text('>') | |
23 | ||
24 | ||
25 | def equal_to(obj): | |
26 | """Matches if object is equal to a given object. | |
27 | ||
28 | :param obj: The object to compare against as the expected value. | |
29 | ||
30 | This matcher compares the evaluated object to ``obj`` for equality.""" | |
31 | return IsEqual(obj) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | class IsInstanceOf(BaseMatcher): | |
8 | ||
9 | def __init__(self, expected_type): | |
10 | if not isinstance(expected_type, type): | |
11 | raise TypeError('IsInstanceOf requires type') | |
12 | self.expected_type = expected_type | |
13 | ||
14 | def _matches(self, item): | |
15 | return isinstance(item, self.expected_type) | |
16 | ||
17 | def describe_to(self, description): | |
18 | description.append_text('an instance of ') \ | |
19 | .append_text(self.expected_type.__name__) | |
20 | ||
21 | ||
22 | def instance_of(atype): | |
23 | """Matches if object is an instance of, or inherits from, a given type. | |
24 | ||
25 | :param atype: The type to compare against as the expected type. | |
26 | ||
27 | This matcher checks whether the evaluated object is an instance of | |
28 | ``atype`` or an instance of any class that inherits from ``atype``. | |
29 | ||
30 | Example:: | |
31 | ||
32 | instance_of(str) | |
33 | ||
34 | """ | |
35 | return IsInstanceOf(atype) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | from isnot import is_not | |
6 | ||
7 | ||
8 | class IsNone(BaseMatcher): | |
9 | ||
10 | def _matches(self, item): | |
11 | return item is None | |
12 | ||
13 | def describe_to(self, description): | |
14 | description.append_text('None') | |
15 | ||
16 | ||
17 | def none(): | |
18 | """Matches if object is ``None``.""" | |
19 | return IsNone() | |
20 | ||
21 | ||
22 | def not_none(): | |
23 | """Matches if object is not ``None``.""" | |
24 | return is_not(none()) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher, Matcher | |
5 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
6 | from isequal import equal_to | |
7 | ||
8 | ||
9 | class IsNot(BaseMatcher): | |
10 | ||
11 | def __init__(self, matcher): | |
12 | self.matcher = matcher | |
13 | ||
14 | def _matches(self, item): | |
15 | return not self.matcher.matches(item) | |
16 | ||
17 | def describe_to(self, description): | |
18 | description.append_text('not ').append_description_of(self.matcher) | |
19 | ||
20 | ||
21 | def is_not(match): | |
22 | """Inverts the given matcher to its logical negation. | |
23 | ||
24 | :param match: The matcher to negate. | |
25 | ||
26 | This matcher compares the evaluated object to the negation of the given | |
27 | matcher. If the ``match`` argument is not a matcher, it is implicitly | |
28 | wrapped in an :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to | |
29 | check for equality, and thus matches for inequality. | |
30 | ||
31 | Examples:: | |
32 | ||
33 | assert_that(cheese, is_not(equal_to(smelly))) | |
34 | assert_that(cheese, is_not(smelly)) | |
35 | ||
36 | """ | |
37 | return IsNot(wrap_matcher(match)) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | ||
6 | ||
7 | class IsSame(BaseMatcher): | |
8 | ||
9 | def __init__(self, object): | |
10 | self.object = object | |
11 | ||
12 | def _matches(self, item): | |
13 | return item is self.object | |
14 | ||
15 | def describe_to(self, description): | |
16 | description.append_text('same instance as ') \ | |
17 | .append_text(hex(id(self.object))) \ | |
18 | .append_text(' ') \ | |
19 | .append_description_of(self.object) | |
20 | ||
21 | def describe_mismatch(self, item, mismatch_description): | |
22 | mismatch_description.append_text('was ') | |
23 | if item is not None: | |
24 | mismatch_description.append_text(hex(id(item))) \ | |
25 | .append_text(' ') | |
26 | mismatch_description.append_description_of(item) | |
27 | ||
28 | ||
29 | def same_instance(obj): | |
30 | """Matches if evaluated object is the same instance as a given object. | |
31 | ||
32 | :param obj: The object to compare against as the expected value. | |
33 | ||
34 | This matcher invokes the ``is`` identity operator to determine if the | |
35 | evaluated object is the the same object as ``obj``. | |
36 | ||
37 | """ | |
38 | return IsSame(obj) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | ||
5 | class Description(object): | |
6 | """A description of a :py:class:`~hamcrest.core.matcher.Matcher`. | |
7 | ||
8 | A :py:class:`~hamcrest.core.matcher.Matcher` will describe itself to a | |
9 | description which can later be used for reporting. | |
10 | ||
11 | """ | |
12 | ||
13 | def append_text(self, text): | |
14 | """Appends some plain text to the description. | |
15 | ||
16 | :returns: ``self``, for chaining | |
17 | ||
18 | """ | |
19 | raise NotImplementedError('append_text') | |
20 | ||
21 | def append_description_of(self, value): | |
22 | """Appends description of given value to this description. | |
23 | ||
24 | If the value implements | |
25 | :py:meth:`~hamcrest.core.selfdescribing.SelfDescribing.describe_to`, | |
26 | then it will be used. | |
27 | ||
28 | :returns: ``self``, for chaining | |
29 | ||
30 | """ | |
31 | raise NotImplementedError('append_description_of') | |
32 | ||
33 | def append_value(self, value): | |
34 | """Appends an arbitary value to the description. | |
35 | ||
36 | **Deprecated:** Call | |
37 | :py:meth:`~hamcrest.core.description.Description.append_description_of` | |
38 | instead. | |
39 | ||
40 | :returns: ``self``, for chaining | |
41 | ||
42 | """ | |
43 | raise NotImplementedError('append_value') | |
44 | ||
45 | def append_list(self, start, separator, end, list): | |
46 | """Appends a list of objects to the description. | |
47 | ||
48 | :param start: String that will begin the list description. | |
49 | :param separator: String that will separate each object in the | |
50 | description. | |
51 | :param end: String that will end the list description. | |
52 | :param list: List of objects to be described. | |
53 | ||
54 | :returns: ``self``, for chaining | |
55 | ||
56 | """ | |
57 | raise NotImplementedError('append_list') |
0 | """Utilities for writing Matchers.""" | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | ||
5 | def hasmethod(obj, methodname): | |
6 | """Does ``obj`` have a method named ``methodname``?""" | |
7 | ||
8 | if not hasattr(obj, methodname): | |
9 | return False | |
10 | method = getattr(obj, methodname) | |
11 | return callable(method) |
0 | from hamcrest.core.base_matcher import Matcher | |
1 | from hamcrest.core.core.isequal import equal_to | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | def wrap_matcher(x): | |
9 | """Wraps argument in a matcher, if necessary. | |
10 | ||
11 | :returns: the argument as-is if it is already a matcher, otherwise wrapped | |
12 | in an :py:func:`~hamcrest.core.core.isequal.equal_to` matcher. | |
13 | ||
14 | """ | |
15 | if isinstance(x, Matcher): | |
16 | return x | |
17 | else: | |
18 | return equal_to(x) |
0 | from selfdescribing import SelfDescribing | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | class Matcher(SelfDescribing): | |
8 | """A matcher over acceptable values. | |
9 | ||
10 | A matcher is able to describe itself to give feedback when it fails. | |
11 | ||
12 | Matcher implementations should *not* directly implement this protocol. | |
13 | Instead, *extend* the :py:class:`~hamcrest.core.base_matcher.BaseMatcher` | |
14 | class, which will ensure that the | |
15 | :py:class:`~hamcrest.core.matcher.Matcher` API can grow to support new | |
16 | features and remain compatible with all | |
17 | :py:class:`~hamcrest.core.matcher.Matcher` implementations. | |
18 | ||
19 | """ | |
20 | ||
21 | def matches(self, item, mismatch_description=None): | |
22 | """Evaluates the matcher for argument item. | |
23 | ||
24 | If a mismatch is detected and argument ``mismatch_description`` is | |
25 | provided, it will generate a description of why the matcher has not | |
26 | accepted the item. | |
27 | ||
28 | :param item: The object against which the matcher is evaluated. | |
29 | :returns: ``True`` if ``item`` matches, otherwise ``False``. | |
30 | ||
31 | """ | |
32 | raise NotImplementedError('matches') | |
33 | ||
34 | def describe_mismatch(self, item, mismatch_description): | |
35 | """Generates a description of why the matcher has not accepted the | |
36 | item. | |
37 | ||
38 | The description will be part of a larger description of why a matching | |
39 | failed, so it should be concise. | |
40 | ||
41 | This method assumes that ``matches(item)`` is ``False``, but will not | |
42 | check this. | |
43 | ||
44 | :param item: The item that the | |
45 | :py:class:`~hamcrest.core.matcher.Matcher` has rejected. | |
46 | :param mismatch_description: The description to be built or appended | |
47 | to. | |
48 | ||
49 | """ | |
50 | raise NotImplementedError('describe_mismatch') |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | ||
5 | class SelfDescribing(object): | |
6 | """The ability of an object to describe itself.""" | |
7 | ||
8 | def describe_to(self, description): | |
9 | """Generates a description of the object. | |
10 | ||
11 | The description may be part of a description of a larger object of | |
12 | which this is just a component, so it should be worded appropriately. | |
13 | ||
14 | :param description: The description to be built or appended to. | |
15 | ||
16 | """ | |
17 | raise NotImplementedError('describe_to') |
0 | from hamcrest.core.selfdescribing import SelfDescribing | |
1 | ||
2 | import warnings | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | class SelfDescribingValue(SelfDescribing): | |
10 | """Wrap any value in a ``SelfDescribingValue`` to satisfy the | |
11 | :py:class:`~hamcrest.core.selfdescribing.SelfDescribing` interface. | |
12 | ||
13 | **Deprecated:** No need for this class now that | |
14 | :py:meth:`~hamcrest.core.description.Description.append_description_of` | |
15 | handles any type of value. | |
16 | ||
17 | """ | |
18 | ||
19 | def __init__(self, value): | |
20 | warnings.warn('SelfDescribingValue no longer needed', | |
21 | DeprecationWarning) | |
22 | self.value = value | |
23 | ||
24 | def describe_to(self, description): | |
25 | """Generates a description of the value.""" | |
26 | description.append_value(self.value) |
0 | from base_description import BaseDescription | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | def tostring(selfdescribing): | |
8 | """Returns the description of a | |
9 | :py:class:`~hamcrest.core.selfdescribing.SelfDescribing` object as a | |
10 | string. | |
11 | ||
12 | :param selfdescribing: The object to be described. | |
13 | :returns: The description of the object. | |
14 | """ | |
15 | return str(StringDescription().append_description_of(selfdescribing)) | |
16 | ||
17 | ||
18 | class StringDescription(BaseDescription): | |
19 | """A :py:class:`~hamcrest.core.description.Description` that is stored as a | |
20 | string. | |
21 | ||
22 | """ | |
23 | ||
24 | def __init__(self): | |
25 | self.out = '' | |
26 | ||
27 | def __str__(self): | |
28 | """Returns the description.""" | |
29 | return self.out | |
30 | ||
31 | def append(self, string): | |
32 | self.out += string |
0 | """Library of Matcher implementations.""" | |
1 | ||
2 | from hamcrest.core import * | |
3 | from collection import * | |
4 | from integration import * | |
5 | from number import * | |
6 | from object import * | |
7 | from text import * | |
8 | ||
9 | __author__ = "Jon Reid" | |
10 | __copyright__ = "Copyright 2011 hamcrest.org" | |
11 | __license__ = "BSD, see License.txt" | |
12 | ||
13 | __all__ = [ | |
14 | 'has_entry', | |
15 | 'has_entries', | |
16 | 'has_key', | |
17 | 'has_value', | |
18 | 'is_in', | |
19 | 'has_item', | |
20 | 'has_items', | |
21 | 'contains_inanyorder', | |
22 | 'contains', | |
23 | 'only_contains', | |
24 | 'match_equality', | |
25 | 'close_to', | |
26 | 'greater_than', | |
27 | 'greater_than_or_equal_to', | |
28 | 'less_than', | |
29 | 'less_than_or_equal_to', | |
30 | 'has_length', | |
31 | 'has_property', | |
32 | 'has_string', | |
33 | 'equal_to_ignoring_case', | |
34 | 'equal_to_ignoring_whitespace', | |
35 | 'contains_string', | |
36 | 'ends_with', | |
37 | 'starts_with', | |
38 | ] |
0 | """Matchers of collections.""" | |
1 | ||
2 | from isdict_containing import has_entry | |
3 | from isdict_containingentries import has_entries | |
4 | from isdict_containingkey import has_key | |
5 | from isdict_containingvalue import has_value | |
6 | from isin import is_in | |
7 | from issequence_containing import has_item, has_items | |
8 | from issequence_containinginanyorder import contains_inanyorder | |
9 | from issequence_containinginorder import contains | |
10 | from issequence_onlycontaining import only_contains | |
11 | ||
12 | __author__ = "Jon Reid" | |
13 | __copyright__ = "Copyright 2011 hamcrest.org" | |
14 | __license__ = "BSD, see License.txt" |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | class IsDictContaining(BaseMatcher): | |
10 | ||
11 | def __init__(self, key_matcher, value_matcher): | |
12 | self.key_matcher = key_matcher | |
13 | self.value_matcher = value_matcher | |
14 | ||
15 | def _matches(self, dictionary): | |
16 | if hasmethod(dictionary, 'items'): | |
17 | for key, value in dictionary.items(): | |
18 | if self.key_matcher.matches(key) and self.value_matcher.matches(value): | |
19 | return True | |
20 | return False | |
21 | ||
22 | def describe_to(self, description): | |
23 | description.append_text('a dictionary containing [') \ | |
24 | .append_description_of(self.key_matcher) \ | |
25 | .append_text(': ') \ | |
26 | .append_description_of(self.value_matcher) \ | |
27 | .append_text(']') | |
28 | ||
29 | ||
30 | def has_entry(key_match, value_match): | |
31 | """Matches if dictionary contains key-value entry satisfying a given pair | |
32 | of matchers. | |
33 | ||
34 | :param key_match: The matcher to satisfy for the key, or an expected value | |
35 | for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
36 | :param value_match: The matcher to satisfy for the value, or an expected | |
37 | value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
38 | ||
39 | This matcher iterates the evaluated dictionary, searching for any key-value | |
40 | entry that satisfies ``key_match`` and ``value_match``. If a matching entry | |
41 | is found, ``has_entry`` is satisfied. | |
42 | ||
43 | Any argument that is not a matcher is implicitly wrapped in an | |
44 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
45 | equality. | |
46 | ||
47 | Examples:: | |
48 | ||
49 | has_entry(equal_to('foo'), equal_to(1)) | |
50 | has_entry('foo', 1) | |
51 | ||
52 | """ | |
53 | return IsDictContaining(wrap_matcher(key_match), wrap_matcher(value_match)) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | class IsDictContainingEntries(BaseMatcher): | |
10 | ||
11 | def __init__(self, value_matchers): | |
12 | self.value_matchers = value_matchers | |
13 | ||
14 | def _not_a_dictionary(self, dictionary, mismatch_description): | |
15 | if mismatch_description: | |
16 | mismatch_description.append_description_of(dictionary) \ | |
17 | .append_text(' is not a mapping object') | |
18 | return False | |
19 | ||
20 | def matches(self, dictionary, mismatch_description=None): | |
21 | for key in self.value_matchers: | |
22 | ||
23 | try: | |
24 | if not key in dictionary: | |
25 | if mismatch_description: | |
26 | mismatch_description.append_text('no ') \ | |
27 | .append_description_of(key) \ | |
28 | .append_text(' key in ') \ | |
29 | .append_description_of(dictionary) | |
30 | return False | |
31 | except TypeError: | |
32 | return self._not_a_dictionary(dictionary, mismatch_description) | |
33 | ||
34 | value_matcher = self.value_matchers[key] | |
35 | try: | |
36 | actual_value = dictionary[key] | |
37 | except TypeError: | |
38 | return self._not_a_dictionary(dictionary, mismatch_description) | |
39 | ||
40 | if not value_matcher.matches(actual_value): | |
41 | if mismatch_description: | |
42 | mismatch_description.append_text('value for ') \ | |
43 | .append_description_of(key) \ | |
44 | .append_text(' ') | |
45 | value_matcher.describe_mismatch(actual_value, mismatch_description) | |
46 | return False | |
47 | ||
48 | return True | |
49 | ||
50 | def describe_mismatch(self, item, mismatch_description): | |
51 | self.matches(item, mismatch_description) | |
52 | ||
53 | def describe_keyvalue(self, index, description): | |
54 | """Describes key-value pair at given index.""" | |
55 | description.append_description_of(index) \ | |
56 | .append_text(': ') \ | |
57 | .append_description_of(self.value_matchers[index]) | |
58 | ||
59 | def describe_to(self, description): | |
60 | description.append_text('a dictionary containing {') | |
61 | first = True | |
62 | for key in self.value_matchers: | |
63 | if not first: | |
64 | description.append_text(', ') | |
65 | self.describe_keyvalue(key, description) | |
66 | first = False | |
67 | description.append_text('}') | |
68 | ||
69 | ||
70 | def has_entries(*keys_valuematchers, **kv_args): | |
71 | """Matches if dictionary contains entries satisfying a dictionary of keys | |
72 | and corresponding value matchers. | |
73 | ||
74 | :param matcher_dict: A dictionary mapping keys to associated value matchers, | |
75 | or to expected values for | |
76 | :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
77 | ||
78 | Note that the keys must be actual keys, not matchers. Any value argument | |
79 | that is not a matcher is implicitly wrapped in an | |
80 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
81 | equality. | |
82 | ||
83 | Examples:: | |
84 | ||
85 | has_entries({'foo':equal_to(1), 'bar':equal_to(2)}) | |
86 | has_entries({'foo':1, 'bar':2}) | |
87 | ||
88 | ``has_entries`` also accepts a list of keyword arguments: | |
89 | ||
90 | .. function:: has_entries(keyword1=value_matcher1[, keyword2=value_matcher2[, ...]]) | |
91 | ||
92 | :param keyword1: A keyword to look up. | |
93 | :param valueMatcher1: The matcher to satisfy for the value, or an expected | |
94 | value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
95 | ||
96 | Examples:: | |
97 | ||
98 | has_entries(foo=equal_to(1), bar=equal_to(2)) | |
99 | has_entries(foo=1, bar=2) | |
100 | ||
101 | Finally, ``has_entries`` also accepts a list of alternating keys and their | |
102 | value matchers: | |
103 | ||
104 | .. function:: has_entries(key1, value_matcher1[, ...]) | |
105 | ||
106 | :param key1: A key (not a matcher) to look up. | |
107 | :param valueMatcher1: The matcher to satisfy for the value, or an expected | |
108 | value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
109 | ||
110 | Examples:: | |
111 | ||
112 | has_entries('foo', equal_to(1), 'bar', equal_to(2)) | |
113 | has_entries('foo', 1, 'bar', 2) | |
114 | ||
115 | """ | |
116 | if len(keys_valuematchers) == 1: | |
117 | try: | |
118 | base_dict = keys_valuematchers[0].copy() | |
119 | for key in base_dict: | |
120 | base_dict[key] = wrap_matcher(base_dict[key]) | |
121 | except AttributeError: | |
122 | raise ValueError('single-argument calls to has_entries must pass a dict as the argument') | |
123 | else: | |
124 | if len(keys_valuematchers) % 2: | |
125 | raise ValueError('has_entries requires key-value pairs') | |
126 | base_dict = {} | |
127 | for index in range(int(len(keys_valuematchers) / 2)): | |
128 | base_dict[keys_valuematchers[2 * index]] = wrap_matcher(keys_valuematchers[2 * index + 1]) | |
129 | ||
130 | for key, value in kv_args.items(): | |
131 | base_dict[key] = wrap_matcher(value) | |
132 | ||
133 | return IsDictContainingEntries(base_dict) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | class IsDictContainingKey(BaseMatcher): | |
10 | ||
11 | def __init__(self, key_matcher): | |
12 | self.key_matcher = key_matcher | |
13 | ||
14 | def _matches(self, dictionary): | |
15 | if hasmethod(dictionary, 'keys'): | |
16 | for key in dictionary.keys(): | |
17 | if self.key_matcher.matches(key): | |
18 | return True | |
19 | return False | |
20 | ||
21 | def describe_to(self, description): | |
22 | description.append_text('a dictionary containing key ') \ | |
23 | .append_description_of(self.key_matcher) | |
24 | ||
25 | ||
26 | def has_key(key_match): | |
27 | """Matches if dictionary contains an entry whose key satisfies a given | |
28 | matcher. | |
29 | ||
30 | :param key_match: The matcher to satisfy for the key, or an expected value | |
31 | for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
32 | ||
33 | This matcher iterates the evaluated dictionary, searching for any key-value | |
34 | entry whose key satisfies the given matcher. If a matching entry is found, | |
35 | ``has_key`` is satisfied. | |
36 | ||
37 | Any argument that is not a matcher is implicitly wrapped in an | |
38 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
39 | equality. | |
40 | ||
41 | Examples:: | |
42 | ||
43 | has_key(equal_to('foo')) | |
44 | has_key('foo') | |
45 | ||
46 | """ | |
47 | return IsDictContainingKey(wrap_matcher(key_match)) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | class IsDictContainingValue(BaseMatcher): | |
10 | ||
11 | def __init__(self, value_matcher): | |
12 | self.value_matcher = value_matcher | |
13 | ||
14 | def _matches(self, dictionary): | |
15 | if hasmethod(dictionary, 'values'): | |
16 | for value in dictionary.values(): | |
17 | if self.value_matcher.matches(value): | |
18 | return True | |
19 | return False | |
20 | ||
21 | def describe_to(self, description): | |
22 | description.append_text('a dictionary containing value ') \ | |
23 | .append_description_of(self.value_matcher) | |
24 | ||
25 | ||
26 | def has_value(value): | |
27 | """Matches if dictionary contains an entry whose value satisfies a given | |
28 | matcher. | |
29 | ||
30 | :param value_match: The matcher to satisfy for the value, or an expected | |
31 | value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
32 | ||
33 | This matcher iterates the evaluated dictionary, searching for any key-value | |
34 | entry whose value satisfies the given matcher. If a matching entry is | |
35 | found, ``has_value`` is satisfied. | |
36 | ||
37 | Any argument that is not a matcher is implicitly wrapped in an | |
38 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
39 | equality. | |
40 | ||
41 | Examples:: | |
42 | ||
43 | has_value(equal_to('bar')) | |
44 | has_value('bar') | |
45 | ||
46 | """ | |
47 | return IsDictContainingValue(wrap_matcher(value)) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | class IsIn(BaseMatcher): | |
8 | ||
9 | def __init__(self, sequence): | |
10 | self.sequence = sequence | |
11 | ||
12 | def _matches(self, item): | |
13 | return item in self.sequence | |
14 | ||
15 | def describe_to(self, description): | |
16 | description.append_text('one of ') \ | |
17 | .append_list('(', ', ', ')', self.sequence) | |
18 | ||
19 | ||
20 | def is_in(sequence): | |
21 | """Matches if evaluated object is present in a given sequence. | |
22 | ||
23 | :param sequence: The sequence to search. | |
24 | ||
25 | This matcher invokes the ``in`` membership operator to determine if the | |
26 | evaluated object is a member of the sequence. | |
27 | ||
28 | """ | |
29 | return IsIn(sequence) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | from hamcrest.core.core.allof import all_of | |
6 | from hamcrest.core.helpers.hasmethod import hasmethod | |
7 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
8 | ||
9 | ||
10 | class IsSequenceContaining(BaseMatcher): | |
11 | ||
12 | def __init__(self, element_matcher): | |
13 | self.element_matcher = element_matcher | |
14 | ||
15 | def _matches(self, sequence): | |
16 | if hasmethod(sequence, '__iter__'): | |
17 | for item in sequence: | |
18 | if self.element_matcher.matches(item): | |
19 | return True | |
20 | return False | |
21 | ||
22 | def describe_to(self, description): | |
23 | description.append_text('a sequence containing ') \ | |
24 | .append_description_of(self.element_matcher) | |
25 | ||
26 | ||
27 | def has_item(match): | |
28 | """Matches if any element of sequence satisfies a given matcher. | |
29 | ||
30 | :param match: The matcher to satisfy, or an expected value for | |
31 | :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
32 | ||
33 | This matcher iterates the evaluated sequence, searching for any element | |
34 | that satisfies a given matcher. If a matching element is found, | |
35 | ``has_item`` is satisfied. | |
36 | ||
37 | If the ``match`` argument is not a matcher, it is implicitly wrapped in an | |
38 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
39 | equality. | |
40 | ||
41 | """ | |
42 | return IsSequenceContaining(wrap_matcher(match)) | |
43 | ||
44 | ||
45 | def has_items(*items): | |
46 | """Matches if all of the given matchers are satisfied by any elements of | |
47 | the sequence. | |
48 | ||
49 | :param match1,...: A comma-separated list of matchers. | |
50 | ||
51 | This matcher iterates the given matchers, searching for any elements in the | |
52 | evaluated sequence that satisfy them. If each matcher is satisfied, then | |
53 | ``has_items`` is satisfied. | |
54 | ||
55 | Any argument that is not a matcher is implicitly wrapped in an | |
56 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
57 | equality. | |
58 | ||
59 | """ | |
60 | matchers = [] | |
61 | for item in items: | |
62 | matchers.append(has_item(item)) | |
63 | return apply(all_of, matchers) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | class MatchInAnyOrder(object): | |
10 | def __init__(self, matchers, mismatch_description): | |
11 | self.matchers = matchers | |
12 | self.mismatch_description = mismatch_description | |
13 | ||
14 | def matches(self, item): | |
15 | return self.isnotsurplus(item) and self.ismatched(item) | |
16 | ||
17 | def isfinished(self, sequence): | |
18 | if not self.matchers: | |
19 | return True | |
20 | if self.mismatch_description: | |
21 | self.mismatch_description.append_text('no item matches: ') \ | |
22 | .append_list('', ', ', '', self.matchers) \ | |
23 | .append_text(' in ') \ | |
24 | .append_list('[', ', ', ']', sequence) | |
25 | return False | |
26 | ||
27 | def isnotsurplus(self, item): | |
28 | if not self.matchers: | |
29 | if self.mismatch_description: | |
30 | self.mismatch_description.append_text('not matched: ') \ | |
31 | .append_description_of(item) | |
32 | return False | |
33 | return True | |
34 | ||
35 | def ismatched(self, item): | |
36 | index = 0 | |
37 | for matcher in self.matchers: | |
38 | if matcher.matches(item): | |
39 | del self.matchers[index] | |
40 | return True | |
41 | index += 1 | |
42 | if self.mismatch_description: | |
43 | self.mismatch_description.append_text('not matched: ') \ | |
44 | .append_description_of(item) | |
45 | return False | |
46 | ||
47 | ||
48 | class IsSequenceContainingInAnyOrder(BaseMatcher): | |
49 | ||
50 | def __init__(self, matchers): | |
51 | self.matchers = matchers | |
52 | ||
53 | def matches(self, sequence, mismatch_description=None): | |
54 | if not hasmethod(sequence, '__iter__'): | |
55 | if mismatch_description: | |
56 | super(IsSequenceContainingInAnyOrder, self) \ | |
57 | .describe_mismatch(sequence, mismatch_description) | |
58 | return False | |
59 | matchsequence = MatchInAnyOrder(self.matchers, mismatch_description) | |
60 | for item in sequence: | |
61 | if not matchsequence.matches(item): | |
62 | return False | |
63 | return matchsequence.isfinished(sequence) | |
64 | ||
65 | def describe_mismatch(self, item, mismatch_description): | |
66 | self.matches(item, mismatch_description) | |
67 | ||
68 | def describe_to(self, description): | |
69 | description.append_text('a sequence over ') \ | |
70 | .append_list('[', ', ', ']', self.matchers) \ | |
71 | .append_text(' in any order') | |
72 | ||
73 | ||
74 | def contains_inanyorder(*items): | |
75 | """Matches if sequences's elements, in any order, satisfy a given list of | |
76 | matchers. | |
77 | ||
78 | :param match1,...: A comma-separated list of matchers. | |
79 | ||
80 | This matcher iterates the evaluated sequence, seeing if each element | |
81 | satisfies any of the given matchers. The matchers are tried from left to | |
82 | right, and when a satisfied matcher is found, it is no longer a candidate | |
83 | for the remaining elements. If a one-to-one correspondence is established | |
84 | between elements and matchers, ``contains_inanyorder`` is satisfied. | |
85 | ||
86 | Any argument that is not a matcher is implicitly wrapped in an | |
87 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
88 | equality. | |
89 | ||
90 | """ | |
91 | ||
92 | matchers = [] | |
93 | for item in items: | |
94 | matchers.append(wrap_matcher(item)) | |
95 | return IsSequenceContainingInAnyOrder(matchers) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | from hamcrest.core.helpers.hasmethod import hasmethod | |
6 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
7 | ||
8 | ||
9 | class MatchingInOrder(object): | |
10 | def __init__(self, matchers, mismatch_description): | |
11 | self.matchers = matchers | |
12 | self.mismatch_description = mismatch_description | |
13 | self.next_match_index = 0 | |
14 | ||
15 | def matches(self, item): | |
16 | return self.isnotsurplus(item) and self.ismatched(item) | |
17 | ||
18 | def isfinished(self): | |
19 | if self.next_match_index < len(self.matchers): | |
20 | if self.mismatch_description: | |
21 | self.mismatch_description.append_text('No item matched: ') \ | |
22 | .append_description_of(self.matchers[self.next_match_index]) | |
23 | return False | |
24 | return True | |
25 | ||
26 | def ismatched(self, item): | |
27 | matcher = self.matchers[self.next_match_index] | |
28 | if not matcher.matches(item): | |
29 | if self.mismatch_description: | |
30 | self.mismatch_description.append_text('item ' + str(self.next_match_index) + ': ') | |
31 | matcher.describe_mismatch(item, self.mismatch_description) | |
32 | return False | |
33 | self.next_match_index += 1 | |
34 | return True | |
35 | ||
36 | def isnotsurplus(self, item): | |
37 | if len(self.matchers) <= self.next_match_index: | |
38 | if self.mismatch_description: | |
39 | self.mismatch_description.append_text('Not matched: ') \ | |
40 | .append_description_of(item) | |
41 | return False | |
42 | return True | |
43 | ||
44 | ||
45 | class IsSequenceContainingInOrder(BaseMatcher): | |
46 | ||
47 | def __init__(self, matchers): | |
48 | self.matchers = matchers | |
49 | ||
50 | def matches(self, sequence, mismatch_description=None): | |
51 | if not hasmethod(sequence, '__iter__'): | |
52 | if mismatch_description: | |
53 | super(IsSequenceContainingInOrder, self) \ | |
54 | .describe_mismatch(sequence, mismatch_description) | |
55 | return False | |
56 | matchsequence = MatchingInOrder(self.matchers, mismatch_description) | |
57 | for item in sequence: | |
58 | if not matchsequence.matches(item): | |
59 | return False | |
60 | return matchsequence.isfinished() | |
61 | ||
62 | def describe_mismatch(self, item, mismatch_description): | |
63 | self.matches(item, mismatch_description) | |
64 | ||
65 | def describe_to(self, description): | |
66 | description.append_text('a sequence containing ') \ | |
67 | .append_list('[', ', ', ']', self.matchers) | |
68 | ||
69 | ||
70 | def contains(*items): | |
71 | """Matches if sequence's elements satisfy a given list of matchers, in order. | |
72 | ||
73 | :param match1,...: A comma-separated list of matchers. | |
74 | ||
75 | This matcher iterates the evaluated sequence and a given list of matchers, | |
76 | seeing if each element satisfies its corresponding matcher. | |
77 | ||
78 | Any argument that is not a matcher is implicitly wrapped in an | |
79 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
80 | equality. | |
81 | ||
82 | """ | |
83 | matchers = [] | |
84 | for item in items: | |
85 | matchers.append(wrap_matcher(item)) | |
86 | return IsSequenceContainingInOrder(matchers) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.core.anyof import any_of | |
2 | from hamcrest.core.helpers.hasmethod import hasmethod | |
3 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
4 | ||
5 | __author__ = "Jon Reid" | |
6 | __copyright__ = "Copyright 2011 hamcrest.org" | |
7 | __license__ = "BSD, see License.txt" | |
8 | ||
9 | ||
10 | class IsSequenceOnlyContaining(BaseMatcher): | |
11 | ||
12 | def __init__(self, matcher): | |
13 | self.matcher = matcher | |
14 | ||
15 | def _matches(self, sequence): | |
16 | if not hasmethod(sequence, '__len__') \ | |
17 | or not hasmethod(sequence, '__iter__'): | |
18 | return False | |
19 | ||
20 | if len(sequence) == 0: | |
21 | return False | |
22 | for item in sequence: | |
23 | if not self.matcher.matches(item): | |
24 | return False | |
25 | return True | |
26 | ||
27 | def describe_to(self, description): | |
28 | description.append_text('a sequence containing items matching ') \ | |
29 | .append_description_of(self.matcher) | |
30 | ||
31 | ||
32 | def only_contains(*items): | |
33 | """Matches if each element of sequence satisfies any of the given matchers. | |
34 | ||
35 | :param match1,...: A comma-separated list of matchers. | |
36 | ||
37 | This matcher iterates the evaluated sequence, confirming whether each | |
38 | element satisfies any of the given matchers. | |
39 | ||
40 | Example:: | |
41 | ||
42 | only_contains(less_than(4)) | |
43 | ||
44 | will match ``[3,1,2]``. | |
45 | ||
46 | Any argument that is not a matcher is implicitly wrapped in an | |
47 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
48 | equality. | |
49 | ||
50 | """ | |
51 | matchers = [] | |
52 | for item in items: | |
53 | matchers.append(wrap_matcher(item)) | |
54 | return IsSequenceOnlyContaining(apply(any_of, matchers)) |
0 | """Utilities for integrating Hamcrest with other libraries.""" | |
1 | ||
2 | from match_equality import match_equality | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" |
0 | from hamcrest.core.string_description import tostring | |
1 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
2 | ||
3 | __author__ = "Chris Rose" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | __unittest = True | |
7 | ||
8 | ||
9 | class EqualityWrapper(object): | |
10 | ||
11 | def __init__(self, matcher): | |
12 | self.matcher = matcher | |
13 | ||
14 | def __eq__(self, object): | |
15 | return self.matcher.matches(object) | |
16 | ||
17 | def __str__(self): | |
18 | return repr(self) | |
19 | ||
20 | def __repr__(self): | |
21 | return tostring(self.matcher) | |
22 | ||
23 | ||
24 | def match_equality(matcher): | |
25 | """Wraps a matcher to define equality in terms of satisfying the matcher. | |
26 | ||
27 | ``match_equality`` allows Hamcrest matchers to be used in libraries that | |
28 | are not Hamcrest-aware. They might use the equality operator:: | |
29 | ||
30 | assert match_equality(matcher) == object | |
31 | ||
32 | Or they might provide a method that uses equality for its test:: | |
33 | ||
34 | library.method_that_tests_eq(match_equality(matcher)) | |
35 | ||
36 | One concrete example is integrating with the ``assert_called_with`` methods | |
37 | in Michael Foord's `mock <http://www.voidspace.org.uk/python/mock/>`_ | |
38 | library. | |
39 | ||
40 | """ | |
41 | return EqualityWrapper(wrap_matcher(matcher)) |
0 | """Matchers that perform numeric comparisons.""" | |
1 | ||
2 | from iscloseto import close_to | |
3 | from ordering_comparison import greater_than, greater_than_or_equal_to, less_than, less_than_or_equal_to | |
4 | ||
5 | __author__ = "Jon Reid" | |
6 | __copyright__ = "Copyright 2011 hamcrest.org" | |
7 | __license__ = "BSD, see License.txt" |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from math import fabs | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | def isnumeric(value): | |
9 | return isinstance(value, (int, long, float)) | |
10 | ||
11 | ||
12 | class IsCloseTo(BaseMatcher): | |
13 | ||
14 | def __init__(self, value, delta): | |
15 | if not isnumeric(value): | |
16 | raise TypeError('IsCloseTo value must be numeric') | |
17 | if not isnumeric(delta): | |
18 | raise TypeError('IsCloseTo delta must be numeric') | |
19 | ||
20 | self.value = value | |
21 | self.delta = delta | |
22 | ||
23 | def _matches(self, item): | |
24 | if not isnumeric(item): | |
25 | return False | |
26 | return fabs(item - self.value) <= self.delta | |
27 | ||
28 | def describe_mismatch(self, item, mismatch_description): | |
29 | if not isnumeric(item): | |
30 | super(IsCloseTo, self).describe_mismatch(item, mismatch_description) | |
31 | else: | |
32 | actual_delta = fabs(item - self.value) | |
33 | mismatch_description.append_description_of(item) \ | |
34 | .append_text(' differed by ') \ | |
35 | .append_description_of(actual_delta) | |
36 | ||
37 | def describe_to(self, description): | |
38 | description.append_text('a numeric value within ') \ | |
39 | .append_description_of(self.delta) \ | |
40 | .append_text(' of ') \ | |
41 | .append_description_of(self.value) | |
42 | ||
43 | ||
44 | def close_to(value, delta): | |
45 | """Matches if object is a number close to a given value, within a given | |
46 | delta. | |
47 | ||
48 | :param value: The value to compare against as the expected value. | |
49 | :param delta: The maximum delta between the values for which the numbers | |
50 | are considered close. | |
51 | ||
52 | This matcher compares the evaluated object against ``value`` to see if the | |
53 | difference is within a positive ``delta``. | |
54 | ||
55 | Example:: | |
56 | ||
57 | close_to(3.0, 0.25) | |
58 | ||
59 | """ | |
60 | return IsCloseTo(value, delta) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | import operator | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | class OrderingComparison(BaseMatcher): | |
9 | ||
10 | def __init__(self, value, comparison_function, comparison_description): | |
11 | self.value = value | |
12 | self.comparison_function = comparison_function | |
13 | self.comparison_description = comparison_description | |
14 | ||
15 | def _matches(self, item): | |
16 | return self.comparison_function(item, self.value) | |
17 | ||
18 | def describe_to(self, description): | |
19 | description.append_text('a value ') \ | |
20 | .append_text(self.comparison_description) \ | |
21 | .append_text(' ') \ | |
22 | .append_description_of(self.value) | |
23 | ||
24 | ||
25 | def greater_than(value): | |
26 | """Matches if object is greater than a given value. | |
27 | ||
28 | :param value: The value to compare against. | |
29 | ||
30 | """ | |
31 | return OrderingComparison(value, operator.gt, 'greater than') | |
32 | ||
33 | ||
34 | def greater_than_or_equal_to(value): | |
35 | """Matches if object is greater than or equal to a given value. | |
36 | ||
37 | :param value: The value to compare against. | |
38 | ||
39 | """ | |
40 | return OrderingComparison(value, operator.ge, 'greater than or equal to') | |
41 | ||
42 | ||
43 | def less_than(value): | |
44 | """Matches if object is less than a given value. | |
45 | ||
46 | :param value: The value to compare against. | |
47 | ||
48 | """ | |
49 | return OrderingComparison(value, operator.lt, 'less than') | |
50 | ||
51 | ||
52 | def less_than_or_equal_to(value): | |
53 | """Matches if object is less than or equal to a given value. | |
54 | ||
55 | :param value: The value to compare against. | |
56 | ||
57 | """ | |
58 | return OrderingComparison(value, operator.le, 'less than or equal to') |
0 | """Matchers that inspect objects and classes.""" | |
1 | ||
2 | from haslength import has_length | |
3 | from hasproperty import has_property | |
4 | from hasstring import has_string | |
5 | ||
6 | __author__ = "Jon Reid" | |
7 | __copyright__ = "Copyright 2011 hamcrest.org" | |
8 | __license__ = "BSD, see License.txt" |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | from hamcrest.core.helpers.hasmethod import hasmethod | |
6 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
7 | ||
8 | ||
9 | class HasLength(BaseMatcher): | |
10 | ||
11 | def __init__(self, len_matcher): | |
12 | self.len_matcher = len_matcher | |
13 | ||
14 | def _matches(self, item): | |
15 | if not hasmethod(item, '__len__'): | |
16 | return False | |
17 | return self.len_matcher.matches(len(item)) | |
18 | ||
19 | def describe_mismatch(self, item, mismatch_description): | |
20 | super(HasLength, self).describe_mismatch(item, mismatch_description) | |
21 | if hasmethod(item, '__len__'): | |
22 | mismatch_description.append_text(' with length of ') \ | |
23 | .append_description_of(len(item)) | |
24 | ||
25 | def describe_to(self, description): | |
26 | description.append_text('an object with length of ') \ | |
27 | .append_description_of(self.len_matcher) | |
28 | ||
29 | ||
30 | def has_length(match): | |
31 | """Matches if ``len(item)`` satisfies a given matcher. | |
32 | ||
33 | :param match: The matcher to satisfy, or an expected value for | |
34 | :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
35 | ||
36 | This matcher invokes the :py:func:`len` function on the evaluated object to | |
37 | get its length, passing the result to a given matcher for evaluation. | |
38 | ||
39 | If the ``match`` argument is not a matcher, it is implicitly wrapped in an | |
40 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
41 | :equality. | |
42 | ||
43 | Examples:: | |
44 | ||
45 | has_length(greater_than(6)) | |
46 | has_length(5) | |
47 | ||
48 | """ | |
49 | return HasLength(wrap_matcher(match)) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core import anything | |
2 | from hamcrest.core.string_description import StringDescription | |
3 | from hamcrest.core.helpers.hasmethod import hasmethod | |
4 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher as wrap_shortcut | |
5 | ||
6 | __author__ = "Chris Rose" | |
7 | __copyright__ = "Copyright 2011 hamcrest.org" | |
8 | __license__ = "BSD, see License.txt" | |
9 | ||
10 | ||
11 | class IsObjectWithProperty(BaseMatcher): | |
12 | ||
13 | def __init__(self, property_name, value_matcher): | |
14 | self.property_name = property_name | |
15 | self.value_matcher = value_matcher | |
16 | ||
17 | def _matches(self, o): | |
18 | if o is None: | |
19 | return False | |
20 | ||
21 | if not hasattr(o, self.property_name): | |
22 | return False | |
23 | ||
24 | value = getattr(o, self.property_name) | |
25 | return self.value_matcher.matches(value) | |
26 | ||
27 | def describe_to(self, description): | |
28 | description.append_text("an object with a property '") \ | |
29 | .append_text(self.property_name) \ | |
30 | .append_text("' matching ") \ | |
31 | .append_description_of(self.value_matcher) | |
32 | ||
33 | def describe_mismatch(self, item, mismatch_description): | |
34 | if item is None: | |
35 | mismatch_description.append_text('was None') | |
36 | return | |
37 | ||
38 | if not hasattr(item, self.property_name): | |
39 | mismatch_description.append_value(item) \ | |
40 | .append_text(' did not have the ') \ | |
41 | .append_value(self.property_name) \ | |
42 | .append_text(' property') | |
43 | return | |
44 | ||
45 | mismatch_description.append_text('property ').append_value(self.property_name).append_text(' ') | |
46 | value = getattr(item, self.property_name) | |
47 | self.value_matcher.describe_mismatch(value, mismatch_description) | |
48 | ||
49 | def __str__(self): | |
50 | d = StringDescription() | |
51 | self.describe_to(d) | |
52 | return str(d) | |
53 | ||
54 | ||
55 | def has_property(name, match=None): | |
56 | """Matches if object has a property with a given name whose value satisfies | |
57 | a given matcher. | |
58 | ||
59 | :param name: The name of the property. | |
60 | :param match: Optional matcher to satisfy. | |
61 | ||
62 | This matcher determines if the evaluated object has a property with a given | |
63 | name. If no such property is found, ``has_property`` is not satisfied. | |
64 | ||
65 | If the property is found, its value is passed to a given matcher for | |
66 | evaluation. If the ``match`` argument is not a matcher, it is implicitly | |
67 | wrapped in an :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to | |
68 | check for equality. | |
69 | ||
70 | If the ``match`` argument is not provided, the | |
71 | :py:func:`~hamcrest.core.core.isanything.anything` matcher is used so that | |
72 | ``has_property`` is satisfied if a matching property is found. | |
73 | ||
74 | Examples:: | |
75 | ||
76 | has_property('name', starts_with('J')) | |
77 | has_property('name', 'Jon') | |
78 | has_property('name') | |
79 | ||
80 | """ | |
81 | ||
82 | if match is None: | |
83 | match = anything() | |
84 | ||
85 | return IsObjectWithProperty(name, wrap_shortcut(match)) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
6 | ||
7 | ||
8 | class HasString(BaseMatcher): | |
9 | ||
10 | def __init__(self, str_matcher): | |
11 | self.str_matcher = str_matcher | |
12 | ||
13 | def _matches(self, item): | |
14 | return self.str_matcher.matches(str(item)) | |
15 | ||
16 | def describe_to(self, description): | |
17 | description.append_text('an object with str ') \ | |
18 | .append_description_of(self.str_matcher) | |
19 | ||
20 | ||
21 | def has_string(match): | |
22 | """Matches if ``str(item)`` satisfies a given matcher. | |
23 | ||
24 | :param match: The matcher to satisfy, or an expected value for | |
25 | :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
26 | ||
27 | This matcher invokes the :py:func:`str` function on the evaluated object to | |
28 | get its length, passing the result to a given matcher for evaluation. If | |
29 | the ``match`` argument is not a matcher, it is implicitly wrapped in an | |
30 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
31 | equality. | |
32 | ||
33 | Examples:: | |
34 | ||
35 | has_string(starts_with('foo')) | |
36 | has_string('bar') | |
37 | ||
38 | """ | |
39 | return HasString(wrap_matcher(match)) |
0 | """Matchers that perform text comparisons.""" | |
1 | ||
2 | from isequal_ignoring_case import equal_to_ignoring_case | |
3 | from isequal_ignoring_whitespace import equal_to_ignoring_whitespace | |
4 | from stringcontains import contains_string | |
5 | from stringendswith import ends_with | |
6 | from stringstartswith import starts_with | |
7 | ||
8 | __author__ = "Jon Reid" | |
9 | __copyright__ = "Copyright 2011 hamcrest.org" | |
10 | __license__ = "BSD, see License.txt" |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | ||
6 | ||
7 | class IsEqualIgnoringCase(BaseMatcher): | |
8 | ||
9 | def __init__(self, string): | |
10 | if not isinstance(string, basestring): | |
11 | raise TypeError('IsEqualIgnoringCase requires string') | |
12 | self.original_string = string | |
13 | self.lowered_string = string.lower() | |
14 | ||
15 | def _matches(self, item): | |
16 | if not isinstance(item, basestring): | |
17 | return False | |
18 | return self.lowered_string == item.lower() | |
19 | ||
20 | def describe_to(self, description): | |
21 | description.append_description_of(self.original_string) \ | |
22 | .append_text(' ignoring case') | |
23 | ||
24 | ||
25 | def equal_to_ignoring_case(string): | |
26 | """Matches if object is a string equal to a given string, ignoring case | |
27 | differences. | |
28 | ||
29 | :param string: The string to compare against as the expected value. | |
30 | ||
31 | This matcher first checks whether the evaluated object is a string. If so, | |
32 | it compares it with ``string``, ignoring differences of case. | |
33 | ||
34 | Example:: | |
35 | ||
36 | equal_to_ignoring_case("hello world") | |
37 | ||
38 | will match "heLLo WorlD". | |
39 | ||
40 | """ | |
41 | return IsEqualIgnoringCase(string) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | ||
6 | ||
7 | def stripspace(string): | |
8 | result = '' | |
9 | last_was_space = True | |
10 | for character in string: | |
11 | if character.isspace(): | |
12 | if not last_was_space: | |
13 | result += ' ' | |
14 | last_was_space = True | |
15 | else: | |
16 | result += character | |
17 | last_was_space = False | |
18 | return result.strip() | |
19 | ||
20 | ||
21 | class IsEqualIgnoringWhiteSpace(BaseMatcher): | |
22 | ||
23 | def __init__(self, string): | |
24 | if not isinstance(string, basestring): | |
25 | raise TypeError('IsEqualIgnoringWhiteSpace requires string') | |
26 | self.original_string = string | |
27 | self.stripped_string = stripspace(string) | |
28 | ||
29 | def _matches(self, item): | |
30 | if not isinstance(item, basestring): | |
31 | return False | |
32 | return self.stripped_string == stripspace(item) | |
33 | ||
34 | def describe_to(self, description): | |
35 | description.append_description_of(self.original_string) \ | |
36 | .append_text(' ignoring whitespace') | |
37 | ||
38 | ||
39 | def equal_to_ignoring_whitespace(string): | |
40 | """Matches if object is a string equal to a given string, ignoring | |
41 | differences in whitespace. | |
42 | ||
43 | :param string: The string to compare against as the expected value. | |
44 | ||
45 | This matcher first checks whether the evaluated object is a string. If so, | |
46 | it compares it with ``string``, ignoring differences in runs of whitespace. | |
47 | ||
48 | Example:: | |
49 | ||
50 | equal_to_ignoring_case("hello world") | |
51 | ||
52 | will match ``"hello world"``. | |
53 | ||
54 | """ | |
55 | return IsEqualIgnoringWhiteSpace(string) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.library.text.substringmatcher import SubstringMatcher | |
5 | from hamcrest.core.helpers.hasmethod import hasmethod | |
6 | ||
7 | ||
8 | class StringContains(SubstringMatcher): | |
9 | ||
10 | def __init__(self, substring): | |
11 | super(StringContains, self).__init__(substring) | |
12 | ||
13 | def _matches(self, item): | |
14 | if not hasmethod(item, 'find'): | |
15 | return False | |
16 | return item.find(self.substring) >= 0 | |
17 | ||
18 | def relationship(self): | |
19 | return 'containing' | |
20 | ||
21 | ||
22 | def contains_string(substring): | |
23 | """Matches if object is a string containing a given string. | |
24 | ||
25 | :param string: The string to search for. | |
26 | ||
27 | This matcher first checks whether the evaluated object is a string. If so, | |
28 | it checks whether it contains ``string``. | |
29 | ||
30 | Example:: | |
31 | ||
32 | contains_string("def") | |
33 | ||
34 | will match "abcdefg". | |
35 | ||
36 | """ | |
37 | return StringContains(substring) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | ||
3 | __author__ = "Romilly Cocking" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | class StringContainsInOrder(BaseMatcher): | |
9 | ||
10 | def __init__(self, *substrings): | |
11 | for substring in substrings: | |
12 | if not isinstance(substring, basestring): | |
13 | raise TypeError(self.__class__.__name__ | |
14 | + ' requires string arguments') | |
15 | self.substrings = substrings | |
16 | ||
17 | def _matches(self, item): | |
18 | if not hasmethod(item, 'find'): | |
19 | return False | |
20 | from_index = 0 | |
21 | for substring in self.substrings: | |
22 | from_index = item.find(substring, from_index) | |
23 | if from_index == -1: | |
24 | return False | |
25 | return True | |
26 | ||
27 | def describe_to(self, description): | |
28 | description.append_list('a string containing ', ', ', ' in order', | |
29 | self.substrings) | |
30 | ||
31 | ||
32 | def string_contains_in_order(*substrings): | |
33 | """Matches if object is a string containing a given list of substrings in | |
34 | relative order. | |
35 | ||
36 | :param string1,...: A comma-separated list of strings. | |
37 | ||
38 | This matcher first checks whether the evaluated object is a string. If so, | |
39 | it checks whether it contains a given list of strings, in relative order to | |
40 | each other. The searches are performed starting from the beginning of the | |
41 | evaluated string. | |
42 | ||
43 | Example:: | |
44 | ||
45 | string_contains_in_order("bc", "fg", "jkl") | |
46 | ||
47 | will match "abcdefghijklm". | |
48 | ||
49 | """ | |
50 | return StringContainsInOrder(*substrings) |
0 | from hamcrest.library.text.substringmatcher import SubstringMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | class StringEndsWith(SubstringMatcher): | |
9 | ||
10 | def __init__(self, substring): | |
11 | super(StringEndsWith, self).__init__(substring) | |
12 | ||
13 | def _matches(self, item): | |
14 | if not hasmethod(item, 'endswith'): | |
15 | return False | |
16 | return item.endswith(self.substring) | |
17 | ||
18 | def relationship(self): | |
19 | return 'ending with' | |
20 | ||
21 | ||
22 | def ends_with(string): | |
23 | """Matches if object is a string ending with a given string. | |
24 | ||
25 | :param string: The string to search for. | |
26 | ||
27 | This matcher first checks whether the evaluated object is a string. If so, | |
28 | it checks if ``string`` matches the ending characters of the evaluated | |
29 | object. | |
30 | ||
31 | Example:: | |
32 | ||
33 | ends_with("bar") | |
34 | ||
35 | will match "foobar". | |
36 | ||
37 | """ | |
38 | return StringEndsWith(string) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.library.text.substringmatcher import SubstringMatcher | |
5 | from hamcrest.core.helpers.hasmethod import hasmethod | |
6 | ||
7 | ||
8 | class StringStartsWith(SubstringMatcher): | |
9 | ||
10 | def __init__(self, substring): | |
11 | super(StringStartsWith, self).__init__(substring) | |
12 | ||
13 | def _matches(self, item): | |
14 | if not hasmethod(item, 'startswith'): | |
15 | return False | |
16 | return item.startswith(self.substring) | |
17 | ||
18 | def relationship(self): | |
19 | return 'starting with' | |
20 | ||
21 | ||
22 | def starts_with(substring): | |
23 | """Matches if object is a string starting with a given string. | |
24 | ||
25 | :param string: The string to search for. | |
26 | ||
27 | This matcher first checks whether the evaluated object is a string. If so, | |
28 | it checks if ``string`` matches the beginning characters of the evaluated | |
29 | object. | |
30 | ||
31 | Example:: | |
32 | ||
33 | starts_with("foo") | |
34 | ||
35 | will match "foobar". | |
36 | ||
37 | """ | |
38 | return StringStartsWith(substring) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | class SubstringMatcher(BaseMatcher): | |
8 | ||
9 | def __init__(self, substring): | |
10 | if not isinstance(substring, basestring): | |
11 | raise TypeError(self.__class__.__name__ + ' requires string') | |
12 | self.substring = substring | |
13 | ||
14 | def describe_to(self, description): | |
15 | description.append_text('a string ') \ | |
16 | .append_text(self.relationship()) \ | |
17 | .append_text(' ') \ | |
18 | .append_description_of(self.substring) |
0 | import logging | |
1 | logging.basicConfig() | |
2 | ||
3 | from alltests import alltests | |
4 | ||
5 | __author__ = "Jon Reid" | |
6 | __copyright__ = "Copyright 2011 hamcrest.org" | |
7 | __license__ = "BSD, see License.txt" | |
8 | ||
9 | ||
10 | def additional_tests(): | |
11 | return alltests() |
0 | import os | |
1 | import sys | |
2 | import unittest | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | if __name__ == "__main__": | |
9 | sys.path.insert(0, '..') | |
10 | ||
11 | ||
12 | def alltests(): | |
13 | """Returns suite of all tests in this directory and below.""" | |
14 | testloader = unittest.defaultTestLoader | |
15 | suite = testloader.suiteClass() | |
16 | ||
17 | fullpath = os.path.abspath(os.path.dirname(sys.argv[0])) | |
18 | for dirpath, dirnames, filenames in os.walk(fullpath): | |
19 | sys.path.insert(0, dirpath) | |
20 | for file in filenames: | |
21 | if file.endswith('test.py'): | |
22 | (name, ext) = os.path.splitext(file) | |
23 | module = __import__(name) | |
24 | suite.addTest(testloader.loadTestsFromModule(module)) | |
25 | sys.path.pop(0) | |
26 | ||
27 | return suite | |
28 | ||
29 | ||
30 | if __name__ == '__main__': | |
31 | unittest.main(defaultTest='alltests') |
0 | if __name__ == "__main__": | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | ||
4 | from hamcrest.core.assert_that import assert_that | |
5 | from hamcrest.core.core.isequal import equal_to | |
6 | import unittest | |
7 | ||
8 | __author__ = "Jon Reid" | |
9 | __copyright__ = "Copyright 2011 hamcrest.org" | |
10 | __license__ = "BSD, see License.txt" | |
11 | ||
12 | ||
13 | class AssertThatTest(unittest.TestCase): | |
14 | ||
15 | def testShouldBeSilentOnSuccessfulMatch(self): | |
16 | assert_that(1, equal_to(1)) | |
17 | ||
18 | def testAssertionErrorShouldDescribeExpectedAndActual(self): | |
19 | expected = 'EXPECTED' | |
20 | actual = 'ACTUAL' | |
21 | ||
22 | expectedMessage = "\nExpected: 'EXPECTED'\n but: was 'ACTUAL'\n" | |
23 | ||
24 | try: | |
25 | assert_that(actual, equal_to(expected)) | |
26 | except AssertionError, e: | |
27 | self.assertEqual(expectedMessage, str(e)) | |
28 | return | |
29 | self.fail('should have failed') | |
30 | ||
31 | def testAssertionErrorShouldIncludeOptionalReason(self): | |
32 | expected = 'EXPECTED' | |
33 | actual = 'ACTUAL' | |
34 | ||
35 | expectedMessage = "REASON\nExpected: 'EXPECTED'\n but: was 'ACTUAL'\n" | |
36 | ||
37 | try: | |
38 | assert_that(actual, equal_to(expected), 'REASON') | |
39 | except AssertionError, e: | |
40 | self.assertEqual(expectedMessage, str(e)) | |
41 | return | |
42 | self.fail('should have failed') | |
43 | ||
44 | def testCanTestBoolDirectly(self): | |
45 | assert_that(True, 'should accept True') | |
46 | ||
47 | try: | |
48 | assert_that(False, 'FAILURE REASON') | |
49 | except AssertionError, e: | |
50 | self.assertEqual('FAILURE REASON', str(e)) | |
51 | return | |
52 | ||
53 | self.fail('should have failed') | |
54 | ||
55 | def testCanTestBoolDirectlyWithoutReason(self): | |
56 | assert_that(True) | |
57 | ||
58 | try: | |
59 | assert_that(False) | |
60 | except AssertionError, e: | |
61 | self.assertEqual('Assertion failed', str(e)) | |
62 | return | |
63 | ||
64 | self.fail('should have failed') | |
65 | ||
66 | ||
67 | if __name__ == "__main__": | |
68 | unittest.main() |
0 | if __name__ == "__main__": | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | ||
4 | from hamcrest.core.base_matcher import * | |
5 | ||
6 | import unittest | |
7 | ||
8 | __author__ = "Jon Reid" | |
9 | __copyright__ = "Copyright 2011 hamcrest.org" | |
10 | __license__ = "BSD, see License.txt" | |
11 | ||
12 | ||
13 | class TestingBaseMatcher(BaseMatcher): | |
14 | ||
15 | def describe_to(self, description): | |
16 | description.append_text('SOME DESCRIPTION') | |
17 | ||
18 | ||
19 | class BaseMatcherTest(unittest.TestCase): | |
20 | ||
21 | def testStrFunctionShouldDescribeMatcher(self): | |
22 | matcher = TestingBaseMatcher() | |
23 | self.assertEqual('SOME DESCRIPTION', str(matcher)) | |
24 | ||
25 | ||
26 | if __name__ == "__main__": | |
27 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.collection.isdict_containing import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | ||
9 | from hamcrest_unit_test.matcher_test import MatcherTest | |
10 | from quasidict import QuasiDictionary | |
11 | import unittest | |
12 | ||
13 | __author__ = "Jon Reid" | |
14 | __copyright__ = "Copyright 2011 hamcrest.org" | |
15 | __license__ = "BSD, see License.txt" | |
16 | ||
17 | ||
18 | class IsDictContainingTest(MatcherTest): | |
19 | ||
20 | def testMatchesDictionaryContainingMatchingKeyAndValue(self): | |
21 | dict = {'a': 1, 'b': 2} | |
22 | self.assert_matches('has a:1', has_entry(equal_to('a'), equal_to(1)), dict) | |
23 | self.assert_matches('has b:2', has_entry(equal_to('b'), equal_to(2)), dict) | |
24 | self.assert_does_not_match('no c:3', has_entry(equal_to('c'), equal_to(3)), dict) | |
25 | ||
26 | def testProvidesConvenientShortcutForMatchingWithEqualTo(self): | |
27 | dict = {'a': 1, 'b': 2} | |
28 | self.assert_matches('has a:1', has_entry('a', equal_to(1)), dict) | |
29 | self.assert_matches('has b:2', has_entry(equal_to('b'), 2), dict) | |
30 | self.assert_does_not_match('no c:3', has_entry('c', 3), dict) | |
31 | ||
32 | def testMatchesAnyConformingDictionary(self): | |
33 | self.assert_matches('quasi-dictionary', has_entry(1, '1'), QuasiDictionary()) | |
34 | self.assert_does_not_match('non-dictionary', has_entry(1, '1'), object()) | |
35 | ||
36 | def testHasReadableDescription(self): | |
37 | self.assert_description("a dictionary containing ['a': <1>]", | |
38 | has_entry('a', 1)) | |
39 | ||
40 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
41 | self.assert_no_mismatch_description(has_entry('a', 1), {'a': 1}) | |
42 | ||
43 | def testMismatchDescriptionShowsActualArgument(self): | |
44 | self.assert_mismatch_description("was 'bad'", has_entry('a', 1), 'bad') | |
45 | ||
46 | def testDescribeMismatch(self): | |
47 | self.assert_describe_mismatch("was 'bad'", has_entry('a', 1), 'bad') | |
48 | ||
49 | ||
50 | if __name__ == '__main__': | |
51 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.collection.isdict_containingentries import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | import unittest | |
10 | ||
11 | __author__ = "Jon Reid" | |
12 | __copyright__ = "Copyright 2011 hamcrest.org" | |
13 | __license__ = "BSD, see License.txt" | |
14 | ||
15 | ||
16 | class IsDictContainingEntriesTest(MatcherTest): | |
17 | ||
18 | def testMatcherCreationRequiresEvenNumberOfPositionalArgs(self): | |
19 | self.assertRaises(ValueError, has_entries, 'a', 'b', 'c') | |
20 | ||
21 | def testDoesNotMatchNonDictionary(self): | |
22 | self.assert_does_not_match('non-dictionary', | |
23 | has_entries('a', equal_to(1)), object()) | |
24 | ||
25 | def testMatchesDictLike(self): | |
26 | class DictLike(object): | |
27 | def __getitem__(self, key): | |
28 | return 'value: ' + str(key) | |
29 | def __contains__(self, key): | |
30 | return True | |
31 | self.assert_matches('matches a dictionary-like object', | |
32 | has_entries('a', equal_to('value: a')), | |
33 | DictLike()) | |
34 | ||
35 | def testMatchesUsingSingleDictionaryArgument(self): | |
36 | target = {'a': 1, 'b': 2, 'c': 3} | |
37 | self.assert_matches('has a & b', | |
38 | has_entries({'a':equal_to(1), 'b':equal_to(2)}), target) | |
39 | self.assert_matches('has c & a', | |
40 | has_entries({'c':equal_to(3), 'a':equal_to(1)}), target) | |
41 | self.assert_does_not_match('no d:3', | |
42 | has_entries({'b':equal_to(2), 'd':equal_to(3)}), target) | |
43 | ||
44 | def testMatcheSingleDictionaryArgumentWithImplicitEqualTo(self): | |
45 | target = {'a': 1, 'b': 2, 'c': 3} | |
46 | self.assert_matches('has a & b', | |
47 | has_entries({'a':1, 'b':2}), target) | |
48 | self.assert_matches('has c & a', | |
49 | has_entries({'c':3, 'a':1}), target) | |
50 | self.assert_does_not_match('no d:3', | |
51 | has_entries({'b':2, 'd': 3}), target) | |
52 | ||
53 | def testMatchesUsingKwargs(self): | |
54 | target = {'a': 1, 'b': 2, 'c': 3} | |
55 | self.assert_matches('has a & b', | |
56 | has_entries(a=equal_to(1), b=equal_to(2)), target) | |
57 | self.assert_matches('has c & a', | |
58 | has_entries(c=equal_to(3), a=equal_to(1)), target) | |
59 | self.assert_does_not_match('no d:3', | |
60 | has_entries(b=equal_to(2), d=equal_to(3)), target) | |
61 | ||
62 | def testMatchesKwargsWithImplicitEqualTo(self): | |
63 | target = {'a': 1, 'b': 2, 'c': 3} | |
64 | self.assert_matches('has a & b', | |
65 | has_entries(a=1, b=2), target) | |
66 | self.assert_matches('has c & a', | |
67 | has_entries(c=3, a=1), target) | |
68 | self.assert_does_not_match('no d:3', | |
69 | has_entries(b=2, d=3), target) | |
70 | ||
71 | def testMatchesDictionaryContainingSingleKeyWithMatchingValue(self): | |
72 | target = {'a': 1, 'b': 2} | |
73 | self.assert_matches('has a:1', has_entries('a', equal_to(1)), target) | |
74 | self.assert_matches('has b:2', has_entries('b', equal_to(2)), target) | |
75 | self.assert_does_not_match('no b:3', has_entries('b', equal_to(3)), target) | |
76 | self.assert_does_not_match('no c:2', has_entries('c', equal_to(2)), target) | |
77 | ||
78 | def testMatchesDictionaryContainingMultipleKeysWithMatchingValues(self): | |
79 | target = {'a': 1, 'b': 2, 'c': 3} | |
80 | self.assert_matches('has a & b', | |
81 | has_entries('a', equal_to(1), 'b', equal_to(2)), target) | |
82 | self.assert_matches('has c & a', | |
83 | has_entries('c', equal_to(3), 'a', equal_to(1)), target) | |
84 | self.assert_does_not_match('no d:3', | |
85 | has_entries('b', equal_to(3), 'd', equal_to(3)), target) | |
86 | ||
87 | def testProvidesConvenientShortcutForMatchingWithEqualTo(self): | |
88 | target = {'a': 1, 'b': 2, 'c': 3} | |
89 | self.assert_matches('has a & b', has_entries('a', 1, 'b', 2), target) | |
90 | self.assert_matches('has c & a', has_entries('c', 3, 'a', 1), target) | |
91 | self.assert_does_not_match('no d:4', has_entries('b', 3, 'd', 4), target) | |
92 | ||
93 | def testHasReadableDescription(self): | |
94 | self.assert_description("a dictionary containing {'a': <1>, 'b': <2>}", | |
95 | has_entries('a', 1, 'b', 2)) | |
96 | ||
97 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
98 | self.assert_no_mismatch_description(has_entries('a', 1), {'a': 1}) | |
99 | ||
100 | def testMismatchDescriptionOfNonDictionaryShowsActualArgument(self): | |
101 | self.assert_mismatch_description("'bad' is not a mapping object", has_entries('a', 1), 'bad') | |
102 | ||
103 | def testMismatchDescriptionOfDictionaryWithoutKey(self): | |
104 | self.assert_mismatch_description("no 'b' key in <{'a': 1, 'c': 3}>", | |
105 | has_entries('a', 1, 'b', 2), {'a': 1, 'c': 3}) | |
106 | ||
107 | def testMismatchDescriptionOfDictionaryWithNonMatchingValue(self): | |
108 | self.assert_mismatch_description("value for 'a' was <2>", | |
109 | has_entries('a', 1), {'a': 2}) | |
110 | ||
111 | def testDescribeMismatchOfNonDictionaryShowsActualArgument(self): | |
112 | self.assert_describe_mismatch("'bad' is not a mapping object", has_entries('a', 1), 'bad') | |
113 | ||
114 | def testDescribeMismatchOfDictionaryWithoutKey(self): | |
115 | self.assert_describe_mismatch("no 'b' key in <{'a': 1, 'c': 3}>", | |
116 | has_entries('a', 1, 'b', 2), {'a': 1, 'c': 3}) | |
117 | ||
118 | def testDescribeMismatchOfDictionaryWithNonMatchingValue(self): | |
119 | self.assert_describe_mismatch("value for 'a' was <2>", | |
120 | has_entries('a', 1), {'a': 2}) | |
121 | ||
122 | ||
123 | if __name__ == '__main__': | |
124 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.collection.isdict_containingkey import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | from quasidict import QuasiDictionary | |
10 | import unittest | |
11 | ||
12 | __author__ = "Jon Reid" | |
13 | __copyright__ = "Copyright 2011 hamcrest.org" | |
14 | __license__ = "BSD, see License.txt" | |
15 | ||
16 | ||
17 | class IsDictContainingKeyTest(MatcherTest): | |
18 | ||
19 | def testMatchesSingletonDictionaryContainingKey(self): | |
20 | dict = {'a': 1} | |
21 | self.assert_matches('same single key', has_key(equal_to('a')), dict) | |
22 | ||
23 | def testMatchesDictionaryContainingKey(self): | |
24 | dict = {'a': 1, 'b': 2, 'c': 3} | |
25 | self.assert_matches('Matches a', has_key(equal_to('a')), dict) | |
26 | self.assert_matches('Matches c', has_key(equal_to('c')), dict) | |
27 | ||
28 | def testProvidesConvenientShortcutForMatchingWithEqualTo(self): | |
29 | dict = {'a': 1, 'b': 2, 'c': 3} | |
30 | self.assert_matches('Matches c', has_key('c'), dict) | |
31 | ||
32 | def testDoesNotMatchEmptyDictionary(self): | |
33 | self.assert_does_not_match('empty', has_key('foo'), {}); | |
34 | ||
35 | def testDoesNotMatchDictionaryMissingKey(self): | |
36 | dict = {'a': 1, 'b': 2, 'c': 3} | |
37 | self.assert_does_not_match('no matching key', has_key('d'), dict) | |
38 | ||
39 | def testMatchesAnyConformingDictionary(self): | |
40 | self.assert_matches('quasi-dictionary', has_key(1), QuasiDictionary()) | |
41 | self.assert_does_not_match('non-dictionary', has_key(1), object()) | |
42 | ||
43 | def testHasReadableDescription(self): | |
44 | self.assert_description("a dictionary containing key 'a'", has_key('a')) | |
45 | ||
46 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
47 | self.assert_no_mismatch_description(has_key('a'), {'a': 1}) | |
48 | ||
49 | def testMismatchDescriptionShowsActualArgument(self): | |
50 | self.assert_mismatch_description("was 'bad'", has_key('a'), 'bad') | |
51 | ||
52 | def testDescribeMismatch(self): | |
53 | self.assert_describe_mismatch("was 'bad'", has_key('a'), 'bad') | |
54 | ||
55 | ||
56 | if __name__ == '__main__': | |
57 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.collection.isdict_containingvalue import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | from quasidict import QuasiDictionary | |
10 | import unittest | |
11 | ||
12 | __author__ = "Jon Reid" | |
13 | __copyright__ = "Copyright 2011 hamcrest.org" | |
14 | __license__ = "BSD, see License.txt" | |
15 | ||
16 | ||
17 | class IsDictContainingValueTest(MatcherTest): | |
18 | ||
19 | def testMatchesSingletonDictionaryContainingValue(self): | |
20 | dict = {'a': 1} | |
21 | self.assert_matches('same single value', has_value(equal_to(1)), dict) | |
22 | ||
23 | def testMatchesDictionaryContainingValue(self): | |
24 | dict = {'a': 1, 'b': 2, 'c': 3} | |
25 | self.assert_matches('Matches 1', has_value(equal_to(1)), dict) | |
26 | self.assert_matches('Matches 3', has_value(equal_to(3)), dict) | |
27 | ||
28 | def testProvidesConvenientShortcutForMatchingWithEqualTo(self): | |
29 | dict = {'a': 1, 'b': 2, 'c': 3} | |
30 | self.assert_matches('Matches 3', has_value(3), dict) | |
31 | ||
32 | def testDoesNotMatchEmptyDictionary(self): | |
33 | self.assert_does_not_match('empty', has_value(1), {}); | |
34 | ||
35 | def testDoesNotMatchDictionaryMissingValue(self): | |
36 | dict = {'a': 1, 'b': 2, 'c': 3} | |
37 | self.assert_does_not_match('no matching value', has_value(4), dict) | |
38 | ||
39 | def testMatchesAnyConformingDictionary(self): | |
40 | self.assert_matches('quasi-dictionary', has_value('1'), QuasiDictionary()) | |
41 | self.assert_does_not_match('non-dictionary', has_value('1'), object()) | |
42 | ||
43 | def testHasReadableDescription(self): | |
44 | self.assert_description("a dictionary containing value 'a'", has_value('a')) | |
45 | ||
46 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
47 | self.assert_no_mismatch_description(has_value(1), {'a': 1}) | |
48 | ||
49 | def testMismatchDescriptionShowsActualArgument(self): | |
50 | self.assert_mismatch_description("was 'bad'", has_value(1), 'bad') | |
51 | ||
52 | def testDescribeMismatch(self): | |
53 | self.assert_describe_mismatch("was 'bad'", has_value(1), 'bad') | |
54 | ||
55 | ||
56 | if __name__ == '__main__': | |
57 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.collection.isin import * | |
6 | ||
7 | from hamcrest_unit_test.matcher_test import MatcherTest | |
8 | import unittest | |
9 | ||
10 | __author__ = "Jon Reid" | |
11 | __copyright__ = "Copyright 2011 hamcrest.org" | |
12 | __license__ = "BSD, see License.txt" | |
13 | ||
14 | ||
15 | sequence = ('a', 'b', 'c') | |
16 | ||
17 | class IsInTest(MatcherTest): | |
18 | ||
19 | def testReturnsTrueIfArgumentIsInSequence(self): | |
20 | matcher = is_in(sequence) | |
21 | ||
22 | self.assert_matches('has a', matcher, 'a') | |
23 | self.assert_matches('has b', matcher, 'b') | |
24 | self.assert_matches('has c', matcher, 'c') | |
25 | self.assert_does_not_match('no d', matcher, 'd') | |
26 | ||
27 | def testHasReadableDescription(self): | |
28 | self.assert_description("one of ('a', 'b', 'c')", is_in(sequence)) | |
29 | ||
30 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
31 | self.assert_no_mismatch_description(is_in(sequence), 'a') | |
32 | ||
33 | def testMismatchDescriptionShowsActualArgument(self): | |
34 | self.assert_mismatch_description("was 'bad'", is_in(sequence), 'bad') | |
35 | ||
36 | def testDescribeMismatch(self): | |
37 | self.assert_describe_mismatch("was 'bad'", is_in(sequence), 'bad') | |
38 | ||
39 | ||
40 | if __name__ == '__main__': | |
41 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.collection.issequence_containing import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | from quasisequence import QuasiSequence | |
10 | import unittest | |
11 | ||
12 | __author__ = "Jon Reid" | |
13 | __copyright__ = "Copyright 2011 hamcrest.org" | |
14 | __license__ = "BSD, see License.txt" | |
15 | ||
16 | ||
17 | class IsSequenceContainingTest(MatcherTest): | |
18 | ||
19 | def testMatchesASequenceThatContainsAnElementMatchingTheGivenMatcher(self): | |
20 | self.assert_matches("sequence contains 'a'", | |
21 | has_item(equal_to('a')), ['a', 'b', 'c']) | |
22 | ||
23 | def testNoMatchIfSequenceDoesntContainAnElementMatchingTheGivenMatcher(self): | |
24 | self.assert_does_not_match("sequence without 'a'", | |
25 | has_item(equal_to('a')), ['b', 'c']) | |
26 | self.assert_does_not_match('empty', has_item(equal_to('a')), []) | |
27 | ||
28 | def testProvidesConvenientShortcutForMatchingWithEqualTo(self): | |
29 | self.assert_matches("sequence contains 'a'", | |
30 | has_item('a'), ['a', 'b', 'c']) | |
31 | self.assert_does_not_match("sequence without 'a'", | |
32 | has_item('a'), ['b', 'c']) | |
33 | ||
34 | def testMatchesAnyConformingSequence(self): | |
35 | self.assert_matches('quasi-sequence', has_item(1), QuasiSequence()) | |
36 | self.assert_does_not_match('non-sequence', has_item(1), object()) | |
37 | ||
38 | def testHasAReadableDescription(self): | |
39 | self.assert_description("a sequence containing 'a'", has_item('a')) | |
40 | ||
41 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
42 | self.assert_no_mismatch_description(has_item('a'), ['a', 'b']) | |
43 | ||
44 | def testMismatchDescriptionShowsActualArgument(self): | |
45 | self.assert_mismatch_description("was <42>", has_item('a'), 42) | |
46 | ||
47 | def testDescribeMismatch(self): | |
48 | self.assert_describe_mismatch("was <42>", has_item('a'), 42) | |
49 | ||
50 | ||
51 | class IsSequenceContainingItemsTest(MatcherTest): | |
52 | ||
53 | def testShouldMatchCollectionContainingAllItems(self): | |
54 | self.assert_matches('contains all items', | |
55 | has_items(equal_to('a'), equal_to('b'), equal_to('c')), | |
56 | ('a', 'b', 'c')) | |
57 | ||
58 | def testProvidesConvenientShortcutForMatchingWithEqualTo(self): | |
59 | self.assert_matches('Values automatically wrapped with equal_to', | |
60 | has_items('a', 'b', 'c'), | |
61 | ('a', 'b', 'c')) | |
62 | ||
63 | def testShouldMatchCollectionContainingAllItemsInDifferentOrder(self): | |
64 | self.assert_matches('all items in different order', | |
65 | has_items('a', 'b', 'c'), | |
66 | ('c', 'b', 'a')) | |
67 | ||
68 | def testShouldMatchCollectionContainingAllItemsPlusExtras(self): | |
69 | self.assert_matches('all items plus extras', | |
70 | has_items('a', 'b', 'c'), | |
71 | ('e', 'c', 'b', 'a', 'd')) | |
72 | ||
73 | def testNoMatchIfCollectionDoesntSatisfyAllMatchers(self): | |
74 | self.assert_does_not_match("missing 'a'", | |
75 | has_items('a', 'b', 'c'), | |
76 | ('e', 'c', 'b', 'd')) | |
77 | ||
78 | def testHasAReadableDescription(self): | |
79 | self.assert_description( | |
80 | "(a sequence containing 'a' and a sequence containing 'b')", | |
81 | has_items('a', 'b')) | |
82 | ||
83 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
84 | self.assert_no_mismatch_description(has_items('a', 'b'), ['a', 'b']) | |
85 | ||
86 | def testMismatchDescriptionShowsFirstUnmetMatcherAndActualArgument(self): | |
87 | self.assert_mismatch_description("a sequence containing 'a' was <42>", | |
88 | has_items('a', 'b'), 42) | |
89 | ||
90 | def testDescribeMismatch(self): | |
91 | self.assert_describe_mismatch("a sequence containing 'a' was <42>", | |
92 | has_items('a', 'b'), 42) | |
93 | ||
94 | ||
95 | if __name__ == '__main__': | |
96 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.collection.issequence_containinginanyorder import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | from quasisequence import QuasiSequence | |
10 | import unittest | |
11 | ||
12 | __author__ = "Jon Reid" | |
13 | __copyright__ = "Copyright 2011 hamcrest.org" | |
14 | __license__ = "BSD, see License.txt" | |
15 | ||
16 | ||
17 | class IsSequenceContainingInAnyOrderTest(MatcherTest): | |
18 | ||
19 | def testMatchingSingleItemSequence(self): | |
20 | self.assert_matches("Single item sequence", | |
21 | contains_inanyorder(equal_to(1)), [1]) | |
22 | ||
23 | def testMatchesSequenceInOrder(self): | |
24 | self.assert_matches("In order", | |
25 | contains_inanyorder(equal_to(1), equal_to(2)), [1,2]) | |
26 | ||
27 | def testMatchesSequenceOutOfOrder(self): | |
28 | self.assert_matches("Out of order", | |
29 | contains_inanyorder(equal_to(1), equal_to(2)), | |
30 | [2,1]) | |
31 | ||
32 | def testProvidesConvenientShortcutForMatchingWithEqualTo(self): | |
33 | self.assert_matches("Values automatically wrapped with equal_to", | |
34 | contains_inanyorder(1,2), [2,1]) | |
35 | ||
36 | def testDoesNotMatchEmptySequence(self): | |
37 | self.assert_mismatch_description("no item matches: <1>, <2> in []", | |
38 | contains_inanyorder(1, 2), []) | |
39 | ||
40 | def testEmptySequenceMatchesEmptySequence(self): | |
41 | self.assert_matches("Empty sequence", contains_inanyorder(), []) | |
42 | ||
43 | def testDoesNotMatchIfOneOfMultipleItemsMismatch(self): | |
44 | self.assert_mismatch_description("not matched: <4>", | |
45 | contains_inanyorder(1,2,3), [1,2,4]) | |
46 | ||
47 | def testDoesNotMatchWithMoreElementsThanExpected(self): | |
48 | self.assert_mismatch_description("not matched: <2>", | |
49 | contains_inanyorder(1,3), [1,2,3]) | |
50 | ||
51 | def testDoesNotMatchWithFewerElementsThanExpected(self): | |
52 | self.assert_mismatch_description( | |
53 | "no item matches: <4> in [<1>, <2>, <3>]", | |
54 | contains_inanyorder(1,2,3,4), [1,2,3]) | |
55 | ||
56 | def testMatchesAnyConformingSequence(self): | |
57 | self.assert_matches('quasi-sequence', contains_inanyorder(1,2), | |
58 | QuasiSequence()) | |
59 | self.assert_does_not_match('non-sequence', contains_inanyorder(1,2), | |
60 | object()) | |
61 | ||
62 | def testHasAReadableDescription(self): | |
63 | self.assert_description("a sequence over [<1>, <2>] in any order", | |
64 | contains_inanyorder(1,2)) | |
65 | ||
66 | def testDescribeMismatch(self): | |
67 | self.assert_describe_mismatch('not matched: <3>', | |
68 | contains_inanyorder(1,2), [1,3]) | |
69 | ||
70 | def testDescribeMismatchOfNonSequence(self): | |
71 | self.assert_describe_mismatch("was <3>", contains_inanyorder(1,2), 3) | |
72 | ||
73 | ||
74 | if __name__ == '__main__': | |
75 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.collection.issequence_containinginorder import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | from quasisequence import QuasiSequence | |
10 | import unittest | |
11 | ||
12 | __author__ = "Jon Reid" | |
13 | __copyright__ = "Copyright 2011 hamcrest.org" | |
14 | __license__ = "BSD, see License.txt" | |
15 | ||
16 | ||
17 | class IsSequenceContainingInOrderTest(MatcherTest): | |
18 | ||
19 | def testMatchingSingleItemSequence(self): | |
20 | self.assert_matches("Single item sequence", contains(equal_to(1)), [1]) | |
21 | ||
22 | def testMatchingMultipleItemSequence(self): | |
23 | self.assert_matches("Multiple item sequence", | |
24 | contains(equal_to(1), equal_to(2), equal_to(3)), | |
25 | [1,2,3]) | |
26 | ||
27 | def testProvidesConvenientShortcutForMatchingWithEqualTo(self): | |
28 | self.assert_matches("Values automatically wrapped with equal_to", | |
29 | contains(1, 2, 3), | |
30 | [1,2,3]) | |
31 | ||
32 | def testDoesNotMatchWithMoreElementsThanExpected(self): | |
33 | self.assert_mismatch_description("Not matched: <4>", | |
34 | contains(1,2,3), [1,2,3,4]) | |
35 | ||
36 | def testDoesNotMatchWithFewerElementsThanExpected(self): | |
37 | self.assert_mismatch_description("No item matched: <3>", | |
38 | contains(1,2,3), [1,2]) | |
39 | ||
40 | def testDoesNotMatchIfSingleItemMismatches(self): | |
41 | self.assert_mismatch_description("item 0: was <3>", contains(4), [3]) | |
42 | ||
43 | def testDoesNotMatchIfOneOfMultipleItemsMismatch(self): | |
44 | self.assert_mismatch_description("item 2: was <4>", | |
45 | contains(1,2,3), [1,2,4]) | |
46 | ||
47 | def testDoesNotMatchEmptySequence(self): | |
48 | self.assert_mismatch_description("No item matched: <4>", | |
49 | contains(4), []) | |
50 | ||
51 | def testEmptySequenceMatchesEmptySequence(self): | |
52 | self.assert_matches("Empty sequence", contains(), []) | |
53 | ||
54 | def testMatchesAnyConformingSequence(self): | |
55 | self.assert_matches('quasi-sequence', contains(1,2), QuasiSequence()) | |
56 | self.assert_does_not_match('non-sequence', contains(1,2), object()) | |
57 | ||
58 | def testHasAReadableDescription(self): | |
59 | self.assert_description("a sequence containing [<1>, <2>]", contains(1,2)) | |
60 | ||
61 | def testDescribeMismatch(self): | |
62 | self.assert_describe_mismatch('item 1: was <3>', contains(1,2), [1,3]) | |
63 | ||
64 | def testDescribeMismatchOfNonSequence(self): | |
65 | self.assert_describe_mismatch("was <3>", contains(1,2), 3) | |
66 | ||
67 | if __name__ == '__main__': | |
68 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.collection.issequence_onlycontaining import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | from hamcrest.library.number.ordering_comparison import less_than | |
9 | from hamcrest_unit_test.matcher_test import MatcherTest | |
10 | from quasisequence import QuasiSequence | |
11 | import unittest | |
12 | ||
13 | __author__ = "Jon Reid" | |
14 | __copyright__ = "Copyright 2011 hamcrest.org" | |
15 | __license__ = "BSD, see License.txt" | |
16 | ||
17 | ||
18 | class IsSequenceOnlyContainingTest(MatcherTest): | |
19 | ||
20 | def testMatchesSingletonList(self): | |
21 | self.assert_matches('singleton list', only_contains(equal_to(1)), [1]) | |
22 | ||
23 | def testMatchesAllItemsWithOneMatcher(self): | |
24 | self.assert_matches('one matcher', | |
25 | only_contains(less_than(3)), [0, 1, 2]) | |
26 | ||
27 | def testMatchesAllItemsWithMultipleMatchers(self): | |
28 | self.assert_matches('multiple matchers', | |
29 | only_contains(less_than(3), equal_to(7)), | |
30 | [0, 7, 1, 2]) | |
31 | ||
32 | def testProvidesConvenientShortcutForMatchingWithEqualTo(self): | |
33 | self.assert_matches('Values automatically wrapped with equal_to', | |
34 | only_contains(less_than(3), 7), | |
35 | [0, 7, 1, 2]) | |
36 | ||
37 | def testDoesNotMatchListWithMismatchingItem(self): | |
38 | self.assert_does_not_match('3 is not less than 3', | |
39 | only_contains(less_than(3)), [1, 2, 3]) | |
40 | ||
41 | def testDoesNotMatchEmptyList(self): | |
42 | self.assert_does_not_match('empty', only_contains('foo'), []) | |
43 | ||
44 | def testMatchesAnyConformingSequence(self): | |
45 | class ObjectWithLenOnly: | |
46 | def __len__(self): return 20 | |
47 | self.assert_matches('quasi-sequence', | |
48 | only_contains(less_than(3)), QuasiSequence()) | |
49 | self.assert_does_not_match('non-sequence', only_contains(1), object()) | |
50 | self.assert_does_not_match('non-sequence with length', | |
51 | only_contains(1), ObjectWithLenOnly()) | |
52 | ||
53 | def testHasAReadableDescription(self): | |
54 | self.assert_description('a sequence containing items matching (<1> or <2>)', | |
55 | only_contains(1,2)) | |
56 | ||
57 | def testDescribeMismatch(self): | |
58 | self.assert_describe_mismatch("was 'bad'", only_contains(1,2), 'bad') | |
59 | ||
60 | def testDescribeMismatchOfNonSequence(self): | |
61 | self.assert_describe_mismatch("was <3>", only_contains(1,2), 3) | |
62 | ||
63 | ||
64 | if __name__ == '__main__': | |
65 | unittest.main() |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | ||
5 | class QuasiDictionary: | |
6 | def items(self): | |
7 | return QuasiDictionaryItemIterator() | |
8 | ||
9 | def keys(self): | |
10 | return QuasiDictionaryKeyIterator() | |
11 | ||
12 | def values(self): | |
13 | return QuasiDictionaryValueIterator() | |
14 | ||
15 | ||
16 | class BaseQuasiDictionaryIterator: | |
17 | def __init__(self): | |
18 | self.index = 1 | |
19 | ||
20 | def __iter__(self): | |
21 | return self | |
22 | ||
23 | def next(self): | |
24 | if self.index >= 3: | |
25 | raise StopIteration | |
26 | result = self.indexToResult() | |
27 | self.index += 1 | |
28 | return result | |
29 | ||
30 | ||
31 | class QuasiDictionaryItemIterator(BaseQuasiDictionaryIterator): | |
32 | def indexToResult(self): | |
33 | return (self.index, str(self.index)) | |
34 | ||
35 | ||
36 | class QuasiDictionaryKeyIterator(BaseQuasiDictionaryIterator): | |
37 | def indexToResult(self): | |
38 | return self.index | |
39 | ||
40 | ||
41 | class QuasiDictionaryValueIterator(BaseQuasiDictionaryIterator): | |
42 | def indexToResult(self): | |
43 | return str(self.index) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | ||
5 | class QuasiSequence: | |
6 | def __iter__(self): | |
7 | return QuasiSequenceIterator() | |
8 | ||
9 | def __len__(self): | |
10 | return 2 | |
11 | ||
12 | ||
13 | class QuasiSequenceIterator: | |
14 | def __init__(self): | |
15 | self.index = 1 | |
16 | ||
17 | def __iter__(self): | |
18 | return self | |
19 | ||
20 | def next(self): | |
21 | if self.index >= 3: | |
22 | raise StopIteration | |
23 | result = self.index | |
24 | self.index += 1 | |
25 | return result |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.core.core.allof import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | import unittest | |
10 | ||
11 | __author__ = "Jon Reid" | |
12 | __copyright__ = "Copyright 2011 hamcrest.org" | |
13 | __license__ = "BSD, see License.txt" | |
14 | ||
15 | ||
16 | class AllOfTest(MatcherTest): | |
17 | ||
18 | def testMatchesIfArgumentSatisfiesBothOfTwoOtherMatchers(self): | |
19 | self.assert_matches('both matchers', | |
20 | all_of(equal_to('good'), equal_to('good')), | |
21 | 'good') | |
22 | ||
23 | def testProvidesConvenientShortcutForMatchingWithEqualTo(self): | |
24 | self.assert_matches('both matchers', | |
25 | all_of('good', 'good'), | |
26 | 'good') | |
27 | ||
28 | def testNoMatchIfArgumentFailsToSatisfyEitherOfTwoOtherMatchers(self): | |
29 | self.assert_does_not_match('first matcher', | |
30 | all_of(equal_to('bad'), equal_to('good')), | |
31 | 'good') | |
32 | self.assert_does_not_match('second matcher', | |
33 | all_of(equal_to('good'), equal_to('bad')), | |
34 | 'good') | |
35 | self.assert_does_not_match('either matcher', | |
36 | all_of(equal_to('bad'), equal_to('bad')), | |
37 | 'good') | |
38 | ||
39 | def testMatchesIfArgumentSatisfiesAllOfManyOtherMatchers(self): | |
40 | self.assert_matches('all matchers', | |
41 | all_of(equal_to('good'), | |
42 | equal_to('good'), | |
43 | equal_to('good'), | |
44 | equal_to('good'), | |
45 | equal_to('good')), | |
46 | 'good') | |
47 | ||
48 | def testNoMatchIfArgumentFailsToSatisfyAllOfManyOtherMatchers(self): | |
49 | self.assert_does_not_match('matcher in the middle', | |
50 | all_of(equal_to('good'), | |
51 | equal_to('good'), | |
52 | equal_to('good'), | |
53 | equal_to('bad'), | |
54 | equal_to('good'), | |
55 | equal_to('good')), | |
56 | 'good') | |
57 | ||
58 | def testHasAReadableDescription(self): | |
59 | self.assert_description("('good' and 'bad' and 'ugly')", | |
60 | all_of(equal_to('good'), equal_to('bad'), equal_to('ugly'))) | |
61 | ||
62 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
63 | self.assert_no_mismatch_description( | |
64 | all_of(equal_to('good'), equal_to('good')), | |
65 | 'good') | |
66 | ||
67 | def testMismatchDescriptionDescribesFirstFailingMatch(self): | |
68 | self.assert_mismatch_description( | |
69 | "'good' was 'bad'", | |
70 | all_of(equal_to('bad'), equal_to('good')), | |
71 | 'bad') | |
72 | ||
73 | def testDescribeMismatch(self): | |
74 | self.assert_describe_mismatch( | |
75 | "'good' was 'bad'", | |
76 | all_of(equal_to('bad'), equal_to('good')), | |
77 | 'bad') | |
78 | ||
79 | ||
80 | if __name__ == '__main__': | |
81 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.core.core.anyof import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | import unittest | |
10 | ||
11 | __author__ = "Jon Reid" | |
12 | __copyright__ = "Copyright 2011 hamcrest.org" | |
13 | __license__ = "BSD, see License.txt" | |
14 | ||
15 | ||
16 | class AnyOfTest(MatcherTest): | |
17 | ||
18 | def testMatchesIfArgumentSatisfiesEitherOrBothOfTwoOtherMatchers(self): | |
19 | self.assert_matches('first matcher', | |
20 | any_of(equal_to('good'), equal_to('bad')), | |
21 | 'good') | |
22 | self.assert_matches('second matcher', | |
23 | any_of(equal_to('bad'), equal_to('good')), | |
24 | 'good') | |
25 | self.assert_matches('both matchers', | |
26 | any_of(equal_to('good'), equal_to('good')), | |
27 | 'good') | |
28 | ||
29 | def testProvidesConvenientShortcutForMatchingWithEqualTo(self): | |
30 | self.assert_matches('first matcher', | |
31 | any_of('good', 'bad'), | |
32 | 'good') | |
33 | self.assert_matches('second matcher', | |
34 | any_of('bad', 'good'), | |
35 | 'good') | |
36 | self.assert_matches('both matchers', | |
37 | any_of('good', 'good'), | |
38 | 'good') | |
39 | ||
40 | def testNoMatchIfArgumentFailsToSatisfyEitherOfTwoOtherMatchers(self): | |
41 | self.assert_does_not_match('either matcher', | |
42 | any_of(equal_to('bad'), equal_to('bad')), | |
43 | 'good') | |
44 | ||
45 | def testMatchesIfArgumentSatisfiesAnyOfManyOtherMatchers(self): | |
46 | self.assert_matches('matcher in the middle', | |
47 | any_of(equal_to('bad'), | |
48 | equal_to('bad'), | |
49 | equal_to('good'), | |
50 | equal_to('bad'), | |
51 | equal_to('bad')), | |
52 | 'good') | |
53 | ||
54 | def testNoMatchIfArgumentFailsToSatisfyAnyOfManyOtherMatchers(self): | |
55 | self.assert_does_not_match('all matchers', | |
56 | any_of(equal_to('bad'), | |
57 | equal_to('bad'), | |
58 | equal_to('bad'), | |
59 | equal_to('bad'), | |
60 | equal_to('bad')), | |
61 | 'good') | |
62 | ||
63 | def testHasAReadableDescription(self): | |
64 | self.assert_description("('good' or 'bad' or 'ugly')", | |
65 | any_of(equal_to('good'), equal_to('bad'), equal_to('ugly'))) | |
66 | ||
67 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
68 | self.assert_no_mismatch_description( | |
69 | any_of(equal_to('good'), equal_to('bad')), | |
70 | 'good') | |
71 | ||
72 | def testMismatchDescriptionDescribesFirstFailingMatch(self): | |
73 | self.assert_mismatch_description( | |
74 | "was 'ugly'", | |
75 | any_of(equal_to('bad'), equal_to('good')), | |
76 | 'ugly') | |
77 | ||
78 | def testDescribeMismatch(self): | |
79 | self.assert_describe_mismatch( | |
80 | "was 'ugly'", | |
81 | any_of(equal_to('bad'), equal_to('good')), | |
82 | 'ugly') | |
83 | ||
84 | ||
85 | if __name__ == '__main__': | |
86 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.core.core.described_as import * | |
6 | ||
7 | from hamcrest.core.core.isanything import anything | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | from nevermatch import NeverMatch | |
10 | import unittest | |
11 | ||
12 | __author__ = "Jon Reid" | |
13 | __copyright__ = "Copyright 2011 hamcrest.org" | |
14 | __license__ = "BSD, see License.txt" | |
15 | ||
16 | ||
17 | class DescribedAsTest(MatcherTest): | |
18 | ||
19 | def testOverridesDescriptionOfNestedMatcherWithConstructorArgument(self): | |
20 | m1 = described_as('m1 description', anything()) | |
21 | m2 = described_as('m2 description', NeverMatch()) | |
22 | ||
23 | self.assert_description('m1 description', m1) | |
24 | self.assert_description('m2 description', m2) | |
25 | ||
26 | def testAppendsValuesToDescription(self): | |
27 | m = described_as('value 1 = %0, value 2 = %1', anything(), 33, 97) | |
28 | ||
29 | self.assert_description('value 1 = <33>, value 2 = <97>', m) | |
30 | ||
31 | def testDelegatesMatchingToNestedMatcher(self): | |
32 | m1 = described_as('irrelevant', anything()) | |
33 | m2 = described_as('irrelevant', NeverMatch()) | |
34 | ||
35 | self.assertTrue(m1.matches(object())) | |
36 | self.assertTrue(not m2.matches('hi')) | |
37 | ||
38 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
39 | self.assert_no_mismatch_description( | |
40 | described_as('irrelevant', anything()), | |
41 | object()) | |
42 | ||
43 | def testDelegatesMismatchDescriptionToNestedMatcher(self): | |
44 | self.assert_mismatch_description( | |
45 | NeverMatch.mismatch_description, | |
46 | described_as('irrelevant', NeverMatch()), | |
47 | 'hi') | |
48 | ||
49 | def testDelegatesDescribeMismatchToNestedMatcher(self): | |
50 | self.assert_describe_mismatch( | |
51 | NeverMatch.mismatch_description, | |
52 | described_as('irrelevant', NeverMatch()), | |
53 | 'hi') | |
54 | ||
55 | ||
56 | if __name__ == '__main__': | |
57 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.core.core.is_ import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | from nevermatch import NeverMatch | |
10 | import unittest | |
11 | ||
12 | __author__ = "Jon Reid" | |
13 | __copyright__ = "Copyright 2011 hamcrest.org" | |
14 | __license__ = "BSD, see License.txt" | |
15 | ||
16 | ||
17 | class IsTest(MatcherTest): | |
18 | ||
19 | def testDelegatesMatchingToNestedMatcher(self): | |
20 | self.assert_matches('should match', is_(equal_to(True)), True) | |
21 | self.assert_matches('should match', is_(equal_to(False)), False) | |
22 | self.assert_does_not_match('should not match', is_(equal_to(True)), False) | |
23 | self.assert_does_not_match('should not match', is_(equal_to(False)), True) | |
24 | ||
25 | def testDescriptionShouldPassThrough(self): | |
26 | self.assert_description('<True>', is_(equal_to(True))) | |
27 | ||
28 | def testProvidesConvenientShortcutForIsEqualTo(self): | |
29 | self.assert_matches('should match', is_('A'), 'A'); | |
30 | self.assert_matches('should match', is_('B'), 'B'); | |
31 | self.assert_does_not_match('should not match', is_('A'), 'B'); | |
32 | self.assert_does_not_match('should not match', is_('B'), 'A'); | |
33 | self.assert_description("'A'", is_('A')); | |
34 | ||
35 | def testProvidesConvenientShortcutForIsInstanceOf(self): | |
36 | self.assert_matches('should match', is_(str), 'A'); | |
37 | self.assert_does_not_match('should not match', is_(int), 'A'); | |
38 | ||
39 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
40 | self.assert_no_mismatch_description(is_('A'), 'A') | |
41 | ||
42 | def testDelegatesMismatchDescriptionToNestedMatcher(self): | |
43 | self.assert_mismatch_description( | |
44 | NeverMatch.mismatch_description, | |
45 | is_(NeverMatch()), | |
46 | 'hi') | |
47 | ||
48 | def testDelegatesDescribeMismatchToNestedMatcher(self): | |
49 | self.assert_describe_mismatch( | |
50 | NeverMatch.mismatch_description, | |
51 | is_(NeverMatch()), | |
52 | 'hi') | |
53 | ||
54 | ||
55 | if __name__ == '__main__': | |
56 | unittest.main() |
0 | if __name__ == "__main__": | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.core.core.isanything import * | |
6 | ||
7 | from hamcrest_unit_test.matcher_test import MatcherTest | |
8 | import unittest | |
9 | ||
10 | __author__ = "Jon Reid" | |
11 | __copyright__ = "Copyright 2011 hamcrest.org" | |
12 | __license__ = "BSD, see License.txt" | |
13 | ||
14 | ||
15 | class IsAnythingTest(MatcherTest): | |
16 | ||
17 | def testAlwaysEvaluatesToTrue(self): | |
18 | self.assert_matches('None', anything(), None) | |
19 | self.assert_matches('object', anything(), object()) | |
20 | self.assert_matches('string', anything(), 'hi') | |
21 | ||
22 | def testHasUsefulDefaultDescription(self): | |
23 | self.assert_description('ANYTHING', anything()) | |
24 | ||
25 | def testCanOverrideDescription(self): | |
26 | description = 'DESCRIPTION' | |
27 | self.assert_description(description, anything(description)) | |
28 | ||
29 | def testMatchAlwaysSucceedsSoShouldNotGenerateMismatchDescription(self): | |
30 | self.assert_no_mismatch_description(anything(), 'hi') | |
31 | ||
32 | ||
33 | if __name__ == "__main__": | |
34 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.core.core.isequal import * | |
6 | ||
7 | from hamcrest_unit_test.matcher_test import MatcherTest | |
8 | import unittest | |
9 | ||
10 | __author__ = "Jon Reid" | |
11 | __copyright__ = "Copyright 2011 hamcrest.org" | |
12 | __license__ = "BSD, see License.txt" | |
13 | ||
14 | ||
15 | class IsEqualTest(MatcherTest): | |
16 | ||
17 | def testComparesObjectsUsingEquality(self): | |
18 | self.assert_matches('equal numbers', equal_to(1), 1) | |
19 | self.assert_does_not_match('unequal numbers', equal_to(1), 2) | |
20 | ||
21 | def testCanCompareNoneValues(self): | |
22 | self.assert_matches('None equals None', equal_to(None), None) | |
23 | ||
24 | self.assert_does_not_match('None as argument', equal_to('hi'), None) | |
25 | self.assert_does_not_match('None in equal_to', equal_to(None), 'hi') | |
26 | ||
27 | def testHonorsArgumentEqImplementationEvenWithNone(self): | |
28 | class AlwaysEqual: | |
29 | def __eq__(self, obj): return True | |
30 | class NeverEqual: | |
31 | def __eq__(self, obj): return False | |
32 | self.assert_matches("always equal", equal_to(None), AlwaysEqual()) | |
33 | self.assert_does_not_match("never equal", equal_to(None), NeverEqual()) | |
34 | ||
35 | def testIncludesTheResultOfCallingToStringOnItsArgumentInTheDescription(self): | |
36 | argument_description = 'ARGUMENT DESCRIPTION' | |
37 | class Argument: | |
38 | def __str__(self): return argument_description | |
39 | self.assert_description('<ARGUMENT DESCRIPTION>', equal_to(Argument())) | |
40 | ||
41 | def testReturnsAnObviousDescriptionIfCreatedWithANestedMatcherByMistake(self): | |
42 | inner_matcher = equal_to('NestedMatcher') | |
43 | self.assert_description("<'NestedMatcher'>", equal_to(inner_matcher)) | |
44 | ||
45 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
46 | self.assert_no_mismatch_description(equal_to('hi'), 'hi') | |
47 | ||
48 | def testMismatchDescriptionShowsActualArgument(self): | |
49 | self.assert_mismatch_description("was 'bad'", equal_to('good'), 'bad') | |
50 | ||
51 | def testDescribeMismatch(self): | |
52 | self.assert_describe_mismatch("was 'bad'", equal_to('good'), 'bad') | |
53 | ||
54 | ||
55 | if __name__ == '__main__': | |
56 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.core.core.isinstanceof import * | |
6 | ||
7 | from hamcrest_unit_test.matcher_test import MatcherTest | |
8 | import unittest | |
9 | ||
10 | __author__ = "Jon Reid" | |
11 | __copyright__ = "Copyright 2011 hamcrest.org" | |
12 | __license__ = "BSD, see License.txt" | |
13 | ||
14 | ||
15 | class IsInstanceOfTest(MatcherTest): | |
16 | ||
17 | def testEvaluatesToTrueIfArgumentIsInstanceOfASpecificClass(self): | |
18 | self.assert_matches('same class', instance_of(int), 1) | |
19 | ||
20 | self.assert_does_not_match('different class', instance_of(int), 'hi') | |
21 | self.assert_does_not_match('None', instance_of(int), None) | |
22 | ||
23 | def testMatcherCreationRequiresType(self): | |
24 | self.assertRaises(TypeError, instance_of, 'not a type') | |
25 | ||
26 | def testHasAReadableDescription(self): | |
27 | self.assert_description('an instance of int', instance_of(int)); | |
28 | ||
29 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
30 | self.assert_no_mismatch_description(instance_of(int), 3) | |
31 | ||
32 | def testMismatchDescriptionShowsActualArgument(self): | |
33 | self.assert_mismatch_description("was 'bad'", instance_of(int), 'bad') | |
34 | ||
35 | def testDescribeMismatch(self): | |
36 | self.assert_describe_mismatch("was 'bad'", instance_of(int), 'bad') | |
37 | ||
38 | ||
39 | if __name__ == '__main__': | |
40 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.core.core.isnone import * | |
6 | ||
7 | from hamcrest_unit_test.matcher_test import MatcherTest | |
8 | import unittest | |
9 | ||
10 | __author__ = "Jon Reid" | |
11 | __copyright__ = "Copyright 2011 hamcrest.org" | |
12 | __license__ = "BSD, see License.txt" | |
13 | ||
14 | ||
15 | class IsNoneTest(MatcherTest): | |
16 | ||
17 | def testEvaluatesToTrueIfArgumentIsNone(self): | |
18 | self.assert_matches('None', none(), None) | |
19 | ||
20 | def testEvaluatesToFalseIfArgumentIsNotNone(self): | |
21 | self.assert_does_not_match('not None', none(), object()) | |
22 | ||
23 | def testHasAReadableDescription(self): | |
24 | self.assert_description('None', none()); | |
25 | ||
26 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
27 | self.assert_no_mismatch_description(none(), None) | |
28 | ||
29 | def testMismatchDescriptionShowsActualArgument(self): | |
30 | self.assert_mismatch_description("was 'bad'", none(), 'bad') | |
31 | ||
32 | def testDescribeMismatch(self): | |
33 | self.assert_describe_mismatch("was 'bad'", none(), 'bad') | |
34 | ||
35 | ||
36 | class NotNoneTest(MatcherTest): | |
37 | ||
38 | def testEvaluatesToTrueIfArgumentIsNotNone(self): | |
39 | self.assert_matches('not None', not_none(), object()) | |
40 | ||
41 | def testEvaluatesToFalseIfArgumentIsNone(self): | |
42 | self.assert_does_not_match('None', not_none(), None) | |
43 | ||
44 | def testHasAReadableDescription(self): | |
45 | self.assert_description('not None', not_none()); | |
46 | ||
47 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
48 | self.assert_no_mismatch_description(not_none(), 'hi') | |
49 | ||
50 | def testMismatchDescriptionShowsActualArgument(self): | |
51 | self.assert_mismatch_description("was <None>", not_none(), None) | |
52 | ||
53 | def testDescribeMismatch(self): | |
54 | self.assert_describe_mismatch("was <None>", not_none(), None) | |
55 | ||
56 | ||
57 | if __name__ == '__main__': | |
58 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.core.core.isnot import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | import unittest | |
10 | ||
11 | __author__ = "Jon Reid" | |
12 | __copyright__ = "Copyright 2011 hamcrest.org" | |
13 | __license__ = "BSD, see License.txt" | |
14 | ||
15 | ||
16 | class IsNotTest(MatcherTest): | |
17 | ||
18 | def testEvaluatesToTheTheLogicalNegationOfAnotherMatcher(self): | |
19 | self.assert_matches('invert mismatch', is_not(equal_to('A')), 'B') | |
20 | self.assert_does_not_match('invert match', is_not(equal_to('A')), 'A') | |
21 | ||
22 | def testProvidesConvenientShortcutForNotEqualTo(self): | |
23 | self.assert_matches('invert mismatch', is_not('A'), 'B'); | |
24 | self.assert_does_not_match('invert match', is_not('A'), 'A'); | |
25 | ||
26 | def testHasAReadableDescription(self): | |
27 | self.assert_description("not 'A'", is_not('A')); | |
28 | ||
29 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
30 | self.assert_no_mismatch_description(is_not('A'), 'B') | |
31 | ||
32 | def testMismatchDescriptionShowsActualArgument(self): | |
33 | self.assert_mismatch_description("was 'A'", is_not('A'), 'A') | |
34 | ||
35 | def testDescribeMismatch(self): | |
36 | self.assert_describe_mismatch("was 'A'", is_not('A'), 'A') | |
37 | ||
38 | ||
39 | if __name__ == '__main__': | |
40 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.core.core.issame import * | |
6 | ||
7 | from hamcrest.core.string_description import StringDescription | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | import re | |
10 | import unittest | |
11 | ||
12 | __author__ = "Jon Reid" | |
13 | __copyright__ = "Copyright 2011 hamcrest.org" | |
14 | __license__ = "BSD, see License.txt" | |
15 | ||
16 | ||
17 | class IsSameTest(MatcherTest): | |
18 | ||
19 | def testEvaluatesToTrueIfArgumentIsReferenceToASpecifiedObject(self): | |
20 | o1 = object() | |
21 | o2 = object() | |
22 | ||
23 | self.assert_matches('same', same_instance(o1), o1) | |
24 | self.assert_does_not_match('different', same_instance(o1), o2) | |
25 | ||
26 | def testDescriptionIncludesMemoryAddress(self): | |
27 | description = StringDescription() | |
28 | expected = re.compile("same instance as 0x[0-9a-fA-F]+ 'abc'") | |
29 | ||
30 | description.append_description_of(same_instance('abc')); | |
31 | self.assertTrue(expected.match(str(description))) | |
32 | ||
33 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
34 | o1 = object() | |
35 | self.assert_no_mismatch_description(same_instance(o1), o1) | |
36 | ||
37 | def testMismatchDescriptionShowsActualArgumentAddress(self): | |
38 | matcher = same_instance('foo') | |
39 | description = StringDescription() | |
40 | expected = re.compile("was 0x[0-9a-fA-F]+ 'hi'") | |
41 | ||
42 | result = matcher.matches('hi', description) | |
43 | self.assertFalse(result, 'Precondition: Matcher should not match item') | |
44 | self.assertTrue(expected.match(str(description))) | |
45 | ||
46 | def testMismatchDescriptionWithNilShouldNotIncludeAddress(self): | |
47 | self.assert_mismatch_description("was <None>", same_instance('foo'), None) | |
48 | ||
49 | def testDescribeMismatch(self): | |
50 | matcher = same_instance('foo') | |
51 | description = StringDescription() | |
52 | expected = re.compile("was 0x[0-9a-fA-F]+ 'hi'") | |
53 | ||
54 | matcher.describe_mismatch('hi', description) | |
55 | expected = re.compile("was 0x[0-9a-fA-F]+ 'hi'") | |
56 | self.assertTrue(expected.match(str(description))) | |
57 | ||
58 | def testDescribeMismatchWithNilShouldNotIncludeAddress(self): | |
59 | self.assert_describe_mismatch("was <None>", same_instance('foo'), None) | |
60 | ||
61 | ||
62 | if __name__ == '__main__': | |
63 | unittest.main() |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | class NeverMatch(BaseMatcher): | |
8 | ||
9 | mismatch_description = 'NEVERMATCH' | |
10 | ||
11 | def matches(self, item, mismatch_description=None): | |
12 | if mismatch_description: | |
13 | self.describe_mismatch(item, mismatch_description) | |
14 | return False | |
15 | ||
16 | def describe_mismatch(self, item, mismatch_description): | |
17 | mismatch_description.append_text(NeverMatch.mismatch_description) |
0 | if __name__ == "__main__": | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.integration.match_equality import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | from hamcrest.core.string_description import tostring | |
9 | import unittest | |
10 | ||
11 | __author__ = "Chris Rose" | |
12 | __copyright__ = "Copyright 2011 hamcrest.org" | |
13 | __license__ = "BSD, see License.txt" | |
14 | ||
15 | ||
16 | class MatchEqualityWrapperTest(unittest.TestCase): | |
17 | ||
18 | def testMatcherIsEqualWhenMatchesIsTrue(self): | |
19 | matcher = equal_to('bar') | |
20 | assert match_equality(matcher) == 'bar' | |
21 | ||
22 | def testMatcherIsNotEqualWhenMatchesIsFalse(self): | |
23 | matcher = equal_to('bar') | |
24 | assert match_equality(matcher) != 'foo' | |
25 | ||
26 | def testMatcherStringIsMatcherDescription(self): | |
27 | matcher = equal_to('bar') | |
28 | assert str(match_equality(matcher)) == tostring(matcher) | |
29 | ||
30 | def testMatcherReprIsMatcher(self): | |
31 | matcher = equal_to('bar') | |
32 | assert repr(match_equality(matcher)) == tostring(matcher) | |
33 | ||
34 | def testMatchesWhenProvidedAnObject(self): | |
35 | assert match_equality('bar') == 'bar' | |
36 | ||
37 | ||
38 | if __name__ == "__main__": | |
39 | unittest.main() |
0 | from hamcrest.core.string_description import StringDescription | |
1 | ||
2 | import unittest | |
3 | import logging | |
4 | ||
5 | log = logging.getLogger(__name__) | |
6 | ||
7 | __author__ = "Jon Reid" | |
8 | __copyright__ = "Copyright 2011 hamcrest.org" | |
9 | __license__ = "BSD, see License.txt" | |
10 | ||
11 | ||
12 | class MatcherTest(unittest.TestCase): | |
13 | ||
14 | def assert_matches(self, message, matcher, arg): | |
15 | try: | |
16 | self.assertTrue(matcher.matches(arg), message) | |
17 | except AssertionError: | |
18 | description = StringDescription() | |
19 | matcher.describe_mismatch(arg, description) | |
20 | log.error(str(description)) | |
21 | raise | |
22 | ||
23 | def assert_does_not_match(self, message, matcher, arg): | |
24 | self.assertFalse(matcher.matches(arg), message) | |
25 | ||
26 | def assert_description(self, expected, matcher): | |
27 | description = StringDescription() | |
28 | description.append_description_of(matcher); | |
29 | self.assertEqual(expected, str(description)) | |
30 | ||
31 | def assert_no_mismatch_description(self, matcher, arg): | |
32 | description = StringDescription() | |
33 | result = matcher.matches(arg, description) | |
34 | self.assertTrue(result, 'Precondition: Matcher should match item') | |
35 | self.assertEqual('', str(description), | |
36 | 'Expected no mismatch description') | |
37 | ||
38 | def assert_mismatch_description(self, expected, matcher, arg): | |
39 | description = StringDescription() | |
40 | result = matcher.matches(arg, description) | |
41 | self.assertFalse(result, 'Precondition: Matcher should not match item') | |
42 | self.assertEqual(expected, str(description)) | |
43 | ||
44 | def assert_describe_mismatch(self, expected, matcher, arg): | |
45 | description = StringDescription() | |
46 | matcher.describe_mismatch(arg, description) | |
47 | self.assertEqual(expected, str(description)) |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.number.iscloseto import * | |
6 | ||
7 | from hamcrest_unit_test.matcher_test import MatcherTest | |
8 | import unittest | |
9 | ||
10 | __author__ = "Jon Reid" | |
11 | __copyright__ = "Copyright 2011 hamcrest.org" | |
12 | __license__ = "BSD, see License.txt" | |
13 | ||
14 | ||
15 | class IsCloseToTest(MatcherTest): | |
16 | ||
17 | def testEvaluatesToTrueIfArgumentIsEqualToAValueWithinSomeError(self): | |
18 | matcher = close_to(1.0, 0.5) | |
19 | ||
20 | self.assert_matches('equal', matcher, 1.0) | |
21 | self.assert_matches('less but within delta', matcher, 0.5) | |
22 | self.assert_matches('greater but within delta', matcher, 1.5) | |
23 | ||
24 | self.assert_does_not_match('too small', matcher, 0.4) | |
25 | self.assert_does_not_match('too large', matcher, 1.6) | |
26 | ||
27 | def testMatcherCreationAcceptsOtherNumericTypes(self): | |
28 | close_to(5, 1) | |
29 | close_to(5L, 1L) | |
30 | ||
31 | def testMatcherCreationRequiresNumbers(self): | |
32 | self.assertRaises(TypeError, close_to, 'a', 0.5) | |
33 | self.assertRaises(TypeError, close_to, 1.0, 'a') | |
34 | ||
35 | def testFailsIfMatchingAgainstNonNumber(self): | |
36 | self.assert_does_not_match('not a number', close_to(1.0, 0.5), 'a') | |
37 | ||
38 | def testHasAReadableDescription(self): | |
39 | self.assert_description('a numeric value within <0.5> of <1.0>', | |
40 | close_to(1.0, 0.5)) | |
41 | ||
42 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
43 | self.assert_no_mismatch_description(close_to(1.0, 0.5), 1.0) | |
44 | ||
45 | def testMismatchDescriptionShowsActualDeltaIfArgumentIsNumeric(self): | |
46 | self.assert_mismatch_description('<1.7> differed by <0.7>', | |
47 | close_to(1.0, 0.5), 1.7) | |
48 | ||
49 | def testMismatchDescriptionShowsActualArgumentIfNotNumeric(self): | |
50 | self.assert_mismatch_description("was 'bad'", close_to(1.0, 0.5), 'bad') | |
51 | ||
52 | def testDescribeMismatchShowsActualDeltaIfArgumentIsNumeric(self): | |
53 | self.assert_describe_mismatch('<1.7> differed by <0.7>', | |
54 | close_to(1.0, 0.5), 1.7) | |
55 | ||
56 | def testDescribeMismatchShowsActualArgumentIfNotNumeric(self): | |
57 | self.assert_describe_mismatch("was 'bad'", close_to(1.0, 0.5), 'bad') | |
58 | ||
59 | ||
60 | if __name__ == '__main__': | |
61 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.number.ordering_comparison import * | |
6 | ||
7 | from datetime import date | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | import unittest | |
10 | ||
11 | __author__ = "Jon Reid" | |
12 | __copyright__ = "Copyright 2011 hamcrest.org" | |
13 | __license__ = "BSD, see License.txt" | |
14 | ||
15 | ||
16 | class OrderingComparisonTest(MatcherTest): | |
17 | ||
18 | def testComparesObjectsForGreaterThan(self): | |
19 | self.assert_matches('match', greater_than(1), 2) | |
20 | self.assert_does_not_match('no match', greater_than(1), 1) | |
21 | ||
22 | def testComparesObjectsForLessThan(self): | |
23 | self.assert_matches('match', less_than(1), 0) | |
24 | self.assert_does_not_match('no match', less_than(1), 1) | |
25 | ||
26 | def testComparesObjectsForGreaterThanOrEqualTo(self): | |
27 | self.assert_matches('match', greater_than_or_equal_to(1), 2) | |
28 | self.assert_matches('match', greater_than_or_equal_to(1), 1) | |
29 | self.assert_does_not_match('no match', greater_than_or_equal_to(1), 0) | |
30 | ||
31 | def testComparesObjectsForLessThanOrEqualTo(self): | |
32 | self.assert_matches('match', less_than_or_equal_to(1), 0) | |
33 | self.assert_matches('match', less_than_or_equal_to(1), 1) | |
34 | self.assert_does_not_match('no match', less_than_or_equal_to(1), 2) | |
35 | ||
36 | def testSupportsDifferentTypesOfComparableObjects(self): | |
37 | self.assert_matches('strings', greater_than('bb'), 'cc') | |
38 | self.assert_matches('dates', less_than(date.today()), date.min) | |
39 | ||
40 | def testHasAReadableDescription(self): | |
41 | self.assert_description('a value greater than <1>', greater_than(1)) | |
42 | self.assert_description('a value greater than or equal to <1>', | |
43 | greater_than_or_equal_to(1)) | |
44 | self.assert_description('a value less than <1>', less_than(1)) | |
45 | self.assert_description('a value less than or equal to <1>', | |
46 | less_than_or_equal_to(1)) | |
47 | ||
48 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
49 | self.assert_no_mismatch_description(greater_than(1), 2) | |
50 | self.assert_no_mismatch_description(less_than(1), 0) | |
51 | self.assert_no_mismatch_description(greater_than_or_equal_to(1), 1) | |
52 | self.assert_no_mismatch_description(less_than_or_equal_to(1), 1) | |
53 | ||
54 | def testMismatchDescription(self): | |
55 | self.assert_mismatch_description("was <0>", greater_than(1), 0) | |
56 | self.assert_mismatch_description("was <2>", less_than(1), 2) | |
57 | self.assert_mismatch_description("was <0>", | |
58 | greater_than_or_equal_to(1), 0) | |
59 | self.assert_mismatch_description("was <2>", | |
60 | less_than_or_equal_to(1), 2) | |
61 | ||
62 | def testDescribeMismatch(self): | |
63 | self.assert_describe_mismatch("was <0>", greater_than(1), 0) | |
64 | self.assert_describe_mismatch("was <2>", less_than(1), 2) | |
65 | self.assert_describe_mismatch("was <0>", | |
66 | greater_than_or_equal_to(1), 0) | |
67 | self.assert_describe_mismatch("was <2>", less_than_or_equal_to(1), 2) | |
68 | ||
69 | ||
70 | if __name__ == '__main__': | |
71 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.object.haslength import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | from hamcrest.library.number.ordering_comparison import greater_than | |
9 | from hamcrest_unit_test.matcher_test import MatcherTest | |
10 | import unittest | |
11 | ||
12 | __author__ = "Jon Reid" | |
13 | __copyright__ = "Copyright 2011 hamcrest.org" | |
14 | __license__ = "BSD, see License.txt" | |
15 | ||
16 | ||
17 | class FakeWithLen(object): | |
18 | ||
19 | def __init__(self, len): | |
20 | self.len = len | |
21 | ||
22 | def __len__(self): | |
23 | return self.len | |
24 | ||
25 | def __str__(self): | |
26 | return 'FakeWithLen' | |
27 | ||
28 | ||
29 | class FakeWithoutLen(object): | |
30 | ||
31 | def __str__(self): | |
32 | return 'FakeWithoutLen' | |
33 | ||
34 | ||
35 | class HasLengthTest(MatcherTest): | |
36 | ||
37 | def testPassesResultOfLenToNestedMatcher(self): | |
38 | self.assert_matches('equal', has_length(equal_to(42)), FakeWithLen(42)) | |
39 | self.assert_does_not_match('unequal', | |
40 | has_length(equal_to(42)), FakeWithLen(1)) | |
41 | ||
42 | def testProvidesConvenientShortcutForHasLengthEqualTo(self): | |
43 | self.assert_matches('equal', has_length(42), FakeWithLen(42)) | |
44 | self.assert_does_not_match('unequal', has_length(42), FakeWithLen(1)) | |
45 | ||
46 | def testDoesNotMatchObjectWithoutLen(self): | |
47 | self.assert_does_not_match('no length', has_length(42), object()) | |
48 | ||
49 | def testHasReadableDescription(self): | |
50 | self.assert_description('an object with length of a value greater than <5>', | |
51 | has_length(greater_than(5))) | |
52 | ||
53 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
54 | self.assert_no_mismatch_description(has_length(3), 'foo') | |
55 | ||
56 | def testMismatchDescriptionForItemWithWrongLength(self): | |
57 | self.assert_mismatch_description('was <FakeWithLen> with length of <4>', | |
58 | has_length(3), FakeWithLen(4)) | |
59 | ||
60 | def testMismatchDescriptionForItemWithoutLength(self): | |
61 | self.assert_mismatch_description("was <FakeWithoutLen>", | |
62 | has_length(3), FakeWithoutLen()) | |
63 | ||
64 | def testDescribeMismatchForItemWithWrongLength(self): | |
65 | self.assert_describe_mismatch('was <FakeWithLen> with length of <4>', | |
66 | has_length(3), FakeWithLen(4)) | |
67 | ||
68 | def testDescribeMismatchForItemWithoutLength(self): | |
69 | self.assert_describe_mismatch("was <FakeWithoutLen>", | |
70 | has_length(3), FakeWithoutLen()) | |
71 | ||
72 | ||
73 | ||
74 | if __name__ == '__main__': | |
75 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | import sys | |
5 | print '\n'.join(sys.path) | |
6 | ||
7 | from hamcrest.library.object.hasproperty import * | |
8 | ||
9 | from hamcrest.core.core.isequal import equal_to | |
10 | from hamcrest_unit_test.matcher_test import MatcherTest | |
11 | import unittest | |
12 | ||
13 | __author__ = "Chris Rose" | |
14 | __copyright__ = "Copyright 2011 hamcrest.org" | |
15 | __license__ = "BSD, see License.txt" | |
16 | ||
17 | class OnePropertyOldStyle: | |
18 | ||
19 | field = 'value' | |
20 | ||
21 | class OnePropertyNewStyle(object): | |
22 | ||
23 | field = 'value' | |
24 | ||
25 | def __repr__(self): | |
26 | return 'OnePropertyNewStyle' | |
27 | ||
28 | def __str__(self): | |
29 | return repr(self) | |
30 | ||
31 | class OverridingOldStyle: | |
32 | ||
33 | def __getattr__(self, name): | |
34 | if name != 'field': | |
35 | raise AttributeError(name) | |
36 | return 'value' | |
37 | ||
38 | class OverridingNewStyleGetAttr(object): | |
39 | ||
40 | def __getattr__(self, name): | |
41 | if name != 'field': | |
42 | raise AttributeError(name) | |
43 | return 'value' | |
44 | ||
45 | class OverridingNewStyleGetAttribute(object): | |
46 | ||
47 | def __getattr__(self, name): | |
48 | if name != 'field': | |
49 | raise AttributeError(name) | |
50 | return 'value' | |
51 | ||
52 | class HasPropertyTest(MatcherTest): | |
53 | ||
54 | def testHasPropertyWithoutValueMatcher(self): | |
55 | self.assert_matches('old-style direct', | |
56 | has_property('field'), OnePropertyOldStyle()) | |
57 | self.assert_matches('old-style direct', | |
58 | has_property('field'), OnePropertyNewStyle()) | |
59 | self.assert_matches('old-style direct', | |
60 | has_property('field'), OverridingOldStyle()) | |
61 | self.assert_matches('old-style direct', | |
62 | has_property('field'), OverridingNewStyleGetAttr()) | |
63 | self.assert_matches('old-style direct', | |
64 | has_property('field'), OverridingNewStyleGetAttribute()) | |
65 | ||
66 | def testHasPropertyWithoutValueMatcherNegative(self): | |
67 | self.assert_does_not_match('old-style direct', | |
68 | has_property('not_there'), OnePropertyOldStyle()) | |
69 | self.assert_does_not_match('old-style direct', | |
70 | has_property('not_there'), OnePropertyNewStyle()) | |
71 | self.assert_does_not_match('old-style direct', | |
72 | has_property('not_there'), OverridingOldStyle()) | |
73 | self.assert_does_not_match('old-style direct', | |
74 | has_property('not_there'), OverridingNewStyleGetAttr()) | |
75 | self.assert_does_not_match('old-style direct', | |
76 | has_property('not_there'), OverridingNewStyleGetAttribute()) | |
77 | ||
78 | def testHasPropertyWithValueMatcher(self): | |
79 | self.assert_matches('old-style direct', | |
80 | has_property('field', 'value'), OnePropertyOldStyle()) | |
81 | self.assert_matches('old-style direct', | |
82 | has_property('field', 'value'), OnePropertyNewStyle()) | |
83 | self.assert_matches('old-style direct', | |
84 | has_property('field', 'value'), OverridingOldStyle()) | |
85 | self.assert_matches('old-style direct', | |
86 | has_property('field', 'value'), OverridingNewStyleGetAttr()) | |
87 | self.assert_matches('old-style direct', | |
88 | has_property('field', 'value'), OverridingNewStyleGetAttribute()) | |
89 | ||
90 | def testHasPropertyWithValueMatcherNegative(self): | |
91 | self.assert_does_not_match('old-style direct', | |
92 | has_property('field', 'not the value'), OnePropertyOldStyle()) | |
93 | self.assert_does_not_match('old-style direct', | |
94 | has_property('field', 'not the value'), OnePropertyNewStyle()) | |
95 | self.assert_does_not_match('old-style direct', | |
96 | has_property('field', 'not the value'), OverridingOldStyle()) | |
97 | self.assert_does_not_match('old-style direct', | |
98 | has_property('field', 'not the value'), OverridingNewStyleGetAttr()) | |
99 | self.assert_does_not_match('old-style direct', | |
100 | has_property('field', 'not the value'), OverridingNewStyleGetAttribute()) | |
101 | ||
102 | def testDescription(self): | |
103 | self.assert_description("an object with a property 'field' matching ANYTHING", | |
104 | has_property('field')) | |
105 | self.assert_description("an object with a property 'field' matching 'value'", | |
106 | has_property('field', 'value')) | |
107 | ||
108 | def testDescribeMissingProperty(self): | |
109 | self.assert_mismatch_description("<OnePropertyNewStyle> did not have the 'not_there' property", | |
110 | has_property('not_there'), OnePropertyNewStyle()) | |
111 | ||
112 | def testDescribePropertyValueMismatch(self): | |
113 | self.assert_mismatch_description("property 'field' was 'value'", | |
114 | has_property('field', 'another_value'), OnePropertyNewStyle()) | |
115 | ||
116 | def testMismatchDescription(self): | |
117 | self.assert_describe_mismatch("<OnePropertyNewStyle> did not have the 'not_there' property", | |
118 | has_property('not_there'), | |
119 | OnePropertyNewStyle()) | |
120 | ||
121 | def testNoMismatchDescriptionOnMatch(self): | |
122 | self.assert_no_mismatch_description(has_property('field', 'value'), OnePropertyNewStyle()) | |
123 | ||
124 | ||
125 | if __name__ == '__main__': | |
126 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.object.hasstring import * | |
6 | ||
7 | from hamcrest.core.core.isequal import equal_to | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | import unittest | |
10 | ||
11 | __author__ = "Jon Reid" | |
12 | __copyright__ = "Copyright 2011 hamcrest.org" | |
13 | __license__ = "BSD, see License.txt" | |
14 | ||
15 | ||
16 | class FakeWithStr(object): | |
17 | ||
18 | def __str__(self): | |
19 | return 'FakeWithStr' | |
20 | ||
21 | ||
22 | class HasStringTest(MatcherTest): | |
23 | ||
24 | def testPassesResultOfToStrToNestedMatcher(self): | |
25 | self.assert_matches('equal', | |
26 | has_string(equal_to('FakeWithStr')), FakeWithStr()) | |
27 | self.assert_does_not_match('unequal', | |
28 | has_string(equal_to('FakeWithStr')), 3) | |
29 | ||
30 | def testProvidesConvenientShortcutForHasStringEqualTo(self): | |
31 | self.assert_matches('equal', has_string('FakeWithStr'), FakeWithStr()) | |
32 | self.assert_does_not_match('unequal', has_string('FakeWithStr'), 3) | |
33 | ||
34 | def testHasReadableDescription(self): | |
35 | self.assert_description("an object with str 'foo'", has_string('foo')) | |
36 | ||
37 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
38 | self.assert_no_mismatch_description(has_string('FakeWithStr'), | |
39 | FakeWithStr()) | |
40 | ||
41 | def testMismatchDescription(self): | |
42 | self.assert_mismatch_description("was <FakeWithStr>", | |
43 | has_string('foo'), FakeWithStr()) | |
44 | ||
45 | def testDescribeMismatchDescription(self): | |
46 | self.assert_describe_mismatch("was <FakeWithStr>", | |
47 | has_string('foo'), FakeWithStr()) | |
48 | ||
49 | ||
50 | if __name__ == '__main__': | |
51 | unittest.main() |
0 | from hamcrest import * | |
1 | ||
2 | try: | |
3 | class MyTest(object): | |
4 | pass | |
5 | except TypeError: | |
6 | print 'Object class defined at ' + getattr(object, '__file__', 'NOWHERE') | |
7 | raise |
0 | import sys | |
1 | if __name__ == "__main__": | |
2 | sys.path.insert(0, '..') | |
3 | ||
4 | from hamcrest.core.string_description import * | |
5 | ||
6 | from hamcrest.core.selfdescribing import SelfDescribing | |
7 | import re | |
8 | try: | |
9 | import unittest2 as unittest | |
10 | except ImportError: | |
11 | import unittest | |
12 | ||
13 | __author__ = "Jon Reid" | |
14 | __copyright__ = "Copyright 2011 hamcrest.org" | |
15 | __license__ = "BSD, see License.txt" | |
16 | ||
17 | ||
18 | class FakeSelfDescribing(SelfDescribing): | |
19 | ||
20 | def describe_to(self, description): | |
21 | description.append_text('DESCRIPTION') | |
22 | ||
23 | ||
24 | class StringDescriptionTest(unittest.TestCase): | |
25 | ||
26 | def setUp(self): | |
27 | self.description = StringDescription() | |
28 | ||
29 | def testLetsSelfDescribingObjectDescribeItself(self): | |
30 | self.description.append_description_of(FakeSelfDescribing()) | |
31 | self.assertEqual('DESCRIPTION', str(self.description)) | |
32 | ||
33 | def testDescribesStringInQuotes(self): | |
34 | self.description.append_description_of('FOO') | |
35 | self.assertEqual("'FOO'", str(self.description)) | |
36 | ||
37 | def testWrapsNonSelfDescribingObjectInAngleBrackets(self): | |
38 | self.description.append_description_of(42) | |
39 | self.assertEqual('<42>', str(self.description)) | |
40 | ||
41 | def testShouldNotAddAngleBracketsIfObjectDescriptionAlreadyHasThem(self): | |
42 | self.description.append_description_of(object()) | |
43 | expected = re.compile("<object object at 0x[0-9a-fA-F]+>") | |
44 | self.assertTrue(expected.match(str(self.description))) | |
45 | ||
46 | @unittest.skipIf(sys.version_info >= (3,), "Describe unicode strings doesn't malform in Python 3") | |
47 | def testDescribeUnicodeStringAsBytes(self): | |
48 | self.description.append_description_of(u'\u05d0') | |
49 | self.assertEqual("u'\\u05d0'", str(self.description)) | |
50 | ||
51 | @unittest.skipUnless(sys.version_info >= (3,), "Describe unicode strings only malforms in Python 2") | |
52 | def testDescribeUnicodeStringAsUnicode(self): | |
53 | self.description.append_description_of(u'\u05d0') | |
54 | self.assertEqual(u"'\u05d0'", str(self.description)) | |
55 | ||
56 | if __name__ == "__main__": | |
57 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.text.isequal_ignoring_case import equal_to_ignoring_case | |
6 | ||
7 | from hamcrest_unit_test.matcher_test import MatcherTest | |
8 | import unittest | |
9 | ||
10 | __author__ = "Jon Reid" | |
11 | __copyright__ = "Copyright 2011 hamcrest.org" | |
12 | __license__ = "BSD, see License.txt" | |
13 | ||
14 | ||
15 | matcher = equal_to_ignoring_case('heLLo') | |
16 | ||
17 | class IsEqualIgnoringCaseTest(MatcherTest): | |
18 | ||
19 | def testIgnoresCaseOfCharsInString(self): | |
20 | self.assert_matches('all upper', matcher, 'HELLO') | |
21 | self.assert_matches('all lower', matcher, 'hello') | |
22 | self.assert_matches('mixed up', matcher, 'HelLo') | |
23 | ||
24 | self.assert_does_not_match('no match', matcher, 'bye') | |
25 | ||
26 | def testFailsIfAdditionalWhitespaceIsPresent(self): | |
27 | self.assert_does_not_match('whitespace suffix', matcher, 'heLLo ') | |
28 | self.assert_does_not_match('whitespace prefix', matcher, ' heLLo') | |
29 | ||
30 | def testMatcherCreationRequiresString(self): | |
31 | self.assertRaises(TypeError, equal_to_ignoring_case, 3) | |
32 | ||
33 | def testFailsIfMatchingAgainstNonString(self): | |
34 | self.assert_does_not_match('non-string', matcher, object()) | |
35 | ||
36 | def testCanApplyUnicodeStringToUnicodeMatcher(self): | |
37 | self.assert_matches('unicode-unicode', | |
38 | equal_to_ignoring_case(u'heLLo'), u'HelLo') | |
39 | ||
40 | def testCanApplyPlainStringToUnicodeMatcher(self): | |
41 | self.assert_matches('unicode-ascii', | |
42 | equal_to_ignoring_case(u'heLLo'), 'HelLo') | |
43 | ||
44 | def testCanApplyUnicodeStringToPlainMatcher(self): | |
45 | self.assert_matches('ascii-unicode', | |
46 | equal_to_ignoring_case('heLLo'), u'HelLo') | |
47 | ||
48 | def testHasAReadableDescription(self): | |
49 | self.assert_description("'heLLo' ignoring case", matcher) | |
50 | ||
51 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
52 | self.assert_no_mismatch_description(matcher, 'hello') | |
53 | ||
54 | def testMismatchDescription(self): | |
55 | self.assert_mismatch_description("was 'bad'", matcher, 'bad') | |
56 | ||
57 | def testDescribeMismatch(self): | |
58 | self.assert_describe_mismatch("was 'bad'", matcher, 'bad') | |
59 | ||
60 | ||
61 | if __name__ == '__main__': | |
62 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.text.isequal_ignoring_whitespace import * | |
6 | ||
7 | from hamcrest_unit_test.matcher_test import MatcherTest | |
8 | import unittest | |
9 | ||
10 | __author__ = "Jon Reid" | |
11 | __copyright__ = "Copyright 2011 hamcrest.org" | |
12 | __license__ = "BSD, see License.txt" | |
13 | ||
14 | ||
15 | matcher = equal_to_ignoring_whitespace('Hello World how\n are we? ') | |
16 | ||
17 | class IsEqualIgnoringWhiteSpaceTest(MatcherTest): | |
18 | ||
19 | def testPassesIfWordsAreSameButWhitespaceDiffers(self): | |
20 | self.assert_matches('less whitespace', | |
21 | matcher, 'Hello World how are we?') | |
22 | self.assert_matches('more whitespace', | |
23 | matcher, ' Hello World how are \n\n\twe?') | |
24 | ||
25 | def testFailsIfTextOtherThanWhitespaceDiffers(self): | |
26 | self.assert_does_not_match('wrong word', | |
27 | matcher, 'Hello PLANET how are we?') | |
28 | self.assert_does_not_match('incomplete', | |
29 | matcher, 'Hello World how are we') | |
30 | ||
31 | def testFailsIfWhitespaceIsAddedOrRemovedInMidWord(self): | |
32 | self.assert_does_not_match('need whitespace between Hello and World', | |
33 | matcher, 'HelloWorld how are we?') | |
34 | self.assert_does_not_match('wrong whitespace within World', | |
35 | matcher, 'Hello Wo rld how are we?') | |
36 | ||
37 | def testMatcherCreationRequiresString(self): | |
38 | self.assertRaises(TypeError, equal_to_ignoring_whitespace, 3) | |
39 | ||
40 | def testFailsIfMatchingAgainstNonString(self): | |
41 | self.assert_does_not_match('non-string', matcher, object()) | |
42 | ||
43 | def testCanApplyUnicodeStringToUnicodeMatcher(self): | |
44 | self.assert_matches('unicode-unicode', | |
45 | equal_to_ignoring_whitespace(u'foo\nbar'), | |
46 | u'foo bar') | |
47 | ||
48 | def testCanApplyPlainStringToUnicodeMatcher(self): | |
49 | self.assert_matches('unicode-ascii', | |
50 | equal_to_ignoring_whitespace(u'foo\nbar'), | |
51 | 'foo bar') | |
52 | ||
53 | def testCanApplyUnicodeStringToPlainMatcher(self): | |
54 | self.assert_matches('ascii-unicode', | |
55 | equal_to_ignoring_whitespace('foo\n bar'), | |
56 | u'foo bar') | |
57 | ||
58 | def testDescribesItselfAsIgnoringWhiteSpace(self): | |
59 | self.assert_description("'foo\\nbar' ignoring whitespace", | |
60 | equal_to_ignoring_whitespace('foo\nbar')) | |
61 | ||
62 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
63 | self.assert_no_mismatch_description( | |
64 | equal_to_ignoring_whitespace('foo\nbar'), 'foo bar') | |
65 | ||
66 | def testMismatchDescription(self): | |
67 | self.assert_mismatch_description("was 'bad'", matcher, 'bad') | |
68 | ||
69 | def testDescribeMismatch(self): | |
70 | self.assert_describe_mismatch("was 'bad'", matcher, 'bad') | |
71 | ||
72 | ||
73 | if __name__ == '__main__': | |
74 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.text.stringcontains import * | |
6 | from hamcrest_unit_test.matcher_test import MatcherTest | |
7 | import unittest | |
8 | ||
9 | __author__ = "Jon Reid" | |
10 | __copyright__ = "Copyright 2011 hamcrest.org" | |
11 | __license__ = "BSD, see License.txt" | |
12 | ||
13 | ||
14 | EXCERPT = 'EXCERPT' | |
15 | matcher = contains_string(EXCERPT) | |
16 | ||
17 | class StringContainsTest(MatcherTest): | |
18 | ||
19 | def testEvaluatesToTrueIfArgumentContainsSpecifiedSubstring(self): | |
20 | self.assert_matches('excerpt at beginning', matcher, EXCERPT + 'END') | |
21 | self.assert_matches('excerpt at end', matcher, 'START' + EXCERPT) | |
22 | self.assert_matches('excerpt in middle', | |
23 | matcher, 'START' + EXCERPT + 'END') | |
24 | self.assert_matches('excerpt repeated', matcher, EXCERPT + EXCERPT) | |
25 | ||
26 | self.assert_does_not_match('excerpt not in string',matcher, 'whatever') | |
27 | self.assert_does_not_match('only part of excerpt',matcher, EXCERPT[1:]) | |
28 | ||
29 | def testEvaluatesToTrueIfArgumentIsEqualToSubstring(self): | |
30 | self.assert_matches('excerpt is entire string', matcher, EXCERPT) | |
31 | ||
32 | def testMatcherCreationRequiresString(self): | |
33 | self.assertRaises(TypeError, contains_string, 3) | |
34 | ||
35 | def testFailsIfMatchingAgainstNonString(self): | |
36 | self.assert_does_not_match('non-string', matcher, object()) | |
37 | ||
38 | def testCanApplyUnicodeStringToUnicodeMatcher(self): | |
39 | self.assert_matches('unicode-unicode', | |
40 | contains_string(u'bar'), u'foo bar baz') | |
41 | ||
42 | def testCanApplyPlainStringToUnicodeMatcher(self): | |
43 | self.assert_matches('unicode-ascii', | |
44 | contains_string(u'bar'), 'foo bar baz') | |
45 | ||
46 | def testCanApplyUnicodeStringToPlainMatcher(self): | |
47 | self.assert_matches('ascii-unicode', | |
48 | contains_string('bar'), u'foo bar baz') | |
49 | ||
50 | def testHasAReadableDescription(self): | |
51 | self.assert_description("a string containing 'EXCERPT'", matcher) | |
52 | ||
53 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
54 | self.assert_no_mismatch_description(matcher, EXCERPT) | |
55 | ||
56 | def testMismatchDescription(self): | |
57 | self.assert_mismatch_description("was 'bad'", matcher, 'bad') | |
58 | ||
59 | def testDescribeMismatch(self): | |
60 | self.assert_describe_mismatch("was 'bad'", matcher, 'bad') | |
61 | ||
62 | ||
63 | ||
64 | if __name__ == '__main__': | |
65 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.text.stringcontainsinorder import * | |
6 | ||
7 | from hamcrest.core.string_description import StringDescription | |
8 | from hamcrest_unit_test.matcher_test import MatcherTest | |
9 | import unittest | |
10 | ||
11 | __author__ = "Romilly Cocking" | |
12 | __copyright__ = "Copyright 2011 hamcrest.org" | |
13 | __license__ = "BSD, see License.txt" | |
14 | ||
15 | ||
16 | matcher = string_contains_in_order('string one', 'string two', 'string three') | |
17 | ||
18 | class StringContainsInOrderTest(MatcherTest): | |
19 | ||
20 | def testMatchesIfOrderIsCorrect(self): | |
21 | self.assert_matches('correct order', matcher, | |
22 | 'string one then string two followed by string three') | |
23 | ||
24 | def testDoesNotMatchIfOrderIsIncorrect(self): | |
25 | self.assert_does_not_match('incorrect order', matcher, | |
26 | 'string two then string one followed by string three') | |
27 | ||
28 | def testDoesNotMatchIfExpectedSubstringsAreMissing(self): | |
29 | self.assert_does_not_match('missing string one', matcher, 'string two then string three') | |
30 | self.assert_does_not_match('missing string two', matcher, 'string one then string three') | |
31 | self.assert_does_not_match('missing string three', matcher, 'string one then string two') | |
32 | ||
33 | def testMatcherCreationRequiresString(self): | |
34 | self.assertRaises(TypeError, string_contains_in_order, 3) | |
35 | ||
36 | def testFailsIfMatchingAgainstNonString(self): | |
37 | self.assert_does_not_match('non-string', matcher, object()) | |
38 | ||
39 | def testHasAReadableDescription(self): | |
40 | self.assert_description("a string containing 'string one', 'string two', 'string three' in order", matcher) | |
41 | ||
42 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
43 | self.assert_no_mismatch_description(matcher, 'string one then string two followed by string three') | |
44 | ||
45 | def testMismatchDescription(self): | |
46 | self.assert_mismatch_description("was 'bad'", matcher, 'bad') | |
47 | ||
48 | def testDescribeMismatch(self): | |
49 | self.assert_describe_mismatch("was 'bad'", matcher, 'bad') |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.text.stringendswith import * | |
6 | ||
7 | from hamcrest_unit_test.matcher_test import MatcherTest | |
8 | import unittest | |
9 | ||
10 | __author__ = "Jon Reid" | |
11 | __copyright__ = "Copyright 2011 hamcrest.org" | |
12 | __license__ = "BSD, see License.txt" | |
13 | ||
14 | ||
15 | EXCERPT = 'EXCERPT' | |
16 | matcher = ends_with(EXCERPT) | |
17 | ||
18 | class StringEndsWithTest(MatcherTest): | |
19 | ||
20 | def testEvaluatesToTrueIfArgumentContainsSpecifiedSubstring(self): | |
21 | self.assert_does_not_match('excerpt at beginning', | |
22 | matcher, EXCERPT + 'END') | |
23 | self.assert_matches('excerpt at end', matcher, 'START' + EXCERPT) | |
24 | self.assert_does_not_match('excerpt in middle', | |
25 | matcher, 'START' + EXCERPT + 'END') | |
26 | self.assert_matches('excerpt repeated', matcher, EXCERPT + EXCERPT) | |
27 | ||
28 | self.assert_does_not_match('excerpt not in string', | |
29 | matcher, 'whatever') | |
30 | self.assert_does_not_match('only part of excerpt is at end of string', | |
31 | matcher, EXCERPT[1:]) | |
32 | ||
33 | def testEvaluatesToTrueIfArgumentIsEqualToSubstring(self): | |
34 | self.assert_matches('excerpt is entire string', matcher, EXCERPT) | |
35 | ||
36 | def testMatcherCreationRequiresString(self): | |
37 | self.assertRaises(TypeError, ends_with, 3) | |
38 | ||
39 | def testFailsIfMatchingAgainstNonString(self): | |
40 | self.assert_does_not_match('non-string', matcher, object()) | |
41 | ||
42 | def testCanApplyUnicodeStringToUnicodeMatcher(self): | |
43 | self.assert_matches('unicode-unicode', | |
44 | ends_with(u'baz'), u'foo bar baz') | |
45 | ||
46 | def testCanApplyPlainStringToUnicodeMatcher(self): | |
47 | self.assert_matches('unicode-ascii', | |
48 | ends_with(u'baz'), 'foo bar baz') | |
49 | ||
50 | def testCanApplyUnicodeStringToPlainMatcher(self): | |
51 | self.assert_matches('ascii-unicode', | |
52 | ends_with(u'baz'), u'foo bar baz') | |
53 | ||
54 | def testHasAReadableDescription(self): | |
55 | self.assert_description("a string ending with 'EXCERPT'", matcher) | |
56 | ||
57 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
58 | self.assert_no_mismatch_description(matcher, EXCERPT) | |
59 | ||
60 | def testMismatchDescription(self): | |
61 | self.assert_mismatch_description("was 'bad'", matcher, 'bad') | |
62 | ||
63 | def testDescribeMismatch(self): | |
64 | self.assert_describe_mismatch("was 'bad'", matcher, 'bad') | |
65 | ||
66 | ||
67 | if __name__ == '__main__': | |
68 | unittest.main() |
0 | if __name__ == '__main__': | |
1 | import sys | |
2 | sys.path.insert(0, '..') | |
3 | sys.path.insert(0, '../..') | |
4 | ||
5 | from hamcrest.library.text.stringstartswith import * | |
6 | ||
7 | from hamcrest.core.assert_that import assert_that | |
8 | from hamcrest.core.core.isnot import is_not | |
9 | from hamcrest_unit_test.matcher_test import MatcherTest | |
10 | import unittest | |
11 | ||
12 | __author__ = "Jon Reid" | |
13 | __copyright__ = "Copyright 2011 hamcrest.org" | |
14 | __license__ = "BSD, see License.txt" | |
15 | ||
16 | ||
17 | EXCERPT = 'EXCERPT' | |
18 | matcher = starts_with(EXCERPT) | |
19 | stringstartswith = starts_with(EXCERPT) | |
20 | ||
21 | class StringStartsWithTest(MatcherTest): | |
22 | ||
23 | def testEvaluatesToTrueIfArgumentContainsSpecifiedSubstring(self): | |
24 | self.assert_matches('excerpt at beginning', matcher, EXCERPT + 'END') | |
25 | self.assert_does_not_match('excerpt at end', | |
26 | matcher, 'START' + EXCERPT) | |
27 | self.assert_does_not_match('excerpt in middle', | |
28 | matcher, 'START' + EXCERPT + 'END') | |
29 | self.assert_matches('excerpt repeated', matcher, EXCERPT + EXCERPT) | |
30 | ||
31 | self.assert_does_not_match('excerpt not in string',matcher, 'whatever') | |
32 | self.assert_does_not_match('only part of excerpt',matcher, EXCERPT[1:]) | |
33 | ||
34 | def testEvaluatesToTrueIfArgumentIsEqualToSubstring(self): | |
35 | self.assert_matches('excerpt is entire string', matcher, EXCERPT) | |
36 | ||
37 | def testMatcherCreationRequiresString(self): | |
38 | self.assertRaises(TypeError, starts_with, 3) | |
39 | ||
40 | def testFailsIfMatchingAgainstNonString(self): | |
41 | self.assert_does_not_match('non-string', matcher, object()) | |
42 | ||
43 | def testCanApplyUnicodeStringToUnicodeMatcher(self): | |
44 | self.assert_matches('unicode-unicode', | |
45 | starts_with(u'foo'), u'foo bar baz') | |
46 | ||
47 | def testCanApplyPlainStringToUnicodeMatcher(self): | |
48 | self.assert_matches('unicode-ascii', | |
49 | starts_with(u'foo'), 'foo bar baz') | |
50 | ||
51 | def testCanApplyUnicodeStringToPlainMatcher(self): | |
52 | self.assert_matches('ascii-unicode', | |
53 | starts_with(u'foo'), u'foo bar baz') | |
54 | ||
55 | def testHasAReadableDescription(self): | |
56 | self.assert_description("a string starting with 'EXCERPT'", matcher) | |
57 | ||
58 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
59 | self.assert_no_mismatch_description(matcher, EXCERPT) | |
60 | ||
61 | def testMismatchDescription(self): | |
62 | self.assert_mismatch_description("was 'bad'", matcher, 'bad') | |
63 | ||
64 | def testDescribeMismatch(self): | |
65 | self.assert_describe_mismatch("was 'bad'", matcher, 'bad') | |
66 | ||
67 | ||
68 | if __name__ == '__main__': | |
69 | unittest.main() |
16 | 16 | |
17 | 17 | # On Python 3, we can't "from hamcrest import __version__" (get ImportError), |
18 | 18 | # so we extract the variable assignment and execute it ourselves. |
19 | fh = open(local('hamcrest/__init__.py')) | |
19 | fh = open(local('src/hamcrest/__init__.py')) | |
20 | 20 | try: |
21 | 21 | for line in fh: |
22 | 22 | if re.match('__version__.*', line): |
30 | 30 | extra_attributes['use_2to3'] = True |
31 | 31 | |
32 | 32 | params = dict( |
33 | name = 'PyHamcrest', | |
34 | version = __version__, | |
35 | author = 'Jon Reid', | |
36 | author_email = 'jon.reid@mac.com', | |
37 | description = 'Hamcrest framework for matcher objects', | |
38 | license = 'New BSD', | |
33 | name='PyHamcrest', | |
34 | version=__version__, #flake8:noqa | |
35 | author='Chris Rose', | |
36 | author_email='offline@offby1.net', | |
37 | description='Hamcrest framework for matcher objects', | |
38 | license='New BSD', | |
39 | 39 | platforms=['All'], |
40 | keywords = 'hamcrest matchers pyunit unit test testing unittest unittesting', | |
41 | url = 'http://code.google.com/p/hamcrest/', | |
42 | download_url = 'http://pypi.python.org/packages/source/P/PyHamcrest/PyHamcrest-%s.tar.gz' % __version__, | |
43 | packages = find_packages(), | |
44 | test_suite = 'hamcrest-unit-test.alltests', | |
45 | provides = ['hamcrest'], | |
46 | long_description=read('README.md'), | |
47 | install_requires=['distribute'], | |
48 | classifiers = [ | |
40 | keywords='hamcrest matchers pyunit unit test testing unittest unittesting', | |
41 | url='https://github.com/hamcrest/PyHamcrest', | |
42 | download_url='http://pypi.python.org/packages/source/P/PyHamcrest/PyHamcrest-%s.tar.gz' % __version__, | |
43 | packages=find_packages('src'), | |
44 | package_dir = {'': 'src'}, | |
45 | provides=['hamcrest'], | |
46 | long_description=read('README.rst'), | |
47 | install_requires=['setuptools'], | |
48 | classifiers=[ | |
49 | 49 | 'Development Status :: 5 - Production/Stable', |
50 | 50 | 'Environment :: Console', |
51 | 51 | 'Intended Audience :: Developers', |
55 | 55 | 'Programming Language :: Python :: 2.5', |
56 | 56 | 'Programming Language :: Python :: 2.6', |
57 | 57 | 'Programming Language :: Python :: 2.7', |
58 | 'Programming Language :: Python :: 3.1', | |
59 | 58 | 'Programming Language :: Python :: 3.2', |
59 | 'Programming Language :: Python :: 3.3', | |
60 | 60 | 'Topic :: Software Development', |
61 | 61 | 'Topic :: Software Development :: Quality Assurance', |
62 | 62 | 'Topic :: Software Development :: Testing', |
0 | Metadata-Version: 1.1 | |
1 | Name: PyHamcrest | |
2 | Version: 1.8.0 | |
3 | Summary: Hamcrest framework for matcher objects | |
4 | Home-page: https://github.com/hamcrest/PyHamcrest | |
5 | Author: Chris Rose | |
6 | Author-email: offline@offby1.net | |
7 | License: New BSD | |
8 | Download-URL: http://pypi.python.org/packages/source/P/PyHamcrest/PyHamcrest-1.8.0.tar.gz | |
9 | Description: PyHamcrest | |
10 | ========== | |
11 | ||
12 | .. image:: https://pypip.in/v/PyHamcrest/badge.png | |
13 | :alt: Release Status | |
14 | :target: https://crate.io/packages/PyHamcrest | |
15 | .. image:: https://pypip.in/d/PyHamcrest/badge.png | |
16 | :alt: Downloads | |
17 | :target: https://crate.io/packages/PyHamcrest | |
18 | .. image:: https://travis-ci.org/hamcrest/PyHamcrest.png?branch=master | |
19 | :alt: Build Status | |
20 | :target: https://travis-ci.org/hamcrest/PyHamcrest | |
21 | ||
22 | Introduction | |
23 | ============ | |
24 | ||
25 | PyHamcrest is a framework for writing matcher objects, allowing you to | |
26 | declaratively define "match" rules. There are a number of situations where | |
27 | matchers are invaluable, such as UI validation, or data filtering, but it is in | |
28 | the area of writing flexible tests that matchers are most commonly used. This | |
29 | tutorial shows you how to use PyHamcrest for unit testing. | |
30 | ||
31 | When writing tests it is sometimes difficult to get the balance right between | |
32 | overspecifying the test (and making it brittle to changes), and not specifying | |
33 | enough (making the test less valuable since it continues to pass even when the | |
34 | thing being tested is broken). Having a tool that allows you to pick out | |
35 | precisely the aspect under test and describe the values it should have, to a | |
36 | controlled level of precision, helps greatly in writing tests that are "just | |
37 | right." Such tests fail when the behavior of the aspect under test deviates | |
38 | from the expected behavior, yet continue to pass when minor, unrelated changes | |
39 | to the behaviour are made. | |
40 | ||
41 | Installation | |
42 | ============ | |
43 | ||
44 | Hamcrest can be installed using the usual Python packaging tools. It depends on | |
45 | distribute, but as long as you have a network connection when you install, the | |
46 | installation process will take care of that for you. | |
47 | ||
48 | My first PyHamcrest test | |
49 | ======================== | |
50 | ||
51 | We'll start by writing a very simple PyUnit test, but instead of using PyUnit's | |
52 | ``assertEqual`` method, we'll use PyHamcrest's ``assert_that`` construct and | |
53 | the standard set of matchers: | |
54 | ||
55 | .. code:: python | |
56 | ||
57 | from hamcrest import * | |
58 | import unittest | |
59 | ||
60 | class BiscuitTest(unittest.TestCase): | |
61 | def testEquals(self): | |
62 | theBiscuit = Biscuit('Ginger') | |
63 | myBiscuit = Biscuit('Ginger') | |
64 | assert_that(theBiscuit, equal_to(myBiscuit)) | |
65 | ||
66 | if __name__ == '__main__': | |
67 | unittest.main() | |
68 | ||
69 | The ``assert_that`` function is a stylized sentence for making a test | |
70 | assertion. In this example, the subject of the assertion is the object | |
71 | ``theBiscuit``, which is the first method parameter. The second method | |
72 | parameter is a matcher for ``Biscuit`` objects, here a matcher that checks one | |
73 | object is equal to another using the Python ``==`` operator. The test passes | |
74 | since the ``Biscuit`` class defines an ``__eq__`` method. | |
75 | ||
76 | If you have more than one assertion in your test you can include an identifier | |
77 | for the tested value in the assertion: | |
78 | ||
79 | .. code:: python | |
80 | ||
81 | assert_that(theBiscuit.getChocolateChipCount(), equal_to(10), 'chocolate chips') | |
82 | assert_that(theBiscuit.getHazelnutCount(), equal_to(3), 'hazelnuts') | |
83 | ||
84 | As a convenience, assert_that can also be used to verify a boolean condition: | |
85 | ||
86 | .. code:: python | |
87 | ||
88 | assert_that(theBiscuit.isCooked(), 'cooked') | |
89 | ||
90 | This is equivalent to the ``assert_`` method of unittest.TestCase, but because | |
91 | it's a standalone function, it offers greater flexibility in test writing. | |
92 | ||
93 | ||
94 | Predefined matchers | |
95 | =================== | |
96 | ||
97 | PyHamcrest comes with a library of useful matchers: | |
98 | ||
99 | * Object | |
100 | ||
101 | * ``equal_to`` - match equal object | |
102 | * ``has_length`` - match ``len()`` | |
103 | * ``has_property`` - match value of property with given name | |
104 | * ``has_properties`` - match an object that has all of the given properties. | |
105 | * ``has_string`` - match ``str()`` | |
106 | * ``instance_of`` - match object type | |
107 | * ``none``, ``not_none`` - match ``None``, or not ``None`` | |
108 | * ``same_instance`` - match same object | |
109 | ||
110 | * Number | |
111 | ||
112 | * ``close_to`` - match number close to a given value | |
113 | * ``greater_than``, ``greater_than_or_equal_to``, ``less_than``, | |
114 | ``less_than_or_equal_to`` - match numeric ordering | |
115 | ||
116 | * Text | |
117 | ||
118 | * ``contains_string`` - match part of a string | |
119 | * ``ends_with`` - match the end of a string | |
120 | * ``equal_to_ignoring_case`` - match the complete string but ignore case | |
121 | * ``equal_to_ignoring_whitespace`` - match the complete string but ignore extra whitespace | |
122 | * ``matches_regexp`` - match a regular expression in a string | |
123 | * ``starts_with`` - match the beginning of a string | |
124 | * ``string_contains_in_order`` - match parts of a string, in relative order | |
125 | ||
126 | * Logical | |
127 | ||
128 | * ``all_of`` - ``and`` together all matchers | |
129 | * ``any_of`` - ``or`` together all matchers | |
130 | * ``anything`` - match anything, useful in composite matchers when you don't care about a particular value | |
131 | * ``is_not`` - negate the matcher | |
132 | ||
133 | * Sequence | |
134 | ||
135 | * ``contains`` - exactly match the entire sequence | |
136 | * ``contains_inanyorder`` - match the entire sequence, but in any order | |
137 | * ``has_item`` - match if given item appears in the sequence | |
138 | * ``has_items`` - match if all given items appear in the sequence, in any order | |
139 | * ``is_in`` - match if item appears in the given sequence | |
140 | * ``only_contains`` - match if sequence's items appear in given list | |
141 | ||
142 | * Dictionary | |
143 | ||
144 | * ``has_entries`` - match dictionary with list of key-value pairs | |
145 | * ``has_entry`` - match dictionary containing a key-value pair | |
146 | * ``has_key`` - match dictionary with a key | |
147 | * ``has_value`` - match dictionary with a value | |
148 | ||
149 | * Decorator | |
150 | ||
151 | * ``calling`` - wrap a callable in a deffered object, for subsequent matching on calling behaviour | |
152 | * ``raises`` - Ensure that a deferred callable raises as expected | |
153 | * ``described_as`` - give the matcher a custom failure description | |
154 | * ``is_`` - decorator to improve readability - see `Syntactic sugar` below | |
155 | ||
156 | The arguments for many of these matchers accept not just a matching value, but | |
157 | another matcher, so matchers can be composed for greater flexibility. For | |
158 | example, ``only_contains(less_than(5))`` will match any sequence where every | |
159 | item is less than 5. | |
160 | ||
161 | ||
162 | Syntactic sugar | |
163 | =============== | |
164 | ||
165 | PyHamcrest strives to make your tests as readable as possible. For example, the | |
166 | ``is_`` matcher is a wrapper that doesn't add any extra behavior to the | |
167 | underlying matcher. The following assertions are all equivalent: | |
168 | ||
169 | .. code:: python | |
170 | ||
171 | assert_that(theBiscuit, equal_to(myBiscuit)) | |
172 | assert_that(theBiscuit, is_(equal_to(myBiscuit))) | |
173 | assert_that(theBiscuit, is_(myBiscuit)) | |
174 | ||
175 | The last form is allowed since ``is_(value)`` wraps most non-matcher arguments | |
176 | with ``equal_to``. But if the argument is a type, it is wrapped with | |
177 | ``instance_of``, so the following are also equivalent: | |
178 | ||
179 | .. code:: python | |
180 | ||
181 | assert_that(theBiscuit, instance_of(Biscuit)) | |
182 | assert_that(theBiscuit, is_(instance_of(Biscuit))) | |
183 | assert_that(theBiscuit, is_(Biscuit)) | |
184 | ||
185 | *Note that PyHamcrest's ``is_`` matcher is unrelated to Python's ``is`` | |
186 | operator. The matcher for object identity is ``same_instance``.* | |
187 | ||
188 | ||
189 | Writing custom matchers | |
190 | ======================= | |
191 | ||
192 | PyHamcrest comes bundled with lots of useful matchers, but you'll probably find | |
193 | that you need to create your own from time to time to fit your testing needs. | |
194 | This commonly occurs when you find a fragment of code that tests the same set | |
195 | of properties over and over again (and in different tests), and you want to | |
196 | bundle the fragment into a single assertion. By writing your own matcher you'll | |
197 | eliminate code duplication and make your tests more readable! | |
198 | ||
199 | Let's write our own matcher for testing if a calendar date falls on a Saturday. | |
200 | This is the test we want to write: | |
201 | ||
202 | .. code:: python | |
203 | ||
204 | def testDateIsOnASaturday(self): | |
205 | d = datetime.date(2008, 04, 26) | |
206 | assert_that(d, is_(on_a_saturday())) | |
207 | ||
208 | And here's the implementation: | |
209 | ||
210 | .. code:: python | |
211 | ||
212 | from hamcrest.core.base_matcher import BaseMatcher | |
213 | from hamcrest.core.helpers.hasmethod import hasmethod | |
214 | ||
215 | class IsGivenDayOfWeek(BaseMatcher): | |
216 | ||
217 | def __init__(self, day): | |
218 | self.day = day # Monday is 0, Sunday is 6 | |
219 | ||
220 | def _matches(self, item): | |
221 | if not hasmethod(item, 'weekday'): | |
222 | return False | |
223 | return item.weekday() == self.day | |
224 | ||
225 | def describe_to(self, description): | |
226 | day_as_string = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', | |
227 | 'Friday', 'Saturday', 'Sunday'] | |
228 | description.append_text('calendar date falling on ') \ | |
229 | .append_text(day_as_string[self.day]) | |
230 | ||
231 | def on_a_saturday(): | |
232 | return IsGivenDayOfWeek(5) | |
233 | ||
234 | For our Matcher implementation we implement the ``_matches`` method - which | |
235 | calls the ``weekday`` method after confirming that the argument (which may not | |
236 | be a date) has such a method - and the ``describe_to`` method - which is used | |
237 | to produce a failure message when a test fails. Here's an example of how the | |
238 | failure message looks: | |
239 | ||
240 | .. code:: python | |
241 | ||
242 | assert_that(datetime.date(2008, 04, 06), is_(on_a_saturday())) | |
243 | ||
244 | fails with the message:: | |
245 | ||
246 | AssertionError: | |
247 | Expected: is calendar date falling on Saturday | |
248 | got: <2008-04-06> | |
249 | ||
250 | Let's say this matcher is saved in a module named ``isgivendayofweek``. We | |
251 | could use it in our test by importing the factory function ``on_a_saturday``: | |
252 | ||
253 | .. code:: python | |
254 | ||
255 | from hamcrest import * | |
256 | import unittest | |
257 | from isgivendayofweek import on_a_saturday | |
258 | ||
259 | class DateTest(unittest.TestCase): | |
260 | def testDateIsOnASaturday(self): | |
261 | d = datetime.date(2008, 04, 26) | |
262 | assert_that(d, is_(on_a_saturday())) | |
263 | ||
264 | if __name__ == '__main__': | |
265 | unittest.main() | |
266 | ||
267 | Even though the ``on_a_saturday`` function creates a new matcher each time it | |
268 | is called, you should not assume this is the only usage pattern for your | |
269 | matcher. Therefore you should make sure your matcher is stateless, so a single | |
270 | instance can be reused between matches. | |
271 | ||
272 | ||
273 | More resources | |
274 | ============== | |
275 | ||
276 | * Documentation_ | |
277 | * Package_ | |
278 | * Sources_ | |
279 | * Hamcrest_ | |
280 | ||
281 | .. _Documentation: http://readthedocs.org/docs/pyhamcrest/en/V1.7.1/ | |
282 | .. _Package: http://pypi.python.org/pypi/PyHamcrest | |
283 | .. _Sources: https://github.com/hamcrest/PyHamcrest | |
284 | .. _Hamcrest: http://hamcrest.org | |
285 | ||
286 | Keywords: hamcrest matchers pyunit unit test testing unittest unittesting | |
287 | Platform: All | |
288 | Classifier: Development Status :: 5 - Production/Stable | |
289 | Classifier: Environment :: Console | |
290 | Classifier: Intended Audience :: Developers | |
291 | Classifier: License :: OSI Approved :: BSD License | |
292 | Classifier: Natural Language :: English | |
293 | Classifier: Operating System :: OS Independent | |
294 | Classifier: Programming Language :: Python :: 2.5 | |
295 | Classifier: Programming Language :: Python :: 2.6 | |
296 | Classifier: Programming Language :: Python :: 2.7 | |
297 | Classifier: Programming Language :: Python :: 3.2 | |
298 | Classifier: Programming Language :: Python :: 3.3 | |
299 | Classifier: Topic :: Software Development | |
300 | Classifier: Topic :: Software Development :: Quality Assurance | |
301 | Classifier: Topic :: Software Development :: Testing | |
302 | Provides: hamcrest |
0 | CHANGES.txt | |
1 | LICENSE.txt | |
2 | MANIFEST.in | |
3 | README.rst | |
4 | setup.cfg | |
5 | setup.py | |
6 | examples/CustomDateMatcher.py | |
7 | examples/ExampleWithAssertThat.py | |
8 | src/PyHamcrest.egg-info/PKG-INFO | |
9 | src/PyHamcrest.egg-info/SOURCES.txt | |
10 | src/PyHamcrest.egg-info/dependency_links.txt | |
11 | src/PyHamcrest.egg-info/requires.txt | |
12 | src/PyHamcrest.egg-info/top_level.txt | |
13 | src/hamcrest/__init__.py | |
14 | src/hamcrest/core/__init__.py | |
15 | src/hamcrest/core/assert_that.py | |
16 | src/hamcrest/core/base_description.py | |
17 | src/hamcrest/core/base_matcher.py | |
18 | src/hamcrest/core/compat.py | |
19 | src/hamcrest/core/description.py | |
20 | src/hamcrest/core/matcher.py | |
21 | src/hamcrest/core/selfdescribing.py | |
22 | src/hamcrest/core/selfdescribingvalue.py | |
23 | src/hamcrest/core/string_description.py | |
24 | src/hamcrest/core/core/__init__.py | |
25 | src/hamcrest/core/core/allof.py | |
26 | src/hamcrest/core/core/anyof.py | |
27 | src/hamcrest/core/core/described_as.py | |
28 | src/hamcrest/core/core/is_.py | |
29 | src/hamcrest/core/core/isanything.py | |
30 | src/hamcrest/core/core/isequal.py | |
31 | src/hamcrest/core/core/isinstanceof.py | |
32 | src/hamcrest/core/core/isnone.py | |
33 | src/hamcrest/core/core/isnot.py | |
34 | src/hamcrest/core/core/issame.py | |
35 | src/hamcrest/core/core/raises.py | |
36 | src/hamcrest/core/helpers/__init__.py | |
37 | src/hamcrest/core/helpers/hasmethod.py | |
38 | src/hamcrest/core/helpers/wrap_matcher.py | |
39 | src/hamcrest/library/__init__.py | |
40 | src/hamcrest/library/collection/__init__.py | |
41 | src/hamcrest/library/collection/is_empty.py | |
42 | src/hamcrest/library/collection/isdict_containing.py | |
43 | src/hamcrest/library/collection/isdict_containingentries.py | |
44 | src/hamcrest/library/collection/isdict_containingkey.py | |
45 | src/hamcrest/library/collection/isdict_containingvalue.py | |
46 | src/hamcrest/library/collection/isin.py | |
47 | src/hamcrest/library/collection/issequence_containing.py | |
48 | src/hamcrest/library/collection/issequence_containinginanyorder.py | |
49 | src/hamcrest/library/collection/issequence_containinginorder.py | |
50 | src/hamcrest/library/collection/issequence_onlycontaining.py | |
51 | src/hamcrest/library/integration/__init__.py | |
52 | src/hamcrest/library/integration/match_equality.py | |
53 | src/hamcrest/library/number/__init__.py | |
54 | src/hamcrest/library/number/iscloseto.py | |
55 | src/hamcrest/library/number/ordering_comparison.py | |
56 | src/hamcrest/library/object/__init__.py | |
57 | src/hamcrest/library/object/haslength.py | |
58 | src/hamcrest/library/object/hasproperty.py | |
59 | src/hamcrest/library/object/hasstring.py | |
60 | src/hamcrest/library/text/__init__.py | |
61 | src/hamcrest/library/text/isequal_ignoring_case.py | |
62 | src/hamcrest/library/text/isequal_ignoring_whitespace.py | |
63 | src/hamcrest/library/text/stringcontains.py | |
64 | src/hamcrest/library/text/stringcontainsinorder.py | |
65 | src/hamcrest/library/text/stringendswith.py | |
66 | src/hamcrest/library/text/stringmatches.py | |
67 | src/hamcrest/library/text/stringstartswith.py | |
68 | src/hamcrest/library/text/substringmatcher.py⏎ |
0 | setuptools⏎ |
0 | hamcrest |
0 | from core import * | |
1 | from library import * | |
2 | ||
3 | __version__ = "1.8.0" | |
4 | __author__ = "Chris Rose" | |
5 | __copyright__ = "Copyright 2013 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" |
0 | from assert_that import assert_that | |
1 | from core import * | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" |
0 | from matcher import Matcher | |
1 | from string_description import StringDescription | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | # unittest integration; hide these frames from tracebacks | |
7 | __unittest = True | |
8 | # py.test integration; hide these frames from tracebacks | |
9 | __tracebackhide__ = True | |
10 | ||
11 | def assert_that(arg1, arg2=None, arg3=''): | |
12 | """Asserts that actual value satisfies matcher. (Can also assert plain | |
13 | boolean condition.) | |
14 | ||
15 | :param actual: The object to evaluate as the actual value. | |
16 | :param matcher: The matcher to satisfy as the expected condition. | |
17 | :param reason: Optional explanation to include in failure description. | |
18 | ||
19 | ``assert_that`` passes the actual value to the matcher for evaluation. If | |
20 | the matcher is not satisfied, an exception is thrown describing the | |
21 | mismatch. | |
22 | ||
23 | ``assert_that`` is designed to integrate well with PyUnit and other unit | |
24 | testing frameworks. The exception raised for an unmet assertion is an | |
25 | :py:exc:`AssertionError`, which PyUnit reports as a test failure. | |
26 | ||
27 | With a different set of parameters, ``assert_that`` can also verify a | |
28 | boolean condition: | |
29 | ||
30 | .. function:: assert_that(assertion[, reason]) | |
31 | ||
32 | :param assertion: Boolean condition to verify. | |
33 | :param reason: Optional explanation to include in failure description. | |
34 | ||
35 | This is equivalent to the :py:meth:`~unittest.TestCase.assertTrue` method | |
36 | of :py:class:`unittest.TestCase`, but offers greater flexibility in test | |
37 | writing by being a standalone function. | |
38 | ||
39 | """ | |
40 | if isinstance(arg2, Matcher): | |
41 | _assert_match(actual=arg1, matcher=arg2, reason=arg3) | |
42 | else: | |
43 | _assert_bool(assertion=arg1, reason=arg2) | |
44 | ||
45 | ||
46 | def _assert_match(actual, matcher, reason): | |
47 | if not matcher.matches(actual): | |
48 | description = StringDescription() | |
49 | description.append_text(reason) \ | |
50 | .append_text('\nExpected: ') \ | |
51 | .append_description_of(matcher) \ | |
52 | .append_text('\n but: ') | |
53 | matcher.describe_mismatch(actual, description) | |
54 | description.append_text('\n') | |
55 | raise AssertionError(str(description)) | |
56 | ||
57 | ||
58 | def _assert_bool(assertion, reason=None): | |
59 | if not assertion: | |
60 | if not reason: | |
61 | reason = 'Assertion failed' | |
62 | raise AssertionError(reason) |
0 | from description import Description | |
1 | from selfdescribingvalue import SelfDescribingValue | |
2 | from helpers.hasmethod import hasmethod | |
3 | ||
4 | import warnings | |
5 | ||
6 | __author__ = "Jon Reid" | |
7 | __copyright__ = "Copyright 2011 hamcrest.org" | |
8 | __license__ = "BSD, see License.txt" | |
9 | ||
10 | ||
11 | class BaseDescription(Description): | |
12 | """Base class for all :py:class:`~hamcrest.core.description.Description` | |
13 | implementations. | |
14 | ||
15 | """ | |
16 | ||
17 | def append_text(self, text): | |
18 | self.append(text) | |
19 | return self | |
20 | ||
21 | def append_description_of(self, value): | |
22 | if hasmethod(value, 'describe_to'): | |
23 | value.describe_to(self) | |
24 | elif isinstance(value, str): | |
25 | self.append_string_in_python_syntax(value) | |
26 | elif isinstance(value, unicode): | |
27 | self.append(repr(value)) | |
28 | else: | |
29 | description = str(value) | |
30 | if description[:1] == '<' and description[-1:] == '>': | |
31 | self.append(description) | |
32 | else: | |
33 | self.append('<') | |
34 | self.append(description) | |
35 | self.append('>') | |
36 | return self | |
37 | ||
38 | def append_value(self, value): | |
39 | warnings.warn('Call append_description_of instead of append_value', | |
40 | DeprecationWarning) | |
41 | if isinstance(value, str): | |
42 | self.append_string_in_python_syntax(value) | |
43 | else: | |
44 | self.append('<') | |
45 | self.append(str(value)) | |
46 | self.append('>') | |
47 | return self | |
48 | ||
49 | def append_value_list(self, start, separator, end, list): | |
50 | warnings.warn('Call append_list instead of append_value_list', | |
51 | DeprecationWarning) | |
52 | return self.append_list(start, separator, end, | |
53 | map(SelfDescribingValue, list)) | |
54 | ||
55 | def append_list(self, start, separator, end, list): | |
56 | separate = False | |
57 | ||
58 | self.append(start) | |
59 | for item in list: | |
60 | if separate: | |
61 | self.append(separator) | |
62 | self.append_description_of(item) | |
63 | separate = True | |
64 | self.append(end) | |
65 | return self | |
66 | ||
67 | def append(self, string): | |
68 | """Append the string to the description.""" | |
69 | raise NotImplementedError('append') | |
70 | ||
71 | def append_string_in_python_syntax(self, string): | |
72 | self.append("'") | |
73 | for ch in string: | |
74 | self.append(character_in_python_syntax(ch)) | |
75 | self.append("'") | |
76 | ||
77 | ||
78 | def character_in_python_syntax(ch): | |
79 | if ch == "'": | |
80 | return "\'" | |
81 | elif ch == '\n': | |
82 | return '\\n' | |
83 | elif ch == '\r': | |
84 | return '\\r' | |
85 | elif ch == '\t': | |
86 | return '\\t' | |
87 | else: | |
88 | return ch |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from matcher import Matcher | |
5 | from string_description import tostring | |
6 | ||
7 | ||
8 | class BaseMatcher(Matcher): | |
9 | """Base class for all :py:class:`~hamcrest.core.matcher.Matcher` | |
10 | implementations. | |
11 | ||
12 | Most implementations can just implement :py:obj:`_matches`, leaving the | |
13 | handling of any mismatch description to the ``matches`` method. But if it | |
14 | makes more sense to generate the mismatch description during the matching, | |
15 | override :py:meth:`~hamcrest.core.matcher.Matcher.matches` instead. | |
16 | ||
17 | """ | |
18 | ||
19 | def __str__(self): | |
20 | return tostring(self) | |
21 | ||
22 | def _matches(self, item): | |
23 | raise NotImplementedError('_matches') | |
24 | ||
25 | def matches(self, item, mismatch_description=None): | |
26 | match_result = self._matches(item) | |
27 | if not match_result and mismatch_description: | |
28 | self.describe_mismatch(item, mismatch_description) | |
29 | return match_result | |
30 | ||
31 | def describe_mismatch(self, item, mismatch_description): | |
32 | mismatch_description.append_text('was ').append_description_of(item) |
0 | __author__ = "Per Fagrell" | |
1 | __copyright__ = "Copyright 2013 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | __all__ = ['is_callable'] | |
5 | ||
6 | import sys | |
7 | ||
8 | # callable was not part of py3k until 3.2, so we create this | |
9 | # generic is_callable to use callable if possible, otherwise | |
10 | # we use generic homebrew. | |
11 | if sys.version_info[0] == 3 and sys.version_info[1] < 2: | |
12 | def is_callable(function): | |
13 | """Return whether the object is callable (i.e., some kind of function).""" | |
14 | if function is None: | |
15 | return False | |
16 | return any("__call__" in klass.__dict__ for klass in type(function).__mro__) | |
17 | else: | |
18 | is_callable = callable |
0 | """Fundamental matchers of objects and values, and composite matchers.""" | |
1 | ||
2 | from allof import all_of | |
3 | from anyof import any_of | |
4 | from described_as import described_as | |
5 | from is_ import is_ | |
6 | from isanything import anything | |
7 | from isequal import equal_to | |
8 | from isinstanceof import instance_of | |
9 | from isnone import none, not_none | |
10 | from isnot import is_not | |
11 | from issame import same_instance | |
12 | from raises import calling, raises | |
13 | ||
14 | __author__ = "Jon Reid" | |
15 | __copyright__ = "Copyright 2011 hamcrest.org" | |
16 | __license__ = "BSD, see License.txt" |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | class AllOf(BaseMatcher): | |
9 | ||
10 | def __init__(self, *matchers): | |
11 | self.matchers = matchers | |
12 | ||
13 | def matches(self, item, mismatch_description=None): | |
14 | for matcher in self.matchers: | |
15 | if not matcher.matches(item): | |
16 | if mismatch_description: | |
17 | mismatch_description.append_description_of(matcher) \ | |
18 | .append_text(' ') | |
19 | matcher.describe_mismatch(item, mismatch_description) | |
20 | return False | |
21 | return True | |
22 | ||
23 | def describe_mismatch(self, item, mismatch_description): | |
24 | self.matches(item, mismatch_description) | |
25 | ||
26 | def describe_to(self, description): | |
27 | description.append_list('(', ' and ', ')', self.matchers) | |
28 | ||
29 | ||
30 | def all_of(*items): | |
31 | """Matches if all of the given matchers evaluate to ``True``. | |
32 | ||
33 | :param matcher1,...: A comma-separated list of matchers. | |
34 | ||
35 | The matchers are evaluated from left to right using short-circuit | |
36 | evaluation, so evaluation stops as soon as a matcher returns ``False``. | |
37 | ||
38 | Any argument that is not a matcher is implicitly wrapped in an | |
39 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
40 | equality. | |
41 | ||
42 | """ | |
43 | return AllOf(*[wrap_matcher(item) for item in items]) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | class AnyOf(BaseMatcher): | |
9 | ||
10 | def __init__(self, *matchers): | |
11 | self.matchers = matchers | |
12 | ||
13 | def _matches(self, item): | |
14 | for matcher in self.matchers: | |
15 | if matcher.matches(item): | |
16 | return True | |
17 | return False | |
18 | ||
19 | def describe_to(self, description): | |
20 | description.append_list('(', ' or ', ')', self.matchers) | |
21 | ||
22 | ||
23 | def any_of(*items): | |
24 | """Matches if any of the given matchers evaluate to ``True``. | |
25 | ||
26 | :param matcher1,...: A comma-separated list of matchers. | |
27 | ||
28 | The matchers are evaluated from left to right using short-circuit | |
29 | evaluation, so evaluation stops as soon as a matcher returns ``True``. | |
30 | ||
31 | Any argument that is not a matcher is implicitly wrapped in an | |
32 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
33 | equality. | |
34 | ||
35 | """ | |
36 | return AnyOf(*[wrap_matcher(item) for item in items]) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | import re | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | ARG_PATTERN = re.compile('%([0-9]+)') | |
9 | ||
10 | ||
11 | class DescribedAs(BaseMatcher): | |
12 | ||
13 | def __init__(self, description_template, matcher, *values): | |
14 | self.template = description_template | |
15 | self.matcher = matcher | |
16 | self.values = values | |
17 | ||
18 | def matches(self, item, mismatch_description=None): | |
19 | return self.matcher.matches(item, mismatch_description) | |
20 | ||
21 | def describe_mismatch(self, item, mismatch_description): | |
22 | self.matcher.describe_mismatch(item, mismatch_description) | |
23 | ||
24 | def describe_to(self, description): | |
25 | text_start = 0 | |
26 | for match in re.finditer(ARG_PATTERN, self.template): | |
27 | description.append_text(self.template[text_start:match.start()]) | |
28 | arg_index = int(match.group()[1:]) | |
29 | description.append_description_of(self.values[arg_index]) | |
30 | text_start = match.end() | |
31 | ||
32 | if text_start < len(self.template): | |
33 | description.append_text(self.template[text_start:]) | |
34 | ||
35 | ||
36 | def described_as(description, matcher, *values): | |
37 | """Adds custom failure description to a given matcher. | |
38 | ||
39 | :param description: Overrides the matcher's description. | |
40 | :param matcher: The matcher to satisfy. | |
41 | :param value1,...: Optional comma-separated list of substitution values. | |
42 | ||
43 | The description may contain substitution placeholders %0, %1, etc. These | |
44 | will be replaced by any values that follow the matcher. | |
45 | ||
46 | """ | |
47 | return DescribedAs(description, matcher, *values) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher, is_matchable_type | |
6 | from isinstanceof import instance_of | |
7 | ||
8 | ||
9 | class Is(BaseMatcher): | |
10 | ||
11 | def __init__(self, matcher): | |
12 | self.matcher = matcher | |
13 | ||
14 | def matches(self, item, mismatch_description=None): | |
15 | return self.matcher.matches(item, mismatch_description) | |
16 | ||
17 | def describe_mismatch(self, item, mismatch_description): | |
18 | return self.matcher.describe_mismatch(item, mismatch_description) | |
19 | ||
20 | def describe_to(self, description): | |
21 | description.append_description_of(self.matcher) | |
22 | ||
23 | ||
24 | def wrap_value_or_type(x): | |
25 | if is_matchable_type(x): | |
26 | return instance_of(x) | |
27 | else: | |
28 | return wrap_matcher(x) | |
29 | ||
30 | ||
31 | def is_(x): | |
32 | """Decorates another matcher, or provides shortcuts to the frequently used | |
33 | ``is(equal_to(x))`` and ``is(instance_of(x))``. | |
34 | ||
35 | :param x: The matcher to satisfy, or a type for | |
36 | :py:func:`~hamcrest.core.core.isinstanceof.instance_of` matching, or an | |
37 | expected value for :py:func:`~hamcrest.core.core.isequal.equal_to` | |
38 | matching. | |
39 | ||
40 | This matcher compares the evaluated object to the given matcher. | |
41 | ||
42 | .. note:: | |
43 | ||
44 | PyHamcrest's ``is_`` matcher is unrelated to Python's ``is`` operator. | |
45 | The matcher for object identity is | |
46 | :py:func:`~hamcrest.core.core.issame.same_instance`. | |
47 | ||
48 | If the ``x`` argument is a matcher, its behavior is retained, but the test | |
49 | may be more expressive. For example:: | |
50 | ||
51 | assert_that(value, less_than(5)) | |
52 | assert_that(value, is_(less_than(5))) | |
53 | ||
54 | If the ``x`` argument is a type, it is wrapped in an | |
55 | :py:func:`~hamcrest.core.core.isinstanceof.instance_of` matcher. This makes | |
56 | the following statements equivalent:: | |
57 | ||
58 | assert_that(cheese, instance_of(Cheddar)) | |
59 | assert_that(cheese, is_(instance_of(Cheddar))) | |
60 | assert_that(cheese, is_(Cheddar)) | |
61 | ||
62 | Otherwise, if the ``x`` argument is not a matcher, it is wrapped in an | |
63 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher. This makes the | |
64 | following statements equivalent:: | |
65 | ||
66 | assert_that(cheese, equal_to(smelly)) | |
67 | assert_that(cheese, is_(equal_to(smelly))) | |
68 | assert_that(cheese, is_(smelly)) | |
69 | ||
70 | Choose the style that makes your expression most readable. This will vary | |
71 | depending on context. | |
72 | ||
73 | """ | |
74 | return Is(wrap_value_or_type(x)) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | class IsAnything(BaseMatcher): | |
8 | ||
9 | def __init__(self, description): | |
10 | self.description = description | |
11 | if not description: | |
12 | self.description = 'ANYTHING' | |
13 | ||
14 | def _matches(self, item): | |
15 | return True | |
16 | ||
17 | def describe_to(self, description): | |
18 | description.append_text(self.description) | |
19 | ||
20 | ||
21 | def anything(description=None): | |
22 | """Matches anything. | |
23 | ||
24 | :param description: Optional string used to describe this matcher. | |
25 | ||
26 | This matcher always evaluates to ``True``. Specify this in composite | |
27 | matchers when the value of a particular element is unimportant. | |
28 | ||
29 | """ | |
30 | return IsAnything(description) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | from hamcrest.core.matcher import Matcher | |
6 | ||
7 | ||
8 | class IsEqual(BaseMatcher): | |
9 | ||
10 | def __init__(self, equals): | |
11 | self.object = equals | |
12 | ||
13 | def _matches(self, item): | |
14 | return item == self.object | |
15 | ||
16 | def describe_to(self, description): | |
17 | nested_matcher = isinstance(self.object, Matcher) | |
18 | if nested_matcher: | |
19 | description.append_text('<') | |
20 | description.append_description_of(self.object) | |
21 | if nested_matcher: | |
22 | description.append_text('>') | |
23 | ||
24 | ||
25 | def equal_to(obj): | |
26 | """Matches if object is equal to a given object. | |
27 | ||
28 | :param obj: The object to compare against as the expected value. | |
29 | ||
30 | This matcher compares the evaluated object to ``obj`` for equality.""" | |
31 | return IsEqual(obj) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.wrap_matcher import is_matchable_type | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | import types | |
8 | ||
9 | class IsInstanceOf(BaseMatcher): | |
10 | ||
11 | def __init__(self, expected_type): | |
12 | if not is_matchable_type(expected_type): | |
13 | raise TypeError('IsInstanceOf requires type') | |
14 | self.expected_type = expected_type | |
15 | ||
16 | def _matches(self, item): | |
17 | return isinstance(item, self.expected_type) | |
18 | ||
19 | def describe_to(self, description): | |
20 | description.append_text('an instance of ') \ | |
21 | .append_text(self.expected_type.__name__) | |
22 | ||
23 | ||
24 | def instance_of(atype): | |
25 | """Matches if object is an instance of, or inherits from, a given type. | |
26 | ||
27 | :param atype: The type to compare against as the expected type. | |
28 | ||
29 | This matcher checks whether the evaluated object is an instance of | |
30 | ``atype`` or an instance of any class that inherits from ``atype``. | |
31 | ||
32 | Example:: | |
33 | ||
34 | instance_of(str) | |
35 | ||
36 | """ | |
37 | return IsInstanceOf(atype) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | from isnot import is_not | |
6 | ||
7 | ||
8 | class IsNone(BaseMatcher): | |
9 | ||
10 | def _matches(self, item): | |
11 | return item is None | |
12 | ||
13 | def describe_to(self, description): | |
14 | description.append_text('None') | |
15 | ||
16 | ||
17 | def none(): | |
18 | """Matches if object is ``None``.""" | |
19 | return IsNone() | |
20 | ||
21 | ||
22 | def not_none(): | |
23 | """Matches if object is not ``None``.""" | |
24 | return is_not(none()) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher, Matcher | |
5 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher, is_matchable_type | |
6 | from isequal import equal_to | |
7 | from isinstanceof import instance_of | |
8 | ||
9 | ||
10 | class IsNot(BaseMatcher): | |
11 | ||
12 | def __init__(self, matcher): | |
13 | self.matcher = matcher | |
14 | ||
15 | def _matches(self, item): | |
16 | return not self.matcher.matches(item) | |
17 | ||
18 | def describe_to(self, description): | |
19 | description.append_text('not ').append_description_of(self.matcher) | |
20 | ||
21 | ||
22 | def wrap_value_or_type(x): | |
23 | if is_matchable_type(x): | |
24 | return instance_of(x) | |
25 | else: | |
26 | return wrap_matcher(x) | |
27 | ||
28 | ||
29 | def is_not(match): | |
30 | """Inverts the given matcher to its logical negation. | |
31 | ||
32 | :param match: The matcher to negate. | |
33 | ||
34 | This matcher compares the evaluated object to the negation of the given | |
35 | matcher. If the ``match`` argument is not a matcher, it is implicitly | |
36 | wrapped in an :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to | |
37 | check for equality, and thus matches for inequality. | |
38 | ||
39 | Examples:: | |
40 | ||
41 | assert_that(cheese, is_not(equal_to(smelly))) | |
42 | assert_that(cheese, is_not(smelly)) | |
43 | ||
44 | """ | |
45 | return IsNot(wrap_value_or_type(match)) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | ||
6 | ||
7 | class IsSame(BaseMatcher): | |
8 | ||
9 | def __init__(self, object): | |
10 | self.object = object | |
11 | ||
12 | def _matches(self, item): | |
13 | return item is self.object | |
14 | ||
15 | def describe_to(self, description): | |
16 | description.append_text('same instance as ') \ | |
17 | .append_text(hex(id(self.object))) \ | |
18 | .append_text(' ') \ | |
19 | .append_description_of(self.object) | |
20 | ||
21 | def describe_mismatch(self, item, mismatch_description): | |
22 | mismatch_description.append_text('was ') | |
23 | if item is not None: | |
24 | mismatch_description.append_text(hex(id(item))) \ | |
25 | .append_text(' ') | |
26 | mismatch_description.append_description_of(item) | |
27 | ||
28 | ||
29 | def same_instance(obj): | |
30 | """Matches if evaluated object is the same instance as a given object. | |
31 | ||
32 | :param obj: The object to compare against as the expected value. | |
33 | ||
34 | This matcher invokes the ``is`` identity operator to determine if the | |
35 | evaluated object is the the same object as ``obj``. | |
36 | ||
37 | """ | |
38 | return IsSame(obj) |
0 | from weakref import ref | |
1 | import re | |
2 | import sys | |
3 | from hamcrest.core.base_matcher import BaseMatcher | |
4 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
5 | from hamcrest.core.compat import is_callable | |
6 | ||
7 | __author__ = "Per Fagrell" | |
8 | __copyright__ = "Copyright 2013 hamcrest.org" | |
9 | __license__ = "BSD, see License.txt" | |
10 | ||
11 | ||
12 | class Raises(BaseMatcher): | |
13 | def __init__(self, expected, pattern=None): | |
14 | self.pattern = pattern | |
15 | self.expected = expected | |
16 | self.actual = None | |
17 | self.function = None | |
18 | ||
19 | def _matches(self, function): | |
20 | if not is_callable(function): | |
21 | return False | |
22 | ||
23 | self.function = ref(function) | |
24 | return self._call_function(function) | |
25 | ||
26 | def _call_function(self, function): | |
27 | self.actual = None | |
28 | try: | |
29 | function() | |
30 | except Exception: | |
31 | self.actual = sys.exc_info()[1] | |
32 | ||
33 | if isinstance(self.actual, self.expected): | |
34 | if self.pattern is not None: | |
35 | return re.search(self.pattern, str(self.actual)) is not None | |
36 | return True | |
37 | return False | |
38 | ||
39 | def describe_to(self, description): | |
40 | description.append_text('Expected a callable raising %s' % self.expected) | |
41 | ||
42 | def describe_mismatch(self, item, description): | |
43 | if not is_callable(item): | |
44 | description.append_text('%s is not callable' % item) | |
45 | return | |
46 | ||
47 | function = None if self.function is None else self.function() | |
48 | if function is None or function is not item: | |
49 | self.function = ref(item) | |
50 | if not self._call_function(item): | |
51 | return | |
52 | ||
53 | if self.actual is None: | |
54 | description.append_text('No exception raised.') | |
55 | elif isinstance(self.actual, self.expected) and self.pattern is not None: | |
56 | description.append_text('Correct assertion type raised, but the expected pattern ("%s") not found.' % self.pattern) | |
57 | description.append_text('\n message was: "%s"' % str(self.actual)) | |
58 | else: | |
59 | description.append_text('%s was raised instead' % type(self.actual)) | |
60 | ||
61 | ||
62 | def raises(exception, pattern=None): | |
63 | """Matches if the called function raised the expected exception. | |
64 | ||
65 | :param exception: The class of the expected exception | |
66 | :param pattern: Optional regular expression to match exception message. | |
67 | ||
68 | Expects the actual to be wrapped by using :py:func:`~hamcrest.core.core.raises.calling`, | |
69 | or a callable taking no arguments. | |
70 | Optional argument pattern should be a string containing a regular expression. If provided, | |
71 | the string representation of the actual exception - e.g. `str(actual)` - must match pattern. | |
72 | ||
73 | Examples:: | |
74 | ||
75 | assert_that(calling(int).with_args('q'), raises(TypeError)) | |
76 | assert_that(calling(parse, broken_input), raises(ValueError)) | |
77 | """ | |
78 | return Raises(exception, pattern) | |
79 | ||
80 | ||
81 | class DeferredCallable(object): | |
82 | def __init__(self, func): | |
83 | self.func = func | |
84 | self.args = tuple() | |
85 | self.kwargs = {} | |
86 | ||
87 | def __call__(self): | |
88 | self.func(*self.args, **self.kwargs) | |
89 | ||
90 | def with_args(self, *args, **kwargs): | |
91 | self.args = args | |
92 | self.kwargs = kwargs | |
93 | return self | |
94 | ||
95 | ||
96 | def calling(func): | |
97 | """Wrapper for function call that delays the actual execution so that | |
98 | :py:func:`~hamcrest.core.core.raises.raises` matcher can catch any thrown exception. | |
99 | ||
100 | :param func: The function or method to be called | |
101 | ||
102 | The arguments can be provided with a call to the `with_args` function on the returned | |
103 | object:: | |
104 | ||
105 | calling(my_method).with_args(arguments, and_='keywords') | |
106 | """ | |
107 | return DeferredCallable(func) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | ||
5 | class Description(object): | |
6 | """A description of a :py:class:`~hamcrest.core.matcher.Matcher`. | |
7 | ||
8 | A :py:class:`~hamcrest.core.matcher.Matcher` will describe itself to a | |
9 | description which can later be used for reporting. | |
10 | ||
11 | """ | |
12 | ||
13 | def append_text(self, text): | |
14 | """Appends some plain text to the description. | |
15 | ||
16 | :returns: ``self``, for chaining | |
17 | ||
18 | """ | |
19 | raise NotImplementedError('append_text') | |
20 | ||
21 | def append_description_of(self, value): | |
22 | """Appends description of given value to this description. | |
23 | ||
24 | If the value implements | |
25 | :py:meth:`~hamcrest.core.selfdescribing.SelfDescribing.describe_to`, | |
26 | then it will be used. | |
27 | ||
28 | :returns: ``self``, for chaining | |
29 | ||
30 | """ | |
31 | raise NotImplementedError('append_description_of') | |
32 | ||
33 | def append_value(self, value): | |
34 | """Appends an arbitary value to the description. | |
35 | ||
36 | **Deprecated:** Call | |
37 | :py:meth:`~hamcrest.core.description.Description.append_description_of` | |
38 | instead. | |
39 | ||
40 | :returns: ``self``, for chaining | |
41 | ||
42 | """ | |
43 | raise NotImplementedError('append_value') | |
44 | ||
45 | def append_list(self, start, separator, end, list): | |
46 | """Appends a list of objects to the description. | |
47 | ||
48 | :param start: String that will begin the list description. | |
49 | :param separator: String that will separate each object in the | |
50 | description. | |
51 | :param end: String that will end the list description. | |
52 | :param list: List of objects to be described. | |
53 | ||
54 | :returns: ``self``, for chaining | |
55 | ||
56 | """ | |
57 | raise NotImplementedError('append_list') |
0 | """Utilities for writing Matchers.""" | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | ||
5 | def hasmethod(obj, methodname): | |
6 | """Does ``obj`` have a method named ``methodname``?""" | |
7 | ||
8 | if not hasattr(obj, methodname): | |
9 | return False | |
10 | method = getattr(obj, methodname) | |
11 | return callable(method) |
0 | from hamcrest.core.base_matcher import Matcher | |
1 | from hamcrest.core.core.isequal import equal_to | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | import types | |
8 | ||
9 | def wrap_matcher(x): | |
10 | """Wraps argument in a matcher, if necessary. | |
11 | ||
12 | :returns: the argument as-is if it is already a matcher, otherwise wrapped | |
13 | in an :py:func:`~hamcrest.core.core.isequal.equal_to` matcher. | |
14 | ||
15 | """ | |
16 | if isinstance(x, Matcher): | |
17 | return x | |
18 | else: | |
19 | return equal_to(x) | |
20 | ||
21 | def is_matchable_type(expected_type): | |
22 | if isinstance(expected_type, type): | |
23 | return True | |
24 | ||
25 | if type(expected_type) == types.ClassType: | |
26 | return True | |
27 | ||
28 | return False |
0 | from selfdescribing import SelfDescribing | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | class Matcher(SelfDescribing): | |
8 | """A matcher over acceptable values. | |
9 | ||
10 | A matcher is able to describe itself to give feedback when it fails. | |
11 | ||
12 | Matcher implementations should *not* directly implement this protocol. | |
13 | Instead, *extend* the :py:class:`~hamcrest.core.base_matcher.BaseMatcher` | |
14 | class, which will ensure that the | |
15 | :py:class:`~hamcrest.core.matcher.Matcher` API can grow to support new | |
16 | features and remain compatible with all | |
17 | :py:class:`~hamcrest.core.matcher.Matcher` implementations. | |
18 | ||
19 | """ | |
20 | ||
21 | def matches(self, item, mismatch_description=None): | |
22 | """Evaluates the matcher for argument item. | |
23 | ||
24 | If a mismatch is detected and argument ``mismatch_description`` is | |
25 | provided, it will generate a description of why the matcher has not | |
26 | accepted the item. | |
27 | ||
28 | :param item: The object against which the matcher is evaluated. | |
29 | :returns: ``True`` if ``item`` matches, otherwise ``False``. | |
30 | ||
31 | """ | |
32 | raise NotImplementedError('matches') | |
33 | ||
34 | def describe_mismatch(self, item, mismatch_description): | |
35 | """Generates a description of why the matcher has not accepted the | |
36 | item. | |
37 | ||
38 | The description will be part of a larger description of why a matching | |
39 | failed, so it should be concise. | |
40 | ||
41 | This method assumes that ``matches(item)`` is ``False``, but will not | |
42 | check this. | |
43 | ||
44 | :param item: The item that the | |
45 | :py:class:`~hamcrest.core.matcher.Matcher` has rejected. | |
46 | :param mismatch_description: The description to be built or appended | |
47 | to. | |
48 | ||
49 | """ | |
50 | raise NotImplementedError('describe_mismatch') |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | ||
5 | class SelfDescribing(object): | |
6 | """The ability of an object to describe itself.""" | |
7 | ||
8 | def describe_to(self, description): | |
9 | """Generates a description of the object. | |
10 | ||
11 | The description may be part of a description of a larger object of | |
12 | which this is just a component, so it should be worded appropriately. | |
13 | ||
14 | :param description: The description to be built or appended to. | |
15 | ||
16 | """ | |
17 | raise NotImplementedError('describe_to') |
0 | from hamcrest.core.selfdescribing import SelfDescribing | |
1 | ||
2 | import warnings | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | class SelfDescribingValue(SelfDescribing): | |
10 | """Wrap any value in a ``SelfDescribingValue`` to satisfy the | |
11 | :py:class:`~hamcrest.core.selfdescribing.SelfDescribing` interface. | |
12 | ||
13 | **Deprecated:** No need for this class now that | |
14 | :py:meth:`~hamcrest.core.description.Description.append_description_of` | |
15 | handles any type of value. | |
16 | ||
17 | """ | |
18 | ||
19 | def __init__(self, value): | |
20 | warnings.warn('SelfDescribingValue no longer needed', | |
21 | DeprecationWarning) | |
22 | self.value = value | |
23 | ||
24 | def describe_to(self, description): | |
25 | """Generates a description of the value.""" | |
26 | description.append_value(self.value) |
0 | from base_description import BaseDescription | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | def tostring(selfdescribing): | |
8 | """Returns the description of a | |
9 | :py:class:`~hamcrest.core.selfdescribing.SelfDescribing` object as a | |
10 | string. | |
11 | ||
12 | :param selfdescribing: The object to be described. | |
13 | :returns: The description of the object. | |
14 | """ | |
15 | return str(StringDescription().append_description_of(selfdescribing)) | |
16 | ||
17 | ||
18 | class StringDescription(BaseDescription): | |
19 | """A :py:class:`~hamcrest.core.description.Description` that is stored as a | |
20 | string. | |
21 | ||
22 | """ | |
23 | ||
24 | def __init__(self): | |
25 | self.out = '' | |
26 | ||
27 | def __str__(self): | |
28 | """Returns the description.""" | |
29 | return self.out | |
30 | ||
31 | def append(self, string): | |
32 | self.out += string |
0 | """Library of Matcher implementations.""" | |
1 | ||
2 | from hamcrest.core import * | |
3 | from collection import * | |
4 | from integration import * | |
5 | from number import * | |
6 | from object import * | |
7 | from text import * | |
8 | ||
9 | __author__ = "Jon Reid" | |
10 | __copyright__ = "Copyright 2011 hamcrest.org" | |
11 | __license__ = "BSD, see License.txt" | |
12 | ||
13 | __all__ = [ | |
14 | 'has_entry', | |
15 | 'has_entries', | |
16 | 'has_key', | |
17 | 'has_value', | |
18 | 'is_in', | |
19 | 'empty', | |
20 | 'has_item', | |
21 | 'has_items', | |
22 | 'contains_inanyorder', | |
23 | 'contains', | |
24 | 'only_contains', | |
25 | 'match_equality', | |
26 | 'matches_regexp', | |
27 | 'close_to', | |
28 | 'greater_than', | |
29 | 'greater_than_or_equal_to', | |
30 | 'less_than', | |
31 | 'less_than_or_equal_to', | |
32 | 'has_length', | |
33 | 'has_property', | |
34 | 'has_properties', | |
35 | 'has_string', | |
36 | 'equal_to_ignoring_case', | |
37 | 'equal_to_ignoring_whitespace', | |
38 | 'contains_string', | |
39 | 'ends_with', | |
40 | 'starts_with', | |
41 | 'string_contains_in_order', | |
42 | ] |
0 | """Matchers of collections.""" | |
1 | from __future__ import absolute_import | |
2 | from .isdict_containing import has_entry | |
3 | from .isdict_containingentries import has_entries | |
4 | from .isdict_containingkey import has_key | |
5 | from .isdict_containingvalue import has_value | |
6 | from .isin import is_in | |
7 | from .issequence_containing import has_item, has_items | |
8 | from .issequence_containinginanyorder import contains_inanyorder | |
9 | from .issequence_containinginorder import contains | |
10 | from .issequence_onlycontaining import only_contains | |
11 | from .is_empty import empty | |
12 | ||
13 | __author__ = "Chris Rose" | |
14 | __copyright__ = "Copyright 2013 hamcrest.org" | |
15 | __license__ = "BSD, see License.txt" |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | ||
2 | __author__ = "Chris Rose" | |
3 | __copyright__ = "Copyright 2012 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | class IsEmpty(BaseMatcher): | |
8 | ||
9 | def matches(self, item, mismatch_description=None): | |
10 | try: | |
11 | if len(item) == 0: | |
12 | return True | |
13 | ||
14 | if mismatch_description: | |
15 | mismatch_description \ | |
16 | .append_text('has %d item(s)' % len(item)) | |
17 | ||
18 | except TypeError: | |
19 | if mismatch_description: | |
20 | mismatch_description \ | |
21 | .append_text('does not support length') | |
22 | ||
23 | return False | |
24 | ||
25 | def describe_to(self, description): | |
26 | description.append_text('an empty collection') | |
27 | ||
28 | ||
29 | def empty(): | |
30 | """ | |
31 | This matcher matches any collection-like object that responds to the | |
32 | __len__ method, and has a length of 0. | |
33 | """ | |
34 | return IsEmpty() |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | class IsDictContaining(BaseMatcher): | |
10 | ||
11 | def __init__(self, key_matcher, value_matcher): | |
12 | self.key_matcher = key_matcher | |
13 | self.value_matcher = value_matcher | |
14 | ||
15 | def _matches(self, dictionary): | |
16 | if hasmethod(dictionary, 'items'): | |
17 | for key, value in dictionary.items(): | |
18 | if self.key_matcher.matches(key) and self.value_matcher.matches(value): | |
19 | return True | |
20 | return False | |
21 | ||
22 | def describe_to(self, description): | |
23 | description.append_text('a dictionary containing [') \ | |
24 | .append_description_of(self.key_matcher) \ | |
25 | .append_text(': ') \ | |
26 | .append_description_of(self.value_matcher) \ | |
27 | .append_text(']') | |
28 | ||
29 | ||
30 | def has_entry(key_match, value_match): | |
31 | """Matches if dictionary contains key-value entry satisfying a given pair | |
32 | of matchers. | |
33 | ||
34 | :param key_match: The matcher to satisfy for the key, or an expected value | |
35 | for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
36 | :param value_match: The matcher to satisfy for the value, or an expected | |
37 | value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
38 | ||
39 | This matcher iterates the evaluated dictionary, searching for any key-value | |
40 | entry that satisfies ``key_match`` and ``value_match``. If a matching entry | |
41 | is found, ``has_entry`` is satisfied. | |
42 | ||
43 | Any argument that is not a matcher is implicitly wrapped in an | |
44 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
45 | equality. | |
46 | ||
47 | Examples:: | |
48 | ||
49 | has_entry(equal_to('foo'), equal_to(1)) | |
50 | has_entry('foo', 1) | |
51 | ||
52 | """ | |
53 | return IsDictContaining(wrap_matcher(key_match), wrap_matcher(value_match)) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | class IsDictContainingEntries(BaseMatcher): | |
10 | ||
11 | def __init__(self, value_matchers): | |
12 | self.value_matchers = value_matchers | |
13 | ||
14 | def _not_a_dictionary(self, dictionary, mismatch_description): | |
15 | if mismatch_description: | |
16 | mismatch_description.append_description_of(dictionary) \ | |
17 | .append_text(' is not a mapping object') | |
18 | return False | |
19 | ||
20 | def matches(self, dictionary, mismatch_description=None): | |
21 | for key in self.value_matchers: | |
22 | ||
23 | try: | |
24 | if not key in dictionary: | |
25 | if mismatch_description: | |
26 | mismatch_description.append_text('no ') \ | |
27 | .append_description_of(key) \ | |
28 | .append_text(' key in ') \ | |
29 | .append_description_of(dictionary) | |
30 | return False | |
31 | except TypeError: | |
32 | return self._not_a_dictionary(dictionary, mismatch_description) | |
33 | ||
34 | value_matcher = self.value_matchers[key] | |
35 | try: | |
36 | actual_value = dictionary[key] | |
37 | except TypeError: | |
38 | return self._not_a_dictionary(dictionary, mismatch_description) | |
39 | ||
40 | if not value_matcher.matches(actual_value): | |
41 | if mismatch_description: | |
42 | mismatch_description.append_text('value for ') \ | |
43 | .append_description_of(key) \ | |
44 | .append_text(' ') | |
45 | value_matcher.describe_mismatch(actual_value, mismatch_description) | |
46 | return False | |
47 | ||
48 | return True | |
49 | ||
50 | def describe_mismatch(self, item, mismatch_description): | |
51 | self.matches(item, mismatch_description) | |
52 | ||
53 | def describe_keyvalue(self, index, description): | |
54 | """Describes key-value pair at given index.""" | |
55 | description.append_description_of(index) \ | |
56 | .append_text(': ') \ | |
57 | .append_description_of(self.value_matchers[index]) | |
58 | ||
59 | def describe_to(self, description): | |
60 | description.append_text('a dictionary containing {') | |
61 | first = True | |
62 | for key in self.value_matchers: | |
63 | if not first: | |
64 | description.append_text(', ') | |
65 | self.describe_keyvalue(key, description) | |
66 | first = False | |
67 | description.append_text('}') | |
68 | ||
69 | ||
70 | def has_entries(*keys_valuematchers, **kv_args): | |
71 | """Matches if dictionary contains entries satisfying a dictionary of keys | |
72 | and corresponding value matchers. | |
73 | ||
74 | :param matcher_dict: A dictionary mapping keys to associated value matchers, | |
75 | or to expected values for | |
76 | :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
77 | ||
78 | Note that the keys must be actual keys, not matchers. Any value argument | |
79 | that is not a matcher is implicitly wrapped in an | |
80 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
81 | equality. | |
82 | ||
83 | Examples:: | |
84 | ||
85 | has_entries({'foo':equal_to(1), 'bar':equal_to(2)}) | |
86 | has_entries({'foo':1, 'bar':2}) | |
87 | ||
88 | ``has_entries`` also accepts a list of keyword arguments: | |
89 | ||
90 | .. function:: has_entries(keyword1=value_matcher1[, keyword2=value_matcher2[, ...]]) | |
91 | ||
92 | :param keyword1: A keyword to look up. | |
93 | :param valueMatcher1: The matcher to satisfy for the value, or an expected | |
94 | value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
95 | ||
96 | Examples:: | |
97 | ||
98 | has_entries(foo=equal_to(1), bar=equal_to(2)) | |
99 | has_entries(foo=1, bar=2) | |
100 | ||
101 | Finally, ``has_entries`` also accepts a list of alternating keys and their | |
102 | value matchers: | |
103 | ||
104 | .. function:: has_entries(key1, value_matcher1[, ...]) | |
105 | ||
106 | :param key1: A key (not a matcher) to look up. | |
107 | :param valueMatcher1: The matcher to satisfy for the value, or an expected | |
108 | value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
109 | ||
110 | Examples:: | |
111 | ||
112 | has_entries('foo', equal_to(1), 'bar', equal_to(2)) | |
113 | has_entries('foo', 1, 'bar', 2) | |
114 | ||
115 | """ | |
116 | if len(keys_valuematchers) == 1: | |
117 | try: | |
118 | base_dict = keys_valuematchers[0].copy() | |
119 | for key in base_dict: | |
120 | base_dict[key] = wrap_matcher(base_dict[key]) | |
121 | except AttributeError: | |
122 | raise ValueError('single-argument calls to has_entries must pass a dict as the argument') | |
123 | else: | |
124 | if len(keys_valuematchers) % 2: | |
125 | raise ValueError('has_entries requires key-value pairs') | |
126 | base_dict = {} | |
127 | for index in range(int(len(keys_valuematchers) / 2)): | |
128 | base_dict[keys_valuematchers[2 * index]] = wrap_matcher(keys_valuematchers[2 * index + 1]) | |
129 | ||
130 | for key, value in kv_args.items(): | |
131 | base_dict[key] = wrap_matcher(value) | |
132 | ||
133 | return IsDictContainingEntries(base_dict) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | class IsDictContainingKey(BaseMatcher): | |
10 | ||
11 | def __init__(self, key_matcher): | |
12 | self.key_matcher = key_matcher | |
13 | ||
14 | def _matches(self, dictionary): | |
15 | if hasmethod(dictionary, 'keys'): | |
16 | for key in dictionary.keys(): | |
17 | if self.key_matcher.matches(key): | |
18 | return True | |
19 | return False | |
20 | ||
21 | def describe_to(self, description): | |
22 | description.append_text('a dictionary containing key ') \ | |
23 | .append_description_of(self.key_matcher) | |
24 | ||
25 | ||
26 | def has_key(key_match): | |
27 | """Matches if dictionary contains an entry whose key satisfies a given | |
28 | matcher. | |
29 | ||
30 | :param key_match: The matcher to satisfy for the key, or an expected value | |
31 | for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
32 | ||
33 | This matcher iterates the evaluated dictionary, searching for any key-value | |
34 | entry whose key satisfies the given matcher. If a matching entry is found, | |
35 | ``has_key`` is satisfied. | |
36 | ||
37 | Any argument that is not a matcher is implicitly wrapped in an | |
38 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
39 | equality. | |
40 | ||
41 | Examples:: | |
42 | ||
43 | has_key(equal_to('foo')) | |
44 | has_key('foo') | |
45 | ||
46 | """ | |
47 | return IsDictContainingKey(wrap_matcher(key_match)) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | class IsDictContainingValue(BaseMatcher): | |
10 | ||
11 | def __init__(self, value_matcher): | |
12 | self.value_matcher = value_matcher | |
13 | ||
14 | def _matches(self, dictionary): | |
15 | if hasmethod(dictionary, 'values'): | |
16 | for value in dictionary.values(): | |
17 | if self.value_matcher.matches(value): | |
18 | return True | |
19 | return False | |
20 | ||
21 | def describe_to(self, description): | |
22 | description.append_text('a dictionary containing value ') \ | |
23 | .append_description_of(self.value_matcher) | |
24 | ||
25 | ||
26 | def has_value(value): | |
27 | """Matches if dictionary contains an entry whose value satisfies a given | |
28 | matcher. | |
29 | ||
30 | :param value_match: The matcher to satisfy for the value, or an expected | |
31 | value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
32 | ||
33 | This matcher iterates the evaluated dictionary, searching for any key-value | |
34 | entry whose value satisfies the given matcher. If a matching entry is | |
35 | found, ``has_value`` is satisfied. | |
36 | ||
37 | Any argument that is not a matcher is implicitly wrapped in an | |
38 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
39 | equality. | |
40 | ||
41 | Examples:: | |
42 | ||
43 | has_value(equal_to('bar')) | |
44 | has_value('bar') | |
45 | ||
46 | """ | |
47 | return IsDictContainingValue(wrap_matcher(value)) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | class IsIn(BaseMatcher): | |
8 | ||
9 | def __init__(self, sequence): | |
10 | self.sequence = sequence | |
11 | ||
12 | def _matches(self, item): | |
13 | return item in self.sequence | |
14 | ||
15 | def describe_to(self, description): | |
16 | description.append_text('one of ') \ | |
17 | .append_list('(', ', ', ')', self.sequence) | |
18 | ||
19 | ||
20 | def is_in(sequence): | |
21 | """Matches if evaluated object is present in a given sequence. | |
22 | ||
23 | :param sequence: The sequence to search. | |
24 | ||
25 | This matcher invokes the ``in`` membership operator to determine if the | |
26 | evaluated object is a member of the sequence. | |
27 | ||
28 | """ | |
29 | return IsIn(sequence) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | from hamcrest.core.core.allof import all_of | |
6 | from hamcrest.core.helpers.hasmethod import hasmethod | |
7 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
8 | ||
9 | ||
10 | class IsSequenceContaining(BaseMatcher): | |
11 | ||
12 | def __init__(self, element_matcher): | |
13 | self.element_matcher = element_matcher | |
14 | ||
15 | def _matches(self, sequence): | |
16 | try: | |
17 | for item in sequence: | |
18 | if self.element_matcher.matches(item): | |
19 | return True | |
20 | except TypeError: # not a sequence | |
21 | return False | |
22 | ||
23 | def describe_to(self, description): | |
24 | description.append_text('a sequence containing ') \ | |
25 | .append_description_of(self.element_matcher) | |
26 | ||
27 | ||
28 | # It'd be great to make use of all_of, but we can't be sure we won't | |
29 | # be seeing a one-time sequence here (like a generator); see issue #20 | |
30 | # Instead, we wrap it inside a class that will convert the sequence into | |
31 | # a concrete list and then hand it off to the all_of matcher. | |
32 | class IsSequenceContainingEvery(BaseMatcher): | |
33 | ||
34 | def __init__(self, *element_matchers): | |
35 | delegates = [has_item(e) for e in element_matchers] | |
36 | self.matcher = all_of(*delegates) | |
37 | ||
38 | def _matches(self, sequence): | |
39 | try: | |
40 | return self.matcher.matches(list(sequence)) | |
41 | except TypeError: | |
42 | return False | |
43 | ||
44 | def describe_mismatch(self, item, mismatch_description): | |
45 | self.matcher.describe_mismatch(item, mismatch_description) | |
46 | ||
47 | def describe_to(self, description): | |
48 | self.matcher.describe_to(description) | |
49 | ||
50 | ||
51 | ||
52 | def has_item(match): | |
53 | """Matches if any element of sequence satisfies a given matcher. | |
54 | ||
55 | :param match: The matcher to satisfy, or an expected value for | |
56 | :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
57 | ||
58 | This matcher iterates the evaluated sequence, searching for any element | |
59 | that satisfies a given matcher. If a matching element is found, | |
60 | ``has_item`` is satisfied. | |
61 | ||
62 | If the ``match`` argument is not a matcher, it is implicitly wrapped in an | |
63 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
64 | equality. | |
65 | ||
66 | """ | |
67 | return IsSequenceContaining(wrap_matcher(match)) | |
68 | ||
69 | ||
70 | def has_items(*items): | |
71 | """Matches if all of the given matchers are satisfied by any elements of | |
72 | the sequence. | |
73 | ||
74 | :param match1,...: A comma-separated list of matchers. | |
75 | ||
76 | This matcher iterates the given matchers, searching for any elements in the | |
77 | evaluated sequence that satisfy them. If each matcher is satisfied, then | |
78 | ``has_items`` is satisfied. | |
79 | ||
80 | Any argument that is not a matcher is implicitly wrapped in an | |
81 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
82 | equality. | |
83 | ||
84 | """ | |
85 | matchers = [] | |
86 | for item in items: | |
87 | matchers.append(wrap_matcher(item)) | |
88 | return IsSequenceContainingEvery(*matchers) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | class MatchInAnyOrder(object): | |
10 | def __init__(self, matchers, mismatch_description): | |
11 | self.matchers = matchers[:] | |
12 | self.mismatch_description = mismatch_description | |
13 | ||
14 | def matches(self, item): | |
15 | return self.isnotsurplus(item) and self.ismatched(item) | |
16 | ||
17 | def isfinished(self, sequence): | |
18 | if not self.matchers: | |
19 | return True | |
20 | if self.mismatch_description: | |
21 | self.mismatch_description.append_text('no item matches: ') \ | |
22 | .append_list('', ', ', '', self.matchers) \ | |
23 | .append_text(' in ') \ | |
24 | .append_list('[', ', ', ']', sequence) | |
25 | return False | |
26 | ||
27 | def isnotsurplus(self, item): | |
28 | if not self.matchers: | |
29 | if self.mismatch_description: | |
30 | self.mismatch_description.append_text('not matched: ') \ | |
31 | .append_description_of(item) | |
32 | return False | |
33 | return True | |
34 | ||
35 | def ismatched(self, item): | |
36 | for index, matcher in enumerate(self.matchers): | |
37 | if matcher.matches(item): | |
38 | del self.matchers[index] | |
39 | return True | |
40 | ||
41 | if self.mismatch_description: | |
42 | self.mismatch_description.append_text('not matched: ') \ | |
43 | .append_description_of(item) | |
44 | return False | |
45 | ||
46 | ||
47 | class IsSequenceContainingInAnyOrder(BaseMatcher): | |
48 | ||
49 | def __init__(self, matchers): | |
50 | self.matchers = matchers | |
51 | ||
52 | def matches(self, sequence, mismatch_description=None): | |
53 | try: | |
54 | sequence = list(sequence) | |
55 | matchsequence = MatchInAnyOrder(self.matchers, mismatch_description) | |
56 | for item in sequence: | |
57 | if not matchsequence.matches(item): | |
58 | return False | |
59 | return matchsequence.isfinished(sequence) | |
60 | except TypeError: | |
61 | if mismatch_description: | |
62 | super(IsSequenceContainingInAnyOrder, self) \ | |
63 | .describe_mismatch(sequence, mismatch_description) | |
64 | return False | |
65 | ||
66 | def describe_mismatch(self, item, mismatch_description): | |
67 | self.matches(item, mismatch_description) | |
68 | ||
69 | def describe_to(self, description): | |
70 | description.append_text('a sequence over ') \ | |
71 | .append_list('[', ', ', ']', self.matchers) \ | |
72 | .append_text(' in any order') | |
73 | ||
74 | ||
75 | def contains_inanyorder(*items): | |
76 | """Matches if sequences's elements, in any order, satisfy a given list of | |
77 | matchers. | |
78 | ||
79 | :param match1,...: A comma-separated list of matchers. | |
80 | ||
81 | This matcher iterates the evaluated sequence, seeing if each element | |
82 | satisfies any of the given matchers. The matchers are tried from left to | |
83 | right, and when a satisfied matcher is found, it is no longer a candidate | |
84 | for the remaining elements. If a one-to-one correspondence is established | |
85 | between elements and matchers, ``contains_inanyorder`` is satisfied. | |
86 | ||
87 | Any argument that is not a matcher is implicitly wrapped in an | |
88 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
89 | equality. | |
90 | ||
91 | """ | |
92 | ||
93 | matchers = [] | |
94 | for item in items: | |
95 | matchers.append(wrap_matcher(item)) | |
96 | return IsSequenceContainingInAnyOrder(matchers) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.core.base_matcher import BaseMatcher | |
5 | from hamcrest.core.helpers.hasmethod import hasmethod | |
6 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
7 | ||
8 | ||
9 | class MatchingInOrder(object): | |
10 | def __init__(self, matchers, mismatch_description): | |
11 | self.matchers = matchers | |
12 | self.mismatch_description = mismatch_description | |
13 | self.next_match_index = 0 | |
14 | ||
15 | def matches(self, item): | |
16 | return self.isnotsurplus(item) and self.ismatched(item) | |
17 | ||
18 | def isfinished(self): | |
19 | if self.next_match_index < len(self.matchers): | |
20 | if self.mismatch_description: | |
21 | self.mismatch_description.append_text('No item matched: ') \ | |
22 | .append_description_of(self.matchers[self.next_match_index]) | |
23 | return False | |
24 | return True | |
25 | ||
26 | def ismatched(self, item): | |
27 | matcher = self.matchers[self.next_match_index] | |
28 | if not matcher.matches(item): | |
29 | if self.mismatch_description: | |
30 | self.mismatch_description.append_text('item ' + str(self.next_match_index) + ': ') | |
31 | matcher.describe_mismatch(item, self.mismatch_description) | |
32 | return False | |
33 | self.next_match_index += 1 | |
34 | return True | |
35 | ||
36 | def isnotsurplus(self, item): | |
37 | if len(self.matchers) <= self.next_match_index: | |
38 | if self.mismatch_description: | |
39 | self.mismatch_description.append_text('Not matched: ') \ | |
40 | .append_description_of(item) | |
41 | return False | |
42 | return True | |
43 | ||
44 | ||
45 | class IsSequenceContainingInOrder(BaseMatcher): | |
46 | ||
47 | def __init__(self, matchers): | |
48 | self.matchers = matchers | |
49 | ||
50 | def matches(self, sequence, mismatch_description=None): | |
51 | try: | |
52 | matchsequence = MatchingInOrder(self.matchers, mismatch_description) | |
53 | for item in sequence: | |
54 | if not matchsequence.matches(item): | |
55 | return False | |
56 | return matchsequence.isfinished() | |
57 | except TypeError: | |
58 | if mismatch_description: | |
59 | super(IsSequenceContainingInOrder, self) \ | |
60 | .describe_mismatch(sequence, mismatch_description) | |
61 | return False | |
62 | ||
63 | def describe_mismatch(self, item, mismatch_description): | |
64 | self.matches(item, mismatch_description) | |
65 | ||
66 | def describe_to(self, description): | |
67 | description.append_text('a sequence containing ') \ | |
68 | .append_list('[', ', ', ']', self.matchers) | |
69 | ||
70 | ||
71 | def contains(*items): | |
72 | """Matches if sequence's elements satisfy a given list of matchers, in order. | |
73 | ||
74 | :param match1,...: A comma-separated list of matchers. | |
75 | ||
76 | This matcher iterates the evaluated sequence and a given list of matchers, | |
77 | seeing if each element satisfies its corresponding matcher. | |
78 | ||
79 | Any argument that is not a matcher is implicitly wrapped in an | |
80 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
81 | equality. | |
82 | ||
83 | """ | |
84 | matchers = [] | |
85 | for item in items: | |
86 | matchers.append(wrap_matcher(item)) | |
87 | return IsSequenceContainingInOrder(matchers) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.core.anyof import any_of | |
2 | from hamcrest.core.helpers.hasmethod import hasmethod | |
3 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
4 | ||
5 | __author__ = "Jon Reid" | |
6 | __copyright__ = "Copyright 2011 hamcrest.org" | |
7 | __license__ = "BSD, see License.txt" | |
8 | ||
9 | ||
10 | class IsSequenceOnlyContaining(BaseMatcher): | |
11 | ||
12 | def __init__(self, matcher): | |
13 | self.matcher = matcher | |
14 | ||
15 | def _matches(self, sequence): | |
16 | try: | |
17 | sequence = list(sequence) | |
18 | if len(sequence) == 0: | |
19 | return False | |
20 | for item in sequence: | |
21 | if not self.matcher.matches(item): | |
22 | return False | |
23 | return True | |
24 | except TypeError: | |
25 | return False | |
26 | ||
27 | def describe_to(self, description): | |
28 | description.append_text('a sequence containing items matching ') \ | |
29 | .append_description_of(self.matcher) | |
30 | ||
31 | ||
32 | def only_contains(*items): | |
33 | """Matches if each element of sequence satisfies any of the given matchers. | |
34 | ||
35 | :param match1,...: A comma-separated list of matchers. | |
36 | ||
37 | This matcher iterates the evaluated sequence, confirming whether each | |
38 | element satisfies any of the given matchers. | |
39 | ||
40 | Example:: | |
41 | ||
42 | only_contains(less_than(4)) | |
43 | ||
44 | will match ``[3,1,2]``. | |
45 | ||
46 | Any argument that is not a matcher is implicitly wrapped in an | |
47 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
48 | equality. | |
49 | ||
50 | """ | |
51 | matchers = [] | |
52 | for item in items: | |
53 | matchers.append(wrap_matcher(item)) | |
54 | return IsSequenceOnlyContaining(apply(any_of, matchers)) |
0 | """Utilities for integrating Hamcrest with other libraries.""" | |
1 | ||
2 | from match_equality import match_equality | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" |
0 | from hamcrest.core.string_description import tostring | |
1 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
2 | ||
3 | __author__ = "Chris Rose" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | __unittest = True | |
7 | ||
8 | ||
9 | class EqualityWrapper(object): | |
10 | ||
11 | def __init__(self, matcher): | |
12 | self.matcher = matcher | |
13 | ||
14 | def __eq__(self, object): | |
15 | return self.matcher.matches(object) | |
16 | ||
17 | def __str__(self): | |
18 | return repr(self) | |
19 | ||
20 | def __repr__(self): | |
21 | return tostring(self.matcher) | |
22 | ||
23 | ||
24 | def match_equality(matcher): | |
25 | """Wraps a matcher to define equality in terms of satisfying the matcher. | |
26 | ||
27 | ``match_equality`` allows Hamcrest matchers to be used in libraries that | |
28 | are not Hamcrest-aware. They might use the equality operator:: | |
29 | ||
30 | assert match_equality(matcher) == object | |
31 | ||
32 | Or they might provide a method that uses equality for its test:: | |
33 | ||
34 | library.method_that_tests_eq(match_equality(matcher)) | |
35 | ||
36 | One concrete example is integrating with the ``assert_called_with`` methods | |
37 | in Michael Foord's `mock <http://www.voidspace.org.uk/python/mock/>`_ | |
38 | library. | |
39 | ||
40 | """ | |
41 | return EqualityWrapper(wrap_matcher(matcher)) |
0 | """Matchers that perform numeric comparisons.""" | |
1 | ||
2 | from iscloseto import close_to | |
3 | from ordering_comparison import greater_than, greater_than_or_equal_to, less_than, less_than_or_equal_to | |
4 | ||
5 | __author__ = "Jon Reid" | |
6 | __copyright__ = "Copyright 2011 hamcrest.org" | |
7 | __license__ = "BSD, see License.txt" |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from math import fabs | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | def isnumeric(value): | |
9 | """Confirm that 'value' can be treated numerically; duck-test accordingly | |
10 | """ | |
11 | if isinstance(value, (int, float, complex, long)): | |
12 | return True | |
13 | ||
14 | try: | |
15 | _ = (fabs(value) + 0 - 0) * 1 | |
16 | return True | |
17 | except ArithmeticError: | |
18 | return True | |
19 | except: | |
20 | return False | |
21 | return False | |
22 | ||
23 | ||
24 | class IsCloseTo(BaseMatcher): | |
25 | ||
26 | def __init__(self, value, delta): | |
27 | if not isnumeric(value): | |
28 | raise TypeError('IsCloseTo value must be numeric') | |
29 | if not isnumeric(delta): | |
30 | raise TypeError('IsCloseTo delta must be numeric') | |
31 | ||
32 | self.value = value | |
33 | self.delta = delta | |
34 | ||
35 | def _matches(self, item): | |
36 | if not isnumeric(item): | |
37 | return False | |
38 | return fabs(item - self.value) <= self.delta | |
39 | ||
40 | def describe_mismatch(self, item, mismatch_description): | |
41 | if not isnumeric(item): | |
42 | super(IsCloseTo, self).describe_mismatch(item, mismatch_description) | |
43 | else: | |
44 | actual_delta = fabs(item - self.value) | |
45 | mismatch_description.append_description_of(item) \ | |
46 | .append_text(' differed by ') \ | |
47 | .append_description_of(actual_delta) | |
48 | ||
49 | def describe_to(self, description): | |
50 | description.append_text('a numeric value within ') \ | |
51 | .append_description_of(self.delta) \ | |
52 | .append_text(' of ') \ | |
53 | .append_description_of(self.value) | |
54 | ||
55 | ||
56 | def close_to(value, delta): | |
57 | """Matches if object is a number close to a given value, within a given | |
58 | delta. | |
59 | ||
60 | :param value: The value to compare against as the expected value. | |
61 | :param delta: The maximum delta between the values for which the numbers | |
62 | are considered close. | |
63 | ||
64 | This matcher compares the evaluated object against ``value`` to see if the | |
65 | difference is within a positive ``delta``. | |
66 | ||
67 | Example:: | |
68 | ||
69 | close_to(3.0, 0.25) | |
70 | ||
71 | """ | |
72 | return IsCloseTo(value, delta) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | import operator | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | class OrderingComparison(BaseMatcher): | |
9 | ||
10 | def __init__(self, value, comparison_function, comparison_description): | |
11 | self.value = value | |
12 | self.comparison_function = comparison_function | |
13 | self.comparison_description = comparison_description | |
14 | ||
15 | def _matches(self, item): | |
16 | return self.comparison_function(item, self.value) | |
17 | ||
18 | def describe_to(self, description): | |
19 | description.append_text('a value ') \ | |
20 | .append_text(self.comparison_description) \ | |
21 | .append_text(' ') \ | |
22 | .append_description_of(self.value) | |
23 | ||
24 | ||
25 | def greater_than(value): | |
26 | """Matches if object is greater than a given value. | |
27 | ||
28 | :param value: The value to compare against. | |
29 | ||
30 | """ | |
31 | return OrderingComparison(value, operator.gt, 'greater than') | |
32 | ||
33 | ||
34 | def greater_than_or_equal_to(value): | |
35 | """Matches if object is greater than or equal to a given value. | |
36 | ||
37 | :param value: The value to compare against. | |
38 | ||
39 | """ | |
40 | return OrderingComparison(value, operator.ge, 'greater than or equal to') | |
41 | ||
42 | ||
43 | def less_than(value): | |
44 | """Matches if object is less than a given value. | |
45 | ||
46 | :param value: The value to compare against. | |
47 | ||
48 | """ | |
49 | return OrderingComparison(value, operator.lt, 'less than') | |
50 | ||
51 | ||
52 | def less_than_or_equal_to(value): | |
53 | """Matches if object is less than or equal to a given value. | |
54 | ||
55 | :param value: The value to compare against. | |
56 | ||
57 | """ | |
58 | return OrderingComparison(value, operator.le, 'less than or equal to') |
0 | """Matchers that inspect objects and classes.""" | |
1 | ||
2 | from haslength import has_length | |
3 | from hasproperty import has_property, has_properties | |
4 | from hasstring import has_string | |
5 | ||
6 | __author__ = "Jon Reid" | |
7 | __copyright__ = "Copyright 2011 hamcrest.org" | |
8 | __license__ = "BSD, see License.txt" |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
3 | ||
4 | __author__ = "Jon Reid" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | class HasLength(BaseMatcher): | |
10 | ||
11 | def __init__(self, len_matcher): | |
12 | self.len_matcher = len_matcher | |
13 | ||
14 | def _matches(self, item): | |
15 | if not hasmethod(item, '__len__'): | |
16 | return False | |
17 | return self.len_matcher.matches(len(item)) | |
18 | ||
19 | def describe_mismatch(self, item, mismatch_description): | |
20 | super(HasLength, self).describe_mismatch(item, mismatch_description) | |
21 | if hasmethod(item, '__len__'): | |
22 | mismatch_description.append_text(' with length of ') \ | |
23 | .append_description_of(len(item)) | |
24 | ||
25 | def describe_to(self, description): | |
26 | description.append_text('an object with length of ') \ | |
27 | .append_description_of(self.len_matcher) | |
28 | ||
29 | ||
30 | def has_length(match): | |
31 | """Matches if ``len(item)`` satisfies a given matcher. | |
32 | ||
33 | :param match: The matcher to satisfy, or an expected value for | |
34 | :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
35 | ||
36 | This matcher invokes the :py:func:`len` function on the evaluated object to | |
37 | get its length, passing the result to a given matcher for evaluation. | |
38 | ||
39 | If the ``match`` argument is not a matcher, it is implicitly wrapped in an | |
40 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
41 | :equality. | |
42 | ||
43 | Examples:: | |
44 | ||
45 | has_length(greater_than(6)) | |
46 | has_length(5) | |
47 | ||
48 | """ | |
49 | return HasLength(wrap_matcher(match)) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core import anything | |
2 | from hamcrest.core.core.allof import all_of | |
3 | from hamcrest.core.string_description import StringDescription | |
4 | from hamcrest.core.helpers.hasmethod import hasmethod | |
5 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher as wrap_shortcut | |
6 | ||
7 | __author__ = "Chris Rose" | |
8 | __copyright__ = "Copyright 2011 hamcrest.org" | |
9 | __license__ = "BSD, see License.txt" | |
10 | ||
11 | ||
12 | class IsObjectWithProperty(BaseMatcher): | |
13 | ||
14 | def __init__(self, property_name, value_matcher): | |
15 | self.property_name = property_name | |
16 | self.value_matcher = value_matcher | |
17 | ||
18 | def _matches(self, o): | |
19 | if o is None: | |
20 | return False | |
21 | ||
22 | if not hasattr(o, self.property_name): | |
23 | return False | |
24 | ||
25 | value = getattr(o, self.property_name) | |
26 | return self.value_matcher.matches(value) | |
27 | ||
28 | def describe_to(self, description): | |
29 | description.append_text("an object with a property '") \ | |
30 | .append_text(self.property_name) \ | |
31 | .append_text("' matching ") \ | |
32 | .append_description_of(self.value_matcher) | |
33 | ||
34 | def describe_mismatch(self, item, mismatch_description): | |
35 | if item is None: | |
36 | mismatch_description.append_text('was None') | |
37 | return | |
38 | ||
39 | if not hasattr(item, self.property_name): | |
40 | mismatch_description.append_value(item) \ | |
41 | .append_text(' did not have the ') \ | |
42 | .append_value(self.property_name) \ | |
43 | .append_text(' property') | |
44 | return | |
45 | ||
46 | mismatch_description.append_text('property ').append_value(self.property_name).append_text(' ') | |
47 | value = getattr(item, self.property_name) | |
48 | self.value_matcher.describe_mismatch(value, mismatch_description) | |
49 | ||
50 | def __str__(self): | |
51 | d = StringDescription() | |
52 | self.describe_to(d) | |
53 | return str(d) | |
54 | ||
55 | ||
56 | def has_property(name, match=None): | |
57 | """Matches if object has a property with a given name whose value satisfies | |
58 | a given matcher. | |
59 | ||
60 | :param name: The name of the property. | |
61 | :param match: Optional matcher to satisfy. | |
62 | ||
63 | This matcher determines if the evaluated object has a property with a given | |
64 | name. If no such property is found, ``has_property`` is not satisfied. | |
65 | ||
66 | If the property is found, its value is passed to a given matcher for | |
67 | evaluation. If the ``match`` argument is not a matcher, it is implicitly | |
68 | wrapped in an :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to | |
69 | check for equality. | |
70 | ||
71 | If the ``match`` argument is not provided, the | |
72 | :py:func:`~hamcrest.core.core.isanything.anything` matcher is used so that | |
73 | ``has_property`` is satisfied if a matching property is found. | |
74 | ||
75 | Examples:: | |
76 | ||
77 | has_property('name', starts_with('J')) | |
78 | has_property('name', 'Jon') | |
79 | has_property('name') | |
80 | ||
81 | """ | |
82 | ||
83 | if match is None: | |
84 | match = anything() | |
85 | ||
86 | return IsObjectWithProperty(name, wrap_shortcut(match)) | |
87 | ||
88 | ||
89 | def has_properties(*keys_valuematchers, **kv_args): | |
90 | """Matches if an object has properties satisfying all of a dictionary | |
91 | of string property names and corresponding value matchers. | |
92 | ||
93 | :param matcher_dict: A dictionary mapping keys to associated value matchers, | |
94 | or to expected values for | |
95 | :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
96 | ||
97 | Note that the keys must be actual keys, not matchers. Any value argument | |
98 | that is not a matcher is implicitly wrapped in an | |
99 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
100 | equality. | |
101 | ||
102 | Examples:: | |
103 | ||
104 | has_properties({'foo':equal_to(1), 'bar':equal_to(2)}) | |
105 | has_properties({'foo':1, 'bar':2}) | |
106 | ||
107 | ``has_properties`` also accepts a list of keyword arguments: | |
108 | ||
109 | .. function:: has_properties(keyword1=value_matcher1[, keyword2=value_matcher2[, ...]]) | |
110 | ||
111 | :param keyword1: A keyword to look up. | |
112 | :param valueMatcher1: The matcher to satisfy for the value, or an expected | |
113 | value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
114 | ||
115 | Examples:: | |
116 | ||
117 | has_properties(foo=equal_to(1), bar=equal_to(2)) | |
118 | has_properties(foo=1, bar=2) | |
119 | ||
120 | Finally, ``has_properties`` also accepts a list of alternating keys and their | |
121 | value matchers: | |
122 | ||
123 | .. function:: has_properties(key1, value_matcher1[, ...]) | |
124 | ||
125 | :param key1: A key (not a matcher) to look up. | |
126 | :param valueMatcher1: The matcher to satisfy for the value, or an expected | |
127 | value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
128 | ||
129 | Examples:: | |
130 | ||
131 | has_properties('foo', equal_to(1), 'bar', equal_to(2)) | |
132 | has_properties('foo', 1, 'bar', 2) | |
133 | ||
134 | """ | |
135 | if len(keys_valuematchers) == 1: | |
136 | try: | |
137 | base_dict = keys_valuematchers[0].copy() | |
138 | for key in base_dict: | |
139 | base_dict[key] = wrap_shortcut(base_dict[key]) | |
140 | except AttributeError: | |
141 | raise ValueError('single-argument calls to has_properties must pass a dict as the argument') | |
142 | else: | |
143 | if len(keys_valuematchers) % 2: | |
144 | raise ValueError('has_properties requires key-value pairs') | |
145 | base_dict = {} | |
146 | for index in range(int(len(keys_valuematchers) / 2)): | |
147 | base_dict[keys_valuematchers[2 * index]] = wrap_shortcut(keys_valuematchers[2 * index + 1]) | |
148 | ||
149 | for key, value in kv_args.items(): | |
150 | base_dict[key] = wrap_shortcut(value) | |
151 | ||
152 | return all_of(*[has_property(property_name, property_value_matcher) for \ | |
153 | property_name, property_value_matcher in base_dict.items()]) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.wrap_matcher import wrap_matcher | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | class HasString(BaseMatcher): | |
9 | ||
10 | def __init__(self, str_matcher): | |
11 | self.str_matcher = str_matcher | |
12 | ||
13 | def _matches(self, item): | |
14 | return self.str_matcher.matches(str(item)) | |
15 | ||
16 | def describe_to(self, description): | |
17 | description.append_text('an object with str ') \ | |
18 | .append_description_of(self.str_matcher) | |
19 | ||
20 | ||
21 | def has_string(match): | |
22 | """Matches if ``str(item)`` satisfies a given matcher. | |
23 | ||
24 | :param match: The matcher to satisfy, or an expected value for | |
25 | :py:func:`~hamcrest.core.core.isequal.equal_to` matching. | |
26 | ||
27 | This matcher invokes the :py:func:`str` function on the evaluated object to | |
28 | get its length, passing the result to a given matcher for evaluation. If | |
29 | the ``match`` argument is not a matcher, it is implicitly wrapped in an | |
30 | :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for | |
31 | equality. | |
32 | ||
33 | Examples:: | |
34 | ||
35 | has_string(starts_with('foo')) | |
36 | has_string('bar') | |
37 | ||
38 | """ | |
39 | return HasString(wrap_matcher(match)) |
0 | """Matchers that perform text comparisons.""" | |
1 | ||
2 | from isequal_ignoring_case import equal_to_ignoring_case | |
3 | from isequal_ignoring_whitespace import equal_to_ignoring_whitespace | |
4 | from stringcontains import contains_string | |
5 | from stringendswith import ends_with | |
6 | from stringstartswith import starts_with | |
7 | from stringmatches import matches_regexp | |
8 | from stringcontainsinorder import string_contains_in_order | |
9 | ||
10 | __author__ = "Jon Reid" | |
11 | __copyright__ = "Copyright 2011 hamcrest.org" | |
12 | __license__ = "BSD, see License.txt" |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | class IsEqualIgnoringCase(BaseMatcher): | |
8 | ||
9 | def __init__(self, string): | |
10 | if not isinstance(string, basestring): | |
11 | raise TypeError('IsEqualIgnoringCase requires string') | |
12 | self.original_string = string | |
13 | self.lowered_string = string.lower() | |
14 | ||
15 | def _matches(self, item): | |
16 | if not isinstance(item, basestring): | |
17 | return False | |
18 | return self.lowered_string == item.lower() | |
19 | ||
20 | def describe_to(self, description): | |
21 | description.append_description_of(self.original_string) \ | |
22 | .append_text(' ignoring case') | |
23 | ||
24 | ||
25 | def equal_to_ignoring_case(string): | |
26 | """Matches if object is a string equal to a given string, ignoring case | |
27 | differences. | |
28 | ||
29 | :param string: The string to compare against as the expected value. | |
30 | ||
31 | This matcher first checks whether the evaluated object is a string. If so, | |
32 | it compares it with ``string``, ignoring differences of case. | |
33 | ||
34 | Example:: | |
35 | ||
36 | equal_to_ignoring_case("hello world") | |
37 | ||
38 | will match "heLLo WorlD". | |
39 | ||
40 | """ | |
41 | return IsEqualIgnoringCase(string) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | def stripspace(string): | |
8 | result = '' | |
9 | last_was_space = True | |
10 | for character in string: | |
11 | if character.isspace(): | |
12 | if not last_was_space: | |
13 | result += ' ' | |
14 | last_was_space = True | |
15 | else: | |
16 | result += character | |
17 | last_was_space = False | |
18 | return result.strip() | |
19 | ||
20 | ||
21 | class IsEqualIgnoringWhiteSpace(BaseMatcher): | |
22 | ||
23 | def __init__(self, string): | |
24 | if not isinstance(string, basestring): | |
25 | raise TypeError('IsEqualIgnoringWhiteSpace requires string') | |
26 | self.original_string = string | |
27 | self.stripped_string = stripspace(string) | |
28 | ||
29 | def _matches(self, item): | |
30 | if not isinstance(item, basestring): | |
31 | return False | |
32 | return self.stripped_string == stripspace(item) | |
33 | ||
34 | def describe_to(self, description): | |
35 | description.append_description_of(self.original_string) \ | |
36 | .append_text(' ignoring whitespace') | |
37 | ||
38 | ||
39 | def equal_to_ignoring_whitespace(string): | |
40 | """Matches if object is a string equal to a given string, ignoring | |
41 | differences in whitespace. | |
42 | ||
43 | :param string: The string to compare against as the expected value. | |
44 | ||
45 | This matcher first checks whether the evaluated object is a string. If so, | |
46 | it compares it with ``string``, ignoring differences in runs of whitespace. | |
47 | ||
48 | Example:: | |
49 | ||
50 | equal_to_ignoring_whitespace("hello world") | |
51 | ||
52 | will match ``"hello world"``. | |
53 | ||
54 | """ | |
55 | return IsEqualIgnoringWhiteSpace(string) |
0 | from hamcrest.library.text.substringmatcher import SubstringMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | class StringContains(SubstringMatcher): | |
9 | ||
10 | def __init__(self, substring): | |
11 | super(StringContains, self).__init__(substring) | |
12 | ||
13 | def _matches(self, item): | |
14 | if not hasmethod(item, 'find'): | |
15 | return False | |
16 | return item.find(self.substring) >= 0 | |
17 | ||
18 | def relationship(self): | |
19 | return 'containing' | |
20 | ||
21 | ||
22 | def contains_string(substring): | |
23 | """Matches if object is a string containing a given string. | |
24 | ||
25 | :param string: The string to search for. | |
26 | ||
27 | This matcher first checks whether the evaluated object is a string. If so, | |
28 | it checks whether it contains ``string``. | |
29 | ||
30 | Example:: | |
31 | ||
32 | contains_string("def") | |
33 | ||
34 | will match "abcdefg". | |
35 | ||
36 | """ | |
37 | return StringContains(substring) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | ||
3 | __author__ = "Romilly Cocking" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | class StringContainsInOrder(BaseMatcher): | |
9 | ||
10 | def __init__(self, *substrings): | |
11 | for substring in substrings: | |
12 | if not isinstance(substring, basestring): | |
13 | raise TypeError(self.__class__.__name__ | |
14 | + ' requires string arguments') | |
15 | self.substrings = substrings | |
16 | ||
17 | def _matches(self, item): | |
18 | if not hasmethod(item, 'find'): | |
19 | return False | |
20 | from_index = 0 | |
21 | for substring in self.substrings: | |
22 | from_index = item.find(substring, from_index) | |
23 | if from_index == -1: | |
24 | return False | |
25 | return True | |
26 | ||
27 | def describe_to(self, description): | |
28 | description.append_list('a string containing ', ', ', ' in order', | |
29 | self.substrings) | |
30 | ||
31 | ||
32 | def string_contains_in_order(*substrings): | |
33 | """Matches if object is a string containing a given list of substrings in | |
34 | relative order. | |
35 | ||
36 | :param string1,...: A comma-separated list of strings. | |
37 | ||
38 | This matcher first checks whether the evaluated object is a string. If so, | |
39 | it checks whether it contains a given list of strings, in relative order to | |
40 | each other. The searches are performed starting from the beginning of the | |
41 | evaluated string. | |
42 | ||
43 | Example:: | |
44 | ||
45 | string_contains_in_order("bc", "fg", "jkl") | |
46 | ||
47 | will match "abcdefghijklm". | |
48 | ||
49 | """ | |
50 | return StringContainsInOrder(*substrings) |
0 | from hamcrest.library.text.substringmatcher import SubstringMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | ||
3 | __author__ = "Jon Reid" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | class StringEndsWith(SubstringMatcher): | |
9 | ||
10 | def __init__(self, substring): | |
11 | super(StringEndsWith, self).__init__(substring) | |
12 | ||
13 | def _matches(self, item): | |
14 | if not hasmethod(item, 'endswith'): | |
15 | return False | |
16 | return item.endswith(self.substring) | |
17 | ||
18 | def relationship(self): | |
19 | return 'ending with' | |
20 | ||
21 | ||
22 | def ends_with(string): | |
23 | """Matches if object is a string ending with a given string. | |
24 | ||
25 | :param string: The string to search for. | |
26 | ||
27 | This matcher first checks whether the evaluated object is a string. If so, | |
28 | it checks if ``string`` matches the ending characters of the evaluated | |
29 | object. | |
30 | ||
31 | Example:: | |
32 | ||
33 | ends_with("bar") | |
34 | ||
35 | will match "foobar". | |
36 | ||
37 | """ | |
38 | return StringEndsWith(string) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | from hamcrest.core.helpers.hasmethod import hasmethod | |
2 | import re | |
3 | ||
4 | __author__ = "Chris Rose" | |
5 | __copyright__ = "Copyright 2011 hamcrest.org" | |
6 | __license__ = "BSD, see License.txt" | |
7 | ||
8 | ||
9 | class StringMatchesPattern(BaseMatcher): | |
10 | ||
11 | def __init__(self, pattern): | |
12 | self.pattern = pattern | |
13 | ||
14 | def describe_to(self, description): | |
15 | description.append_text("a string matching '") \ | |
16 | .append_text(self.pattern.pattern) \ | |
17 | .append_text("'") | |
18 | ||
19 | def _matches(self, item): | |
20 | return self.pattern.search(item) is not None | |
21 | ||
22 | ||
23 | def matches_regexp(pattern): | |
24 | """Matches if object is a string containing a match for a given regular | |
25 | expression. | |
26 | ||
27 | :param pattern: The regular expression to search for. | |
28 | ||
29 | This matcher first checks whether the evaluated object is a string. If so, | |
30 | it checks if the regular expression ``pattern`` matches anywhere within the | |
31 | evaluated object. | |
32 | ||
33 | """ | |
34 | if isinstance(pattern, basestring): | |
35 | pattern = re.compile(pattern) | |
36 | ||
37 | return StringMatchesPattern(pattern) |
0 | __author__ = "Jon Reid" | |
1 | __copyright__ = "Copyright 2011 hamcrest.org" | |
2 | __license__ = "BSD, see License.txt" | |
3 | ||
4 | from hamcrest.library.text.substringmatcher import SubstringMatcher | |
5 | from hamcrest.core.helpers.hasmethod import hasmethod | |
6 | ||
7 | ||
8 | class StringStartsWith(SubstringMatcher): | |
9 | ||
10 | def __init__(self, substring): | |
11 | super(StringStartsWith, self).__init__(substring) | |
12 | ||
13 | def _matches(self, item): | |
14 | if not hasmethod(item, 'startswith'): | |
15 | return False | |
16 | return item.startswith(self.substring) | |
17 | ||
18 | def relationship(self): | |
19 | return 'starting with' | |
20 | ||
21 | ||
22 | def starts_with(substring): | |
23 | """Matches if object is a string starting with a given string. | |
24 | ||
25 | :param string: The string to search for. | |
26 | ||
27 | This matcher first checks whether the evaluated object is a string. If so, | |
28 | it checks if ``string`` matches the beginning characters of the evaluated | |
29 | object. | |
30 | ||
31 | Example:: | |
32 | ||
33 | starts_with("foo") | |
34 | ||
35 | will match "foobar". | |
36 | ||
37 | """ | |
38 | return StringStartsWith(substring) |
0 | from hamcrest.core.base_matcher import BaseMatcher | |
1 | ||
2 | __author__ = "Jon Reid" | |
3 | __copyright__ = "Copyright 2011 hamcrest.org" | |
4 | __license__ = "BSD, see License.txt" | |
5 | ||
6 | ||
7 | class SubstringMatcher(BaseMatcher): | |
8 | ||
9 | def __init__(self, substring): | |
10 | if not isinstance(substring, basestring): | |
11 | raise TypeError(self.__class__.__name__ + ' requires string') | |
12 | self.substring = substring | |
13 | ||
14 | def describe_to(self, description): | |
15 | description.append_text('a string ') \ | |
16 | .append_text(self.relationship()) \ | |
17 | .append_text(' ') \ | |
18 | .append_description_of(self.substring) |