blob: 638688027df49de67b3efd6741d1b2ecf122876c [file] [log] [blame] [edit]
use std::collections::BTreeMap;
#[derive(Debug)]
pub(crate) struct RunnerSpec {
cases: Vec<CaseSpec>,
include: Option<Vec<String>>,
default_bin: Option<crate::schema::Bin>,
timeout: Option<std::time::Duration>,
env: crate::schema::Env,
}
impl RunnerSpec {
pub(crate) fn new() -> Self {
Self {
cases: Default::default(),
include: None,
default_bin: None,
timeout: Default::default(),
env: Default::default(),
}
}
pub(crate) fn case(
&mut self,
glob: &std::path::Path,
expected: Option<crate::schema::CommandStatus>,
) {
self.cases.push(CaseSpec {
glob: glob.into(),
expected,
});
}
pub(crate) fn include(&mut self, include: Option<Vec<String>>) {
self.include = include;
}
pub(crate) fn default_bin(&mut self, bin: Option<crate::schema::Bin>) {
self.default_bin = bin;
}
pub(crate) fn timeout(&mut self, time: Option<std::time::Duration>) {
self.timeout = time;
}
pub(crate) fn env(&mut self, key: impl Into<String>, value: impl Into<String>) {
self.env.add.insert(key.into(), value.into());
}
pub(crate) fn prepare(&mut self) -> crate::Runner {
let mut runner = crate::Runner::new();
// Both sort and let the last writer win to allow overriding specific cases within a glob
let mut cases: BTreeMap<std::path::PathBuf, crate::Case> = BTreeMap::new();
for spec in &self.cases {
if let Some(glob) = get_glob(&spec.glob) {
match ::glob::glob(glob) {
Ok(paths) => {
for path in paths {
match path {
Ok(path) => {
cases.insert(
path.clone(),
crate::Case {
path,
expected: spec.expected,
default_bin: self.default_bin.clone(),
timeout: self.timeout,
env: self.env.clone(),
error: None,
},
);
}
Err(err) => {
let path = err.path().to_owned();
let err = crate::Error::new(err.into_error().to_string());
cases.insert(path.clone(), crate::Case::with_error(path, err));
}
}
}
}
Err(err) => {
let err = crate::Error::new(err.to_string());
cases.insert(
spec.glob.clone(),
crate::Case::with_error(spec.glob.clone(), err),
);
}
}
} else {
let path = spec.glob.as_path();
cases.insert(
path.into(),
crate::Case {
path: path.into(),
expected: spec.expected,
default_bin: self.default_bin.clone(),
timeout: self.timeout,
env: self.env.clone(),
error: None,
},
);
}
}
for case in cases.into_values() {
if self.is_included(&case) {
runner.case(case);
}
}
runner
}
fn is_included(&self, case: &crate::Case) -> bool {
if let Some(include) = self.include.as_deref() {
include
.iter()
.any(|i| case.path.to_string_lossy().contains(i))
} else {
true
}
}
}
impl Default for RunnerSpec {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug)]
struct CaseSpec {
glob: std::path::PathBuf,
expected: Option<crate::schema::CommandStatus>,
}
fn get_glob(path: &std::path::Path) -> Option<&str> {
if let Some(utf8) = path.to_str() {
if utf8.contains('*') {
return Some(utf8);
}
}
None
}