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

from hypothesis import given
from hypothesis.strategies import (
    composite,
    lists,
    sampled_from,
    text,
)

from src.parse import (
    NoteSkipper,
    ParseError,
    ParseErrorException,
    ParseTask,
    ParseContext,
    parse,
)
from src.syntax import SyntaxStream
from tests.test_syntax import draw_token_classified, draw_syntax_random


# Draws a random parse task
@composite
def draw_parse_task(draw):
    return draw(sampled_from(list(ParseTask)))


# Draws a random parse context with a dummy parent
@composite
def draw_parse_context(draw):
    task = draw(draw_parse_task())
    syntax = draw(draw_syntax_random())
    parent = draw(text())
    return ParseContext(task, syntax, parent)


# Test parse context getters
@given(draw_parse_task(), draw_syntax_random(), text())
def test_parse_context_getters(task, syntax, parent):
    test = ParseContext(task, syntax, parent)
    assert test.task == task
    assert test.syntax == syntax
    assert test.parent == parent


# Test parse context equals
@given(draw_parse_context(), draw_parse_context())
def test_parse_context_equality(context1, context2):
    equals = (
        context1.task == context2.task
        and context1.syntax == context2.syntax
        and context1.parent == context2.parent
    )
    assert (context1 == context2) == equals


# Draws a random parse error
@composite
def draw_parse_error(draw):
    return draw(sampled_from(list(ParseError)))


# Draws a random parse error exception
@composite
def draw_parse_error_exception(draw):
    error = draw(draw_parse_error())
    syntax = draw(draw_syntax_random())
    expected = draw(text())
    context = draw(draw_parse_context())
    return ParseErrorException(error, syntax, expected, context)


# Test parse error exception getters
@given(draw_parse_error(), draw_syntax_random(), text(), draw_parse_context())
def test_parse_error_getters(error, syntax, expected, context):
    test = ParseErrorException(error, syntax, expected, context)
    assert test.error == error
    assert test.syntax == syntax
    assert test.expected == expected
    assert test.context == context


# Test parse error exception equals
@given(draw_parse_error_exception(), draw_parse_error_exception())
def test_parse_error_equality(except1, except2):
    equals = (
        except1.error == except2.error
        and except1.syntax == except2.syntax
        and except1.expected == except2.expected
        and except1.context == except2.context
    )
    assert (except1 == except2) == equals


# Tests the parser wrapper works correctly
# We expect the following behaviour:
# - Notes to be removed from the tokens
@given(lists(draw_token_classified()), draw_parse_context())
def test_parse_fuzz(tokens, context):
    result = None
    try:
        stream = SyntaxStream(tokens.copy())
        result = NoteSkipper().clear_notes(stream, context)
    except ParseErrorException as e:
        result = e
    try:
        parsed = parse(tokens, context)
        assert parsed == result
    except ParseErrorException as e:
        assert e == result