use openrouter_api::models::tool::ToolType;
use openrouter_api::types::chat::{
AudioContent, AudioUrl, ChatRole, ContentPart, ContentType, FileContent, FileUrl, ImageContent,
ImageUrl, Message, MessageContent, TextContent,
};
use openrouter_api::types::ids::ToolCallId;
use serde_json::{from_str, from_value, to_value};
#[test]
fn test_message_uses_chat_role_enum() {
let msg = Message::text(ChatRole::User, "Hello, world!");
match msg.role {
ChatRole::User => {} ChatRole::Assistant => panic!("Wrong role"),
ChatRole::System => panic!("Wrong role"),
ChatRole::Tool => panic!("Wrong role"),
_ => panic!("Unknown role"),
}
}
#[test]
fn test_all_chat_role_variants() {
let user_msg = Message::text(ChatRole::User, "User message");
assert_eq!(user_msg.role, ChatRole::User);
let assistant_msg = Message::text(ChatRole::Assistant, "Assistant message");
assert_eq!(assistant_msg.role, ChatRole::Assistant);
let system_msg = Message::text(ChatRole::System, "System message");
assert_eq!(system_msg.role, ChatRole::System);
let tool_msg = Message::text(ChatRole::Tool, "Tool result");
assert_eq!(tool_msg.role, ChatRole::Tool);
}
#[test]
fn test_chat_role_serialization() {
let msg = Message::text(ChatRole::User, "test");
let json = to_value(&msg).unwrap();
assert_eq!(json["role"], "user"); }
#[test]
fn test_chat_role_deserialization() {
let json = r#"{
"role": "user",
"content": "test"
}"#;
let msg: Message = from_str(json).unwrap();
assert_eq!(msg.role, ChatRole::User);
}
#[test]
fn test_assistant_role_deserialization() {
let json = r#"{
"role": "assistant",
"content": "response"
}"#;
let msg: Message = from_str(json).unwrap();
assert_eq!(msg.role, ChatRole::Assistant);
}
#[test]
fn test_system_role_deserialization() {
let json = r#"{
"role": "system",
"content": "instructions"
}"#;
let msg: Message = from_str(json).unwrap();
assert_eq!(msg.role, ChatRole::System);
}
#[test]
fn test_tool_role_deserialization() {
let json = r#"{
"role": "tool",
"content": "tool output",
"tool_call_id": "call_123"
}"#;
let msg: Message = from_str(json).unwrap();
assert_eq!(msg.role, ChatRole::Tool);
assert_eq!(msg.tool_call_id, Some(ToolCallId::new("call_123")));
}
#[test]
fn test_message_with_name() {
let msg = Message::text_with_name(ChatRole::User, "message", "Alice");
assert_eq!(msg.role, ChatRole::User);
assert_eq!(msg.name, Some("Alice".to_string()));
let json = r#"{
"role": "user",
"content": "message",
"name": "Bob"
}"#;
let msg: Message = from_str(json).unwrap();
assert_eq!(msg.role, ChatRole::User);
assert_eq!(msg.name, Some("Bob".to_string()));
}
#[test]
fn test_multimodal_text_content() {
let text_part = ContentPart::Text(TextContent {
content_type: ContentType::Text,
text: "Hello".to_string(),
});
let msg = Message::multimodal(ChatRole::User, vec![text_part]);
match msg.content {
MessageContent::Parts(parts) => {
assert_eq!(parts.len(), 1);
}
MessageContent::Text(_) => panic!("Should be Parts, not Text"),
}
}
#[test]
fn test_multimodal_image_content() {
let image_part = ContentPart::Image(ImageContent {
content_type: ContentType::ImageUrl,
image_url: ImageUrl {
url: "https://example.com/image.jpg".to_string(),
detail: None,
},
});
let msg = Message::multimodal(ChatRole::User, vec![image_part]);
match msg.content {
MessageContent::Parts(parts) => {
assert_eq!(parts.len(), 1);
}
MessageContent::Text(_) => panic!("Should be Parts, not Text"),
}
}
#[test]
fn test_multimodal_audio_content() {
let audio_part = ContentPart::Audio(AudioContent {
content_type: ContentType::AudioUrl,
audio_url: AudioUrl {
url: "https://example.com/audio.mp3".to_string(),
},
});
let msg = Message::multimodal(ChatRole::User, vec![audio_part]);
match msg.content {
MessageContent::Parts(parts) => {
assert_eq!(parts.len(), 1);
}
MessageContent::Text(_) => panic!("Should be Parts, not Text"),
}
}
#[test]
fn test_multimodal_file_content() {
let file_part = ContentPart::File(FileContent {
content_type: ContentType::FileUrl,
file_url: FileUrl {
url: "https://example.com/document.pdf".to_string(),
},
});
let msg = Message::multimodal(ChatRole::User, vec![file_part]);
match msg.content {
MessageContent::Parts(parts) => {
assert_eq!(parts.len(), 1);
}
MessageContent::Text(_) => panic!("Should be Parts, not Text"),
}
}
#[test]
fn test_multimodal_mixed_content() {
let text_part = ContentPart::Text(TextContent {
content_type: ContentType::Text,
text: "Look at this image:".to_string(),
});
let image_part = ContentPart::Image(ImageContent {
content_type: ContentType::ImageUrl,
image_url: ImageUrl {
url: "https://example.com/image.jpg".to_string(),
detail: None,
},
});
let msg = Message::multimodal(ChatRole::User, vec![text_part, image_part]);
match msg.content {
MessageContent::Parts(parts) => {
assert_eq!(parts.len(), 2);
}
MessageContent::Text(_) => panic!("Should be Parts, not Text"),
}
}
#[test]
fn test_tool_message() {
let msg = Message::tool("tool output", "call_abc123");
assert_eq!(msg.role, ChatRole::Tool);
assert_eq!(msg.tool_call_id, Some(ToolCallId::new("call_abc123")));
match msg.content {
MessageContent::Text(s) => assert_eq!(s, "tool output"),
MessageContent::Parts(_) => panic!("Tool message should have Text content"),
}
}
#[test]
fn test_assistant_with_tools() {
use openrouter_api::models::tool::{FunctionCall, ToolCall};
let tool_calls = vec![ToolCall {
id: ToolCallId::new("call_123"),
kind: ToolType::Function,
function_call: FunctionCall {
name: "get_weather".to_string(),
arguments: r#"{"city": "NYC"}"#.to_string(),
},
}];
let msg = Message::assistant_with_tools(Some("I'll check the weather"), tool_calls.clone());
assert_eq!(msg.role, ChatRole::Assistant);
assert_eq!(msg.tool_calls, Some(tool_calls));
match msg.content {
MessageContent::Text(s) => assert_eq!(s, "I'll check the weather"),
MessageContent::Parts(_) => panic!("Assistant message should have Text content"),
}
}
#[test]
fn test_assistant_with_tools_no_content() {
use openrouter_api::models::tool::{FunctionCall, ToolCall};
let tool_calls = vec![ToolCall {
id: ToolCallId::new("call_456"),
kind: ToolType::Function,
function_call: FunctionCall {
name: "get_weather".to_string(),
arguments: r#"{"city": "LA"}"#.to_string(),
},
}];
let msg = Message::assistant_with_tools(None::<String>, tool_calls);
assert_eq!(msg.role, ChatRole::Assistant);
assert!(msg.tool_calls.is_some());
}
#[test]
fn test_message_default() {
let msg = Message::default();
assert_eq!(msg.role, ChatRole::User); assert_eq!(msg.name, None);
assert_eq!(msg.tool_call_id, None);
assert_eq!(msg.tool_calls, None);
}
#[test]
fn test_message_roundtrip_serialization() {
let original = Message::text_with_name(ChatRole::System, "You are helpful", "SystemPrompt");
let json = to_value(&original).unwrap();
let deserialized: Message = from_value(json).unwrap();
assert_eq!(original.role, deserialized.role);
assert_eq!(original.name, deserialized.name);
assert_eq!(original.tool_call_id, deserialized.tool_call_id);
}
#[test]
fn test_invalid_role_deserialization_fails() {
let json = r#"{
"role": "invalid_role",
"content": "test"
}"#;
let result: Result<Message, _> = from_str(json);
assert!(result.is_err(), "Should reject invalid role strings");
}
#[test]
fn test_case_insensitive_role_deserialization() {
let json = r#"{
"role": "USER",
"content": "test"
}"#;
let result: Result<Message, _> = from_str(json);
assert!(result.is_err(), "Should reject uppercase role");
}
#[test]
fn test_message_content_text_serialization() {
let msg = Message::text(ChatRole::User, "Hello");
let json = to_value(&msg).unwrap();
assert_eq!(json["content"], "Hello");
}
#[test]
fn test_message_content_parts_serialization() {
let parts = vec![
ContentPart::Text(TextContent {
content_type: ContentType::Text,
text: "Check this:".to_string(),
}),
ContentPart::Image(ImageContent {
content_type: ContentType::ImageUrl,
image_url: ImageUrl {
url: "https://example.com/img.jpg".to_string(),
detail: None,
},
}),
];
let msg = Message::multimodal(ChatRole::User, parts);
let json = to_value(&msg).unwrap();
assert!(json["content"].is_array());
assert_eq!(json["content"].as_array().unwrap().len(), 2);
}
#[test]
fn test_chat_role_traits() {
let role = ChatRole::User;
let role_clone = role.clone();
assert_eq!(role, role_clone);
assert_eq!(role, ChatRole::User);
assert_ne!(role, ChatRole::Assistant);
let debug_str = format!("{:?}", role);
assert!(debug_str.contains("User"));
}
#[test]
fn test_message_traits() {
let msg = Message::text(ChatRole::User, "test");
let msg_clone = msg.clone();
assert_eq!(msg.role, msg_clone.role);
let debug_str = format!("{:?}", msg);
assert!(debug_str.contains("Message"));
assert_eq!(msg, msg_clone);
}