use super::cli::FailureReason; use rayon::prelude::*; use std::process::Command; fn runner_command(runner: &str) -> Command { let mut it = runner.split_whitespace(); let mut cmd = Command::new(it.next().unwrap()); cmd.args(it); cmd } pub fn compare_outputs(intrinsic_name_list: &Vec, runner: &str, target: &str) -> bool { let intrinsics = intrinsic_name_list .par_iter() .filter_map(|intrinsic_name| { let c = runner_command(runner) .arg("intrinsic-test-programs") .arg(intrinsic_name) .current_dir("c_programs") .output(); let rust = runner_command(runner) .arg(format!("target/{target}/release/intrinsic-test-programs")) .arg(intrinsic_name) .current_dir("rust_programs") .output(); let (c, rust) = match (c, rust) { (Ok(c), Ok(rust)) => (c, rust), a => panic!("{a:#?}"), }; if !c.status.success() { error!( "Failed to run C program for intrinsic `{intrinsic_name}`\nstdout: {stdout}\nstderr: {stderr}", stdout = std::str::from_utf8(&c.stdout).unwrap_or(""), stderr = std::str::from_utf8(&c.stderr).unwrap_or(""), ); return Some(FailureReason::RunC(intrinsic_name.clone())); } if !rust.status.success() { error!( "Failed to run Rust program for intrinsic `{intrinsic_name}`\nstdout: {stdout}\nstderr: {stderr}", stdout = std::str::from_utf8(&rust.stdout).unwrap_or(""), stderr = std::str::from_utf8(&rust.stderr).unwrap_or(""), ); return Some(FailureReason::RunRust(intrinsic_name.clone())); } info!("Comparing intrinsic: {intrinsic_name}"); let c = std::str::from_utf8(&c.stdout) .unwrap() .to_lowercase() .replace("-nan", "nan"); let rust = std::str::from_utf8(&rust.stdout) .unwrap() .to_lowercase() .replace("-nan", "nan"); if c == rust { None } else { Some(FailureReason::Difference(intrinsic_name.clone(), c, rust)) } }) .collect::>(); intrinsics.iter().for_each(|reason| match reason { FailureReason::Difference(intrinsic, c, rust) => { println!("Difference for intrinsic: {intrinsic}"); let diff = diff::lines(c, rust); diff.iter().for_each(|diff| match diff { diff::Result::Left(c) => println!("C: {c}"), diff::Result::Right(rust) => println!("Rust: {rust}"), diff::Result::Both(_, _) => (), }); println!("****************************************************************"); } FailureReason::RunC(intrinsic) => { println!("Failed to run C program for intrinsic {intrinsic}") } FailureReason::RunRust(intrinsic) => { println!("Failed to run rust program for intrinsic {intrinsic}") } }); println!("{} differences found", intrinsics.len()); intrinsics.is_empty() }