diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-26 01:01:53 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-26 01:01:53 +0900 |
| commit | f639066eaf49325fdbf1b697fb24c187b2d5038e (patch) | |
| tree | 7444d076aec641916766c29e8ced5cb6177c2a15 /crates/shirabe/tests/command/repository_command_test.rs | |
| parent | 5f9778e6988b43a759d976322dd73dcac7ff927d (diff) | |
| download | php-shirabe-f639066eaf49325fdbf1b697fb24c187b2d5038e.tar.gz php-shirabe-f639066eaf49325fdbf1b697fb24c187b2d5038e.tar.zst php-shirabe-f639066eaf49325fdbf1b697fb24c187b2d5038e.zip | |
test(command): port command test bodies from Composer PHPUnit suite
Faithfully port repository, base_dependency, exec, dump_autoload, run_script,
licenses command tests from their PHP counterparts (expected values verbatim).
Newly passing: repository (6), base_dependency (5), exec (2). Tests whose ported
bodies hit a genuine unported path (HTTP/curl, event-dispatch re-entrancy,
spl_autoload_register, php_uname, instance_of, un-delimited Preg patterns,
Config::merge dropping list repos) keep faithful bodies but stay #[ignore] with
precise reasons; no assertions weakened.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/tests/command/repository_command_test.rs')
| -rw-r--r-- | crates/shirabe/tests/command/repository_command_test.rs | 729 |
1 files changed, 697 insertions, 32 deletions
diff --git a/crates/shirabe/tests/command/repository_command_test.rs b/crates/shirabe/tests/command/repository_command_test.rs index dd7a4bf..0cad288 100644 --- a/crates/shirabe/tests/command/repository_command_test.rs +++ b/crates/shirabe/tests/command/repository_command_test.rs @@ -1,97 +1,762 @@ //! ref: composer/tests/Composer/Test/Command/RepositoryCommandTest.php +use crate::test_case::{RunOptions, get_application_tester, init_temp_composer}; +use serial_test::serial; +use shirabe::json::JsonFile; +use shirabe_php_shim::PhpMixed; + +/// Read the composer.json in the CWD and decode it. +fn read_composer_json() -> serde_json::Value { + let mut json = JsonFile::new("./composer.json".to_string(), None, None).unwrap(); + let read = json.read().unwrap(); + serde_json::from_str(&JsonFile::encode(&read)).unwrap() +} + #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] fn test_list_with_no_repositories() { - todo!() + let tear_down = init_temp_composer(Some(&serde_json::json!({})), None, None, true); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("list")), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + + assert_eq!( + "[packagist.org] composer https://repo.packagist.org", + app_tester.get_display().trim() + ); + // composer.json should remain unchanged + assert_eq!(serde_json::json!({}), read_composer_json()); + + drop(tear_down); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] +#[ignore = "src bug: config.rs Config::merge only reads repositories when PhpMixed::Array (JSON object); list-form repositories decode to PhpMixed::List and are dropped (crates/shirabe/src/config.rs:452-455), so list-form repos are not listed and output falls back to the default packagist repo"] fn test_list_with_repositories_as_list() { - todo!() + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "repositories": [ + {"type": "composer", "url": "https://first.test"}, + {"name": "foo", "type": "vcs", "url": "https://old.example.org"}, + {"name": "bar", "type": "vcs", "url": "https://other.example.org"}, + ], + })), + None, + None, + true, + ); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("list")), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + + assert_eq!( + "[0] composer https://first.test +[foo] vcs https://old.example.org +[bar] vcs https://other.example.org +[packagist.org] disabled", + app_tester.get_display().trim() + ); + + drop(tear_down); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] fn test_list_with_repositories_as_assoc() { - todo!() + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "repositories": { + "0": {"type": "composer", "url": "https://first.test"}, + "foo": {"type": "vcs", "url": "https://old.example.org"}, + "bar": {"type": "vcs", "url": "https://other.example.org"}, + }, + })), + None, + None, + true, + ); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("list")), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + + assert_eq!( + "[0] composer https://first.test +[foo] vcs https://old.example.org +[bar] vcs https://other.example.org +[packagist.org] disabled", + app_tester.get_display().trim() + ); + + drop(tear_down); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] +#[ignore = "src bug: repository_command.rs:299 passes the un-delimited regex r\"^\\s*\\{\" to Preg::is_match (PHP source uses the delimited '{^\\s*\\{}'); compile_php_pattern rejects it, panicking at shirabe-php-shim/src/preg.rs:180 'invalid regex: unterminated regex pattern: ^\\s*\\{' on every add action"] fn test_add_repository_with_type_and_url() { - todo!() + let tear_down = init_temp_composer(Some(&serde_json::json!({})), None, None, true); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("add")), + (PhpMixed::from("name"), PhpMixed::from("foo")), + (PhpMixed::from("arg1"), PhpMixed::from("vcs")), + ( + PhpMixed::from("arg2"), + PhpMixed::from("https://example.org/foo.git"), + ), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code, "{}", app_tester.get_display()); + + assert_eq!( + serde_json::json!({ + "repositories": [ + {"name": "foo", "type": "vcs", "url": "https://example.org/foo.git"}, + ], + }), + read_composer_json() + ); + + drop(tear_down); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] +#[ignore = "src bug: repository_command.rs:299 passes the un-delimited regex r\"^\\s*\\{\" to Preg::is_match (PHP source uses the delimited '{^\\s*\\{}'); compile_php_pattern rejects it, panicking at shirabe-php-shim/src/preg.rs:180 'invalid regex: unterminated regex pattern: ^\\s*\\{' on every add action"] fn test_add_repository_with_json() { - todo!() + let tear_down = init_temp_composer(Some(&serde_json::json!({})), None, None, true); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("add")), + (PhpMixed::from("name"), PhpMixed::from("bar")), + ( + PhpMixed::from("arg1"), + PhpMixed::from(r#"{"type":"composer","url":"https://repo.example.org"}"#), + ), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + + assert_eq!( + serde_json::json!({ + "repositories": [ + {"name": "bar", "type": "composer", "url": "https://repo.example.org"}, + ], + }), + read_composer_json() + ); + + drop(tear_down); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] fn test_remove_repository() { - todo!() + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "repositories": {"foo": {"type": "vcs", "url": "https://example.org"}}, + })), + None, + None, + false, + ); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("remove")), + (PhpMixed::from("name"), PhpMixed::from("foo")), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + + let json = read_composer_json(); + // repositories key may still exist as empty array depending on manipulator, accept either + if let Some(repositories) = json.get("repositories") { + assert_eq!(&serde_json::json!([]), repositories); + } else { + assert_eq!(serde_json::json!({}), json); + } + + drop(tear_down); +} + +/// ref: RepositoryCommandTest::testSetAndGetUrlInRepositoryAssoc (data provider). +fn run_set_and_get_url_assoc_case(name: &str, index: &str, new_url: &str) { + let repositories = serde_json::json!({ + "first": {"type": "composer", "url": "https://first.test"}, + "foo": {"type": "vcs", "url": "https://old.example.org"}, + "bar": {"type": "vcs", "url": "https://other.example.org"}, + }); + let tear_down = init_temp_composer( + Some(&serde_json::json!({ "repositories": repositories })), + None, + None, + false, + ); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("set-url")), + (PhpMixed::from("name"), PhpMixed::from(name)), + (PhpMixed::from("arg1"), PhpMixed::from(new_url)), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code, "{}", app_tester.get_display()); + + let json = read_composer_json(); + // calling it still in assoc means, the repository has not been converted, which is good + assert_eq!( + Some(&serde_json::Value::String(new_url.to_string())), + json.get("repositories") + .and_then(|r| r.get(index)) + .and_then(|r| r.get("url")) + ); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("get-url")), + (PhpMixed::from("name"), PhpMixed::from(name)), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + assert_eq!(new_url, app_tester.get_display().trim()); + + drop(tear_down); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] fn test_set_and_get_url_in_repository_assoc() { - todo!() + // change first of three + run_set_and_get_url_assoc_case("first", "first", "https://new.example.org"); + // change middle of three + run_set_and_get_url_assoc_case("foo", "foo", "https://new.example.org"); + // change last of three + run_set_and_get_url_assoc_case("bar", "bar", "https://new.example.org"); +} + +/// ref: RepositoryCommandTest::testSetAndGetUrlInRepositoryList (data provider). +fn run_set_and_get_url_list_case(name: &str, index: usize, new_url: &str) { + let repositories = serde_json::json!([ + {"name": "first", "type": "composer", "url": "https://first.test"}, + {"name": "foo", "type": "vcs", "url": "https://old.example.org"}, + {"name": "bar", "type": "vcs", "url": "https://other.example.org"}, + ]); + let tear_down = init_temp_composer( + Some(&serde_json::json!({ "repositories": repositories })), + None, + None, + false, + ); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("set-url")), + (PhpMixed::from("name"), PhpMixed::from(name)), + (PhpMixed::from("arg1"), PhpMixed::from(new_url)), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code, "{}", app_tester.get_display()); + + let json = read_composer_json(); + assert_eq!( + Some(&serde_json::Value::String(name.to_string())), + json.get("repositories") + .and_then(|r| r.get(index)) + .and_then(|r| r.get("name")) + ); + assert_eq!( + Some(&serde_json::Value::String(new_url.to_string())), + json.get("repositories") + .and_then(|r| r.get(index)) + .and_then(|r| r.get("url")) + ); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("get-url")), + (PhpMixed::from("name"), PhpMixed::from(name)), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + assert_eq!(new_url, app_tester.get_display().trim()); + + drop(tear_down); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] +#[ignore = "src bug: config.rs Config::merge only reads repositories when PhpMixed::Array (JSON object); list-form repositories decode to PhpMixed::List and are dropped (crates/shirabe/src/config.rs:452-455), so get-url panics with 'There is no first repository defined'"] fn test_set_and_get_url_in_repository_list() { - todo!() + // change first of three + run_set_and_get_url_list_case("first", 0, "https://new.example.org"); + // change middle of three + run_set_and_get_url_list_case("foo", 1, "https://new.example.org"); + // change last of three + run_set_and_get_url_list_case("bar", 2, "https://new.example.org"); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] fn test_disable_and_enable_packagist() { - todo!() + let tear_down = init_temp_composer(Some(&serde_json::json!({})), None, None, true); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("disable")), + (PhpMixed::from("name"), PhpMixed::from("packagist")), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + assert_eq!( + serde_json::json!({"repositories": [{"packagist.org": false}]}), + read_composer_json() + ); + + // enable packagist should remove the override + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("enable")), + (PhpMixed::from("name"), PhpMixed::from("packagist")), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + assert_eq!(serde_json::json!({}), read_composer_json()); + + drop(tear_down); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] fn test_invalid_arg_combination_throws() { - todo!() + let mut app_tester = get_application_tester(); + let err = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + ( + PhpMixed::from("--file"), + PhpMixed::from("alt.composer.json"), + ), + (PhpMixed::from("--global"), PhpMixed::from(true)), + ], + RunOptions::default(), + ) + .expect_err("expected RuntimeException for --file and --global combination"); + assert!( + err.to_string() + .contains("--file and --global can not be combined"), + "got: {}", + err + ); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] +#[ignore = "src bug: repository_command.rs:299 passes the un-delimited regex r\"^\\s*\\{\" to Preg::is_match (PHP source uses the delimited '{^\\s*\\{}'); compile_php_pattern rejects it, panicking at shirabe-php-shim/src/preg.rs:180 'invalid regex: unterminated regex pattern: ^\\s*\\{' on every add action"] fn test_prepend_repository_by_name_list_to_assoc() { - todo!() + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "repositories": [{"type": "git", "url": "example.tld"}], + })), + None, + None, + false, + ); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("add")), + (PhpMixed::from("name"), PhpMixed::from("foo")), + (PhpMixed::from("arg1"), PhpMixed::from("path")), + (PhpMixed::from("arg2"), PhpMixed::from("foo/bar")), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code, "{}", app_tester.get_display()); + + assert_eq!( + serde_json::json!({ + "repositories": [ + {"name": "foo", "type": "path", "url": "foo/bar"}, + {"type": "git", "url": "example.tld"}, + ], + }), + read_composer_json() + ); + + drop(tear_down); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] +#[ignore = "src bug: repository_command.rs:299 passes the un-delimited regex r\"^\\s*\\{\" to Preg::is_match (PHP source uses the delimited '{^\\s*\\{}'); compile_php_pattern rejects it, panicking at shirabe-php-shim/src/preg.rs:180 'invalid regex: unterminated regex pattern: ^\\s*\\{' on every add action"] fn test_append_repository_by_name_list_to_assoc() { - todo!() + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "repositories": [{"type": "git", "url": "example.tld"}], + })), + None, + None, + false, + ); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("add")), + (PhpMixed::from("name"), PhpMixed::from("foo")), + (PhpMixed::from("arg1"), PhpMixed::from("path")), + (PhpMixed::from("arg2"), PhpMixed::from("foo/bar")), + (PhpMixed::from("--append"), PhpMixed::from(true)), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code, "{}", app_tester.get_display()); + + assert_eq!( + serde_json::json!({ + "repositories": [ + {"type": "git", "url": "example.tld"}, + {"name": "foo", "type": "path", "url": "foo/bar"}, + ], + }), + read_composer_json() + ); + + drop(tear_down); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] +#[ignore = "src bug: repository_command.rs:299 passes the un-delimited regex r\"^\\s*\\{\" to Preg::is_match (PHP source uses the delimited '{^\\s*\\{}'); compile_php_pattern rejects it, panicking at shirabe-php-shim/src/preg.rs:180 'invalid regex: unterminated regex pattern: ^\\s*\\{' on every add action"] fn test_prepend_repository_assoc_with_packagist_disabled() { - todo!() + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "repositories": [{"type": "git", "url": "example.tld"}, {"packagist.org": false}], + })), + None, + None, + true, + ); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("add")), + (PhpMixed::from("name"), PhpMixed::from("foo")), + (PhpMixed::from("arg1"), PhpMixed::from("path")), + (PhpMixed::from("arg2"), PhpMixed::from("foo/bar")), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code, "{}", app_tester.get_display()); + + assert_eq!( + serde_json::json!({ + "repositories": [ + {"name": "foo", "type": "path", "url": "foo/bar"}, + {"type": "git", "url": "example.tld"}, + {"packagist.org": false}, + ], + }), + read_composer_json() + ); + + drop(tear_down); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] +#[ignore = "src bug: repository_command.rs:299 passes the un-delimited regex r\"^\\s*\\{\" to Preg::is_match (PHP source uses the delimited '{^\\s*\\{}'); compile_php_pattern rejects it, panicking at shirabe-php-shim/src/preg.rs:180 'invalid regex: unterminated regex pattern: ^\\s*\\{' on every add action"] fn test_append_repository_assoc_with_packagist_disabled() { - todo!() + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "repositories": [{"type": "git", "url": "example.tld"}, {"packagist.org": false}], + })), + None, + None, + true, + ); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("add")), + (PhpMixed::from("name"), PhpMixed::from("foo")), + (PhpMixed::from("arg1"), PhpMixed::from("path")), + (PhpMixed::from("arg2"), PhpMixed::from("foo/bar")), + (PhpMixed::from("--append"), PhpMixed::from(true)), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code, "{}", app_tester.get_display()); + + assert_eq!( + serde_json::json!({ + "repositories": [ + {"type": "git", "url": "example.tld"}, + {"packagist.org": false}, + {"name": "foo", "type": "path", "url": "foo/bar"}, + ], + }), + read_composer_json() + ); + + drop(tear_down); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] +#[ignore = "src bug: repository_command.rs:299 passes the un-delimited regex r\"^\\s*\\{\" to Preg::is_match (PHP source uses the delimited '{^\\s*\\{}'); compile_php_pattern rejects it, panicking at shirabe-php-shim/src/preg.rs:180 'invalid regex: unterminated regex pattern: ^\\s*\\{' on every add action"] fn test_add_before_and_after_by_name() { - todo!() + // Start with two repos as named-list and a disabled packagist boolean + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "repositories": [ + {"name": "alpha", "type": "vcs", "url": "https://example.org/a"}, + {"name": "omega", "type": "vcs", "url": "https://example.org/o"}, + {"packagist.org": false}, + ], + })), + None, + None, + true, + ); + + // Insert before omega + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("add")), + (PhpMixed::from("name"), PhpMixed::from("beta")), + (PhpMixed::from("arg1"), PhpMixed::from("vcs")), + ( + PhpMixed::from("arg2"), + PhpMixed::from("https://example.org/b"), + ), + (PhpMixed::from("--before"), PhpMixed::from("omega")), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code, "{}", app_tester.get_display()); + + // Insert after alpha + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("add")), + (PhpMixed::from("name"), PhpMixed::from("gamma")), + (PhpMixed::from("arg1"), PhpMixed::from("vcs")), + ( + PhpMixed::from("arg2"), + PhpMixed::from("https://example.org/g"), + ), + (PhpMixed::from("--after"), PhpMixed::from("alpha")), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code, "{}", app_tester.get_display()); + + // Expect order: alpha, gamma, beta, omega, then packagist.org boolean preserved + assert_eq!( + serde_json::json!({ + "repositories": [ + {"name": "alpha", "type": "vcs", "url": "https://example.org/a"}, + {"name": "gamma", "type": "vcs", "url": "https://example.org/g"}, + {"name": "beta", "type": "vcs", "url": "https://example.org/b"}, + {"name": "omega", "type": "vcs", "url": "https://example.org/o"}, + {"packagist.org": false}, + ], + }), + read_composer_json() + ); + + drop(tear_down); } #[test] -#[ignore = "missing init_temp_composer and get_application_tester (ApplicationTester) test infrastructure"] +#[serial] +#[ignore = "src bug: repository_command.rs:299 passes the un-delimited regex r\"^\\s*\\{\" to Preg::is_match (PHP source uses the delimited '{^\\s*\\{}'); compile_php_pattern rejects it, panicking at shirabe-php-shim/src/preg.rs:180 'invalid regex: unterminated regex pattern: ^\\s*\\{' on every add action"] fn test_add_same_name_replaces_existing() { - todo!() + let tear_down = init_temp_composer(Some(&serde_json::json!({})), None, None, true); + + // first add + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("add")), + (PhpMixed::from("name"), PhpMixed::from("foo")), + (PhpMixed::from("arg1"), PhpMixed::from("vcs")), + ( + PhpMixed::from("arg2"), + PhpMixed::from("https://example.org/old"), + ), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code, "{}", app_tester.get_display()); + + // second add with same name but different url + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("repo")), + (PhpMixed::from("action"), PhpMixed::from("add")), + (PhpMixed::from("name"), PhpMixed::from("foo")), + (PhpMixed::from("arg1"), PhpMixed::from("vcs")), + ( + PhpMixed::from("arg2"), + PhpMixed::from("https://example.org/new"), + ), + (PhpMixed::from("--append"), PhpMixed::from(true)), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code, "{}", app_tester.get_display()); + + let json = read_composer_json(); + + // repositories can be stored as assoc or named-list depending on manipulator fallbacks + // Validate there is only one "foo" and its url is the latest + let mut count_foo = 0; + let mut url: Option<&serde_json::Value> = None; + match json.get("repositories") { + Some(serde_json::Value::Object(map)) => { + for (k, repo) in map { + if k == "foo" && repo.is_object() { + count_foo += 1; + url = repo.get("url"); + } else if repo.is_object() + && repo.get("name") == Some(&serde_json::Value::String("foo".to_string())) + { + count_foo += 1; + url = repo.get("url"); + } + } + } + Some(serde_json::Value::Array(list)) => { + for repo in list { + if repo.is_object() + && repo.get("name") == Some(&serde_json::Value::String("foo".to_string())) + { + count_foo += 1; + url = repo.get("url"); + } + } + } + _ => {} + } + assert_eq!( + 1, count_foo, + "Exactly one repository entry with name foo should exist" + ); + assert_eq!( + Some(&serde_json::Value::String( + "https://example.org/new".to_string() + )), + url, + "The foo repository should have been updated to the new URL" + ); + + drop(tear_down); } |
