diff --git a/tests/parse/templates.py b/tests/parse/templates.py index ad01fdc..832d849 100644 --- a/tests/parse/templates.py +++ b/tests/parse/templates.py @@ -2,12 +2,19 @@ # Copyright 2022 Jookia from hypothesis import given -from hypothesis.strategies import integers +from hypothesis.strategies import composite, integers -from src.parse import SyntaxStream +from src.parse import ParseErrorException, SyntaxStream from tests.test_syntax import draw_syntax_random +# Inserts an element at a random place in a list +def insert_random(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: # - Only the supplied tokens are parsed @@ -32,8 +39,15 @@ return lambda func: do -# Inserts an element at a random place in a list -def insert_random(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 +# Test that something parsers incorrectly +def template_parse_invalid(parser): + def do(test_data): + (tokens, error, context) = test_data + stream = SyntaxStream(tokens) + try: + parsed = parser(stream, context) + raise AssertionError("Parsed invalid data: %s" % (parsed)) + except ParseErrorException as e: + assert e == error + + return lambda func: given(composite(func)())(do) diff --git a/tests/parse/test_bool.py b/tests/parse/test_bool.py index 8f9c2e9..47aadda 100644 --- a/tests/parse/test_bool.py +++ b/tests/parse/test_bool.py @@ -1,12 +1,12 @@ # SPDX-License-Identifier: LGPL-2.1-only # Copyright 2022 Jookia -from hypothesis import assume, given +from hypothesis import assume from hypothesis.strategies import booleans, composite 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 src.syntax import Syntax, SyntaxType +from tests.parse.templates import template_parse_valid, template_parse_invalid from tests.parse.test_parse import draw_parse_context from tests.test_syntax import draw_token_bool, draw_syntax_random @@ -36,8 +36,8 @@ # - Error if there isn't a token # - Error if the token is not a SyntaxType.TOKEN # - Error if the token is not True or False -@composite -def draw_syntax_bool_invalid(draw): +@template_parse_invalid(Parser().parse_bool) +def test_parse_bool_invalid(draw): parent_context = draw(draw_parse_context()) if draw(booleans()): token = draw(draw_syntax_random()) @@ -54,15 +54,3 @@ context = ParseContext(ParseTask.PARSE_BOOL, None, parent_context) error = ParseErrorException(ParseError.NO_TOKEN, None, None, context) return ([], error, parent_context) - - -# Test that parse_bool errors in invalid cases -@given(draw_syntax_bool_invalid()) -def test_parse_bool_invalid(test_data): - (tokens, error, context) = test_data - stream = SyntaxStream(tokens) - try: - parsed = Parser().parse_bool(stream, context) - raise AssertionError("Parsed invalid data: %s" % (parsed)) - except ParseErrorException as e: - assert e == error diff --git a/tests/parse/test_clear_notes.py b/tests/parse/test_clear_notes.py index b5557d4..d2ec3a4 100644 --- a/tests/parse/test_clear_notes.py +++ b/tests/parse/test_clear_notes.py @@ -12,6 +12,7 @@ ParseTask, ) from src.syntax import SyntaxStream +from tests.parse.templates import template_parse_invalid, template_parse_valid from tests.parse.test_parse import draw_parse_context from tests.test_syntax import draw_token_by_value, draw_syntax_token @@ -23,6 +24,13 @@ return None +# Creates a NoteSkipper with clear_notes_skip_note_valid +def dummy_skipper_valid(): + skipper = NoteSkipper() + skipper.skip_note = clear_notes_skip_note_valid + return skipper + + # Dummy parse_note implementation for testing error propgation # This redefines skip_note to always throw an error def clear_notes_skip_note_error(stream, parent_context): @@ -30,6 +38,13 @@ raise ParseErrorException(ParseError.TEST_ERROR, s, None, parent_context) +# Creates a NoteSkipper with clear_notes_skip_note_error +def dummy_skipper_invalid(): + skipper = NoteSkipper() + skipper.skip_note = clear_notes_skip_note_error + return skipper + + # Draws a random token suitable for note clearing testing @composite def draw_clear_notes_value_token(draw): @@ -57,15 +72,16 @@ def test_parse_clear_notes_valid(test_data): (tokens, result) = test_data stream = SyntaxStream(tokens) - skipper = NoteSkipper() - skipper.skip_note = clear_notes_skip_note_valid - cleared = skipper.clear_notes(stream, None) + cleared = dummy_skipper_valid().clear_notes(stream, None) assert cleared == result -# Draws tokens to test clear_notes error propagation -@composite -def draw_syntax_clear_notes_startnote_propagation(draw): +# Tests clear_notes passes through skip_note errors +# We expect the following behaviour: +# - When StartNote is encountered skip_note is called to skip the note +# - Any error skip_note gives is propagated through clear_notes +@template_parse_invalid(dummy_skipper_invalid().clear_notes) +def test_parse_clear_notes_startnote_propagation(draw): tokens = draw(lists(draw_clear_notes_value_token())) # Ensure we have a StartNote somewhere start = draw(draw_token_by_value("StartNote")) @@ -79,26 +95,11 @@ raise AssertionError("Unable to find StartNote?") -# Tests clear_notes passes through skip_note errors +# Tests clear_notes errors when finding an EndNote # We expect the following behaviour: -# - When StartNote is encountered skip_note is called to skip the note -# - Any error skip_note gives is propagated through clear_notes -@given(draw_syntax_clear_notes_startnote_propagation()) -def test_parse_clear_notes_startnote_propagation(test_data): - (tokens, error, parent_context) = test_data - stream = SyntaxStream(tokens) - skipper = NoteSkipper() - skipper.skip_note = clear_notes_skip_note_error - try: - parsed = skipper.clear_notes(stream, parent_context) - raise AssertionError("Parsed invalid data: %s" % (parsed)) - except ParseErrorException as e: - assert e == error - - -# Draws tokens to test clear_notes EndNote invalid error -@composite -def draw_syntax_clear_notes_invalid_endnote(draw): +# - When EndNote is encountered a FOUND_ENDNOTE error is raised +@template_parse_invalid(dummy_skipper_valid().clear_notes) +def test_parse_clear_notes_invalid_endnote(draw): tokens = draw(lists(draw_clear_notes_value_token())) # Ensure we have an EndNote somewhere start = draw(draw_token_by_value("EndNote")) @@ -110,19 +111,3 @@ error = ParseErrorException(ParseError.FOUND_ENDNOTE, token, None, context) return (new_tokens, error, parent_context) raise AssertionError("Unable to find EndNote?") - - -# Tests clear_notes errors when finding an EndNote -# We expect the following behaviour: -# - When EndNote is encountered a FOUND_ENDNOTE error is raised -@given(draw_syntax_clear_notes_invalid_endnote()) -def test_parse_clear_notes_invalid_endnote(test_data): - (tokens, error, parent_context) = test_data - stream = SyntaxStream(tokens) - skipper = NoteSkipper() - skipper.skip_note = clear_notes_skip_note_valid - try: - parsed = skipper.clear_notes(stream, parent_context) - raise AssertionError("Parsed invalid data: %s" % (parsed)) - except ParseErrorException as e: - assert e == error diff --git a/tests/parse/test_note.py b/tests/parse/test_note.py index a453d01..e4b53f5 100644 --- a/tests/parse/test_note.py +++ b/tests/parse/test_note.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1-only # Copyright 2022 Jookia -from hypothesis import assume, given +from hypothesis import assume from hypothesis.strategies import ( booleans, composite, @@ -16,8 +16,12 @@ ParseErrorException, ParseTask, ) -from src.syntax import SyntaxStream, SyntaxType -from tests.parse.templates import insert_random, template_parse_valid +from src.syntax import SyntaxType +from tests.parse.templates import ( + insert_random, + template_parse_invalid, + template_parse_valid, +) from tests.parse.test_parse import draw_parse_context from tests.test_syntax import ( draw_token_by_value, @@ -106,24 +110,12 @@ return (tokens[0:-1], error, parent_context) -# Generate an invalid note case -@composite -def draw_syntax_note_invalid(draw): +# Test that parse_note errors in invalid cases +@template_parse_invalid(NoteSkipper().skip_note) +def test_parse_note_invalid(draw): strategies = [ draw_syntax_note_invalid_nostartnote(), draw_syntax_note_invalid_extrastartnote(), draw_syntax_note_invalid_noendnote(), ] return draw(one_of(strategies)) - - -# Test that parse_note errors in invalid cases -@given(draw_syntax_note_invalid()) -def test_parse_note_invalid(test_data): - (tokens, error, context) = test_data - stream = SyntaxStream(tokens) - try: - parsed = NoteSkipper().skip_note(stream, context) - raise AssertionError("Parsed invalid data: %s" % (parsed)) - except ParseErrorException as e: - assert e == error diff --git a/tests/parse/test_text.py b/tests/parse/test_text.py index f758120..67e37f4 100644 --- a/tests/parse/test_text.py +++ b/tests/parse/test_text.py @@ -1,7 +1,7 @@ # SPDX-License-Identifier: LGPL-2.1-only # Copyright 2022 Jookia -from hypothesis import assume, given +from hypothesis import assume from hypothesis.strategies import ( booleans, composite, @@ -16,8 +16,12 @@ ParseTask, Parser, ) -from src.syntax import Syntax, SyntaxStream, SyntaxType -from tests.parse.templates import insert_random, template_parse_valid +from src.syntax import Syntax, SyntaxType +from tests.parse.templates import ( + insert_random, + template_parse_invalid, + template_parse_valid, +) from tests.parse.test_parse import draw_parse_context from tests.test_syntax import ( draw_token_by_value, @@ -129,9 +133,9 @@ return (tokens[0:-1], error, parent_context) -# Generate an invalid text case -@composite -def draw_syntax_text_invalid(draw): +# Test that parse_text errors in invalid cases +@template_parse_invalid(Parser().parse_text) +def test_parse_text_invalid(draw): strategies = [ draw_syntax_text_invalid_nostarttext(), draw_syntax_text_invalid_invalidcontent(), @@ -139,15 +143,3 @@ draw_syntax_text_invalid_noendtext(), ] return draw(one_of(strategies)) - - -# Test that parse_text errors in invalid cases -@given(draw_syntax_text_invalid()) -def test_parse_text_invalid(test_data): - (tokens, error, context) = test_data - stream = SyntaxStream(tokens) - try: - parsed = Parser().parse_text(stream, context) - raise AssertionError("Parsed invalid data: %s" % (parsed)) - except ParseErrorException as e: - assert e == error