use clap::{Parser, ValueEnum};
use std::path::PathBuf;
#[derive(Parser)]
#[command(name = "h1_request_building_conformance")]
#[command(about = "HTTP/1.1 request building conformance tester")]
struct Args {
#[arg(long, default_value = "markdown")]
format: OutputFormat,
#[arg(long, short)]
output: Option<PathBuf>,
#[arg(long)]
test_case: Option<String>,
#[arg(long, short)]
verbose: bool,
#[arg(long, default_value = "30")]
timeout: u64,
}
#[derive(Debug, Clone, ValueEnum)]
enum OutputFormat {
Json,
Markdown,
Summary,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let args = Args::parse();
if args.verbose {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("debug")).init();
}
println!("🔧 HTTP/1.1 Request Building Conformance Tester");
println!(" Testing asupersync against hyper-util reference");
println!(" Focus: Byte-identical wire format for same RequestBuilder operations");
println!();
let mut tester = asupersync_conformance::RequestBuildingConformanceTester::new();
if let Some(test_id) = &args.test_case {
tester.test_cases.retain(|case| case.id == *test_id);
if tester.test_cases.is_empty() {
eprintln!("❌ Test case '{}' not found", test_id);
std::process::exit(1);
}
println!("🔍 Running single test case: {}", test_id);
} else {
println!(
"📋 Running {} conformance test cases",
tester.test_cases.len()
);
}
let timeout_duration = std::time::Duration::from_secs(args.timeout);
let report = match tokio::time::timeout(timeout_duration, tester.run_all_tests()).await {
Ok(report) => report,
Err(_) => {
eprintln!("❌ Tests timed out after {} seconds", args.timeout);
std::process::exit(1);
}
};
let output = match args.format {
OutputFormat::Json => serde_json::to_string_pretty(&report)?,
OutputFormat::Markdown => tester.generate_markdown_report(&report),
OutputFormat::Summary => generate_summary_output(&report),
};
match args.output {
Some(path) => {
std::fs::write(&path, &output)?;
println!("📝 Report written to: {}", path.display());
}
None => {
println!("{}", output);
}
}
println!();
print_test_summary(&report);
let has_failures = report.summary.failed > 0;
let has_partial_coverage = has_incomplete_coverage(&report);
let exit_code = exit_code(&report);
if args.verbose && exit_code != 0 {
eprintln!("🚨 Exiting with code {} due to:", exit_code);
if has_failures {
eprintln!(" - {} test failures", report.summary.failed);
}
if has_partial_coverage {
eprintln!(
" - Partial coverage: {} expected failures, {} skipped",
report.summary.expected_failures, report.summary.skipped
);
}
}
std::process::exit(exit_code);
}
fn generate_summary_output(
report: &asupersync_conformance::RequestBuildingComplianceReport,
) -> String {
let mut output = String::new();
output.push_str("HTTP/1.1 REQUEST BUILDING CONFORMANCE SUMMARY\n");
output.push_str("=========================================\n\n");
output.push_str(&format!("Test Run: {}\n", report.test_run_id));
output.push_str(&format!("Timestamp: {}\n", report.timestamp));
output.push_str(&format!("Total Cases: {}\n\n", report.total_cases));
output.push_str("RESULTS:\n");
output.push_str(&format!(" ✅ Passed: {}\n", report.summary.passed));
output.push_str(&format!(" ❌ Failed: {}\n", report.summary.failed));
output.push_str(&format!(
" ⚠️ Expected Failures: {}\n",
report.summary.expected_failures
));
output.push_str(&format!(" ⏭️ Skipped: {}\n\n", report.summary.skipped));
output.push_str(&format!(
"Compliance Score: {:.1}%\n",
report.summary.compliance_score * 100.0
));
if report.summary.failed > 0 {
output.push_str("\nFAILURES:\n");
for result in &report.results {
if result.verdict == asupersync_conformance::RequestBuildingTestVerdict::Fail {
output.push_str(&format!(
" ❌ {}: {}\n",
result.case_id,
result.error.as_deref().unwrap_or("Unknown error")
));
output.push_str(&format!(
" Bytes match: {}, Asupersync: {} bytes, Hyper-util: {} bytes\n",
result.bytes_match, result.asupersync_size, result.reqwest_size
));
}
}
}
output.push_str("\nWIRE FORMAT ANALYSIS:\n");
for result in &report.results {
output.push_str(&format!(
" 📊 {}: match={}, asupersync={} bytes, hyper-util={} bytes\n",
result.case_id, result.bytes_match, result.asupersync_size, result.reqwest_size
));
}
output
}
fn print_test_summary(report: &asupersync_conformance::RequestBuildingComplianceReport) {
eprintln!("╭─ HTTP/1.1 REQUEST BUILDING CONFORMANCE RESULTS ─╮");
eprintln!("│ │");
let has_failures = report.summary.failed > 0;
let has_partial_coverage = has_incomplete_coverage(report);
let status_line = final_status_line(
report.summary.failed,
report.summary.skipped,
report.summary.expected_failures,
);
eprintln!("│ {:<46}│", status_line);
if !has_failures && !has_partial_coverage {
eprintln!(
"│ 🎯 Compliance: {:.1}% │",
report.summary.compliance_score * 100.0
);
} else if has_failures {
eprintln!(
"│ 📊 Compliance: {:.1}% │",
report.summary.compliance_score * 100.0
);
} else {
eprintln!(
"│ 📊 Coverage: {} expected failures, {} skipped │",
report.summary.expected_failures, report.summary.skipped
);
}
eprintln!("│ │");
eprintln!(
"│ 📋 Total: {} │",
report.total_cases
);
eprintln!(
"│ ✅ Passed: {} │",
report.summary.passed
);
eprintln!(
"│ ❌ Failed: {} │",
report.summary.failed
);
eprintln!(
"│ ⚠️ Expected: {} │",
report.summary.expected_failures
);
eprintln!(
"│ ⏭️ Skipped: {} │",
report.summary.skipped
);
eprintln!("│ │");
eprintln!("╰──────────────────────────────────────────────────╯");
}
fn has_incomplete_coverage(
report: &asupersync_conformance::RequestBuildingComplianceReport,
) -> bool {
report.total_cases == 0 || report.summary.expected_failures > 0 || report.summary.skipped > 0
}
fn exit_code(report: &asupersync_conformance::RequestBuildingComplianceReport) -> i32 {
if report.summary.failed > 0 || has_incomplete_coverage(report) {
1
} else {
0
}
}
fn final_status_line(failed: usize, skipped: usize, expected_failures: usize) -> String {
let has_partial_coverage = skipped > 0 || expected_failures > 0;
if failed == 0 && !has_partial_coverage {
"✅ ALL TESTS PASSED - FULL COVERAGE".to_string()
} else if failed > 0 && has_partial_coverage {
format!("❌ {failed} TESTS FAILED + PARTIAL COVERAGE")
} else if failed > 0 {
format!("❌ {failed} TESTS FAILED")
} else {
"⚠️ PARTIAL COVERAGE - NOT ALL TESTS RUN".to_string()
}
}
#[cfg(test)]
mod tests {
use super::*;
use asupersync_conformance::RequestBuildingComplianceSummary;
fn synthetic_report(
total_cases: usize,
failed: usize,
expected_failures: usize,
skipped: usize,
) -> asupersync_conformance::RequestBuildingComplianceReport {
asupersync_conformance::RequestBuildingComplianceReport {
test_run_id: "synthetic".to_string(),
timestamp: chrono::Utc::now().to_rfc3339(),
total_cases,
results: Vec::new(),
summary: RequestBuildingComplianceSummary {
passed: total_cases
.saturating_sub(failed)
.saturating_sub(expected_failures)
.saturating_sub(skipped),
failed,
expected_failures,
skipped,
total: total_cases,
compliance_score: 0.0,
},
}
}
#[test]
fn exit_code_is_nonzero_for_expected_failures() {
let report = synthetic_report(8, 0, 1, 0);
assert_eq!(exit_code(&report), 1);
}
#[test]
fn exit_code_is_nonzero_for_skipped_coverage() {
let report = synthetic_report(8, 0, 0, 1);
assert_eq!(exit_code(&report), 1);
}
#[test]
fn exit_code_is_nonzero_for_zero_case_reports() {
let report = synthetic_report(0, 0, 0, 0);
assert_eq!(exit_code(&report), 1);
}
#[test]
fn exit_code_is_nonzero_for_failures() {
let report = synthetic_report(8, 1, 0, 0);
assert_eq!(exit_code(&report), 1);
}
#[test]
fn exit_code_is_zero_for_full_pass_coverage() {
let report = synthetic_report(8, 0, 0, 0);
assert_eq!(exit_code(&report), 0);
}
#[test]
fn incomplete_coverage_is_true_for_zero_case_reports() {
let report = synthetic_report(0, 0, 0, 0);
assert!(has_incomplete_coverage(&report));
}
#[test]
fn final_status_line_does_not_claim_full_coverage_for_partial_results() {
let status = final_status_line(0, 1, 0);
assert!(status.contains("PARTIAL COVERAGE"));
assert!(!status.contains("ALL TESTS PASSED"));
}
#[test]
fn final_status_line_claims_full_coverage_only_for_full_green_results() {
assert_eq!(
final_status_line(0, 0, 0),
"✅ ALL TESTS PASSED - FULL COVERAGE"
);
}
}