use std::io;
use std::path::{Path, PathBuf};
use std::sync::Mutex;
use super::util::PathProbe;
#[derive(Debug, Clone)]
pub enum Entry {
ReadableDir,
UnreadableDir,
NotADirectory,
Unresolvable(io::ErrorKind),
}
#[derive(Debug, Default)]
pub struct FakeProbe {
links: Vec<(PathBuf, PathBuf)>,
entries: Vec<(PathBuf, Entry)>,
canonicalized: Mutex<Vec<PathBuf>>,
}
impl FakeProbe {
pub fn with(path: impl Into<PathBuf>, entry: Entry) -> Self {
Self::default().add(path, entry)
}
pub fn dir(path: impl Into<PathBuf>) -> Self {
Self::with(path, Entry::ReadableDir)
}
pub fn add(mut self, path: impl Into<PathBuf>, entry: Entry) -> Self {
self.entries.push((path.into(), entry));
self
}
pub fn and_dir(self, path: impl Into<PathBuf>) -> Self {
self.add(path, Entry::ReadableDir)
}
pub fn link(mut self, path: impl Into<PathBuf>, target: impl Into<PathBuf>) -> Self {
let target = target.into();
self.links.push((path.into(), target.clone()));
self.and_dir(target)
}
fn entry(&self, path: &Path) -> Option<&Entry> {
self.entries
.iter()
.find(|(known, _)| known == path)
.map(|(_, entry)| entry)
}
pub fn canonicalized(&self) -> Vec<PathBuf> {
self.canonicalized.lock().unwrap().clone()
}
}
impl PathProbe for FakeProbe {
fn canonicalize(&self, path: &Path) -> io::Result<PathBuf> {
self.canonicalized.lock().unwrap().push(path.to_path_buf());
if let Some((_, target)) = self.links.iter().find(|(known, _)| known == path) {
return Ok(target.clone());
}
match self.entry(path) {
Some(Entry::Unresolvable(kind)) => Err(io::Error::from(*kind)),
Some(_) => Ok(path.to_path_buf()),
None => Err(io::Error::from(io::ErrorKind::NotFound)),
}
}
fn is_directory(&self, path: &Path) -> bool {
matches!(
self.entry(path),
Some(Entry::ReadableDir | Entry::UnreadableDir)
)
}
fn is_readable_dir(&self, path: &Path) -> bool {
matches!(self.entry(path), Some(Entry::ReadableDir))
}
}