From 6028b8046cdc643b453cf2ae5978fe02b02c9c6a Mon Sep 17 00:00:00 2001 From: Jonathan Lange Date: Sun, 31 Oct 2010 12:25:47 -0400 Subject: [PATCH] Implement KeysEqual matcher. --- testtools/matchers.py | 28 ++++++++++++++++++++++++++++ testtools/tests/test_matchers.py | 26 ++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/testtools/matchers.py b/testtools/matchers.py index 6208545..448d28e 100644 --- a/testtools/matchers.py +++ b/testtools/matchers.py @@ -342,6 +342,34 @@ class StartsWith(Matcher): return None +class KeysEqual(Matcher): + """Checks whether a dict has particular keys.""" + + def __init__(self, *expected): + """Create a `KeysEqual` Matcher. + + :param *expected: The keys the dict is expected to have. If a dict, + then we use the keys of that dict, if a collection, we assume it + is a collection of expected keys. + """ + try: + self.expected = expected.keys() + except AttributeError: + self.expected = list(expected) + + def __str__(self): + return "KeysEqual(%s)" % ', '.join(map(repr, self.expected)) + + def match(self, matchee): + expected = sorted(self.expected) + matched = Equals(expected).match(sorted(matchee.keys())) + if matched: + return AnnotatedMismatch( + 'Keys not equal', + _BinaryMismatch(expected, 'does not match', matchee)) + return None + + class Annotate(object): """Annotates a matcher with a descriptive string. diff --git a/testtools/tests/test_matchers.py b/testtools/tests/test_matchers.py index b8406e7..270fa64 100644 --- a/testtools/tests/test_matchers.py +++ b/testtools/tests/test_matchers.py @@ -13,6 +13,7 @@ from testtools.matchers import ( Equals, DocTestMatches, DoesNotStartWith, + KeysEqual, Is, LessThan, MatchesAny, @@ -211,6 +212,31 @@ class TestMatchesAllInterface(TestCase, TestMatchersInterface): 1, MatchesAll(NotEquals(1), NotEquals(2)))] +class TestKeysEqual(TestCase, TestMatchersInterface): + + matches_matcher = KeysEqual('foo', 'bar') + matches_matches = [ + {'foo': 0, 'bar': 1}, + ] + matches_mismatches = [ + {}, + {'foo': 0}, + {'bar': 1}, + {'foo': 0, 'bar': 1, 'baz': 2}, + {'a': None, 'b': None, 'c': None}, + ] + + str_examples = [ + ("KeysEqual('foo', 'bar')", KeysEqual('foo', 'bar')), + ] + + describe_examples = [ + ("['bar', 'foo'] does not match {'baz': 2, 'foo': 0, 'bar': 1}: " + "Keys not equal", + {'foo': 0, 'bar': 1, 'baz': 2}, KeysEqual('foo', 'bar')), + ] + + class TestAnnotate(TestCase, TestMatchersInterface): matches_matcher = Annotate("foo", Equals(1))