|
| 1 | +# Test suite using hypothesis to generate test cases. |
| 2 | +# This is in a standalone module so that these tests |
| 3 | +# can a) be run separately and b) allow for customization |
| 4 | +# via env var for longer runs in travis. |
| 5 | +import os |
| 6 | +import sys |
| 7 | + |
| 8 | +from nose.plugins.skip import SkipTest |
| 9 | +from hypothesis import given, settings, assume, HealthCheck |
| 10 | +import hypothesis.strategies as st |
| 11 | + |
| 12 | +from jmespath import lexer |
| 13 | +from jmespath import parser |
| 14 | +from jmespath import exceptions |
| 15 | + |
| 16 | + |
| 17 | +if sys.version_info[:2] == (2, 6): |
| 18 | + raise RuntimeError("Hypothesis tests are not supported on python2.6. " |
| 19 | + "Use python2.7, or python3.3 and greater.") |
| 20 | + |
| 21 | + |
| 22 | +RANDOM_JSON = st.recursive( |
| 23 | + st.floats() | st.booleans() | st.text() | st.none(), |
| 24 | + lambda children: st.lists(children) | st.dictionaries(st.text(), children) |
| 25 | +) |
| 26 | + |
| 27 | + |
| 28 | +MAX_EXAMPLES = int(os.environ.get('JP_MAX_EXAMPLES', 1000)) |
| 29 | +BASE_SETTINGS = { |
| 30 | + 'max_examples': MAX_EXAMPLES, |
| 31 | + 'suppress_health_check': [HealthCheck.too_slow], |
| 32 | +} |
| 33 | + |
| 34 | + |
| 35 | +# For all of these tests they verify these proprties: |
| 36 | +# either the operation succeeds or it raises a JMESPathError. |
| 37 | +# If any other exception is raised then we error out. |
| 38 | +@settings(**BASE_SETTINGS) |
| 39 | +@given(st.text()) |
| 40 | +def test_lexer_api(expr): |
| 41 | + try: |
| 42 | + tokens = list(lexer.Lexer().tokenize(expr)) |
| 43 | + except exceptions.JMESPathError as e: |
| 44 | + return |
| 45 | + except Exception as e: |
| 46 | + raise AssertionError("Non JMESPathError raised: %s" % e) |
| 47 | + assert isinstance(tokens, list) |
| 48 | + |
| 49 | + |
| 50 | +@settings(**BASE_SETTINGS) |
| 51 | +@given(st.text()) |
| 52 | +def test_parser_api_from_str(expr): |
| 53 | + # Same a lexer above with the assumption that we're parsing |
| 54 | + # a valid sequence of tokens. |
| 55 | + try: |
| 56 | + list(lexer.Lexer().tokenize(expr)) |
| 57 | + except exceptions.JMESPathError as e: |
| 58 | + # We want to try to parse things that tokenize |
| 59 | + # properly. |
| 60 | + assume(False) |
| 61 | + try: |
| 62 | + ast = parser.Parser().parse(expr) |
| 63 | + except exceptions.JMESPathError as e: |
| 64 | + return |
| 65 | + except Exception as e: |
| 66 | + raise AssertionError("Non JMESPathError raised: %s" % e) |
| 67 | + assert isinstance(ast.parsed, dict) |
| 68 | + |
| 69 | + |
| 70 | +@settings(**BASE_SETTINGS) |
| 71 | +@given(expr=st.text(), data=RANDOM_JSON) |
| 72 | +def test_search_api(expr, data): |
| 73 | + try: |
| 74 | + ast = parser.Parser().parse(expr) |
| 75 | + except exceptions.JMESPathError as e: |
| 76 | + # We want to try to parse things that tokenize |
| 77 | + # properly. |
| 78 | + assume(False) |
| 79 | + try: |
| 80 | + ast.search(data) |
| 81 | + except exceptions.JMESPathError as e: |
| 82 | + return |
| 83 | + except Exception as e: |
| 84 | + raise AssertionError("Non JMESPathError raised: %s" % e) |
0 commit comments