mirror of
https://github.com/pocketpaw/pocketpaw.git
synced 2026-05-13 21:21:53 +00:00
Complete the package rename: src/pocketclaw/ → src/pocketpaw/, all imports, pyproject.toml entry point, docs code examples, installer references, and test patch targets updated. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
120 lines
4.0 KiB
Python
120 lines
4.0 KiB
Python
# Tests for integrations/gmail.py and tools/builtin/gmail.py
|
|
# Created: 2026-02-07
|
|
|
|
import base64
|
|
from unittest.mock import patch
|
|
|
|
from pocketpaw.integrations.gmail import GmailClient
|
|
from pocketpaw.tools.builtin.gmail import GmailReadTool, GmailSearchTool, GmailSendTool
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# GmailClient._extract_body
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestExtractBody:
|
|
def test_plain_text_direct(self):
|
|
payload = {
|
|
"mimeType": "text/plain",
|
|
"body": {"data": base64.urlsafe_b64encode(b"Hello world").decode()},
|
|
}
|
|
assert GmailClient._extract_body(payload) == "Hello world"
|
|
|
|
def test_multipart(self):
|
|
payload = {
|
|
"mimeType": "multipart/alternative",
|
|
"parts": [
|
|
{
|
|
"mimeType": "text/plain",
|
|
"body": {"data": base64.urlsafe_b64encode(b"Text body").decode()},
|
|
},
|
|
{
|
|
"mimeType": "text/html",
|
|
"body": {"data": base64.urlsafe_b64encode(b"<p>HTML</p>").decode()},
|
|
},
|
|
],
|
|
}
|
|
assert GmailClient._extract_body(payload) == "Text body"
|
|
|
|
def test_no_text_content(self):
|
|
payload = {"mimeType": "multipart/mixed", "parts": []}
|
|
assert GmailClient._extract_body(payload) == "(no text content)"
|
|
|
|
def test_nested_multipart(self):
|
|
payload = {
|
|
"mimeType": "multipart/mixed",
|
|
"parts": [
|
|
{
|
|
"mimeType": "multipart/alternative",
|
|
"parts": [
|
|
{
|
|
"mimeType": "text/plain",
|
|
"body": {"data": base64.urlsafe_b64encode(b"Nested").decode()},
|
|
},
|
|
],
|
|
}
|
|
],
|
|
}
|
|
assert GmailClient._extract_body(payload) == "Nested"
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Tool definitions
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
class TestToolDefinitions:
|
|
def test_gmail_search_tool(self):
|
|
tool = GmailSearchTool()
|
|
assert tool.name == "gmail_search"
|
|
assert tool.trust_level == "high"
|
|
assert "query" in tool.parameters["properties"]
|
|
|
|
def test_gmail_read_tool(self):
|
|
tool = GmailReadTool()
|
|
assert tool.name == "gmail_read"
|
|
assert "message_id" in tool.parameters["properties"]
|
|
|
|
def test_gmail_send_tool(self):
|
|
tool = GmailSendTool()
|
|
assert tool.name == "gmail_send"
|
|
assert "to" in tool.parameters["properties"]
|
|
assert "subject" in tool.parameters["properties"]
|
|
assert "body" in tool.parameters["properties"]
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Tool execution — error path (no OAuth token)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
async def test_gmail_search_no_auth():
|
|
tool = GmailSearchTool()
|
|
with patch(
|
|
"pocketpaw.integrations.gmail.GmailClient._get_token",
|
|
side_effect=RuntimeError("Not authenticated"),
|
|
):
|
|
result = await tool.execute(query="test")
|
|
assert "Error" in result
|
|
assert "authenticated" in result.lower()
|
|
|
|
|
|
async def test_gmail_read_no_auth():
|
|
tool = GmailReadTool()
|
|
with patch(
|
|
"pocketpaw.integrations.gmail.GmailClient._get_token",
|
|
side_effect=RuntimeError("Not authenticated"),
|
|
):
|
|
result = await tool.execute(message_id="abc123")
|
|
assert "Error" in result
|
|
|
|
|
|
async def test_gmail_send_no_auth():
|
|
tool = GmailSendTool()
|
|
with patch(
|
|
"pocketpaw.integrations.gmail.GmailClient._get_token",
|
|
side_effect=RuntimeError("Not authenticated"),
|
|
):
|
|
result = await tool.execute(to="x@x.com", subject="Hi", body="Test")
|
|
assert "Error" in result
|