"""Tests for gitea_list_prs pagination metadata (#340).""" import os import sys import unittest from unittest.mock import patch sys.path.insert(0, str(__import__("pathlib").Path(__file__).resolve().parent.parent)) import gitea_auth # noqa: E402 from mcp_server import gitea_list_prs # noqa: E402 from review_proofs import assess_list_prs_pagination_proof # noqa: E402 FAKE_AUTH = "Basic dGVzdDp0ZXN0" URL = "https://gitea.example.com/api/v1/repos/o/r/pulls?state=open" SAMPLE_PR = { "number": 1, "title": "PR 1", "state": "open", "head": {"ref": "branch1"}, "base": {"ref": "master"}, "mergeable": True, "updated_at": "2026-07-05T12:00:00Z", } class TestApiFetchPage(unittest.TestCase): @patch("gitea_auth.api_request") def test_final_page_metadata(self, mock_req): mock_req.return_value = [SAMPLE_PR] items, meta = gitea_auth.api_fetch_page(URL, FAKE_AUTH, page=1, limit=50) self.assertEqual(len(items), 1) self.assertFalse(meta["has_more"]) self.assertTrue(meta["is_final_page"]) self.assertIsNone(meta["next_page"]) @patch("gitea_auth.api_request") def test_full_page_has_more(self, mock_req): mock_req.return_value = [{"id": i} for i in range(2)] items, meta = gitea_auth.api_fetch_page(URL, FAKE_AUTH, page=1, limit=2) self.assertEqual(len(items), 2) self.assertTrue(meta["has_more"]) self.assertFalse(meta["is_final_page"]) self.assertEqual(meta["next_page"], 2) class TestGiteaListPrsPagination(unittest.TestCase): @patch("mcp_server.api_fetch_page") @patch("mcp_server.get_auth_header", return_value=FAKE_AUTH) def test_explicit_page_returns_has_more(self, _auth, mock_fetch): mock_fetch.return_value = ( [SAMPLE_PR], { "page": 1, "per_page": 50, "returned_count": 1, "has_more": False, "next_page": None, "is_final_page": True, }, ) with patch.dict(os.environ, {}, clear=True): result = gitea_list_prs(page=1, per_page=50) self.assertEqual(len(result["prs"]), 1) self.assertFalse(result["pagination"]["inventory_complete"]) self.assertTrue(result["pagination"]["is_final_page"]) @patch("mcp_server.api_fetch_page") @patch("mcp_server.get_auth_header", return_value=FAKE_AUTH) def test_multi_page_fetch_all_marks_inventory_complete(self, _auth, mock_fetch): mock_fetch.side_effect = [ ( [dict(SAMPLE_PR, number=i) for i in (1, 2)], { "page": 1, "per_page": 2, "returned_count": 2, "has_more": True, "next_page": 2, "is_final_page": False, }, ), ( [dict(SAMPLE_PR, number=3)], { "page": 2, "per_page": 2, "returned_count": 1, "has_more": False, "next_page": None, "is_final_page": True, }, ), ] with patch.dict(os.environ, {}, clear=True): result = gitea_list_prs(per_page=2) self.assertEqual([p["number"] for p in result["prs"]], [1, 2, 3]) self.assertTrue(result["pagination"]["inventory_complete"]) self.assertEqual(result["pagination"]["pages_fetched"], 2) self.assertEqual(result["pagination"]["total_count"], 3) class TestListPrsPaginationProof(unittest.TestCase): def test_wrapped_final_page_passes_completeness_claim(self): response = { "prs": [], "pagination": { "page": 1, "per_page": 50, "returned_count": 0, "has_more": False, "next_page": None, "is_final_page": True, "inventory_complete": True, "pages_fetched": 1, "total_count": 0, }, } result = assess_list_prs_pagination_proof( response, inventory_complete_claimed=True ) self.assertTrue(result["proven"]) def test_bare_list_blocks_completeness_claim(self): result = assess_list_prs_pagination_proof( [{"number": 1}], inventory_complete_claimed=True ) self.assertFalse(result["proven"]) self.assertIn("pagination metadata", " ".join(result["reasons"])) def test_single_page_without_complete_blocks_claim(self): response = { "prs": [{"number": 1}], "pagination": { "page": 1, "per_page": 50, "returned_count": 1, "has_more": True, "next_page": 2, "is_final_page": False, "inventory_complete": False, "pages_fetched": 1, "total_count": None, }, } result = assess_list_prs_pagination_proof( response, inventory_complete_claimed=True ) self.assertFalse(result["proven"]) if __name__ == "__main__": unittest.main()