use assert_cmd::Command;
use predicates::prelude::*;
use serial_test::serial;
use std::fs;
use tempfile::TempDir;
fn dampen_cmd() -> Command {
Command::cargo_bin("dampen").unwrap()
}
fn create_test_project(temp_dir: &TempDir) -> std::path::PathBuf {
let project_path = temp_dir.path().join("test-project");
fs::create_dir_all(&project_path).unwrap();
fs::create_dir_all(project_path.join("src/ui")).unwrap();
let cargo_toml = r#"
[package]
name = "test-project"
version = "0.1.0"
edition = "2024"
[dependencies]
dampen-core = "0.2.2"
dampen-macros = "0.2.2"
"#;
fs::write(project_path.join("Cargo.toml"), cargo_toml).unwrap();
fs::write(project_path.join("src/main.rs"), "fn main() {}").unwrap();
fs::write(project_path.join("src/ui/mod.rs"), "// UI modules\n").unwrap();
project_path
}
#[test]
#[serial]
fn test_add_ui_creates_files() {
let temp = TempDir::new().unwrap();
let project_path = create_test_project(&temp);
dampen_cmd()
.arg("add")
.arg("--ui")
.arg("settings")
.current_dir(&project_path)
.assert()
.success()
.stdout(predicate::str::contains("Created UI window 'settings'"))
.stdout(predicate::str::contains("settings.rs"))
.stdout(predicate::str::contains("settings.dampen"));
let settings_rs = project_path.join("src/ui/settings.rs");
let settings_dampen = project_path.join("src/ui/settings.dampen");
assert!(settings_rs.exists(), "settings.rs should be created");
assert!(
settings_dampen.exists(),
"settings.dampen should be created"
);
let rs_content = fs::read_to_string(&settings_rs).unwrap();
assert!(
rs_content.contains("settings"),
"Rust file should contain module name"
);
assert!(
rs_content.contains("#[dampen_ui"),
"Rust file should have dampen_ui attribute"
);
assert!(
rs_content.contains("pub struct Model"),
"Rust file should define Model struct"
);
let dampen_content = fs::read_to_string(&settings_dampen).unwrap();
assert!(
!dampen_content.contains("<?xml"),
"XML file should NOT have declaration"
);
assert!(
dampen_content.contains("Settings"),
"XML file should contain window title"
);
}
#[test]
#[serial]
fn test_add_ui_prevents_overwrite() {
let temp = TempDir::new().unwrap();
let project_path = create_test_project(&temp);
dampen_cmd()
.arg("add")
.arg("--ui")
.arg("dashboard")
.current_dir(&project_path)
.assert()
.success();
dampen_cmd()
.arg("add")
.arg("--ui")
.arg("dashboard")
.current_dir(&project_path)
.assert()
.failure()
.stderr(predicate::str::contains("already exists"))
.stderr(predicate::str::contains("dashboard"));
}
#[test]
#[serial]
fn test_add_ui_fails_outside_dampen_project() {
let temp = TempDir::new().unwrap();
dampen_cmd()
.arg("add")
.arg("--ui")
.arg("test")
.current_dir(temp.path())
.assert()
.failure()
.stderr(predicate::str::contains("Not a Dampen project"));
}
#[test]
#[serial]
fn test_add_ui_validates_window_name() {
let temp = TempDir::new().unwrap();
let project_path = create_test_project(&temp);
dampen_cmd()
.arg("add")
.arg("--ui")
.arg("")
.current_dir(&project_path)
.assert()
.failure();
dampen_cmd()
.arg("add")
.arg("--ui")
.arg("9window")
.current_dir(&project_path)
.assert()
.failure()
.stderr(predicate::str::contains("must start with a letter"));
dampen_cmd()
.arg("add")
.arg("--ui")
.arg("mod")
.current_dir(&project_path)
.assert()
.failure()
.stderr(predicate::str::contains("reserved"));
}
#[test]
#[serial]
fn test_add_ui_case_conversion() {
let temp = TempDir::new().unwrap();
let project_path = create_test_project(&temp);
dampen_cmd()
.arg("add")
.arg("--ui")
.arg("UserProfile")
.current_dir(&project_path)
.assert()
.success();
assert!(project_path.join("src/ui/user_profile.rs").exists());
assert!(project_path.join("src/ui/user_profile.dampen").exists());
let rs_content = fs::read_to_string(project_path.join("src/ui/user_profile.rs")).unwrap();
assert!(rs_content.contains("user_profile"));
}
#[test]
#[serial]
fn test_add_ui_custom_path() {
let temp = TempDir::new().unwrap();
let project_path = create_test_project(&temp);
dampen_cmd()
.arg("add")
.arg("--ui")
.arg("admin_panel")
.arg("--path")
.arg("src/ui/admin")
.current_dir(&project_path)
.assert()
.success();
assert!(project_path.join("src/ui/admin/admin_panel.rs").exists());
assert!(
project_path
.join("src/ui/admin/admin_panel.dampen")
.exists()
);
}
#[test]
#[serial]
fn test_generated_files_compile() {
let temp = TempDir::new().unwrap();
let project_path = create_test_project(&temp);
dampen_cmd()
.arg("add")
.arg("--ui")
.arg("test_window")
.current_dir(&project_path)
.assert()
.success();
let rs_content = fs::read_to_string(project_path.join("src/ui/test_window.rs")).unwrap();
let dampen_content =
fs::read_to_string(project_path.join("src/ui/test_window.dampen")).unwrap();
assert!(
rs_content.contains("use") && rs_content.contains("pub fn"),
"Rust file should have proper structure"
);
assert!(
dampen_content.starts_with("<dampen") && dampen_content.contains("</dampen>"),
"XML should be well-formed"
);
}
#[test]
#[serial]
fn test_add_ui_creates_missing_directories() {
let temp = TempDir::new().unwrap();
let project_path = create_test_project(&temp);
dampen_cmd()
.arg("add")
.arg("--ui")
.arg("order_form")
.arg("--path")
.arg("ui/orders/forms")
.current_dir(&project_path)
.assert()
.success();
let target_dir = project_path.join("ui/orders/forms");
assert!(target_dir.exists(), "Directory should be created");
assert!(target_dir.join("order_form.rs").exists());
assert!(target_dir.join("order_form.dampen").exists());
}
#[test]
#[serial]
fn test_add_ui_rejects_absolute_path() {
let temp = TempDir::new().unwrap();
let project_path = create_test_project(&temp);
dampen_cmd()
.arg("add")
.arg("--ui")
.arg("window")
.arg("--path")
.arg("/absolute/path")
.current_dir(&project_path)
.assert()
.failure()
.stderr(predicate::str::contains("Absolute paths are not allowed"))
.stderr(predicate::str::contains("help:"));
}
#[test]
#[serial]
fn test_add_ui_rejects_outside_project() {
let temp = TempDir::new().unwrap();
let project_path = create_test_project(&temp);
dampen_cmd()
.arg("add")
.arg("--ui")
.arg("window")
.arg("--path")
.arg("../outside")
.current_dir(&project_path)
.assert()
.failure()
.stderr(predicate::str::contains("outside the project directory"))
.stderr(predicate::str::contains("help:"));
}
#[test]
#[serial]
fn test_add_ui_error_message_helpful() {
let temp = TempDir::new().unwrap();
let project_path = create_test_project(&temp);
dampen_cmd()
.arg("add")
.arg("--ui")
.arg("orders")
.current_dir(&project_path)
.assert()
.success();
let output = dampen_cmd()
.arg("add")
.arg("--ui")
.arg("orders")
.current_dir(&project_path)
.assert()
.failure();
output
.stderr(predicate::str::contains("already exists")) .stderr(predicate::str::contains("orders")) .stderr(predicate::str::contains("orders.rs").or(predicate::str::contains("orders.dampen"))) .stderr(predicate::str::contains("help:")) .stderr(
predicate::str::contains("Choose a different name")
.or(predicate::str::contains("remove the existing file")),
); }