Files
odysseus/tests/test_document_export_zip_filenames.py
T

97 lines
4.1 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""ZIP exports keep language extensions and place collision suffixes before them."""
import io
import zipfile
import pytest
from fastapi import FastAPI, Request
from fastapi.testclient import TestClient
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from core.database import Base, Document
from routes.document import document_routes
@pytest.fixture
def exports(tmp_path, monkeypatch):
engine = create_engine(f"sqlite:///{tmp_path / 'documents.db'}", connect_args={"check_same_thread": False})
Base.metadata.create_all(engine)
factory = sessionmaker(bind=engine)
monkeypatch.setattr(document_routes, "SessionLocal", factory)
monkeypatch.setenv("AUTH_ENABLED", "true")
app = FastAPI()
@app.middleware("http")
async def fixture_user(request: Request, call_next):
request.state.current_user = "alice"
return await call_next(request)
app.include_router(document_routes.setup_document_routes(None))
def add(doc_id, title, language, content="body\n", owner="alice"):
with factory() as db:
db.add(Document(id=doc_id, title=title, language=language,
current_content=content, owner=owner, is_active=True))
db.commit()
with TestClient(app) as client:
yield client, add
engine.dispose()
@pytest.mark.parametrize("title,language,filename", [
("config.local", "python", "config.local.py"),
("report.v2", "markdown", "report.v2.md"),
("data.2024", "json", "data.2024.json"),
("module.ts", "typescript", "module.ts"),
("SCRIPT.PY", "python", "SCRIPT.PY"),
("résumé.v2", "text", "résumé.v2.txt"),
("unknown.v2", "unknown", "unknown.v2.txt"),
("draft", None, "draft.txt"),
("project/report.v2", "markdown", "projectreport.v2.md"),
])
def test_export_uses_the_language_extension_even_for_dotted_titles(exports, title, language, filename):
client, add = exports
body = "Original text: α\n"
add("doc", title, language, body)
response = client.post("/api/documents/export-zip", json={"ids": ["doc"]})
assert response.status_code == 200
assert response.headers["content-type"] == "application/zip"
with zipfile.ZipFile(io.BytesIO(response.content)) as archive:
assert archive.namelist() == [filename]
assert archive.read(filename).decode() == body
@pytest.mark.parametrize("title", ["config.local", "config.local.py"])
def test_duplicate_names_keep_the_extension_at_the_end(exports, title):
client, add = exports
for i in range(3):
add(str(i), title, "python", f"body {i}")
response = client.post("/api/documents/export-zip", json={"ids": ["0", "1", "2"]})
assert response.status_code == 200
with zipfile.ZipFile(io.BytesIO(response.content)) as archive:
assert set(archive.namelist()) == {"config.local.py", "config.local-1.py", "config.local-2.py"}
assert {archive.read(name).decode() for name in archive.namelist()} == {"body 0", "body 1", "body 2"}
def test_added_extension_collides_safely_with_an_existing_extension(exports):
client, add = exports
add("a", "report.v2", "markdown", "first")
add("b", "report.v2.md", "markdown", "second")
response = client.post("/api/documents/export-zip", json={"ids": ["a", "b"]})
assert response.status_code == 200
with zipfile.ZipFile(io.BytesIO(response.content)) as archive:
assert set(archive.namelist()) == {"report.v2.md", "report.v2-1.md"}
assert {archive.read(name) for name in archive.namelist()} == {b"first", b"second"}
def test_foreign_documents_are_still_excluded_and_email_body_is_preserved(exports):
client, add = exports
add("owned", "reply.v2", "email", "Subject: Hello\n---\nBody")
add("foreign", "private", "python", "secret", owner="bob")
response = client.post("/api/documents/export-zip", json={"ids": ["owned", "foreign"]})
assert response.status_code == 200
with zipfile.ZipFile(io.BytesIO(response.content)) as archive:
assert archive.namelist() == ["reply.v2.eml"]
assert archive.read("reply.v2.eml") == b"Subject: Hello\r\n\r\nBody"