fix: detect PascalCase compiled-language tests and root-level conftest.py - #874
Conversation
…t.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 entrius#866 Closes entrius#865
anderdc
left a comment
There was a problem hiding this comment.
Scope this down to two pattern-list additions:
test_dir_patterns = [
...
r'\.tests?/', # .NET MyProject.Tests/FooTests.cs
]
test_patterns = [
...
r'^conftest\.py$',
]Drop the basename_original variable and the [A-Z][A-Za-z0-9]*Tests?\.(swift|kt|java|cs|scala)$ regex. The \.tests?/ directory pattern covers the meaningful #866 case (.NET test-project layout — MyProject.Tests/FooTests.cs doesn't match the existing (^|/)tests?/ because the segment is MyProject.Tests, not tests). The remaining co-located FooTest.kt layout the basename regex catches is rare enough not to justify a second case-sensitivity rule in the function — and the leading [A-Z] requirement excludes fooTest.cs, which #866 explicitly lists as a missed case.
Tests can shrink to match: keep conftest-at-any-depth and .Tests/ directory cases; the co-located PascalCase fixtures aren't needed.
…review Per anderdc's review on entrius#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 entrius#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 entrius#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.
I updated, Could you check it? |
Summary
FileChange.is_test_file()missed two real-world test naming conventions, so legitimate test files were being scored as production source.#866 — PascalCase compiled-language tests
JUnit / Kotlin / MSTest / XCTest / ScalaTest commonly use
<ClassName>Test.<ext>or<ClassName>Tests.<ext>. Examples that previously slipped through:app/src/main/java/com/example/AccountServiceTest.javaapp/src/main/kotlin/com/example/UserRepositoryTests.ktMyApp/Tests/AuthFlowTests.swiftsrc/MyProject.Tests/CheckoutTests.cscore/src/main/scala/com/example/PaymentTest.scalaThe existing
_test\.[ext]$patterns only fire on snake_case, soFoo_test.ktmatched butFooTest.ktdid not.The matcher needs to distinguish
FooTest.kt(test) fromLatest.kt/Manifest.java(not test). The capitalTis the disambiguator, but the existing implementation lowercases the basename before matching, which erases it. The new pattern uses the original-case basename and requires[A-Z][A-Za-z0-9]*Tests?\.(swift|kt|java|cs|scala)$.#865 — root-level / package-level
conftest.pypytest's fixture file is treated as a test by pytest regardless of where it lives in the tree. Previously only
conftest.pyfiles inside atests/directory were classified as tests; ones at the project root or alongside a package (a common pytest layout) were scored as production code.Added an early return on
basename == 'conftest.py'.Tests
Three new parametrized blocks in
tests/test_classes.py:test_is_test_file_detects_pascalcase_compiled_language_tests— 9 cases across Java / Kotlin / Swift / C# / Scalatest_is_test_file_rejects_pascalcase_lookalikes— guards againstLatest.kt,Manifest.java,latest.md,contest.csstest_is_test_file_detects_conftest_at_any_depth— root,tests/, package-level, deeply nestedExisting detection cases (gradle source sets, rspec, non-test lookalikes, snake_case
_test/_spec/.test) all still pass.Test plan
pytest tests/test_classes.py— 42 passedruff check gittensor/classes.py tests/test_classes.py— cleanruff format --check— cleanCloses #866
Closes #865