#[cfg(test)]
mod anthropic_validation_tests {
use rstructor::{AnthropicClient, AnthropicModel, Instructor, LLMClient, RStructorError};
use serde::{Deserialize, Serialize};
use std::env;
#[derive(Instructor, Serialize, Deserialize, Debug)]
#[llm(description = "Information about a city's weather")]
struct WeatherInfo {
#[llm(description = "Name of the city")]
city: String,
#[llm(description = "Current temperature in Celsius", example = 22.5)]
temperature: f32,
#[llm(description = "Weather condition", example = "Sunny")]
condition: String,
#[llm(description = "Humidity percentage", example = 65)]
humidity: u8,
}
impl WeatherInfo {
fn validate(&self) -> rstructor::Result<()> {
if self.city.trim().is_empty() {
return Err(RStructorError::ValidationError(
"City name cannot be empty".to_string(),
));
}
if self.temperature < -100.0 || self.temperature > 60.0 {
return Err(RStructorError::ValidationError(format!(
"Temperature must be between -100°C and 60°C, got {}°C",
self.temperature
)));
}
if self.humidity > 100 {
return Err(RStructorError::ValidationError(format!(
"Humidity must be between 0 and 100%, got {}%",
self.humidity
)));
}
Ok(())
}
}
#[tokio::test]
async fn test_anthropic_validation_fails_with_extreme_temperature() {
let api_key =
env::var("ANTHROPIC_API_KEY").expect("ANTHROPIC_API_KEY must be set for this test");
let client = AnthropicClient::new(api_key)
.expect("Failed to create Anthropic client")
.model(AnthropicModel::ClaudeSonnet46)
.temperature(0.0);
let prompt = "What is the current weather in New York City?";
let valid_result = client.materialize::<WeatherInfo>(prompt).await;
assert!(
valid_result.is_ok(),
"API call failed: {:?}",
valid_result.err()
);
let invalid_weather = WeatherInfo {
city: "Temperature Test City".to_string(),
temperature: 999.0, condition: "Extreme Heat".to_string(),
humidity: 50, };
let validation_result = invalid_weather.validate();
assert!(
validation_result.is_err(),
"Validation should fail with extreme temperature"
);
if let Err(RStructorError::ValidationError(msg)) = validation_result {
assert!(
msg.contains("Temperature") || msg.contains("temperature"),
"Error should mention temperature: {}",
msg
);
} else if let Err(e) = validation_result {
panic!("Expected ValidationError about temperature, got: {:?}", e);
}
}
#[tokio::test]
async fn test_anthropic_validation_fails_with_invalid_humidity() {
let invalid_weather = WeatherInfo {
city: "Humidity Test City".to_string(),
temperature: 25.0, condition: "Rainy".to_string(),
humidity: 150, };
let validation_result = invalid_weather.validate();
assert!(
validation_result.is_err(),
"Validation should fail with extreme humidity"
);
if let Err(RStructorError::ValidationError(msg)) = validation_result {
assert!(
msg.contains("Humidity") || msg.contains("humidity"),
"Error should mention humidity: {}",
msg
);
} else if let Err(e) = validation_result {
panic!("Expected ValidationError about humidity, got: {:?}", e);
}
}
#[tokio::test]
async fn test_anthropic_validation_succeeds_with_valid_data() {
let api_key =
env::var("ANTHROPIC_API_KEY").expect("ANTHROPIC_API_KEY must be set for this test");
let client = AnthropicClient::new(api_key)
.expect("Failed to create Anthropic client")
.model(AnthropicModel::ClaudeSonnet46)
.temperature(0.0);
let prompt = "What's the weather like in Paris today? Use realistic values.";
let result = client.materialize::<WeatherInfo>(prompt).await;
assert!(result.is_ok(), "API call failed: {:?}", result.err());
let weather = result.unwrap();
assert_eq!(weather.city, "Paris");
assert!(weather.temperature >= -30.0 && weather.temperature <= 45.0);
assert!(weather.humidity <= 100);
assert!(!weather.condition.is_empty());
}
}