diff --git a/src/python/pants/backend/python/rules/coverage_integration_test.py b/src/python/pants/backend/python/rules/coverage_integration_test.py index 537ee0b251b..8fe4202ae66 100644 --- a/src/python/pants/backend/python/rules/coverage_integration_test.py +++ b/src/python/pants/backend/python/rules/coverage_integration_test.py @@ -5,144 +5,144 @@ from textwrap import dedent from pants.base.build_environment import get_buildroot -from pants.testutil.pants_run_integration_test import PantsRunIntegrationTest +from pants.testutil.pants_run_integration_test import PantsResult, PantsRunIntegrationTest from pants.util.contextutil import temporary_dir class CoverageIntegrationTest(PantsRunIntegrationTest): - def test_coverage(self) -> None: - with temporary_dir(root_dir=get_buildroot()) as tmpdir: - tmpdir_relative = Path(tmpdir).relative_to(get_buildroot()) - src_root = Path(tmpdir, "src", "python", "project") - src_root.mkdir(parents=True) - (src_root / "__init__.py").touch() - - # Set up the source files. Only `lib.py` will actually be tested, but we still expect - # `random.py` to show up in the final report correctly. - (src_root / "lib.py").write_text( - dedent( - """\ - def add(x, y): - return x + y - - def subtract(x, y): - return x - y - - def multiply(x, y): - return x * y - """ - ) + def _prepare_sources(self, tmpdir: str, build_root: str) -> Path: + tmpdir_relative = Path(tmpdir).relative_to(build_root) + src_root = Path(tmpdir, "src", "python", "project") + src_root.mkdir(parents=True) + (src_root / "__init__.py").touch() + + # Set up the source files. Only `lib.py` will actually be tested, but we still expect + # `random.py` to show up in the final report correctly. + (src_root / "lib.py").write_text( + dedent( + """\ + def add(x, y): + return x + y + + def subtract(x, y): + return x - y + + def multiply(x, y): + return x * y + """ ) - (src_root / "random.py").write_text( - dedent( - """\ - def capitalize(s): - return s.capitalize() - """ - ) + ) + (src_root / "random.py").write_text( + dedent( + """\ + def capitalize(s): + return s.capitalize() + """ ) + ) - # Only test half of the library. - (src_root / "lib_test.py").write_text( - dedent( - """\ - from project.lib import add + # Only test half of the library. + (src_root / "lib_test.py").write_text( + dedent( + """\ + from project.lib import add - def test_add(): - assert add(2, 3) == 5 - """ - ) + def test_add(): + assert add(2, 3) == 5 + """ ) + ) - (src_root / "BUILD").write_text( - dedent( - """\ - python_library() + (src_root / "BUILD").write_text( + dedent( + """\ + python_library() - python_tests( - name="tests", - dependencies=[":project"], - ) - """ + python_tests( + name="tests", + dependencies=[":project"], ) + """ ) + ) - # Test that a `tests/` source root accurately gets coverage data for the `src/` root. - test_root = Path(tmpdir, "tests", "python", "project_test") - test_root.mkdir(parents=True) - (test_root / "__init__.py").touch() - (test_root / "test_multiply.py").write_text( - dedent( - """\ - from project.lib import multiply - - def test_multiply(): - assert multiply(2, 3) == 6 - """ - ) + # Test that a `tests/` source root accurately gets coverage data for the `src/` root. + test_root = Path(tmpdir, "tests", "python", "project_test") + test_root.mkdir(parents=True) + (test_root / "__init__.py").touch() + (test_root / "test_multiply.py").write_text( + dedent( + """\ + from project.lib import multiply + + def test_multiply(): + assert multiply(2, 3) == 6 + """ ) - (test_root / "test_arithmetic.py").write_text( - dedent( - """\ - from project.lib import add, subtract - - def test_arithmetic(): - assert add(4, 3) == 7 == subtract(10, 3) - """ - ) + ) + (test_root / "test_arithmetic.py").write_text( + dedent( + """\ + from project.lib import add, subtract + + def test_arithmetic(): + assert add(4, 3) == 7 == subtract(10, 3) + """ ) - (test_root / "BUILD").write_text( - dedent( - f"""\ - python_tests( - name="multiply", - sources=["test_multiply.py"], - dependencies=['{tmpdir_relative}/src/python/project'], - ) - - python_tests( - name="arithmetic", - sources=["test_arithmetic.py"], - dependencies=['{tmpdir_relative}/src/python/project'], - ) - """ + ) + (test_root / "BUILD").write_text( + dedent( + f"""\ + python_tests( + name="multiply", + sources=["test_multiply.py"], + dependencies=['{tmpdir_relative}/src/python/project'], ) - ) - # Test a file that does not cover any src code. While this is unlikely to happen, this - # tests that we can properly handle the edge case. In particular, we want to make sure - # that coverage still works when we omit this test file through the option - # `--omit-test-sources`. - no_src_folder = Path(tmpdir, "tests", "python", "project_test", "no_src") - no_src_folder.mkdir() - (no_src_folder / "__init__.py").touch() - (no_src_folder / "test_no_src.py").write_text( - "def test_true():\n\tassert True is True\n" - ) - (no_src_folder / "BUILD").write_text("python_tests()") - - command = [ - "--no-v1", - "--v2", - "test", - "--use-coverage", - f"{tmpdir_relative}/src/python/project:tests", - f"{tmpdir_relative}/tests/python/project_test:multiply", - f"{tmpdir_relative}/tests/python/project_test:arithmetic", - f"{tmpdir_relative}/tests/python/project_test/no_src", - ] - default_result = self.run_pants(command) - filter_result = self.run_pants( - [*command, "--coverage-py-filter=['project.lib', 'project_test.no_src']"] + python_tests( + name="arithmetic", + sources=["test_arithmetic.py"], + dependencies=['{tmpdir_relative}/src/python/project'], + ) + """ ) + ) + # Test a file that does not cover any src code. While this is unlikely to happen, this + # tests that we can properly handle the edge case. In particular, we want to make sure + # that coverage still works when we omit this test file through the option + # `--omit-test-sources`. + no_src_folder = Path(tmpdir, "tests", "python", "project_test", "no_src") + no_src_folder.mkdir() + (no_src_folder / "__init__.py").touch() + (no_src_folder / "test_no_src.py").write_text("def test_true():\n\tassert True is True\n") + (no_src_folder / "BUILD").write_text("python_tests()") + return tmpdir_relative + + def _run_tests(self, tmpdir_relative, *more_args: str) -> PantsResult: + command = [ + "--no-v1", + "--v2", + "test", + "--use-coverage", + f"{tmpdir_relative}/src/python/project:tests", + f"{tmpdir_relative}/tests/python/project_test:multiply", + f"{tmpdir_relative}/tests/python/project_test:arithmetic", + f"{tmpdir_relative}/tests/python/project_test/no_src", + ] + command.extend(more_args) + result = self.run_pants(command) + assert result.returncode == 0 + # Regression test: make sure that individual tests do not complain about failing to + # generate reports. This was showing up at test-time, even though the final merged + # report would work properly. + assert "Failed to generate report" not in result.stderr_data + return result - for result in (default_result, filter_result): - assert result.returncode == 0 - # Regression test: make sure that individual tests do not complain about failing to - # generate reports. This was showing up at test-time, even though the final merged - # report would work properly. - assert "Failed to generate report" not in result.stderr_data - + def test_coverage(self) -> None: + build_root = get_buildroot() + with temporary_dir(root_dir=build_root) as tmpdir: + tmpdir_relative = self._prepare_sources(tmpdir, build_root) + result = self._run_tests(tmpdir_relative) assert ( dedent( f"""\ @@ -159,8 +159,16 @@ def test_arithmetic(): TOTAL 19 2 0 0 89% """ ) - in default_result.stderr_data + in result.stderr_data ) + + def test_coverage_with_filter(self) -> None: + build_root = get_buildroot() + with temporary_dir(root_dir=build_root) as tmpdir: + tmpdir_relative = self._prepare_sources(tmpdir, build_root) + result = self._run_tests( + tmpdir_relative, "--coverage-py-filter=['project.lib', 'project_test.no_src']" + ) assert ( dedent( f"""\ @@ -172,5 +180,5 @@ def test_arithmetic(): TOTAL 8 0 0 0 100% """ ) - in filter_result.stderr_data + in result.stderr_data )