use anyhow::Result;
use fsvalidator::ModelBuilder;
use std::fs;
#[test]
fn test_builder_file_creation() -> Result<()> {
let test_dir = tempfile::tempdir()?;
let file_path = test_dir.path().join("test_file.txt");
fs::write(&file_path, "test content")?;
let file_node = ModelBuilder::new_file("test_file.txt")
.required(true)
.build();
assert!(file_node.validate(&file_path).is_ok());
Ok(())
}
#[test]
fn test_builder_dir_creation() -> Result<()> {
let test_dir = tempfile::tempdir()?;
let sub_dir = test_dir.path().join("sub_dir");
fs::create_dir(&sub_dir)?;
let dir_node = ModelBuilder::new_dir("sub_dir")
.required(true)
.allow_defined_only(false)
.build();
assert!(dir_node.validate(&sub_dir).is_ok());
Ok(())
}
#[test]
fn test_builder_dir_with_children() -> Result<()> {
let test_dir = tempfile::tempdir()?;
let sub_dir = test_dir.path().join("sub_dir");
fs::create_dir(&sub_dir)?;
let file_in_sub_dir = sub_dir.join("test_file.txt");
fs::write(&file_in_sub_dir, "test content")?;
let dir_node = ModelBuilder::new_dir("sub_dir")
.required(true)
.add_file("test_file.txt", true)
.build();
assert!(dir_node.validate(&sub_dir).is_ok());
Ok(())
}
#[test]
fn test_builder_complex_structure() -> Result<()> {
let test_dir = tempfile::tempdir()?;
let project_dir = test_dir.path().join("project");
fs::create_dir(&project_dir)?;
fs::write(project_dir.join("README.md"), "# Project")?;
let src_dir = project_dir.join("src");
fs::create_dir(&src_dir)?;
fs::write(src_dir.join("main.rs"), "fn main() {}")?;
fs::write(src_dir.join("lib.rs"), "pub fn hello() -> &'static str { \"Hello\" }")?;
let tests_dir = project_dir.join("tests");
fs::create_dir(&tests_dir)?;
fs::write(tests_dir.join("test_main.rs"), "#[test] fn test() {}")?;
let project = ModelBuilder::new_dir("project")
.required(true)
.allow_defined_only(true)
.add_file("README.md", true)
.add_dir("src", true)
.add_file_pattern(".*\\.rs", true)
.up()
.add_dir("tests", true)
.add_file_pattern("test_.*\\.rs", true)
.up()
.build();
let result = project.validate(&project_dir);
assert!(result.is_ok());
Ok(())
}
#[test]
fn test_builder_nested_dirs_multiple_levels() -> Result<()> {
let test_dir = tempfile::tempdir()?;
let root_dir = test_dir.path().join("root");
fs::create_dir(&root_dir)?;
let level1 = root_dir.join("level1");
fs::create_dir(&level1)?;
let level2 = level1.join("level2");
fs::create_dir(&level2)?;
let level3 = level2.join("level3");
fs::create_dir(&level3)?;
fs::write(level3.join("file.txt"), "test content")?;
let root = ModelBuilder::new_dir("root")
.required(true)
.add_dir("level1", true)
.add_dir("level2", true)
.add_dir("level3", true)
.add_file("file.txt", true)
.up()
.up()
.up()
.build();
let result = root.validate(&root_dir);
assert!(result.is_ok());
Ok(())
}
#[test]
fn test_builder_pattern_matching() -> Result<()> {
let test_dir = tempfile::tempdir()?;
let config_dir = test_dir.path().join("config");
fs::create_dir(&config_dir)?;
fs::write(config_dir.join("settings.json"), "{}")?;
fs::write(config_dir.join("config.json"), "{}")?;
fs::write(config_dir.join("user.yaml"), "user: test")?;
let config = ModelBuilder::new_dir("config")
.required(true)
.add_file_pattern(".*\\.json", true) .add_file_pattern(".*\\.yaml", false) .build();
let result = config.validate(&config_dir);
assert!(result.is_ok());
Ok(())
}
#[test]
fn test_builder_with_excluded_patterns() -> Result<()> {
let test_dir = tempfile::tempdir()?;
let data_dir = test_dir.path().join("data");
fs::create_dir(&data_dir)?;
fs::write(data_dir.join("data.csv"), "a,b,c")?;
fs::write(data_dir.join(".hidden"), "hidden file")?;
fs::write(data_dir.join(".DS_Store"), "mac file")?;
let data = ModelBuilder::new_dir("data")
.required(true)
.allow_defined_only(true)
.exclude_patterns(vec!["^\\..*", "\\.DS_Store"])
.add_file_pattern(".*\\.csv", true)
.build();
let result = data.validate(&data_dir);
assert!(result.is_ok());
Ok(())
}
#[test]
fn test_builder_validation_failures() -> Result<()> {
let test_dir = tempfile::tempdir()?;
let docs_dir = test_dir.path().join("docs");
fs::create_dir(&docs_dir)?;
let docs = ModelBuilder::new_dir("docs")
.required(true)
.add_file("README.md", true)
.build();
let result = docs.validate(&docs_dir);
assert!(result.is_err());
fs::write(docs_dir.join("README.md"), "# Docs")?;
let result = docs.validate(&docs_dir);
assert!(result.is_ok());
Ok(())
}
#[test]
fn test_builder_only_defined_children() -> Result<()> {
let test_dir = tempfile::tempdir()?;
let conf_dir = test_dir.path().join("conf");
fs::create_dir(&conf_dir)?;
fs::write(conf_dir.join("allowed.conf"), "allowed config")?;
fs::write(conf_dir.join("unexpected.txt"), "unexpected file")?;
let conf = ModelBuilder::new_dir("conf")
.required(true)
.allow_defined_only(true)
.add_file("allowed.conf", true)
.build();
let result = conf.validate(&conf_dir);
assert!(result.is_err());
fs::remove_file(conf_dir.join("unexpected.txt"))?;
let result = conf.validate(&conf_dir);
assert!(result.is_ok());
Ok(())
}