use std::fs::File;
use std::io::Read;
use std::path::Path;
pub(crate) trait FileResolver {
fn path_exists(&self, path: &Path) -> bool;
fn resolve(&self, path: &Path) -> syn::File;
}
#[derive(Default, Clone)]
pub(crate) struct FsResolver;
impl FileResolver for FsResolver {
fn path_exists(&self, path: &Path) -> bool {
path.exists()
}
fn resolve(&self, path: &Path) -> syn::File {
let mut file = File::open(&path).expect("Unable to open file");
let mut src = String::new();
file.read_to_string(&mut src).expect("Unable to read file");
syn::parse_file(&src).expect("Unable to parse file")
}
}
#[cfg(test)]
#[derive(Default, Clone)]
pub(crate) struct TestResolver {
files: std::collections::HashMap<std::path::PathBuf, String>,
}
#[cfg(test)]
impl TestResolver {
pub fn register(&mut self, path: &'static str, contents: &'static str) {
self.files
.insert(Path::new(path).to_path_buf(), contents.into());
}
}
#[cfg(test)]
impl FileResolver for TestResolver {
fn path_exists(&self, path: &Path) -> bool {
self.files.contains_key(path)
}
fn resolve(&self, path: &Path) -> syn::File {
let src = self
.files
.get(path)
.expect("Test should only refer to files in context");
syn::parse_file(src).unwrap_or_else(|_| {
panic!(
"Test code in {} should be parseable",
path.to_string_lossy()
)
})
}
}
#[cfg(test)]
#[derive(Default, Clone)]
pub(crate) struct PathCommentResolver;
#[cfg(test)]
impl FileResolver for PathCommentResolver {
fn path_exists(&self, _path: &Path) -> bool {
true
}
fn resolve(&self, path: &Path) -> syn::File {
syn::parse_file(&format!(
r#"const PATH: &str = "{}";"#,
path.to_str().unwrap()
))
.unwrap()
}
}