Files
webmail-client/backend/tests/indexer/test_mime.py
T

104 lines
3.4 KiB
Python
Raw Normal View History

2026-07-17 23:20:34 +02:00
"""MIME parsing (SPEC §6.4)."""
from __future__ import annotations
from email.message import EmailMessage
from app.indexer.mime import parse_message
def _build(
*,
subject: str = "Hello",
from_addr: str = "Alice <alice@example.com>",
to_addr: str = "bob@example.com",
message_id: str = "<m1@example.com>",
references: str | None = None,
in_reply_to: str | None = None,
text: str | None = "plain body",
html: str | None = None,
) -> bytes:
msg = EmailMessage()
msg["Subject"] = subject
msg["From"] = from_addr
msg["To"] = to_addr
msg["Message-ID"] = message_id
msg["Date"] = "Mon, 09 Mar 2026 08:36:37 +0100"
if references:
msg["References"] = references
if in_reply_to:
msg["In-Reply-To"] = in_reply_to
if text is not None:
msg.set_content(text)
if html is not None:
if text is not None:
msg.add_alternative(html, subtype="html")
else:
msg.set_content(html, subtype="html")
return msg.as_bytes()
def test_parse_basic_headers_and_body() -> None:
parsed = parse_message(_build())
assert parsed.subject == "Hello"
assert parsed.message_id == "m1@example.com"
assert parsed.from_addr == [{"name": "Alice", "email": "alice@example.com"}]
assert parsed.to_addr == [{"name": "", "email": "bob@example.com"}]
assert "plain body" in parsed.text_body
assert parsed.date is not None
assert parsed.snippet == "plain body"
def test_references_include_in_reply_to_in_order() -> None:
parsed = parse_message(_build(references="<a@x.com> <b@x.com>", in_reply_to="<b@x.com>"))
# References first, then In-Reply-To, deduped
assert parsed.references == ["a@x.com", "b@x.com"]
assert parsed.in_reply_to == "b@x.com"
def test_html_only_derives_text() -> None:
parsed = parse_message(_build(text=None, html="<p>Hello <b>world</b></p>"))
assert parsed.html_body is not None
assert "Hello" in parsed.text_body
assert "world" in parsed.text_body
assert "<b>" not in parsed.text_body # tags stripped for indexing text
def test_multipart_alternative_prefers_html_for_display() -> None:
parsed = parse_message(_build(text="text version", html="<p>html version</p>"))
assert parsed.html_body is not None
assert "html version" in parsed.html_body
assert "text version" in parsed.text_body
def test_rfc2047_encoded_subject_is_decoded() -> None:
# "Próba" base64-encoded UTF-8
parsed = parse_message(_build(subject="=?UTF-8?B?UHLDs2Jh?="))
assert parsed.subject == "Próba"
def test_attachment_extracted() -> None:
msg = EmailMessage()
msg["Subject"] = "with attachment"
msg["From"] = "a@b.com"
msg["To"] = "c@d.com"
msg["Message-ID"] = "<att@example.com>"
msg.set_content("see attached")
msg.add_attachment(
b"\x00\x01\x02data", maintype="application", subtype="octet-stream", filename="file.bin"
)
parsed = parse_message(msg.as_bytes())
assert parsed.has_attachments
assert parsed.attachments[0].filename == "file.bin"
assert parsed.attachments[0].payload == b"\x00\x01\x02data"
def test_missing_message_id_returns_none() -> None:
msg = EmailMessage()
msg["Subject"] = "no id"
msg["From"] = "a@b.com"
msg["To"] = "c@d.com"
msg.set_content("body")
parsed = parse_message(msg.as_bytes())
assert parsed.message_id is None