Add dev::test module for filesystem tests setup/teardown
This commit is contained in:
parent
9ebd91a589
commit
c305627822
3 changed files with 227 additions and 29 deletions
135
src/dev/test.rs
Normal file
135
src/dev/test.rs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
use std::{env, fs, io, path::PathBuf};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
pub struct Directories {
|
||||
pub original: PathBuf,
|
||||
pub templates: PathBuf,
|
||||
pub test: PathBuf,
|
||||
}
|
||||
|
||||
impl Directories {
|
||||
/// Sets up self-cleaning original, temporary and 'templates' directories.
|
||||
///
|
||||
/// # Errors
|
||||
/// May return Error when:
|
||||
/// - Current directory does not exist or lacking permissions
|
||||
/// - Several I/O possibilities from directory creation failures
|
||||
/// - Several I/O possibilities from working directory changing failures
|
||||
pub fn setup(dir_name: &str) -> Result<Directories, Error> {
|
||||
let original = env::current_dir()?;
|
||||
let test = original.join(format!("target/mocks/{dir_name}"));
|
||||
let templates = test.join("templates");
|
||||
|
||||
drop(fs::remove_dir_all(&test));
|
||||
|
||||
if let Err(error) = fs::create_dir_all(&test) {
|
||||
return Err(Error::with_io(
|
||||
"Failed test's directory creation",
|
||||
error,
|
||||
))
|
||||
}
|
||||
|
||||
if let Err(error) = fs::create_dir_all(&templates) {
|
||||
return Err(Error::with_io(
|
||||
"Failed 'templates' directory creation",
|
||||
error,
|
||||
))
|
||||
}
|
||||
|
||||
if let Err(error) = env::set_current_dir(&test) {
|
||||
return Err(Error::with_io("Failed current directory change", error))
|
||||
}
|
||||
|
||||
Ok(Directories {
|
||||
original,
|
||||
templates,
|
||||
test,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Directories {
|
||||
fn drop(&mut self) {
|
||||
if let Err(error) = std::env::set_current_dir(&self.original) {
|
||||
log!(ERROR, "Couldn't reset to original directory: {error}");
|
||||
}
|
||||
if let Err(error) = std::fs::remove_dir_all(&self.test) {
|
||||
log!(WARN, "Couldn't cleanup test directory: {error}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Error {
|
||||
pub message: String,
|
||||
pub inner_io: Option<io::Error>,
|
||||
pub inner_tera: Option<tera::Error>,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
fn with_io(message: &str, inner_io: io::Error) -> Error {
|
||||
Error {
|
||||
message: String::from(message),
|
||||
inner_io: Some(inner_io),
|
||||
inner_tera: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
let mut message = self.message.clone();
|
||||
|
||||
if let Some(inner_io) = &self.inner_io {
|
||||
message = format!("{message}\n{inner_io}");
|
||||
}
|
||||
|
||||
if let Some(inner_tera) = &self.inner_tera {
|
||||
message = format!("{message}\n{inner_tera}");
|
||||
}
|
||||
|
||||
write!(f, "{message}")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for Error {
|
||||
fn from(string: String) -> Error {
|
||||
Error {
|
||||
message: string,
|
||||
inner_io: None,
|
||||
inner_tera: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for Error {
|
||||
fn from(str: &str) -> Error { Error::from(String::from(str)) }
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(inner: io::Error) -> Error {
|
||||
let mut error = Error::from(inner.to_string());
|
||||
error.inner_io = Some(inner);
|
||||
error
|
||||
}
|
||||
}
|
||||
|
||||
impl From<tera::Error> for Error {
|
||||
fn from(inner: tera::Error) -> Error {
|
||||
let mut error = Error::from(inner.to_string());
|
||||
error.inner_tera = Some(inner);
|
||||
error
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn bad_test_directory_name() {
|
||||
let dirs = Directories::setup("\0");
|
||||
assert!(dirs.is_err());
|
||||
}
|
||||
}
|
||||
15
src/graph.rs
15
src/graph.rs
|
|
@ -1308,24 +1308,19 @@ mod tests {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(clippy::panic_in_result_fn)]
|
||||
mod serial_tests {
|
||||
use super::*;
|
||||
use crate::dev::test::{Directories, Error};
|
||||
|
||||
#[test]
|
||||
fn bad_graph_path() {
|
||||
let original_working_directory = std::env::current_dir().unwrap();
|
||||
|
||||
assert!(
|
||||
std::env::set_current_dir(std::path::Path::new(
|
||||
"tests/mocks/no_graph"
|
||||
))
|
||||
.is_ok()
|
||||
);
|
||||
fn bad_graph_path() -> Result<(), Error> {
|
||||
let _dirs = Directories::setup("bad_graph_path")?;
|
||||
|
||||
let graph = Graph::load();
|
||||
let message = graph.meta.messages.first().unwrap();
|
||||
assert!(message.contains("Failed reading file at"));
|
||||
|
||||
assert!(std::env::set_current_dir(original_working_directory).is_ok());
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -496,33 +496,101 @@ mod tests {
|
|||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[expect(clippy::panic_in_result_fn)]
|
||||
mod serial_tests {
|
||||
use std::{ffi::OsStr, os::unix::ffi::OsStrExt as _};
|
||||
|
||||
use super::*;
|
||||
use crate::dev::test::{Directories, Error};
|
||||
|
||||
#[cfg_attr(not(unix), ignore)]
|
||||
#[test]
|
||||
fn invalid_utf8_template_filename() {
|
||||
use std::{ffi::OsStr, os::unix::ffi::OsStrExt as _, path::PathBuf};
|
||||
#[cfg_attr(not(unix), ignore)]
|
||||
fn invalid_utf8_template_filename() -> Result<(), Error> {
|
||||
let dirs = Directories::setup("encoding")?;
|
||||
|
||||
let original_working_directory = std::env::current_dir().unwrap();
|
||||
let base_dir = PathBuf::from("tests/mocks/encoding/temp");
|
||||
let templates_dir = base_dir.clone().join("templates");
|
||||
assert!(std::fs::create_dir_all(&base_dir).is_ok());
|
||||
assert!(
|
||||
std::env::set_current_dir(&base_dir)
|
||||
.is_ok()
|
||||
);
|
||||
assert!(std::fs::create_dir_all(&templates_dir).is_ok());
|
||||
let invalid_name = OsStr::from_bytes(&[0xff, 0xfe, 0x80]);
|
||||
let file_path = dirs.templates.join(invalid_name);
|
||||
fs::write(file_path, b"")?;
|
||||
|
||||
let template_load_result = load_templates();
|
||||
let err = template_load_result.err().unwrap();
|
||||
|
||||
let invalid_name = OsStr::from_bytes(&[0xff, 0xfe, 0x00]);
|
||||
let file_path = templates_dir.join(invalid_name);
|
||||
assert!(std::fs::write(&file_path, b"eNJq4FPUqSKoozdg").is_ok());
|
||||
let error_message = err.to_string();
|
||||
assert!(error_message.contains("not valid unicode"));
|
||||
|
||||
let result = load_templates();
|
||||
assert!(result.is_err());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
assert!(std::fs::remove_dir_all(&base_dir).is_ok());
|
||||
assert!(std::env::set_current_dir(original_working_directory).is_ok());
|
||||
#[test]
|
||||
fn custom_template() -> Result<(), Error> {
|
||||
let dirs = Directories::setup("custom_template")?;
|
||||
|
||||
let file_name = "custom.html";
|
||||
let file_path = dirs.templates.join(file_name);
|
||||
fs::write(file_path, b"")?;
|
||||
|
||||
let engine = load_templates()?;
|
||||
assert!(engine.get_template_names().any(|t| t == "custom.html"));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn custom_template_inheritance_error() -> Result<(), Error> {
|
||||
let dirs = Directories::setup("custom_template")?;
|
||||
|
||||
let file_name = "custom.html";
|
||||
let file_path = dirs.templates.join(file_name);
|
||||
fs::write(file_path, br#"{% extends "nonexistent.html" %}"#)?;
|
||||
|
||||
let template_load_result = load_templates();
|
||||
assert!(template_load_result.is_err());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inner_template_no_op() -> Result<(), Error> {
|
||||
let dirs = Directories::setup("inner_template")?;
|
||||
|
||||
let inner_dir = dirs.templates.join("inner");
|
||||
fs::create_dir(&inner_dir)?;
|
||||
let inner_template = inner_dir.join("inner.html");
|
||||
fs::write(inner_template, br#"{% extends "nonexistent.html" %}"#)?;
|
||||
|
||||
let engine = load_templates()?;
|
||||
let default_count = dirs.original.join("templates").read_dir()?.count();
|
||||
let template_count = engine.get_template_names().count();
|
||||
assert!(template_count == default_count);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn templates_dir_not_found_ok() -> Result<(), Error> {
|
||||
let dirs = Directories::setup("not_found_error")?;
|
||||
|
||||
std::fs::remove_dir_all(&dirs.templates)?;
|
||||
let template_load_result = load_templates();
|
||||
template_load_result?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
// Unexpected here means any error other than 'not found'
|
||||
fn templates_dir_unexpected_error() -> Result<(), Error> {
|
||||
let dirs = Directories::setup("unexpected_error")?;
|
||||
|
||||
log!(DEBUG, "Working directory is {:?}", std::env::current_dir());
|
||||
|
||||
std::fs::remove_dir_all(&dirs.templates)?;
|
||||
let templates = dirs.test.join("templates");
|
||||
fs::write(&templates, b"")?;
|
||||
|
||||
let template_load_result = load_templates();
|
||||
assert!(template_load_result.is_err());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue