4
4
# via env var for longer runs in travis.
5
5
import os
6
6
import sys
7
+ import numbers
7
8
8
9
from nose .plugins .skip import SkipTest
9
10
from hypothesis import given , settings , assume , HealthCheck
12
13
from jmespath import lexer
13
14
from jmespath import parser
14
15
from jmespath import exceptions
16
+ from jmespath .functions import Functions
15
17
16
18
17
19
if sys .version_info [:2 ] == (2 , 6 ):
18
20
raise RuntimeError ("Hypothesis tests are not supported on python2.6. "
19
21
"Use python2.7, or python3.3 and greater." )
20
22
21
23
24
+ JSON_NUMBERS = (st .integers () | st .floats (allow_nan = False ,
25
+ allow_infinity = False ))
26
+
22
27
RANDOM_JSON = st .recursive (
23
- st . floats () | st .booleans () | st .text () | st .none (),
28
+ JSON_NUMBERS | st .booleans () | st .text () | st .none (),
24
29
lambda children : st .lists (children ) | st .dictionaries (st .text (), children )
25
30
)
26
31
27
-
28
32
MAX_EXAMPLES = int (os .environ .get ('JP_MAX_EXAMPLES' , 1000 ))
29
33
BASE_SETTINGS = {
30
34
'max_examples' : MAX_EXAMPLES ,
40
44
def test_lexer_api (expr ):
41
45
try :
42
46
tokens = list (lexer .Lexer ().tokenize (expr ))
43
- except exceptions .JMESPathError as e :
47
+ except exceptions .EmptyExpressionError :
48
+ return
49
+ except exceptions .LexerError as e :
50
+ assert e .lex_position >= 0 , e .lex_position
51
+ assert e .lex_position < len (expr ), e .lex_position
52
+ if expr :
53
+ assert expr [e .lex_position ] == e .token_value [0 ], (
54
+ "Lex position does not match first token char.\n "
55
+ "Expression: %s\n %s != %s" % (expr , expr [e .lex_position ],
56
+ e .token_value [0 ])
57
+ )
44
58
return
45
59
except Exception as e :
46
60
raise AssertionError ("Non JMESPathError raised: %s" % e )
47
61
assert isinstance (tokens , list )
62
+ # Token starting positions must be unique, can't have two
63
+ # tokens with the same start position.
64
+ start_locations = [t ['start' ] for t in tokens ]
65
+ assert len (set (start_locations )) == len (start_locations ), (
66
+ "Tokens must have unique starting locations." )
67
+ # Starting positions must be increasing (i.e sorted).
68
+ assert sorted (start_locations ) == start_locations , (
69
+ "Tokens must have increasing start locations." )
70
+ # Last token is always EOF.
71
+ assert tokens [- 1 ]['type' ] == 'eof'
48
72
49
73
50
74
@settings (** BASE_SETTINGS )
@@ -65,6 +89,9 @@ def test_parser_api_from_str(expr):
65
89
except Exception as e :
66
90
raise AssertionError ("Non JMESPathError raised: %s" % e )
67
91
assert isinstance (ast .parsed , dict )
92
+ assert 'type' in ast .parsed
93
+ assert 'children' in ast .parsed
94
+ assert isinstance (ast .parsed ['children' ], list )
68
95
69
96
70
97
@settings (** BASE_SETTINGS )
@@ -82,3 +109,32 @@ def test_search_api(expr, data):
82
109
return
83
110
except Exception as e :
84
111
raise AssertionError ("Non JMESPathError raised: %s" % e )
112
+
113
+
114
+ # Additional property tests for functions.
115
+
116
+ @given (arg = JSON_NUMBERS )
117
+ def test_abs (arg ):
118
+ assert Functions ().call_function ('abs' , [arg ]) >= 0
119
+
120
+
121
+ @given (arg = st .lists (JSON_NUMBERS ))
122
+ def test_avg (arg ):
123
+ result = Functions ().call_function ('avg' , [arg ])
124
+ if result is not None :
125
+ assert isinstance (result , numbers .Number )
126
+
127
+
128
+ @given (arg = st .lists (st .floats () | st .booleans () | st .text () | st .none (),
129
+ min_size = 1 ))
130
+ def test_not_null (arg ):
131
+ result = Functions ().call_function ('not_null' , arg )
132
+ if result is not None :
133
+ assert result in arg
134
+
135
+
136
+ @given (arg = RANDOM_JSON )
137
+ def test_to_number (arg ):
138
+ result = Functions ().call_function ('to_number' , [arg ])
139
+ if result is not None :
140
+ assert isinstance (result , numbers .Number )
0 commit comments