#[ allow( unused_imports ) ]
use super::*;
#[ test ]
fn test_model_validation_empty()
{
let request = the_module::CreateMessageRequest
{
model : String::new(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let result = request.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().to_string().contains( "Model cannot be empty" ) );
}
#[ test ]
fn test_model_validation_whitespace()
{
let request = the_module::CreateMessageRequest
{
model : " ".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let result = request.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().to_string().contains( "Model cannot be empty" ) );
}
#[ test ]
fn test_max_tokens_below_minimum()
{
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 0,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let result = request.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().to_string().contains( "max_tokens must be between" ) );
}
#[ test ]
fn test_max_tokens_above_maximum()
{
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 300_000,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let result = request.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().to_string().contains( "max_tokens must be between" ) );
}
#[ test ]
fn test_max_tokens_at_boundaries()
{
let request_min = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 1,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let request_max = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 200_000,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
assert!( request_min.validate().is_ok() );
assert!( request_max.validate().is_ok() );
}
#[ test ]
fn test_messages_empty()
{
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let result = request.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().to_string().contains( "At least one message is required" ) );
}
#[ test ]
fn test_temperature_below_minimum()
{
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : Some( -0.1 ),
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let result = request.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().to_string().contains( "Temperature must be between" ) );
}
#[ test ]
fn test_temperature_above_maximum()
{
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : Some( 1.5 ),
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let result = request.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().to_string().contains( "Temperature must be between" ) );
}
#[ test ]
fn test_temperature_at_boundaries()
{
let request_min = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : Some( 0.0 ),
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let request_max = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : Some( 1.0 ),
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
assert!( request_min.validate().is_ok() );
assert!( request_max.validate().is_ok() );
}
#[ test ]
fn test_valid_request()
{
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 1000,
messages : vec!
[
the_module::Message::user( "Hello!" ),
the_module::Message::assistant( "Hi there!" ),
the_module::Message::user( "How are you?" ),
],
system : Some( vec![ the_module::SystemContent::text( "You are helpful" ) ] ),
temperature : Some( 0.7 ),
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
assert!( request.validate().is_ok() );
}
#[ test ]
#[ cfg( feature = "tools" ) ]
fn test_tool_choice_without_tools()
{
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : None,
stream : None,
tools : None,
tool_choice : Some( the_module::ToolChoice::Auto ),
};
let result = request.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().to_string().contains( "tool_choice specified but no tools provided" ) );
}
#[ test ]
#[ cfg( feature = "tools" ) ]
fn test_tool_choice_unknown_tool()
{
let tool = the_module::ToolDefinition
{
name : "calculator".to_string(),
description : "Perform calculations".to_string(),
input_schema : serde_json::json!( { "type" : "object" } ),
};
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : None,
stream : None,
tools : Some( vec![ tool ] ),
tool_choice : Some( the_module::ToolChoice::specific( "unknown_tool" ) ),
};
let result = request.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().to_string().contains( "tool_choice references unknown tool" ) );
}
#[ test ]
#[ cfg( feature = "tools" ) ]
fn test_empty_tools_array()
{
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : None,
stream : None,
tools : Some( vec![] ),
tool_choice : None,
};
let result = request.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().to_string().contains( "tools array cannot be empty" ) );
}
#[ test ]
#[ cfg( feature = "tools" ) ]
fn test_tool_with_empty_name()
{
let tool = the_module::ToolDefinition
{
name : String::new(),
description : "A tool".to_string(),
input_schema : serde_json::json!( { "type" : "object" } ),
};
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : None,
stream : None,
tools : Some( vec![ tool ] ),
tool_choice : None,
};
let result = request.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().to_string().contains( "tool name cannot be empty" ) );
}
#[ test ]
#[ cfg( feature = "tools" ) ]
fn test_duplicate_tool_names()
{
let tool1 = the_module::ToolDefinition
{
name : "calculator".to_string(),
description : "First calculator".to_string(),
input_schema : serde_json::json!( { "type" : "object" } ),
};
let tool2 = the_module::ToolDefinition
{
name : "calculator".to_string(),
description : "Second calculator".to_string(),
input_schema : serde_json::json!( { "type" : "object" } ),
};
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : None,
stream : None,
tools : Some( vec![ tool1, tool2 ] ),
tool_choice : None,
};
let result = request.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().to_string().contains( "duplicate tool name" ) );
}
#[ test ]
#[ cfg( feature = "tools" ) ]
fn test_tool_with_empty_description()
{
let tool = the_module::ToolDefinition
{
name : "calculator".to_string(),
description : String::new(),
input_schema : serde_json::json!( { "type" : "object" } ),
};
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : None,
stream : None,
tools : Some( vec![ tool ] ),
tool_choice : None,
};
let result = request.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().to_string().contains( "description cannot be empty" ) );
}
#[ test ]
#[ cfg( feature = "tools" ) ]
fn test_too_many_tools()
{
let tools : Vec< the_module::ToolDefinition > = ( 0..65 ).map( |i|
{
the_module::ToolDefinition
{
name : format!( "tool_{i}" ),
description : format!( "Tool number {i}" ),
input_schema : serde_json::json!( { "type" : "object" } ),
}
} ).collect();
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : None,
stream : None,
tools : Some( tools ),
tool_choice : None,
};
let result = request.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().to_string().contains( "maximum of 64 tools" ) );
}
#[ test ]
#[ cfg( feature = "tools" ) ]
fn test_valid_tools()
{
let tool = the_module::ToolDefinition
{
name : "calculator".to_string(),
description : "Perform mathematical calculations".to_string(),
input_schema : serde_json::json!
({
"type" : "object",
"properties" :
{
"expression" : { "type" : "string" }
}
}),
};
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 100,
messages : vec![ the_module::Message::user( "Calculate 2 + 2" ) ],
system : None,
temperature : None,
stream : None,
tools : Some( vec![ tool ] ),
tool_choice : Some( the_module::ToolChoice::specific( "calculator" ) ),
};
assert!( request.validate().is_ok() );
}
#[ test ]
fn test_system_content_empty_text()
{
let content = the_module::SystemContent
{
r#type : "text".to_string(),
text : String::new(),
cache_control : None,
};
let result = content.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().contains( "text cannot be empty" ) );
}
#[ test ]
fn test_system_content_invalid_type()
{
let content = the_module::SystemContent
{
r#type : "image".to_string(),
text : "Some text".to_string(),
cache_control : None,
};
let result = content.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().contains( "Invalid system content type" ) );
}
#[ test ]
fn test_system_content_valid()
{
let content = the_module::SystemContent::text( "You are a helpful assistant" );
assert!( content.validate().is_ok() );
}
#[ test ]
fn test_system_instructions_empty()
{
let instructions = the_module::SystemInstructions::new();
let result = instructions.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().contains( "cannot be empty" ) );
}
#[ test ]
fn test_system_instructions_with_invalid_content()
{
let empty_content = the_module::SystemContent
{
r#type : "text".to_string(),
text : String::new(),
cache_control : None,
};
let instructions = the_module::SystemInstructions::new()
.add( empty_content );
let result = instructions.validate();
assert!( result.is_err() );
assert!( result.unwrap_err().contains( "Invalid content at index" ) );
}
#[ test ]
fn test_system_instructions_valid()
{
let instructions = the_module::SystemInstructions::new()
.add_text( "You are a helpful assistant" )
.add_cached_text( "Knowledge base content" )
.add_text( "Help the user" );
assert!( instructions.validate().is_ok() );
}
#[ tokio::test ]
#[ cfg( feature = "integration" ) ]
#[ ignore = "Requires workspace secrets file" ]
async fn integration_validation_prevents_invalid_requests()
{
let client = the_module::Client::from_workspace()
.expect( "INTEGRATION: Must have valid API key" );
let invalid_request = the_module::CreateMessageRequest
{
model : String::new(), max_tokens : 100,
messages : vec![ the_module::Message::user( "Hello" ) ],
system : None,
temperature : None,
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let validation_result = invalid_request.validate();
assert!( validation_result.is_err() );
let response = client.create_message( invalid_request ).await;
assert!( response.is_err() );
println!( "✅ Validation prevents invalid requests!" );
}
#[ tokio::test ]
#[ cfg( feature = "integration" ) ]
#[ ignore = "Requires workspace secrets file" ]
async fn integration_validation_allows_valid_requests()
{
let client = the_module::Client::from_workspace()
.expect( "INTEGRATION: Must have valid API key" );
let valid_request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 50,
messages : vec![ the_module::Message::user( "Say hello!" ) ],
system : None,
temperature : Some( 0.0 ),
stream : None,
#[ cfg( feature = "tools" ) ]
tools : None,
#[ cfg( feature = "tools" ) ]
tool_choice : None,
};
let validation_result = valid_request.validate();
assert!( validation_result.is_ok() );
let response = match client.create_message( valid_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" );
return;
},
Err( err ) => panic!( "INTEGRATION: Valid request must work : {err}" ),
};
assert!( !response.id.is_empty() );
println!( "✅ Validation allows valid requests!" );
}