44# via env var for longer runs in travis.
55import os
66import sys
7+ import numbers
78
89from nose .plugins .skip import SkipTest
910from hypothesis import given , settings , assume , HealthCheck
1213from jmespath import lexer
1314from jmespath import parser
1415from jmespath import exceptions
16+ from jmespath .functions import Functions
1517
1618
1719if sys .version_info [:2 ] == (2 , 6 ):
1820 raise RuntimeError ("Hypothesis tests are not supported on python2.6. "
1921 "Use python2.7, or python3.3 and greater." )
2022
2123
24+ JSON_NUMBERS = (st .integers () | st .floats (allow_nan = False ,
25+ allow_infinity = False ))
26+
2227RANDOM_JSON = st .recursive (
23- st . floats () | st .booleans () | st .text () | st .none (),
28+ JSON_NUMBERS | st .booleans () | st .text () | st .none (),
2429 lambda children : st .lists (children ) | st .dictionaries (st .text (), children )
2530)
2631
27-
2832MAX_EXAMPLES = int (os .environ .get ('JP_MAX_EXAMPLES' , 1000 ))
2933BASE_SETTINGS = {
3034 'max_examples' : MAX_EXAMPLES ,
4044def test_lexer_api (expr ):
4145 try :
4246 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+ )
4458 return
4559 except Exception as e :
4660 raise AssertionError ("Non JMESPathError raised: %s" % e )
4761 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'
4872
4973
5074@settings (** BASE_SETTINGS )
@@ -65,6 +89,9 @@ def test_parser_api_from_str(expr):
6589 except Exception as e :
6690 raise AssertionError ("Non JMESPathError raised: %s" % e )
6791 assert isinstance (ast .parsed , dict )
92+ assert 'type' in ast .parsed
93+ assert 'children' in ast .parsed
94+ assert isinstance (ast .parsed ['children' ], list )
6895
6996
7097@settings (** BASE_SETTINGS )
@@ -82,3 +109,32 @@ def test_search_api(expr, data):
82109 return
83110 except Exception as e :
84111 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