from __future__ import annotations from app.gmail_agent import GmailTriageAgent class _FailingClassifier: def classify(self, **kwargs): # type: ignore[no-untyped-def] raise RuntimeError("model unavailable") def test_build_effective_query_enforces_inbox_and_unread() -> None: agent = GmailTriageAgent(gmail_service=object(), query="-label:AgentProcessed") assert ( agent._build_effective_query() == "-label:AgentProcessed in:inbox is:unread" ) def test_build_effective_query_keeps_existing_requirements() -> None: agent = GmailTriageAgent( gmail_service=object(), query="IN:INBOX is:unread -label:AgentProcessed", ) assert agent._build_effective_query() == "IN:INBOX is:unread -label:AgentProcessed" def test_classify_email_returns_other_when_model_fails_and_no_rules_fallback() -> None: agent = GmailTriageAgent( gmail_service=object(), query="", classifier=_FailingClassifier(), # type: ignore[arg-type] fallback_to_rules=False, ) label = agent._classify_email( message_id="m1", sender="newsletter@example.com", subject="50% OFF today", snippet="promo content", list_unsubscribe="", precedence="bulk", message_label_ids={"CATEGORY_PROMOTIONS"}, ) assert label == "OTHER" def test_classify_email_prioritizes_linkedin_over_advertising_signals() -> None: agent = GmailTriageAgent( gmail_service=object(), query="", classifier=None, fallback_to_rules=True, ) label = agent._classify_email( message_id="m2", sender="jobs-noreply@linkedin.com", subject="Limited time offer for your profile", snippet="promotional snippet", list_unsubscribe="", precedence="bulk", message_label_ids={"CATEGORY_PROMOTIONS"}, ) assert label == "LINKEDIN"