From 731746365b28a406faaa3aff406eb81c92faefc9 Mon Sep 17 00:00:00 2001 From: Pierre Sassoulas Date: Thu, 23 Mar 2023 14:07:20 +0100 Subject: [testutil] Fix the algorithm for functional test discovery --- .../testutils/functional/find_functional_tests.py | 44 +++++++++++++++------- .../r/regression/regression_property_slots_2439.py | 22 ----------- .../regression_property_slots_2439.py | 22 +++++++++++ .../u/_no_issue_here/_incredibly_bold_mischief.py | 0 tests/testutils/test_functional_testutils.py | 11 ++++-- 5 files changed, 60 insertions(+), 39 deletions(-) delete mode 100644 tests/functional/r/regression/regression_property_slots_2439.py create mode 100644 tests/functional/r/regression_02/regression_property_slots_2439.py create mode 100644 tests/testutils/data/u/_no_issue_here/_incredibly_bold_mischief.py diff --git a/pylint/testutils/functional/find_functional_tests.py b/pylint/testutils/functional/find_functional_tests.py index f71e3090a..b40fbbbde 100644 --- a/pylint/testutils/functional/find_functional_tests.py +++ b/pylint/testutils/functional/find_functional_tests.py @@ -5,6 +5,7 @@ from __future__ import annotations import os +from collections.abc import Iterator from pathlib import Path from pylint.testutils.functional.test_file import FunctionalTestFile @@ -50,27 +51,38 @@ def get_functional_test_files_from_directory( def _check_functional_tests_structure(directory: Path) -> None: - """Check if test directories follow correct file/folder structure.""" - # Ignore underscored directories + """Check if test directories follow correct file/folder structure. + + Ignore underscored directories or files. + """ if Path(directory).stem.startswith("_"): return files: set[Path] = set() dirs: set[Path] = set() + def walk(path: Path) -> Iterator[Path]: + for _file_or_dir in path.iterdir(): + if _file_or_dir.is_dir(): + _files = list(_file_or_dir.iterdir()) + assert len(_files) <= REASONABLY_DISPLAYABLE_VERTICALLY, ( + f"{_file_or_dir} contains too many functional tests files " + + f"({len(_files)} > {REASONABLY_DISPLAYABLE_VERTICALLY})." + ) + yield _file_or_dir + yield from walk(_file_or_dir) + else: + yield _file_or_dir.resolve() + # Collect all sub-directories and files in directory - for file_or_dir in directory.iterdir(): - if file_or_dir.is_file(): - if file_or_dir.suffix == ".py" and not file_or_dir.stem.startswith("_"): - files.add(file_or_dir) - elif file_or_dir.is_dir(): + for file_or_dir in walk(directory): + if file_or_dir.stem.startswith("_"): + continue + if file_or_dir.is_dir(): dirs.add(file_or_dir) - _check_functional_tests_structure(file_or_dir) + elif file_or_dir.suffix == ".py": + files.add(file_or_dir) - assert len(files) <= REASONABLY_DISPLAYABLE_VERTICALLY, ( - f"{directory} contains too many functional tests files " - + f"({len(files)} > {REASONABLY_DISPLAYABLE_VERTICALLY})." - ) directory_does_not_exists: list[tuple[Path, Path]] = [] misplaced_file: list[Path] = [] for file in files: @@ -88,10 +100,14 @@ def _check_functional_tests_structure(directory: Path) -> None: if directory_does_not_exists or misplaced_file: msg = "The following functional tests are disorganized:\n" for file, possible_dir in directory_does_not_exists: - msg += f"- {file} should go in {possible_dir}\n" + msg += ( + f"- In '{directory}', '{file.relative_to(directory)}' " + f"should go in '{possible_dir.relative_to(directory)}'\n" + ) for file in misplaced_file: msg += ( - f"- {file} should go in a directory that starts with the first letters" + f"- In '{directory}', {file.relative_to(directory)} should go in a directory" + f" that starts with the first letters" f" of '{file.stem}' (not '{file.parent.stem}')\n" ) raise AssertionError(msg) diff --git a/tests/functional/r/regression/regression_property_slots_2439.py b/tests/functional/r/regression/regression_property_slots_2439.py deleted file mode 100644 index 91cf86cfd..000000000 --- a/tests/functional/r/regression/regression_property_slots_2439.py +++ /dev/null @@ -1,22 +0,0 @@ -# pylint: disable=missing-docstring,invalid-name,too-few-public-methods -# https://github.com/PyCQA/pylint/issues/2439 -class TestClass: - __slots__ = ["_i"] - - def __init__(self): - self._i = 0 - - @property - def i(self): - return self._i - - @i.setter - def i(self, v): - self._i = v - - other = i - - -instance = TestClass() -instance.other = 42 -print(instance.i) diff --git a/tests/functional/r/regression_02/regression_property_slots_2439.py b/tests/functional/r/regression_02/regression_property_slots_2439.py new file mode 100644 index 000000000..91cf86cfd --- /dev/null +++ b/tests/functional/r/regression_02/regression_property_slots_2439.py @@ -0,0 +1,22 @@ +# pylint: disable=missing-docstring,invalid-name,too-few-public-methods +# https://github.com/PyCQA/pylint/issues/2439 +class TestClass: + __slots__ = ["_i"] + + def __init__(self): + self._i = 0 + + @property + def i(self): + return self._i + + @i.setter + def i(self, v): + self._i = v + + other = i + + +instance = TestClass() +instance.other = 42 +print(instance.i) diff --git a/tests/testutils/data/u/_no_issue_here/_incredibly_bold_mischief.py b/tests/testutils/data/u/_no_issue_here/_incredibly_bold_mischief.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/testutils/test_functional_testutils.py b/tests/testutils/test_functional_testutils.py index e12fd7a84..6019cceac 100644 --- a/tests/testutils/test_functional_testutils.py +++ b/tests/testutils/test_functional_testutils.py @@ -41,12 +41,17 @@ def test_parsing_of_pylintrc_init_hook() -> None: def test_get_functional_test_files_from_directory() -> None: """Test that we correctly check the functional test directory structures.""" - match = ( + with pytest.raises(AssertionError) as exc_info: + get_functional_test_files_from_directory(DATA_DIRECTORY / "u") + assert exc_info.match("'use_dir.py' should go in 'use'") + assert exc_info.match( "using_dir.py should go in a directory that starts with the " "first letters of 'using_dir'" ) - with pytest.raises(AssertionError, match=match): - get_functional_test_files_from_directory(DATA_DIRECTORY / "u") + with pytest.raises(AssertionError): + exc_info.match("incredibly_bold_mischief.py") + # Leading underscore mean that this should not fail the assertion + get_functional_test_files_from_directory(DATA_DIRECTORY / "u/_no_issue_here") def test_minimal_messages_config_enabled(pytest_config: MagicMock) -> None: -- cgit v1.2.1