#[ allow( unused_imports ) ]
use super::*;
#[ tokio::test ]
async fn test_api_error_response_parsing_and_classification()
{
let error_response = r#"
{
"error": {
"type": "invalid_request_error",
"message": "Your request contains invalid parameters"
}
}
"#;
let result = the_module::ErrorParser::parse_api_error( error_response );
match result
{
Ok( error ) =>
{
assert_eq!( error.error_class(), the_module::ErrorClass::InvalidRequest );
assert_eq!( error.severity(), the_module::ErrorSeverity::High );
assert!( !error.is_transient() );
},
Err( _err ) =>
{
}
}
let auth_error_response = r#"
{
"error": {
"type": "authentication_error",
"message": "Invalid API key provided"
}
}
"#;
let result = the_module::ErrorParser::parse_api_error( auth_error_response );
match result
{
Ok( error ) =>
{
assert_eq!( error.error_class(), the_module::ErrorClass::Authentication );
assert!( error.requires_credential_refresh() );
},
Err( _err ) =>
{
}
}
}
#[ tokio::test ]
async fn test_http_status_code_mapping_to_error_types()
{
let result = the_module::ErrorMapper::map_http_status( 400, "Bad Request" );
match result
{
Ok( error ) =>
{
assert_eq!( error.error_type(), the_module::ErrorType::InvalidRequest );
assert!( error.has_remediation_steps() );
},
Err( _err ) =>
{
}
}
let result = the_module::ErrorMapper::map_http_status( 401, "Unauthorized" );
match result
{
Ok( error ) =>
{
assert_eq!( error.error_type(), the_module::ErrorType::Authentication );
assert!( error.is_credential_related() );
},
Err( _err ) =>
{
}
}
let result = the_module::ErrorMapper::map_http_status( 429, "Too Many Requests" );
match result
{
Ok( error ) =>
{
assert_eq!( error.error_type(), the_module::ErrorType::RateLimit );
assert!( error.has_backoff_strategy() );
},
Err( _err ) =>
{
}
}
let result = the_module::ErrorMapper::map_http_status( 500, "Internal Server Error" );
match result
{
Ok( error ) =>
{
assert_eq!( error.error_type(), the_module::ErrorType::ServerError );
assert!( error.is_transient() );
assert!( error.supports_retry() );
},
Err( _err ) =>
{
}
}
}
#[ tokio::test ]
async fn test_error_context_preservation_and_stack_traces()
{
}
#[ tokio::test ]
async fn test_error_recovery_strategies_and_retry_conditions()
{
let network_error = the_module::AnthropicError::http_error( "Connection timeout".to_string() );
let recovery_strategy = the_module::ErrorRecovery::analyze_error( &network_error );
match recovery_strategy
{
Ok( strategy ) =>
{
assert!( strategy.should_retry() );
assert_eq!( strategy.max_retries(), 3 );
assert!( strategy.backoff_strategy() == the_module::BackoffStrategy::ExponentialBackoff );
assert!( strategy.base_delay() > core::time::Duration::from_millis( 100 ) );
},
Err( _err ) =>
{
}
}
let auth_error = the_module::AnthropicError::Authentication(
the_module::AuthenticationError::new( "Invalid API key".to_string() )
);
let recovery_strategy = the_module::ErrorRecovery::analyze_error( &auth_error );
match recovery_strategy
{
Ok( strategy ) =>
{
assert!( !strategy.should_retry() );
assert!( strategy.requires_user_action() );
assert!( strategy.suggested_action().contains( "API key" ) );
},
Err( _err ) =>
{
}
}
}
#[ tokio::test ]
async fn test_user_actionable_error_messages_with_remediation()
{
}
#[ tokio::test ]
async fn test_error_aggregation_and_batch_error_handling()
{
}
#[ tokio::test ]
async fn test_timeout_error_detection_and_classification()
{
let connection_timeout = the_module::TimeoutError::new(
the_module::TimeoutType::Connection,
core::time::Duration::from_secs( 30 ),
"Connection timeout after 30 seconds".to_string()
);
let classified_error = the_module::ErrorClassifier::classify_timeout( &connection_timeout );
match classified_error
{
Ok( classified ) =>
{
assert_eq!( classified.timeout_type(), the_module::TimeoutType::Connection );
assert!( classified.is_network_related() );
assert!( classified.suggested_timeout_increase() > core::time::Duration::from_secs( 30 ) );
},
Err( _err ) =>
{
}
}
let read_timeout = the_module::TimeoutError::new(
the_module::TimeoutType::Read,
core::time::Duration::from_secs( 60 ),
"Read timeout after 60 seconds".to_string()
);
let classified_error = the_module::ErrorClassifier::classify_timeout( &read_timeout );
match classified_error
{
Ok( classified ) =>
{
assert_eq!( classified.timeout_type(), the_module::TimeoutType::Read );
assert!( classified.is_server_processing_related() );
assert!( classified.supports_streaming_fallback() );
},
Err( _err ) =>
{
}
}
}
#[ tokio::test ]
async fn test_network_error_classification()
{
let dns_error = the_module::NetworkError::new(
the_module::NetworkErrorType::DnsResolution,
"Failed to resolve api.anthropic.com".to_string(),
Some( "NXDOMAIN".to_string() )
);
let classified = the_module::NetworkErrorClassifier::classify( &dns_error );
match classified
{
Ok( classification ) =>
{
assert_eq!( classification.error_type(), the_module::NetworkErrorType::DnsResolution );
assert!( classification.is_infrastructure_related() );
assert!( classification.suggested_actions().contains( &"DNS".to_string() ) );
},
Err( _err ) =>
{
}
}
let ssl_error = the_module::NetworkError::new(
the_module::NetworkErrorType::SslHandshake,
"SSL handshake failed".to_string(),
Some( "certificate verify failed".to_string() )
);
let classified = the_module::NetworkErrorClassifier::classify( &ssl_error );
match classified
{
Ok( classification ) =>
{
assert_eq!( classification.error_type(), the_module::NetworkErrorType::SslHandshake );
assert!( classification.is_security_related() );
assert!( classification.suggested_actions().contains( &"certificate".to_string() ) );
},
Err( _err ) =>
{
}
}
let connection_error = the_module::NetworkError::new(
the_module::NetworkErrorType::ConnectionRefused,
"Connection refused".to_string(),
Some( "port 443".to_string() )
);
let classified = the_module::NetworkErrorClassifier::classify( &connection_error );
match classified
{
Ok( classification ) =>
{
assert_eq!( classification.error_type(), the_module::NetworkErrorType::ConnectionRefused );
assert!( classification.is_service_availability_related() );
assert!( classification.supports_retry_with_backoff() );
},
Err( _err ) =>
{
}
}
}
#[ tokio::test ]
async fn test_rate_limiting_error_with_backoff_suggestions()
{
let rate_limit_error = the_module::RateLimitError::new(
"Too many requests".to_string(),
Some( 60 ),
"request_limit".to_string()
);
let backoff_strategy = the_module::BackoffCalculator::calculate_backoff( &rate_limit_error );
match backoff_strategy
{
Ok( strategy ) =>
{
assert!( strategy.initial_delay() >= core::time::Duration::from_secs( 60 ) );
assert_eq!( strategy.backoff_type(), the_module::BackoffType::Linear );
assert!( strategy.max_retries() <= 5 );
assert!( strategy.jitter_enabled() );
},
Err( _err ) =>
{
}
}
let token_rate_limit = the_module::RateLimitError::new(
"Token limit exceeded".to_string(),
Some( 300 ),
"token_limit".to_string()
);
let backoff_strategy = the_module::BackoffCalculator::calculate_backoff( &token_rate_limit );
match backoff_strategy
{
Ok( strategy ) =>
{
assert!( strategy.initial_delay() >= core::time::Duration::from_secs( 300 ) );
assert!( strategy.suggested_batch_size_reduction().is_some() );
},
Err( _err ) =>
{
}
}
}
#[ tokio::test ]
async fn test_authentication_error_with_credential_hints()
{
}
#[ tokio::test ]
async fn test_error_serialization_and_deserialization()
{
let original_error = the_module::EnhancedAnthropicError::new(
the_module::ErrorType::RateLimit,
"Rate limit exceeded".to_string(),
Some( the_module::ErrorContext::new(
"create_message".to_string(),
"req_123".to_string(),
std::collections::HashMap::from([
( "model".to_string(), "claude-sonnet-4-5-20250929".to_string() ),
( "tokens".to_string(), "1000".to_string() ),
])
))
);
let serialized = the_module::ErrorSerializer::serialize( &original_error );
match serialized
{
Ok( json_string ) =>
{
assert!( json_string.contains( "Rate limit exceeded" ) );
assert!( json_string.contains( "req_123" ) );
let deserialized = the_module::ErrorSerializer::deserialize( &json_string );
match deserialized
{
Ok( error ) =>
{
assert_eq!( error.error_type(), the_module::ErrorType::RateLimit );
assert_eq!( error.message(), "Rate limit exceeded" );
assert_eq!( error.context().unwrap().request_id(), "req_123" );
},
Err( _err ) =>
{
}
}
},
Err( _err ) =>
{
}
}
}
#[ tokio::test ]
async fn test_error_logging_and_monitoring_integration()
{
}
#[ tokio::test ]
async fn test_error_correlation_and_request_tracking()
{
}
#[ tokio::test ]
async fn test_error_message_localization_support()
{
let error = the_module::AnthropicError::InvalidRequest(
"Invalid model parameter".to_string()
);
let localized_en = the_module::ErrorLocalizer::localize( &error, "en" );
match localized_en
{
Ok( localized ) =>
{
assert!( localized.message().contains( "Invalid model parameter" ) );
assert_eq!( localized.locale(), "en" );
},
Err( _err ) =>
{
}
}
let spanish_localized = the_module::ErrorLocalizer::localize( &error, "es" );
match spanish_localized
{
Ok( localized ) =>
{
assert!( localized.message().contains( "parámetro del modelo" ) );
assert_eq!( localized.locale(), "es" );
},
Err( _err ) =>
{
}
}
let localized_fr = the_module::ErrorLocalizer::localize( &error, "fr" );
match localized_fr
{
Ok( localized ) =>
{
assert!( localized.message().contains( "paramètre de modèle" ) );
assert_eq!( localized.locale(), "fr" );
},
Err( _err ) =>
{
}
}
}
#[ tokio::test ]
async fn test_custom_error_types_and_chaining()
{
let domain_error = the_module::CustomError::new(
"ModelConfigurationError".to_string(),
"Model temperature out of range".to_string(),
the_module::ErrorSeverity::Medium
);
let api_error = the_module::AnthropicError::InvalidRequest(
"Temperature must be between 0.0 and 1.0".to_string()
);
let chained_error = the_module::ErrorChain::new( domain_error )
.caused_by( api_error )
.with_context( "temperature validation" );
match chained_error.build()
{
Ok( error ) =>
{
assert_eq!( error.chain_length(), 2 );
assert!( error.root_cause().contains( "Temperature must be between" ) );
assert!( error.immediate_cause().contains( "Model temperature out of range" ) );
assert!( error.has_context() );
assert_eq!( error.context(), "temperature validation" );
let chain_iterator = error.chain_iterator();
let errors : Vec< _ > = chain_iterator.collect();
assert_eq!( errors.len(), 2 );
assert!( errors[ 0 ].contains( "Model temperature out of range" ) );
assert!( errors[ 1 ].contains( "Temperature must be between" ) );
},
Err( _err ) =>
{
}
}
}
#[ tokio::test ]
#[ cfg( feature = "integration" ) ]
#[ ignore = "Requires workspace secrets file" ]
async fn integration_error_handling_network_timeout()
{
let client = the_module::Client::from_workspace()
.expect( "INTEGRATION: Must have valid API key for timeout testing" );
let large_request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 4000, messages : vec![
the_module::Message::user(
"Write a very detailed analysis of quantum computing, machine learning, blockchain technology, and artificial intelligence. Include mathematical formulas, code examples, and comprehensive explanations of each topic. Make it as detailed as possible.".repeat( 20 )
)
],
system : Some( vec![ the_module::SystemContent::text( "You are a comprehensive technical expert. Provide extremely detailed responses." ) ] ),
temperature : Some( 0.3 ),
stream : None,
tools : None,
tool_choice : None,
};
let result = client.create_message( large_request ).await;
match result
{
Ok( response ) => {
assert!( !response.id.is_empty(), "Large request response must have ID" );
assert!( response.usage.output_tokens > 0, "Must generate tokens" );
println!( "✅ Large request succeeded : {} tokens", response.usage.output_tokens );
},
Err( error ) => {
let error_str = error.to_string().to_lowercase();
assert!(
error_str.contains( "timeout" ) ||
error_str.contains( "rate" ) ||
error_str.contains( "limit" ) ||
error_str.contains( "request" ),
"Large request error should be meaningful : {error}"
);
println!( "✅ Large request properly handled error : {error}" );
}
}
}
#[ tokio::test ]
#[ cfg( feature = "integration" ) ]
#[ ignore = "Requires workspace secrets file" ]
async fn integration_error_handling_invalid_parameters()
{
let client = the_module::Client::from_workspace()
.expect( "Integration test requires valid API key. Set ANTHROPIC_API_KEY environment variable or configure workspace secrets." );
let invalid_temp_request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 10,
messages : vec![ the_module::Message::user( "Test".to_string() ) ],
system : None,
temperature : Some( 2.5 ), stream : None,
tools : None,
tool_choice : None,
};
let result = client.create_message( invalid_temp_request ).await;
assert!( result.is_err(), "Invalid temperature should cause error" );
let error = result.unwrap_err();
let error_str = error.to_string().to_lowercase();
assert!(
error_str.contains( "temperature" ) ||
error_str.contains( "parameter" ) ||
error_str.contains( "invalid" ),
"Temperature error should mention the issue : {error}"
);
println!( "✅ Invalid parameter error handling integration test passed!" );
println!( " Invalid temperature properly rejected : {error}" );
}
#[ tokio::test ]
#[ cfg( feature = "integration" ) ]
async fn integration_error_handling_authentication_failures()
{
let invalid_secret = the_module::Secret::new( "sk-ant-invalid-key-12345".to_string() )
.expect( "Invalid secret should construct" );
let invalid_client = the_module::Client::new( invalid_secret );
let request = the_module::CreateMessageRequest
{
model : "claude-3-5-haiku-20241022".to_string(),
max_tokens : 10,
messages : vec![ the_module::Message::user( "Test auth".to_string() ) ],
system : None,
temperature : None,
stream : None,
tools : None,
tool_choice : None,
};
let result = invalid_client.create_message( request ).await;
assert!( result.is_err(), "Invalid API key should cause authentication error" );
let error = result.unwrap_err();
let error_str = error.to_string().to_lowercase();
assert!(
error_str.contains( "authentication" ) ||
error_str.contains( "unauthorized" ) ||
error_str.contains( "invalid" ) ||
error_str.contains( "key" ),
"Auth error should mention authentication issue : {error}"
);
println!( "✅ Authentication error handling integration test passed!" );
println!( " Invalid API key properly rejected : {error}" );
}
#[ cfg( feature = "streaming" ) ]
#[ tokio::test ]
async fn test_sse_parsing_errors_malformed_json()
{
let malformed_message_start = r#"event : message_start
data : {"id": "msg_123", "type": INVALID_JSON}
"#;
let result = the_module::parse_sse_events( malformed_message_start );
assert!( result.is_ok(), "Should parse and filter out bad events" );
}
#[ cfg( feature = "streaming" ) ]
#[ tokio::test ]
async fn test_sse_parsing_unknown_event_type()
{
let unknown_event = r#"event : unknown_event_type
data : {"some": "data"}
"#;
let result = the_module::parse_sse_events( unknown_event );
assert!( result.is_ok() );
}
#[ cfg( feature = "streaming" ) ]
#[ tokio::test ]
async fn test_sse_parsing_content_block_delta_errors()
{
let incomplete_delta = r#"event : content_block_delta
data : {"index": 0}
"#;
let result = the_module::parse_sse_events( incomplete_delta );
assert!( result.is_ok() );
}
#[ cfg( feature = "error-handling" ) ]
#[ test ]
fn test_error_classification_is_retryable()
{
let rate_limit_err = the_module::AnthropicError::RateLimit(
the_module::RateLimitError::new( "Rate limited".to_string(), Some( 60 ), "request".to_string() )
);
assert!( rate_limit_err.is_retryable(), "Rate limit errors should be retryable" );
let internal_err = the_module::AnthropicError::Internal( "Server error".to_string() );
assert!( internal_err.is_retryable(), "Internal errors should be retryable" );
let stream_err = the_module::AnthropicError::Stream( "Stream interrupted".to_string() );
assert!( stream_err.is_retryable(), "Stream errors should be retryable" );
let invalid_arg_err = the_module::AnthropicError::InvalidArgument( "Bad input".to_string() );
assert!( !invalid_arg_err.is_retryable(), "Invalid argument errors should not be retryable" );
let auth_err = the_module::AnthropicError::Authentication(
the_module::AuthenticationError::new( "Bad key".to_string() )
);
assert!( !auth_err.is_retryable(), "Authentication errors should not be retryable" );
let parsing_err = the_module::AnthropicError::Parsing( "Parse failed".to_string() );
assert!( !parsing_err.is_retryable(), "Parsing errors should not be retryable" );
}
#[ cfg( feature = "error-handling" ) ]
#[ test ]
fn test_error_severity_classification()
{
use the_module::ErrorSeverity;
let auth_err = the_module::AnthropicError::Authentication(
the_module::AuthenticationError::new( "Invalid key".to_string() )
);
assert_eq!( auth_err.severity(), ErrorSeverity::Critical, "Auth errors should be critical" );
let missing_env_err = the_module::AnthropicError::MissingEnvironment( "No API key".to_string() );
assert_eq!( missing_env_err.severity(), ErrorSeverity::Critical, "Missing env errors should be critical" );
let invalid_req_err = the_module::AnthropicError::InvalidRequest( "Bad params".to_string() );
assert_eq!( invalid_req_err.severity(), ErrorSeverity::High, "Invalid request errors should be high" );
let rate_limit_err = the_module::AnthropicError::RateLimit(
the_module::RateLimitError::new( "Rate limited".to_string(), Some( 60 ), "request".to_string() )
);
assert_eq!( rate_limit_err.severity(), ErrorSeverity::Medium, "Rate limit errors should be medium" );
}
#[ cfg( feature = "error-handling" ) ]
#[ test ]
fn test_error_display_formatting()
{
let parsing_err = the_module::AnthropicError::Parsing( "JSON parse failed".to_string() );
let err_msg = format!( "{parsing_err}" );
assert!( err_msg.contains( "Parsing error" ) && err_msg.contains( "JSON parse failed" ),
"Parsing error should contain type and message : {err_msg}" );
let internal_err = the_module::AnthropicError::Internal( "Internal failure".to_string() );
let err_msg = format!( "{internal_err}" );
assert!( err_msg.contains( "Internal error" ) && err_msg.contains( "Internal failure" ),
"Internal error should contain type and message : {err_msg}" );
let missing_env_err = the_module::AnthropicError::MissingEnvironment( "ANTHROPIC_API_KEY not set".to_string() );
let err_msg = format!( "{missing_env_err}" );
assert!( err_msg.contains( "Missing environment" ) && err_msg.contains( "ANTHROPIC_API_KEY" ),
"Missing env error should contain type and variable : {err_msg}" );
let file_err = the_module::AnthropicError::File( "File not found".to_string() );
let err_msg = format!( "{file_err}" );
assert!( err_msg.contains( "File error" ) && err_msg.contains( "File not found" ),
"File error should contain type and message : {err_msg}" );
let not_impl_err = the_module::AnthropicError::NotImplemented( "Feature X not implemented".to_string() );
let err_msg = format!( "{not_impl_err}" );
assert!( err_msg.contains( "Not implemented" ) && err_msg.contains( "Feature X" ),
"NotImplemented error should contain type and feature : {err_msg}" );
}
#[ cfg( feature = "error-handling" ) ]
#[ test ]
fn test_error_recovery_suggestions()
{
let missing_env_err = the_module::AnthropicError::MissingEnvironment(
"ANTHROPIC_API_KEY not found".to_string()
);
let suggestions = missing_env_err.recovery_suggestions();
assert!( !suggestions.is_empty(), "Missing env errors should have recovery suggestions" );
assert!( suggestions.iter().any( | s | s.contains( "ANTHROPIC_API_KEY" ) || s.contains( "environment" ) ),
"Suggestions should mention the environment variable" );
let auth_err = the_module::AnthropicError::Authentication(
the_module::AuthenticationError::new( "Invalid API key".to_string() )
);
let suggestions = auth_err.recovery_suggestions();
assert!( !suggestions.is_empty(), "Auth errors should have recovery suggestions" );
let rate_limit_err = the_module::AnthropicError::RateLimit(
the_module::RateLimitError::new( "Rate limited".to_string(), Some( 60 ), "request".to_string() )
);
let suggestions = rate_limit_err.recovery_suggestions();
assert!( !suggestions.is_empty(), "Rate limit errors should have recovery suggestions" );
}
#[ cfg( all( feature = "streaming", feature = "error-handling" ) ) ]
#[ tokio::test ]
async fn test_stream_event_validation()
{
let valid_message = the_module::StreamMessage::new(
"msg_123",
"message",
"assistant",
"claude-sonnet-4-5-20250929",
the_module::Usage
{
input_tokens : 10,
output_tokens : 50,
cache_creation_input_tokens : None,
cache_read_input_tokens : None,
}
);
assert!( valid_message.validate().is_ok(), "Valid message should pass validation" );
let text_block = the_module::StreamContentBlock::new_text( "Hello world" );
assert!( text_block.validate().is_ok(), "Valid text block should pass validation" );
let text_delta = the_module::StreamDelta::new_text( "Hello" );
assert!( text_delta.validate().is_ok(), "Valid text delta should pass validation" );
}