#[ allow( unused_imports ) ]
use super::*;
#[ tokio::test ]
async fn test_image_content_structure()
{
let image_content = the_module::ImageContent
{
r#type : "image".to_string(),
source : the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "image/jpeg".to_string(),
data : "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==".to_string(),
},
};
assert_eq!( image_content.r#type, "image" );
assert_eq!( image_content.source.r#type, "base64" );
assert_eq!( image_content.source.media_type, "image/jpeg" );
assert!( !image_content.source.data.is_empty() );
}
#[ tokio::test ]
async fn test_image_source_types()
{
let base64_source = the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "image/png".to_string(),
data : "base64datahere".to_string(),
};
assert_eq!( base64_source.r#type, "base64" );
assert_eq!( base64_source.media_type, "image/png" );
let media_types = vec![ "image/jpeg", "image/png", "image/gif", "image/webp" ];
for media_type in media_types
{
let source = the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : media_type.to_string(),
data : "test_data".to_string(),
};
assert_eq!( source.media_type, media_type );
}
}
#[ tokio::test ]
async fn test_mixed_content_message()
{
let image_content = the_module::ImageContent
{
r#type : "image".to_string(),
source : the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "image/jpeg".to_string(),
data : "base64imagedata".to_string(),
},
};
let message = the_module::Message::user_with_image(
"What's in this picture?".to_string(),
image_content
);
match message.role
{
the_module::Role::User => {},
_ => panic!( "Expected User role" ),
}
assert_eq!( message.content.len(), 2 ); }
#[ tokio::test ]
async fn test_image_only_message()
{
let image_content = the_module::ImageContent
{
r#type : "image".to_string(),
source : the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "image/png".to_string(),
data : "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg==".to_string(),
},
};
let message = the_module::Message::user_image( image_content.clone() );
match message.role
{
the_module::Role::User => {},
_ => panic!( "Expected User role" ),
}
assert_eq!( message.content.len(), 1 );
}
#[ tokio::test ]
async fn test_multiple_images_message()
{
let image1 = the_module::ImageContent
{
r#type : "image".to_string(),
source : the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "image/jpeg".to_string(),
data : "first_image_data".to_string(),
},
};
let image2 = the_module::ImageContent
{
r#type : "image".to_string(),
source : the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "image/png".to_string(),
data : "second_image_data".to_string(),
},
};
let message = the_module::Message::user_with_images(
"Compare these two images".to_string(),
vec![ image1, image2 ]
);
assert_eq!( message.content.len(), 3 );
assert_eq!( message.content[0].r#type(), "text" );
}
#[ tokio::test ]
async fn test_vision_api_request()
{
let image_content = the_module::ImageContent
{
r#type : "image".to_string(),
source : the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "image/jpeg".to_string(),
data : "test_image_base64_data".to_string(),
},
};
let message = the_module::Message::user_with_image(
"Describe what you see in this image".to_string(),
image_content
);
let request = the_module::CreateMessageRequest::builder()
.model( "claude-sonnet-4-5-20250929" )
.max_tokens( 500 )
.message( message )
.build();
assert_eq!( request.model, "claude-sonnet-4-5-20250929" );
assert_eq!( request.messages.len(), 1 );
assert_eq!( request.messages[0].content.len(), 2 ); }
#[ tokio::test ]
async fn test_vision_conversation_flow()
{
let image_content = the_module::ImageContent
{
r#type : "image".to_string(),
source : the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "image/png".to_string(),
data : "conversation_image_data".to_string(),
},
};
let messages = vec![
the_module::Message::user_with_image(
"What's in this image?".to_string(),
image_content
),
the_module::Message::assistant(
"I can see a beautiful landscape with mountains and trees.".to_string()
),
the_module::Message::user(
"What time of day do you think it is?".to_string()
),
];
let request = the_module::CreateMessageRequest::builder()
.model( "claude-sonnet-4-5-20250929" )
.max_tokens( 300 )
.messages( messages.clone() )
.build();
assert_eq!( request.messages.len(), 3 );
assert_eq!( request.messages[0].content.len(), 2 );
assert_eq!( request.messages[1].content.len(), 1 );
assert_eq!( request.messages[2].content.len(), 1 );
}
#[ tokio::test ]
async fn test_image_content_serialization()
{
let image_content = the_module::ImageContent
{
r#type : "image".to_string(),
source : the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "image/jpeg".to_string(),
data : "test123".to_string(),
},
};
let json = serde_json::to_string( &image_content ).expect( "Should serialize successfully" );
assert!( json.contains( "\"type\":\"image\"" ) );
assert!( json.contains( "\"source\":" ) );
assert!( json.contains( "\"type\":\"base64\"" ) );
assert!( json.contains( "\"media_type\":\"image/jpeg\"" ) );
assert!( json.contains( "\"data\":\"test123\"" ) );
}
#[ tokio::test ]
async fn test_image_content_deserialization()
{
let json = r#"{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8/5+hHgAHggJ/PchI7wAAAABJRU5ErkJggg=="
}
}"#;
let image_content : the_module::ImageContent = serde_json::from_str( json ).expect( "Should deserialize successfully" );
assert_eq!( image_content.r#type, "image" );
assert_eq!( image_content.source.r#type, "base64" );
assert_eq!( image_content.source.media_type, "image/png" );
assert!( !image_content.source.data.is_empty() );
}
#[ tokio::test ]
async fn test_vision_with_tools()
{
let image_content = the_module::ImageContent
{
r#type : "image".to_string(),
source : the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "image/jpeg".to_string(),
data : "image_for_tool_analysis".to_string(),
},
};
let tools = vec![
the_module::ToolDefinition
{
name : "image_analyzer".to_string(),
description : "Analyze image content and extract information".to_string(),
input_schema : serde_json::json!(
{
"type": "object",
"properties": {
"analysis_type": {"type": "string", "enum": ["objects", "colors", "text", "emotions"]}
},
"required": ["analysis_type"]
}),
}
];
let message = the_module::Message::user_with_image(
"Analyze this image for objects".to_string(),
image_content
);
let request = the_module::CreateMessageRequest::builder()
.model( "claude-sonnet-4-5-20250929" )
.max_tokens( 400 )
.message( message )
.tools( tools )
.tool_choice( the_module::ToolChoice::Auto )
.build();
assert!( request.tools.is_some() );
assert!( request.tool_choice.is_some() );
assert_eq!( request.messages[0].content.len(), 2 ); }
#[ tokio::test ]
async fn test_image_validation()
{
let empty_image = the_module::ImageContent
{
r#type : "image".to_string(),
source : the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "image/jpeg".to_string(),
data : String::new(), },
};
assert!( empty_image.source.data.is_empty() );
let invalid_media_type = the_module::ImageContent
{
r#type : "image".to_string(),
source : the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "invalid/type".to_string(),
data : "test_data".to_string(),
},
};
assert_eq!( invalid_media_type.source.media_type, "invalid/type" );
}
#[ tokio::test ]
async fn test_large_image_handling()
{
let large_data = "a".repeat( 1000 );
let large_image = the_module::ImageContent
{
r#type : "image".to_string(),
source : the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "image/jpeg".to_string(),
data : large_data.clone(),
},
};
assert_eq!( large_image.source.data.len(), 1000 );
let json = serde_json::to_string( &large_image ).expect( "Should handle large images" );
assert!( json.len() > 1000 );
}
#[ tokio::test ]
async fn test_vision_with_streaming()
{
let image_content = the_module::ImageContent
{
r#type : "image".to_string(),
source : the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "image/png".to_string(),
data : "streaming_test_image".to_string(),
},
};
let message = the_module::Message::user_with_image(
"Describe this image in detail".to_string(),
image_content
);
let request = the_module::CreateMessageRequest::builder()
.model( "claude-sonnet-4-5-20250929" )
.max_tokens( 600 )
.message( message )
.stream( true )
.build();
assert!( request.stream.unwrap() );
assert_eq!( request.messages[0].content.len(), 2 );
}
#[ tokio::test ]
async fn test_mixed_content_serialization()
{
let message = the_module::Message::user_with_image(
"Analyze this".to_string(),
the_module::ImageContent
{
r#type : "image".to_string(),
source : the_module::ImageSource
{
r#type : "base64".to_string(),
media_type : "image/jpeg".to_string(),
data : "mixed_content_test".to_string(),
},
}
);
let json = serde_json::to_string( &message ).expect( "Should serialize mixed content" );
assert!( json.contains( "\"role\":\"user\"" ) );
assert!( json.contains( "\"content\":" ) );
assert!( json.contains( "\"type\":\"text\"" ) );
assert!( json.contains( "\"type\":\"image\"" ) );
assert!( json.contains( "\"source\":" ) );
}
#[ tokio::test ]
#[ cfg( all( feature = "integration", feature = "vision" ) ) ]
#[ ignore = "Requires workspace secrets file" ]
async fn integration_vision_real_image_processing()
{
let client = the_module::Client::from_workspace()
.expect( "INTEGRATION: Must have valid API key for vision testing" );
let test_image_base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
let image_source = the_module::ImageSource::png( test_image_base64 );
let image_content = the_module::ImageContent::new( image_source );
let request = the_module::CreateMessageRequest
{
model : "claude-sonnet-4-5-20250929".to_string(), max_tokens : 50,
messages : vec![
the_module::Message::user_with_image(
"What color is this image?".to_string(),
image_content
)
],
system : None,
temperature : None,
stream : None,
tools : None,
tool_choice : None,
};
let response = match client.create_message( request ).await
{
Ok( response ) => response,
Err( the_module::AnthropicError::Api( ref api_err ) ) if api_err.message.contains( "credit balance is too low" ) =>
{
println!( "INTEGRATION TEST SKIPPED: Credit balance exhausted - this confirms real API usage" );
return;
},
Err( err ) => panic!( "INTEGRATION: Vision API call must work : {err}" ),
};
assert!( !response.id.is_empty(), "Vision API must return message ID" );
assert_eq!( response.r#type, "message" );
assert_eq!( response.role, "assistant" );
assert!( !response.content.is_empty(), "Vision API must return content" );
assert!( response.usage.input_tokens > 0, "Vision API must track input tokens" );
assert!( response.usage.output_tokens > 0, "Vision API must track output tokens" );
let content_text = response.content[0].text.as_ref()
.expect( "Vision response must have text content" );
let response_lower = content_text.to_lowercase();
assert!(
response_lower.contains( "red" ) ||
response_lower.contains( "color" ) ||
response_lower.contains( "image" ) ||
response_lower.contains( "pixel" ),
"Vision API should analyze image content, got : {content_text}"
);
println!( "✅ Vision integration test passed!" );
println!( " Vision response : {content_text}" );
println!( " Input tokens : {}", response.usage.input_tokens );
println!( " Output tokens : {}", response.usage.output_tokens );
}
#[ tokio::test ]
#[ cfg( all( feature = "integration", feature = "vision" ) ) ]
#[ ignore = "Requires workspace secrets file" ]
async fn integration_vision_mixed_content_real_api()
{
let client = the_module::Client::from_workspace()
.expect( "INTEGRATION: Must have valid API key for mixed content testing" );
let test_image_base64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg==";
let image_content = the_module::ImageContent::png( test_image_base64 );
let message = the_module::Message::user_with_image(
"I'm sending you an image and asking : What do you see in this small image? Please be specific about any colors or patterns.".to_string(),
image_content
);
let request = the_module::CreateMessageRequest
{
model : "claude-sonnet-4-5-20250929".to_string(),
max_tokens : 100,
messages : vec![ message ],
system : Some( vec![ the_module::SystemContent::text( "You are a helpful vision assistant. Describe images accurately." ) ] ),
temperature : Some( 0.1 ),
stream : None,
tools : None,
tool_choice : None,
};
let response = match client.create_message( request ).await
{
Ok( response ) => response,
Err( the_module::AnthropicError::Api( ref api_err ) ) if api_err.message.contains( "credit balance is too low" ) =>
{
println!( "INTEGRATION TEST SKIPPED: Credit balance exhausted - this confirms real API usage" );
return;
},
Err( err ) => panic!( "INTEGRATION: Mixed content vision API call must work : {err}" ),
};
assert!( !response.id.is_empty() );
assert!( response.usage.input_tokens > 0 );
assert!( response.usage.output_tokens > 0 );
let content_text = response.content[0].text.as_ref()
.expect( "Mixed content response must have text" );
let response_lower = content_text.to_lowercase();
assert!(
response_lower.contains( "image" ) || response_lower.contains( "see" ) ||
response_lower.contains( "blank" ) || response_lower.contains( "tint" ) ||
response_lower.contains( "color" ) || response_lower.contains( "pixel" ),
"Mixed content should show vision processing, got : {content_text}"
);
println!( "✅ Vision mixed content integration test passed!" );
println!( " Mixed content response : {content_text}" );
}