"""Tests for scripts/cycle_retro.py issue auto-detection.""" from __future__ import annotations # Import the module under test — it's a script so we import the helpers directly import importlib import subprocess from pathlib import Path from unittest.mock import patch import pytest SCRIPTS_DIR = Path(__file__).resolve().parent.parent.parent / "scripts" @pytest.fixture(autouse=True) def _add_scripts_to_path(monkeypatch): monkeypatch.syspath_prepend(str(SCRIPTS_DIR)) @pytest.fixture() def mod(): """Import cycle_retro as a module.""" return importlib.import_module("cycle_retro") class TestDetectIssueFromBranch: def test_kimi_issue_branch(self, mod): with patch.object(subprocess, "check_output", return_value="kimi/issue-492\n"): assert mod.detect_issue_from_branch() == 492 def test_plain_issue_branch(self, mod): with patch.object(subprocess, "check_output", return_value="issue-123\n"): assert mod.detect_issue_from_branch() == 123 def test_issue_slash_number(self, mod): with patch.object(subprocess, "check_output", return_value="fix/issue/55\n"): assert mod.detect_issue_from_branch() == 55 def test_no_issue_in_branch(self, mod): with patch.object(subprocess, "check_output", return_value="main\n"): assert mod.detect_issue_from_branch() is None def test_feature_branch(self, mod): with patch.object(subprocess, "check_output", return_value="feature/add-widget\n"): assert mod.detect_issue_from_branch() is None def test_git_not_available(self, mod): with patch.object(subprocess, "check_output", side_effect=FileNotFoundError): assert mod.detect_issue_from_branch() is None def test_git_fails(self, mod): with patch.object( subprocess, "check_output", side_effect=subprocess.CalledProcessError(1, "git"), ): assert mod.detect_issue_from_branch() is None class TestBackfillExtractIssueNumber: """Tests for backfill_retro.extract_issue_number PR-number filtering.""" @pytest.fixture() def backfill(self): return importlib.import_module("backfill_retro") def test_body_has_issue(self, backfill): assert backfill.extract_issue_number("fix: foo (#491)", "Fixes #490", pr_number=491) == 490 def test_title_skips_pr_number(self, backfill): assert backfill.extract_issue_number("fix: foo (#491)", "", pr_number=491) is None def test_title_with_issue_and_pr(self, backfill): # [loop-cycle-538] refactor: ... (#459) (#481) assert ( backfill.extract_issue_number( "[loop-cycle-538] refactor: remove dead airllm (#459) (#481)", "", pr_number=481, ) == 459 ) def test_no_pr_number_provided(self, backfill): assert backfill.extract_issue_number("fix: foo (#491)", "") == 491