Merge branch 'main' into patch-1

This commit is contained in:
Buck Evan 2024-01-19 11:11:04 -06:00 committed by GitHub
commit e93f6cc2ad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 33 additions and 19 deletions

View File

@ -0,0 +1 @@
Properly escape the ``reason`` of a :ref:`skip <pytest.mark.skip ref>` mark when writing JUnit XML files.

View File

@ -46,24 +46,18 @@ Plugin discovery order at tool startup
5. by loading all plugins specified through the :envvar:`PYTEST_PLUGINS` environment variable. 5. by loading all plugins specified through the :envvar:`PYTEST_PLUGINS` environment variable.
6. by loading all :file:`conftest.py` files as inferred by the command line 6. by loading all "initial ":file:`conftest.py` files:
invocation:
- if no test paths are specified, use the current dir as a test path - determine the test paths: specified on the command line, otherwise in
- if exists, load ``conftest.py`` and ``test*/conftest.py`` relative :confval:`testpaths` if defined and running from the rootdir, otherwise the
to the directory part of the first test path. After the ``conftest.py`` current dir
file is loaded, load all plugins specified in its - for each test path, load ``conftest.py`` and ``test*/conftest.py`` relative
:globalvar:`pytest_plugins` variable if present. to the directory part of the test path, if exist. Before a ``conftest.py``
file is loaded, load ``conftest.py`` files in all of its parent directories.
Note that pytest does not find ``conftest.py`` files in deeper nested After a ``conftest.py`` file is loaded, recursively load all plugins specified
sub directories at tool startup. It is usually a good idea to keep in its :globalvar:`pytest_plugins` variable if present.
your ``conftest.py`` file in the top level test or project root directory.
7. by recursively loading all plugins specified by the
:globalvar:`pytest_plugins` variable in ``conftest.py`` files.
.. _`pytest/plugin`: http://bitbucket.org/pytest-dev/pytest/src/tip/pytest/plugin/
.. _`conftest.py plugins`: .. _`conftest.py plugins`:
.. _`localplugin`: .. _`localplugin`:
.. _`local conftest plugins`: .. _`local conftest plugins`:
@ -108,9 +102,9 @@ Here is how you might run it::
See also: :ref:`pythonpath`. See also: :ref:`pythonpath`.
.. note:: .. note::
Some hooks should be implemented only in plugins or conftest.py files situated at the Some hooks cannot be implemented in conftest.py files which are not
tests root directory due to how pytest discovers plugins during startup, :ref:`initial <pluginorder>` due to how pytest discovers plugins during
see the documentation of each hook for details. startup. See the documentation of each hook for details.
Writing your own plugin Writing your own plugin
----------------------- -----------------------

View File

@ -248,7 +248,9 @@ class _NodeReporter:
skipreason = skipreason[9:] skipreason = skipreason[9:]
details = f"{filename}:{lineno}: {skipreason}" details = f"{filename}:{lineno}: {skipreason}"
skipped = ET.Element("skipped", type="pytest.skip", message=skipreason) skipped = ET.Element(
"skipped", type="pytest.skip", message=bin_xml_escape(skipreason)
)
skipped.text = bin_xml_escape(details) skipped.text = bin_xml_escape(details)
self.append(skipped) self.append(skipped)
self.write_captured_output(report) self.write_captured_output(report)

View File

@ -1653,6 +1653,23 @@ def test_escaped_skipreason_issue3533(
snode.assert_attr(message="1 <> 2") snode.assert_attr(message="1 <> 2")
def test_bin_escaped_skipreason(pytester: Pytester, run_and_parse: RunAndParse) -> None:
"""Escape special characters from mark.skip reason (#11842)."""
pytester.makepyfile(
"""
import pytest
@pytest.mark.skip("\33[31;1mred\33[0m")
def test_skip():
pass
"""
)
_, dom = run_and_parse()
node = dom.find_first_by_tag("testcase")
snode = node.find_first_by_tag("skipped")
assert "#x1B[31;1mred#x1B[0m" in snode.text
snode.assert_attr(message="#x1B[31;1mred#x1B[0m")
def test_escaped_setup_teardown_error( def test_escaped_setup_teardown_error(
pytester: Pytester, run_and_parse: RunAndParse pytester: Pytester, run_and_parse: RunAndParse
) -> None: ) -> None: