diff --git a/tests/test_testing.py b/tests/test_testing.py index d5447c45a..7e875618e 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -3,17 +3,22 @@ """Tests that our test infrastructure is really working!""" +from __future__ import annotations + import datetime import os import re import sys import warnings +from typing import List, Tuple + import pytest import coverage from coverage.exceptions import CoverageWarning from coverage.files import actual_path +from coverage.types import TArc from tests.coveragetest import CoverageTest from tests.helpers import ( @@ -22,13 +27,13 @@ ) -def test_xdist_sys_path_nuttiness_is_fixed(): +def test_xdist_sys_path_nuttiness_is_fixed() -> None: # See conftest.py:fix_xdist_sys_path assert sys.path[1] != '' assert os.environ.get('PYTHONPATH') is None -def test_assert_count_equal(): +def test_assert_count_equal() -> None: assert_count_equal(set(), set()) assert_count_equal({"a": 1, "b": 2}, ["b", "a"]) with pytest.raises(AssertionError): @@ -40,7 +45,7 @@ def test_assert_count_equal(): class CoverageTestTest(CoverageTest): """Test the methods in `CoverageTest`.""" - def test_file_exists(self): + def test_file_exists(self) -> None: self.make_file("whoville.txt", "We are here!") self.assert_exists("whoville.txt") self.assert_doesnt_exist("shadow.txt") @@ -51,7 +56,7 @@ def test_file_exists(self): with pytest.raises(AssertionError, match=msg): self.assert_exists("shadow.txt") - def test_file_count(self): + def test_file_count(self) -> None: self.make_file("abcde.txt", "abcde") self.make_file("axczz.txt", "axczz") self.make_file("afile.txt", "afile") @@ -82,8 +87,8 @@ def test_file_count(self): with pytest.raises(AssertionError, match=msg): self.assert_file_count("*.q", 10) - def test_assert_recent_datetime(self): - def now_delta(seconds): + def test_assert_recent_datetime(self) -> None: + def now_delta(seconds: int) -> datetime.datetime: """Make a datetime `seconds` seconds from now.""" return datetime.datetime.now() + datetime.timedelta(seconds=seconds) @@ -103,7 +108,7 @@ def now_delta(seconds): with pytest.raises(AssertionError): self.assert_recent_datetime(now_delta(1), seconds=120) - def test_assert_warnings(self): + def test_assert_warnings(self) -> None: cov = coverage.Coverage() # Make a warning, it should catch it properly. @@ -152,7 +157,7 @@ def test_assert_warnings(self): with self.assert_warnings(cov, ["Hello there!"]): raise ZeroDivisionError("oops") - def test_assert_no_warnings(self): + def test_assert_no_warnings(self) -> None: cov = coverage.Coverage() # Happy path: no warnings. @@ -165,7 +170,7 @@ def test_assert_no_warnings(self): with self.assert_warnings(cov, []): cov._warn("Watch out!") - def test_sub_python_is_this_python(self): + def test_sub_python_is_this_python(self) -> None: # Try it with a Python command. self.set_environ('COV_FOOBAR', 'XYZZY') self.make_file("showme.py", """\ @@ -174,10 +179,10 @@ def test_sub_python_is_this_python(self): print(os.__file__) print(os.environ['COV_FOOBAR']) """) - out = self.run_command("python showme.py").splitlines() - assert actual_path(out[0]) == actual_path(sys.executable) - assert out[1] == os.__file__ - assert out[2] == 'XYZZY' + out_lines = self.run_command("python showme.py").splitlines() + assert actual_path(out_lines[0]) == actual_path(sys.executable) + assert out_lines[1] == os.__file__ + assert out_lines[2] == 'XYZZY' # Try it with a "coverage debug sys" command. out = self.run_command("coverage debug sys") @@ -191,7 +196,7 @@ def test_sub_python_is_this_python(self): _, _, environ = environ.rpartition(":") assert environ.strip() == "COV_FOOBAR = XYZZY" - def test_run_command_stdout_stderr(self): + def test_run_command_stdout_stderr(self) -> None: # run_command should give us both stdout and stderr. self.make_file("outputs.py", """\ import sys @@ -202,7 +207,7 @@ def test_run_command_stdout_stderr(self): assert "StdOut\n" in out assert "StdErr\n" in out - def test_stdout(self): + def test_stdout(self) -> None: # stdout is captured. print("This is stdout") print("Line 2") @@ -219,14 +224,19 @@ class CheckUniqueFilenamesTest(CoverageTest): class Stub: """A stand-in for the class we're checking.""" - def __init__(self, x): + def __init__(self, x: int) -> None: self.x = x - def method(self, filename, a=17, b="hello"): + def method( + self, + filename: str, + a: int = 17, + b: str = "hello", + ) -> Tuple[int, str, int, str]: """The method we'll wrap, with args to be sure args work.""" return (self.x, filename, a, b) - def test_detect_duplicate(self): + def test_detect_duplicate(self) -> None: stub = self.Stub(23) CheckUniqueFilenames.hook(stub, "method") @@ -259,7 +269,7 @@ def oops(x): ARCZ_MISSING = "3-2 78 8B" ARCZ_UNPREDICTED = "79" - def test_check_coverage_possible(self): + def test_check_coverage_possible(self) -> None: msg = r"(?s)Possible arcs differ: .*- \(6, 3\).*\+ \(6, 7\)" with pytest.raises(AssertionError, match=msg): self.check_coverage( @@ -269,7 +279,7 @@ def test_check_coverage_possible(self): arcz_unpredicted=self.ARCZ_UNPREDICTED, ) - def test_check_coverage_missing(self): + def test_check_coverage_missing(self) -> None: msg = r"(?s)Missing arcs differ: .*- \(3, 8\).*\+ \(7, 8\)" with pytest.raises(AssertionError, match=msg): self.check_coverage( @@ -279,7 +289,7 @@ def test_check_coverage_missing(self): arcz_unpredicted=self.ARCZ_UNPREDICTED, ) - def test_check_coverage_unpredicted(self): + def test_check_coverage_unpredicted(self) -> None: msg = r"(?s)Unpredicted arcs differ: .*- \(3, 9\).*\+ \(7, 9\)" with pytest.raises(AssertionError, match=msg): self.check_coverage( @@ -300,7 +310,7 @@ class ReLinesTest(CoverageTest): ("[13]", "line1\nline2\nline3\n", "line1\nline3\n"), ("X", "line1\nline2\nline3\n", ""), ]) - def test_re_lines(self, pat, text, result): + def test_re_lines(self, pat: str, text: str, result: str) -> None: assert re_lines_text(pat, text) == result assert re_lines(pat, text) == result.splitlines() @@ -309,26 +319,26 @@ def test_re_lines(self, pat, text, result): ("[13]", "line1\nline2\nline3\n", "line2\n"), ("X", "line1\nline2\nline3\n", "line1\nline2\nline3\n"), ]) - def test_re_lines_inverted(self, pat, text, result): + def test_re_lines_inverted(self, pat: str, text: str, result: str) -> None: assert re_lines_text(pat, text, match=False) == result assert re_lines(pat, text, match=False) == result.splitlines() @pytest.mark.parametrize("pat, text, result", [ ("2", "line1\nline2\nline3\n", "line2"), ]) - def test_re_line(self, pat, text, result): + def test_re_line(self, pat: str, text: str, result: str) -> None: assert re_line(pat, text) == result @pytest.mark.parametrize("pat, text", [ ("line", "line1\nline2\nline3\n"), # too many matches ("X", "line1\nline2\nline3\n"), # no matches ]) - def test_re_line_bad(self, pat, text): + def test_re_line_bad(self, pat: str, text: str) -> None: with pytest.raises(AssertionError): re_line(pat, text) -def _same_python_executable(e1, e2): +def _same_python_executable(e1: str, e2: str) -> bool: """Determine if `e1` and `e2` refer to the same Python executable. Either path could include symbolic links. The two paths might not refer @@ -365,7 +375,7 @@ class ArczTest(CoverageTest): ("-11 12 2-5", [(-1, 1), (1, 2), (2, -5)]), ("-QA CB IT Z-A", [(-26, 10), (12, 11), (18, 29), (35, -10)]), ]) - def test_arcz_to_arcs(self, arcz, arcs): + def test_arcz_to_arcs(self, arcz: str, arcs: List[TArc]) -> None: assert arcz_to_arcs(arcz) == arcs @pytest.mark.parametrize("arcs, arcz_repr", [ @@ -382,45 +392,45 @@ def test_arcz_to_arcs(self, arcz, arcs): ) ), ]) - def test_arcs_to_arcz_repr(self, arcs, arcz_repr): + def test_arcs_to_arcz_repr(self, arcs: List[TArc], arcz_repr: str) -> None: assert arcs_to_arcz_repr(arcs) == arcz_repr class AssertCoverageWarningsTest(CoverageTest): """Tests of assert_coverage_warnings""" - def test_one_warning(self): + def test_one_warning(self) -> None: with pytest.warns(Warning) as warns: warnings.warn("Hello there", category=CoverageWarning) assert_coverage_warnings(warns, "Hello there") - def test_many_warnings(self): + def test_many_warnings(self) -> None: with pytest.warns(Warning) as warns: warnings.warn("The first", category=CoverageWarning) warnings.warn("The second", category=CoverageWarning) warnings.warn("The third", category=CoverageWarning) assert_coverage_warnings(warns, "The first", "The second", "The third") - def test_wrong_type(self): + def test_wrong_type(self) -> None: with pytest.warns(Warning) as warns: warnings.warn("Not ours", category=Warning) with pytest.raises(AssertionError): assert_coverage_warnings(warns, "Not ours") - def test_wrong_message(self): + def test_wrong_message(self) -> None: with pytest.warns(Warning) as warns: warnings.warn("Goodbye", category=CoverageWarning) with pytest.raises(AssertionError): assert_coverage_warnings(warns, "Hello there") - def test_wrong_number_too_many(self): + def test_wrong_number_too_many(self) -> None: with pytest.warns(Warning) as warns: warnings.warn("The first", category=CoverageWarning) warnings.warn("The second", category=CoverageWarning) with pytest.raises(AssertionError): assert_coverage_warnings(warns, "The first", "The second", "The third") - def test_wrong_number_too_few(self): + def test_wrong_number_too_few(self) -> None: with pytest.warns(Warning) as warns: warnings.warn("The first", category=CoverageWarning) warnings.warn("The second", category=CoverageWarning) @@ -428,12 +438,12 @@ def test_wrong_number_too_few(self): with pytest.raises(AssertionError): assert_coverage_warnings(warns, "The first", "The second") - def test_regex_matches(self): + def test_regex_matches(self) -> None: with pytest.warns(Warning) as warns: warnings.warn("The first", category=CoverageWarning) assert_coverage_warnings(warns, re.compile("f?rst")) - def test_regex_doesnt_match(self): + def test_regex_doesnt_match(self) -> None: with pytest.warns(Warning) as warns: warnings.warn("The first", category=CoverageWarning) with pytest.raises(AssertionError): diff --git a/tests/test_version.py b/tests/test_version.py index ce6c705ac..9efa228ab 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -3,6 +3,8 @@ """Tests of version.py.""" +from __future__ import annotations + import coverage from coverage.version import _make_url, _make_version @@ -14,13 +16,13 @@ class VersionTest(CoverageTest): run_in_temp_dir = False - def test_version_info(self): + def test_version_info(self) -> None: # Make sure we didn't screw up the version_info tuple. assert isinstance(coverage.version_info, tuple) assert [type(d) for d in coverage.version_info] == [int, int, int, str, int] assert coverage.version_info[3] in {'alpha', 'beta', 'candidate', 'final'} - def test_make_version(self): + def test_make_version(self) -> None: assert _make_version(4, 0, 0, 'alpha') == "4.0.0a0" assert _make_version(4, 0, 0, 'alpha', 1) == "4.0.0a1" assert _make_version(4, 0, 0, 'final') == "4.0.0" @@ -30,7 +32,7 @@ def test_make_version(self): assert _make_version(5, 10, 2, 'candidate', 7) == "5.10.2rc7" assert _make_version(5, 10, 2, 'candidate', 7, 3) == "5.10.2rc7.dev3" - def test_make_url(self): + def test_make_url(self) -> None: assert _make_url(4, 0, 0, 'final') == "https://coverage.readthedocs.io" expected = "https://coverage.readthedocs.io/en/4.1.2b3" assert _make_url(4, 1, 2, 'beta', 3) == expected diff --git a/tox.ini b/tox.ini index cf0d09d29..bf5f40bad 100644 --- a/tox.ini +++ b/tox.ini @@ -106,9 +106,10 @@ setenv = T3=tests/test_config.py tests/test_context.py tests/test_coverage.py tests/test_data.py tests/test_debug.py tests/test_execfile.py T4=tests/test_filereporter.py tests/test_files.py tests/test_goldtest.py tests/test_html.py tests/test_json.py tests/test_lcov.py T5=tests/test_misc.py tests/test_mixins.py tests/test_numbits.py tests/test_oddball.py tests/test_parser.py tests/test_phystokens.py - T6=tests/test_process.py tests/test_python.py tests/test_report.py tests/test_results.py tests/test_setup.py tests/test_summary.py tests/test_xml.py - # not done yet: test_plugins.py - TYPEABLE={env:C1} {env:C2} {env:C3} {env:C4} {env:C5} {env:C6} {env:T1} {env:T2} {env:T3} {env:T4} {env:T5} {env:T6} + T6=tests/test_process.py tests/test_python.py tests/test_report.py tests/test_results.py tests/test_setup.py + T7=tests/test_summary.py tests/test_testing.py tests/test_version.py tests/test_xml.py + # not done yet: test_plugins.py test_templite.py test_venv.py + TYPEABLE={env:C1} {env:C2} {env:C3} {env:C4} {env:C5} {env:C6} {env:T1} {env:T2} {env:T3} {env:T4} {env:T5} {env:T6} {env:T7} commands = # PYVERSIONS