"""Regression tests for project info error handling."""
from contextlib import asynccontextmanager
from types import SimpleNamespace
import pytest
import typer
from mcp.server.fastmcp.exceptions import ToolError
from typer.testing import CliRunner
from basic_memory.cli.app import app
from basic_memory.mcp.clients.project import ProjectClient
import basic_memory.cli.commands.command_utils as command_utils
import basic_memory.cli.commands.project as project_cmd # noqa: F401
runner = CliRunner()
@pytest.mark.asyncio
async def test_get_project_info_cloud_config_error_has_clear_message(monkeypatch, capsys):
"""Cloud internal proxy config failures should surface actionable guidance."""
@asynccontextmanager
async def fake_get_client(project_name=None):
yield object()
async def fake_get_active_project(client, project, context):
return SimpleNamespace(external_id="proj-123")
async def fake_get_info(self, project_external_id):
raise ToolError("Internal proxy error: Project 'demo' not found in configuration")
monkeypatch.setattr(command_utils, "get_client", fake_get_client)
monkeypatch.setattr(command_utils, "get_active_project", fake_get_active_project)
monkeypatch.setattr(ProjectClient, "get_info", fake_get_info)
with pytest.raises(typer.Exit) as exc:
await command_utils.get_project_info("demo")
assert exc.value.exit_code == 1
captured = capsys.readouterr()
combined_output = captured.out + captured.err
assert "Project info failed: cloud returned an internal configuration error" in combined_output
assert "bm project list" in combined_output
assert "--cloud" in combined_output
def test_project_info_does_not_print_wrapper_exit_code(monkeypatch):
"""project info should not append a secondary 'Error getting project info: 1' line."""
async def fake_get_project_info(_project_name: str):
raise typer.Exit(1)
monkeypatch.setattr(project_cmd, "get_project_info", fake_get_project_info)
result = runner.invoke(app, ["project", "info", "demo"])
assert result.exit_code == 1
assert "Error getting project info" not in result.output