"""Tests for review_pr.py. Mocks api_request and credentials. """ import sys import unittest from unittest.mock import patch sys.path.insert(0, str(__import__("pathlib").Path(__file__).resolve().parent.parent)) import review_pr # noqa: E402 FAKE_CREDS = "Basic dGVzdHVzZXI6dGVzdHBhc3M=" FAKE_PR_DATA = { "number": 81, "state": "open", "head": { "ref": "feature-branch", "sha": "abcdef1234567890" }, "base": { "ref": "main" }, "html_url": "https://gitea.example.com/pulls/81" } class TestArgParsing(unittest.TestCase): @patch("review_pr.get_auth_header", return_value=FAKE_CREDS) def test_missing_pr_number_exits(self, _auth): with self.assertRaises(SystemExit): review_pr.main([]) class TestAPIPayload(unittest.TestCase): @patch("review_pr.api_request") @patch("review_pr.get_auth_header", return_value=FAKE_CREDS) def test_payload_fields_and_workflow(self, _auth, mock_api): # Setup mock api_request to return PR details, then review response mock_api.side_effect = [FAKE_PR_DATA, {}] rc = review_pr.main([ "--pr-number", "81", "--event", "APPROVE", "--body", "Approved and ready to merge", ]) self.assertEqual(rc, 0) self.assertEqual(mock_api.call_count, 2) # Verify first call: GET PR first_call_args = mock_api.call_args_list[0] self.assertEqual(first_call_args[0][0], "GET") self.assertEqual(first_call_args[0][1], "https://gitea.dadeschools.net/api/v1/repos/Contractor/Timesheet/pulls/81") # Verify second call: POST review second_call_args = mock_api.call_args_list[1] self.assertEqual(second_call_args[0][0], "POST") self.assertEqual(second_call_args[0][1], "https://gitea.dadeschools.net/api/v1/repos/Contractor/Timesheet/pulls/81/reviews") payload = second_call_args[0][3] self.assertEqual(payload["event"], "APPROVE") self.assertEqual(payload["body"], "Approved and ready to merge") self.assertEqual(payload["commit_id"], "abcdef1234567890") @patch("review_pr.api_request") @patch("review_pr.get_auth_header", return_value=FAKE_CREDS) def test_merge_flag_fails_closed_without_api_call(self, _auth, mock_api): # --merge is an ungated bypass and is disabled (#16). It must fail # closed BEFORE any API call — no review, no merge. rc = review_pr.main([ "--pr-number", "81", "--event", "APPROVE", "--body", "Approved", "--merge", "--merge-method", "squash", ]) self.assertEqual(rc, 2) self.assertEqual(mock_api.call_count, 0) def test_merge_flag_message_points_to_gated_workflow(self): import io import contextlib with patch("review_pr.get_auth_header", return_value=FAKE_CREDS), \ patch("review_pr.api_request") as mock_api: buf = io.StringIO() with contextlib.redirect_stderr(buf): rc = review_pr.main([ "--pr-number", "81", "--event", "APPROVE", "--merge", ]) self.assertEqual(rc, 2) self.assertEqual(mock_api.call_count, 0) msg = buf.getvalue().lower() self.assertIn("disabled", msg) self.assertIn("gitea_merge_pr", msg) if __name__ == "__main__": unittest.main()