use mcp_gmailcal::errors::GmailApiError;
use mcp_gmailcal::gmail_api::{DraftEmail, EmailMessage};
use mockall::predicate::*;
use serde_json::json;
mockall::mock! {
pub GmailClient {
pub fn check_connection(&self) -> Result<(String, u64), GmailApiError>;
pub fn list_labels(&self) -> Result<String, GmailApiError>;
pub fn create_draft(&self, draft: &DraftEmail) -> Result<String, GmailApiError>;
pub fn list_messages<'a>(&'a self, max_results: u32, query: Option<&'a str>) -> Result<Vec<EmailMessage>, GmailApiError>;
pub fn get_message_details(&self, message_id: &str) -> Result<EmailMessage, GmailApiError>;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_check_connection_success() {
let mut mock = MockGmailClient::new();
mock.expect_check_connection()
.returning(|| Ok(("test@example.com".to_string(), 123)));
let result = mock.check_connection();
assert!(result.is_ok());
let (email, count) = result.unwrap();
assert_eq!(email, "test@example.com");
assert_eq!(count, 123);
}
#[test]
fn test_check_connection_failure() {
let mut mock = MockGmailClient::new();
mock.expect_check_connection()
.returning(|| Err(GmailApiError::AuthError("Authentication failed".to_string())));
let result = mock.check_connection();
assert!(result.is_err());
match result {
Err(GmailApiError::AuthError(msg)) => {
assert_eq!(msg, "Authentication failed");
}
_ => panic!("Expected AuthError")
}
}
#[test]
fn test_list_labels_success() {
let mut mock = MockGmailClient::new();
let labels_json = json!({
"labels": [
{"id": "INBOX", "name": "Inbox", "type": "system"},
{"id": "SENT", "name": "Sent", "type": "system"},
{"id": "TRASH", "name": "Trash", "type": "system"},
{"id": "CATEGORY_PERSONAL", "name": "Personal", "type": "user"}
]
}).to_string();
mock.expect_list_labels()
.returning(move || Ok(labels_json.clone()));
let result = mock.list_labels();
assert!(result.is_ok());
let labels = result.unwrap();
assert!(labels.contains("INBOX"));
assert!(labels.contains("Personal"));
}
#[test]
fn test_list_labels_failure() {
let mut mock = MockGmailClient::new();
mock.expect_list_labels()
.returning(|| Err(GmailApiError::NetworkError("Network error".to_string())));
let result = mock.list_labels();
assert!(result.is_err());
match result {
Err(GmailApiError::NetworkError(msg)) => {
assert_eq!(msg, "Network error");
}
_ => panic!("Expected NetworkError")
}
}
#[test]
fn test_create_draft_success() {
let mut mock = MockGmailClient::new();
mock.expect_create_draft()
.returning(|_| Ok("draft123".to_string()));
let draft = DraftEmail {
to: "recipient@example.com".to_string(),
subject: "Test Draft".to_string(),
body: "This is a test draft.".to_string(),
cc: None,
bcc: None,
thread_id: None,
in_reply_to: None,
references: None,
};
let result = mock.create_draft(&draft);
assert!(result.is_ok());
let draft_id = result.unwrap();
assert_eq!(draft_id, "draft123");
}
#[test]
fn test_create_draft_with_all_fields() {
let mut mock = MockGmailClient::new();
mock.expect_create_draft()
.withf(|draft| {
draft.to == "recipient@example.com" &&
draft.subject == "Test Draft with All Fields" &&
draft.cc.is_some() &&
draft.bcc.is_some() &&
draft.thread_id.is_some() &&
draft.in_reply_to.is_some() &&
draft.references.is_some()
})
.returning(|_| Ok("draft456".to_string()));
let draft = DraftEmail {
to: "recipient@example.com".to_string(),
subject: "Test Draft with All Fields".to_string(),
body: "This is a test draft with all fields.".to_string(),
cc: Some("cc@example.com".to_string()),
bcc: Some("bcc@example.com".to_string()),
thread_id: Some("thread123".to_string()),
in_reply_to: Some("message123".to_string()),
references: Some("reference123".to_string()),
};
let result = mock.create_draft(&draft);
assert!(result.is_ok());
let draft_id = result.unwrap();
assert_eq!(draft_id, "draft456");
}
#[test]
fn test_create_draft_failure() {
let mut mock = MockGmailClient::new();
mock.expect_create_draft()
.returning(|_| Err(GmailApiError::ApiError("API error".to_string())));
let draft = DraftEmail {
to: "recipient@example.com".to_string(),
subject: "Test Draft".to_string(),
body: "This is a test draft.".to_string(),
cc: None,
bcc: None,
thread_id: None,
in_reply_to: None,
references: None,
};
let result = mock.create_draft(&draft);
assert!(result.is_err());
match result {
Err(GmailApiError::ApiError(msg)) => {
assert_eq!(msg, "API error");
}
_ => panic!("Expected ApiError")
}
}
#[test]
fn test_get_message_details_success() {
let mut mock = MockGmailClient::new();
let email = EmailMessage {
id: "msg123".to_string(),
thread_id: "thread123".to_string(),
subject: Some("Test Message".to_string()),
from: Some("sender@example.com".to_string()),
to: Some("recipient@example.com".to_string()),
date: Some("2025-01-01T12:00:00Z".to_string()),
snippet: Some("This is a test message...".to_string()),
body_text: Some("This is the message body.".to_string()),
body_html: Some("<html><body>This is the HTML message body.</body></html>".to_string()),
};
mock.expect_get_message_details()
.with(eq("msg123"))
.returning(move |_| Ok(email.clone()));
let result = mock.get_message_details("msg123");
assert!(result.is_ok());
let message = result.unwrap();
assert_eq!(message.id, "msg123");
assert_eq!(message.subject.unwrap(), "Test Message");
assert_eq!(message.from.unwrap(), "sender@example.com");
assert_eq!(message.to.unwrap(), "recipient@example.com");
assert!(message.body_text.is_some());
assert!(message.body_html.is_some());
}
#[test]
fn test_get_message_details_failure() {
let mut mock = MockGmailClient::new();
mock.expect_get_message_details()
.with(eq("not_found"))
.returning(|_| Err(GmailApiError::MessageRetrievalError("Message not found".to_string())));
let result = mock.get_message_details("not_found");
assert!(result.is_err());
match result {
Err(GmailApiError::MessageRetrievalError(msg)) => {
assert_eq!(msg, "Message not found");
}
_ => panic!("Expected MessageRetrievalError")
}
}
#[test]
fn test_list_messages_success() {
let mut mock = MockGmailClient::new();
let messages = vec![
EmailMessage {
id: "msg1".to_string(),
thread_id: "thread1".to_string(),
subject: Some("First Message".to_string()),
from: Some("sender1@example.com".to_string()),
to: Some("recipient@example.com".to_string()),
date: Some("2025-01-01T12:00:00Z".to_string()),
snippet: Some("First message snippet...".to_string()),
body_text: Some("First message body.".to_string()),
body_html: None,
},
EmailMessage {
id: "msg2".to_string(),
thread_id: "thread2".to_string(),
subject: Some("Second Message".to_string()),
from: Some("sender2@example.com".to_string()),
to: Some("recipient@example.com".to_string()),
date: Some("2025-01-02T12:00:00Z".to_string()),
snippet: Some("Second message snippet...".to_string()),
body_text: Some("Second message body.".to_string()),
body_html: None,
},
];
mock.expect_list_messages()
.returning(move |_, _| Ok(messages.clone()));
let result = mock.list_messages(10, None);
assert!(result.is_ok());
let messages = result.unwrap();
assert_eq!(messages.len(), 2);
assert_eq!(messages[0].id, "msg1");
assert_eq!(messages[1].id, "msg2");
}
#[test]
fn test_list_messages_with_query() {
let mut mock = MockGmailClient::new();
let messages = vec![
EmailMessage {
id: "msg3".to_string(),
thread_id: "thread3".to_string(),
subject: Some("Important Message".to_string()),
from: Some("important@example.com".to_string()),
to: Some("recipient@example.com".to_string()),
date: Some("2025-01-03T12:00:00Z".to_string()),
snippet: Some("Important message snippet...".to_string()),
body_text: Some("Important message body.".to_string()),
body_html: None,
},
];
mock.expect_list_messages()
.returning(move |max, query| {
if max == 10 && query == Some("important") {
Ok(messages.clone())
} else {
Ok(vec![])
}
});
let result = mock.list_messages(10, Some("important"));
assert!(result.is_ok());
let messages = result.unwrap();
assert_eq!(messages.len(), 1);
assert_eq!(messages[0].id, "msg3");
assert_eq!(messages[0].subject.as_ref().unwrap(), "Important Message");
}
#[test]
fn test_list_messages_failure() {
let mut mock = MockGmailClient::new();
mock.expect_list_messages()
.returning(|_, _| Err(GmailApiError::ApiError("API error".to_string())));
let result = mock.list_messages(10, None);
assert!(result.is_err());
match result {
Err(GmailApiError::ApiError(msg)) => {
assert_eq!(msg, "API error");
}
_ => panic!("Expected ApiError")
}
}
}