diff --git a/packages/core/src/repowise/core/analysis/health/engine.py b/packages/core/src/repowise/core/analysis/health/engine.py index 618982d2c..0f0c3912d 100644 --- a/packages/core/src/repowise/core/analysis/health/engine.py +++ b/packages/core/src/repowise/core/analysis/health/engine.py @@ -252,8 +252,9 @@ def _has_paired_test_file(rel_path: str, path_basenames: set[str]) -> bool: stem = p.stem test_suffix = ".exs" if p.suffix == ".ex" else p.suffix candidates = { - f"test_{stem}.py", + f"test_{stem}{test_suffix}", f"{stem}_test{test_suffix}", + f"{stem}_spec{test_suffix}", f"{stem}.test.ts", f"{stem}.test.tsx", f"{stem}.test.js", diff --git a/tests/unit/health/test_paired_test_basenames.py b/tests/unit/health/test_paired_test_basenames.py index b90685eb6..e659ad428 100644 --- a/tests/unit/health/test_paired_test_basenames.py +++ b/tests/unit/health/test_paired_test_basenames.py @@ -25,6 +25,7 @@ def _reference_has_paired_test_file(rel_path: str, all_paths: set[str]) -> bool: candidates = { f"test_{stem}.py", f"{stem}_test.py", + f"{stem}_spec.rb", f"{stem}.test.ts", f"{stem}.test.tsx", f"{stem}.test.js", @@ -104,7 +105,6 @@ def test_empty_paths(self) -> None: assert _path_basenames(set()) == set() assert not _has_paired_test_file("anything.py", set()) - class TestPascalPairing: """Delphi/FPC's ``u``-prefixed unit pairs with a standalone console test program named ``Test.dpr`` (the ``u`` dropped) -- confirmed against @@ -141,3 +141,12 @@ def test_non_pascal_file_is_unaffected_by_pascal_candidate(self) -> None: # up the Pascal Test.dpr candidate. basenames = _path_basenames({"uKeymap.ts", "TestKeymap.dpr"}) assert not _has_paired_test_file("uKeymap.ts", basenames) + + def test_ruby_and_crystal_underscore_spec_pairing(self) -> None: + """Ruby's _spec.rb (and Crystal's _spec.cr) is a paired test (#1768).""" + ruby = {"spec/user_spec.rb"} + assert _has_paired_test_file("lib/user.rb", _path_basenames(ruby)) + crystal = {"spec/user_spec.cr"} + assert _has_paired_test_file("src/user.cr", _path_basenames(crystal)) + # Same stem, dot form, must NOT count for Ruby's underscore layout. + assert not _has_paired_test_file("lib/user.rb", _path_basenames({"spec/user.spec.rb"})) diff --git a/tests/unit/server/mcp/test_risk.py b/tests/unit/server/mcp/test_risk.py index 603b59e03..e1faa73f9 100644 --- a/tests/unit/server/mcp/test_risk.py +++ b/tests/unit/server/mcp/test_risk.py @@ -351,6 +351,9 @@ def test_classify_bus_factor_unknown_team_size_keeps_behaviour(): ("lib/user.dart", "test/user_test.dart"), ("lib/user.ex", "test/user_test.exs"), ("src/user.rs", "tests/user_test.rs"), + ("lib/user.rb", "spec/user_spec.rb"), + ("src/user.cr", "spec/user_spec.cr"), + ("lib/user.rb", "test/test_user.rb"), ], ) def test_health_filename_heuristic_supports_suffix_test_conventions(source, test):