use std::fs;
use dotr_dear::{
cli::{
Cli, Command, DeployArgs, DiffArgs, ImportArgs, PackagesArgs, PackagesCommand,
RemovePackageArgs, UpdateArgs, run_cli,
},
config::Config,
};
mod common;
const PLAYGROUND_DIR: &str = "tests/playground";
struct TestFixture {
cwd: std::path::PathBuf,
}
impl TestFixture {
fn new() -> Self {
Self {
cwd: std::path::PathBuf::from(PLAYGROUND_DIR),
}
}
fn get_cli(&self, command: Option<Command>) -> Cli {
Cli {
command,
working_dir: Some(PLAYGROUND_DIR.to_string()),
}
}
fn init(&self) {
run_cli(self.get_cli(Some(Command::Init(dotr_dear::cli::InitArgs {}))))
.expect("Init failed");
}
fn get_config(&self) -> Config {
Config::from_path(&self.cwd).expect("Failed to load config")
}
fn create_test_file(&self, name: &str, content: &str) {
fs::create_dir_all(self.cwd.join("dotfiles")).expect("Failed to create dotfiles dir");
fs::write(self.cwd.join(format!("dotfiles/{}", name)), content)
.expect("Failed to create test file");
}
fn assert_file_exists(&self, path: &str) {
assert!(self.cwd.join(path).exists(), "File should exist: {}", path);
}
fn assert_file_not_exists(&self, path: &str) {
assert!(
!self.cwd.join(path).exists(),
"File should not exist: {}",
path
);
}
}
impl Drop for TestFixture {
fn drop(&mut self) {
common::teardown(&self.cwd);
}
}
#[test]
fn test_packages_import_subcommand() {
let fixture = TestFixture::new();
fixture.init();
fs::create_dir_all(fixture.cwd.join("src")).expect("Failed to create src dir");
fs::write(fixture.cwd.join("src/.test_import"), "test content\n")
.expect("Failed to create test file");
run_cli(fixture.get_cli(Some(Command::Packages(PackagesArgs {
profile: None,
command: Some(PackagesCommand::Import(ImportArgs {
path: "src/.test_import".to_string(),
symlink: false,
name: None,
profile: None,
})),
}))))
.expect("Packages import failed");
let config = fixture.get_config();
assert!(
config.packages.contains_key("f_test_import"),
"Package should be imported"
);
fixture.assert_file_exists("dotfiles/f_test_import");
}
#[test]
fn test_packages_deploy_subcommand() {
let fixture = TestFixture::new();
fixture.init();
fixture.create_test_file("f_deploy_test", "deploy test\n");
let mut config = fixture.get_config();
let package = dotr_dear::package::Package {
name: "f_deploy_test".to_string(),
src: "dotfiles/f_deploy_test".to_string(),
dest: "src/.deploy_test".to_string(),
..Default::default()
};
config.packages.insert("f_deploy_test".to_string(), package);
config.save(&fixture.cwd).expect("Failed to save config");
run_cli(fixture.get_cli(Some(Command::Packages(PackagesArgs {
profile: None,
command: Some(PackagesCommand::Deploy(DeployArgs {
packages: Some(vec!["f_deploy_test".to_string()]),
profile: None,
ignore_errors: false,
clean: Some(false),
dry_run: false,
..Default::default()
})),
}))))
.expect("Packages deploy failed");
fixture.assert_file_exists("src/.deploy_test");
}
#[test]
fn test_packages_update_subcommand() {
let fixture = TestFixture::new();
fixture.init();
fixture.create_test_file("f_update_test", "original content\n");
let mut config = fixture.get_config();
let package = dotr_dear::package::Package {
name: "f_update_test".to_string(),
src: "dotfiles/f_update_test".to_string(),
dest: "src/.update_test".to_string(),
..Default::default()
};
config.packages.insert("f_update_test".to_string(), package);
config.save(&fixture.cwd).expect("Failed to save config");
run_cli(fixture.get_cli(Some(Command::Deploy(DeployArgs {
packages: Some(vec!["f_update_test".to_string()]),
profile: None,
ignore_errors: false,
clean: Some(false),
dry_run: false,
..Default::default()
}))))
.expect("Deploy failed");
fs::write(fixture.cwd.join("src/.update_test"), "modified content\n")
.expect("Failed to modify file");
run_cli(fixture.get_cli(Some(Command::Packages(PackagesArgs {
profile: None,
command: Some(PackagesCommand::Update(UpdateArgs {
packages: Some(vec!["f_update_test".to_string()]),
profile: None,
ignore_errors: false,
clean: Some(false),
dry_run: false,
})),
}))))
.expect("Packages update failed");
let content = fs::read_to_string(fixture.cwd.join("dotfiles/f_update_test"))
.expect("Failed to read backup");
assert_eq!(content, "modified content\n");
}
#[test]
fn test_packages_diff_subcommand() {
let fixture = TestFixture::new();
fixture.init();
fixture.create_test_file("f_diff_test", "original content\n");
let mut config = fixture.get_config();
let package = dotr_dear::package::Package {
name: "f_diff_test".to_string(),
src: "dotfiles/f_diff_test".to_string(),
dest: "src/.diff_test".to_string(),
..Default::default()
};
config.packages.insert("f_diff_test".to_string(), package);
config.save(&fixture.cwd).expect("Failed to save config");
run_cli(fixture.get_cli(Some(Command::Deploy(DeployArgs {
packages: Some(vec!["f_diff_test".to_string()]),
profile: None,
ignore_errors: false,
clean: Some(false),
dry_run: false,
..Default::default()
}))))
.expect("Deploy failed");
fs::write(fixture.cwd.join("src/.diff_test"), "modified content\n")
.expect("Failed to modify file");
run_cli(fixture.get_cli(Some(Command::Packages(PackagesArgs {
profile: None,
command: Some(PackagesCommand::Diff(DiffArgs {
packages: Some(vec!["f_diff_test".to_string()]),
profile: None,
ignore_errors: false,
})),
}))))
.expect("Packages diff failed");
}
#[test]
fn test_packages_remove_subcommand() {
let fixture = TestFixture::new();
fixture.init();
fixture.create_test_file("f_remove_test", "remove test\n");
let mut config = fixture.get_config();
let package = dotr_dear::package::Package {
name: "f_remove_test".to_string(),
src: "dotfiles/f_remove_test".to_string(),
dest: "src/.remove_test".to_string(),
..Default::default()
};
config.packages.insert("f_remove_test".to_string(), package);
config.save(&fixture.cwd).expect("Failed to save config");
run_cli(fixture.get_cli(Some(Command::Packages(PackagesArgs {
profile: None,
command: Some(PackagesCommand::Remove(RemovePackageArgs {
packages: Some(vec!["f_remove_test".to_string()]),
force: false,
remove_orphans: false,
dry_run: false,
profile: None,
})),
}))))
.expect("Packages remove failed");
let config = fixture.get_config();
assert!(
!config.packages.contains_key("f_remove_test"),
"Package should be removed from config"
);
fixture.assert_file_not_exists("dotfiles/f_remove_test");
}
#[test]
fn test_packages_import_with_profile() {
let fixture = TestFixture::new();
fixture.init();
let mut config = fixture.get_config();
let profile = dotr_dear::profile::Profile::new("test_profile");
config.profiles.insert("test_profile".to_string(), profile);
config.save(&fixture.cwd).expect("Failed to save config");
fs::create_dir_all(fixture.cwd.join("src")).expect("Failed to create src dir");
fs::write(
fixture.cwd.join("src/.test_profile_import"),
"profile test\n",
)
.expect("Failed to create test file");
run_cli(fixture.get_cli(Some(Command::Packages(PackagesArgs {
profile: Some("test_profile".to_string()),
command: Some(PackagesCommand::Import(ImportArgs {
path: "src/.test_profile_import".to_string(),
symlink: false,
name: None,
profile: Some("test_profile".to_string()),
})),
}))))
.expect("Packages import with profile failed");
let config = fixture.get_config();
let profile = config.profiles.get("test_profile").unwrap();
assert!(
profile
.dependencies
.contains(&"f_test_profile_import".to_string()),
"Package should be added to profile dependencies"
);
}
#[test]
fn test_packages_deploy_with_profile() {
let fixture = TestFixture::new();
fixture.init();
let mut config = fixture.get_config();
let mut profile = dotr_dear::profile::Profile::new("deploy_profile");
profile.dependencies.push("f_profile_deploy".to_string());
config
.profiles
.insert("deploy_profile".to_string(), profile);
config.save(&fixture.cwd).expect("Failed to save config");
fixture.create_test_file("f_profile_deploy", "profile deploy\n");
let mut config = fixture.get_config();
let package = dotr_dear::package::Package {
name: "f_profile_deploy".to_string(),
src: "dotfiles/f_profile_deploy".to_string(),
dest: "src/.profile_deploy".to_string(),
..Default::default()
};
config
.packages
.insert("f_profile_deploy".to_string(), package);
config.save(&fixture.cwd).expect("Failed to save config");
run_cli(fixture.get_cli(Some(Command::Packages(PackagesArgs {
profile: Some("deploy_profile".to_string()),
command: Some(PackagesCommand::Deploy(DeployArgs {
packages: None, profile: Some("deploy_profile".to_string()),
ignore_errors: false,
clean: Some(false),
dry_run: false,
..Default::default()
})),
}))))
.expect("Packages deploy with profile failed");
fixture.assert_file_exists("src/.profile_deploy");
}
#[test]
fn test_packages_deploy_dry_run() {
let fixture = TestFixture::new();
fixture.init();
fixture.create_test_file("f_dryrun_test", "dry run test\n");
let mut config = fixture.get_config();
let package = dotr_dear::package::Package {
name: "f_dryrun_test".to_string(),
src: "dotfiles/f_dryrun_test".to_string(),
dest: "src/.dryrun_test".to_string(),
..Default::default()
};
config.packages.insert("f_dryrun_test".to_string(), package);
config.save(&fixture.cwd).expect("Failed to save config");
run_cli(fixture.get_cli(Some(Command::Packages(PackagesArgs {
profile: None,
command: Some(PackagesCommand::Deploy(DeployArgs {
packages: Some(vec!["f_dryrun_test".to_string()]),
profile: None,
ignore_errors: false,
clean: Some(false),
dry_run: true,
..Default::default()
})),
}))))
.expect("Packages deploy dry-run failed");
fixture.assert_file_not_exists("src/.dryrun_test");
}
#[test]
fn test_packages_update_dry_run() {
let fixture = TestFixture::new();
fixture.init();
fixture.create_test_file("f_update_dryrun", "original\n");
let mut config = fixture.get_config();
let package = dotr_dear::package::Package {
name: "f_update_dryrun".to_string(),
src: "dotfiles/f_update_dryrun".to_string(),
dest: "src/.update_dryrun".to_string(),
..Default::default()
};
config
.packages
.insert("f_update_dryrun".to_string(), package);
config.save(&fixture.cwd).expect("Failed to save config");
run_cli(fixture.get_cli(Some(Command::Deploy(DeployArgs {
packages: Some(vec!["f_update_dryrun".to_string()]),
profile: None,
ignore_errors: false,
clean: Some(false),
dry_run: false,
..Default::default()
}))))
.expect("Deploy failed");
fs::write(fixture.cwd.join("src/.update_dryrun"), "modified\n").expect("Failed to modify file");
run_cli(fixture.get_cli(Some(Command::Packages(PackagesArgs {
profile: None,
command: Some(PackagesCommand::Update(UpdateArgs {
packages: Some(vec!["f_update_dryrun".to_string()]),
profile: None,
ignore_errors: false,
clean: Some(false),
dry_run: true,
})),
}))))
.expect("Packages update dry-run failed");
let content = fs::read_to_string(fixture.cwd.join("dotfiles/f_update_dryrun"))
.expect("Failed to read backup");
assert_eq!(
content, "original\n",
"Backup should not be updated in dry-run"
);
}
#[test]
fn test_packages_multiple_packages_deploy() {
let fixture = TestFixture::new();
fixture.init();
fixture.create_test_file("f_multi1", "content1\n");
fixture.create_test_file("f_multi2", "content2\n");
fixture.create_test_file("f_multi3", "content3\n");
let mut config = fixture.get_config();
for i in 1..=3 {
let package = dotr_dear::package::Package {
name: format!("f_multi{}", i),
src: format!("dotfiles/f_multi{}", i),
dest: format!("src/.multi{}", i),
..Default::default()
};
config.packages.insert(format!("f_multi{}", i), package);
}
config.save(&fixture.cwd).expect("Failed to save config");
run_cli(fixture.get_cli(Some(Command::Packages(PackagesArgs {
profile: None,
command: Some(PackagesCommand::Deploy(DeployArgs {
packages: Some(vec![
"f_multi1".to_string(),
"f_multi2".to_string(),
"f_multi3".to_string(),
]),
profile: None,
ignore_errors: false,
clean: Some(false),
dry_run: false,
..Default::default()
})),
}))))
.expect("Packages deploy multiple failed");
fixture.assert_file_exists("src/.multi1");
fixture.assert_file_exists("src/.multi2");
fixture.assert_file_exists("src/.multi3");
}