from __future__ import annotations from pathlib import Path from unittest.mock import patch import pytest from click import ClickException from click.testing import CliRunner import scripts.ci.push_badges as push_badges class TestFetchLatestMaster: def test_fetch_and_reset(self) -> None: with patch("subprocess.run") as mock_run: push_badges.fetch_latest_master("master") # Should call git fetch and git reset --hard calls = [str(c.args[0]) for c in mock_run.call_args_list] assert any("fetch" in c for c in calls) assert any("reset" in c for c in calls) def test_custom_branch(self) -> None: with patch("subprocess.run") as mock_run: push_badges.fetch_latest_master("develop") calls = [list(c.args[0]) for c in mock_run.call_args_list] # fetch call should include the branch name fetch_call = [c for c in calls if "fetch" in c][0] assert "develop" in fetch_call # reset call should include origin/develop reset_call = [c for c in calls if "reset" in c][0] assert "origin/develop" in reset_call def test_fetch_failure_raises(self) -> None: import subprocess with patch("subprocess.run", side_effect=subprocess.CalledProcessError(1, "git fetch")): with pytest.raises(subprocess.CalledProcessError): push_badges.fetch_latest_master() class TestGenerateBadges: def test_success(self, tmp_path: Path) -> None: output_dir = tmp_path / ".badges" output_dir.mkdir() (output_dir / "badge1.svg").touch() with patch("subprocess.run") as mock_run: push_badges.generate_badges(str(output_dir)) mock_run.assert_called_once() def test_no_badges_generated(self, tmp_path: Path) -> None: output_dir = tmp_path / ".badges" output_dir.mkdir() with patch("subprocess.run"): with pytest.raises(ClickException, match="No badge SVG files generated"): push_badges.generate_badges(str(output_dir)) class TestPushToBadgesBranch: def test_success(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.chdir(tmp_path) badges_dir = tmp_path / ".badges" badges_dir.mkdir() svg = badges_dir / "badge1.svg" svg.write_text("") with patch("subprocess.run") as mock_run: push_badges.push_to_badges_branch(str(badges_dir)) # Should have called git config, checkout, rm, add, commit, push assert mock_run.call_count >= 6 # Verify the SVG was copied to cwd assert (tmp_path / "badge1.svg").exists() class TestMain: def test_success(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.chdir(tmp_path) badges_dir = tmp_path / ".badges" badges_dir.mkdir() (badges_dir / "badge1.svg").touch() runner = CliRunner() with patch("subprocess.run"): result = runner.invoke(push_badges.main, ["--output-dir", str(badges_dir)]) assert result.exit_code == 0 def test_no_badges(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.chdir(tmp_path) badges_dir = tmp_path / ".badges" badges_dir.mkdir() runner = CliRunner() with patch("subprocess.run"): result = runner.invoke(push_badges.main, ["--output-dir", str(badges_dir)]) assert result.exit_code != 0 def test_custom_branch(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.chdir(tmp_path) badges_dir = tmp_path / ".badges" badges_dir.mkdir() (badges_dir / "badge1.svg").touch() runner = CliRunner() with patch("subprocess.run") as mock_run: result = runner.invoke( push_badges.main, ["--output-dir", str(badges_dir), "--branch", "develop"], ) assert result.exit_code == 0 # Verify fetch was called with the custom branch calls = [list(c.args[0]) for c in mock_run.call_args_list] fetch_call = [c for c in calls if "fetch" in c][0] assert "develop" in fetch_call def test_fetch_failure(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.chdir(tmp_path) import subprocess runner = CliRunner() with patch("subprocess.run", side_effect=subprocess.CalledProcessError(1, "git fetch")): result = runner.invoke(push_badges.main, []) assert result.exit_code != 0