From 0c1557e79aed9b1f32dd9a301afb831d76dcdc97 Mon Sep 17 00:00:00 2001 From: Gleb Nikonorov Date: Sun, 31 May 2020 16:34:00 -0400 Subject: [PATCH 1/4] Fix crash that happened under --runxfail -o empty_parameter_set_mark=xfail --- src/_pytest/mark/structures.py | 5 ++++- testing/test_mark.py | 14 +++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index a34a0c28d..223f0381d 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -37,7 +37,10 @@ def get_empty_parameterset_mark(config, argnames, func): if requested_mark in ("", None, "skip"): mark = MARK_GEN.skip elif requested_mark == "xfail": - mark = MARK_GEN.xfail(run=False) + if config.getoption("runxfail", default=False): + mark = MARK_GEN.skip + else: + mark = MARK_GEN.xfail(run=False) elif requested_mark == "fail_at_collect": f_name = func.__name__ _, lineno = getfslineno(func) diff --git a/testing/test_mark.py b/testing/test_mark.py index c14f770da..134b53e47 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -885,15 +885,19 @@ class TestMarkDecorator: assert md.kwargs == {"three": 3} -@pytest.mark.parametrize("mark", [None, "", "skip", "xfail"]) -def test_parameterset_for_parametrize_marks(testdir, mark): +@pytest.mark.parametrize( + "mark, addopts", + [(None, ""), ("", ""), ("skip", ""), ("xfail", ""), ("xfail", "--runxfail")], +) +def test_parameterset_for_parametrize_marks(testdir, mark, addopts): if mark is not None: testdir.makeini( """ [pytest] {}={} + addopts={} """.format( - EMPTY_PARAMETERSET_OPTION, mark + EMPTY_PARAMETERSET_OPTION, mark, addopts ) ) @@ -902,7 +906,7 @@ def test_parameterset_for_parametrize_marks(testdir, mark): pytest_configure(config) result_mark = get_empty_parameterset_mark(config, ["a"], all) - if mark in (None, ""): + if mark in (None, "") or (mark == "xfail" and addopts == "--runxfail"): # normalize to the requested name mark = "skip" assert result_mark.name == mark @@ -955,7 +959,7 @@ def test_parameterset_for_fail_at_collect(testdir): def test_parameterset_for_parametrize_bad_markname(testdir): with pytest.raises(pytest.UsageError): - test_parameterset_for_parametrize_marks(testdir, "bad") + test_parameterset_for_parametrize_marks(testdir, "bad", False) def test_mark_expressions_no_smear(testdir): From feeddb9882a64073fc20f64b2dccc8003bc57740 Mon Sep 17 00:00:00 2001 From: Gleb Nikonorov Date: Thu, 4 Jun 2020 00:02:18 -0400 Subject: [PATCH 2/4] proper solution --- src/_pytest/fixtures.py | 2 +- src/_pytest/mark/structures.py | 5 +---- testing/test_mark.py | 14 +++++--------- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/_pytest/fixtures.py b/src/_pytest/fixtures.py index 82a148127..d04a613a4 100644 --- a/src/_pytest/fixtures.py +++ b/src/_pytest/fixtures.py @@ -302,7 +302,7 @@ def fillfixtures(function): def get_direct_param_fixture_func(request): - return request.param + return request.param if hasattr(request, "param") else None @attr.s(slots=True) diff --git a/src/_pytest/mark/structures.py b/src/_pytest/mark/structures.py index 223f0381d..a34a0c28d 100644 --- a/src/_pytest/mark/structures.py +++ b/src/_pytest/mark/structures.py @@ -37,10 +37,7 @@ def get_empty_parameterset_mark(config, argnames, func): if requested_mark in ("", None, "skip"): mark = MARK_GEN.skip elif requested_mark == "xfail": - if config.getoption("runxfail", default=False): - mark = MARK_GEN.skip - else: - mark = MARK_GEN.xfail(run=False) + mark = MARK_GEN.xfail(run=False) elif requested_mark == "fail_at_collect": f_name = func.__name__ _, lineno = getfslineno(func) diff --git a/testing/test_mark.py b/testing/test_mark.py index 134b53e47..c14f770da 100644 --- a/testing/test_mark.py +++ b/testing/test_mark.py @@ -885,19 +885,15 @@ class TestMarkDecorator: assert md.kwargs == {"three": 3} -@pytest.mark.parametrize( - "mark, addopts", - [(None, ""), ("", ""), ("skip", ""), ("xfail", ""), ("xfail", "--runxfail")], -) -def test_parameterset_for_parametrize_marks(testdir, mark, addopts): +@pytest.mark.parametrize("mark", [None, "", "skip", "xfail"]) +def test_parameterset_for_parametrize_marks(testdir, mark): if mark is not None: testdir.makeini( """ [pytest] {}={} - addopts={} """.format( - EMPTY_PARAMETERSET_OPTION, mark, addopts + EMPTY_PARAMETERSET_OPTION, mark ) ) @@ -906,7 +902,7 @@ def test_parameterset_for_parametrize_marks(testdir, mark, addopts): pytest_configure(config) result_mark = get_empty_parameterset_mark(config, ["a"], all) - if mark in (None, "") or (mark == "xfail" and addopts == "--runxfail"): + if mark in (None, ""): # normalize to the requested name mark = "skip" assert result_mark.name == mark @@ -959,7 +955,7 @@ def test_parameterset_for_fail_at_collect(testdir): def test_parameterset_for_parametrize_bad_markname(testdir): with pytest.raises(pytest.UsageError): - test_parameterset_for_parametrize_marks(testdir, "bad", False) + test_parameterset_for_parametrize_marks(testdir, "bad") def test_mark_expressions_no_smear(testdir): From 2d7eb039c3e5a2476947086a439103c79b813d01 Mon Sep 17 00:00:00 2001 From: Gleb Nikonorov Date: Thu, 4 Jun 2020 00:52:26 -0400 Subject: [PATCH 3/4] add test --- testing/test_skipping.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/testing/test_skipping.py b/testing/test_skipping.py index f48e78364..64eda03ae 100644 --- a/testing/test_skipping.py +++ b/testing/test_skipping.py @@ -475,6 +475,41 @@ class TestXFail: result.stdout.fnmatch_lines(["*1 passed*"]) assert result.ret == 0 + @pytest.mark.parametrize("strict", [True, False]) + def test_runxfail_with_empty_parameter_set_mark_xfail(self, testdir, strict): + testdir.makeini( + """ + [pytest] + xfail_strict = %s + """ + % strict + ) + + p = testdir.makepyfile( + """ + import pytest + + @pytest.mark.parametrize( + ('a', 'b'), + # no cases defined yet + ( + ), + ) + def test(a, b): + assert 1 == 1 + """ + ) + result = testdir.runpytest( + p, "--runxfail", "-o", "empty_parameter_set_mark=xfail" + ) + + result.stdout.fnmatch_lines(["*1 failed*" if strict else "*1 passed*"]) + if strict: + result.stdout.fnmatch_lines( + ["*XPASS(strict)] got empty parameter set ('a', 'b')*"] + ) + assert result.ret == (1 if strict else 0) + @pytest.mark.parametrize("strict_val", ["true", "false"]) def test_strict_xfail_default_from_file(self, testdir, strict_val): testdir.makeini( From fd477f1a3b9f70d27046482a05da76a27cb2add9 Mon Sep 17 00:00:00 2001 From: Gleb Nikonorov Date: Thu, 4 Jun 2020 00:55:23 -0400 Subject: [PATCH 4/4] add a changelog entry --- changelog/4497.bugfix.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/4497.bugfix.rst diff --git a/changelog/4497.bugfix.rst b/changelog/4497.bugfix.rst new file mode 100644 index 000000000..f2e71218e --- /dev/null +++ b/changelog/4497.bugfix.rst @@ -0,0 +1 @@ +Fix the crash that occurred when pytest was invoked with `-o empty_parameter_set_mark=xfail` + `--runxfail`