use crate::__private::{FAILPOINTS, State};
use crate::common::{Branch, Label};
use crate::error::Error;
use crate::introspection::{Report, Trace};
use crate::options::Options;
use crate::tree::{ExecutionStatus, Tree};
#[derive(Default)]
pub struct Runner {
options: Options,
}
pub struct TraceHandle {}
impl TraceHandle {
pub fn trace(&self) -> Trace {
let mut trace = Trace { path: vec![] };
FAILPOINTS.with_borrow(|state| {
trace = state
.as_ref()
.expect("failpoints state must be initialized")
.tree
.generate_current_trace();
});
trace
}
}
impl Runner {
pub fn with_branch_preference(mut self, branch_preference: Branch) -> Self {
self.options.branch_preference = branch_preference;
self
}
pub fn run(self, mut func: impl FnMut(&TraceHandle)) -> Result<Report, Error> {
FAILPOINTS.with_borrow_mut(|state| {
assert!(state.is_none(), "failpoints state double initialization");
*state = Some(Box::new(State {
enabled: true,
tree: Tree::new(self.options),
}));
});
#[allow(unused)] let mut is_exhaustive = false;
loop {
FAILPOINTS.with_borrow_mut(|state| {
let state = state
.as_mut()
.expect("failpoints state must be initialized");
state.enabled = true;
state.tree.start();
});
let handle = TraceHandle {};
func(&handle);
let mut status = ExecutionStatus::Continue;
FAILPOINTS.with_borrow_mut(|state| {
status = state
.as_mut()
.expect("failpoints state must be initialized")
.tree
.finalize(Label::Finished);
});
match status {
ExecutionStatus::Continue => {}
ExecutionStatus::Stop => {
is_exhaustive = true;
break;
}
}
}
let mut report = None;
FAILPOINTS.with_borrow_mut(|state| {
let state = state.take().expect("failpoints state must be initialized");
report = Some(Report {
traces: state.tree.generate_all_traces(),
is_exhaustive,
})
});
Ok(report.expect("report must be filled"))
}
}