diff --git a/tests/skill/understand/test_merge_batch_graphs.py b/tests/skill/understand/test_merge_batch_graphs.py index 33504f212..6be942ccc 100644 --- a/tests/skill/understand/test_merge_batch_graphs.py +++ b/tests/skill/understand/test_merge_batch_graphs.py @@ -132,6 +132,29 @@ def test_python_test_files(self) -> None: self.assertTrue(mbg.is_test_path("bar_test.py")) self.assertTrue(mbg.is_test_path("test_bar.py")) + def test_python_tests_directory(self) -> None: + # Files under `tests/` count as tests even without a `test_` prefix or + # `_test` suffix — e.g. `tests/run_tests.py`, `tests/stage4_e2e.py`. + for path in [ + "tests/run_tests.py", + "tests/stage3_tests.py", + "tests/stage4_e2e.py", + "tests/gen_data.py", + "tests/helpers.py", + ]: + with self.subTest(path=path): + self.assertTrue(mbg.is_test_path(path), f"{path} should be a test") + + def test_python_non_test_paths(self) -> None: + # A `tests` substring elsewhere in the path must not trigger a match. + for path in [ + "data_agent/core/sqlite_utils.py", + "mypkg/testing/helpers.py", + "src/latest.py", + ]: + with self.subTest(path=path): + self.assertFalse(mbg.is_test_path(path), f"{path} should NOT be a test") + def test_java_test_files(self) -> None: self.assertTrue(mbg.is_test_path("src/test/java/com/foo/BarTest.java")) self.assertTrue(mbg.is_test_path("src/test/java/com/foo/BarTests.java")) diff --git a/understand-anything-plugin/skills/understand/merge-batch-graphs.py b/understand-anything-plugin/skills/understand/merge-batch-graphs.py index b0cf51a3b..f8ef6b65a 100644 --- a/understand-anything-plugin/skills/understand/merge-batch-graphs.py +++ b/understand-anything-plugin/skills/understand/merge-batch-graphs.py @@ -130,7 +130,7 @@ def resolve_ua_dir(root: Path) -> Path: # These language configs treat every source file below `tests/` as part of a # test target, even when the basename itself has no test marker. JS/TS is # intentionally absent: files such as `__tests__/helpers.ts` remain helpers. -_TEST_DIRECTORY_EXTENSIONS: frozenset[str] = frozenset({".swift", ".rs", ".php"}) +_TEST_DIRECTORY_EXTENSIONS: frozenset[str] = frozenset({".swift", ".rs", ".php", ".py"}) _EXACT_TEST_STEMS: dict[str, frozenset[str]] = { ".rb": frozenset({"spec_helper"}), @@ -342,9 +342,11 @@ def _basename(path: str) -> str: def is_test_path(path: str) -> bool: """Return True if `path` looks like a test file by language convention. - Most languages use basename markers. Swift, Rust, and PHP additionally - make `tests/` a test-source root. JS/TS files still require `.test` or - `.spec`, so `__tests__/helpers.ts` remains a non-test helper. + Most languages use basename markers. Swift, Rust, PHP, and Python + additionally make `tests/` a test-source root, so `tests/run_tests.py` + (no `test_` prefix, no `_test` suffix) is still recognized as a test. + JS/TS files still require `.test` or `.spec`, so `__tests__/helpers.ts` + remains a non-test helper. """ stem, ext = os.path.splitext(_basename(path)) ext = ext.lower()