use super::*;
#[test]
fn config_serializes_with_sections() {
let config = Config::new().with_npm(NpmConfig::enabled());
let toml_str = toml::to_string(&config.data).unwrap();
assert!(toml_str.contains("[npm]"));
assert!(toml_str.contains("enabled = true"));
}
#[test]
fn config_deserializes_with_sections() {
let config: ConfigData = toml::from_str("[npm]\nenabled = true").unwrap();
assert!(config.npm.enabled);
assert!(!config.cargo.enabled);
let config: ConfigData = toml::from_str("[cargo]\nenabled = true").unwrap();
assert!(!config.npm.enabled);
assert!(config.cargo.enabled);
}
#[tokio::test]
async fn load_fails_on_unknown_top_level_field() {
let dir = temp_dir();
let config_dir = dir.path().join(".cursus");
std::fs::create_dir_all(&config_dir).unwrap();
std::fs::write(config_dir.join("config.toml"), "[rust]\nenabled = true").unwrap();
let env = make_env_with_git(dir.path());
let err = load(env.fs(), env.git().path()).await.unwrap_err();
let chain = format!("{err:#}");
assert!(
chain.contains("unknown field"),
"Expected 'unknown field' error, got: {chain}"
);
}
#[tokio::test]
async fn load_fails_on_unknown_package_manager_field() {
let dir = temp_dir();
let config_dir = dir.path().join(".cursus");
std::fs::create_dir_all(&config_dir).unwrap();
std::fs::write(
config_dir.join("config.toml"),
"[npm]\nenabled = true\nversion = \"1.0\"",
)
.unwrap();
let env = make_env_with_git(dir.path());
let err = load(env.fs(), env.git().path()).await.unwrap_err();
let chain = format!("{err:#}");
assert!(
chain.contains("unknown field"),
"Expected 'unknown field' error, got: {chain}"
);
}
#[test]
fn deserialize_config_with_path() {
let config: ConfigData = toml::from_str("[npm]\nenabled = true\npath = \"frontend\"").unwrap();
assert!(config.npm.enabled);
assert_eq!(config.npm.path, Some("frontend".to_string()));
}
#[test]
fn deserialize_config_without_path() {
let config: ConfigData = toml::from_str("[npm]\nenabled = true").unwrap();
assert!(config.npm.enabled);
assert_eq!(config.npm.path, None);
}
#[test]
fn serialize_config_omits_none_path() {
let config = Config::new().with_npm(NpmConfig::enabled());
let toml_str = toml::to_string(&config.data).unwrap();
assert!(!toml_str.contains("path"), "None path should be omitted");
}
#[test]
fn serialize_config_includes_some_path() {
let mut config = Config::new().with_npm(NpmConfig::enabled());
config.npm.path = Some("frontend".to_string());
let toml_str = toml::to_string(&config.data).unwrap();
assert!(
toml_str.contains("path = \"frontend\""),
"Some path should be serialized, got: {toml_str}"
);
}
#[tokio::test]
async fn config_roundtrip_with_path() {
let dir = temp_dir();
let env = make_env_with_git(dir.path());
let mut config = Config::new().with_npm(NpmConfig::enabled());
config.npm.path = Some("frontend".to_string());
config.save(env.fs(), env.git().path()).await.unwrap();
let loaded = load(env.fs(), env.git().path()).await.unwrap().unwrap();
assert_eq!(loaded.npm.path, Some("frontend".to_string()));
}
#[tokio::test]
async fn config_roundtrip() {
let dir = temp_dir();
let env = make_env_with_git(dir.path());
for pm in [PackageManager::Npm, PackageManager::Cargo] {
let config = match pm {
PackageManager::Npm => Config::new().with_npm(NpmConfig::enabled()),
PackageManager::Cargo => Config::new().with_cargo(CargoConfig::enabled()),
};
config.save(env.fs(), env.git().path()).await.unwrap();
let loaded = load(env.fs(), env.git().path()).await.unwrap().unwrap();
let enabled: Vec<_> = loaded.enabled_package_managers().collect();
assert_eq!(enabled, vec![pm]);
}
}
#[test]
fn global_config_defaults_to_warnings_enabled() {
let global = GlobalConfig::default();
assert!(!global.disable_dependency_cycle_warnings);
}
#[test]
fn config_deserializes_without_global_section() {
let config: ConfigData = toml::from_str("[npm]\nenabled = true").unwrap();
assert!(config.npm.enabled);
assert!(!config.global.disable_dependency_cycle_warnings);
}
#[test]
fn config_deserializes_with_global_section() {
let toml_str = r#"
[global]
disable_dependency_cycle_warnings = true
[npm]
enabled = true
"#;
let config: ConfigData = toml::from_str(toml_str).unwrap();
assert!(config.npm.enabled);
assert!(config.global.disable_dependency_cycle_warnings);
}
#[tokio::test]
async fn config_roundtrip_with_global() {
let dir = temp_dir();
let env = make_env_with_git(dir.path());
let global = GlobalConfig {
disable_dependency_cycle_warnings: true,
..Default::default()
};
let config = Config::new()
.with_global(global)
.with_npm(NpmConfig::enabled());
config.save(env.fs(), env.git().path()).await.unwrap();
let loaded = load(env.fs(), env.git().path()).await.unwrap().unwrap();
assert!(loaded.global.disable_dependency_cycle_warnings);
}
#[tokio::test]
async fn global_config_unknown_field_fails() {
let dir = temp_dir();
let config_dir = dir.path().join(".cursus");
std::fs::create_dir_all(&config_dir).unwrap();
std::fs::write(
config_dir.join("config.toml"),
"[global]\nunknown_field = true\n[npm]\nenabled = true",
)
.unwrap();
let env = make_env_with_git(dir.path());
let err = load(env.fs(), env.git().path()).await.unwrap_err();
let chain = format!("{err:#}");
assert!(
chain.contains("unknown field"),
"Expected 'unknown field' error, got: {chain}"
);
}
#[test]
fn config_deserializes_github_section() {
let config: ConfigData =
toml::from_str("[npm]\nenabled = true\n[github]\nenabled = true").unwrap();
assert!(config.github.enabled);
}
#[test]
fn config_github_unknown_field_fails() {
let result: Result<ConfigData, _> =
toml::from_str("[npm]\nenabled = true\n[github]\nunknown = true");
assert!(
result.is_err(),
"Expected error for unknown field in [github]"
);
}
#[test]
fn config_without_github_section_defaults_disabled() {
let config: ConfigData = toml::from_str("[npm]\nenabled = true").unwrap();
assert!(!config.github.enabled);
}
#[tokio::test]
async fn load_github_enabled_derives_git_enabled() {
let dir = temp_dir();
let config_dir = dir.path().join(".cursus");
std::fs::create_dir_all(&config_dir).unwrap();
std::fs::write(
config_dir.join("config.toml"),
"[cargo]\nenabled = true\n[github]\nenabled = true\n",
)
.unwrap();
let env = make_env_with_git(dir.path());
let loaded = load(env.fs(), env.git().path()).await.unwrap().unwrap();
assert!(loaded.github.enabled);
assert!(
loaded.git.enabled(),
"git.enabled should be true when github.enabled = true"
);
}
#[tokio::test]
async fn load_explicit_git_disabled_overrides_derived_default() {
let dir = temp_dir();
let config_dir = dir.path().join(".cursus");
std::fs::create_dir_all(&config_dir).unwrap();
std::fs::write(
config_dir.join("config.toml"),
"[cargo]\nenabled = true\n[github]\nenabled = true\n[git]\nenabled = false\n",
)
.unwrap();
let env = make_env_with_git(dir.path());
let loaded = load(env.fs(), env.git().path()).await.unwrap().unwrap();
assert!(loaded.github.enabled);
assert!(
!loaded.git.enabled(),
"explicit [git].enabled = false must not be overridden"
);
}
#[tokio::test]
async fn load_derives_branch_strategy_when_github_enabled() {
let dir = temp_dir();
let config_dir = dir.path().join(".cursus");
std::fs::create_dir_all(&config_dir).unwrap();
std::fs::write(
config_dir.join("config.toml"),
"[cargo]\nenabled = true\n[github]\nenabled = true\n",
)
.unwrap();
let env = make_env_with_git(dir.path());
let loaded = load(env.fs(), env.git().path()).await.unwrap().unwrap();
assert_eq!(
loaded.git.strategy(),
Strategy::Branch,
"strategy should be derived as Branch when github.enabled = true"
);
}
#[tokio::test]
async fn load_derives_push_strategy_when_github_disabled() {
let dir = temp_dir();
let config_dir = dir.path().join(".cursus");
std::fs::create_dir_all(&config_dir).unwrap();
std::fs::write(
config_dir.join("config.toml"),
"[cargo]\nenabled = true\n[git]\nenabled = true\n",
)
.unwrap();
let env = make_env_with_git(dir.path());
let loaded = load(env.fs(), env.git().path()).await.unwrap().unwrap();
assert_eq!(
loaded.git.strategy(),
Strategy::Push,
"strategy should be derived as Push when github is not enabled"
);
}
#[tokio::test]
async fn load_explicit_strategy_overrides_derived_default() {
let dir = temp_dir();
let config_dir = dir.path().join(".cursus");
std::fs::create_dir_all(&config_dir).unwrap();
std::fs::write(
config_dir.join("config.toml"),
"[cargo]\nenabled = true\n[github]\nenabled = true\n[git]\nstrategy = \"push\"\n",
)
.unwrap();
let env = make_env_with_git(dir.path());
let loaded = load(env.fs(), env.git().path()).await.unwrap().unwrap();
assert_eq!(
loaded.git.strategy(),
Strategy::Push,
"explicit strategy must not be overridden by derivation"
);
}