use std::process::Command;
use std::path::Path;
use std::fs;
#[derive(Debug)]
struct TestResult {
name: String,
success: bool,
output: String,
error: Option<String>,
}
#[derive(Debug)]
struct ExampleInfo {
name: String,
file: String,
description: String,
}
fn get_examples() -> Vec<ExampleInfo> {
vec![
ExampleInfo {
name: "基本使用示例".to_string(),
file: "basic_usage".to_string(),
description: "演示 QuantumLog 的基本使用方法".to_string(),
},
ExampleInfo {
name: "完整示例集合".to_string(),
file: "complete_examples".to_string(),
description: "包含所有使用场景的完整示例".to_string(),
},
ExampleInfo {
name: "配置文件示例".to_string(),
file: "config_file_example".to_string(),
description: "演示如何从配置文件加载设置".to_string(),
},
ExampleInfo {
name: "统一 Sink Trait 使用示例(含单元测试)".to_string(),
file: "sink_trait_usage".to_string(),
description: "覆盖 Pipeline::add_exclusive_sink 与 PipelineBuilder::set_exclusive_sink 的示例与测试".to_string(),
},
]
}
fn run_example(example: &ExampleInfo) -> TestResult {
println!("\n🧪 测试示例: {}", example.name);
println!("📁 文件: examples/{}.rs", example.file);
println!("📝 描述: {}", example.description);
println!("{}", "=".repeat(60));
let output = if example.file == "sink_trait_usage" {
Command::new("cargo")
.args(["test", "--example", &example.file])
.output()
} else {
Command::new("cargo")
.args(["run", "--example", &example.file])
.output()
};
match output {
Ok(output) => {
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
let success = output.status.success();
let combined_output = format!("STDOUT:\n{}\nSTDERR:\n{}", stdout, stderr);
TestResult {
name: example.name.clone(),
success,
output: combined_output,
error: if success { None } else { Some(stderr.to_string()) },
}
}
Err(e) => TestResult {
name: example.name.clone(),
success: false,
output: String::new(),
error: Some(format!("执行命令失败: {}", e)),
},
}
}
fn check_environment() -> Result<(), String> {
if !Path::new("Cargo.toml").exists() {
return Err("请在 QuantumLog 项目根目录运行此脚本".to_string());
}
let cargo_check = Command::new("cargo").args(["--version"]).output();
match cargo_check {
Ok(output) => {
if output.status.success() {
let version = String::from_utf8_lossy(&output.stdout);
println!("✅ Cargo 版本: {}", version.trim());
} else {
return Err("Cargo 不可用".to_string());
}
}
Err(e) => {
return Err(format!("无法执行 cargo: {}", e));
}
}
println!("🔍 检查项目编译状态...");
let build_check = Command::new("cargo").args(["check"]).output();
match build_check {
Ok(output) => {
if output.status.success() {
println!("✅ 项目编译检查通过");
} else {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(format!("项目编译检查失败:\n{}", stderr));
}
}
Err(e) => {
return Err(format!("无法执行编译检查: {}", e));
}
}
Ok(())
}
fn setup_directories() -> Result<(), String> {
if !Path::new("logs").exists() {
fs::create_dir_all("logs").map_err(|e| format!("创建日志目录失败: {}", e))?;
println!("📁 创建日志目录: logs/");
}
Ok(())
}
fn generate_report(results: &[TestResult]) -> String {
let mut report = String::new();
for r in results {
let error_snippet = r
.error
.as_ref()
.map(|e| e.chars().take(200).collect::<String>())
.unwrap_or_else(|| "<none>".to_string());
report.push_str(&format!(
"Example: {} -> {}\nOutput snippet: {}\nError: {}\n\n",
r.name,
if r.success { "SUCCESS" } else { "FAIL" },
r.output.chars().take(200).collect::<String>(),
error_snippet,
));
}
report
}
fn cleanup() {
println!("\n🧹 清理临时文件...");
let temp_files = ["temp_config.toml"];
for file in &temp_files {
if Path::new(file).exists() {
if let Err(e) = fs::remove_file(file) {
println!("⚠️ 删除临时文件 {} 失败: {}", file, e);
} else {
println!("🗑️ 删除临时文件: {}", file);
}
}
}
}
fn main() {
println!("🚀 QuantumLog 示例测试脚本");
println!("{}", "=".repeat(50));
if let Err(e) = check_environment() {
eprintln!("❌ 环境检查失败: {}", e);
std::process::exit(1);
}
if let Err(e) = setup_directories() {
eprintln!("❌ 目录设置失败: {}", e);
std::process::exit(1);
}
let examples = get_examples();
println!("\n📝 找到 {} 个示例需要测试", examples.len());
let mut results = Vec::new();
for example in &examples {
let result = run_example(example);
if result.success {
println!("✅ {} 测试通过", result.name);
} else {
println!("❌ {} 测试失败", result.name);
}
results.push(result);
std::thread::sleep(std::time::Duration::from_millis(500));
}
let report = generate_report(&results);
println!("{}", report);
cleanup();
let failed_count = results.iter().filter(|r| !r.success).count();
if failed_count > 0 {
std::process::exit(1);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_examples() {
let examples = get_examples();
assert!(!examples.is_empty());
assert!(examples.iter().any(|e| e.file == "basic_usage"));
assert!(examples.iter().any(|e| e.file == "complete_examples"));
assert!(examples.iter().any(|e| e.file == "config_file_example"));
}
#[test]
fn test_example_info_creation() {
let example = ExampleInfo {
name: "测试示例".to_string(),
file: "test_example".to_string(),
description: "这是一个测试示例".to_string(),
};
assert_eq!(example.name, "测试示例");
assert_eq!(example.file, "test_example");
assert_eq!(example.description, "这是一个测试示例");
}
#[test]
fn test_test_result_creation() {
let result = TestResult {
name: "测试结果".to_string(),
success: true,
output: "测试输出".to_string(),
error: None,
};
assert_eq!(result.name, "测试结果");
assert!(result.success);
assert_eq!(result.output, "测试输出");
assert!(result.error.is_none());
}
}