#![allow(deprecated)]
use assert2::assert;
use assert2::check;
use assert2::let_assert;
use tempfile::TempDir;
use tree_type::tree_type;
tree_type! {
ProjectRoot {
src/,
target/,
config/ {
local/,
prod/
}
}
}
#[test]
fn test_setup_creates_all_directories() {
let_assert!(Ok(tempdir) = TempDir::new());
let project = ProjectRoot::new(tempdir.path()).unwrap();
let_assert!(Ok(_errors) = project.setup());
check!(project.exists());
check!(project.src().exists());
check!(project.target().exists());
check!(project.config().exists());
check!(project.config().local().exists());
check!(project.config().prod().exists());
}
tree_type! {
IssuesDir {
[id: String]/ as IssueDir {
attachments/,
comments/,
}
}
}
#[test]
fn test_setup_idempotent() {
let_assert!(Ok(tempdir) = TempDir::new());
let project = ProjectRoot::new(tempdir.path()).unwrap();
let_assert!(Ok(_errors) = project.setup());
check!(project.exists());
let_assert!(Ok(_errors) = project.setup());
check!(project.exists());
}
#[allow(dead_code)]
fn default_readme(file: &ProjectWithDefaultsReadme) -> Result<String, std::io::Error> {
Ok(format!(
"# Project at {}\n\nDefault readme content\n",
file.as_path().display()
))
}
#[allow(dead_code)]
fn default_config(_file: &ProjectWithDefaultsConfig) -> Result<String, std::io::Error> {
Ok("# Config\ndefault = true\n".to_string())
}
tree_type! {
ProjectWithDefaults {
src/,
#[default(default_readme)]
readme("README.md"),
#[default(default_config)]
config("config.toml"),
}
}
#[test]
fn test_setup_creates_files_with_defaults() {
let_assert!(Ok(tempdir) = TempDir::new());
let project = ProjectWithDefaults::new(tempdir.path()).unwrap();
let_assert!(Ok(_errors) = project.setup());
check!(project.src().exists());
check!(project.readme().exists());
check!(project.config().exists());
let_assert!(Ok(readme_content) = std::fs::read_to_string(project.readme().as_path()));
assert!(readme_content.starts_with("# Project at"));
let_assert!(Ok(config_content) = std::fs::read_to_string(project.config().as_path()));
assert!(config_content == "# Config\ndefault = true\n");
}
#[test]
fn test_setup_skips_existing_files() {
let_assert!(Ok(tempdir) = TempDir::new());
let project = ProjectWithDefaults::new(tempdir.path()).unwrap();
let_assert!(Ok(()) = std::fs::create_dir_all(tempdir.path()));
let_assert!(Ok(()) = std::fs::write(project.readme().as_path(), "# Custom\n"));
let_assert!(Ok(_errors) = project.setup());
let_assert!(Ok(readme_content) = std::fs::read_to_string(project.readme().as_path()));
assert!(readme_content == "# Custom\n");
check!(project.config().exists());
}
#[allow(dead_code)]
fn failing_default(_file: &ProjectWithErrorsFailingFile) -> Result<String, std::io::Error> {
Err(std::io::Error::other("intentional error"))
}
#[allow(dead_code)]
fn working_default(_file: &ProjectWithErrorsWorkingFile) -> Result<String, std::io::Error> {
Ok("working content\n".to_string())
}
tree_type! {
ProjectWithErrors {
src/,
#[default(failing_default)]
failing_file("fail.txt"),
#[default(working_default)]
working_file("work.txt"),
}
}
#[test]
fn test_setup_collects_errors() {
let_assert!(Ok(tempdir) = TempDir::new());
let project = ProjectWithErrors::new(tempdir.path()).unwrap();
let_assert!(Err(errors) = project.setup());
assert!(errors.len() == 1);
let_assert!(tree_type::BuildError::File(path, _) = &errors[0]);
assert!(path == &project.failing_file().as_path());
check!(project.src().exists());
check!(project.working_file().exists());
check!(!project.failing_file().exists());
}