Newer
Older
NewLang / tests / parse / test_bool.py
# SPDX-License-Identifier: LGPL-2.1-only
# Copyright 2022 Jookia <contact@jookia.org>

from hypothesis import assume, given
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.test_parse import draw_parse_context
from tests.test_syntax import draw_token_bool, draw_syntax_random


# Draws tokens to make a valid boolean
@composite
def draw_syntax_bool_valid(draw):
    token = draw(draw_token_bool())
    value = token.value == "True"
    result = Syntax(value, token.location, SyntaxType.BOOL)
    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


# Generate an invalid boolean
# We expect the following behaviour:
# - 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):
    parent_context = draw(draw_parse_context())
    if draw(booleans()):
        token = draw(draw_syntax_random())
        assume(
            not (token.type == SyntaxType.TOKEN and token.value in ["True", "False"])
        )
        context = ParseContext(ParseTask.PARSE_BOOL, token, parent_context)
        if token.type == SyntaxType.TOKEN:
            error = ParseErrorException(ParseError.NOT_BOOL, token, None, context)
        else:
            error = ParseErrorException(ParseError.NOT_TOKEN, token, None, context)
        return ([token], error, parent_context)
    else:
        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