#![ cfg( feature = "enhanced_tools" ) ]
use api_xai::{ ToolCall, FunctionCall, ToolResult, execute_tool_calls_parallel, execute_tool_calls_sequential };
use serde_json::json;
fn create_test_tool_call( id : &str, function_name : &str ) -> ToolCall
{
ToolCall
{
id : id.to_string(),
tool_type : "function".to_string(),
function : FunctionCall
{
name : function_name.to_string(),
arguments : r#"{"test": true}"#.to_string(),
},
}
}
#[ tokio::test ]
async fn test_parallel_execution_success()
{
let tool_calls = vec![
create_test_tool_call( "call_1", "func_a" ),
create_test_tool_call( "call_2", "func_b" ),
create_test_tool_call( "call_3", "func_c" ),
];
let results = execute_tool_calls_parallel( tool_calls, | call | async move {
let result = json!({
"function": call.function.name,
"status": "success"
});
Ok( ToolResult::new( call.id, &result ) )
} ).await;
assert_eq!( results.len(), 3 );
for result in results
{
assert!( result.is_ok() );
}
}
#[ tokio::test ]
async fn test_parallel_execution_with_errors()
{
let tool_calls = vec![
create_test_tool_call( "call_1", "func_success" ),
create_test_tool_call( "call_2", "func_error" ),
create_test_tool_call( "call_3", "func_success" ),
];
let results = execute_tool_calls_parallel( tool_calls, | call | async move {
if call.function.name == "func_error"
{
Err( "Simulated error".into() )
}
else
{
let result = json!({ "status": "ok" });
Ok( ToolResult::new( call.id, &result ) )
}
} ).await;
assert_eq!( results.len(), 3 );
assert!( results[ 0 ].is_ok() );
assert!( results[ 1 ].is_err() );
assert!( results[ 2 ].is_ok() );
}
#[ tokio::test ]
async fn test_sequential_execution()
{
let tool_calls = vec![
create_test_tool_call( "call_1", "step_1" ),
create_test_tool_call( "call_2", "step_2" ),
create_test_tool_call( "call_3", "step_3" ),
];
let execution_order = Vec::new();
let results = execute_tool_calls_sequential( tool_calls, | call | {
let order = execution_order.clone();
async move {
let mut order = order;
order.push( call.function.name.clone() );
let result = json!({
"function": call.function.name,
"order": order.len()
});
Ok( ToolResult::new( call.id, &result ) )
}
} ).await;
assert_eq!( results.len(), 3 );
for result in results
{
assert!( result.is_ok() );
}
}
#[ tokio::test ]
async fn test_tool_result_creation()
{
let result1 = ToolResult::new(
"call_123".to_string(),
&json!({ "temperature": 72 })
);
assert_eq!( result1.tool_call_id, "call_123" );
assert!( result1.result.contains( "temperature" ) );
assert!( result1.result.contains( "72" ) );
let result2 = ToolResult::from_string(
"call_456".to_string(),
r#"{"weather": "sunny"}"#.to_string()
);
assert_eq!( result2.tool_call_id, "call_456" );
assert_eq!( result2.result, r#"{"weather": "sunny"}"# );
let result3 = ToolResult::from_error(
"call_789".to_string(),
"Connection timeout"
);
assert_eq!( result3.tool_call_id, "call_789" );
assert!( result3.result.contains( "error" ) );
assert!( result3.result.contains( "Connection timeout" ) );
}
#[ tokio::test ]
async fn test_parallel_execution_empty_list()
{
let tool_calls : Vec< ToolCall > = vec![];
let results = execute_tool_calls_parallel( tool_calls, | call | async move {
let result = json!({ "status": "ok" });
Ok( ToolResult::new( call.id, &result ) )
} ).await;
assert_eq!( results.len(), 0 );
}
#[ tokio::test ]
async fn test_sequential_execution_empty_list()
{
let tool_calls : Vec< ToolCall > = vec![];
let results = execute_tool_calls_sequential( tool_calls, | call | async move {
let result = json!({ "status": "ok" });
Ok( ToolResult::new( call.id, &result ) )
} ).await;
assert_eq!( results.len(), 0 );
}