Hide navigation sidebar
Hide table of contents sidebar
Skip to content
Back to top
Toggle table of contents sidebar

# Source code for betty.test_utils.assertion.error

    """
    Test utilities for :py:mod:`betty.assertion.error`.
    """

    from __future__ import annotations

    from contextlib import contextmanager
    from typing import overload, Any, Iterator, TYPE_CHECKING

    from betty.assertion.error import AssertionFailed, AssertionFailedGroup
    from betty.locale.localizer import DEFAULT_LOCALIZER

    if TYPE_CHECKING:
        from collections.abc import Iterable

    @overload
    def assert_error(
        actual_error: AssertionFailed | AssertionFailedGroup,
        *,
        error: AssertionFailed,
        error_type: None = None,
        error_message: None = None,
        error_contexts: None = None,
    ) -> list[AssertionFailed]:
        pass

    @overload
    def assert_error(
        actual_error: AssertionFailed | AssertionFailedGroup,
        *,
        error: None = None,
        error_type: type[AssertionFailed] = AssertionFailed,
        error_message: str | None = None,
        error_contexts: list[str] | None = None,
    ) -> list[AssertionFailed]:
        pass

    def assert_error(
        actual_error: AssertionFailed | AssertionFailedGroup,
        *,
        error: AssertionFailed | None = None,
        error_type: type[AssertionFailed] | None = AssertionFailed,
        error_message: str | None = None,
        error_contexts: list[str] | None = None,
    ) -> list[AssertionFailed]:
        """
        Assert that an error group contains an error matching the given parameters.
        """
        expected_error_contexts: list[str] | None
        actual_errors: Iterable[AssertionFailed]
        if isinstance(actual_error, AssertionFailedGroup):
            actual_errors = [*actual_error]
        else:
            actual_errors = [actual_error]

        expected_error_type: type
        expected_error_message = None
        expected_error_contexts = None
        if error:
            expected_error_type = type(error)
            expected_error_message = str(error)
            expected_error_contexts = [
                error.localize(DEFAULT_LOCALIZER) for error in error.contexts
            ]
        else:
            expected_error_type = error_type  # type: ignore[assignment]
            if error_message is not None:
                expected_error_message = error_message
            if error_contexts is not None:
                expected_error_contexts = error_contexts

        errors = [
            actual_error
            for actual_error in actual_errors
            if isinstance(actual_error, expected_error_type)
        ]
        if expected_error_message is not None:
            errors = [
                actual_error
                for actual_error in actual_errors
                if str(actual_error).startswith(expected_error_message)
            ]
        if expected_error_contexts is not None:
            errors = [
                actual_error
                for actual_error in actual_errors
                if expected_error_contexts
                == [error.localize(DEFAULT_LOCALIZER) for error in actual_error.contexts]
            ]
        if errors:
            return errors
        raise AssertionError("Failed raising a serialization or deserialization error.")

    @contextmanager
    def raises_error(*args: Any, **kwargs: Any) -> Iterator[AssertionFailedGroup]:
        """
        Provide a context manager to assert that an error group contains an error matching the given parameters.
        """
        try:
            with AssertionFailedGroup().catch() as errors:
                yield errors
        finally:
            assert_error(errors, *args, **kwargs)
            errors.assert_valid()