#[ 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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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-haiku-4-5-20251001".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() );
}
#[ cfg( feature = "integration" ) ]
#[ tokio::test ]
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!" );
}
#[ cfg( feature = "integration" ) ]
#[ tokio::test ]
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-haiku-4-5-20251001".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" ) =>
{
panic!( "INTEGRATION: credit balance exhausted - real API call succeeded but account has no credits. Test must fail per Loud Failure Mandate: {}", api_err.message )
},
Err( err ) => panic!( "INTEGRATION: Valid request must work : {err}" ),
};
assert!( !response.id.is_empty() );
println!( "✅ Validation allows valid requests!" );
}
#[ test ]
fn test_validate_model_valid()
{
assert!( the_module::validators::validate_model( "claude-opus-4-6" ).is_ok() );
}
#[ test ]
fn test_validate_model_empty()
{
let result = the_module::validators::validate_model( "" );
assert!( result.is_err() );
let err = result.unwrap_err();
assert_eq!( err.field, "model" );
}
#[ test ]
fn test_validate_model_too_long()
{
let long_model = "a".repeat( 300 );
let result = the_module::validators::validate_model( &long_model );
assert!( result.is_err() );
}
#[ test ]
fn test_validate_max_tokens_valid()
{
assert!( the_module::validators::validate_max_tokens( 1024 ).is_ok() );
assert!( the_module::validators::validate_max_tokens( 4096 ).is_ok() );
}
#[ test ]
fn test_validate_max_tokens_zero()
{
assert!( the_module::validators::validate_max_tokens( 0 ).is_err() );
}
#[ test ]
fn test_validate_max_tokens_too_large()
{
assert!( the_module::validators::validate_max_tokens( 10_000 ).is_err() );
}
#[ test ]
fn test_validate_temperature_valid()
{
assert!( the_module::validators::validate_temperature( 0.0 ).is_ok() );
assert!( the_module::validators::validate_temperature( 0.5 ).is_ok() );
assert!( the_module::validators::validate_temperature( 1.0 ).is_ok() );
}
#[ test ]
fn test_validate_temperature_invalid()
{
assert!( the_module::validators::validate_temperature( -0.1 ).is_err() );
assert!( the_module::validators::validate_temperature( 1.1 ).is_err() );
}
#[ test ]
fn test_validate_top_p_valid()
{
assert!( the_module::validators::validate_top_p( 0.0 ).is_ok() );
assert!( the_module::validators::validate_top_p( 0.9 ).is_ok() );
assert!( the_module::validators::validate_top_p( 1.0 ).is_ok() );
}
#[ test ]
fn test_validate_top_p_invalid()
{
assert!( the_module::validators::validate_top_p( -0.1 ).is_err() );
assert!( the_module::validators::validate_top_p( 1.1 ).is_err() );
}
#[ test ]
fn test_validate_top_k_valid()
{
assert!( the_module::validators::validate_top_k( 1 ).is_ok() );
assert!( the_module::validators::validate_top_k( 40 ).is_ok() );
assert!( the_module::validators::validate_top_k( 500 ).is_ok() );
}
#[ test ]
fn test_validate_top_k_invalid()
{
assert!( the_module::validators::validate_top_k( 0 ).is_err() );
assert!( the_module::validators::validate_top_k( 1000 ).is_err() );
}
#[ test ]
fn test_validate_messages_not_empty_valid()
{
let messages = vec![ "message1", "message2" ];
assert!( the_module::validators::validate_messages_not_empty( &messages ).is_ok() );
}
#[ test ]
fn test_validate_messages_not_empty_invalid()
{
let messages : Vec< String > = vec![];
assert!( the_module::validators::validate_messages_not_empty( &messages ).is_err() );
}
#[ test ]
fn test_validation_error_display()
{
let err = the_module::ValidationError::new( "temperature", "Invalid value" )
.with_value( "2.5" )
.with_constraint( "0.0 <= temperature <= 1.0" );
let display = format!( "{err}" );
assert!( display.contains( "temperature" ) );
assert!( display.contains( "Invalid value" ) );
assert!( display.contains( "2.5" ) );
}