"""Tests for the OpenCDE select-documents picker endpoints."""
from __future__ import annotations
from urllib.parse import parse_qs, urlparse
import pytest
from fastapi.testclient import TestClient
from ifcurl.documents_api import encode_document_id
from ifcurl.service import _rate_hits, app
client = TestClient(app)
CALLBACK = "https://viewer.example.com/api/opencde/callback"
@pytest.fixture(autouse=True)
def reset_rate_limit():
_rate_hits.clear()
yield
_rate_hits.clear()
# ---------------------------------------------------------------------------
# POST /documents/1.0/select-documents
# ---------------------------------------------------------------------------
class TestSelectDocuments:
def _post(self, callback_url=CALLBACK, headers=None):
return client.post(
"/documents/1.0/select-documents",
json={"callback": {"url": callback_url, "expires_in": 3600}},
headers=headers or {},
)
def test_returns_200(self):
r = self._post()
assert r.status_code == 200
def test_returns_select_documents_url(self):
r = self._post()
assert "select_documents_url" in r.json()
def test_url_points_to_picker_ui(self):
r = self._post()
url = r.json()["select_documents_url"]
assert "/documents/1.0/select-documents/ui" in url
def test_callback_url_encoded_in_picker_url(self):
r = self._post()
picker_url = r.json()["select_documents_url"]
parsed = urlparse(picker_url)
params = parse_qs(parsed.query)
assert "callback_url" in params
assert params["callback_url"][0] == CALLBACK
def test_picker_url_uses_forwarded_host(self):
r = self._post(
headers={"x-forwarded-host": "cde.example.com", "x-forwarded-proto": "https"}
)
url = r.json()["select_documents_url"]
assert url.startswith("https://cde.example.com/")
def test_missing_callback_url_returns_422(self):
r = client.post(
"/documents/1.0/select-documents",
json={"callback": {"expires_in": 3600}},
)
assert r.status_code == 422
def test_missing_callback_object_returns_422(self):
r = client.post("/documents/1.0/select-documents", json={})
assert r.status_code == 422
# ---------------------------------------------------------------------------
# GET /documents/1.0/select-documents/ui
# ---------------------------------------------------------------------------
class TestSelectDocumentsUi:
def _get(self, callback_url=CALLBACK):
from urllib.parse import quote
return client.get(
"/documents/1.0/select-documents/ui",
params={"callback_url": callback_url},
)
def test_returns_200(self):
r = self._get()
assert r.status_code == 200
def test_returns_html(self):
r = self._get()
assert "text/html" in r.headers["content-type"]
def test_html_contains_callback_url(self):
r = self._get()
assert CALLBACK in r.text
def test_html_contains_forgejo_base(self):
r = self._get()
# FORGEJO_BASE is embedded as a JS string literal
assert "localhost:3000" in r.text or "forgejo" in r.text.lower()
def test_html_has_repo_select(self):
r = self._get()
assert "repo-select" in r.text
def test_html_has_file_list(self):
r = self._get()
assert "file-list" in r.text
def test_missing_callback_url_returns_400(self):
r = client.get("/documents/1.0/select-documents/ui")
assert r.status_code in (400, 422)
def test_callback_url_safely_embedded(self):
# Ensure XSS-dangerous characters in callback URL are JSON-escaped
evil = 'https://example.com/cb?x=1&y='
r = self._get(callback_url=evil)
assert r.status_code == 200
# The raw should not appear unescaped outside a JSON string
assert "