use std::fs;
use std::path::{Path, PathBuf};
use crate::generate::emit::independence::{verify_test_independence, CertificateVerdict};
use crate::generate::emit::GenError;
pub struct EmittedTest<'a> {
pub test_name: &'a str,
pub provenance: &'a str,
pub rendered_template: &'a str,
pub rust: &'a str,
pub op_under_test: &'a str,
}
#[inline]
pub fn write_test(path: &Path, emitted: &EmittedTest<'_>) -> Result<PathBuf, GenError> {
let contents = assemble(emitted);
let parse_err = syn::parse_file(&contents)
.err()
.map(|err| GenError::InvalidRust {
test_name: emitted.test_name.to_string(),
reason: err.to_string(),
});
let cert_result = verify_test_independence(&contents, emitted.op_under_test);
let cert_err = cert_result.as_ref().err().map(|err| GenError::InvalidRust {
test_name: emitted.test_name.to_string(),
reason: format!("independence certificate parse failure: {err}"),
});
match (parse_err, cert_err) {
(Some(e1), Some(e2)) => return Err(GenError::Multiple(vec![e1, e2])),
(Some(e), None) | (None, Some(e)) => return Err(e),
(None, None) => {}
}
let certificate = match cert_result {
Ok(certificate) => certificate,
Err(err) => {
return Err(GenError::InvalidRust {
test_name: emitted.test_name.to_string(),
reason: format!("independence certificate parse failure: {err}"),
});
}
};
if let CertificateVerdict::SuspectedTautology {
line,
call_path,
hint,
} = certificate.verdict
{
return Err(GenError::TautologicalTest {
test_name: emitted.test_name.to_string(),
op: emitted.op_under_test.to_string(),
line,
call_path,
hint,
});
}
if let Some(parent) = path.parent() {
fs::create_dir_all(parent)?;
}
fs::write(path, contents)?;
Ok(path.to_path_buf())
}
fn assemble(emitted: &EmittedTest<'_>) -> String {
let mut out = String::new();
out.push_str(emitted.provenance);
out.push_str("// rendered template follows for auditability:\n");
for line in emitted.rendered_template.lines() {
out.push_str("// ");
out.push_str(line);
out.push('\n');
}
out.push('\n');
out.push_str(emitted.rust);
if !emitted.rust.ends_with('\n') {
out.push('\n');
}
out
}