# SPDX-License-Identifier: LGPL-2.1-only # Copyright 2022 Jookia <contact@jookia.org> # File syntax consists of the following: # - One or more directives # # Parsing gives the following: # A list of directives - All directives in the file # # The following error contexts are used: # PARSE_FILE - Used when parsing the file # # No parse errors are generated. # # The following parsers are used and have their errors # and data structures propagated: # parse_directive - Used to parse a directive import enum from hypothesis import assume, given from hypothesis.strategies import composite, data, integers, just, lists from src.token import TokenStream from src.parse import ( ParseContext, ParseError, ParseErrorException, ParseTask, Parser, read_token, ) from tests.parse.templates import ( template_test_invalid, ) from tests.test_token import ( draw_token_random, static_token_by_value, ) from tests.parse.test_error import static_parse_context # # Helper functions # # Values used by the mocked parser class MockDirective(enum.Enum): MockDirective = enum.auto() # Mocks and tests the parse_directive parser # Instead of parsing directives, return a mock value # it instead returns a mock value class MockParser(Parser): def parse_directive(self, stream, parent_context): read_token(stream, "MockDirective", parent_context) return MockDirective.MockDirective # A valid directive def static_directive(): return ([static_token_by_value("MockDirective")], MockDirective.MockDirective) # A valid file @composite def draw_file_valid(draw): directives = draw(lists(just(static_directive()))) all_tokens = [] all_expected = [] for (tokens, expected) in directives: all_tokens += tokens all_expected.append(expected) return (all_tokens, all_expected) # # Test functions # # Tests parsing a valid file # We expect the following behaviour: # - All directives are parsed # - No tokens are left after parsing @given(draw_file_valid()) def test_parse_file_valid(test_data): (tokens, expected) = test_data stream = TokenStream(tokens.copy()) parsed = MockParser().parse_file(stream, None) assert parsed == expected assert stream.pop() is None # Tests parsing a invalid file # We expect the following behaviour: # - The error context is PARSE_FILE # - A wrong directive error is propagated @given(draw_file_valid(), data()) def test_parse_file_invalid(test_data, data): (tokens, _) = test_data assume(len(tokens) > 0) new_token = data.draw(draw_token_random(), "error token") assume(new_token.value != "MockDirective") max_chosen = len(tokens) - 1 chosen = data.draw( integers(min_value=0, max_value=max_chosen), "error token position" ) new_tokens = tokens[:chosen] + [new_token] + tokens[chosen + 1 :] parent_context = static_parse_context() context = ParseContext(ParseTask.PARSE_FILE, new_tokens[0], parent_context) error = ParseErrorException( ParseError.WRONG_TOKEN, new_token, "MockDirective", context ) parser = MockParser().parse_file template_test_invalid(parser, parent_context, new_tokens, error)