use std::path::{Path, PathBuf};
use serde::{Deserialize, Serialize};
use super::checker::{CheckDeserialization, Checker};
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(transparent)]
pub struct InputFile {
path: PathBuf,
}
impl InputFile {
pub fn new<P>(path: P) -> Self
where
PathBuf: From<P>,
{
Self {
path: PathBuf::from(path),
}
}
}
impl std::ops::Deref for InputFile {
type Target = Path;
fn deref(&self) -> &Self::Target {
&self.path
}
}
impl CheckDeserialization for InputFile {
fn check_deserialization(&mut self, checker: &mut Checker) -> Result<(), anyhow::Error> {
let checked_path = checker.check_path(self);
match checked_path {
Ok(p) => {
self.path = p;
Ok(())
}
Err(e) => Err(e),
}
}
}
#[cfg(test)]
mod tests {
use std::fs::{create_dir, File};
use super::*;
#[test]
fn test_input_file() {
let file = InputFile::new("hello/world");
let file_deref: &Path = &file;
assert_eq!(file_deref.to_str().unwrap(), "hello/world");
}
#[test]
fn test_serialization() {
let st: &str = "\"path/to/directory\"";
let file: InputFile = serde_json::from_str(st).unwrap();
assert_eq!(file.to_str().unwrap(), st.trim_matches('\"'));
assert_eq!(&*serde_json::to_string(&file).unwrap(), st);
}
#[test]
fn test_check_deserialization() {
let dir = tempfile::tempdir().unwrap();
let path = dir.path();
File::create(path.join("file_a.txt")).unwrap();
create_dir(path.join("dir0")).unwrap();
create_dir(path.join("dir1")).unwrap();
create_dir(path.join("dir1/dir0")).unwrap();
File::create(path.join("dir0/file_b.txt")).unwrap();
File::create(path.join("dir1/file_c.txt")).unwrap();
File::create(path.join("dir1/dir0/file_c.txt")).unwrap();
{
let absolute = path.join("file_a.txt");
let mut file = InputFile::new(absolute.clone());
let mut checker = Checker::new(Vec::new(), None);
file.check_deserialization(&mut checker).unwrap();
assert_eq!(file.path, absolute);
let absolute = path.join("dir0/file_b.txt");
let mut file = InputFile::new(absolute.clone());
let mut checker = Checker::new(Vec::new(), None);
file.check_deserialization(&mut checker).unwrap();
assert_eq!(file.path, absolute);
}
{
let absolute = path.join("dir0/file_c.txt");
let mut file = InputFile::new(absolute.clone());
let mut checker = Checker::new(Vec::new(), None);
let err = file.check_deserialization(&mut checker).unwrap_err();
let message = err.to_string();
assert!(message.contains("input file with absolute path"));
assert!(message.contains("either does not exist or is not a file"));
}
{
let mut checker = Checker::new(
vec![path.join("dir1/dir0"), path.join("dir1"), path.join("dir0")],
None,
);
let mut file = InputFile::new("file_c.txt");
file.check_deserialization(&mut checker).unwrap();
assert_eq!(file.path, path.join("dir1/dir0/file_c.txt"));
let mut file = InputFile::new("file_b.txt");
file.check_deserialization(&mut checker).unwrap();
assert_eq!(file.path, path.join("dir0/file_b.txt"));
let mut file = InputFile::new("file_a.txt");
let err = file.check_deserialization(&mut checker).unwrap_err();
let message = err.to_string();
assert!(message.contains("could not find input file"));
assert!(message.contains("in the search directories"));
let mut file = InputFile::new(path.join("file_c.txt"));
let err = file.check_deserialization(&mut checker).unwrap_err();
let message = err.to_string();
assert!(message.starts_with("input file with absolute path"));
}
}
}