"""Test the generic fetch_all paginator.""" from types import SimpleNamespace from typing import Any from unittest.mock import call, Mock from src.connectors.utils import fetch_all from src.constants import BATCH_SIZE def _page(items: list[Any], total_count: int) -> SimpleNamespace: """Build a fake paginated response with .items and .total_count.""" return SimpleNamespace(items=items, total_count=total_count) def test_fetch_all_single_page() -> None: """A single page (total_count == len(items)) yields all items in one call.""" fetch_page = Mock(side_effect=[_page(['a', 'b'], total_count=2)]) res = list(fetch_all(fetch_page)) assert res == ['a', 'b'] assert fetch_page.call_args_list == [call(limit=BATCH_SIZE, offset=0)] def test_fetch_all_multiple_pages() -> None: """Items are aggregated across pages and offset advances by limit.""" fetch_page = Mock( side_effect=[ _page(['a'], total_count=2), _page(['b'], total_count=2), ] ) res = list(fetch_all(fetch_page, limit=1)) assert res == ['a', 'b'] assert fetch_page.call_args_list == [ call(limit=1, offset=0), call(limit=1, offset=1), ] def test_fetch_all_stops_on_empty_first_page() -> None: """An empty page terminates the loop even when total_count claims more. Guards against an infinite loop when total_count overstates the number of items the endpoint actually returns. """ fetch_page = Mock(side_effect=[_page([], total_count=5)]) res = list(fetch_all(fetch_page, limit=1)) assert res == [] assert fetch_page.call_count == 1 def test_fetch_all_stops_on_empty_mid_page() -> None: """A short/empty page after some items stops paging despite a larger total_count.""" fetch_page = Mock( side_effect=[ _page(['a'], total_count=5), _page([], total_count=5), ] ) res = list(fetch_all(fetch_page, limit=1)) assert res == ['a'] assert fetch_page.call_count == 2 def test_fetch_all_forwards_args_and_kwargs() -> None: """Positional args and extra kwargs are forwarded to fetch_page each call.""" fetch_page = Mock(side_effect=[_page(['a'], total_count=1)]) res = list(fetch_all(fetch_page, 'arg1', limit=10, extra='value')) assert res == ['a'] assert fetch_page.call_args_list == [ call('arg1', limit=10, offset=0, extra='value') ]