aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/PyHamcrest/src/hamcrest/library/collection/isdict_containingentries.py
blob: 5e6ec9b9057bc92bd08ef3d0fb6889e2885daf88 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
from hamcrest.core.base_matcher import BaseMatcher 
from hamcrest.core.helpers.hasmethod import hasmethod 
from hamcrest.core.helpers.wrap_matcher import wrap_matcher 
 
__author__ = "Jon Reid" 
__copyright__ = "Copyright 2011 hamcrest.org" 
__license__ = "BSD, see License.txt" 
 
 
class IsDictContainingEntries(BaseMatcher): 
 
    def __init__(self, value_matchers): 
        self.value_matchers = sorted(value_matchers.items()) 
 
    def _not_a_dictionary(self, dictionary, mismatch_description): 
        if mismatch_description: 
            mismatch_description.append_description_of(dictionary) \ 
                                .append_text(' is not a mapping object') 
        return False 
 
    def matches(self, dictionary, mismatch_description=None): 
        for key, value_matcher in self.value_matchers: 
 
            try: 
                if not key in dictionary: 
                    if mismatch_description: 
                        mismatch_description.append_text('no ')             \ 
                                            .append_description_of(key)     \ 
                                            .append_text(' key in ')        \ 
                                            .append_description_of(dictionary) 
                    return False 
            except TypeError: 
                return self._not_a_dictionary(dictionary, mismatch_description) 
 
            try: 
                actual_value = dictionary[key] 
            except TypeError: 
                return self._not_a_dictionary(dictionary, mismatch_description) 
 
            if not value_matcher.matches(actual_value): 
                if mismatch_description: 
                    mismatch_description.append_text('value for ')  \ 
                                        .append_description_of(key) \ 
                                        .append_text(' ') 
                    value_matcher.describe_mismatch(actual_value, mismatch_description) 
                return False 
 
        return True 
 
    def describe_mismatch(self, item, mismatch_description): 
        self.matches(item, mismatch_description) 
 
    def describe_keyvalue(self, index, value, description): 
        """Describes key-value pair at given index.""" 
        description.append_description_of(index)                        \ 
                   .append_text(': ')                                   \ 
                   .append_description_of(value) 
 
    def describe_to(self, description): 
        description.append_text('a dictionary containing {') 
        first = True 
        for key, value in self.value_matchers: 
            if not first: 
                description.append_text(', ') 
            self.describe_keyvalue(key, value, description) 
            first = False 
        description.append_text('}') 
 
 
def has_entries(*keys_valuematchers, **kv_args): 
    """Matches if dictionary contains entries satisfying a dictionary of keys 
    and corresponding value matchers. 
 
    :param matcher_dict: A dictionary mapping keys to associated value matchers, 
        or to expected values for 
        :py:func:`~hamcrest.core.core.isequal.equal_to` matching. 
 
    Note that the keys must be actual keys, not matchers. Any value argument 
    that is not a matcher is implicitly wrapped in an 
    :py:func:`~hamcrest.core.core.isequal.equal_to` matcher to check for 
    equality. 
 
    Examples:: 
 
        has_entries({'foo':equal_to(1), 'bar':equal_to(2)}) 
        has_entries({'foo':1, 'bar':2}) 
 
    ``has_entries`` also accepts a list of keyword arguments: 
 
    .. function:: has_entries(keyword1=value_matcher1[, keyword2=value_matcher2[, ...]]) 
 
    :param keyword1: A keyword to look up. 
    :param valueMatcher1: The matcher to satisfy for the value, or an expected 
        value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. 
 
    Examples:: 
 
        has_entries(foo=equal_to(1), bar=equal_to(2)) 
        has_entries(foo=1, bar=2) 
 
    Finally, ``has_entries`` also accepts a list of alternating keys and their 
    value matchers: 
 
    .. function:: has_entries(key1, value_matcher1[, ...]) 
 
    :param key1: A key (not a matcher) to look up. 
    :param valueMatcher1: The matcher to satisfy for the value, or an expected 
        value for :py:func:`~hamcrest.core.core.isequal.equal_to` matching. 
 
    Examples:: 
 
        has_entries('foo', equal_to(1), 'bar', equal_to(2)) 
        has_entries('foo', 1, 'bar', 2) 
 
    """ 
    if len(keys_valuematchers) == 1: 
        try: 
            base_dict = keys_valuematchers[0].copy() 
            for key in base_dict: 
                base_dict[key] = wrap_matcher(base_dict[key]) 
        except AttributeError: 
            raise ValueError('single-argument calls to has_entries must pass a dict as the argument') 
    else: 
        if len(keys_valuematchers) % 2: 
            raise ValueError('has_entries requires key-value pairs') 
        base_dict = {} 
        for index in range(int(len(keys_valuematchers) / 2)): 
            base_dict[keys_valuematchers[2 * index]] = wrap_matcher(keys_valuematchers[2 * index + 1]) 
 
    for key, value in kv_args.items(): 
        base_dict[key] = wrap_matcher(value) 
 
    return IsDictContainingEntries(base_dict)