"""Unit tests for devx.tools.pre_push_check.""" from unittest.mock import MagicMock, patch import click import pytest from click.testing import CliRunner from devx.tools.pre_push_check import ( cli, extract_task_id, get_current_branch, task_exists, validate, ) class TestExtractTaskId: def test_valid_branch(self) -> None: assert extract_task_id("DEVX-42-fix-bug") == "DEVX-42" def test_no_task_id(self) -> None: assert extract_task_id("feature-branch") == "" def test_empty_branch(self) -> None: assert extract_task_id("") == "" class TestGetCurrentBranch: @patch("devx.tools.pre_push_check.subprocess.run") def test_success(self, mock_run: MagicMock) -> None: mock_run.return_value = MagicMock(stdout="DEVX-42-fix\n", returncode=0) assert get_current_branch() == "DEVX-42-fix" @patch("devx.tools.pre_push_check.subprocess.run") def test_failure(self, mock_run: MagicMock) -> None: mock_run.return_value = MagicMock(stdout="", returncode=1) assert get_current_branch() == "" class TestTaskExists: @patch("devx.tools.pre_push_check.VikunjaClient") @patch.dict("os.environ", {"VIKUNJA_TOKEN": "tok"}) def test_found(self, mock_client_cls: MagicMock) -> None: mock_client = MagicMock() mock_client.find_task_by_identifier.return_value = {"identifier": "DEVX-42"} mock_client_cls.return_value = mock_client assert task_exists("DEVX-42") is True @patch("devx.tools.pre_push_check.VikunjaClient") @patch.dict("os.environ", {"VIKUNJA_TOKEN": "tok"}) def test_not_found(self, mock_client_cls: MagicMock) -> None: mock_client = MagicMock() mock_client.find_task_by_identifier.return_value = None mock_client_cls.return_value = mock_client assert task_exists("DEVX-42") is False @patch.dict("os.environ", {}, clear=True) def test_no_token(self) -> None: assert task_exists("DEVX-42") is False class TestValidate: def test_master_branch_skips(self) -> None: validate("master") def test_main_branch_skips(self) -> None: validate("main") def test_empty_branch_skips(self) -> None: validate("") def test_no_task_id_raises(self) -> None: with pytest.raises(click.ClickException, match="does not contain a task ID"): validate("feature-branch") @patch.dict("os.environ", {}, clear=True) def test_no_token_warns(self) -> None: validate("DEVX-42-fix-bug") @patch("devx.tools.pre_push_check.task_exists", return_value=True) @patch.dict("os.environ", {"VIKUNJA_TOKEN": "tok"}) def test_task_exists_passes(self, mock_exists: MagicMock) -> None: validate("DEVX-42-fix-bug") @patch("devx.tools.pre_push_check.task_exists", return_value=False) @patch.dict("os.environ", {"VIKUNJA_TOKEN": "tok"}) def test_task_not_found_raises(self, mock_exists: MagicMock) -> None: with pytest.raises(click.ClickException, match="not found"): validate("DEVX-42-fix-bug") class TestCli: @patch("devx.tools.pre_push_check.get_current_branch", return_value="master") def test_auto_detect_master(self, mock_branch: MagicMock) -> None: runner = CliRunner() result = runner.invoke(cli, []) assert result.exit_code == 0 @patch("devx.tools.pre_push_check.get_current_branch") @patch("devx.tools.pre_push_check.task_exists", return_value=True) @patch.dict("os.environ", {"VIKUNJA_TOKEN": "tok"}) def test_explicit_branch(self, mock_exists: MagicMock, mock_branch: MagicMock) -> None: runner = CliRunner() result = runner.invoke(cli, ["--branch", "DEVX-42-fix"]) assert result.exit_code == 0 assert "passed" in result.output