aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/mozart/src/commands/remove.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/mozart/src/commands/remove.rs')
-rw-r--r--crates/mozart/src/commands/remove.rs449
1 files changed, 0 insertions, 449 deletions
diff --git a/crates/mozart/src/commands/remove.rs b/crates/mozart/src/commands/remove.rs
index 938a5d1..c5b9ba7 100644
--- a/crates/mozart/src/commands/remove.rs
+++ b/crates/mozart/src/commands/remove.rs
@@ -676,452 +676,3 @@ async fn remove_unused(
Ok(())
}
-
-#[cfg(test)]
-mod tests {
- use super::*;
- use mozart_core::package::RawPackageData;
- use mozart_core::repository::lockfile;
-
- fn make_locked_package(name: &str, version: &str) -> lockfile::LockedPackage {
- lockfile::LockedPackage {
- name: name.to_string(),
- version: version.to_string(),
- version_normalized: Some(format!("{}.0", version)),
- source: None,
- dist: None,
- require: indexmap::IndexMap::new(),
- require_dev: indexmap::IndexMap::new(),
- conflict: indexmap::IndexMap::new(),
- provide: indexmap::IndexMap::new(),
- replace: indexmap::IndexMap::new(),
- suggest: None,
- package_type: Some("library".to_string()),
- autoload: None,
- autoload_dev: None,
- license: None,
- description: None,
- homepage: None,
- keywords: None,
- authors: None,
- support: None,
- funding: None,
- time: None,
- extra_fields: indexmap::IndexMap::new(),
- }
- }
-
- fn minimal_lock(packages: Vec<lockfile::LockedPackage>) -> lockfile::LockFile {
- lockfile::LockFile {
- readme: lockfile::LockFile::default_readme(),
- content_hash: "abc123".to_string(),
- packages,
- packages_dev: Some(vec![]),
- aliases: vec![],
- minimum_stability: "stable".to_string(),
- stability_flags: serde_json::json!({}),
- prefer_stable: false,
- prefer_lowest: false,
- platform: serde_json::json!({}),
- platform_dev: serde_json::json!({}),
- plugin_api_version: Some("2.6.0".to_string()),
- }
- }
-
- fn make_raw_package(name: &str) -> RawPackageData {
- RawPackageData::new(name.to_string())
- }
-
- /// Remove a package from `require`, verify it's gone from `RawPackageData`.
- #[test]
- fn test_remove_from_require() {
- let mut composer = make_raw_package("test/project");
- composer
- .require
- .insert("psr/log".to_string(), "^3.0".to_string());
- composer
- .require
- .insert("monolog/monolog".to_string(), "^3.0".to_string());
-
- assert!(composer.require.contains_key("psr/log"));
-
- composer.require.shift_remove("psr/log");
-
- assert!(
- !composer.require.contains_key("psr/log"),
- "psr/log should be removed from require"
- );
- assert!(
- composer.require.contains_key("monolog/monolog"),
- "monolog/monolog should remain in require"
- );
- }
-
- /// Remove a package from `require-dev` with `--dev` flag.
- #[test]
- fn test_remove_from_require_dev() {
- let mut composer = make_raw_package("test/project");
- composer
- .require_dev
- .insert("phpunit/phpunit".to_string(), "^11.0".to_string());
- composer
- .require_dev
- .insert("mockery/mockery".to_string(), "^1.0".to_string());
-
- assert!(composer.require_dev.contains_key("phpunit/phpunit"));
-
- composer.require_dev.shift_remove("phpunit/phpunit");
-
- assert!(
- !composer.require_dev.contains_key("phpunit/phpunit"),
- "phpunit/phpunit should be removed from require-dev"
- );
- assert!(
- composer.require_dev.contains_key("mockery/mockery"),
- "mockery/mockery should remain in require-dev"
- );
- }
-
- /// Removing a package not in either section does not panic and doesn't change anything.
- #[test]
- fn test_remove_nonexistent_package_no_panic() {
- let mut composer = make_raw_package("test/project");
- composer
- .require
- .insert("psr/log".to_string(), "^3.0".to_string());
-
- let name = "nonexistent/package";
- let found_in_require = composer.require.shift_remove(name).is_some();
- let found_in_require_dev = composer.require_dev.shift_remove(name).is_some();
-
- assert!(!found_in_require);
- assert!(!found_in_require_dev);
-
- assert_eq!(composer.require.len(), 1);
- assert!(composer.require.contains_key("psr/log"));
- }
-
- /// Without `--dev`, auto-detect finds the package in whichever section contains it.
- #[test]
- fn test_remove_auto_detects_section_require() {
- let mut composer = make_raw_package("test/project");
- composer
- .require
- .insert("psr/log".to_string(), "^3.0".to_string());
- composer
- .require_dev
- .insert("phpunit/phpunit".to_string(), "^11.0".to_string());
-
- let name = "psr/log";
- let removed_from_require = composer.require.shift_remove(name).is_some();
- let removed_from_dev = if !removed_from_require {
- composer.require_dev.shift_remove(name).is_some()
- } else {
- false
- };
-
- assert!(
- removed_from_require,
- "should be found and removed from require"
- );
- assert!(!removed_from_dev);
- assert!(!composer.require.contains_key("psr/log"));
- assert!(composer.require_dev.contains_key("phpunit/phpunit"));
- }
-
- /// Without `--dev`, auto-detect finds the package in require-dev if not in require.
- #[test]
- fn test_remove_auto_detects_section_require_dev() {
- let mut composer = make_raw_package("test/project");
- composer
- .require
- .insert("psr/log".to_string(), "^3.0".to_string());
- composer
- .require_dev
- .insert("phpunit/phpunit".to_string(), "^11.0".to_string());
-
- let name = "phpunit/phpunit";
- let removed_from_require = composer.require.shift_remove(name).is_some();
- let removed_from_dev = if !removed_from_require {
- composer.require_dev.shift_remove(name).is_some()
- } else {
- false
- };
-
- assert!(!removed_from_require);
- assert!(
- removed_from_dev,
- "should be found and removed from require-dev"
- );
- assert!(!composer.require_dev.contains_key("phpunit/phpunit"));
- assert!(composer.require.contains_key("psr/log"));
- }
-
- /// After re-resolve, removed packages appear as `ChangeKind::Uninstall` in the change report.
- #[test]
- fn test_remove_change_report_shows_removals() {
- let old_lock = minimal_lock(vec![
- make_locked_package("psr/log", "3.0.0"),
- make_locked_package("monolog/monolog", "3.8.0"),
- ]);
- let new_lock = minimal_lock(vec![make_locked_package("psr/log", "3.0.0")]);
-
- let changes =
- super::super::update::compute_update_changes(Some(&old_lock), &new_lock, false);
-
- assert_eq!(changes.len(), 1, "exactly one change expected");
- assert_eq!(changes[0].name, "monolog/monolog");
- assert!(
- matches!(
- &changes[0].kind,
- super::super::update::ChangeKind::Uninstall { old_version }
- if old_version == "3.8.0"
- ),
- "monolog/monolog should appear as an Uninstall change"
- );
- }
-
- /// Glob-style package names (e.g. "vendor/*") no longer bail with an "Invalid package name"
- /// error — they fall through to the "not required" warning path. This is a regression test
- /// for the validate_package_name bail that was removed in PR-A.
- #[test]
- fn test_glob_package_name_falls_through_to_not_required() {
- let mut composer = make_raw_package("test/project");
- composer
- .require
- .insert("psr/log".to_string(), "^3.0".to_string());
-
- // A glob-style name: not a valid exact package name, not in require either.
- let name = "vendor/*";
- let found = composer.require.shift_remove(name).is_some()
- || composer.require_dev.shift_remove(name).is_some();
-
- // Should NOT be found (falls through to "not required" warning), not panicked/bailed.
- assert!(!found, "glob name should not match any package");
- // composer.json is unchanged
- assert_eq!(composer.require.len(), 1);
- }
-
- /// --unused with no lock file must return an error matching Composer's wording.
- #[test]
- fn test_unused_no_lock_error_wording() {
- use tempfile::tempdir;
-
- let dir = tempdir().unwrap();
- // No lock file present — the error message is tested via the remove_unused code path.
- let lock_path = dir.path().join("composer.lock");
- assert!(!lock_path.exists());
-
- // The error message Composer uses (and Mozart must match):
- let expected = "A valid composer.lock file is required to run this command with --unused";
- // Simulate the check that remove_unused() performs:
- let result: anyhow::Result<()> = if !lock_path.exists() {
- Err(anyhow::anyhow!("{}", expected))
- } else {
- Ok(())
- };
- assert!(result.is_err());
- assert!(result.unwrap_err().to_string().contains(expected));
- }
-
- #[tokio::test]
- #[ignore]
- async fn test_remove_full_e2e() {
- use indexmap::{IndexMap, IndexSet};
- use mozart_core::repository::lockfile::{LockFileGenerationRequest, generate_lock_file};
- use mozart_core::repository::resolver::{ResolveRequest, resolve};
- use tempfile::tempdir;
-
- let dir = tempdir().unwrap();
- let composer_path = dir.path().join("composer.json");
- let lock_path = dir.path().join("composer.lock");
- let vendor_dir = dir.path().join("vendor");
-
- let content = r#"{"name": "test/project", "require": {"psr/log": "^3.0"}}"#;
- std::fs::write(&composer_path, content).unwrap();
-
- let mut composer: RawPackageData = serde_json::from_str(content).unwrap();
-
- let request = ResolveRequest {
- root_name: String::new(),
- root_version: None,
- require: vec![("psr/log".to_string(), "^3.0".to_string())],
- require_dev: vec![],
- include_dev: false,
- minimum_stability: mozart_core::package::Stability::Stable,
- stability_flags: IndexMap::new(),
- prefer_stable: true,
- prefer_lowest: false,
- platform: mozart_core::repository::resolver::PlatformConfig::new(),
- ignore_platform_reqs: false,
- ignore_platform_req_list: vec![],
- repositories: std::sync::Arc::new(
- mozart_core::repository::repository::RepositorySet::with_packagist(
- mozart_core::repository::cache::Cache::new(
- std::env::temp_dir().join("mozart-test-cache"),
- false,
- ),
- ),
- ),
- temporary_constraints: IndexMap::new(),
- raw_repositories: vec![],
- root_provide: IndexMap::new(),
- root_replace: IndexMap::new(),
- root_conflict: IndexMap::new(),
- locked_package_names: IndexSet::new(),
- locked_packages: Vec::new(),
- block_abandoned: false,
- root_branch_alias: None,
- preferred_versions: IndexMap::new(),
- block_insecure: false,
- };
- let resolved = resolve(&request)
- .await
- .expect("initial resolution should succeed");
- let initial_lock = generate_lock_file(&LockFileGenerationRequest {
- resolved_packages: resolved,
- composer_json_content: content.to_string(),
- composer_json: composer.clone(),
- include_dev: false,
- repositories: std::sync::Arc::new(
- mozart_core::repository::repository::RepositorySet::with_packagist(
- mozart_core::repository::cache::Cache::new(
- std::env::temp_dir().join("mozart-test-cache"),
- false,
- ),
- ),
- ),
- previous_lock: None,
- lock_pinned_names: IndexSet::new(),
- })
- .await
- .expect("initial lock file generation should succeed");
- initial_lock
- .write_to_file(&lock_path)
- .expect("should write initial lock file");
-
- composer.require.shift_remove("psr/log");
- package::write_to_file(&composer, &composer_path).unwrap();
-
- let request2 = ResolveRequest {
- root_name: String::new(),
- root_version: None,
- require: vec![],
- require_dev: vec![],
- include_dev: false,
- minimum_stability: mozart_core::package::Stability::Stable,
- stability_flags: IndexMap::new(),
- prefer_stable: true,
- prefer_lowest: false,
- platform: mozart_core::repository::resolver::PlatformConfig::new(),
- ignore_platform_reqs: false,
- ignore_platform_req_list: vec![],
- repositories: std::sync::Arc::new(
- mozart_core::repository::repository::RepositorySet::with_packagist(
- mozart_core::repository::cache::Cache::new(
- std::env::temp_dir().join("mozart-test-cache"),
- false,
- ),
- ),
- ),
- temporary_constraints: IndexMap::new(),
- raw_repositories: vec![],
- root_provide: IndexMap::new(),
- root_replace: IndexMap::new(),
- root_conflict: IndexMap::new(),
- locked_package_names: IndexSet::new(),
- locked_packages: Vec::new(),
- block_abandoned: false,
- root_branch_alias: None,
- preferred_versions: IndexMap::new(),
- block_insecure: false,
- };
- let resolved2 = resolve(&request2)
- .await
- .expect("post-remove resolution should succeed");
-
- let composer_json_content2 = std::fs::read_to_string(&composer_path).unwrap();
- let new_lock = generate_lock_file(&LockFileGenerationRequest {
- resolved_packages: resolved2,
- composer_json_content: composer_json_content2,
- composer_json: composer,
- include_dev: false,
- repositories: std::sync::Arc::new(
- mozart_core::repository::repository::RepositorySet::with_packagist(
- mozart_core::repository::cache::Cache::new(
- std::env::temp_dir().join("mozart-test-cache"),
- false,
- ),
- ),
- ),
- previous_lock: Some(initial_lock.clone()),
- lock_pinned_names: IndexSet::new(),
- })
- .await
- .expect("post-remove lock file generation should succeed");
-
- assert!(
- !new_lock.packages.iter().any(|p| p.name == "psr/log"),
- "psr/log should be absent from the new lock file"
- );
-
- new_lock.write_to_file(&lock_path).unwrap();
- assert!(lock_path.exists(), "lock file should exist");
-
- let _ = vendor_dir;
- }
-
- #[test]
- fn test_remove_no_update_only_modifies_json() {
- use tempfile::tempdir;
-
- let dir = tempdir().unwrap();
- let composer_path = dir.path().join("composer.json");
- let lock_path = dir.path().join("composer.lock");
-
- let content = r#"{"name": "test/project", "require": {"psr/log": "^3.0"}}"#;
- std::fs::write(&composer_path, content).unwrap();
-
- let mut composer: RawPackageData = serde_json::from_str(content).unwrap();
- composer.require.shift_remove("psr/log");
- package::write_to_file(&composer, &composer_path).unwrap();
-
- assert!(
- !lock_path.exists(),
- "lock file should not be created with --no-update"
- );
-
- let updated_content = std::fs::read_to_string(&composer_path).unwrap();
- assert!(
- !updated_content.contains("psr/log"),
- "psr/log should be removed from composer.json"
- );
- }
-
- #[test]
- fn test_remove_dry_run_modifies_nothing() {
- use tempfile::tempdir;
-
- let dir = tempdir().unwrap();
- let composer_path = dir.path().join("composer.json");
- let lock_path = dir.path().join("composer.lock");
- let vendor_dir = dir.path().join("vendor");
-
- let original_content = r#"{"name": "test/project", "require": {"psr/log": "^3.0"}}"#;
- std::fs::write(&composer_path, original_content).unwrap();
-
- assert_eq!(
- std::fs::read_to_string(&composer_path).unwrap(),
- original_content,
- "composer.json should be unmodified after dry run"
- );
- assert!(
- !lock_path.exists(),
- "lock file should not be created by dry run"
- );
- assert!(
- !vendor_dir.exists(),
- "vendor dir should not be created by dry run"
- );
- }
-}