# SPDX-License-Identifier: LGPL-2.1-only # Copyright 2022 Jookia <contact@jookia.org> from hypothesis import given from hypothesis.strategies import composite, integers from src.parse import ParseErrorException from src.token import TokenStream from tests.parse.test_parse import static_parse_context from tests.test_token import static_token_by_value # Inserts an element randomly between the first and last token of a list def insert_random_within(draw, list, data): pos = draw(integers(min_value=1, max_value=(len(list) - 1))) new_data = list[0:pos] + [data] + list[pos:] return new_data # Tests that something parses correctly # We expect the following behaviour: # - The parse function generates the expected output # - The parse function doesn't consume extra tokens def template_test_valid(parser, tokens, expected): canary = static_token_by_value("CANARY") stream = TokenStream(tokens + [canary]) parsed = parser(stream, None) if expected is None: assert parsed is None else: assert parsed is not None assert parsed == expected assert stream.pop() == canary assert stream.pop() is None # Test that something parses incorrectly # We expect the following behaviour: # - The parse function generates the expected error # - The parse function uses the parse context as a parent def template_test_invalid(parser, context, tokens, expected): stream = TokenStream(tokens.copy()) error = None try: parsed = parser(stream, context) raise AssertionError("Parsed invalid data: %s" % (parsed)) except ParseErrorException as e: error = e assert error == expected # Deprecated: Do not use # Tests that something parses correctly # We expect the following behaviour: # - The decoration supplies a generator for test data and expected output # - The decorated function is unused # - Only the supplied tokens are parsed # - The supplied tokens parse to the expected value # - The Token's value is the expected value # - The Token's location is the first token's location def template_parse_valid(parser, draw): @given(draw) def do(test_data): (tokens, expected) = test_data return template_test_valid(parser, tokens, expected) return lambda func: do # Deprecated: Do not use # Tests that something parses correctly with a custom parser # We expect the following behaviour: # - The decorated function supplies a parser, test data and expected data # - Only the supplied tokens are parsed # - The supplied tokens parse to the expected value # - The Token's value is the expected value # - The Token's location is the first token's location def template_parse_valid_composite(func): @given(composite(func)()) def do(test_data): (parser, tokens, expected) = test_data return template_test_valid(parser, tokens, expected) return do # Deprecated: Do not use # Test that something parses incorrectly # We expect the following behaviour: # - The decoration supplies a parser function # - The decorated function takes a parse context # - The decorated function generates input tokens and an error # - Parsing causes an error # - The parse error is as expected def template_parse_invalid(parser): # Wrapper to add parse_context to our test_data @composite def wrapper(draw, func): context = static_parse_context() (tokens, error) = draw(composite(func)(context)) return (tokens, error, context) # test_data is the output of wrapper def do(test_data): (tokens, error, context) = test_data return template_test_invalid(parser, context, tokens, error) return lambda func: given(wrapper(func))(do) # Deprecated: Do not use # Test that something parses incorrectly with a custom parser # We expect the following behaviour: # - The decorated function takes a parse context # - The decorated function generates a parser, input tokens and an error # - Parsing causes an error # - The parse error is as expected def template_parse_invalid_composite(func): # Wrapper to add parse_context to our test_data @composite def wrapper(draw): context = static_parse_context() (parser, tokens, error) = draw(composite(func)(context)) return (parser, tokens, error, context) # test_data is the output of wrapper @given(wrapper()) def do(test_data): (parser, tokens, error, context) = test_data return template_test_invalid(parser, context, tokens, error) return do