diff --git a/tests/parse/templates.py b/tests/parse/templates.py new file mode 100644 index 0000000..e0b1b65 --- /dev/null +++ b/tests/parse/templates.py @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: LGPL-2.1-only +# Copyright 2022 Jookia + +from hypothesis import given + +from src.parse import SyntaxStream +from tests.test_syntax import draw_syntax_random + + +# Tests that something parses correctly +# We expect the following behaviour: +# - Only the supplied tokens are parsed +# - The supplied tokens parse to the expected value +# - The Syntax's value is the expected value +# - The Syntax's type is expected type +# - The Syntax's location is the first token's location +def template_parse_valid(parser, draw): + @given(draw_syntax_random(), draw) + def do(canary, test_data): + (tokens, expected) = test_data + stream = SyntaxStream(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 + + return lambda func: do diff --git a/tests/parse/test_bool.py b/tests/parse/test_bool.py index 84d8b41..8f9c2e9 100644 --- a/tests/parse/test_bool.py +++ b/tests/parse/test_bool.py @@ -6,6 +6,7 @@ from src.parse import ParseContext, ParseError, ParseErrorException, ParseTask, Parser from src.syntax import Syntax, SyntaxStream, SyntaxType +from tests.parse.templates import template_parse_valid from tests.parse.test_parse import draw_parse_context from tests.test_syntax import draw_token_bool, draw_syntax_random @@ -16,26 +17,18 @@ token = draw(draw_token_bool()) value = token.value == "True" result = Syntax(value, token.location, SyntaxType.BOOL) - return (token, result) + return ([token], result) # Tests parse_bool works correctly # We expect the following behaviour: -# - Only the first token is parsed # - The resulting boolean is True if the first token is True # - The resulting boolean is False if the first token is False -# - The Syntax's value is the resulting token # - The Syntax's type is SyntaxType.BOOL -# - The Syntax's location is the first token's location -@given(draw_syntax_random(), draw_syntax_bool_valid()) -def test_parse_bool_valid(canary, test_data): - (token, result) = test_data - stream = SyntaxStream([token] + [canary]) - parsed = Parser().parse_bool(stream, None) - assert parsed is not None - assert parsed == result - assert stream.pop() == canary - assert stream.pop() is None +# template_parse_valid provides general parsing properties +@template_parse_valid(Parser().parse_bool, draw_syntax_bool_valid()) +def test_parse_bool_valid(): + pass # Generate an invalid boolean diff --git a/tests/parse/test_note.py b/tests/parse/test_note.py index 641bafc..0f8fd33 100644 --- a/tests/parse/test_note.py +++ b/tests/parse/test_note.py @@ -18,6 +18,7 @@ ParseTask, ) from src.syntax import SyntaxStream, SyntaxType +from tests.parse.templates import template_parse_valid from tests.parse.test_parse import draw_parse_context from tests.test_syntax import ( draw_token_by_value, @@ -48,22 +49,16 @@ start = draw(draw_token_by_value("StartNote")) end = draw(draw_token_by_value("EndNote")) all_tokens = [start] + tokens + [end] - return all_tokens + return (all_tokens, None) # Tests skip_note works correctly # We expect the following behaviour: -# - Only the note expression is parsed # - No value is returned -# - All tokens are consumed up to and including EndNote -@given(draw_syntax_random(), draw_syntax_note_valid()) -def test_parse_note_valid(canary, test_data): - tokens = test_data - stream = SyntaxStream(tokens + [canary]) - skipped = NoteSkipper().skip_note(stream, None) - assert skipped is None - assert stream.pop() == canary - assert stream.pop() is None +# template_parse_valid provides general parsing properties +@template_parse_valid(NoteSkipper().skip_note, draw_syntax_note_valid()) +def test_parse_note_valid(): + pass # Generate note without StartNote @@ -73,7 +68,7 @@ # - Error if StartNote's token value is not "StartNote" @composite def draw_syntax_note_invalid_nostartnote(draw): - tokens = draw(draw_syntax_note_valid()) + (tokens, _) = draw(draw_syntax_note_valid()) parent_context = draw(draw_parse_context()) if draw(booleans()): token = draw(draw_syntax_random()) @@ -98,7 +93,7 @@ # - Error if a StartNote token is in the note content @composite def draw_syntax_note_invalid_extrastartnote(draw): - tokens = draw(draw_syntax_note_valid()) + (tokens, _) = draw(draw_syntax_note_valid()) start = draw(draw_token_by_value("StartNote")) new_tokens = insert_random(draw, tokens, start) parent_context = draw(draw_parse_context()) @@ -112,7 +107,7 @@ # - Error if there is no EndNote node at all @composite def draw_syntax_note_invalid_noendnote(draw): - tokens = draw(draw_syntax_note_valid()) + (tokens, _) = draw(draw_syntax_note_valid()) parent_context = draw(draw_parse_context()) context = ParseContext(ParseTask.PARSE_NOTE, tokens[0], parent_context) error = ParseErrorException(ParseError.NO_TOKEN, None, None, context) diff --git a/tests/parse/test_text.py b/tests/parse/test_text.py index 11d559c..b3d9c20 100644 --- a/tests/parse/test_text.py +++ b/tests/parse/test_text.py @@ -18,6 +18,7 @@ Parser, ) from src.syntax import Syntax, SyntaxStream, SyntaxType +from tests.parse.templates import template_parse_valid from tests.parse.test_parse import draw_parse_context from tests.test_syntax import ( draw_token_by_value, @@ -58,21 +59,14 @@ # Tests parse_text works correctly # We expect the following behaviour: -# - Only the text expression is parsed # - The resulting text is the value of tokens between StartText and EndText # - The value of the tokens is joined by U+0020 SPACE code points # - The Syntax's value is the resulting text # - The Syntax's type is SyntaxType.TEXT -# - The Syntax's location is the StartText location -@given(draw_syntax_random(), draw_syntax_text_valid()) -def test_parse_text_valid(canary, test_data): - (tokens, result) = test_data - stream = SyntaxStream(tokens + [canary]) - parsed = Parser().parse_text(stream, None) - assert parsed is not None - assert parsed == result - assert stream.pop() == canary - assert stream.pop() is None +# template_parse_valid provides general parsing properties +@template_parse_valid(Parser().parse_text, draw_syntax_text_valid()) +def test_parse_text_valid(): + pass # Generate text without StartText