userver: en/testsuite/plugins/matching.py Source File
Loading...
Searching...
No Matches
matching.py
1import pytest
2
3from testsuite import matching
4
5
6def _default_regex_match(doc: dict):
7 return matching.RegexString(doc['pattern'])
8
9
10def _default_partial_dict_match(doc: dict):
11 return matching.PartialDict(doc['value'])
12
13
14def _match_unordered_list(doc: dict):
15 items = doc['items']
16 if 'keys' in doc:
17 key = _make_keys_getter(doc['keys'])
18 elif 'key' in doc:
19 key = _make_key_getter(doc['key'])
20 else:
21 key = None
22 return matching.unordered_list(items, key=key)
23
24
25def _match_list_of(doc):
26 return matching.ListOf(value=doc.get('item', matching.any_value))
27
28
29def _match_dict_of(doc):
30 return matching.DictOf(
31 key=doc.get('key', matching.any_value),
32 value=doc.get('value', matching.any_value),
33 )
34
35
36def pytest_register_matching_hooks():
37 return {
38 'any-value': matching.any_value,
39 'any-float': matching.any_float,
40 'any-integer': matching.any_integer,
41 'any-numeric': matching.any_numeric,
42 'positive-float': matching.positive_float,
43 'positive-integer': matching.positive_integer,
44 'positive-numeric': matching.positive_numeric,
45 'negative-float': matching.negative_float,
46 'negative-integer': matching.negative_integer,
47 'negative-numeric': matching.negative_numeric,
48 'non-negative-float': matching.non_negative_float,
49 'non-negative-integer': matching.non_negative_integer,
50 'non-negative-numeric': matching.non_negative_numeric,
51 'any-string': matching.any_string,
52 'uuid-string': matching.uuid_string,
53 'objectid-string': matching.objectid_string,
54 'datetime-string': matching.datetime_string,
55 'regex': _default_regex_match,
56 # dictionaries
57 'any-dict': matching.any_dict,
58 'dict-of': _match_dict_of,
59 'partial-dict': _default_partial_dict_match,
60 # lists
61 'any-list': matching.any_list,
62 'list-of': _match_list_of,
63 'unordered-list': _match_unordered_list,
64 'unordered_list': _match_unordered_list,
65 }
66
67
69 def pytest_register_matching_hooks(self):
70 pass
71
72
73class MatchingPlugin:
74 def __init__(self):
75 self._matching_hooks = {}
76
77 @property
78 def matching_hooks(self):
79 return self._matching_hooks
80
81 def pytest_sessionstart(self, session):
82 hooks = (
83 session.config.pluginmanager.hook.pytest_register_matching_hooks()
84 )
85 for hook in hooks:
86 self._matching_hooks.update(hook)
87
88 def pytest_addhooks(self, pluginmanager):
89 pluginmanager.add_hookspecs(Hookspec)
90
91
92def pytest_configure(config):
93 config.pluginmanager.register(MatchingPlugin(), 'matching_params')
94
95
96@pytest.fixture(scope='session')
97def operator_match(request, pytestconfig):
98 plugin = pytestconfig.pluginmanager.get_plugin('matching_params')
99
100 def match(doc: dict):
101 match_type = doc.get('type')
102 try:
103 hook = plugin.matching_hooks[match_type]
104 except KeyError:
105 raise RuntimeError(f'Unknown match type {match_type}')
106 if callable(hook):
107 return hook(doc)
108 return hook
109
110 return match
111
112
113@pytest.fixture(scope='session')
114def match_operator(operator_match):
115 def _wrapper(doc: dict):
116 match = doc['$match']
117 if isinstance(match, str):
118 match = {'type': match}
119 return operator_match(match)
120
121 return _wrapper
122
123
124def _make_keys_getter(keys):
125 key_getters = tuple(_make_key_getter(key) for key in keys)
126
127 def getter(value):
128 return tuple(getter(value) for getter in key_getters)
129
130 return getter
131
132
133def _make_key_getter(path):
134 if isinstance(path, str):
135 path = [path]
136
137 def getter(doc):
138 for key in path:
139 doc = doc[key]
140 return doc
141
142 return getter