import types import devplacepy.seo as seo import devplacepy.attachments as attach def test_truncate_no_overflow(): assert len(seo.truncate("x" * 200)) <= 160 assert seo.truncate("short text") == "short text" assert seo.truncate("") == "" def test_software_application_url_is_per_project(): schema = seo.software_application_schema({"uid": "p1", "slug": "p1-foo", "title": "P"}, "https://x.test") assert schema["url"] == "https://x.test/projects/p1-foo" def test_schema_types(): assert seo.organization_schema("https://x.test")["@type"] == "Organization" assert seo.news_article_schema({"uid": "n1", "title": "T", "synced_at": "2026-01-01"}, "https://x.test")["@type"] == "NewsArticle" assert seo.software_source_code_schema({"uid": "g1", "title": "G", "language": "python"}, "https://x.test")["@type"] == "SoftwareSourceCode" def test_news_article_publisher_is_organization(): schema = seo.news_article_schema({"uid": "n1", "title": "T", "synced_at": "2026-01-01"}, "https://x.test") assert schema["publisher"]["@type"] == "Organization" def test_site_url_prefers_env(monkeypatch): monkeypatch.setattr(seo, "SITE_URL", "https://configured.test") assert seo.site_url(None) == "https://configured.test" def test_site_url_falls_back_to_request(monkeypatch): monkeypatch.setattr(seo, "SITE_URL", "") request = types.SimpleNamespace(base_url="http://fallback.test/") assert seo.site_url(request) == "http://fallback.test" def test_upload_allowlist_excludes_dangerous_types(): assert ".svg" not in attach.ALLOWED_UPLOAD_TYPES assert ".html" not in attach.ALLOWED_UPLOAD_TYPES assert ".png" in attach.ALLOWED_UPLOAD_TYPES assert ".svg" not in attach.POST_IMAGE_EXTENSIONS def test_detect_mime_neutralizes_dangerous_types(): assert attach._detect_mime(b"", "x.svg") == "application/octet-stream" assert attach._detect_mime(b"", "x.html") == "application/octet-stream" assert attach._detect_mime(b"", "x.png") == "image/png"