use anthropic_async::BetaFeature;
use anthropic_async::types::content::ContentBlockParam;
use anthropic_async::types::content::ImageSource;
use anthropic_async::types::content::MessageParam;
use anthropic_async::types::content::MessageRole;
use anthropic_async::types::content::ToolResultContent;
use anthropic_async::types::content::ToolResultContentBlock;
use anthropic_async::types::messages::MessagesCreateRequest;
use anthropic_async::types::messages::OutputFormat;
use anthropic_async::types::tools::Tool;
#[test]
fn test_output_format_json_schema_serialization() {
let schema = serde_json::json!({
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer" }
},
"required": ["name", "age"]
});
let output_format = OutputFormat::JsonSchema {
schema: schema.clone(),
};
let s = serde_json::to_string(&output_format).unwrap();
assert!(s.contains(r#""type":"json_schema""#));
assert!(s.contains(r#""schema""#));
assert!(s.contains(r#""name""#));
assert!(s.contains(r#""age""#));
let parsed: OutputFormat = serde_json::from_str(&s).unwrap();
match parsed {
OutputFormat::JsonSchema {
schema: parsed_schema,
} => {
assert_eq!(parsed_schema, schema);
}
}
}
#[test]
#[expect(deprecated)]
fn test_messages_request_with_output_format() {
let req = MessagesCreateRequest {
model: "claude-sonnet-4-6".into(),
max_tokens: 1024,
messages: vec![MessageParam {
role: MessageRole::User,
content: "Generate a person".into(),
}],
output_format: Some(OutputFormat::JsonSchema {
schema: serde_json::json!({
"type": "object",
"properties": {
"name": { "type": "string" }
}
}),
}),
..Default::default()
};
let s = serde_json::to_string(&req).unwrap();
assert!(s.contains(r#""output_config""#));
assert!(s.contains(r#""type":"json_schema""#));
}
#[test]
fn test_messages_request_omits_none_output_format() {
let req = MessagesCreateRequest {
model: "claude-sonnet-4-6".into(),
max_tokens: 1024,
messages: vec![MessageParam {
role: MessageRole::User,
content: "Hello".into(),
}],
..Default::default()
};
let s = serde_json::to_string(&req).unwrap();
assert!(!s.contains("output_format"));
assert!(!s.contains("output_config"));
}
#[test]
fn test_messages_request_with_stream() {
let req = MessagesCreateRequest {
model: "claude-sonnet-4-6".into(),
max_tokens: 1024,
messages: vec![MessageParam {
role: MessageRole::User,
content: "Hello".into(),
}],
stream: Some(true),
..Default::default()
};
let s = serde_json::to_string(&req).unwrap();
assert!(s.contains(r#""stream":true"#));
}
#[test]
fn test_beta_header_structured_outputs_versions() {
let beta_py: String = BetaFeature::StructuredOutputs20250917.into();
assert_eq!(beta_py, "structured-outputs-2025-09-17");
let beta_ts: String = BetaFeature::StructuredOutputs20251113.into();
assert_eq!(beta_ts, "structured-outputs-2025-11-13");
let beta_latest: String = BetaFeature::StructuredOutputsLatest.into();
assert_eq!(beta_latest, "structured-outputs-2025-11-13");
}
#[test]
fn test_tool_strict_serialization() {
let tool_without_strict = Tool {
name: "calculator".into(),
description: Some("Math calculations".into()),
input_schema: serde_json::json!({
"type": "object",
"properties": {
"expression": { "type": "string" }
}
}),
cache_control: None,
strict: None,
};
let s = serde_json::to_string(&tool_without_strict).unwrap();
assert!(!s.contains("strict"));
let tool_with_strict = Tool {
name: "calculator".into(),
description: Some("Math calculations".into()),
input_schema: serde_json::json!({
"type": "object",
"properties": {
"expression": { "type": "string" }
}
}),
cache_control: None,
strict: Some(true),
};
let s = serde_json::to_string(&tool_with_strict).unwrap();
assert!(s.contains(r#""strict":true"#));
}
#[test]
fn test_tool_result_string_content() {
let tool_result = ContentBlockParam::ToolResult {
tool_use_id: "tool_123".into(),
content: Some(ToolResultContent::String("Simple string result".into())),
is_error: None,
cache_control: None,
};
let s = serde_json::to_string(&tool_result).unwrap();
assert!(s.contains(r#""content":"Simple string result""#));
}
#[test]
fn test_tool_result_blocks_content() {
let tool_result = ContentBlockParam::ToolResult {
tool_use_id: "tool_456".into(),
content: Some(ToolResultContent::Blocks(vec![
ToolResultContentBlock::Text {
text: "First block".into(),
cache_control: None,
},
ToolResultContentBlock::Text {
text: "Second block".into(),
cache_control: None,
},
])),
is_error: None,
cache_control: None,
};
let s = serde_json::to_string(&tool_result).unwrap();
assert!(s.contains(r#""type":"tool_result""#));
assert!(s.contains(r#""First block""#));
assert!(s.contains(r#""Second block""#));
assert!(s.contains(r#""content":[{"#));
}
#[test]
fn test_tool_result_content_with_image() {
let tool_result = ContentBlockParam::ToolResult {
tool_use_id: "tool_789".into(),
content: Some(ToolResultContent::Blocks(vec![
ToolResultContentBlock::Text {
text: "Image description".into(),
cache_control: None,
},
ToolResultContentBlock::Image {
source: ImageSource::Base64 {
media_type: "image/png".into(),
data: "iVBORw0KGgo...".into(),
},
cache_control: None,
},
])),
is_error: None,
cache_control: None,
};
let s = serde_json::to_string(&tool_result).unwrap();
assert!(s.contains(r#""type":"text""#));
assert!(s.contains(r#""type":"image""#));
assert!(s.contains(r#""media_type":"image/png""#));
}
#[test]
fn test_tool_result_content_from_string() {
let content: ToolResultContent = "test result".into();
match content {
ToolResultContent::String(s) => assert_eq!(s, "test result"),
ToolResultContent::Blocks(_) => panic!("Expected String variant"),
}
let content: ToolResultContent = String::from("another result").into();
match content {
ToolResultContent::String(s) => assert_eq!(s, "another result"),
ToolResultContent::Blocks(_) => panic!("Expected String variant"),
}
}
#[test]
fn test_tool_result_content_deserialization() {
let json_string = r#""simple string result""#;
let content: ToolResultContent = serde_json::from_str(json_string).unwrap();
match content {
ToolResultContent::String(s) => assert_eq!(s, "simple string result"),
ToolResultContent::Blocks(_) => panic!("Expected String variant"),
}
let json_blocks = r#"[{"type":"text","text":"block text"}]"#;
let content: ToolResultContent = serde_json::from_str(json_blocks).unwrap();
match content {
ToolResultContent::Blocks(blocks) => {
assert_eq!(blocks.len(), 1);
match &blocks[0] {
ToolResultContentBlock::Text { text, .. } => {
assert_eq!(text, "block text");
}
ToolResultContentBlock::Image { .. } => panic!("Expected Text block"),
}
}
ToolResultContent::String(_) => panic!("Expected Blocks variant"),
}
}