0
# Matchers System
1
2
Sophisticated assertion system with 46 matchers for complex comparisons and validations. Matchers provide a composable, expressive way to specify test expectations beyond simple equality checks.
3
4
## Capabilities
5
6
### Core Matcher Infrastructure
7
8
Base classes and exceptions for the matcher system.
9
10
```python { .api }
11
class Matcher:
12
"""
13
Abstract base class for all matchers.
14
15
Defines the protocol that all matchers must implement
16
for composable assertion logic.
17
"""
18
19
def match(self, other):
20
"""
21
Try to match other with this matcher.
22
23
Args:
24
other: Object to match against
25
26
Returns:
27
None if match succeeds, Mismatch object if it fails
28
"""
29
30
def describe(self):
31
"""
32
Describe what this matcher matches.
33
34
Returns:
35
str: Human-readable description
36
"""
37
38
class Mismatch:
39
"""
40
Represents a matcher mismatch with detailed description.
41
"""
42
43
def __init__(self, description):
44
"""
45
Create a mismatch.
46
47
Args:
48
description (str): Description of the mismatch
49
"""
50
51
def describe(self):
52
"""
53
Get the mismatch description.
54
55
Returns:
56
str: Detailed mismatch information
57
"""
58
59
class MismatchError(Exception):
60
"""
61
Exception raised when matcher assertion fails.
62
"""
63
```
64
65
### Basic Value Matchers
66
67
Fundamental matchers for comparing values, strings, and basic data types.
68
69
```python { .api }
70
def Equals(expected):
71
"""
72
Match if objects are equal using == operator.
73
74
Args:
75
expected: Expected value
76
77
Returns:
78
Matcher: Equality matcher
79
"""
80
81
def NotEquals(expected):
82
"""
83
Match if objects are not equal using != operator.
84
85
Args:
86
expected: Value that should not match
87
88
Returns:
89
Matcher: Inequality matcher
90
"""
91
92
def Is(expected):
93
"""
94
Match using identity comparison (is operator).
95
96
Args:
97
expected: Expected object identity
98
99
Returns:
100
Matcher: Identity matcher
101
"""
102
103
def IsInstance(class_or_tuple):
104
"""
105
Match if object is instance of specified type(s).
106
107
Args:
108
class_or_tuple: Class or tuple of classes
109
110
Returns:
111
Matcher: Instance type matcher
112
"""
113
114
def Contains(contained):
115
"""
116
Match if object contains specified item.
117
118
Args:
119
contained: Item that should be contained
120
121
Returns:
122
Matcher: Containment matcher
123
"""
124
125
def StartsWith(expected):
126
"""
127
Match if string starts with specified substring.
128
129
Args:
130
expected (str): Expected prefix
131
132
Returns:
133
Matcher: String prefix matcher
134
"""
135
136
def EndsWith(expected):
137
"""
138
Match if string ends with specified substring.
139
140
Args:
141
expected (str): Expected suffix
142
143
Returns:
144
Matcher: String suffix matcher
145
"""
146
147
def MatchesRegex(pattern, flags=0):
148
"""
149
Match string against regular expression pattern.
150
151
Args:
152
pattern (str): Regular expression pattern
153
flags (int): Regex flags (re.IGNORECASE, etc.)
154
155
Returns:
156
Matcher: Regular expression matcher
157
"""
158
159
def GreaterThan(expected):
160
"""
161
Match if value is greater than expected value.
162
163
Args:
164
expected: Value to compare against
165
166
Returns:
167
Matcher: Greater than comparison matcher
168
"""
169
170
def LessThan(expected):
171
"""
172
Match if value is less than expected value.
173
174
Args:
175
expected: Value to compare against
176
177
Returns:
178
Matcher: Less than comparison matcher
179
"""
180
181
def HasLength(expected):
182
"""
183
Match if object has expected length.
184
185
Args:
186
expected (int): Expected length
187
188
Returns:
189
Matcher: Length matcher
190
"""
191
192
def SameMembers(expected):
193
"""
194
Match if iterables have same members regardless of order.
195
196
Args:
197
expected: Iterable with expected members
198
199
Returns:
200
Matcher: Set membership matcher
201
"""
202
```
203
204
### Data Structure Matchers
205
206
Matchers for complex data structures like lists, dictionaries, and objects.
207
208
```python { .api }
209
def MatchesDict(d):
210
"""
211
Match dictionary structure with value matchers.
212
213
Args:
214
d (dict): Dictionary mapping keys to matchers
215
216
Returns:
217
Matcher: Dictionary structure matcher
218
"""
219
220
def ContainsDict(d):
221
"""
222
Match if dictionary contains expected key-value pairs.
223
224
Args:
225
d (dict): Expected key-value pairs
226
227
Returns:
228
Matcher: Dictionary containment matcher
229
"""
230
231
def ContainedByDict(d):
232
"""
233
Match if dictionary is contained within another dictionary.
234
235
Args:
236
d (dict): Container dictionary
237
238
Returns:
239
Matcher: Dictionary containment checker
240
"""
241
242
def KeysEqual(expected):
243
"""
244
Match if dictionary keys equal expected set of keys.
245
246
Args:
247
expected: Expected keys (iterable)
248
249
Returns:
250
Matcher: Dictionary keys matcher
251
"""
252
253
def MatchesListwise(matchers):
254
"""
255
Match lists element by element with corresponding matchers.
256
257
Args:
258
matchers (list): List of matchers for each element
259
260
Returns:
261
Matcher: Element-wise list matcher
262
"""
263
264
def MatchesSetwise(matchers):
265
"""
266
Match sets ignoring order with corresponding matchers.
267
268
Args:
269
matchers: Iterable of matchers
270
271
Returns:
272
Matcher: Unordered set matcher
273
"""
274
275
def MatchesStructure(**kwargs):
276
"""
277
Match object attributes against specified matchers.
278
279
Args:
280
**kwargs: Attribute names mapped to matchers
281
282
Returns:
283
Matcher: Object structure matcher
284
"""
285
286
def ContainsAll(items):
287
"""
288
Match if object contains all specified items.
289
290
Args:
291
items: Iterable of items that should be contained
292
293
Returns:
294
Matcher: Multiple containment matcher
295
"""
296
```
297
298
### Exception Matchers
299
300
Matchers for testing exception behavior and error conditions.
301
302
```python { .api }
303
def Raises(exception_matcher):
304
"""
305
Match if callable raises expected exception.
306
307
Args:
308
exception_matcher: Matcher for the expected exception
309
310
Returns:
311
Matcher: Exception raising matcher
312
"""
313
314
def MatchesException(exception, value_re=None):
315
"""
316
Match exception instances or types with optional attribute matching.
317
318
Args:
319
exception: Exception class or instance to match
320
value_re (str): Optional regex for exception message
321
322
Returns:
323
Matcher: Exception matcher
324
"""
325
326
def raises(exception_matcher):
327
"""
328
Context manager version of Raises matcher.
329
330
Args:
331
exception_matcher: Matcher for expected exception
332
333
Returns:
334
Context manager for exception testing
335
"""
336
```
337
338
### Filesystem Matchers
339
340
Matchers for filesystem operations and file content verification.
341
342
```python { .api }
343
def PathExists():
344
"""
345
Match if filesystem path exists.
346
347
Returns:
348
Matcher: Path existence matcher
349
"""
350
351
def FileExists():
352
"""
353
Match if path exists and is a regular file.
354
355
Returns:
356
Matcher: File existence matcher
357
"""
358
359
def DirExists():
360
"""
361
Match if path exists and is a directory.
362
363
Returns:
364
Matcher: Directory existence matcher
365
"""
366
367
def FileContains(matcher):
368
"""
369
Match file contents against expected content.
370
371
Args:
372
matcher: Matcher for file contents
373
374
Returns:
375
Matcher: File content matcher
376
"""
377
378
def DirContains(filenames):
379
"""
380
Match if directory contains specified files.
381
382
Args:
383
filenames: Expected filenames (iterable)
384
385
Returns:
386
Matcher: Directory content matcher
387
"""
388
389
def HasPermissions(expected):
390
"""
391
Match file permissions against expected permissions.
392
393
Args:
394
expected: Expected permission bits
395
396
Returns:
397
Matcher: File permissions matcher
398
"""
399
400
def SamePath(expected):
401
"""
402
Match if paths refer to the same filesystem location.
403
404
Args:
405
expected: Expected path
406
407
Returns:
408
Matcher: Path equivalence matcher
409
"""
410
411
def TarballContains(filenames):
412
"""
413
Match contents of tarball archives.
414
415
Args:
416
filenames: Expected filenames in tarball
417
418
Returns:
419
Matcher: Tarball content matcher
420
"""
421
```
422
423
### Higher-Order Matchers
424
425
Matcher combinators for building complex matching logic.
426
427
```python { .api }
428
def MatchesAll(*matchers):
429
"""
430
Match against multiple matchers (logical AND).
431
432
Args:
433
*matchers: Matchers that must all succeed
434
435
Returns:
436
Matcher: Conjunction matcher
437
"""
438
439
def MatchesAny(*matchers):
440
"""
441
Match against any of multiple matchers (logical OR).
442
443
Args:
444
*matchers: Matchers, at least one must succeed
445
446
Returns:
447
Matcher: Disjunction matcher
448
"""
449
450
def Not(matcher):
451
"""
452
Negate/invert the result of another matcher.
453
454
Args:
455
matcher: Matcher to negate
456
457
Returns:
458
Matcher: Negated matcher
459
"""
460
461
def AllMatch(matcher):
462
"""
463
Match if all items in iterable match the given matcher.
464
465
Args:
466
matcher: Matcher to apply to each item
467
468
Returns:
469
Matcher: Universal quantification matcher
470
"""
471
472
def AnyMatch(matcher):
473
"""
474
Match if any item in iterable matches the given matcher.
475
476
Args:
477
matcher: Matcher to apply to items
478
479
Returns:
480
Matcher: Existential quantification matcher
481
"""
482
483
def AfterPreprocessing(preprocessor, matcher):
484
"""
485
Apply preprocessing function before matching.
486
487
Args:
488
preprocessor: Function to transform input
489
matcher: Matcher to apply to transformed data
490
491
Returns:
492
Matcher: Preprocessing matcher
493
"""
494
495
def Annotate(annotation, matcher):
496
"""
497
Add annotation/description to existing matcher.
498
499
Args:
500
annotation (str): Additional description
501
matcher: Matcher to annotate
502
503
Returns:
504
Matcher: Annotated matcher
505
"""
506
507
def MatchesPredicate(predicate, message=None):
508
"""
509
Match using predicate function.
510
511
Args:
512
predicate: Function returning bool
513
message (str): Optional description
514
515
Returns:
516
Matcher: Predicate-based matcher
517
"""
518
519
def MatchesPredicateWithParams(predicate, message=None, **params):
520
"""
521
Match using predicate function with additional parameters.
522
523
Args:
524
predicate: Function accepting value and params
525
message (str): Optional description
526
**params: Additional parameters for predicate
527
528
Returns:
529
Matcher: Parameterized predicate matcher
530
"""
531
```
532
533
### Constant Matchers
534
535
Matchers with fixed behavior for testing and composition.
536
537
```python { .api }
538
def Always():
539
"""
540
Matcher that always succeeds (never fails).
541
542
Returns:
543
Matcher: Always-succeeding matcher
544
"""
545
546
def Never():
547
"""
548
Matcher that never succeeds (always fails).
549
550
Returns:
551
Matcher: Always-failing matcher
552
"""
553
```
554
555
### DocTest Integration
556
557
Matcher for integrating with Python's doctest module.
558
559
```python { .api }
560
def DocTestMatches(expected, flags=0):
561
"""
562
Match string against doctest expected output format.
563
564
Args:
565
expected (str): Expected doctest output
566
flags (int): Doctest option flags
567
568
Returns:
569
Matcher: DocTest output matcher
570
"""
571
```
572
573
### Warning System Matchers
574
575
Matchers for testing warning emissions and deprecation behavior.
576
577
```python { .api }
578
def Warnings(matchers):
579
"""
580
Match warnings emitted during code execution.
581
582
Args:
583
matchers: Matchers for expected warnings
584
585
Returns:
586
Matcher: Warning emission matcher
587
"""
588
589
def WarningMessage(category=None, message=None, filename=None, lineno=None):
590
"""
591
Match specific warning message details.
592
593
Args:
594
category: Warning category class
595
message: Warning message matcher
596
filename: Source filename matcher
597
lineno: Line number matcher
598
599
Returns:
600
Matcher: Warning message matcher
601
"""
602
603
def IsDeprecated():
604
"""
605
Match deprecated functionality warnings.
606
607
Returns:
608
Matcher: Deprecation warning matcher
609
"""
610
```
611
612
## Usage Examples
613
614
### Basic Matcher Usage
615
616
```python
617
import testtools
618
from testtools.matchers import *
619
620
class TestMatchers(testtools.TestCase):
621
622
def test_basic_matchers(self):
623
# String matchers
624
self.assertThat("Hello World", Contains("World"))
625
self.assertThat("test.py", EndsWith(".py"))
626
self.assertThat("function_name", MatchesRegex(r'\w+_\w+'))
627
628
# Numeric matchers
629
self.assertThat(42, GreaterThan(40))
630
self.assertThat([1, 2, 3], HasLength(3))
631
632
# Type matchers
633
self.assertThat([], IsInstance(list))
634
self.assertThat("test", Not(IsInstance(int)))
635
```
636
637
### Complex Data Structure Matching
638
639
```python
640
def test_complex_structures(self):
641
data = {
642
'users': [
643
{'name': 'Alice', 'age': 30},
644
{'name': 'Bob', 'age': 25}
645
],
646
'status': 'active',
647
'count': 2
648
}
649
650
# Match dictionary structure
651
self.assertThat(data, MatchesDict({
652
'users': HasLength(2),
653
'status': Equals('active'),
654
'count': GreaterThan(0)
655
}))
656
657
# Match list elements
658
self.assertThat(data['users'], MatchesListwise([
659
MatchesDict({'name': StartsWith('A'), 'age': GreaterThan(25)}),
660
MatchesDict({'name': StartsWith('B'), 'age': LessThan(30)})
661
]))
662
```
663
664
### Exception Testing
665
666
```python
667
def test_exceptions(self):
668
# Test specific exception
669
self.assertThat(
670
lambda: int('not_a_number'),
671
Raises(MatchesException(ValueError))
672
)
673
674
# Test exception message
675
with raises(MatchesException(ValueError, "invalid literal.*")):
676
int('not_a_number')
677
```
678
679
### Filesystem Testing
680
681
```python
682
def test_filesystem(self):
683
# Test file operations
684
self.assertThat('/etc/passwd', FileExists())
685
self.assertThat('/tmp', DirExists())
686
self.assertThat('config.txt', FileContains(Contains('version')))
687
```
688
689
### Combining Matchers
690
691
```python
692
def test_matcher_combinations(self):
693
# Logical combinations
694
self.assertThat(42, MatchesAll(
695
GreaterThan(40),
696
LessThan(50),
697
IsInstance(int)
698
))
699
700
# Check all list items
701
numbers = [2, 4, 6, 8]
702
self.assertThat(numbers, AllMatch(
703
MatchesAll(IsInstance(int), lambda x: x % 2 == 0)
704
))
705
706
# Preprocessing
707
self.assertThat(" trimmed ", AfterPreprocessing(
708
str.strip,
709
Equals("trimmed")
710
))
711
```