chore: add unit tests for pure functions + CI test job
Docker Build and Push / test (pull_request) Failing after 1m35s
Docker Build and Push / build (pull_request) Has been skipped

- Unit tests for normalize_email_address, payload_matches_participant,
  format_search_result (9 test cases across 3 test classes)
- New 'test' job in CI workflow (runs before build)
- pytest.ini for pythonpath config
This commit is contained in:
2026-06-11 12:18:20 +00:00
parent 93549155b2
commit 1700877918
3 changed files with 125 additions and 3 deletions
+16 -3
View File
@@ -9,11 +9,24 @@ on:
- cron: '0 0 * * *' - cron: '0 0 * * *'
jobs: jobs:
build: test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 - uses: actions/setup-python@v6
with:
python-version: "3.13"
- name: Install dependencies
run: |
pip install -r requirements.txt pytest
- name: Run unit tests
run: pytest tests/ -v
build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4 uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4
+3
View File
@@ -0,0 +1,3 @@
[pytest]
testpaths = tests
pythonpath = src
+106
View File
@@ -0,0 +1,106 @@
"""Unit tests for mcp-maildir server pure functions."""
from server import (
normalize_email_address,
payload_matches_participant,
format_search_result,
)
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>") == "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 <alice@example.com>"}
assert payload_matches_participant(payload, "alice@example.com") is True
def test_display_name_in_receiver(self):
payload = {"receiver": "Bob Smith <bob@example.com>"}
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": "<abc@def>",
"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"] == "<abc@def>"
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"] == []