# SPDX-License-Identifier: LGPL-2.1-only # Copyright 2022 Jookia <contact@jookia.org> from hypothesis import assume, given from hypothesis.strategies import ( composite, lists, ) from src.ast_types import Text from src.parse2.parse import ( ParseContext, ParseError, ParseErrorException, ParseTask, Parser, ) from tests.parse2.templates import ( draw_random_within, template_test_invalid, template_test_valid, ) from tests.parse2.test_error import static_parse_context from tests.parse2.test_token import ( static_token_by_value, draw_token_random, ) # Draws a random token suitable for text building @composite def draw_text_value_token(draw): token = draw(draw_token_random()) assume(token.value not in ["StartText", "EndText"]) return token # Draws a random token that isn't StartText token @composite def draw_token_not_starttext(draw): token = draw(draw_token_random()) assume(token.value != "StartText") return token # Draws tokens to make a valid text string and its value @composite def draw_token_text_valid(draw): tokens = draw(lists(draw_text_value_token())) buffer = "" for token in tokens: buffer += token.value + " " value = buffer[:-1] # Drop trailing space start = static_token_by_value("StartText") end = static_token_by_value("EndText") all_tokens = [start] + tokens + [end] return (all_tokens, Text(value)) # Draws just the tokens of a valid text string @composite def draw_token_text_valid_tokens(draw): (tokens, _) = draw(draw_token_text_valid()) return tokens # Tests parse_text works correctly # We expect the following behaviour: # - 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 Token's value is the resulting text # template_test_valid provides general parsing properties @given(draw_token_text_valid()) def test_parse2_text_valid(valid_data): (tokens, expected) = valid_data template_test_valid(Parser().parse_text, tokens, expected) # Test parsing text without StartText # We expect the following behaviour: # - Error if StartText's token value is not "StartText" # - Have ParseError.PARSE_TEXT as the exception code # - Have ParseTask.PARSE_TEXT as the context's parse task @given(draw_token_text_valid_tokens(), draw_token_not_starttext()) def test_parse2_text_invalid_nostarttext(tokens, not_starttext): new_tokens = [not_starttext] + tokens[1:0] parent_context = static_parse_context() context = ParseContext(ParseTask.PARSE_TEXT, new_tokens[0], parent_context) error = ParseErrorException( ParseError.WRONG_TOKEN, not_starttext, "StartText", context ) template_test_invalid(Parser().parse_text, parent_context, new_tokens, error) # Tests parsing empty text # We expect the following behaviour: # - Error if there is no StartText token at all # - Have ParseError.NO_TOKEN as the exception code # - Have ParseTask.PARSE_TEXT as the context's parse task def test_parse2_text_invalid_empty(): parent_context = static_parse_context() context = ParseContext(ParseTask.PARSE_TEXT, None, parent_context) error = ParseErrorException(ParseError.NO_TOKEN, None, None, context) template_test_invalid(Parser().parse_text, parent_context, [], error) # Tests parsing text with a StartText token in it # We expect the following behaviour: # - Error if a StartText token is in the text content # - Have ParseError.FOUND_STARTTEXT as the exception code # - Have ParseTask.PARSE_TEXT as the context's parse task @given(draw_random_within(draw_token_text_valid_tokens(), "StartText")) def test_parse2_text_invalid_extrastarttext(within): (tokens, start) = within parent_context = static_parse_context() context = ParseContext(ParseTask.PARSE_TEXT, tokens[0], parent_context) error = ParseErrorException(ParseError.FOUND_STARTTEXT, start, None, context) template_test_invalid(Parser().parse_text, parent_context, tokens, error) # Tests parsing text without an EndText token # We expect the following behaviour: # - Error if there is no EndText token at all # - Have ParseError.NO_TOKEN as the exception code # - Have ParseTask.PARSE_TEXT as the context's parse task @given(draw_token_text_valid_tokens()) def test_parse2_text_invalid_noendtext(tokens): new_tokens = tokens[0:-1] parent_context = static_parse_context() context = ParseContext(ParseTask.PARSE_TEXT, tokens[0], parent_context) error = ParseErrorException(ParseError.NO_TOKEN, None, None, context) template_test_invalid(Parser().parse_text, parent_context, new_tokens, error)