diff --git a/AUTHORS b/AUTHORS index 8a6f5ee..4caf02b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -4,6 +4,7 @@ Contributors ------------ * Allison Karlitskaya +* Cody D'Ambrosio * Dan Dofter * Erik Cederstrand * Frédéric Mangano-Tarumi diff --git a/conftest.py b/conftest.py index 23c5555..2fe0329 100644 --- a/conftest.py +++ b/conftest.py @@ -8,11 +8,17 @@ def sample_test_file(testdir): testdir.makepyfile( """ import pytest + import logging + + LOGGER = logging.getLogger(__name__) def test_ok(): + LOGGER.info("Running test_ok") + LOGGER.debug("Debug logging info") assert True def test_not_ok(): + LOGGER.error("Running test_not_ok") assert False @pytest.mark.parametrize('param', ("foo", "bar")) diff --git a/setup.py b/setup.py index 1c809e0..fb9cb4a 100644 --- a/setup.py +++ b/setup.py @@ -35,7 +35,7 @@ include_package_data=True, zip_safe=False, platforms="any", - install_requires=["pytest>=3.0", "tap.py>=3.0,<4.0"], + install_requires=["pytest>=3.0", "tap.py>=3.2,<4.0"], classifiers=[ "Development Status :: 5 - Production/Stable", "Framework :: Pytest", diff --git a/src/pytest_tap/plugin.py b/src/pytest_tap/plugin.py index 95e40e5..08a8121 100644 --- a/src/pytest_tap/plugin.py +++ b/src/pytest_tap/plugin.py @@ -5,6 +5,10 @@ from tap.formatter import format_as_diagnostics from tap.tracker import Tracker +SHOW_CAPTURE_LOG = ("log", "all") +SHOW_CAPTURE_OUT = ("stdout", "all") +SHOW_CAPTUER_ERR = ("stderr", "all") + class TAPPlugin: def __init__(self, config: pytest.Config) -> None: @@ -25,6 +29,9 @@ def __init__(self, config: pytest.Config) -> None: # Disable it automatically for streaming. self._tracker.header = False + self.tap_logging = config.option.showcapture + self.tap_log_passing_tests = config.option.tap_log_passing_tests + @pytest.hookimpl() def pytest_runtestloop(self, session): """Output the plan line first.""" @@ -70,9 +77,12 @@ def pytest_runtest_logreport(self, report: pytest.TestReport): directive = "TODO unexpected success{}".format(reason) self._tracker.add_ok(testcase, description, directive=directive) elif report.passed: - self._tracker.add_ok(testcase, description) + diagnostics = None + if self.tap_log_passing_tests: + diagnostics = _make_as_diagnostics(report, self.tap_logging) + self._tracker.add_ok(testcase, description, diagnostics=diagnostics) elif report.failed: - diagnostics = _make_as_diagnostics(report) + diagnostics = _make_as_diagnostics(report, self.tap_logging) # pytest treats an unexpected success from unitest.expectedFailure # as a failure. @@ -143,6 +153,12 @@ def pytest_addoption(parser): "If the directory does not exist, it will be created." ), ) + group.addoption( + "--tap-log-passing-tests", + default=False, + action="store_true", + help="Capture log information for passing tests to TAP report", + ) @pytest.hookimpl(trylast=True) @@ -161,7 +177,27 @@ def pytest_configure(config: pytest.Config) -> None: config.pluginmanager.register(TAPPlugin(config), "tapplugin") -def _make_as_diagnostics(report): +def _make_as_diagnostics(report, tap_logging): """Format a report as TAP diagnostic output.""" lines = report.longreprtext.splitlines(keepends=True) + + if tap_logging in SHOW_CAPTURE_LOG: + if lines: + lines[-1] += "\n" + lines += ["--- Captured Log ---\n"] + ( + report.caplog.splitlines(keepends=True) or [""] + ) + if tap_logging in SHOW_CAPTURE_OUT: + if lines: + lines[-1] += "\n" + lines += ["--- Captured Out ---\n"] + ( + report.capstdout.splitlines(keepends=True) or [""] + ) + if tap_logging in SHOW_CAPTUER_ERR: + if lines: + lines[-1] += "\n" + lines += ["--- Captured Err ---\n"] + ( + report.capstderr.splitlines(keepends=True) or [""] + ) + return format_as_diagnostics(lines) diff --git a/tests/test_help.py b/tests/test_help.py index 38bf3ac..543a11a 100644 --- a/tests/test_help.py +++ b/tests/test_help.py @@ -7,6 +7,7 @@ def test_includes_options(testdir): "*--tap-files*", "*--tap-combined*", "*--tap-outdir=path*", + "*--tap-log-passing-tests*", ] result.stdout.fnmatch_lines(expected_option_flags) diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 25c7dec..1c5b0ac 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -86,6 +86,34 @@ def test_outdir(testdir, sample_test_file): assert testresults.check() +def test_logging(testdir, sample_test_file): + """Test logs are added to TAP diagnostics.""" + result = testdir.runpytest_subprocess("--tap") + result.stdout.fnmatch_lines( + [ + "# --- Captured Log ---", + "*Running test_not_ok*", + "# --- Captured Out ---", + "# --- Captured Err ---", + ] + ) + result.stdout.no_fnmatch_line("*Running test_ok*") + + +def test_log_passing_tests(testdir, sample_test_file): + """Test logs are added to TAP diagnostics.""" + result = testdir.runpytest_subprocess( + "--tap", "--tap-log-passing-tests", "--log-level", "INFO" + ) + result.stdout.fnmatch_lines( + [ + "# --- Captured Log ---", + "*Running test_ok*", + ] + ) + result.stdout.no_fnmatch_line("*Debug logging info*") + + def test_xfail_no_reason(testdir): """xfails output gracefully when no reason is provided.""" testdir.makepyfile(