From a4ba4ee29e89e49868408e65d5db21d52577dfbc Mon Sep 17 00:00:00 2001 From: polyjeff529 Date: Wed, 29 Apr 2026 20:49:38 -0400 Subject: [PATCH 1/2] fix: detect PascalCase compiled-language tests and root-level conftest.py is_test_file() missed two common conventions: - PascalCase test names in compiled languages (FooTest.java, FooTests.kt, AccountServiceTests.cs, FooTests.swift, FooTest.scala). Detection uses the original-case basename so the capital-T boundary distinguishes them from incidental words like Latest.kt or Manifest.java. - conftest.py outside a tests/ directory (e.g. at the project root or inside a package), which pytest treats as a fixture file project-wide. Closes #866 Closes #865 --- gittensor/classes.py | 14 +++++++++++++- tests/test_classes.py | 44 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/gittensor/classes.py b/gittensor/classes.py index 93bed5e1d..d101b66dd 100644 --- a/gittensor/classes.py +++ b/gittensor/classes.py @@ -76,6 +76,11 @@ def _calculate_file_extension(self) -> str: def is_test_file(self) -> bool: filename_lower = self.filename.lower() basename = filename_lower.split('/')[-1] + basename_original = self.filename.split('/')[-1] + + # pytest fixture file — applies project-wide regardless of directory + if basename == 'conftest.py': + return True test_dir_patterns = [ r'(^|/)tests?/', @@ -100,7 +105,14 @@ def is_test_file(self) -> bool: r'^tests\.[^.]+$', ] - return any(re.search(pattern, basename) for pattern in test_patterns) + if any(re.search(pattern, basename) for pattern in test_patterns): + return True + + # PascalCase test conventions in compiled languages: `FooTest.kt`, + # `FooTests.swift`, `AccountServiceTests.cs`. The capital `T` boundary + # is what lets us distinguish these from incidental endings like + # `Latest.kt`, so we match against the original-case basename. + return bool(re.search(r'[A-Z][A-Za-z0-9]*Tests?\.(swift|kt|java|cs|scala)$', basename_original)) @classmethod def from_github_response(cls, pr_number: int, repository_full_name: str, file_diff: DefaultDict) -> 'FileChange': diff --git a/tests/test_classes.py b/tests/test_classes.py index a23e89f10..44e82304d 100644 --- a/tests/test_classes.py +++ b/tests/test_classes.py @@ -72,6 +72,50 @@ def test_is_test_file_preserves_existing_test_conventions(): assert _file_change('src/foo/bar.py').is_test_file() is False +@pytest.mark.parametrize( + 'filename', + [ + 'app/src/main/java/com/example/FooTest.java', + 'app/src/main/java/com/example/FooTests.java', + 'app/src/main/kotlin/com/example/FooTest.kt', + 'app/src/main/kotlin/com/example/FooTests.kt', + 'MyApp/Tests/FooTests.swift', + 'MyApp/Tests/FooTest.swift', + 'src/MyProject.Tests/AccountServiceTests.cs', + 'src/MyProject.Tests/AccountServiceTest.cs', + 'core/src/main/scala/com/example/FooTest.scala', + ], +) +def test_is_test_file_detects_pascalcase_compiled_language_tests(filename): + assert _file_change(filename).is_test_file() is True + + +@pytest.mark.parametrize( + 'filename', + [ + 'docs/latest.md', + 'src/main/kotlin/com/example/Latest.kt', + 'app/src/main/java/com/example/Manifest.java', + 'src/styles/contest.css', + ], +) +def test_is_test_file_rejects_pascalcase_lookalikes(filename): + assert _file_change(filename).is_test_file() is False + + +@pytest.mark.parametrize( + 'filename', + [ + 'conftest.py', + 'tests/conftest.py', + 'project/conftest.py', + 'project/sub/package/conftest.py', + ], +) +def test_is_test_file_detects_conftest_at_any_depth(filename): + assert _file_change(filename).is_test_file() is True + + def test_pull_request_handles_deleted_label_event(): pr_data = { 'number': 42, From eda85468a0ddd1830578953817d4d2e29515b7fa Mon Sep 17 00:00:00 2001 From: polyjeff529 Date: Mon, 4 May 2026 23:02:58 -0400 Subject: [PATCH 2/2] fix: scope is_test_file to two pattern-list additions per #874 review Per anderdc's review on #874: - Replace the conftest.py early-return with a r'^conftest\.py$' entry in test_patterns so the shared regex loop owns the match. - Replace the trailing PascalCase basename regex with a r'\.tests?/' entry in test_dir_patterns. This covers the meaningful #866 case (.NET layout MyProject.Tests/FooTests.cs, which doesn't match the existing (^|/)tests?/ because the segment is MyProject.Tests, not tests). The co-located FooTest.kt layout the basename regex covered is rare enough not to justify a second case-sensitivity rule, and the previous [A-Z][A-Za-z0-9]*Tests?\. anchor would have excluded fooTest.cs that #866 explicitly listed as a missed case. - Drop the basename_original variable now that no original-case match remains. Tests shrunk to match: keep conftest-at-any-depth and the .Tests/ directory cases; drop the co-located PascalCase fixtures and the PascalCase-lookalike rejects. --- gittensor/classes.py | 16 +++------------- tests/test_classes.py | 22 +--------------------- 2 files changed, 4 insertions(+), 34 deletions(-) diff --git a/gittensor/classes.py b/gittensor/classes.py index d101b66dd..e5269ee79 100644 --- a/gittensor/classes.py +++ b/gittensor/classes.py @@ -76,11 +76,6 @@ def _calculate_file_extension(self) -> str: def is_test_file(self) -> bool: filename_lower = self.filename.lower() basename = filename_lower.split('/')[-1] - basename_original = self.filename.split('/')[-1] - - # pytest fixture file — applies project-wide regardless of directory - if basename == 'conftest.py': - return True test_dir_patterns = [ r'(^|/)tests?/', @@ -88,6 +83,7 @@ def is_test_file(self) -> bool: r'(^|/)androidtest[a-z]*/', r'(^|/)integrationtest/', r'(^|/)spec/', + r'\.tests?/', # .NET MyProject.Tests/FooTests.cs ] if any(re.search(pattern, filename_lower) for pattern in test_dir_patterns): return True @@ -103,16 +99,10 @@ def is_test_file(self) -> bool: r'\.spec\.[^.]+$', r'^test\.[^.]+$', r'^tests\.[^.]+$', + r'^conftest\.py$', ] - if any(re.search(pattern, basename) for pattern in test_patterns): - return True - - # PascalCase test conventions in compiled languages: `FooTest.kt`, - # `FooTests.swift`, `AccountServiceTests.cs`. The capital `T` boundary - # is what lets us distinguish these from incidental endings like - # `Latest.kt`, so we match against the original-case basename. - return bool(re.search(r'[A-Z][A-Za-z0-9]*Tests?\.(swift|kt|java|cs|scala)$', basename_original)) + return any(re.search(pattern, basename) for pattern in test_patterns) @classmethod def from_github_response(cls, pr_number: int, repository_full_name: str, file_diff: DefaultDict) -> 'FileChange': diff --git a/tests/test_classes.py b/tests/test_classes.py index 44e82304d..476036143 100644 --- a/tests/test_classes.py +++ b/tests/test_classes.py @@ -75,34 +75,14 @@ def test_is_test_file_preserves_existing_test_conventions(): @pytest.mark.parametrize( 'filename', [ - 'app/src/main/java/com/example/FooTest.java', - 'app/src/main/java/com/example/FooTests.java', - 'app/src/main/kotlin/com/example/FooTest.kt', - 'app/src/main/kotlin/com/example/FooTests.kt', - 'MyApp/Tests/FooTests.swift', - 'MyApp/Tests/FooTest.swift', 'src/MyProject.Tests/AccountServiceTests.cs', 'src/MyProject.Tests/AccountServiceTest.cs', - 'core/src/main/scala/com/example/FooTest.scala', ], ) -def test_is_test_file_detects_pascalcase_compiled_language_tests(filename): +def test_is_test_file_detects_dotnet_dotted_tests_directory(filename): assert _file_change(filename).is_test_file() is True -@pytest.mark.parametrize( - 'filename', - [ - 'docs/latest.md', - 'src/main/kotlin/com/example/Latest.kt', - 'app/src/main/java/com/example/Manifest.java', - 'src/styles/contest.css', - ], -) -def test_is_test_file_rejects_pascalcase_lookalikes(filename): - assert _file_change(filename).is_test_file() is False - - @pytest.mark.parametrize( 'filename', [