mod common;
use anyhow::Result;
use common::TestEnv;
use dotstate::services::SyncService;
#[test]
fn e2e_add_file_creates_symlink_and_tracks() -> Result<()> {
let env = TestEnv::new()
.with_profile("default")
.with_activated_profile("default")
.with_home_file(".zshrc", "# my zshrc config")
.with_env_override()
.build()?;
env.assert_home_regular_file(".zshrc");
env.assert_file_not_tracked(".zshrc");
let config = env.load_config()?;
let full_path = env.home_path(".zshrc");
let result = SyncService::add_file_to_sync(&config, &full_path, ".zshrc", false)?;
assert!(
matches!(
result,
dotstate::services::sync_service::AddFileResult::Success
),
"Expected Success, got {:?}",
result
);
env.assert_is_symlink(".zshrc");
env.assert_file_tracked(".zshrc");
env.assert_file_in_profile("default", ".zshrc");
assert_eq!(
env.home_file_content(".zshrc"),
Some("# my zshrc config".to_string())
);
let repo_file = env.profile_file_path("default", ".zshrc");
assert!(repo_file.exists(), "File should exist in repo");
Ok(())
}
#[test]
fn e2e_add_file_with_nested_path() -> Result<()> {
let env = TestEnv::new()
.with_profile("default")
.with_activated_profile("default")
.with_home_file(".config/app/settings.toml", "[settings]\nvalue = 42")
.with_env_override()
.build()?;
let config = env.load_config()?;
let full_path = env.home_path(".config/app/settings.toml");
let result =
SyncService::add_file_to_sync(&config, &full_path, ".config/app/settings.toml", false)?;
assert!(matches!(
result,
dotstate::services::sync_service::AddFileResult::Success
));
env.assert_is_symlink(".config/app/settings.toml");
env.assert_file_tracked(".config/app/settings.toml");
let repo_file = env.profile_file_path("default", ".config/app/settings.toml");
assert!(repo_file.exists());
Ok(())
}
#[test]
fn e2e_add_file_already_synced_returns_already_synced() -> Result<()> {
let env = TestEnv::new()
.with_profile("default")
.with_activated_profile("default")
.with_synced_file("default", ".bashrc", "bash config")
.with_env_override()
.build()?;
let config = env.load_config()?;
let full_path = env.home_path(".bashrc");
let result = SyncService::add_file_to_sync(&config, &full_path, ".bashrc", false)?;
assert!(
matches!(
result,
dotstate::services::sync_service::AddFileResult::AlreadySynced
),
"Expected AlreadySynced, got {:?}",
result
);
Ok(())
}
#[test]
fn e2e_add_nonexistent_file_returns_validation_failed() -> Result<()> {
let env = TestEnv::new()
.with_profile("default")
.with_activated_profile("default")
.with_env_override()
.build()?;
let config = env.load_config()?;
let full_path = env.home_path(".nonexistent");
let result = SyncService::add_file_to_sync(&config, &full_path, ".nonexistent", false)?;
assert!(
matches!(
result,
dotstate::services::sync_service::AddFileResult::ValidationFailed(_)
),
"Expected ValidationFailed, got {:?}",
result
);
Ok(())
}
#[test]
fn e2e_remove_file_restores_and_untracks() -> Result<()> {
let env = TestEnv::new()
.with_profile("default")
.with_activated_profile("default")
.with_synced_file("default", ".zshrc", "original content")
.with_env_override()
.build()?;
env.assert_is_symlink(".zshrc");
env.assert_file_tracked(".zshrc");
let config = env.load_config()?;
let result = SyncService::remove_file_from_sync(&config, ".zshrc")?;
assert!(
matches!(
result,
dotstate::services::sync_service::RemoveFileResult::Success
),
"Expected Success, got {:?}",
result
);
env.assert_no_symlink(".zshrc");
env.assert_home_regular_file(".zshrc");
assert_eq!(
env.home_file_content(".zshrc"),
Some("original content".to_string())
);
env.assert_file_not_tracked(".zshrc");
env.assert_file_not_in_profile("default", ".zshrc");
Ok(())
}
#[test]
fn e2e_remove_not_synced_file_returns_not_synced() -> Result<()> {
let env = TestEnv::new()
.with_profile("default")
.with_activated_profile("default")
.with_env_override()
.build()?;
let config = env.load_config()?;
let result = SyncService::remove_file_from_sync(&config, ".nonexistent")?;
assert!(
matches!(
result,
dotstate::services::sync_service::RemoveFileResult::NotSynced
),
"Expected NotSynced, got {:?}",
result
);
Ok(())
}
#[test]
fn e2e_add_then_remove_then_add_again() -> Result<()> {
let env = TestEnv::new()
.with_profile("default")
.with_activated_profile("default")
.with_home_file(".testrc", "test content v1")
.with_env_override()
.build()?;
let config = env.load_config()?;
let full_path = env.home_path(".testrc");
let result = SyncService::add_file_to_sync(&config, &full_path, ".testrc", false)?;
assert!(matches!(
result,
dotstate::services::sync_service::AddFileResult::Success
));
env.assert_is_symlink(".testrc");
env.assert_file_tracked(".testrc");
let result = SyncService::remove_file_from_sync(&config, ".testrc")?;
assert!(matches!(
result,
dotstate::services::sync_service::RemoveFileResult::Success
));
env.assert_no_symlink(".testrc");
env.assert_file_not_tracked(".testrc");
let result = SyncService::add_file_to_sync(&config, &full_path, ".testrc", false)?;
assert!(matches!(
result,
dotstate::services::sync_service::AddFileResult::Success
));
env.assert_is_symlink(".testrc");
env.assert_file_tracked(".testrc");
Ok(())
}
#[test]
fn e2e_add_multiple_files() -> Result<()> {
let env = TestEnv::new()
.with_profile("default")
.with_activated_profile("default")
.with_home_file(".file1", "content 1")
.with_home_file(".file2", "content 2")
.with_home_file(".file3", "content 3")
.with_env_override()
.build()?;
let config = env.load_config()?;
for name in &[".file1", ".file2", ".file3"] {
let full_path = env.home_path(name);
let result = SyncService::add_file_to_sync(&config, &full_path, name, false)?;
assert!(
matches!(
result,
dotstate::services::sync_service::AddFileResult::Success
),
"Failed to add {}",
name
);
}
for name in &[".file1", ".file2", ".file3"] {
env.assert_is_symlink(name);
env.assert_file_tracked(name);
env.assert_file_in_profile("default", name);
}
Ok(())
}