Files
Gitea-Tools/tests/test_python_cli.py

115 lines
4.1 KiB
Python

"""Tests for the python CLI scripts close_issue.py and mark_issue.py.
All tests mock credentials and API requests so no real network calls are made.
"""
import sys
import unittest
from unittest.mock import patch, MagicMock
# The modules under test live in the repo root
sys.path.insert(0, str(__import__("pathlib").Path(__file__).resolve().parent.parent))
import close_issue
import mark_issue
FAKE_AUTH = "Basic dGVzdDp0ZXN0"
# ---------------------------------------------------------------------------
# close_issue.py
# ---------------------------------------------------------------------------
class TestCloseIssueCLI(unittest.TestCase):
def test_missing_argument_exits(self):
with self.assertRaises(SystemExit):
close_issue.main([])
def test_invalid_argument_type_exits(self):
with self.assertRaises(SystemExit):
close_issue.main(["not_a_number"])
@patch("close_issue.api_request")
@patch("close_issue.get_auth_header", return_value=FAKE_AUTH)
def test_successful_close(self, _auth, mock_api):
rc = close_issue.main(["42"])
self.assertEqual(rc, 0)
mock_api.assert_called_once()
url = mock_api.call_args[0][1]
self.assertIn("/issues/42", url)
self.assertEqual(mock_api.call_args[0][3], {"state": "closed"})
@patch("close_issue.api_request")
@patch("close_issue.get_auth_header", return_value=FAKE_AUTH)
def test_remote_override(self, _auth, mock_api):
rc = close_issue.main(["--remote", "prgs", "12"])
self.assertEqual(rc, 0)
url = mock_api.call_args[0][1]
self.assertIn("gitea.prgs.cc", url)
self.assertIn("/issues/12", url)
# ---------------------------------------------------------------------------
# mark_issue.py
# ---------------------------------------------------------------------------
class TestMarkIssueCLI(unittest.TestCase):
def test_missing_argument_exits(self):
with self.assertRaises(SystemExit):
mark_issue.main([])
def test_invalid_action_exits(self):
with self.assertRaises(SystemExit):
mark_issue.main(["10", "bogus_action"])
@patch("mark_issue.api_request")
@patch("mark_issue.get_auth_header", return_value=FAKE_AUTH)
def test_successful_start(self, _auth, mock_api):
# First call is GET labels, second is POST label
mock_api.side_effect = [
[{"id": 101, "name": "status:in-progress"}],
[{"name": "status:in-progress"}],
]
rc = mark_issue.main(["15", "start"])
self.assertEqual(rc, 0)
self.assertEqual(mock_api.call_count, 2)
# Verify GET labels call
get_call = mock_api.call_args_list[0]
self.assertEqual(get_call[0][0], "GET")
self.assertIn("/labels?limit=100", get_call[0][1])
# Verify POST labels call
post_call = mock_api.call_args_list[1]
self.assertEqual(post_call[0][0], "POST")
self.assertIn("/issues/15/labels", post_call[0][1])
self.assertEqual(post_call[0][3], {"labels": [101]})
@patch("mark_issue.api_request")
@patch("mark_issue.get_auth_header", return_value=FAKE_AUTH)
def test_successful_done(self, _auth, mock_api):
# First call is GET labels, second is DELETE label
mock_api.side_effect = [
[{"id": 101, "name": "status:in-progress"}],
None,
]
rc = mark_issue.main(["15", "done"])
self.assertEqual(rc, 0)
self.assertEqual(mock_api.call_count, 2)
# Verify DELETE labels call
delete_call = mock_api.call_args_list[1]
self.assertEqual(delete_call[0][0], "DELETE")
self.assertIn("/issues/15/labels/101", delete_call[0][1])
@patch("mark_issue.api_request")
@patch("mark_issue.get_auth_header", return_value=FAKE_AUTH)
def test_label_not_found(self, _auth, mock_api):
# GET labels returns no status:in-progress label
mock_api.return_value = [{"id": 1, "name": "bug"}]
rc = mark_issue.main(["15", "start"])
self.assertEqual(rc, 1)
if __name__ == "__main__":
unittest.main()