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