"""Unit tests for mcp-maildir server pure functions.""" import os os.environ["QDRANT_URL"] = "http://localhost:6333" os.environ["COLLECTION_NAME"] = "test" from server import ( normalize_email_address, payload_matches_participant, format_search_result, build_filter, ) class TestNormalizeEmailAddress: def test_empty_value(self): assert normalize_email_address("") == "" assert normalize_email_address(None) == "" def test_simple_email(self): assert normalize_email_address("user@example.com") == "user@example.com" def test_display_name_with_email(self): assert normalize_email_address("John Doe ") == "john@example.com" def test_whitespace_and_case(self): assert normalize_email_address(" USER@Example.COM ") == "user@example.com" def test_invalid_email_fallback(self): result = normalize_email_address("not-an-email") # Returns stripped lowercase version of the input assert result == "not-an-email" class TestPayloadMatchesParticipant: def test_sender_match_normalized(self): payload = {"sender": "alice@example.com"} assert payload_matches_participant(payload, "alice@example.com") is True def test_receiver_match_normalized(self): payload = {"receiver": "bob@example.com"} assert payload_matches_participant(payload, "bob@example.com") is True def test_sender_raw_match(self): payload = {"sender_raw": "alice@other.com"} assert payload_matches_participant(payload, "alice@other.com") is True def test_no_match(self): payload = {"sender": "alice@example.com", "receiver": "bob@example.com"} assert payload_matches_participant(payload, "carol@example.com") is False def test_display_name_in_sender(self): payload = {"sender": "Alice "} assert payload_matches_participant(payload, "alice@example.com") is True def test_display_name_in_receiver(self): payload = {"receiver": "Bob Smith "} assert payload_matches_participant(payload, "bob@example.com") is True def test_empty_payload(self): assert payload_matches_participant({}, "someone@example.com") is False def test_case_insensitive(self): payload = {"sender": "ALICE@EXAMPLE.COM"} assert payload_matches_participant(payload, "alice@example.com") is True class TestFormatSearchResult: def test_basic_formatting(self): class MockPoint: payload = { "message_id": "", "date": "2026-01-15T10:00:00", "sender": "alice@example.com", "receiver": "bob@example.com", "subject": "Hello", "attachments": ["file.pdf"], } score = 0.95 result = format_search_result(MockPoint()) assert result["message_id"] == "" assert result["date"] == "2026-01-15T10:00:00" assert result["sender"] == "alice@example.com" assert result["receiver"] == "bob@example.com" assert result["subject"] == "Hello" assert result["attachments"] == ["file.pdf"] assert result["score"] == 0.95 def test_empty_payload(self): class MockPoint: payload = None score = None result = format_search_result(MockPoint()) assert result["message_id"] is None assert result["score"] is None assert result["attachments"] == [] def test_missing_fields(self): class MockPoint: payload = {"message_id": "<123>"} score = 0.5 result = format_search_result(MockPoint()) assert result["message_id"] == "<123>" assert result["date"] is None assert result["sender"] is None assert result["receiver"] is None assert result["subject"] is None assert result["attachments"] == [] class TestBuildFilter: def test_no_filters_returns_none(self): assert build_filter(None, None, None) is None def test_empty_strings_return_none(self): assert build_filter("", "", "") is None def test_participant_filter_is_should_clause_on_sender_and_receiver(self): f = build_filter("alice@example.com", None, None) assert f is not None # The date conditions list must be absent and only the participant filter present assert len(f.must) == 1 participant = f.must[0] keys = [c.key for c in participant.should] assert keys == ["sender", "receiver"] assert all(c.match.value == "alice@example.com" for c in participant.should) def test_participant_normalized_before_match(self): f = build_filter("Alice ", None, None) should = f.must[0].should assert all(c.match.value == "alice@example.com" for c in should) def test_date_range_only(self): f = build_filter(None, "2026-01-01", "2026-06-30") assert len(f.must) == 1 cond = f.must[0] assert cond.key == "date" assert cond.range.gte is not None assert cond.range.lte is not None def test_start_date_only(self): f = build_filter(None, "2026-03-15", None) cond = f.must[0] assert cond.range.gte is not None assert cond.range.lte is None def test_end_date_only(self): f = build_filter(None, None, "2026-03-15") cond = f.must[0] assert cond.range.gte is None assert cond.range.lte is not None def test_combined_participant_and_date(self): f = build_filter("bob@example.org", "2026-01-01", "2026-12-31") assert len(f.must) == 2 # One is the participant should-filter, the other the date range kinds = sorted( "participant" if getattr(c, "should", None) else "date" for c in f.must ) assert kinds == ["date", "participant"]