1
+ ## JMESPATH.ORG COMPLIANCE
2
+ ## run the following command to extract jmespath.org compliance test suite
3
+ ## git clone https://github.com/jmespath/jmespath.test tests/jmespath.org
4
+
5
+ import os
6
+ from pprint import pformat
7
+ from tests import OrderedDict
8
+ from tests import json
9
+
10
+ import pytest
11
+
12
+ from jmespath .visitor import Options
13
+
14
+ TEST_DIR = os .path .dirname (os .path .abspath (__file__ ))
15
+ JMESPATH_ORG_DIR = os .path .join (TEST_DIR , 'jmespath.org' )
16
+ LEGACY_OPTIONS = Options (dict_cls = OrderedDict , enable_legacy_literals = True )
17
+
18
+ ExcludedTests = [
19
+ "literal.json"
20
+ ]
21
+
22
+ def _compliance_tests (requested_test_type ):
23
+ for full_path in _walk_files ():
24
+ if full_path .endswith ('.json' ):
25
+ for given , test_type , test_data in load_cases (full_path ):
26
+ t = test_data
27
+ # Benchmark tests aren't run as part of the normal
28
+ # test suite, so we only care about 'result' and
29
+ # 'error' test_types.
30
+ if test_type == 'result' and test_type == requested_test_type :
31
+ yield (given , t ['expression' ],
32
+ t ['result' ], os .path .basename (full_path ))
33
+ elif test_type == 'error' and test_type == requested_test_type :
34
+ yield (given , t ['expression' ],
35
+ t ['error' ], os .path .basename (full_path ))
36
+
37
+ def _is_valid_test_file (filename ):
38
+ if filename .endswith (".json" ) and \
39
+ not filename .endswith ("schema.json" ) and \
40
+ not os .path .basename (filename ) in ExcludedTests :
41
+ return True
42
+ return False
43
+
44
+ def _walk_files ():
45
+ for dir in [JMESPATH_ORG_DIR ]:
46
+ for root , dirnames , filenames in os .walk (dir ):
47
+ for filename in filenames :
48
+ if _is_valid_test_file (filename ):
49
+ yield os .path .join (root , filename )
50
+
51
+ def load_cases (full_path ):
52
+ all_test_data = json .load (open (full_path ), object_pairs_hook = OrderedDict )
53
+ for test_data in all_test_data :
54
+ given = test_data ['given' ]
55
+ for case in test_data ['cases' ]:
56
+ if 'result' in case :
57
+ test_type = 'result'
58
+ elif 'error' in case :
59
+ test_type = 'error'
60
+ elif 'bench' in case :
61
+ test_type = 'bench'
62
+ else :
63
+ raise RuntimeError ("Unknown test type: %s" % json .dumps (case ))
64
+ yield (given , test_type , case )
65
+
66
+
67
+ @pytest .mark .parametrize (
68
+ 'given, expression, expected, filename' ,
69
+ _compliance_tests ('result' )
70
+ )
71
+ def test_expression (given , expression , expected , filename ):
72
+ try :
73
+ (actual , parsed ) = _search_expression (given , expression , filename )
74
+ except ValueError as e :
75
+ raise AssertionError (
76
+ 'jmespath expression failed to compile: "%s", error: %s"' %
77
+ (expression , e ))
78
+
79
+ expected_repr = json .dumps (expected , indent = 4 )
80
+ actual_repr = json .dumps (actual , indent = 4 )
81
+ error_msg = ("\n \n (%s) The expression '%s' was supposed to give:\n %s\n "
82
+ "Instead it matched:\n %s\n parsed as:\n %s\n given:\n %s" % (
83
+ filename , expression , expected_repr ,
84
+ actual_repr , pformat (parsed .parsed ),
85
+ json .dumps (given , indent = 4 )))
86
+ error_msg = error_msg .replace (r'\n' , '\n ' )
87
+ assert actual == expected , error_msg
88
+
89
+
90
+ @pytest .mark .parametrize (
91
+ 'given, expression, error, filename' ,
92
+ _compliance_tests ('error' )
93
+ )
94
+ def test_error_expression (given , expression , error , filename ):
95
+ if error not in ('syntax' , 'invalid-type' ,
96
+ 'unknown-function' , 'invalid-arity' , 'invalid-value' ):
97
+ raise RuntimeError ("Unknown error type '%s'" % error )
98
+ try :
99
+ (_ , parsed ) = _search_expression (given , expression , filename )
100
+ except ValueError :
101
+ # Test passes, it raised a parse error as expected.
102
+ pass
103
+ except Exception as e :
104
+ # Failure because an unexpected exception was raised.
105
+ error_msg = ("\n \n (%s) The expression '%s' was suppose to be a "
106
+ "syntax error, but it raised an unexpected error:\n \n %s" % (
107
+ filename , expression , e ))
108
+ error_msg = error_msg .replace (r'\n' , '\n ' )
109
+ raise AssertionError (error_msg )
110
+ else :
111
+ error_msg = ("\n \n (%s) The expression '%s' was suppose to be a "
112
+ "syntax error, but it successfully parsed as:\n \n %s" % (
113
+ filename , expression , pformat (parsed .parsed )))
114
+ error_msg = error_msg .replace (r'\n' , '\n ' )
115
+ raise AssertionError (error_msg )
116
+
117
+ def _search_expression (given , expression , filename ):
118
+ import jmespath .parser
119
+
120
+ options = LEGACY_OPTIONS
121
+
122
+ parsed = jmespath .compile (expression , options = options )
123
+ actual = parsed .search (given , options = options )
124
+ return (actual , parsed )
0 commit comments