test: ensure full candidate probing and clear cache in setUp

- Updates _check_bash_state to not short-circuit on the first unusable
  bash candidate on Windows, ensuring a working fallback is found if present.
- Clears bash detection cache in unittest setUp/tearDown rather than just
  relying on a pytest fixture, covering native unittest runners.
This commit is contained in:
Gracy769 authored and gaebal-gajae committed 2026-10-12 22:06:08 +00:00
1 parent 86cf10a43a
commit ad8cd12fa2
3 files changed
+24 -4

No files matched your search

+6 -2
View File
@@ -17,6 +17,7 @@ def _probe_bash(bash_path: str) -> bool:
@functools.lru_cache(maxsize=1)
def _check_bash_state() -> tuple[str | None, str]:
reasons = []
if os.name == 'nt':
for candidate in (
r'C:\Program Files\Git\bin\bash.exe',
@@ -27,12 +28,15 @@ def _check_bash_state() -> tuple[str | None, str]:
if os.path.exists(candidate):
if _probe_bash(candidate):
return candidate, ""
return None, f"bash present at {candidate} but unusable"
reasons.append(f"present at {candidate} but unusable")
bash = shutil.which('bash')
if bash and 'WindowsApps' not in bash:
if _probe_bash(bash):
return bash, ""
return None, f"bash present at {bash} but unusable"
reasons.append(f"present at {bash} but unusable")
if reasons:
return None, "bash found but broken: " + "; ".join(reasons)
return None, "Requires bash"
def get_bash_executable() -> str | None:
+9 -1
View File
@@ -5,7 +5,7 @@ import subprocess
import unittest
from pathlib import Path
from tests._bash import get_bash_executable, require_bash, bash_skip_reason
from tests._bash import get_bash_executable, require_bash, bash_skip_reason, _check_bash_state
REPO_ROOT = Path(__file__).resolve().parents[1]
@@ -13,6 +13,14 @@ PRE_PUSH_HOOK = REPO_ROOT / '.github' / 'hooks' / 'pre-push'
class PrePushHookContractTests(unittest.TestCase):
def setUp(self) -> None:
_check_bash_state.cache_clear()
super().setUp()
def tearDown(self) -> None:
_check_bash_state.cache_clear()
super().tearDown()
@unittest.skipUnless(require_bash(), bash_skip_reason())
def test_skip_escape_hatch_exits_successfully_with_stderr_notice(self) -> None:
bash_cmd = get_bash_executable() or 'bash'
+9 -1
View File
@@ -14,7 +14,7 @@ REPO_ROOT = Path(__file__).resolve().parents[1]
NEXT_ID = REPO_ROOT / 'scripts' / 'roadmap-next-id.sh'
DOGFOOD_PROBE = REPO_ROOT / 'scripts' / 'dogfood-probe.py'
from tests._bash import get_bash_executable, require_bash, bash_skip_reason
from tests._bash import get_bash_executable, require_bash, bash_skip_reason, _check_bash_state
def run_next_id(roadmap: Path, script: Path = NEXT_ID) -> subprocess.CompletedProcess[str]:
@@ -40,6 +40,14 @@ def run_dogfood_probe(args: list[str]) -> subprocess.CompletedProcess[str]:
class RoadmapHelperTests(unittest.TestCase):
def setUp(self) -> None:
_check_bash_state.cache_clear()
super().setUp()
def tearDown(self) -> None:
_check_bash_state.cache_clear()
super().tearDown()
@unittest.skipUnless(require_bash(), bash_skip_reason())
def test_roadmap_next_id_prints_only_next_id_after_duplicate_check(self) -> None:
with tempfile.TemporaryDirectory() as temp_dir: