#![allow(missing_docs)]
use serde_json::json;
use std::path::PathBuf;
use vtcode_config::constants::tools;
use vtcode_core::tools::registry::ToolRegistry;
#[tokio::test]
async fn test_code_search_dual_output_integration() {
let workspace = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let registry = ToolRegistry::new(workspace).await;
let args = json!({
"query": "ToolRegistry",
"path": "src/tools",
"file_types": ["rust"],
"result_types": ["definition", "usage", "text"],
"max_results": 10
});
let result = registry
.execute_tool_dual(tools::CODE_SEARCH, args)
.await
.expect("code_search execution should succeed");
assert_eq!(result.tool_name, tools::CODE_SEARCH);
assert!(result.success, "Tool should succeed");
assert_eq!(result.llm_content, result.ui_content);
let response: serde_json::Value = serde_json::from_str(&result.llm_content).expect("compact code_search response");
let mut fields = response
.as_object()
.expect("response object")
.keys()
.map(String::as_str)
.collect::<Vec<_>>();
fields.sort_unstable();
assert_eq!(fields, ["filters", "hints", "query", "results", "returned", "truncated"]);
assert_eq!(response["query"], "ToolRegistry");
assert_eq!(response["filters"]["path"], "src/tools");
assert_eq!(response["filters"]["file_types"], json!(["rust"]));
assert_eq!(response["filters"]["result_types"], json!(["definition", "usage", "text"]));
assert_eq!(response["filters"]["max_results"], 10);
assert_eq!(response["returned"].as_u64(), response["results"].as_array().map(|results| results.len() as u64));
}
#[tokio::test]
async fn test_shell_listing_dual_output_integration() {
let workspace = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let registry = ToolRegistry::new(workspace).await;
let args = json!({
"cmd": "find src/tools -maxdepth 2 -type f | sort | head -n 20",
"yield_time_ms": 1000
});
let result = registry
.execute_tool_dual(tools::EXEC_COMMAND, args)
.await
.expect("exec_command listing should succeed");
assert!(!result.llm_content.is_empty());
assert!(!result.ui_content.is_empty());
assert!(!result.tool_name.is_empty());
let counts = &result.metadata.token_counts;
assert!(counts.llm_tokens > 0);
assert!(counts.ui_tokens > 0);
assert!(
result.llm_content.to_lowercase().contains("item")
|| result.llm_content.to_lowercase().contains("file")
|| result.llm_content.to_lowercase().contains("listed")
|| result.llm_content.to_lowercase().contains("found")
|| result.llm_content.to_lowercase().contains("lines"),
"LLM summary should mention items/files: {}",
result.llm_content
);
println!("v List Dual Output:");
println!(" LLM: {}", result.llm_content);
println!(" Savings: {}", result.savings_summary());
}
#[tokio::test]
async fn test_file_inspection_dual_output() {
let workspace = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let registry = ToolRegistry::new(workspace).await;
let args = json!({
"cmd": "sed -n '1,120p' README.md",
"yield_time_ms": 1000
});
let result = registry
.execute_tool_dual(tools::EXEC_COMMAND, args)
.await
.expect("exec_command file inspection should succeed");
assert!(!result.llm_content.is_empty());
assert!(!result.ui_content.is_empty());
assert!(!result.tool_name.is_empty());
assert!(
result.llm_content.to_lowercase().contains("read")
|| result.llm_content.to_lowercase().contains("line")
|| result.llm_content.to_lowercase().contains("file"),
"LLM summary should mention file stats: {}",
result.llm_content
);
let counts = &result.metadata.token_counts;
if counts.ui_tokens > 200 {
assert!(
counts.savings_percent > 50.0,
"Should have significant savings on large files: {:.1}%",
counts.savings_percent
);
println!("v Read File Dual Output:");
println!(" UI tokens: {}", counts.ui_tokens);
println!(" LLM tokens: {}", counts.llm_tokens);
println!(" Savings: {:.1}%", counts.savings_percent);
} else {
println!("v Read File Dual Output (small file):");
println!(" File too small for significant savings");
}
}
#[tokio::test]
async fn test_exec_command_dual_output() {
let workspace = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let registry = ToolRegistry::new(workspace).await;
let args = json!({
"cmd": "ls -la src/tools",
"yield_time_ms": 1000
});
let result = registry
.execute_tool_dual(tools::EXEC_COMMAND, args)
.await
.expect("exec_command execution should succeed");
assert!(!result.llm_content.is_empty());
assert!(!result.ui_content.is_empty());
assert!(!result.tool_name.is_empty());
let llm_lower = result.llm_content.to_lowercase();
assert!(
llm_lower.contains("command")
|| llm_lower.contains("exit")
|| llm_lower.contains("output")
|| llm_lower.contains("success"),
"LLM summary should mention execution details: {}",
result.llm_content
);
let counts = &result.metadata.token_counts;
if counts.ui_tokens > 200 {
assert!(
counts.savings_percent > 50.0,
"Should have significant savings on large command output: {:.1}%",
counts.savings_percent
);
println!("v Bash Dual Output:");
println!(" UI tokens: {}", counts.ui_tokens);
println!(" LLM tokens: {}", counts.llm_tokens);
println!(" Savings: {:.1}%", counts.savings_percent);
} else {
println!("v Bash Dual Output (small output):");
println!(" Command output too small for significant savings");
}
}
#[tokio::test]
async fn test_apply_patch_dual_output() {
let workspace = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let test_file = workspace.join("test_temp_write.txt");
let registry = ToolRegistry::new(workspace).await;
use std::fs;
let patch = "*** Begin Patch\n*** Add File: test_temp_write.txt\n+Test content for write operation\n+Line 2\n+Line 3\n*** End Patch\n";
let args = json!({
"patch": patch
});
let result = registry
.execute_tool_dual(tools::APPLY_PATCH, args)
.await
.expect("apply_patch execution should succeed");
let _ = fs::remove_file(&test_file);
assert!(!result.llm_content.is_empty());
assert!(!result.ui_content.is_empty());
assert!(!result.tool_name.is_empty());
let llm_lower = result.llm_content.to_lowercase();
assert!(
llm_lower.contains("modified")
|| llm_lower.contains("file")
|| llm_lower.contains("success")
|| llm_lower.contains("wrote")
|| llm_lower.contains("write"),
"LLM summary should mention file operation: {}",
result.llm_content
);
println!("v Edit/Write Dual Output:");
println!(" Tool: {}", result.tool_name);
println!(" LLM summary: {}", result.llm_content);
println!(" Savings: {}", result.savings_summary());
}
#[tokio::test]
async fn test_backward_compatibility() {
let workspace = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let registry = ToolRegistry::new(workspace).await;
let args = json!({
"pattern": "pub struct",
"path": "src/tools",
"max_results": 5
});
let old_result = registry
.execute_tool(tools::GREP_FILE, args.clone())
.await
.expect("Old execute_tool should still work");
assert!(old_result.is_object() || old_result.is_string());
let new_result = registry
.execute_tool_dual(tools::GREP_FILE, args)
.await
.expect("New execute_tool_dual should work");
assert!(!new_result.llm_content.is_empty());
assert!(!new_result.ui_content.is_empty());
println!("v Backward Compatibility:");
println!(" Old API: Working");
println!(" New API: Working with {} savings", new_result.savings_summary());
}