Merge branch 'master' into fix-flaky-test
This commit is contained in:
38
testing/io/test_wcwidth.py
Normal file
38
testing/io/test_wcwidth.py
Normal file
@@ -0,0 +1,38 @@
|
||||
import pytest
|
||||
from _pytest._io.wcwidth import wcswidth
|
||||
from _pytest._io.wcwidth import wcwidth
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("c", "expected"),
|
||||
[
|
||||
("\0", 0),
|
||||
("\n", -1),
|
||||
("a", 1),
|
||||
("1", 1),
|
||||
("א", 1),
|
||||
("\u200B", 0),
|
||||
("\u1ABE", 0),
|
||||
("\u0591", 0),
|
||||
("🉐", 2),
|
||||
("$", 2),
|
||||
],
|
||||
)
|
||||
def test_wcwidth(c: str, expected: int) -> None:
|
||||
assert wcwidth(c) == expected
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("s", "expected"),
|
||||
[
|
||||
("", 0),
|
||||
("hello, world!", 13),
|
||||
("hello, world!\n", -1),
|
||||
("0123456789", 10),
|
||||
("שלום, עולם!", 11),
|
||||
("שְבֻעָיים", 6),
|
||||
("🉐🉐🉐", 6),
|
||||
],
|
||||
)
|
||||
def test_wcswidth(s: str, expected: int) -> None:
|
||||
assert wcswidth(s) == expected
|
||||
@@ -3,6 +3,7 @@ import os
|
||||
import re
|
||||
|
||||
import pytest
|
||||
from _pytest.pytester import Testdir
|
||||
|
||||
|
||||
def test_nothing_logged(testdir):
|
||||
@@ -1101,3 +1102,48 @@ def test_colored_ansi_esc_caplogtext(testdir):
|
||||
)
|
||||
result = testdir.runpytest("--log-level=INFO", "--color=yes")
|
||||
assert result.ret == 0
|
||||
|
||||
|
||||
def test_logging_emit_error(testdir: Testdir) -> None:
|
||||
"""
|
||||
An exception raised during emit() should fail the test.
|
||||
|
||||
The default behavior of logging is to print "Logging error"
|
||||
to stderr with the call stack and some extra details.
|
||||
|
||||
pytest overrides this behavior to propagate the exception.
|
||||
"""
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
import logging
|
||||
|
||||
def test_bad_log():
|
||||
logging.warning('oops', 'first', 2)
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest()
|
||||
result.assert_outcomes(failed=1)
|
||||
result.stdout.fnmatch_lines(
|
||||
[
|
||||
"====* FAILURES *====",
|
||||
"*not all arguments converted during string formatting*",
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def test_logging_emit_error_supressed(testdir: Testdir) -> None:
|
||||
"""
|
||||
If logging is configured to silently ignore errors, pytest
|
||||
doesn't propagate errors either.
|
||||
"""
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
import logging
|
||||
|
||||
def test_bad_log(monkeypatch):
|
||||
monkeypatch.setattr(logging, 'raiseExceptions', False)
|
||||
logging.warning('oops', 'first', 2)
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest()
|
||||
result.assert_outcomes(passed=1)
|
||||
|
||||
@@ -1251,7 +1251,7 @@ def test_syntax_error_with_non_ascii_chars(testdir):
|
||||
result.stdout.fnmatch_lines(["*ERROR collecting*", "*SyntaxError*", "*1 error in*"])
|
||||
|
||||
|
||||
def test_collecterror_with_fulltrace(testdir):
|
||||
def test_collect_error_with_fulltrace(testdir):
|
||||
testdir.makepyfile("assert 0")
|
||||
result = testdir.runpytest("--fulltrace")
|
||||
result.stdout.fnmatch_lines(
|
||||
@@ -1259,15 +1259,12 @@ def test_collecterror_with_fulltrace(testdir):
|
||||
"collected 0 items / 1 error",
|
||||
"",
|
||||
"*= ERRORS =*",
|
||||
"*_ ERROR collecting test_collecterror_with_fulltrace.py _*",
|
||||
"",
|
||||
"*/_pytest/python.py:*: ",
|
||||
"_ _ _ _ _ _ _ _ *",
|
||||
"*_ ERROR collecting test_collect_error_with_fulltrace.py _*",
|
||||
"",
|
||||
"> assert 0",
|
||||
"E assert 0",
|
||||
"",
|
||||
"test_collecterror_with_fulltrace.py:1: AssertionError",
|
||||
"test_collect_error_with_fulltrace.py:1: AssertionError",
|
||||
"*! Interrupted: 1 error during collection !*",
|
||||
]
|
||||
)
|
||||
|
||||
@@ -19,16 +19,28 @@ from _pytest.config import ExitCode
|
||||
# pylib 1.4.20.dev2 (rev 13d9af95547e)
|
||||
|
||||
|
||||
def StdCaptureFD(out=True, err=True, in_=True):
|
||||
return capture.MultiCapture(out, err, in_, Capture=capture.FDCapture)
|
||||
def StdCaptureFD(out: bool = True, err: bool = True, in_: bool = True) -> MultiCapture:
|
||||
return capture.MultiCapture(
|
||||
in_=capture.FDCapture(0) if in_ else None,
|
||||
out=capture.FDCapture(1) if out else None,
|
||||
err=capture.FDCapture(2) if err else None,
|
||||
)
|
||||
|
||||
|
||||
def StdCapture(out=True, err=True, in_=True):
|
||||
return capture.MultiCapture(out, err, in_, Capture=capture.SysCapture)
|
||||
def StdCapture(out: bool = True, err: bool = True, in_: bool = True) -> MultiCapture:
|
||||
return capture.MultiCapture(
|
||||
in_=capture.SysCapture(0) if in_ else None,
|
||||
out=capture.SysCapture(1) if out else None,
|
||||
err=capture.SysCapture(2) if err else None,
|
||||
)
|
||||
|
||||
|
||||
def TeeStdCapture(out=True, err=True, in_=True):
|
||||
return capture.MultiCapture(out, err, in_, Capture=capture.TeeSysCapture)
|
||||
def TeeStdCapture(out: bool = True, err: bool = True, in_: bool = True) -> MultiCapture:
|
||||
return capture.MultiCapture(
|
||||
in_=capture.SysCapture(0, tee=True) if in_ else None,
|
||||
out=capture.SysCapture(1, tee=True) if out else None,
|
||||
err=capture.SysCapture(2, tee=True) if err else None,
|
||||
)
|
||||
|
||||
|
||||
class TestCaptureManager:
|
||||
@@ -866,9 +878,8 @@ class TestFDCapture:
|
||||
cap = capture.FDCapture(fd)
|
||||
data = b"hello"
|
||||
os.write(fd, data)
|
||||
s = cap.snap()
|
||||
pytest.raises(AssertionError, cap.snap)
|
||||
cap.done()
|
||||
assert not s
|
||||
cap = capture.FDCapture(fd)
|
||||
cap.start()
|
||||
os.write(fd, data)
|
||||
@@ -889,7 +900,7 @@ class TestFDCapture:
|
||||
fd = tmpfile.fileno()
|
||||
cap = capture.FDCapture(fd)
|
||||
cap.done()
|
||||
pytest.raises(ValueError, cap.start)
|
||||
pytest.raises(AssertionError, cap.start)
|
||||
|
||||
def test_stderr(self):
|
||||
cap = capture.FDCapture(2)
|
||||
@@ -940,11 +951,11 @@ class TestFDCapture:
|
||||
assert s == "but now yes\n"
|
||||
cap.suspend()
|
||||
cap.done()
|
||||
pytest.raises(AttributeError, cap.suspend)
|
||||
pytest.raises(AssertionError, cap.suspend)
|
||||
|
||||
assert repr(cap) == (
|
||||
"<FDCapture 1 oldfd=<UNSET> _state='done' tmpfile={!r}>".format(
|
||||
cap.tmpfile
|
||||
"<FDCapture 1 oldfd={} _state='done' tmpfile={!r}>".format(
|
||||
cap.targetfd_save, cap.tmpfile
|
||||
)
|
||||
)
|
||||
# Should not crash with missing "_old".
|
||||
@@ -1142,6 +1153,7 @@ class TestStdCaptureFD(TestStdCapture):
|
||||
with lsof_check():
|
||||
for i in range(10):
|
||||
cap = StdCaptureFD()
|
||||
cap.start_capturing()
|
||||
cap.stop_capturing()
|
||||
|
||||
|
||||
@@ -1150,27 +1162,38 @@ class TestStdCaptureFDinvalidFD:
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
import os
|
||||
from fnmatch import fnmatch
|
||||
from _pytest import capture
|
||||
|
||||
def StdCaptureFD(out=True, err=True, in_=True):
|
||||
return capture.MultiCapture(out, err, in_, Capture=capture.FDCapture)
|
||||
return capture.MultiCapture(
|
||||
in_=capture.FDCapture(0) if in_ else None,
|
||||
out=capture.FDCapture(1) if out else None,
|
||||
err=capture.FDCapture(2) if err else None,
|
||||
)
|
||||
|
||||
def test_stdout():
|
||||
os.close(1)
|
||||
cap = StdCaptureFD(out=True, err=False, in_=False)
|
||||
assert repr(cap.out) == "<FDCapture 1 oldfd=<UNSET> _state=None tmpfile=<UNSET>>"
|
||||
assert fnmatch(repr(cap.out), "<FDCapture 1 oldfd=* _state='initialized' tmpfile=*>")
|
||||
cap.start_capturing()
|
||||
os.write(1, b"stdout")
|
||||
assert cap.readouterr() == ("stdout", "")
|
||||
cap.stop_capturing()
|
||||
|
||||
def test_stderr():
|
||||
os.close(2)
|
||||
cap = StdCaptureFD(out=False, err=True, in_=False)
|
||||
assert repr(cap.err) == "<FDCapture 2 oldfd=<UNSET> _state=None tmpfile=<UNSET>>"
|
||||
assert fnmatch(repr(cap.err), "<FDCapture 2 oldfd=* _state='initialized' tmpfile=*>")
|
||||
cap.start_capturing()
|
||||
os.write(2, b"stderr")
|
||||
assert cap.readouterr() == ("", "stderr")
|
||||
cap.stop_capturing()
|
||||
|
||||
def test_stdin():
|
||||
os.close(0)
|
||||
cap = StdCaptureFD(out=False, err=False, in_=True)
|
||||
assert repr(cap.in_) == "<FDCapture 0 oldfd=<UNSET> _state=None tmpfile=<UNSET>>"
|
||||
assert fnmatch(repr(cap.in_), "<FDCapture 0 oldfd=* _state='initialized' tmpfile=*>")
|
||||
cap.stop_capturing()
|
||||
"""
|
||||
)
|
||||
@@ -1178,6 +1201,37 @@ class TestStdCaptureFDinvalidFD:
|
||||
assert result.ret == 0
|
||||
assert result.parseoutcomes()["passed"] == 3
|
||||
|
||||
def test_fdcapture_invalid_fd_with_fd_reuse(self, testdir):
|
||||
with saved_fd(1):
|
||||
os.close(1)
|
||||
cap = capture.FDCaptureBinary(1)
|
||||
cap.start()
|
||||
os.write(1, b"started")
|
||||
cap.suspend()
|
||||
os.write(1, b" suspended")
|
||||
cap.resume()
|
||||
os.write(1, b" resumed")
|
||||
assert cap.snap() == b"started resumed"
|
||||
cap.done()
|
||||
with pytest.raises(OSError):
|
||||
os.write(1, b"done")
|
||||
|
||||
def test_fdcapture_invalid_fd_without_fd_reuse(self, testdir):
|
||||
with saved_fd(1), saved_fd(2):
|
||||
os.close(1)
|
||||
os.close(2)
|
||||
cap = capture.FDCaptureBinary(2)
|
||||
cap.start()
|
||||
os.write(2, b"started")
|
||||
cap.suspend()
|
||||
os.write(2, b" suspended")
|
||||
cap.resume()
|
||||
os.write(2, b" resumed")
|
||||
assert cap.snap() == b"started resumed"
|
||||
cap.done()
|
||||
with pytest.raises(OSError):
|
||||
os.write(2, b"done")
|
||||
|
||||
|
||||
def test_capture_not_started_but_reset():
|
||||
capsys = StdCapture()
|
||||
@@ -1201,11 +1255,8 @@ def test_capsys_results_accessible_by_attribute(capsys):
|
||||
assert capture_result.err == "eggs"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("use", [True, False])
|
||||
def test_fdcapture_tmpfile_remains_the_same(tmpfile, use):
|
||||
if not use:
|
||||
tmpfile = True
|
||||
cap = StdCaptureFD(out=False, err=tmpfile)
|
||||
def test_fdcapture_tmpfile_remains_the_same() -> None:
|
||||
cap = StdCaptureFD(out=False, err=True)
|
||||
try:
|
||||
cap.start_capturing()
|
||||
capfile = cap.err.tmpfile
|
||||
@@ -1238,16 +1289,21 @@ def test_close_and_capture_again(testdir):
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("method", ["SysCapture", "FDCapture", "TeeSysCapture"])
|
||||
def test_capturing_and_logging_fundamentals(testdir, method):
|
||||
@pytest.mark.parametrize(
|
||||
"method", ["SysCapture(2)", "SysCapture(2, tee=True)", "FDCapture(2)"]
|
||||
)
|
||||
def test_capturing_and_logging_fundamentals(testdir, method: str) -> None:
|
||||
# here we check a fundamental feature
|
||||
p = testdir.makepyfile(
|
||||
"""
|
||||
import sys, os
|
||||
import py, logging
|
||||
from _pytest import capture
|
||||
cap = capture.MultiCapture(out=False, in_=False,
|
||||
Capture=capture.%s)
|
||||
cap = capture.MultiCapture(
|
||||
in_=None,
|
||||
out=None,
|
||||
err=capture.%s,
|
||||
)
|
||||
cap.start_capturing()
|
||||
|
||||
logging.warning("hello1")
|
||||
|
||||
@@ -147,6 +147,70 @@ class TestParseIni:
|
||||
result = testdir.inline_run("--confcutdir=.")
|
||||
assert result.ret == 0
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"ini_file_text, invalid_keys, stderr_output, exception_text",
|
||||
[
|
||||
(
|
||||
"""
|
||||
[pytest]
|
||||
unknown_ini = value1
|
||||
another_unknown_ini = value2
|
||||
""",
|
||||
["unknown_ini", "another_unknown_ini"],
|
||||
[
|
||||
"WARNING: Unknown config ini key: unknown_ini",
|
||||
"WARNING: Unknown config ini key: another_unknown_ini",
|
||||
],
|
||||
"Unknown config ini key: unknown_ini",
|
||||
),
|
||||
(
|
||||
"""
|
||||
[pytest]
|
||||
unknown_ini = value1
|
||||
minversion = 5.0.0
|
||||
""",
|
||||
["unknown_ini"],
|
||||
["WARNING: Unknown config ini key: unknown_ini"],
|
||||
"Unknown config ini key: unknown_ini",
|
||||
),
|
||||
(
|
||||
"""
|
||||
[some_other_header]
|
||||
unknown_ini = value1
|
||||
[pytest]
|
||||
minversion = 5.0.0
|
||||
""",
|
||||
[],
|
||||
[],
|
||||
"",
|
||||
),
|
||||
(
|
||||
"""
|
||||
[pytest]
|
||||
minversion = 5.0.0
|
||||
""",
|
||||
[],
|
||||
[],
|
||||
"",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_invalid_ini_keys(
|
||||
self, testdir, ini_file_text, invalid_keys, stderr_output, exception_text
|
||||
):
|
||||
testdir.tmpdir.join("pytest.ini").write(textwrap.dedent(ini_file_text))
|
||||
config = testdir.parseconfig()
|
||||
assert config._get_unknown_ini_keys() == invalid_keys, str(
|
||||
config._get_unknown_ini_keys()
|
||||
)
|
||||
|
||||
result = testdir.runpytest()
|
||||
result.stderr.fnmatch_lines(stderr_output)
|
||||
|
||||
if stderr_output:
|
||||
with pytest.raises(pytest.fail.Exception, match=exception_text):
|
||||
testdir.runpytest("--strict-config")
|
||||
|
||||
|
||||
class TestConfigCmdlineParsing:
|
||||
def test_parsing_again_fails(self, testdir):
|
||||
@@ -1243,9 +1307,7 @@ def test_help_and_version_after_argument_error(testdir):
|
||||
assert result.ret == ExitCode.USAGE_ERROR
|
||||
|
||||
result = testdir.runpytest("--version")
|
||||
result.stderr.fnmatch_lines(
|
||||
["*pytest*{}*imported from*".format(pytest.__version__)]
|
||||
)
|
||||
result.stderr.fnmatch_lines(["pytest {}".format(pytest.__version__)])
|
||||
assert result.ret == ExitCode.USAGE_ERROR
|
||||
|
||||
|
||||
|
||||
@@ -342,6 +342,15 @@ class TestPDB:
|
||||
child.sendeof()
|
||||
self.flush(child)
|
||||
|
||||
def test_pdb_prevent_ConftestImportFailure_hiding_exception(self, testdir):
|
||||
testdir.makepyfile("def test_func(): pass")
|
||||
sub_dir = testdir.tmpdir.join("ns").ensure_dir()
|
||||
sub_dir.join("conftest").new(ext=".py").write("import unknown")
|
||||
sub_dir.join("test_file").new(ext=".py").write("def test_func(): pass")
|
||||
|
||||
result = testdir.runpytest_subprocess("--pdb", ".")
|
||||
result.stdout.fnmatch_lines(["-> import unknown"])
|
||||
|
||||
def test_pdb_interaction_capturing_simple(self, testdir):
|
||||
p1 = testdir.makepyfile(
|
||||
"""
|
||||
|
||||
@@ -2,11 +2,10 @@ import pytest
|
||||
from _pytest.config import ExitCode
|
||||
|
||||
|
||||
def test_version(testdir, pytestconfig):
|
||||
def test_version_verbose(testdir, pytestconfig):
|
||||
testdir.monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD")
|
||||
result = testdir.runpytest("--version")
|
||||
result = testdir.runpytest("--version", "--version")
|
||||
assert result.ret == 0
|
||||
# p = py.path.local(py.__file__).dirpath()
|
||||
result.stderr.fnmatch_lines(
|
||||
["*pytest*{}*imported from*".format(pytest.__version__)]
|
||||
)
|
||||
@@ -14,6 +13,14 @@ def test_version(testdir, pytestconfig):
|
||||
result.stderr.fnmatch_lines(["*setuptools registered plugins:", "*at*"])
|
||||
|
||||
|
||||
def test_version_less_verbose(testdir, pytestconfig):
|
||||
testdir.monkeypatch.delenv("PYTEST_DISABLE_PLUGIN_AUTOLOAD")
|
||||
result = testdir.runpytest("--version")
|
||||
assert result.ret == 0
|
||||
# p = py.path.local(py.__file__).dirpath()
|
||||
result.stderr.fnmatch_lines(["pytest {}".format(pytest.__version__)])
|
||||
|
||||
|
||||
def test_help(testdir):
|
||||
result = testdir.runpytest("--help")
|
||||
assert result.ret == 0
|
||||
|
||||
@@ -58,3 +58,30 @@ def test__check_initialpaths_for_relpath():
|
||||
|
||||
outside = py.path.local("/outside")
|
||||
assert nodes._check_initialpaths_for_relpath(FakeSession, outside) is None
|
||||
|
||||
|
||||
def test_failure_with_changed_cwd(testdir):
|
||||
"""
|
||||
Test failure lines should use absolute paths if cwd has changed since
|
||||
invocation, so the path is correct (#6428).
|
||||
"""
|
||||
p = testdir.makepyfile(
|
||||
"""
|
||||
import os
|
||||
import pytest
|
||||
|
||||
@pytest.fixture
|
||||
def private_dir():
|
||||
out_dir = 'ddd'
|
||||
os.mkdir(out_dir)
|
||||
old_dir = os.getcwd()
|
||||
os.chdir(out_dir)
|
||||
yield out_dir
|
||||
os.chdir(old_dir)
|
||||
|
||||
def test_show_wrong_path(private_dir):
|
||||
assert False
|
||||
"""
|
||||
)
|
||||
result = testdir.runpytest()
|
||||
result.stdout.fnmatch_lines([str(p) + ":*: AssertionError", "*1 failed in *"])
|
||||
|
||||
@@ -5,6 +5,7 @@ import py
|
||||
|
||||
import pytest
|
||||
from _pytest.pathlib import fnmatch_ex
|
||||
from _pytest.pathlib import get_extended_length_path_str
|
||||
from _pytest.pathlib import get_lock_path
|
||||
from _pytest.pathlib import maybe_delete_a_numbered_dir
|
||||
from _pytest.pathlib import Path
|
||||
@@ -89,3 +90,26 @@ def test_access_denied_during_cleanup(tmp_path, monkeypatch):
|
||||
lock_path = get_lock_path(path)
|
||||
maybe_delete_a_numbered_dir(path)
|
||||
assert not lock_path.is_file()
|
||||
|
||||
|
||||
def test_long_path_during_cleanup(tmp_path):
|
||||
"""Ensure that deleting long path works (particularly on Windows (#6775))."""
|
||||
path = (tmp_path / ("a" * 250)).resolve()
|
||||
if sys.platform == "win32":
|
||||
# make sure that the full path is > 260 characters without any
|
||||
# component being over 260 characters
|
||||
assert len(str(path)) > 260
|
||||
extended_path = "\\\\?\\" + str(path)
|
||||
else:
|
||||
extended_path = str(path)
|
||||
os.mkdir(extended_path)
|
||||
assert os.path.isdir(extended_path)
|
||||
maybe_delete_a_numbered_dir(path)
|
||||
assert not os.path.isdir(extended_path)
|
||||
|
||||
|
||||
def test_get_extended_length_path_str():
|
||||
assert get_extended_length_path_str(r"c:\foo") == r"\\?\c:\foo"
|
||||
assert get_extended_length_path_str(r"\\share\foo") == r"\\?\UNC\share\foo"
|
||||
assert get_extended_length_path_str(r"\\?\UNC\share\foo") == r"\\?\UNC\share\foo"
|
||||
assert get_extended_length_path_str(r"\\?\c:\foo") == r"\\?\c:\foo"
|
||||
|
||||
@@ -396,6 +396,14 @@ class TestReportSerialization:
|
||||
# for same reasons as previous test, ensure we don't blow up here
|
||||
loaded_report.longrepr.toterminal(tw_mock)
|
||||
|
||||
def test_report_prevent_ConftestImportFailure_hiding_exception(self, testdir):
|
||||
sub_dir = testdir.tmpdir.join("ns").ensure_dir()
|
||||
sub_dir.join("conftest").new(ext=".py").write("import unknown")
|
||||
|
||||
result = testdir.runpytest_subprocess(".")
|
||||
result.stdout.fnmatch_lines(["E *Error: No module named 'unknown'"])
|
||||
result.stdout.no_fnmatch_line("ERROR - *ConftestImportFailure*")
|
||||
|
||||
|
||||
class TestHooks:
|
||||
"""Test that the hooks are working correctly for plugins"""
|
||||
|
||||
@@ -1002,6 +1002,17 @@ class TestReportContents:
|
||||
assert rep.capstdout == ""
|
||||
assert rep.capstderr == ""
|
||||
|
||||
def test_longrepr_type(self, testdir) -> None:
|
||||
reports = testdir.runitem(
|
||||
"""
|
||||
import pytest
|
||||
def test_func():
|
||||
pytest.fail(pytrace=False)
|
||||
"""
|
||||
)
|
||||
rep = reports[1]
|
||||
assert isinstance(rep.longrepr, _pytest._code.code.ExceptionRepr)
|
||||
|
||||
|
||||
def test_outcome_exception_bad_msg() -> None:
|
||||
"""Check that OutcomeExceptions validate their input to prevent confusing errors (#5578)"""
|
||||
|
||||
@@ -194,7 +194,7 @@ class TestXFail:
|
||||
assert len(reports) == 3
|
||||
callreport = reports[1]
|
||||
assert callreport.failed
|
||||
assert callreport.longrepr == "[XPASS(strict)] nope"
|
||||
assert str(callreport.longrepr) == "[XPASS(strict)] nope"
|
||||
assert not hasattr(callreport, "wasxfail")
|
||||
|
||||
def test_xfail_run_anyway(self, testdir):
|
||||
|
||||
@@ -14,7 +14,9 @@ import pluggy
|
||||
import py
|
||||
|
||||
import _pytest.config
|
||||
import _pytest.terminal
|
||||
import pytest
|
||||
from _pytest._io.wcwidth import wcswidth
|
||||
from _pytest.config import ExitCode
|
||||
from _pytest.pytester import Testdir
|
||||
from _pytest.reports import BaseReport
|
||||
@@ -2027,9 +2029,6 @@ def test_skip_reasons_folding():
|
||||
|
||||
|
||||
def test_line_with_reprcrash(monkeypatch):
|
||||
import _pytest.terminal
|
||||
from wcwidth import wcswidth
|
||||
|
||||
mocked_verbose_word = "FAILED"
|
||||
|
||||
mocked_pos = "some::nodeid"
|
||||
@@ -2079,19 +2078,19 @@ def test_line_with_reprcrash(monkeypatch):
|
||||
check("some\nmessage", 80, "FAILED some::nodeid - some")
|
||||
|
||||
# Test unicode safety.
|
||||
check("😄😄😄😄😄\n2nd line", 25, "FAILED some::nodeid - ...")
|
||||
check("😄😄😄😄😄\n2nd line", 26, "FAILED some::nodeid - ...")
|
||||
check("😄😄😄😄😄\n2nd line", 27, "FAILED some::nodeid - 😄...")
|
||||
check("😄😄😄😄😄\n2nd line", 28, "FAILED some::nodeid - 😄...")
|
||||
check("😄😄😄😄😄\n2nd line", 29, "FAILED some::nodeid - 😄😄...")
|
||||
check("🉐🉐🉐🉐🉐\n2nd line", 25, "FAILED some::nodeid - ...")
|
||||
check("🉐🉐🉐🉐🉐\n2nd line", 26, "FAILED some::nodeid - ...")
|
||||
check("🉐🉐🉐🉐🉐\n2nd line", 27, "FAILED some::nodeid - 🉐...")
|
||||
check("🉐🉐🉐🉐🉐\n2nd line", 28, "FAILED some::nodeid - 🉐...")
|
||||
check("🉐🉐🉐🉐🉐\n2nd line", 29, "FAILED some::nodeid - 🉐🉐...")
|
||||
|
||||
# NOTE: constructed, not sure if this is supported.
|
||||
mocked_pos = "nodeid::😄::withunicode"
|
||||
check("😄😄😄😄😄\n2nd line", 29, "FAILED nodeid::😄::withunicode")
|
||||
check("😄😄😄😄😄\n2nd line", 40, "FAILED nodeid::😄::withunicode - 😄😄...")
|
||||
check("😄😄😄😄😄\n2nd line", 41, "FAILED nodeid::😄::withunicode - 😄😄...")
|
||||
check("😄😄😄😄😄\n2nd line", 42, "FAILED nodeid::😄::withunicode - 😄😄😄...")
|
||||
check("😄😄😄😄😄\n2nd line", 80, "FAILED nodeid::😄::withunicode - 😄😄😄😄😄")
|
||||
mocked_pos = "nodeid::🉐::withunicode"
|
||||
check("🉐🉐🉐🉐🉐\n2nd line", 29, "FAILED nodeid::🉐::withunicode")
|
||||
check("🉐🉐🉐🉐🉐\n2nd line", 40, "FAILED nodeid::🉐::withunicode - 🉐🉐...")
|
||||
check("🉐🉐🉐🉐🉐\n2nd line", 41, "FAILED nodeid::🉐::withunicode - 🉐🉐...")
|
||||
check("🉐🉐🉐🉐🉐\n2nd line", 42, "FAILED nodeid::🉐::withunicode - 🉐🉐🉐...")
|
||||
check("🉐🉐🉐🉐🉐\n2nd line", 80, "FAILED nodeid::🉐::withunicode - 🉐🉐🉐🉐🉐")
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
||||
@@ -1193,6 +1193,40 @@ def test_pdb_teardown_called(testdir, monkeypatch):
|
||||
]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("mark", ["@unittest.skip", "@pytest.mark.skip"])
|
||||
def test_pdb_teardown_skipped(testdir, monkeypatch, mark):
|
||||
"""
|
||||
With --pdb, setUp and tearDown should not be called for skipped tests.
|
||||
"""
|
||||
tracked = []
|
||||
monkeypatch.setattr(pytest, "test_pdb_teardown_skipped", tracked, raising=False)
|
||||
|
||||
testdir.makepyfile(
|
||||
"""
|
||||
import unittest
|
||||
import pytest
|
||||
|
||||
class MyTestCase(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
pytest.test_pdb_teardown_skipped.append("setUp:" + self.id())
|
||||
|
||||
def tearDown(self):
|
||||
pytest.test_pdb_teardown_skipped.append("tearDown:" + self.id())
|
||||
|
||||
{mark}("skipped for reasons")
|
||||
def test_1(self):
|
||||
pass
|
||||
|
||||
""".format(
|
||||
mark=mark
|
||||
)
|
||||
)
|
||||
result = testdir.runpytest_inprocess("--pdb")
|
||||
result.stdout.fnmatch_lines("* 1 skipped in *")
|
||||
assert tracked == []
|
||||
|
||||
|
||||
def test_async_support(testdir):
|
||||
pytest.importorskip("unittest.async_case")
|
||||
|
||||
|
||||
@@ -268,9 +268,8 @@ def test_warning_captured_hook(testdir):
|
||||
collected = []
|
||||
|
||||
class WarningCollector:
|
||||
def pytest_warning_captured(self, warning_message, when, item):
|
||||
imge_name = item.name if item is not None else ""
|
||||
collected.append((str(warning_message.message), when, imge_name))
|
||||
def pytest_warning_recorded(self, warning_message, when, nodeid, location):
|
||||
collected.append((str(warning_message.message), when, nodeid, location))
|
||||
|
||||
result = testdir.runpytest(plugins=[WarningCollector()])
|
||||
result.stdout.fnmatch_lines(["*1 passed*"])
|
||||
@@ -278,11 +277,27 @@ def test_warning_captured_hook(testdir):
|
||||
expected = [
|
||||
("config warning", "config", ""),
|
||||
("collect warning", "collect", ""),
|
||||
("setup warning", "runtest", "test_func"),
|
||||
("call warning", "runtest", "test_func"),
|
||||
("teardown warning", "runtest", "test_func"),
|
||||
("setup warning", "runtest", "test_warning_captured_hook.py::test_func"),
|
||||
("call warning", "runtest", "test_warning_captured_hook.py::test_func"),
|
||||
("teardown warning", "runtest", "test_warning_captured_hook.py::test_func"),
|
||||
]
|
||||
assert collected == expected
|
||||
for index in range(len(expected)):
|
||||
collected_result = collected[index]
|
||||
expected_result = expected[index]
|
||||
|
||||
assert collected_result[0] == expected_result[0], str(collected)
|
||||
assert collected_result[1] == expected_result[1], str(collected)
|
||||
assert collected_result[2] == expected_result[2], str(collected)
|
||||
|
||||
# NOTE: collected_result[3] is location, which differs based on the platform you are on
|
||||
# thus, the best we can do here is assert the types of the paremeters match what we expect
|
||||
# and not try and preload it in the expected array
|
||||
if collected_result[3] is not None:
|
||||
assert type(collected_result[3][0]) is str, str(collected)
|
||||
assert type(collected_result[3][1]) is int, str(collected)
|
||||
assert type(collected_result[3][2]) is str, str(collected)
|
||||
else:
|
||||
assert collected_result[3] is None, str(collected)
|
||||
|
||||
|
||||
@pytest.mark.filterwarnings("always")
|
||||
@@ -649,7 +664,7 @@ class TestStackLevel:
|
||||
captured = []
|
||||
|
||||
@classmethod
|
||||
def pytest_warning_captured(cls, warning_message, when, item, location):
|
||||
def pytest_warning_recorded(cls, warning_message, when, nodeid, location):
|
||||
cls.captured.append((warning_message, location))
|
||||
|
||||
testdir.plugins = [CapturedWarnings()]
|
||||
|
||||
Reference in New Issue
Block a user