use std::path::Path;
use crate::evidence::{EvidenceBundle, EvidenceSelection, assemble};
use crate::party::{OutcomeStatus, Results};
use crate::pipeline::{Error, read_json};
use crate::transcript::RunTranscript;
pub const RED_STATUSES: [OutcomeStatus; 2] = [OutcomeStatus::Failed, OutcomeStatus::Errored];
#[derive(Debug)]
pub struct EvidenceRequest<'a> {
pub transcript: &'a Path,
pub results: Option<&'a Path>,
pub only: &'a [String],
pub filter: Option<&'a str>,
pub failing: bool,
}
pub fn export_evidence(request: &EvidenceRequest<'_>) -> Result<EvidenceBundle, Error> {
if request.failing && request.results.is_none() {
return Err(Error::Selector(String::from(
"--failing needs --results: the red rows are named by the run's results record",
)));
}
let transcript: RunTranscript = read_json(request.transcript, "transcript")?;
let results: Option<Results> = match request.results {
None => None,
Some(path) => Some(read_json(path, "results")?),
};
let mut only: Vec<String> = request.only.to_vec();
only.sort_unstable();
only.dedup();
let selection = EvidenceSelection {
only,
filter: request.filter.map(ToOwned::to_owned),
statuses: if request.failing {
RED_STATUSES.to_vec()
} else {
Vec::new()
},
};
let outcomes = results.as_ref().map_or(&[][..], |r| r.outcomes.as_slice());
Ok(assemble(&transcript, outcomes, &selection)?)
}
#[cfg(test)]
mod tests {
use std::path::Path;
use super::{EvidenceRequest, export_evidence};
use crate::pipeline::Error;
#[test]
fn failing_without_a_results_record_is_refused_as_a_selector_fault() {
let request = EvidenceRequest {
transcript: Path::new("/nonexistent/transcript.json"),
results: None,
only: &[],
filter: None,
failing: true,
};
let error = export_evidence(&request).expect_err("there is no record to read rows from");
assert!(matches!(&error, Error::Selector(_)), "{error}");
assert!(error.to_string().contains("--results"), "{error}");
}
}