use std::path::{Path, PathBuf};
#[derive(Hash, PartialEq, Eq, Clone)]
pub struct Testable {
pub filename: PathBuf,
pub source: Option<PathBuf>,
pub contents: Vec<u8>,
}
impl std::fmt::Debug for Testable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Testable({:?})", self.filename)
}
}
impl Testable {
pub fn new<P: Into<PathBuf> + AsRef<Path>>(filename: P) -> Result<Self, std::io::Error> {
let contents = std::fs::read(&filename)?;
Ok(Self {
filename: filename.into(),
source: None,
contents,
})
}
pub fn new_with_source<P: Into<PathBuf> + AsRef<Path>>(
filename: P,
source: P,
) -> Result<Self, std::io::Error> {
let contents = std::fs::read(&filename)?;
Ok(Self {
filename: filename.into(),
source: Some(source.into()),
contents,
})
}
pub fn new_with_contents<P: Into<PathBuf> + AsRef<Path>>(
filename: P,
contents: Vec<u8>,
) -> Self {
Self {
filename: filename.into(),
source: None,
contents,
}
}
pub fn basename(&self) -> Option<String> {
self.filename
.file_name()
.and_then(|x| x.to_str())
.map(|x| x.to_string())
}
pub fn extension(&self) -> Option<String> {
self.filename
.extension()
.and_then(|x| x.to_str())
.map(|x| x.to_string())
}
pub fn set(&mut self, new_bytes: Vec<u8>) {
self.contents = new_bytes;
}
pub fn save(&self) -> Result<(), std::io::Error> {
std::fs::write(&self.filename, &self.contents)
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct TestableCollection {
pub testables: Vec<Testable>,
pub directory: String,
}
impl TestableCollection {
pub fn from_filenames<P: Into<PathBuf> + AsRef<Path> + Clone>(
filenames: &[P],
identifier: Option<&str>,
) -> Result<Self, std::io::Error> {
let collection: Result<Vec<Testable>, _> =
filenames.iter().map(|x| Testable::new(x.clone())).collect();
Ok(Self {
testables: collection?,
directory: identifier
.map(|x| x.to_string())
.unwrap_or("A collection".to_string()),
})
}
pub fn from_testables(testables: Vec<Testable>, identifier: Option<String>) -> Self {
Self {
testables,
directory: identifier.unwrap_or("A collection".to_string()),
}
}
pub fn iter(&self) -> impl Iterator<Item = &Testable> {
self.testables.iter()
}
pub fn collection_and_files(&self) -> impl Iterator<Item = TestableType<'_>> {
vec![TestableType::Collection(self)]
.into_iter()
.chain(self.testables.iter().map(TestableType::Single))
}
pub fn get_file(&self, filename: &str) -> Option<&Testable> {
self.testables
.iter()
.find(|x| x.basename().as_deref() == Some(filename))
}
}
#[derive(Debug, PartialEq, Eq)]
pub enum TestableType<'a> {
Single(&'a Testable),
Collection(&'a TestableCollection),
}
impl TestableType<'_> {
pub fn is_single(&self) -> bool {
matches!(self, TestableType::Single(_))
}
}