1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
|
"""Tests for xfail support."""
import os
import signal
import pytest
IS_PYTEST4_PLUS = int(pytest.__version__[0]) >= 4 # noqa: WPS609
FAILED_WORD = "FAILED" if IS_PYTEST4_PLUS else "FAIL"
PYTEST_GTE_7_2 = hasattr(pytest, "version_tuple") and pytest.version_tuple >= (7, 2) # type: ignore[attr-defined]
PYTEST_GTE_8_0 = hasattr(pytest, "version_tuple") and pytest.version_tuple >= (8, 0) # type: ignore[attr-defined]
PYTEST_GTE_9_0 = hasattr(pytest, "version_tuple") and pytest.version_tuple >= (9, 0) # type: ignore[attr-defined]
pytestmark = pytest.mark.skipif( # pylint: disable=invalid-name
not hasattr(os, "fork"), # noqa: WPS421
reason="os.fork required",
)
@pytest.mark.parametrize(
("is_crashing", "is_strict"),
(
pytest.param(True, True, id="strict xfail"),
pytest.param(False, True, id="strict xpass"),
pytest.param(True, False, id="non-strict xfail"),
pytest.param(False, False, id="non-strict xpass"),
),
)
def test_xfail(is_crashing, is_strict, testdir):
"""Test xfail/xpass/strict permutations."""
# pylint: disable=possibly-unused-variable
sig_num = signal.SIGTERM.numerator
test_func_body = (
"os.kill(os.getpid(), signal.SIGTERM)" if is_crashing else "assert True"
)
if is_crashing:
# marked xfailed and crashing, no matter strict or not
expected_letter = "x" # XFAILED
expected_lowercase = "xfailed"
expected_word = "XFAIL"
elif is_strict:
# strict and not failing as expected should cause failure
expected_letter = "F" # FAILED
expected_lowercase = "failed"
expected_word = FAILED_WORD
elif not is_strict:
# non-strict and not failing as expected should cause xpass
expected_letter = "X" # XPASS
expected_lowercase = "xpassed"
expected_word = "XPASS"
session_start_title = "*==== test session starts ====*"
loaded_pytest_plugins = "plugins:* forked*"
collected_tests_num = "collected 1 item"
expected_progress = f"test_xfail.py {expected_letter!s}*"
failures_title = "*==== FAILURES ====*"
failures_test_name = "*____ test_function ____*"
failures_test_reason = "[XPASS(strict)] The process gets terminated"
short_test_summary_title = "*==== short test summary info ====*"
short_test_summary = f"{expected_word!s} test_xfail.py::test_function"
if expected_lowercase == "xpassed":
# XPASS wouldn't have the crash message from
# pytest-forked because the crash doesn't happen
if PYTEST_GTE_8_0:
short_test_summary += " -"
short_test_summary += " The process gets terminated"
reason_string = (
f"reason: The process gets terminated; "
f"pytest-forked reason: "
f"*:*: running the test CRASHED with signal {sig_num:d}"
)
if expected_lowercase == "xfailed" and PYTEST_GTE_7_2:
short_test_summary += " - " + reason_string
if expected_lowercase == "failed" and PYTEST_GTE_9_0:
short_test_summary += " - [XPASS(strict)] The process gets termin..."
total_summary_line = f"*==== 1 {expected_lowercase!s} in 0.*s* ====*"
expected_lines = (
session_start_title,
loaded_pytest_plugins,
collected_tests_num,
expected_progress,
)
if expected_word == FAILED_WORD:
# XPASS(strict)
expected_lines += (
failures_title,
failures_test_name,
failures_test_reason,
)
expected_lines += (
short_test_summary_title,
short_test_summary,
)
if expected_lowercase == "xpassed" and expected_word == FAILED_WORD:
# XPASS(strict)
expected_lines += (" " + reason_string,)
expected_lines += (total_summary_line,)
test_module = testdir.makepyfile(
f"""
import os
import signal
import pytest
# The current implementation emits RuntimeWarning.
pytestmark = pytest.mark.filterwarnings('ignore:pytest-forked xfail')
@pytest.mark.xfail(
reason='The process gets terminated',
strict={is_strict!s},
)
@pytest.mark.forked
def test_function():
{test_func_body!s}
"""
)
pytest_run_result = testdir.runpytest(test_module, "-ra")
pytest_run_result.stdout.fnmatch_lines(expected_lines)
|