find_functional_tests.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. # Licensed under the GPL: https://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  2. # For details: https://github.com/pylint-dev/pylint/blob/main/LICENSE
  3. # Copyright (c) https://github.com/pylint-dev/pylint/blob/main/CONTRIBUTORS.txt
  4. from __future__ import annotations
  5. import os
  6. from pathlib import Path
  7. from pylint.testutils.functional.test_file import FunctionalTestFile
  8. REASONABLY_DISPLAYABLE_VERTICALLY = 48
  9. """'Wet finger' number of files that are reasonable to display by an IDE."""
  10. SHOULD_BE_IN_THE_SAME_DIRECTORY = 5
  11. """'Wet finger' as in 'in my settings there are precisely this many'."""
  12. IGNORED_PARENT_DIRS = {
  13. "deprecated_relative_import",
  14. "ext",
  15. "regression",
  16. "regression_02",
  17. }
  18. """Direct parent directories that should be ignored."""
  19. IGNORED_PARENT_PARENT_DIRS = {
  20. "docparams",
  21. "deprecated_relative_import",
  22. "ext",
  23. }
  24. """Parents of direct parent directories that should be ignored."""
  25. def get_functional_test_files_from_directory(
  26. input_dir: Path | str,
  27. ) -> list[FunctionalTestFile]:
  28. """Get all functional tests in the input_dir."""
  29. suite = []
  30. _check_functional_tests_structure(Path(input_dir))
  31. for dirpath, dirnames, filenames in os.walk(input_dir):
  32. if dirpath.endswith("__pycache__"):
  33. continue
  34. dirnames.sort()
  35. filenames.sort()
  36. for filename in filenames:
  37. if filename != "__init__.py" and filename.endswith(".py"):
  38. suite.append(FunctionalTestFile(dirpath, filename))
  39. return suite
  40. def _check_functional_tests_structure(directory: Path) -> None:
  41. """Check if test directories follow correct file/folder structure."""
  42. # Ignore underscored directories
  43. if Path(directory).stem.startswith("_"):
  44. return
  45. files: set[Path] = set()
  46. dirs: set[Path] = set()
  47. # Collect all sub-directories and files in directory
  48. for file_or_dir in directory.iterdir():
  49. if file_or_dir.is_file():
  50. if file_or_dir.suffix == ".py" and not file_or_dir.stem.startswith("_"):
  51. files.add(file_or_dir)
  52. elif file_or_dir.is_dir():
  53. dirs.add(file_or_dir)
  54. _check_functional_tests_structure(file_or_dir)
  55. assert len(files) <= REASONABLY_DISPLAYABLE_VERTICALLY, (
  56. f"{directory} contains too many functional tests files "
  57. + f"({len(files)} > {REASONABLY_DISPLAYABLE_VERTICALLY})."
  58. )
  59. for file in files:
  60. possible_dir = file.parent / file.stem.split("_")[0]
  61. assert not possible_dir.exists(), f"{file} should go in {possible_dir}."
  62. # Exclude some directories as they follow a different structure
  63. if (
  64. not len(file.parent.stem) == 1 # First letter sub-directories
  65. and file.parent.stem not in IGNORED_PARENT_DIRS
  66. and file.parent.parent.stem not in IGNORED_PARENT_PARENT_DIRS
  67. ):
  68. assert file.stem.startswith(
  69. file.parent.stem
  70. ), f"{file} should not go in {file.parent}"