Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(pytest): add an assert_error plugin method #218

Merged
merged 2 commits into from
Nov 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions craft_cli/pytest_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@
import pathlib
import re
import tempfile
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, cast
from unittest.mock import call

import pytest

from craft_cli import messages, printer
from craft_cli import errors, messages, printer

if TYPE_CHECKING:
from unittest.mock import _Call
Expand Down Expand Up @@ -163,6 +163,18 @@ def assert_messages(self, texts):
"""
self.assert_interactions([call("message", text) for text in texts])

def assert_error(self, error: errors.CraftError) -> errors.CraftError:
"""Check that the 'error' method was called with the given error."""
# Error should be the last thing called, so start at the end.
errors_called = []
for stored_call in reversed(self.interactions):
if stored_call.args[0] != "error":
continue
errors_called.append(stored_call.args[1])
if stored_call.args[1] == error:
return cast(errors.CraftError, stored_call.args[1])
raise AssertionError(f"Error not emitted: {error!r}", errors_called[::-1])

def assert_interactions(self, expected_call_list):
"""Check that the expected call list happen at some point between all stored calls.

Expand Down Expand Up @@ -205,7 +217,7 @@ def advance(self, *a, **k):
def emitter(monkeypatch):
"""Provide a helper to test everything that was shown using the Emitter."""
recording_emitter = RecordingEmitter()
for method_name in ("message", "progress", "verbose", "debug", "trace"):
for method_name in ("message", "progress", "verbose", "debug", "trace", "error"):
monkeypatch.setattr(
messages.emit,
method_name,
Expand Down
40 changes: 38 additions & 2 deletions tests/test_pytest_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,13 @@
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

"""Test the fixtures provided by Craft CLI."""

import copy
from unittest.mock import call

import pytest

from craft_cli import messages, printer
from craft_cli import messages, printer, errors


# -- tests for the `init_emitter` auto-fixture

Expand Down Expand Up @@ -183,6 +184,41 @@ def test_emitter_messages(emitter):
)


@pytest.mark.parametrize(
"error",
[
errors.CraftError("Basic error"),
errors.CraftError("Detailed", details="Very detailed"),
errors.CraftError("Resolved", resolution="640x480"),
errors.CraftError("Documented", docs_url="https://docs.ubuntu.com"),
errors.CraftError("Detailed Resolved", details="Extra fine", resolution="3840x2160"),
],
)
def test_emitter_error_success(emitter, error):
"""Verify that the checking the emitter for the correct error succeeds."""
error_copy = copy.deepcopy(error) # Ensure we're not just checking identity.
messages.emit.error(error)
assert emitter.assert_error(error_copy) is error


@pytest.mark.parametrize(
("error", "assert_error"),
[
(errors.CraftError("Basic"), errors.CraftError("Very basic")),
(
errors.CraftError("Detailed", details="Case sensitive"),
errors.CraftError("Detailed", details="case Sensitive"),
),
],
)
def test_emitter_error_failure(emitter, error, assert_error):
"""Verify that checking the emitter for the wrong error fails."""
messages.emit.error(error)
with pytest.raises(AssertionError, match="Error not emitted:") as exc_info:
emitter.assert_error(assert_error)
assert exc_info.value.args[1] == [error]


def test_emitter_interactions_positive_complete(emitter):
"""All interactions can be verified, complete."""
messages.emit.progress("foo")
Expand Down
Loading