-
Notifications
You must be signed in to change notification settings - Fork 184
/
Copy pathtest_compliance.py
117 lines (103 loc) · 4.5 KB
/
test_compliance.py
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
import os
from pprint import pformat
from tests import OrderedDict
from tests import json
import pytest
from jmespath.visitor import Options
TEST_DIR = os.path.dirname(os.path.abspath(__file__))
COMPLIANCE_DIR = os.path.join(TEST_DIR, 'compliance')
LEGACY_DIR = os.path.join(TEST_DIR, 'legacy')
NOT_SPECIFIED = object()
OPTIONS = Options(dict_cls=OrderedDict)
def _compliance_tests(requested_test_type):
for full_path in _walk_files():
if full_path.endswith('.json'):
for given, test_type, test_data in load_cases(full_path):
t = test_data
# Benchmark tests aren't run as part of the normal
# test suite, so we only care about 'result' and
# 'error' test_types.
if test_type == 'result' and test_type == requested_test_type:
yield (given, t['expression'],
t['result'], os.path.basename(full_path))
elif test_type == 'error' and test_type == requested_test_type:
yield (given, t['expression'],
t['error'], os.path.basename(full_path))
def _walk_files():
# Check for a shortcut when running the tests interactively.
# If a JMESPATH_TEST is defined, that file is used as the
# only test to run. Useful when doing feature development.
single_file = os.environ.get('JMESPATH_TEST')
if single_file is not None:
yield os.path.abspath(single_file)
else:
for root, dirnames, filenames in os.walk(TEST_DIR):
for filename in filenames:
yield os.path.join(root, filename)
for root, dirnames, filenames in os.walk(LEGACY_DIR):
for filename in filenames:
yield os.path.join(root, filename)
def load_cases(full_path):
all_test_data = json.load(open(full_path), object_pairs_hook=OrderedDict)
for test_data in all_test_data:
given = test_data['given']
for case in test_data['cases']:
if 'result' in case:
test_type = 'result'
elif 'error' in case:
test_type = 'error'
elif 'bench' in case:
test_type = 'bench'
else:
raise RuntimeError("Unknown test type: %s" % json.dumps(case))
yield (given, test_type, case)
@pytest.mark.parametrize(
'given, expression, expected, filename',
_compliance_tests('result')
)
def test_expression(given, expression, expected, filename):
import jmespath.parser
try:
parsed = jmespath.compile(expression)
except ValueError as e:
raise AssertionError(
'jmespath expression failed to compile: "%s", error: %s"' %
(expression, e))
actual = parsed.search(given, options=OPTIONS)
expected_repr = json.dumps(expected, indent=4)
actual_repr = json.dumps(actual, indent=4)
error_msg = ("\n\n (%s) The expression '%s' was suppose to give:\n%s\n"
"Instead it matched:\n%s\nparsed as:\n%s\ngiven:\n%s" % (
filename, expression, expected_repr,
actual_repr, pformat(parsed.parsed),
json.dumps(given, indent=4)))
error_msg = error_msg.replace(r'\n', '\n')
assert actual == expected, error_msg
@pytest.mark.parametrize(
'given, expression, error, filename',
_compliance_tests('error')
)
def test_error_expression(given, expression, error, filename):
import jmespath.parser
if error not in ('syntax', 'invalid-type',
'unknown-function', 'invalid-arity', 'invalid-value'):
raise RuntimeError("Unknown error type '%s'" % error)
try:
parsed = jmespath.compile(expression)
parsed.search(given)
except ValueError:
# Test passes, it raised a parse error as expected.
pass
except Exception as e:
# Failure because an unexpected exception was raised.
error_msg = ("\n\n (%s) The expression '%s' was suppose to be a "
"syntax error, but it raised an unexpected error:\n\n%s" % (
filename, expression, e))
error_msg = error_msg.replace(r'\n', '\n')
raise AssertionError(error_msg)
else:
error_msg = ("\n\n (%s) The expression '%s' was suppose to be a "
"syntax error, but it successfully parsed as:\n\n%s" % (
filename, expression, pformat(parsed.parsed)))
error_msg = error_msg.replace(r'\n', '\n')
raise AssertionError(error_msg)