tree-type 0.4.5

Rust macros for creating type-safe filesystem tree structures
Documentation
#![allow(deprecated)]
use std::path::PathBuf;
use tempfile::TempDir;
use tree_type::ValidatorResult;
use tree_type::tree_type;

#[allow(dead_code)]
fn check_toml(config: &TestProjectConfig) -> ValidatorResult {
    // Simple validator that checks file has .toml extension
    if config.as_path().extension().and_then(|s| s.to_str()) == Some("toml") {
        ValidatorResult {
            errors: vec![],
            warnings: vec![],
        }
    } else {
        ValidatorResult {
            errors: vec!["File must have .toml extension".to_string()],
            warnings: vec![],
        }
    }
}

tree_type! {
    TestProject {
        #[required]
        src/,
        #[optional]
        cache/,
        #[required]
        #[validate(check_toml)]
        config("config.toml")
    }
}

#[test]
fn test_required_optional_parsing() {
    let project = TestProject::new(PathBuf::from("/test")).unwrap();

    // Should compile - this tests that the macro accepts the syntax
    let _src = project.src();
    let _cache = project.cache();
    let _config = project.config();
}

#[test]
fn test_validate_with_attributes() {
    let project = TestProject::new(PathBuf::from("/test")).unwrap();

    // Validate should check required paths exist
    let report = project.validate();

    // Since paths don't exist, should have errors
    assert!(!report.errors.is_empty());
}

#[test]
fn test_validator_function_called() {
    let tempdir = TempDir::new().unwrap();
    let project = TestProject::new(tempdir.path()).unwrap();

    // Create the directory structure
    project.setup().unwrap();

    // Create the config file manually (since it doesn't have #[default])
    std::fs::write(project.config().as_path(), "# config").unwrap();

    // Now validate - config file exists and validator should be called
    let report = project.validate();

    // Should pass since file has .toml extension
    assert!(
        report.is_ok(),
        "Validation should pass: {:?}",
        report.errors
    );
}

#[test]
fn test_ensure_only_creates_required_paths() {
    let tempdir = TempDir::new().unwrap();
    let project = TestProject::new(tempdir.path()).unwrap();

    // Call ensure() - NEW BEHAVIOR: calls setup() first, then validate()
    // setup() creates ALL directories (required and optional)
    let result = project.ensure();

    // NOTE: Current behavior - custom validator overrides required check
    // So config file with #[required] #[validate(...)] won't fail if missing
    assert!(result.is_ok());
    // ValidationReport with .is_ok() method
    let report = result.unwrap();
    assert!(
        report.is_ok(),
        "Validation passes (custom validator doesn't check existence)"
    );

    // Verify: setup() created all directories
    assert!(project.src().exists(), "Required src/ created by setup()");
    assert!(
        project.cache().exists(),
        "Optional cache/ also created by setup()"
    );
    assert!(
        !project.config().exists(),
        "Config file not created (no default)"
    );
}