diff --git a/main.py b/main.py index 5500559..e21ef1e 100644 --- a/main.py +++ b/main.py @@ -470,5 +470,29 @@ def calculate_poi(poi_id: int, travel_modes: str, listing_type: str) -> None: click.echo(f"Computed {total} distances") +from cli._context import CliContext +from cli.districts import districts_group + + +@cli.group("debug") +@click.option("--user-email", "-u", required=True, help="Email of user to impersonate") +@click.option("--http", "use_http", is_flag=True, default=False, help="Use HTTP requests instead of direct service calls") +@click.option("--json", "json_output", is_flag=True, default=False, help="Output in JSON format") +@click.option("--api-url", default="http://localhost:8000", help="API base URL for HTTP mode") +@click.pass_context +def debug(ctx: click.Context, user_email: str, use_http: bool, json_output: bool, api_url: str) -> None: + """Debug CLI — mirrors web UI interactions with superuser access.""" + ctx.ensure_object(dict) + ctx.obj["cli_ctx"] = CliContext( + user_email=user_email, + use_http=use_http, + json_output=json_output, + api_base_url=api_url, + ) + + +debug.add_command(districts_group) + + if __name__ == "__main__": cli() diff --git a/tests/unit/test_debug_cli.py b/tests/unit/test_debug_cli.py new file mode 100644 index 0000000..a369c16 --- /dev/null +++ b/tests/unit/test_debug_cli.py @@ -0,0 +1,56 @@ +"""Tests for the debug CLI.""" +from unittest.mock import MagicMock, patch + +from click.testing import CliRunner + +from main import cli + + +class TestDebugGroup: + """Tests for the debug command group.""" + + @patch("main.engine", new_callable=MagicMock) + def test_debug_help_shows_subcommands(self, mock_engine: MagicMock) -> None: + runner = CliRunner() + result = runner.invoke(cli, ["debug", "--help"]) + assert result.exit_code == 0 + assert "districts" in result.output + + @patch("main.engine", new_callable=MagicMock) + def test_debug_requires_user_email(self, mock_engine: MagicMock) -> None: + runner = CliRunner() + result = runner.invoke(cli, ["debug", "districts", "list"]) + assert result.exit_code != 0 + assert "user-email" in result.output.lower() or "Missing" in result.output + + +class TestDistrictsCommand: + """Tests for debug districts subcommand.""" + + @patch("cli.districts.district_service.get_all_districts") + @patch("main.engine", new_callable=MagicMock) + def test_list_districts_direct( + self, mock_engine: MagicMock, mock_get: MagicMock + ) -> None: + mock_get.return_value = {"London": "R1", "Camden": "R2"} + runner = CliRunner() + result = runner.invoke( + cli, ["debug", "-u", "test@example.com", "districts", "list"] + ) + assert result.exit_code == 0 + assert "London" in result.output + + @patch("cli.districts.district_service.get_all_districts") + @patch("main.engine", new_callable=MagicMock) + def test_list_districts_json( + self, mock_engine: MagicMock, mock_get: MagicMock + ) -> None: + mock_get.return_value = {"London": "R1"} + runner = CliRunner() + result = runner.invoke( + cli, ["debug", "-u", "test@example.com", "--json", "districts", "list"] + ) + assert result.exit_code == 0 + import json + data = json.loads(result.output) + assert "London" in data