"""Unit tests for content_publish tool."""
import pytest
import navi.content_store as content_store_mod
import navi.session_files as session_files_mod
import navi.tools.content_publish as content_publish_mod
from navi.tools._internal.base import ToolContext
from navi.tools.content_publish import ContentPublishTool
class TestContentPublishTool:
@pytest.fixture
def tool(self, monkeypatch, tmp_path):
from navi.config import Settings
_test_settings = Settings(session_files_dir=str(tmp_path / "sessions"))
monkeypatch.setattr(content_publish_mod, "settings", _test_settings)
monkeypatch.setattr(session_files_mod, "settings", _test_settings)
monkeypatch.setattr(content_store_mod, "settings", _test_settings)
yield ContentPublishTool()
async def test_requires_active_session(self):
result = await ContentPublishTool().execute({"filename": "logo.svg"}, ctx=ToolContext(session_id=None))
assert not result.success
assert result.error == "no_session"
async def test_missing_file_reports_session_dir(self, tool, tmp_path):
result = await tool.execute({"filename": "missing.svg"}, ctx=ToolContext(session_id="sess-1"))
assert not result.success
assert result.error == "not_found"
assert str(tmp_path / "sessions" / "sess-1") in result.output
assert "SESSION_FILES_DIR" in result.output
async def test_rejects_directory(self, tool, tmp_path):
sess_dir = tmp_path / "sessions" / "sess-1"
(sess_dir / "folder").mkdir(parents=True)
result = await tool.execute({"filename": "folder"}, ctx=ToolContext(session_id="sess-1"))
assert not result.success
assert result.error == "not_a_file"
async def test_strips_path_components_and_publishes(self, tool, monkeypatch, tmp_path):
sess_dir = tmp_path / "sessions" / "sess-1"
sess_dir.mkdir(parents=True)
(sess_dir / "logo.svg").write_text("<svg></svg>")
calls = []
async def fake_publish(**kwargs):
calls.append(kwargs)
return {
"id": "content-id",
"url": "http://localhost:8000/sessions/sess-1/files/logo.svg",
"filename": kwargs["filename"],
"content_type": kwargs["content_type"] or "svg",
"title": kwargs["title"] or kwargs["filename"],
}
monkeypatch.setattr(content_publish_mod, "publish", fake_publish)
result = await tool.execute({
"filename": "../logo.svg",
"title": "Logo",
"content_type": "svg",
}, ctx=ToolContext(session_id="sess-1"))
assert result.success
assert calls == [{
"session_id": "sess-1",
"filename": "logo.svg",
"title": "Logo",
"content_type": "svg",
"source_filename": None,
}]
assert result.metadata["filename"] == "logo.svg"
async def test_passes_optional_source_filename(self, tool, monkeypatch, tmp_path):
sess_dir = tmp_path / "sessions" / "sess-1"
sess_dir.mkdir(parents=True)
(sess_dir / "model.stl").write_text("solid model")
(sess_dir / "model.scad").write_text("cube([1, 1, 1]);")
calls = []
async def fake_publish(**kwargs):
calls.append(kwargs)
return {
"id": "content-id",
"url": "http://localhost:8000/sessions/sess-1/files/model.stl",
"filename": kwargs["filename"],
"content_type": "stl",
"title": kwargs["title"] or kwargs["filename"],
"source_filename": kwargs["source_filename"],
"source_url": "http://localhost:8000/sessions/sess-1/files/model.scad",
}
monkeypatch.setattr(content_publish_mod, "publish", fake_publish)
result = await tool.execute({
"filename": "model.stl",
"source_filename": "model.scad",
}, ctx=ToolContext(session_id="sess-1"))
assert result.success
assert calls[0]["source_filename"] == "model.scad"
assert result.metadata["source_filename"] == "model.scad"