7afa33f375
Agent-Logs-Url: https://github.com/christianlouis/InboxConverge/sessions/63618a76-39b3-43af-b7a8-be2ae3d3ec8a Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
184 lines
6.7 KiB
Python
184 lines
6.7 KiB
Python
"""
|
||
Unit tests for Gmail label utilities (utils/gmail_labels.py).
|
||
Pure function tests – no database or HTTP layer required.
|
||
"""
|
||
|
||
from app.utils.gmail_labels import (
|
||
DEFAULT_IMPORT_LABEL_TEMPLATES,
|
||
MAX_IMPORT_LABELS,
|
||
_normalize_string_list,
|
||
normalize_import_label_templates,
|
||
extract_granted_scopes,
|
||
extract_import_label_templates,
|
||
build_gmail_credential_scopes,
|
||
render_import_labels,
|
||
)
|
||
|
||
|
||
class TestNormalizeStringList:
|
||
def test_basic_dedup(self):
|
||
result = _normalize_string_list(["a", "A", "b"])
|
||
assert result == ["a", "b"]
|
||
|
||
def test_strips_whitespace(self):
|
||
result = _normalize_string_list([" hello ", "world"])
|
||
assert result == ["hello", "world"]
|
||
|
||
def test_empty_strings_filtered(self):
|
||
result = _normalize_string_list(["", " ", "real"])
|
||
assert result == ["real"]
|
||
|
||
def test_none_returns_empty(self):
|
||
assert _normalize_string_list(None) == []
|
||
|
||
def test_preserves_case_in_output(self):
|
||
# Case-insensitive dedup but preserves original casing
|
||
result = _normalize_string_list(["Hello", "hello"])
|
||
assert result == ["Hello"]
|
||
|
||
def test_order_preserved(self):
|
||
items = ["c", "a", "b"]
|
||
assert _normalize_string_list(items) == ["c", "a", "b"]
|
||
|
||
|
||
class TestNormalizeImportLabelTemplates:
|
||
def test_none_returns_defaults(self):
|
||
result = normalize_import_label_templates(None)
|
||
assert result == DEFAULT_IMPORT_LABEL_TEMPLATES
|
||
|
||
def test_empty_list_returns_defaults(self):
|
||
result = normalize_import_label_templates([])
|
||
assert result == DEFAULT_IMPORT_LABEL_TEMPLATES
|
||
|
||
def test_custom_templates(self):
|
||
result = normalize_import_label_templates(["archive", "inbox"])
|
||
assert result == ["archive", "inbox"]
|
||
|
||
def test_deduplicates(self):
|
||
result = normalize_import_label_templates(["tag", "TAG"])
|
||
assert result == ["tag"]
|
||
|
||
def test_returns_copy_of_defaults(self):
|
||
result = normalize_import_label_templates(None)
|
||
result.append("extra")
|
||
assert "extra" not in DEFAULT_IMPORT_LABEL_TEMPLATES
|
||
|
||
|
||
class TestExtractGrantedScopes:
|
||
def test_list_format(self):
|
||
result = extract_granted_scopes(["scope1", "scope2"])
|
||
assert result == ["scope1", "scope2"]
|
||
|
||
def test_list_filters_non_strings(self):
|
||
result = extract_granted_scopes(["valid", 42, None, "other"])
|
||
assert result == ["valid", "other"]
|
||
|
||
def test_dict_format(self):
|
||
data = {"granted_scopes": ["https://mail.google.com/", "openid"]}
|
||
result = extract_granted_scopes(data)
|
||
assert result == ["https://mail.google.com/", "openid"]
|
||
|
||
def test_dict_missing_granted_scopes(self):
|
||
result = extract_granted_scopes({})
|
||
assert result == []
|
||
|
||
def test_dict_non_list_granted_scopes(self):
|
||
result = extract_granted_scopes({"granted_scopes": "not-a-list"})
|
||
assert result == []
|
||
|
||
def test_unrecognized_type(self):
|
||
assert extract_granted_scopes(None) == []
|
||
assert extract_granted_scopes(42) == []
|
||
assert extract_granted_scopes("string") == []
|
||
|
||
|
||
class TestExtractImportLabelTemplates:
|
||
def test_dict_with_templates(self):
|
||
data = {"import_label_templates": ["archive", "imported"]}
|
||
result = extract_import_label_templates(data)
|
||
assert result == ["archive", "imported"]
|
||
|
||
def test_dict_missing_key(self):
|
||
result = extract_import_label_templates({})
|
||
assert result == DEFAULT_IMPORT_LABEL_TEMPLATES
|
||
|
||
def test_non_dict(self):
|
||
assert extract_import_label_templates(None) == DEFAULT_IMPORT_LABEL_TEMPLATES
|
||
assert extract_import_label_templates([]) == DEFAULT_IMPORT_LABEL_TEMPLATES
|
||
|
||
def test_empty_templates_falls_back_to_defaults(self):
|
||
result = extract_import_label_templates({"import_label_templates": []})
|
||
assert result == DEFAULT_IMPORT_LABEL_TEMPLATES
|
||
|
||
def test_filters_non_strings(self):
|
||
data = {"import_label_templates": ["valid", 123, None]}
|
||
result = extract_import_label_templates(data)
|
||
assert result == ["valid"]
|
||
|
||
|
||
class TestBuildGmailCredentialScopes:
|
||
def test_basic(self):
|
||
result = build_gmail_credential_scopes(
|
||
["https://mail.google.com/"], ["{{source_email}}", "imported"]
|
||
)
|
||
assert "granted_scopes" in result
|
||
assert "import_label_templates" in result
|
||
assert result["granted_scopes"] == ["https://mail.google.com/"]
|
||
|
||
def test_none_granted_scopes(self):
|
||
result = build_gmail_credential_scopes(None)
|
||
assert result["granted_scopes"] == []
|
||
assert result["import_label_templates"] == DEFAULT_IMPORT_LABEL_TEMPLATES
|
||
|
||
def test_deduplication(self):
|
||
result = build_gmail_credential_scopes(["scope", "SCOPE"])
|
||
assert result["granted_scopes"] == ["scope"]
|
||
|
||
|
||
class TestRenderImportLabels:
|
||
def test_source_email_substitution(self):
|
||
result = render_import_labels(["{{source_email}}"], "user@example.com")
|
||
assert result == ["user@example.com"]
|
||
|
||
def test_literal_template(self):
|
||
result = render_import_labels(["imported"], "user@example.com")
|
||
assert result == ["imported"]
|
||
|
||
def test_mixed_templates(self):
|
||
result = render_import_labels(
|
||
["{{source_email}}", "imported"], "user@example.com"
|
||
)
|
||
assert result == ["user@example.com", "imported"]
|
||
|
||
def test_deduplication(self):
|
||
result = render_import_labels(["tag", "TAG"], "user@example.com")
|
||
assert result == ["tag"]
|
||
|
||
def test_none_source_email(self):
|
||
# Template containing source_email placeholder with no email → empty string,
|
||
# gets stripped, filtered out.
|
||
result = render_import_labels(["{{source_email}}"], None)
|
||
assert result == []
|
||
|
||
def test_empty_source_email(self):
|
||
result = render_import_labels(["{{source_email}}"], "")
|
||
assert result == []
|
||
|
||
def test_none_templates_uses_defaults(self):
|
||
result = render_import_labels(None, "user@example.com")
|
||
assert "user@example.com" in result
|
||
assert "imported" in result
|
||
|
||
def test_whitespace_only_template_filtered(self):
|
||
# Whitespace-only entries are stripped to empty strings and then filtered
|
||
# by normalize_import_label_templates. When no valid templates remain,
|
||
# defaults are returned. The source_email template then renders to the
|
||
# source email, and "imported" is included too.
|
||
result = render_import_labels([" "], "user@example.com")
|
||
# normalize_import_label_templates falls back to defaults → includes
|
||
# {{source_email}} (renders to "user@example.com") and "imported"
|
||
assert result == ["user@example.com", "imported"]
|
||
|
||
def test_max_labels_constant(self):
|
||
assert MAX_IMPORT_LABELS == 10
|