diff options
Diffstat (limited to 'crates/mozart/src/commands/config.rs')
| -rw-r--r-- | crates/mozart/src/commands/config.rs | 1130 |
1 files changed, 0 insertions, 1130 deletions
diff --git a/crates/mozart/src/commands/config.rs b/crates/mozart/src/commands/config.rs index 7f4fd06..9e2e9ff 100644 --- a/crates/mozart/src/commands/config.rs +++ b/crates/mozart/src/commands/config.rs @@ -1082,1133 +1082,3 @@ fn execute_read( Ok(()) } - -#[cfg(test)] -mod tests { - use super::*; - use mozart_core::config::Config; - - #[test] - fn test_defaults_contain_expected_keys() { - let cfg = Config::default(); - - let required_keys = [ - "process-timeout", - "use-include-path", - "preferred-install", - "notify-on-install", - "github-protocols", - "vendor-dir", - "bin-dir", - "bin-compat", - "cache-dir", - "cache-files-dir", - "cache-repo-dir", - "cache-vcs-dir", - "cache-files-ttl", - "cache-files-maxsize", - "cache-read-only", - "prepend-autoloader", - "autoloader-suffix", - "optimize-autoloader", - "sort-packages", - "classmap-authoritative", - "apcu-autoloader", - "platform", - "platform-check", - "lock", - "discard-changes", - "archive-format", - "archive-dir", - "htaccess-protect", - "secure-http", - "allow-plugins", - ]; - - for key in &required_keys { - assert!(cfg.get(*key).is_some(), "defaults missing key: {key}"); - } - } - - #[test] - fn test_defaults_values_correct() { - let cfg = Config::default(); - - assert_eq!(cfg.process_timeout, 300); - assert_eq!(cfg.preferred_install, serde_json::json!("dist")); - assert_eq!(cfg.vendor_dir, "vendor"); - assert_eq!(cfg.github_protocols, vec!["https", "ssh", "git"]); - assert_eq!(cfg.secure_http, true); - assert_eq!(cfg.lock, true); - assert_eq!(cfg.autoloader_suffix, None); - } - - #[test] - fn test_merge_overrides_existing_key() { - let mut cfg = Config::default(); - - let mut overrides = BTreeMap::new(); - overrides.insert("vendor-dir".to_string(), serde_json::json!("packages")); - overrides.insert("sort-packages".to_string(), serde_json::json!(true)); - - cfg.merge(&overrides).unwrap(); - - assert_eq!(cfg.vendor_dir, "packages"); - assert_eq!(cfg.sort_packages, true); - } - - #[test] - fn test_merge_adds_new_key() { - let mut cfg = Config::default(); - - let mut overrides = BTreeMap::new(); - overrides.insert("custom-key".to_string(), serde_json::json!("custom-value")); - - cfg.merge(&overrides).unwrap(); - - assert_eq!(cfg.extra["custom-key"], serde_json::json!("custom-value")); - } - - #[test] - fn test_merge_empty_overrides_leaves_defaults_intact() { - let mut cfg = Config::default(); - let original_vendor = cfg.vendor_dir.clone(); - - cfg.merge(&BTreeMap::new()).unwrap(); - - assert_eq!(cfg.vendor_dir, original_vendor); - } - - #[test] - fn test_reference_resolution_bin_dir() { - let mut cfg = Config::default(); - // bin-dir default is "{$vendor-dir}/bin"; vendor-dir default is "vendor" - resolve_references(&mut cfg); - - assert_eq!(cfg.bin_dir, "vendor/bin"); - } - - #[test] - fn test_reference_resolution_custom_vendor_dir() { - let mut cfg = Config::default(); - - cfg.vendor_dir = "lib".to_string(); - resolve_references(&mut cfg); - - assert_eq!(cfg.bin_dir, "lib/bin"); - } - - #[test] - fn test_reference_resolution_cache_dirs() { - let mut cfg = Config::default(); - // Inject a predictable home so the test is environment-independent. - cfg.cache_dir = "/home/user/.cache/composer".to_string(); - resolve_references(&mut cfg); - - assert_eq!(cfg.cache_files_dir, "/home/user/.cache/composer/files"); - assert_eq!(cfg.cache_repo_dir, "/home/user/.cache/composer/repo"); - assert_eq!(cfg.cache_vcs_dir, "/home/user/.cache/composer/vcs"); - } - - #[test] - fn test_reference_resolution_no_change_for_non_string() { - let mut cfg = Config::default(); - let before = cfg.process_timeout; - resolve_references(&mut cfg); - assert_eq!(cfg.process_timeout, before); - } - - #[test] - fn test_get_existing_key() { - let cfg = Config::default(); - let value = cfg.get("vendor-dir"); - assert!(value.is_some()); - assert_eq!(value.unwrap(), serde_json::json!("vendor")); - } - - #[test] - fn test_get_nonexistent_key_returns_none() { - let cfg = Config::default(); - assert!(cfg.get("does-not-exist").is_none()); - } - - #[test] - fn test_render_value_string() { - assert_eq!(render_value(&serde_json::json!("hello")), "hello"); - } - - #[test] - fn test_render_value_bool() { - assert_eq!(render_value(&serde_json::json!(true)), "true"); - assert_eq!(render_value(&serde_json::json!(false)), "false"); - } - - #[test] - fn test_render_value_number() { - assert_eq!(render_value(&serde_json::json!(300)), "300"); - } - - #[test] - fn test_render_value_null() { - assert_eq!(render_value(&serde_json::Value::Null), "null"); - } - - #[test] - fn test_render_value_array() { - let v = serde_json::json!(["https", "ssh", "git"]); - assert_eq!(render_value(&v), r#"["https","ssh","git"]"#); - } - - #[test] - fn test_render_value_empty_object() { - assert_eq!(render_value(&serde_json::json!({})), "{}"); - } - - #[test] - fn test_load_config_section_absent_file() { - let path = std::path::Path::new("/tmp/nonexistent_composer_abc123.json"); - let result = load_config_section(path).unwrap(); - assert!(result.is_empty()); - } - - #[test] - fn test_load_config_section_with_config_key() { - use std::io::Write; - use tempfile::NamedTempFile; - - let mut f = NamedTempFile::new().unwrap(); - write!( - f, - r#"{{"name":"test/pkg","config":{{"sort-packages":true,"vendor-dir":"packages"}}}}"# - ) - .unwrap(); - - let result = load_config_section(f.path()).unwrap(); - assert_eq!(result.get("sort-packages"), Some(&serde_json::json!(true))); - assert_eq!( - result.get("vendor-dir"), - Some(&serde_json::json!("packages")) - ); - } - - #[test] - fn test_load_config_section_missing_config_key() { - use std::io::Write; - use tempfile::NamedTempFile; - - let mut f = NamedTempFile::new().unwrap(); - write!(f, r#"{{"name":"test/pkg","require":{{}}}}"#).unwrap(); - - let result = load_config_section(f.path()).unwrap(); - assert!(result.is_empty()); - } - - #[test] - fn test_full_pipeline_project_overrides_are_applied() { - use std::io::Write; - use tempfile::TempDir; - - let dir = TempDir::new().unwrap(); - let composer_json = dir.path().join("composer.json"); - let mut f = std::fs::File::create(&composer_json).unwrap(); - write!( - f, - r#"{{"name":"test/pkg","config":{{"vendor-dir":"custom_vendor","sort-packages":true}}}}"# - ) - .unwrap(); - - let overrides = load_config_section(&composer_json).unwrap(); - let mut cfg = Config::default(); - cfg.merge(&overrides).unwrap(); - resolve_references(&mut cfg); - - assert_eq!(cfg.vendor_dir, "custom_vendor"); - assert_eq!(cfg.sort_packages, true); - // bin-dir should have resolved against the overridden vendor-dir - assert_eq!(cfg.bin_dir, "custom_vendor/bin"); - } - - #[test] - fn test_match_repository_key_full() { - assert_eq!(match_repository_key("repositories.foo"), Some("foo")); - assert_eq!(match_repository_key("repos.foo"), Some("foo")); - assert_eq!(match_repository_key("repo.foo"), Some("foo")); - } - - #[test] - fn test_match_repository_key_no_match() { - assert_eq!(match_repository_key("vendor-dir"), None); - assert_eq!(match_repository_key("repositories."), None); - assert_eq!(match_repository_key("sort-packages"), None); - } - - #[test] - fn test_json_set_nested_simple() { - let mut root = serde_json::json!({}); - json_set_nested(&mut root, "foo", serde_json::json!("bar")); - assert_eq!(root["foo"], serde_json::json!("bar")); - } - - #[test] - fn test_json_set_nested_deep() { - let mut root = serde_json::json!({}); - json_set_nested(&mut root, "extra.foo.bar", serde_json::json!(42)); - assert_eq!(root["extra"]["foo"]["bar"], serde_json::json!(42)); - } - - #[test] - fn test_json_set_nested_overwrites() { - let mut root = serde_json::json!({"config": {"sort-packages": false}}); - json_set_nested(&mut root, "config.sort-packages", serde_json::json!(true)); - assert_eq!(root["config"]["sort-packages"], serde_json::json!(true)); - } - - #[test] - fn test_json_remove_nested_simple() { - let mut root = serde_json::json!({"foo": "bar"}); - let removed = json_remove_nested(&mut root, "foo"); - assert!(removed); - assert!(root.get("foo").is_none()); - } - - #[test] - fn test_json_remove_nested_deep() { - let mut root = serde_json::json!({"config": {"sort-packages": true}}); - let removed = json_remove_nested(&mut root, "config.sort-packages"); - assert!(removed); - assert!(root["config"].get("sort-packages").is_none()); - } - - #[test] - fn test_json_remove_nested_nonexistent() { - let mut root = serde_json::json!({"foo": "bar"}); - let removed = json_remove_nested(&mut root, "nonexistent"); - assert!(!removed); - } - - #[test] - fn test_validate_bool_true() { - let result = validate_and_normalize("sort-packages", "true", &ConfigValueType::Bool); - assert_eq!(result.unwrap(), serde_json::json!(true)); - } - - #[test] - fn test_validate_bool_false() { - let result = validate_and_normalize("sort-packages", "0", &ConfigValueType::Bool); - assert_eq!(result.unwrap(), serde_json::json!(false)); - } - - #[test] - fn test_validate_invalid_bool() { - let result = validate_and_normalize("sort-packages", "maybe", &ConfigValueType::Bool); - assert!(result.is_err()); - } - - #[test] - fn test_validate_integer() { - let result = validate_and_normalize("process-timeout", "600", &ConfigValueType::Integer); - assert_eq!(result.unwrap(), serde_json::json!(600)); - } - - #[test] - fn test_validate_invalid_integer() { - let result = validate_and_normalize("process-timeout", "abc", &ConfigValueType::Integer); - assert!(result.is_err()); - } - - #[test] - fn test_validate_enum_valid() { - let result = validate_and_normalize( - "preferred-install", - "source", - &ConfigValueType::Enum(&["auto", "source", "dist"]), - ); - assert_eq!(result.unwrap(), serde_json::json!("source")); - } - - #[test] - fn test_validate_enum_invalid() { - let result = validate_and_normalize( - "preferred-install", - "invalid", - &ConfigValueType::Enum(&["auto", "source", "dist"]), - ); - assert!(result.is_err()); - } - - #[test] - fn test_validate_bool_or_enum_stash() { - let result = validate_and_normalize( - "discard-changes", - "stash", - &ConfigValueType::BoolOrEnum(&["stash"]), - ); - assert_eq!(result.unwrap(), serde_json::json!("stash")); - } - - #[test] - fn test_validate_bool_or_enum_bool() { - let result = validate_and_normalize( - "discard-changes", - "true", - &ConfigValueType::BoolOrEnum(&["stash"]), - ); - assert_eq!(result.unwrap(), serde_json::json!(true)); - } - - #[test] - fn test_validate_autoloader_suffix_null() { - let result = validate_and_normalize("autoloader-suffix", "null", &ConfigValueType::Str); - assert_eq!(result.unwrap(), serde_json::Value::Null); - } - - #[test] - fn test_validate_multi_string_array() { - let values = vec!["a".to_string(), "b".to_string()]; - let result = - validate_and_normalize_multi("github-domains", &values, &ConfigValueType::StringArray); - assert_eq!(result.unwrap(), serde_json::json!(["a", "b"])); - } - - #[test] - fn test_validate_multi_enum_array_valid() { - let values = vec!["https".to_string(), "ssh".to_string()]; - let result = validate_and_normalize_multi( - "github-protocols", - &values, - &ConfigValueType::EnumArray(&["git", "https", "ssh"]), - ); - assert_eq!(result.unwrap(), serde_json::json!(["https", "ssh"])); - } - - #[test] - fn test_validate_multi_enum_array_invalid() { - let values = vec!["https".to_string(), "ftp".to_string()]; - let result = validate_and_normalize_multi( - "github-protocols", - &values, - &ConfigValueType::EnumArray(&["git", "https", "ssh"]), - ); - assert!(result.is_err()); - } - - fn make_empty_json() -> serde_json::Value { - serde_json::json!({}) - } - - fn make_config_args_default() -> ConfigArgs { - ConfigArgs { - setting_key: None, - setting_value: vec![], - global: false, - editor: false, - auth: false, - unset: false, - list: false, - file: None, - absolute: false, - json: false, - merge: false, - append: false, - source: false, - } - } - - #[test] - fn test_set_bool_config_value() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set(&mut json, "sort-packages", &["true".to_string()], &args).unwrap(); - assert_eq!(json["config"]["sort-packages"], serde_json::json!(true)); - } - - #[test] - fn test_set_integer_config_value() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set(&mut json, "process-timeout", &["600".to_string()], &args).unwrap(); - assert_eq!(json["config"]["process-timeout"], serde_json::json!(600)); - } - - #[test] - fn test_set_string_config_value() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set(&mut json, "vendor-dir", &["lib".to_string()], &args).unwrap(); - assert_eq!(json["config"]["vendor-dir"], serde_json::json!("lib")); - } - - #[test] - fn test_set_enum_config_value() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set( - &mut json, - "preferred-install", - &["source".to_string()], - &args, - ) - .unwrap(); - assert_eq!( - json["config"]["preferred-install"], - serde_json::json!("source") - ); - } - - #[test] - fn test_set_bool_or_enum_stash() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set(&mut json, "discard-changes", &["stash".to_string()], &args).unwrap(); - assert_eq!( - json["config"]["discard-changes"], - serde_json::json!("stash") - ); - } - - #[test] - fn test_set_bool_or_enum_bool() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set(&mut json, "discard-changes", &["true".to_string()], &args).unwrap(); - assert_eq!(json["config"]["discard-changes"], serde_json::json!(true)); - } - - #[test] - fn test_set_multi_value() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set( - &mut json, - "github-protocols", - &["https".to_string(), "ssh".to_string()], - &args, - ) - .unwrap(); - assert_eq!( - json["config"]["github-protocols"], - serde_json::json!(["https", "ssh"]) - ); - } - - #[test] - fn test_set_invalid_bool_value() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - let result = execute_set(&mut json, "sort-packages", &["maybe".to_string()], &args); - assert!(result.is_err()); - } - - #[test] - fn test_set_invalid_enum_value() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - let result = execute_set( - &mut json, - "preferred-install", - &["invalid".to_string()], - &args, - ); - assert!(result.is_err()); - } - - #[test] - fn test_set_too_many_values() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - let result = execute_set( - &mut json, - "sort-packages", - &["true".to_string(), "false".to_string()], - &args, - ); - assert!(result.is_err()); - } - - #[test] - fn test_unset_config_value() { - let mut json = serde_json::json!({"config": {"sort-packages": true}}); - let args = make_config_args_default(); - execute_unset(&mut json, "sort-packages", &args).unwrap(); - assert!(json["config"].get("sort-packages").is_none()); - } - - #[test] - fn test_unset_nonexistent_key() { - // A4: unknown top-level single-segment key is silently removed (mirrors Composer 920-924) - let mut json = make_empty_json(); - let args = make_config_args_default(); - let result = execute_unset(&mut json, "unknown-key-xyz", &args); - assert!(result.is_ok()); - } - - #[test] - fn test_set_package_property_name() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set(&mut json, "name", &["vendor/pkg".to_string()], &args).unwrap(); - assert_eq!(json["name"], serde_json::json!("vendor/pkg")); - } - - #[test] - fn test_set_minimum_stability() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set(&mut json, "minimum-stability", &["dev".to_string()], &args).unwrap(); - assert_eq!(json["minimum-stability"], serde_json::json!("dev")); - } - - #[test] - fn test_set_prefer_stable() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set(&mut json, "prefer-stable", &["true".to_string()], &args).unwrap(); - assert_eq!(json["prefer-stable"], serde_json::json!(true)); - } - - #[test] - fn test_set_keywords() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set( - &mut json, - "keywords", - &["php".to_string(), "cli".to_string(), "tool".to_string()], - &args, - ) - .unwrap(); - assert_eq!(json["keywords"], serde_json::json!(["php", "cli", "tool"])); - } - - #[test] - fn test_set_package_property_global_error() { - let mut json = make_empty_json(); - let mut args = make_config_args_default(); - args.global = true; - let result = execute_set(&mut json, "name", &["vendor/pkg".to_string()], &args); - assert!(result.is_err()); - } - - #[test] - fn test_unset_package_property() { - let mut json = serde_json::json!({"description": "A test package"}); - let args = make_config_args_default(); - execute_unset(&mut json, "description", &args).unwrap(); - assert!(json.get("description").is_none()); - } - - #[test] - fn test_add_repository() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set( - &mut json, - "repositories.foo", - &["vcs".to_string(), "https://bar.com".to_string()], - &args, - ) - .unwrap(); - - let repos = json["repositories"].as_array().unwrap(); - assert_eq!(repos.len(), 1); - assert_eq!(repos[0]["name"], serde_json::json!("foo")); - assert_eq!(repos[0]["type"], serde_json::json!("vcs")); - assert_eq!(repos[0]["url"], serde_json::json!("https://bar.com")); - } - - #[test] - fn test_add_repository_prepend() { - let mut json = serde_json::json!({ - "repositories": [{"name": "existing", "type": "vcs", "url": "https://existing.com"}] - }); - let args = make_config_args_default(); - execute_set( - &mut json, - "repositories.new", - &["vcs".to_string(), "https://new.com".to_string()], - &args, - ) - .unwrap(); - - let repos = json["repositories"].as_array().unwrap(); - assert_eq!(repos[0]["name"], serde_json::json!("new")); - assert_eq!(repos[1]["name"], serde_json::json!("existing")); - } - - #[test] - fn test_add_repository_append() { - let mut json = serde_json::json!({ - "repositories": [{"name": "existing", "type": "vcs", "url": "https://existing.com"}] - }); - let mut args = make_config_args_default(); - args.append = true; - execute_set( - &mut json, - "repositories.new", - &["vcs".to_string(), "https://new.com".to_string()], - &args, - ) - .unwrap(); - - let repos = json["repositories"].as_array().unwrap(); - assert_eq!(repos[0]["name"], serde_json::json!("existing")); - assert_eq!(repos[1]["name"], serde_json::json!("new")); - } - - #[test] - fn test_add_repository_replace_existing() { - let mut json = serde_json::json!({ - "repositories": [{"name": "foo", "type": "vcs", "url": "https://old.com"}] - }); - let args = make_config_args_default(); - execute_set( - &mut json, - "repositories.foo", - &["vcs".to_string(), "https://new.com".to_string()], - &args, - ) - .unwrap(); - - let repos = json["repositories"].as_array().unwrap(); - assert_eq!(repos.len(), 1); - assert_eq!(repos[0]["url"], serde_json::json!("https://new.com")); - } - - #[test] - fn test_disable_repository() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set( - &mut json, - "repositories.packagist.org", - &["false".to_string()], - &args, - ) - .unwrap(); - - let repos = json["repositories"].as_array().unwrap(); - assert_eq!(repos.len(), 1); - assert_eq!(repos[0]["packagist.org"], serde_json::json!(false)); - } - - #[test] - fn test_remove_repository() { - let mut json = serde_json::json!({ - "repositories": [{"name": "foo", "type": "vcs", "url": "https://bar.com"}] - }); - let args = make_config_args_default(); - execute_unset(&mut json, "repo.foo", &args).unwrap(); - - // Array removed when empty - assert!(json.get("repositories").is_none()); - } - - #[test] - fn test_repo_alias() { - assert_eq!(match_repository_key("repo.foo"), Some("foo")); - assert_eq!(match_repository_key("repos.foo"), Some("foo")); - assert_eq!(match_repository_key("repositories.foo"), Some("foo")); - } - - #[test] - fn test_set_extra_property() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set(&mut json, "extra.key", &["value".to_string()], &args).unwrap(); - assert_eq!(json["extra"]["key"], serde_json::json!("value")); - } - - #[test] - fn test_set_extra_json() { - let mut json = make_empty_json(); - let mut args = make_config_args_default(); - args.json = true; - execute_set(&mut json, "extra.key", &[r#"{"a":1}"#.to_string()], &args).unwrap(); - assert_eq!(json["extra"]["key"], serde_json::json!({"a": 1})); - } - - #[test] - fn test_set_extra_merge_objects() { - let mut json = serde_json::json!({"extra": {"key": {"x": 1}}}); - let mut args = make_config_args_default(); - args.json = true; - args.merge = true; - execute_set(&mut json, "extra.key", &[r#"{"y":2}"#.to_string()], &args).unwrap(); - assert_eq!(json["extra"]["key"]["x"], serde_json::json!(1)); - assert_eq!(json["extra"]["key"]["y"], serde_json::json!(2)); - } - - #[test] - fn test_set_extra_merge_arrays() { - let mut json = serde_json::json!({"extra": {"key": [1, 2]}}); - let mut args = make_config_args_default(); - args.json = true; - args.merge = true; - execute_set(&mut json, "extra.key", &["[3, 4]".to_string()], &args).unwrap(); - assert_eq!(json["extra"]["key"], serde_json::json!([1, 2, 3, 4])); - } - - #[test] - fn test_set_suggest() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set( - &mut json, - "suggest.vendor/pkg", - &["for".to_string(), "testing".to_string()], - &args, - ) - .unwrap(); - assert_eq!( - json["suggest"]["vendor/pkg"], - serde_json::json!("for testing") - ); - } - - #[test] - fn test_unset_extra() { - let mut json = serde_json::json!({"extra": {"key": "value"}}); - let args = make_config_args_default(); - execute_unset(&mut json, "extra.key", &args).unwrap(); - assert!(json["extra"].get("key").is_none()); - } - - #[test] - fn test_set_platform_php() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set(&mut json, "platform.php", &["8.1.0".to_string()], &args).unwrap(); - assert_eq!( - json["config"]["platform"]["php"], - serde_json::json!("8.1.0") - ); - } - - #[test] - fn test_unset_platform_php() { - let mut json = serde_json::json!({"config": {"platform": {"php": "8.1.0"}}}); - let args = make_config_args_default(); - execute_unset(&mut json, "platform.php", &args).unwrap(); - assert!(json["config"]["platform"].get("php").is_none()); - } - - #[test] - fn test_set_preferred_install_per_package() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set( - &mut json, - "preferred-install.vendor/*", - &["source".to_string()], - &args, - ) - .unwrap(); - assert_eq!( - json["config"]["preferred-install"]["vendor/*"], - serde_json::json!("source") - ); - } - - #[test] - fn test_set_allow_plugins() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set( - &mut json, - "allow-plugins.vendor/plugin", - &["true".to_string()], - &args, - ) - .unwrap(); - assert_eq!( - json["config"]["allow-plugins"]["vendor/plugin"], - serde_json::json!(true) - ); - } - - #[test] - fn test_global_config_creates_file() { - use tempfile::TempDir; - - let dir = TempDir::new().unwrap(); - let config_file = dir.path().join("config.json"); - - // Start from an empty/nonexistent file - let mut json = read_json_file(&config_file, true).unwrap(); - let args = make_config_args_default(); - execute_set(&mut json, "sort-packages", &["true".to_string()], &args).unwrap(); - write_json_file(&config_file, &json).unwrap(); - - assert!(config_file.exists()); - let written: serde_json::Value = - serde_json::from_str(&std::fs::read_to_string(&config_file).unwrap()).unwrap(); - assert_eq!(written["config"]["sort-packages"], serde_json::json!(true)); - } - - #[test] - fn test_global_config_set_and_read() { - use tempfile::TempDir; - - let dir = TempDir::new().unwrap(); - let config_file = dir.path().join("config.json"); - - // Write - let mut json = read_json_file(&config_file, true).unwrap(); - let args = make_config_args_default(); - execute_set(&mut json, "vendor-dir", &["custom-lib".to_string()], &args).unwrap(); - write_json_file(&config_file, &json).unwrap(); - - // Read back - let json2 = read_json_file(&config_file, true).unwrap(); - assert_eq!( - json2["config"]["vendor-dir"], - serde_json::json!("custom-lib") - ); - } - - #[test] - fn test_read_json_file_missing_global() { - let path = std::path::Path::new("/tmp/nonexistent_global_abc123.json"); - let v = read_json_file(path, true).unwrap(); - assert!(v["config"].is_object()); - } - - #[test] - fn test_read_json_file_missing_local() { - let path = std::path::Path::new("/tmp/nonexistent_local_abc123.json"); - let v = read_json_file(path, false).unwrap(); - assert!(v.is_object()); - assert!(v.get("config").is_none()); - } - - // --- A2: audit.ignore / audit.ignore-abandoned --- - - #[test] - fn test_set_audit_ignore_simple() { - let mut json = make_empty_json(); - let mut args = make_config_args_default(); - args.json = true; - execute_set( - &mut json, - "audit.ignore", - &[r#"["CVE-2024-AAAA"]"#.to_string()], - &args, - ) - .unwrap(); - assert_eq!( - json["config"]["audit"]["ignore"], - serde_json::json!(["CVE-2024-AAAA"]) - ); - } - - #[test] - fn test_set_audit_ignore_merge_arrays() { - let mut json = serde_json::json!({"config": {"audit": {"ignore": ["CVE-2024-AAAA"]}}}); - let mut args = make_config_args_default(); - args.json = true; - args.merge = true; - execute_set( - &mut json, - "audit.ignore", - &[r#"["CVE-2024-XXXX"]"#.to_string()], - &args, - ) - .unwrap(); - assert_eq!( - json["config"]["audit"]["ignore"], - serde_json::json!(["CVE-2024-AAAA", "CVE-2024-XXXX"]) - ); - } - - #[test] - fn test_set_audit_ignore_merge_list_object_error() { - let mut json = serde_json::json!({"config": {"audit": {"ignore": ["CVE-2024-AAAA"]}}}); - let mut args = make_config_args_default(); - args.json = true; - args.merge = true; - let result = execute_set( - &mut json, - "audit.ignore", - &[r#"{"pkg/name": "reason"}"#.to_string()], - &args, - ); - assert!(result.is_err()); - } - - // --- A3: scripts.X --- - - #[test] - fn test_set_scripts_single() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set( - &mut json, - "scripts.post-install-cmd", - &["echo done".to_string()], - &args, - ) - .unwrap(); - assert_eq!( - json["scripts"]["post-install-cmd"], - serde_json::json!("echo done") - ); - } - - #[test] - fn test_set_scripts_multi() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - execute_set( - &mut json, - "scripts.post-install-cmd", - &["echo a".to_string(), "echo b".to_string()], - &args, - ) - .unwrap(); - assert_eq!( - json["scripts"]["post-install-cmd"], - serde_json::json!(["echo a", "echo b"]) - ); - } - - #[test] - fn test_unset_scripts() { - let mut json = serde_json::json!({"scripts": {"post-install-cmd": "echo done"}}); - let args = make_config_args_default(); - execute_unset(&mut json, "scripts.post-install-cmd", &args).unwrap(); - assert!(json["scripts"].get("post-install-cmd").is_none()); - } - - // --- A4: top-level --unset fallback --- - - #[test] - fn test_unset_unknown_top_level_key_succeeds() { - let mut json = serde_json::json!({"my-custom-field": "value"}); - let args = make_config_args_default(); - execute_unset(&mut json, "my-custom-field", &args).unwrap(); - assert!(json.get("my-custom-field").is_none()); - } - - // --- A5: bare extra / suggest / audit --- - - #[test] - fn test_unset_extra_bare() { - let mut json = serde_json::json!({"extra": {"key": "value"}}); - let args = make_config_args_default(); - execute_unset(&mut json, "extra", &args).unwrap(); - assert!(json.get("extra").is_none()); - } - - #[test] - fn test_unset_suggest_bare() { - let mut json = serde_json::json!({"suggest": {"vendor/pkg": "reason"}}); - let args = make_config_args_default(); - execute_unset(&mut json, "suggest", &args).unwrap(); - assert!(json.get("suggest").is_none()); - } - - #[test] - fn test_unset_audit_bare() { - let mut json = serde_json::json!({"config": {"audit": {"abandoned": "report"}}}); - let args = make_config_args_default(); - execute_unset(&mut json, "audit", &args).unwrap(); - assert!(json["config"].get("audit").is_none()); - } - - // --- A10: cache-files-maxsize validation --- - - #[test] - fn test_cache_files_maxsize_valid() { - for v in &["512M", "512MB", "512MiB", "1g", "1GiB", "100", "1.5k"] { - let result = - validate_and_normalize("cache-files-maxsize", v, &ConfigValueType::SizeString); - assert!(result.is_ok(), "expected ok for {v}"); - } - } - - #[test] - fn test_cache_files_maxsize_invalid() { - let result = - validate_and_normalize("cache-files-maxsize", "abc", &ConfigValueType::SizeString); - assert!(result.is_err()); - } - - // --- A14: merge_json_values existing-wins --- - - #[test] - fn test_merge_objects_existing_wins() { - // Composer PHP `+` semantics: existing keys take precedence - let existing = serde_json::json!({"a": 1, "b": 2}); - let new_val = serde_json::json!({"a": 99, "c": 3}); - let result = merge_json_values(Some(&existing), &new_val).unwrap(); - assert_eq!(result["a"], serde_json::json!(1)); // existing wins - assert_eq!(result["b"], serde_json::json!(2)); - assert_eq!(result["c"], serde_json::json!(3)); // new key added - } - - // --- A11: cafile / capath null clearing --- - - #[test] - fn test_cafile_null_clears() { - let result = validate_and_normalize("cafile", "null", &ConfigValueType::FilePath); - assert_eq!(result.unwrap(), serde_json::Value::Null); - } - - #[test] - fn test_capath_null_clears() { - let result = validate_and_normalize("capath", "null", &ConfigValueType::DirPath); - assert_eq!(result.unwrap(), serde_json::Value::Null); - } - - // --- A16: repositories.<name>.url --- - - #[test] - fn test_set_repository_url() { - let mut json = serde_json::json!({ - "repositories": [{"name": "foo", "type": "vcs", "url": "https://old.com"}] - }); - let args = make_config_args_default(); - execute_set( - &mut json, - "repositories.foo.url", - &["https://new.com".to_string()], - &args, - ) - .unwrap(); - assert_eq!( - json["repositories"][0]["url"], - serde_json::json!("https://new.com") - ); - } - - #[test] - fn test_set_repository_url_not_found() { - let mut json = serde_json::json!({"repositories": []}); - let args = make_config_args_default(); - let result = execute_set( - &mut json, - "repositories.nonexistent.url", - &["https://x.com".to_string()], - &args, - ); - assert!(result.is_err()); - } - - // --- A19: add_repository with name injection and assoc-form normalization --- - - #[test] - fn test_add_repository_injects_name() { - let mut json = make_empty_json(); - let args = make_config_args_default(); - // Passing config without "name" field - execute_set( - &mut json, - "repositories.myrepo", - &["vcs".to_string(), "https://example.com".to_string()], - &args, - ) - .unwrap(); - let repos = json["repositories"].as_array().unwrap(); - assert_eq!(repos[0]["name"], serde_json::json!("myrepo")); - } -} |
