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 | |
| 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')
7 files changed, 1821 insertions, 94 deletions
diff --git a/crates/shirabe/tests/command/base_dependency_command_test.rs b/crates/shirabe/tests/command/base_dependency_command_test.rs index a112933..ed0c601 100644 --- a/crates/shirabe/tests/command/base_dependency_command_test.rs +++ b/crates/shirabe/tests/command/base_dependency_command_test.rs @@ -1,43 +1,614 @@ //! ref: composer/tests/Composer/Test/Command/BaseDependencyCommandTest.php +use crate::test_case::{ + RunOptions, create_composer_lock, create_installed_json, get_application_tester, get_package, + get_version_constraint, init_temp_composer, +}; +use serial_test::serial; +use shirabe::package::Link; +use shirabe::package::handle::PackageInterfaceHandle; +use shirabe_php_shim::PhpMixed; +use shirabe_semver::constraint::{AnyConstraint, MatchAllConstraint, MultiConstraint}; + +/// ref: TestCase::trimLines — strip trailing spaces from each line, then trim the whole string. +fn trim_lines(s: &str) -> String { + let stripped = s + .lines() + .map(|line| line.trim_end_matches(' ')) + .collect::<Vec<_>>() + .join("\n"); + stripped.trim().to_string() +} + +fn match_all() -> AnyConstraint { + AnyConstraint::MatchAll(MatchAllConstraint::new(None)) +} + +/// ref: BaseDependencyCommandTest::testExceptionWhenNoRequiredParameters (data provider rolled in). #[test] -#[ignore = "ApplicationTester / get_application_tester helper not implemented"] +#[serial] fn test_exception_when_no_required_parameters() { - todo!() + // noParametersCaseProvider + let cases: Vec<(&str, Vec<(&str, PhpMixed)>, &str)> = vec![ + ( + "why", + vec![], + "Not enough arguments (missing: \"package\").", + ), + ( + "why-not", + vec![], + "Not enough arguments (missing: \"package, version\").", + ), + ( + "why-not", + vec![("version", PhpMixed::from("*"))], + "Not enough arguments (missing: \"package\").", + ), + ( + "why-not", + vec![("package", PhpMixed::from("vendor1/package1"))], + "Not enough arguments (missing: \"version\").", + ), + ]; + + for (command, parameters, expected_message) in cases { + let mut input: Vec<(PhpMixed, PhpMixed)> = + vec![(PhpMixed::from("command"), PhpMixed::from(command))]; + for (k, v) in parameters { + input.push((PhpMixed::from(k), v)); + } + + let mut app_tester = get_application_tester(); + let err = app_tester + .run(input, RunOptions::default()) + .expect_err("expected RuntimeException"); + assert!( + err.to_string().contains(expected_message), + "expected error to contain {:?}, got: {:?}", + expected_message, + err.to_string(), + ); + } } +/// ref: BaseDependencyCommandTest::testExceptionWhenRunningLockedWithoutLockFile. #[test] -#[ignore = "init_temp_composer / get_application_tester helper not implemented"] +#[serial] fn test_exception_when_running_locked_without_lock_file() { - todo!() + // caseProvider + let cases: Vec<(&str, Vec<(&str, PhpMixed)>)> = vec![ + ("why", vec![("package", PhpMixed::from("vendor1/package1"))]), + ( + "why-not", + vec![ + ("package", PhpMixed::from("vendor1/package1")), + ("version", PhpMixed::from("1.*")), + ], + ), + ]; + + for (command, parameters) in cases { + let tear_down = init_temp_composer(None, None, None, true); + + let mut input: Vec<(PhpMixed, PhpMixed)> = + vec![(PhpMixed::from("command"), PhpMixed::from(command))]; + for (k, v) in parameters { + input.push((PhpMixed::from(k), v)); + } + input.push((PhpMixed::from("--locked"), PhpMixed::from(true))); + + let mut app_tester = get_application_tester(); + let err = app_tester + .run(input, RunOptions::default()) + .expect_err("expected UnexpectedValueException"); + assert!( + err.to_string().contains( + "A valid composer.lock file is required to run this command with --locked" + ), + "got: {:?}", + err.to_string(), + ); + + drop(tear_down); + } } +/// ref: BaseDependencyCommandTest::testExceptionWhenItCouldNotFoundThePackage. #[test] -#[ignore = "init_temp_composer / get_application_tester helper not implemented"] +#[serial] fn test_exception_when_it_could_not_found_the_package() { - todo!() + // caseProvider + let cases: Vec<(&str, Vec<(&str, PhpMixed)>)> = vec![ + ("why", vec![("package", PhpMixed::from("vendor1/package1"))]), + ( + "why-not", + vec![ + ("package", PhpMixed::from("vendor1/package1")), + ("version", PhpMixed::from("1.*")), + ], + ), + ]; + + for (command, parameters) in cases { + let package_to_be_inspected = "vendor1/package1"; + + let tear_down = init_temp_composer(None, None, None, true); + + let mut input: Vec<(PhpMixed, PhpMixed)> = + vec![(PhpMixed::from("command"), PhpMixed::from(command))]; + for (k, v) in parameters { + input.push((PhpMixed::from(k), v)); + } + + let mut app_tester = get_application_tester(); + let err = app_tester + .run(input, RunOptions::default()) + .expect_err("expected InvalidArgumentException"); + let expected = format!( + "Could not find package \"{}\" in your project", + package_to_be_inspected + ); + assert!( + err.to_string().contains(&expected), + "expected error to contain {:?}, got: {:?}", + expected, + err.to_string(), + ); + + drop(tear_down); + } } +/// ref: BaseDependencyCommandTest::testExceptionWhenPackageWasNotFoundInProject. #[test] -#[ignore = "init_temp_composer / create_installed_json / create_composer_lock / get_application_tester helpers not implemented"] +#[serial] fn test_exception_when_package_was_not_found_in_project() { - todo!() + // caseProvider + let cases: Vec<(&str, Vec<(&str, PhpMixed)>)> = vec![ + ("why", vec![("package", PhpMixed::from("vendor1/package1"))]), + ( + "why-not", + vec![ + ("package", PhpMixed::from("vendor1/package1")), + ("version", PhpMixed::from("1.*")), + ], + ), + ]; + + for (command, parameters) in cases { + let package_to_be_inspected = "vendor1/package1"; + + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "require": { + "vendor1/package2": "1.*", + "vendor2/package1": "2.*", + }, + })), + None, + None, + true, + ); + + let first_required_package = get_package("vendor1/package2", "1.0.0"); + let second_required_package = get_package("vendor2/package1", "1.0.0"); + + let packages: Vec<PackageInterfaceHandle> = vec![ + first_required_package.clone(), + second_required_package.clone(), + ]; + create_installed_json(&packages, &[], false); + create_composer_lock(&packages, &[]); + + let mut input: Vec<(PhpMixed, PhpMixed)> = + vec![(PhpMixed::from("command"), PhpMixed::from(command))]; + for (k, v) in parameters { + input.push((PhpMixed::from(k), v)); + } + + let mut app_tester = get_application_tester(); + let err = app_tester + .run(input, RunOptions::default()) + .expect_err("expected InvalidArgumentException"); + let expected = format!( + "Could not find package \"{}\" in your project", + package_to_be_inspected + ); + assert!( + err.to_string().contains(&expected), + "expected error to contain {:?}, got: {:?}", + expected, + err.to_string(), + ); + + drop(tear_down); + } } +/// ref: BaseDependencyCommandTest::testWarningWhenDependenciesAreNotInstalled. #[test] -#[ignore = "init_temp_composer / create_composer_lock / get_application_tester helpers not implemented"] +#[serial] fn test_warning_when_dependencies_are_not_installed() { - todo!() + let expected_warning_message = "<warning>No dependencies installed. Try running composer install or update, or use --locked.</warning>"; + + // caseProvider + let cases: Vec<(&str, Vec<(&str, PhpMixed)>)> = vec![ + ("why", vec![("package", PhpMixed::from("vendor1/package1"))]), + ( + "why-not", + vec![ + ("package", PhpMixed::from("vendor1/package1")), + ("version", PhpMixed::from("1.*")), + ], + ), + ]; + + for (command, parameters) in cases { + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "require": { + "vendor1/package1": "1.*", + }, + "require-dev": { + "vendor2/package1": "2.*", + }, + })), + None, + None, + true, + ); + + let some_required_package = get_package("vendor1/package1", "1.0.0"); + let some_dev_required_package = get_package("vendor2/package1", "1.0.0"); + + create_composer_lock( + &[some_required_package.clone()], + &[some_dev_required_package.clone()], + ); + + let mut input: Vec<(PhpMixed, PhpMixed)> = + vec![(PhpMixed::from("command"), PhpMixed::from(command))]; + for (k, v) in parameters { + input.push((PhpMixed::from(k), v)); + } + + let mut app_tester = get_application_tester(); + app_tester.run(input, RunOptions::default()).unwrap(); + + assert_eq!(expected_warning_message, app_tester.get_display().trim()); + + drop(tear_down); + } } +/// ref: BaseDependencyCommandTest::testWhyCommandOutputs (caseWhyProvider rolled in). #[test] -#[ignore = "init_temp_composer / create_composer_lock / create_installed_json / get_application_tester helpers not implemented"] +#[serial] +#[ignore = "panics in shirabe_php_shim::var::instance_of (crates/shirabe-php-shim/src/var.rs:191): PHP `instanceof` is not modeled (PhpMixed carries no runtime class), reached on the `why` command execution path"] fn test_why_command_outputs() { - todo!() + // caseWhyProvider: (package, --tree, --recursive, expected_output, expected_status_code) + let cases: Vec<(&str, bool, bool, &str, i32)> = vec![ + ( + "vendor1/package1", + false, + false, + "There is no installed package depending on \"vendor1/package1\"", + 1, + ), + ( + "vendor1/package3", + false, + false, + "__root__ - requires vendor1/package3 (2.3.0)\n\ + vendor1/package2 2.3.0 requires vendor1/package3 (^1)", + 0, + ), + ( + "vendor1/package3", + true, + false, + "vendor1/package3 2.1.0\n\ + |--__root__ (requires vendor1/package3 2.3.0)\n\ + `--vendor1/package2 2.3.0 (requires vendor1/package3 ^1)\n \ + |--__root__ (requires vendor1/package2 1.3.0)\n \ + `--vendor1/package1 1.3.0 (requires vendor1/package2 ^2)", + 0, + ), + ( + "vendor1/package3", + false, + true, + "__root__ - requires vendor1/package2 (1.3.0)\n\ + vendor1/package1 1.3.0 requires vendor1/package2 (^2)\n\ + __root__ - requires vendor1/package3 (2.3.0)\n\ + vendor1/package2 2.3.0 requires vendor1/package3 (^1)", + 0, + ), + ( + "vendor2/package1", + false, + false, + "__root__ - requires (for development) vendor2/package1 (2.*)", + 0, + ), + ]; + + for ( + package_to_be_inspected, + render_as_tree, + render_recursively, + expected_output, + expected_status_code, + ) in cases + { + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "repositories": { + "packages": { + "type": "package", + "package": [ + {"name": "vendor1/package1", "version": "1.3.0", "require": {"vendor1/package2": "^2"}}, + {"name": "vendor1/package2", "version": "2.3.0", "require": {"vendor1/package3": "^1"}}, + {"name": "vendor1/package3", "version": "2.1.0"}, + ], + }, + }, + "require": { + "vendor1/package2": "1.3.0", + "vendor1/package3": "2.3.0", + }, + "require-dev": { + "vendor2/package1": "2.*", + }, + })), + None, + None, + true, + ); + + let first_required_package = get_package("vendor1/package1", "1.3.0"); + let mut req1 = indexmap::IndexMap::new(); + req1.insert( + "vendor1/package2".to_string(), + Link::new( + "vendor1/package1".to_string(), + "vendor1/package2".to_string(), + match_all(), + Some(Link::TYPE_REQUIRE.to_string()), + "^2".to_string(), + ), + ); + first_required_package.__set_requires(req1); + + let second_required_package = get_package("vendor1/package2", "2.3.0"); + let mut req2 = indexmap::IndexMap::new(); + req2.insert( + "vendor1/package3".to_string(), + Link::new( + "vendor1/package2".to_string(), + "vendor1/package3".to_string(), + match_all(), + Some(Link::TYPE_REQUIRE.to_string()), + "^1".to_string(), + ), + ); + second_required_package.__set_requires(req2); + + let third_required_package = get_package("vendor1/package3", "2.1.0"); + let some_dev_required_package = get_package("vendor2/package1", "1.0.0"); + + create_composer_lock( + &[ + first_required_package.clone(), + second_required_package.clone(), + third_required_package.clone(), + ], + &[some_dev_required_package.clone()], + ); + create_installed_json( + &[ + first_required_package.clone(), + second_required_package.clone(), + third_required_package.clone(), + ], + &[some_dev_required_package.clone()], + true, + ); + + let input: Vec<(PhpMixed, PhpMixed)> = vec![ + (PhpMixed::from("command"), PhpMixed::from("why")), + ( + PhpMixed::from("package"), + PhpMixed::from(package_to_be_inspected), + ), + (PhpMixed::from("--tree"), PhpMixed::from(render_as_tree)), + ( + PhpMixed::from("--recursive"), + PhpMixed::from(render_recursively), + ), + (PhpMixed::from("--locked"), PhpMixed::from(true)), + ]; + + let mut app_tester = get_application_tester(); + app_tester.run(input, RunOptions::default()).unwrap(); + + assert_eq!(expected_status_code, app_tester.get_status_code()); + assert_eq!( + expected_output.trim(), + trim_lines(&app_tester.get_display()), + ); + + drop(tear_down); + } } +/// ref: BaseDependencyCommandTest::testWhyNotCommandOutputs (caseWhyNotProvider rolled in). #[test] -#[ignore = "init_temp_composer / create_composer_lock / create_installed_json / get_application_tester helpers not implemented"] +#[serial] +#[ignore = "panics in shirabe_php_shim::runtime::php_uname `_ => todo!()` arm (crates/shirabe-php-shim/src/runtime.rs:434): unimplemented php_uname() modes (n/v/m/a), reached on the `why-not` command execution path"] fn test_why_not_command_outputs() { - todo!() + // caseWhyNotProvider: (package, version, expected_output, expected_status_code) + let cases: Vec<(&str, &str, &str, i32)> = vec![ + ( + "vendor1/package1", + "3.*", + "Package \"vendor1/package1\" could not be found with constraint \"3.*\", results below will most likely be incomplete.\n\ + __root__ - requires vendor1/package1 (1.*)\n\ + Not finding what you were looking for? Try calling `composer require \"vendor1/package1:3.*\" --dry-run` to get another view on the problem.", + 1, + ), + ( + "vendor1/package1", + "^1.4", + "Package \"vendor1/package1\" could not be found with constraint \"^1.4\", results below will most likely be incomplete.\n\ + There is no installed package depending on \"vendor1/package1\" in versions not matching ^1.4\n\ + Not finding what you were looking for? Try calling `composer require \"vendor1/package1:^1.4\" --dry-run` to get another view on the problem.", + 0, + ), + ( + "vendor1/package1", + "^1.3", + "Package \"vendor1/package1\" 1.3.0 is already installed! To find out why, run `composer why vendor1/package1`", + 0, + ), + ( + "vendor2/package3", + "1.5.0", + "vendor2/package2 1.0.0 requires vendor2/package3 (1.4.*)\n\ + Not finding what you were looking for? Try calling `composer update \"vendor2/package3:1.5.0\" --dry-run` to get another view on the problem.", + 1, + ), + ( + "php", + "^8", + "Package \"php ^8\" found in version \"8.3.2\" (version provided by config.platform).\n\ + There is no installed package depending on \"php\" in versions not matching ^8", + 0, + ), + ( + "php", + "9.1.0", + "__root__ - requires php (^8)\n\ + vendor2/package2 1.0.0 requires php (^8.2)", + 1, + ), + ]; + + for ( + package_to_be_inspected, + package_version_to_be_inspected, + expected_output, + expected_status_code, + ) in cases + { + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "repositories": { + "packages": { + "type": "package", + "package": [ + {"name": "vendor1/package1", "version": "1.3.0"}, + {"name": "vendor2/package1", "version": "2.0.0"}, + {"name": "vendor2/package2", "version": "1.0.0", "require": {"vendor2/package3": "1.4.*", "php": "^8.2"}}, + {"name": "vendor2/package3", "version": "1.4.0"}, + {"name": "vendor2/package3", "version": "1.5.0"}, + ], + }, + }, + "require": { + "vendor1/package1": "1.*", + "php": "^8", + }, + "require-dev": { + "vendor2/package1": "2.*", + "vendor2/package2": "^1", + }, + "config": { + "platform": { + "php": "8.3.2", + }, + }, + })), + None, + None, + true, + ); + + let some_required_package = get_package("vendor1/package1", "1.3.0"); + let first_dev_required_package = get_package("vendor2/package1", "2.0.0"); + let second_dev_required_package = get_package("vendor2/package2", "1.0.0"); + + let mut req = indexmap::IndexMap::new(); + req.insert( + "vendor2/package3".to_string(), + Link::new( + "vendor2/package2".to_string(), + "vendor2/package3".to_string(), + match_all(), + Some(Link::TYPE_REQUIRE.to_string()), + "1.4.*".to_string(), + ), + ); + req.insert( + "php".to_string(), + Link::new( + "vendor2/package2".to_string(), + "php".to_string(), + AnyConstraint::Multi(MultiConstraint::new( + vec![ + get_version_constraint(">=", "8.2.0.0"), + get_version_constraint("<", "9.0.0.0-dev"), + ], + true, + None, + )), + Some(Link::TYPE_REQUIRE.to_string()), + "^8.2".to_string(), + ), + ); + second_dev_required_package.__set_requires(req); + + let second_dev_nested_required_package = get_package("vendor2/package3", "1.4.0"); + + create_composer_lock( + &[some_required_package.clone()], + &[ + first_dev_required_package.clone(), + second_dev_required_package.clone(), + ], + ); + create_installed_json( + &[some_required_package.clone()], + &[ + first_dev_required_package.clone(), + second_dev_required_package.clone(), + second_dev_nested_required_package.clone(), + ], + true, + ); + + let input: Vec<(PhpMixed, PhpMixed)> = vec![ + (PhpMixed::from("command"), PhpMixed::from("why-not")), + ( + PhpMixed::from("package"), + PhpMixed::from(package_to_be_inspected), + ), + ( + PhpMixed::from("version"), + PhpMixed::from(package_version_to_be_inspected), + ), + ]; + + let mut app_tester = get_application_tester(); + app_tester.run(input, RunOptions::default()).unwrap(); + + assert_eq!(expected_status_code, app_tester.get_status_code()); + assert_eq!( + expected_output.trim(), + trim_lines(&app_tester.get_display()), + ); + + drop(tear_down); + } } diff --git a/crates/shirabe/tests/command/dump_autoload_command_test.rs b/crates/shirabe/tests/command/dump_autoload_command_test.rs index b3e79b3..1d302f5 100644 --- a/crates/shirabe/tests/command/dump_autoload_command_test.rs +++ b/crates/shirabe/tests/command/dump_autoload_command_test.rs @@ -1,73 +1,400 @@ //! ref: composer/tests/Composer/Test/Command/DumpAutoloadCommandTest.php +use crate::test_case::{RunOptions, get_application_tester, init_temp_composer}; +use regex::Regex; +use serial_test::serial; +use shirabe_php_shim::PhpMixed; + +/// ref: DumpAutoloadCommandTest::testDumpAutoload #[test] -#[ignore = "ApplicationTester / get_application_tester helper not implemented"] +#[serial] +#[ignore = "DumpAutoloadCommand::execute panics: composer_full_mut() holds a mut borrow of the composer RefCell across get_event_dispatcher().dispatch(), which re-enters via EventDispatcher::get_script_listeners -> PartialComposerHandle::borrow_partial (composer.rs:446) -> RefCell already mutably borrowed. Source bug in event_dispatcher.rs:1004 / dump_autoload_command.rs:88-91, not fixable from the test"] fn test_dump_autoload() { - todo!() + let tear_down = init_temp_composer(None, None, None, true); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![(PhpMixed::from("command"), PhpMixed::from("dump-autoload"))], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + + let output = app_tester.get_display(); + assert!(output.contains("Generating autoload files")); + assert!(output.contains("Generated autoload files")); + + drop(tear_down); } +/// ref: DumpAutoloadCommandTest::testDumpDevAutoload #[test] -#[ignore = "ApplicationTester / get_application_tester helper not implemented"] +#[serial] +#[ignore = "DumpAutoloadCommand::execute panics: composer_full_mut() holds a mut borrow of the composer RefCell across get_event_dispatcher().dispatch(), which re-enters via EventDispatcher::get_script_listeners -> PartialComposerHandle::borrow_partial (composer.rs:446) -> RefCell already mutably borrowed. Source bug in event_dispatcher.rs:1004 / dump_autoload_command.rs:88-91, not fixable from the test"] fn test_dump_dev_autoload() { - todo!() + let tear_down = init_temp_composer(None, None, None, true); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("dump-autoload")), + (PhpMixed::from("--dev"), PhpMixed::from(true)), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + + let output = app_tester.get_display(); + assert!(output.contains("Generating autoload files")); + assert!(output.contains("Generated autoload files")); + + drop(tear_down); } +/// ref: DumpAutoloadCommandTest::testDumpNoDevAutoload #[test] -#[ignore = "ApplicationTester / get_application_tester helper not implemented"] +#[serial] +#[ignore = "DumpAutoloadCommand::execute panics: composer_full_mut() holds a mut borrow of the composer RefCell across get_event_dispatcher().dispatch(), which re-enters via EventDispatcher::get_script_listeners -> PartialComposerHandle::borrow_partial (composer.rs:446) -> RefCell already mutably borrowed. Source bug in event_dispatcher.rs:1004 / dump_autoload_command.rs:88-91, not fixable from the test"] fn test_dump_no_dev_autoload() { - todo!() + let tear_down = init_temp_composer(None, None, None, true); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("dump-autoload")), + (PhpMixed::from("--dev"), PhpMixed::from(true)), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + + let output = app_tester.get_display(); + assert!(output.contains("Generating autoload files")); + assert!(output.contains("Generated autoload files")); + + drop(tear_down); } +/// ref: DumpAutoloadCommandTest::testUsingOptimizeAndStrictPsr #[test] -#[ignore = "ApplicationTester / get_application_tester helper not implemented"] +#[serial] +#[ignore = "DumpAutoloadCommand::execute panics: composer_full_mut() holds a mut borrow of the composer RefCell across get_event_dispatcher().dispatch(), which re-enters via EventDispatcher::get_script_listeners -> PartialComposerHandle::borrow_partial (composer.rs:446) -> RefCell already mutably borrowed. Source bug in event_dispatcher.rs:1004 / dump_autoload_command.rs:88-91, not fixable from the test"] fn test_using_optimize_and_strict_psr() { - todo!() + let tear_down = init_temp_composer(None, None, None, true); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("dump-autoload")), + (PhpMixed::from("--optimize"), PhpMixed::from(true)), + (PhpMixed::from("--strict-psr"), PhpMixed::from(true)), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + + let output = app_tester.get_display(); + assert!(output.contains("Generating optimized autoload files")); + let re = Regex::new(r"Generated optimized autoload files containing \d+ classes").unwrap(); + assert!(re.is_match(&output)); + + drop(tear_down); } +/// ref: DumpAutoloadCommandTest::testFailsUsingStrictPsrIfClassMapViolationsAreFound #[test] -#[ignore = "init_temp_composer / get_application_tester helpers not implemented"] +#[serial] +#[ignore = "DumpAutoloadCommand::execute panics: composer_full_mut() holds a mut borrow of the composer RefCell across get_event_dispatcher().dispatch(), which re-enters via EventDispatcher::get_script_listeners -> PartialComposerHandle::borrow_partial (composer.rs:446) -> RefCell already mutably borrowed. Source bug in event_dispatcher.rs:1004 / dump_autoload_command.rs:88-91, not fixable from the test"] fn test_fails_using_strict_psr_if_class_map_violations_are_found() { - todo!() + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "autoload": { + "psr-4": { + "Application\\": "src", + }, + }, + })), + None, + None, + true, + ); + let dir = tear_down.working_dir(); + std::fs::create_dir(dir.join("src")).unwrap(); + std::fs::write( + dir.join("src/Foo.php"), + "<?php namespace Application\\Src; class Foo {}", + ) + .unwrap(); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("dump-autoload")), + (PhpMixed::from("--optimize"), PhpMixed::from(true)), + (PhpMixed::from("--strict-psr"), PhpMixed::from(true)), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(1, status_code); + + let output = app_tester.get_display(); + let re = Regex::new( + r"Class Application\\Src\\Foo located in .*? does not comply with psr-4 autoloading standard \(rule: Application\\ => \./src\)\. Skipping\.", + ) + .unwrap(); + assert!(re.is_match(&output)); + + drop(tear_down); } +/// ref: DumpAutoloadCommandTest::testUsingClassmapAuthoritative #[test] -#[ignore = "ApplicationTester / get_application_tester helper not implemented"] +#[serial] +#[ignore = "DumpAutoloadCommand::execute panics: composer_full_mut() holds a mut borrow of the composer RefCell across get_event_dispatcher().dispatch(), which re-enters via EventDispatcher::get_script_listeners -> PartialComposerHandle::borrow_partial (composer.rs:446) -> RefCell already mutably borrowed. Source bug in event_dispatcher.rs:1004 / dump_autoload_command.rs:88-91, not fixable from the test"] fn test_using_classmap_authoritative() { - todo!() + let tear_down = init_temp_composer(None, None, None, true); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("dump-autoload")), + ( + PhpMixed::from("--classmap-authoritative"), + PhpMixed::from(true), + ), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + + let output = app_tester.get_display(); + assert!(output.contains("Generating optimized autoload files (authoritative)")); + let re = + Regex::new(r"Generated optimized autoload files \(authoritative\) containing \d+ classes") + .unwrap(); + assert!(re.is_match(&output)); + + drop(tear_down); } +/// ref: DumpAutoloadCommandTest::testUsingClassmapAuthoritativeAndStrictPsr #[test] -#[ignore = "ApplicationTester / get_application_tester helper not implemented"] +#[serial] +#[ignore = "DumpAutoloadCommand::execute panics: composer_full_mut() holds a mut borrow of the composer RefCell across get_event_dispatcher().dispatch(), which re-enters via EventDispatcher::get_script_listeners -> PartialComposerHandle::borrow_partial (composer.rs:446) -> RefCell already mutably borrowed. Source bug in event_dispatcher.rs:1004 / dump_autoload_command.rs:88-91, not fixable from the test"] fn test_using_classmap_authoritative_and_strict_psr() { - todo!() + let tear_down = init_temp_composer(None, None, None, true); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("dump-autoload")), + ( + PhpMixed::from("--classmap-authoritative"), + PhpMixed::from(true), + ), + (PhpMixed::from("--strict-psr"), PhpMixed::from(true)), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + + let output = app_tester.get_display(); + assert!(output.contains("Generating optimized autoload files")); + let re = + Regex::new(r"Generated optimized autoload files \(authoritative\) containing \d+ classes") + .unwrap(); + assert!(re.is_match(&output)); + + drop(tear_down); } +/// ref: DumpAutoloadCommandTest::testStrictPsrDoesNotWorkWithoutOptimizedAutoloader #[test] -#[ignore = "ApplicationTester / get_application_tester helper not implemented"] +#[serial] +#[ignore = "DumpAutoloadCommand::execute panics: composer_full_mut() holds a mut borrow of the composer RefCell across get_event_dispatcher().dispatch(), which re-enters via EventDispatcher::get_script_listeners -> PartialComposerHandle::borrow_partial (composer.rs:446) -> RefCell already mutably borrowed. Source bug in event_dispatcher.rs:1004 / dump_autoload_command.rs:88-91, not fixable from the test"] fn test_strict_psr_does_not_work_without_optimized_autoloader() { - todo!() + let tear_down = init_temp_composer(None, None, None, true); + + let mut app_tester = get_application_tester(); + let err = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("dump-autoload")), + (PhpMixed::from("--strict-psr"), PhpMixed::from(true)), + ], + RunOptions::default(), + ) + .expect_err("expected --strict-psr without optimize to error"); + assert!(err.to_string().contains( + "--strict-psr mode only works with optimized autoloader, use --optimize or --classmap-authoritative if you want a strict return value." + )); + + drop(tear_down); } +/// ref: DumpAutoloadCommandTest::testDevAndNoDevCannotBeCombined #[test] -#[ignore = "ApplicationTester / get_application_tester helper not implemented"] +#[serial] +#[ignore = "DumpAutoloadCommand::execute panics: composer_full_mut() holds a mut borrow of the composer RefCell across get_event_dispatcher().dispatch(), which re-enters via EventDispatcher::get_script_listeners -> PartialComposerHandle::borrow_partial (composer.rs:446) -> RefCell already mutably borrowed. Source bug in event_dispatcher.rs:1004 / dump_autoload_command.rs:88-91, not fixable from the test"] fn test_dev_and_no_dev_cannot_be_combined() { - todo!() + let tear_down = init_temp_composer(None, None, None, true); + + let mut app_tester = get_application_tester(); + let err = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("dump-autoload")), + (PhpMixed::from("--dev"), PhpMixed::from(true)), + (PhpMixed::from("--no-dev"), PhpMixed::from(true)), + ], + RunOptions::default(), + ) + .expect_err("expected --dev and --no-dev combination to error"); + assert!( + err.to_string() + .contains("You can not use both --no-dev and --dev as they conflict with each other.") + ); + + drop(tear_down); } +/// ref: DumpAutoloadCommandTest::testWithCustomAutoloaderSuffix #[test] -#[ignore = "init_temp_composer / get_application_tester helpers not implemented"] +#[serial] +#[ignore = "DumpAutoloadCommand::execute panics: composer_full_mut() holds a mut borrow of the composer RefCell across get_event_dispatcher().dispatch(), which re-enters via EventDispatcher::get_script_listeners -> PartialComposerHandle::borrow_partial (composer.rs:446) -> RefCell already mutably borrowed. Source bug in event_dispatcher.rs:1004 / dump_autoload_command.rs:88-91, not fixable from the test"] fn test_with_custom_autoloader_suffix() { - todo!() + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "config": { + "autoloader-suffix": "Foobar", + }, + })), + None, + None, + true, + ); + let dir = tear_down.working_dir(); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![(PhpMixed::from("command"), PhpMixed::from("dump-autoload"))], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + + let contents = std::fs::read_to_string(dir.join("vendor/autoload.php")).unwrap_or_default(); + assert!(contents.contains("ComposerAutoloaderInitFoobar")); + + drop(tear_down); } +/// ref: DumpAutoloadCommandTest::testWithExistingComposerLockAndAutoloaderSuffix #[test] -#[ignore = "init_temp_composer / get_application_tester helpers not implemented"] +#[serial] +#[ignore = "DumpAutoloadCommand::execute panics: composer_full_mut() holds a mut borrow of the composer RefCell across get_event_dispatcher().dispatch(), which re-enters via EventDispatcher::get_script_listeners -> PartialComposerHandle::borrow_partial (composer.rs:446) -> RefCell already mutably borrowed. Source bug in event_dispatcher.rs:1004 / dump_autoload_command.rs:88-91, not fixable from the test"] fn test_with_existing_composer_lock_and_autoloader_suffix() { - todo!() + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "config": { + "autoloader-suffix": "Foobar", + }, + })), + None, + Some(&serde_json::json!({ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically", + ], + "content-hash": "d751713988987e9331980363e24189ce", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.6.0", + })), + true, + ); + let dir = tear_down.working_dir(); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![(PhpMixed::from("command"), PhpMixed::from("dump-autoload"))], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + + let contents = std::fs::read_to_string(dir.join("vendor/autoload.php")).unwrap_or_default(); + assert!(contents.contains("ComposerAutoloaderInitFoobar")); + + drop(tear_down); } +/// ref: DumpAutoloadCommandTest::testWithExistingComposerLockWithoutAutoloaderSuffix #[test] -#[ignore = "init_temp_composer / get_application_tester helpers not implemented"] +#[serial] +#[ignore = "DumpAutoloadCommand::execute panics: composer_full_mut() holds a mut borrow of the composer RefCell across get_event_dispatcher().dispatch(), which re-enters via EventDispatcher::get_script_listeners -> PartialComposerHandle::borrow_partial (composer.rs:446) -> RefCell already mutably borrowed. Source bug in event_dispatcher.rs:1004 / dump_autoload_command.rs:88-91, not fixable from the test"] fn test_with_existing_composer_lock_without_autoloader_suffix() { - todo!() + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "name": "foo/bar", + })), + None, + Some(&serde_json::json!({ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically", + ], + "content-hash": "2d4a6be9a93712c5d6a119b26734a047", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.6.0", + })), + true, + ); + let dir = tear_down.working_dir(); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![(PhpMixed::from("command"), PhpMixed::from("dump-autoload"))], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code); + + let contents = std::fs::read_to_string(dir.join("vendor/autoload.php")).unwrap_or_default(); + assert!(contents.contains("ComposerAutoloaderInit2d4a6be9a93712c5d6a119b26734a047")); + + drop(tear_down); } diff --git a/crates/shirabe/tests/command/exec_command_test.rs b/crates/shirabe/tests/command/exec_command_test.rs index d182754..95649f7 100644 --- a/crates/shirabe/tests/command/exec_command_test.rs +++ b/crates/shirabe/tests/command/exec_command_test.rs @@ -1,13 +1,77 @@ //! ref: composer/tests/Composer/Test/Command/ExecCommandTest.php +use crate::test_case::{RunOptions, get_application_tester, init_temp_composer}; +use serial_test::serial; +use shirabe_php_shim::PhpMixed; + +/// ref: ExecCommandTest::testListThrowsIfNoBinariesExist #[test] -#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester with run/get_display) infrastructure"] +#[serial] fn test_list_throws_if_no_binaries_exist() { - todo!() + let tear_down = init_temp_composer(Some(&serde_json::json!({})), None, None, false); + let composer_dir = tear_down.working_dir(); + + let composer_bin_dir = format!("{}/vendor/bin", composer_dir.display()); + + let mut app_tester = get_application_tester(); + let err = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("exec")), + (PhpMixed::from("--list"), PhpMixed::from(true)), + ], + RunOptions::default(), + ) + .expect_err("exec --list with no binaries should raise a RuntimeException"); + + assert!( + err.to_string().contains(&format!( + "No binaries found in composer.json or in bin-dir ({})", + composer_bin_dir + )), + "expected RuntimeException about no binaries, got: {:?}", + err.to_string(), + ); + + drop(tear_down); } +/// ref: ExecCommandTest::testList #[test] -#[ignore = "missing TestCase::init_temp_composer and get_application_tester (ApplicationTester with run/get_display) infrastructure"] +#[serial] fn test_list() { - todo!() + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "bin": [ + "a", + ], + })), + None, + None, + false, + ); + let composer_dir = tear_down.working_dir(); + + let composer_bin_dir = format!("{}/vendor/bin", composer_dir.display()); + std::fs::create_dir_all(&composer_bin_dir).unwrap(); + std::fs::write(format!("{}/b", composer_bin_dir), "").unwrap(); + std::fs::write(format!("{}/b.bat", composer_bin_dir), "").unwrap(); + std::fs::write(format!("{}/c", composer_bin_dir), "").unwrap(); + + let mut app_tester = get_application_tester(); + app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("exec")), + (PhpMixed::from("--list"), PhpMixed::from(true)), + ], + RunOptions::default(), + ) + .unwrap(); + + let output = app_tester.get_display(); + + assert_eq!("Available binaries:\n- b\n- c\n- a (local)", output.trim(),); + + drop(tear_down); } diff --git a/crates/shirabe/tests/command/licenses_command_test.rs b/crates/shirabe/tests/command/licenses_command_test.rs index f680621..80708f6 100644 --- a/crates/shirabe/tests/command/licenses_command_test.rs +++ b/crates/shirabe/tests/command/licenses_command_test.rs @@ -79,9 +79,9 @@ fn assert_lines(display: &str, expected: &[Vec<&str>]) { #[test] #[serial] -#[ignore = "renders the text-format Table, which reaches shirabe_php_shim::instance_of (var.rs todo!()); \ - PhpMixed::Object carries no runtime class tag, so the Symfony Table helper cannot \ - distinguish TableSeparator/TableCell rows yet"] +#[ignore = "renders the text-format Table, which reaches shirabe_php_shim::instance_of \ + (var.rs:191 todo!()); PhpMixed::Object carries no runtime class tag, so the Symfony \ + Table helper cannot distinguish TableSeparator/TableCell rows yet"] fn test_basic_run() { let _tear_down = set_up(); @@ -111,8 +111,8 @@ fn test_basic_run() { #[test] #[serial] -#[ignore = "renders the text-format Table, which reaches shirabe_php_shim::instance_of (var.rs todo!()); \ - see test_basic_run"] +#[ignore = "renders the text-format Table, which reaches shirabe_php_shim::instance_of \ + (var.rs:191 todo!()); see test_basic_run"] fn test_no_dev() { let _tear_down = set_up(); @@ -180,8 +180,10 @@ fn test_format_json() { #[test] #[serial] -#[ignore = "renders a Table via SymfonyStyle::table, which reaches shirabe_php_shim::instance_of \ - (var.rs todo!()); see test_basic_run"] +#[ignore = "SymfonyStyle::table reaches \ + symfony_style.rs:445 is_console_output_interface() todo!() (downcasting \ + dyn OutputInterface to dyn ConsoleOutputInterface is not expressible with the current \ + trait design)"] fn test_format_summary() { let _tear_down = set_up(); @@ -244,8 +246,8 @@ fn test_format_unknown() { #[test] #[serial] -#[ignore = "renders the text-format Table, which reaches shirabe_php_shim::instance_of (var.rs todo!()); \ - see test_basic_run"] +#[ignore = "renders the text-format Table, which reaches shirabe_php_shim::instance_of \ + (var.rs:191 todo!()); see test_basic_run"] fn test_locked() { let _tear_down = set_up(); @@ -278,8 +280,8 @@ fn test_locked() { #[test] #[serial] -#[ignore = "renders the text-format Table, which reaches shirabe_php_shim::instance_of (var.rs todo!()); \ - see test_basic_run"] +#[ignore = "renders the text-format Table, which reaches shirabe_php_shim::instance_of \ + (var.rs:191 todo!()); see test_basic_run"] fn test_locked_no_dev() { let _tear_down = set_up(); 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); } diff --git a/crates/shirabe/tests/command/run_script_command_test.rs b/crates/shirabe/tests/command/run_script_command_test.rs index 366ee96..8e96cf3 100644 --- a/crates/shirabe/tests/command/run_script_command_test.rs +++ b/crates/shirabe/tests/command/run_script_command_test.rs @@ -1,31 +1,120 @@ //! ref: composer/tests/Composer/Test/Command/RunScriptCommandTest.php +use crate::test_case::{RunOptions, get_application_tester, init_temp_composer}; +use serial_test::serial; +use shirabe_php_shim::PhpMixed; + #[test] #[ignore = "requires PHPUnit getMockBuilder/onlyMethods partial mock of RunScriptCommand (override requireComposer/initialize/etc) plus expects()/with()/willReturn()/returnValueMap mocks of InputInterface/OutputInterface/EventDispatcher with a callback constraint on ScriptEvent; no mocking infrastructure exists"] fn test_detect_and_pass_dev_mode_to_event_and_to_dispatching() { todo!() } +/// ref: RunScriptCommandTest::testCanListScripts #[test] -#[ignore = "requires init_temp_composer and get_application_tester (ApplicationTester) infrastructure; neither exists"] +#[serial] +#[ignore = "Application::do_run registers composer.json scripts as commands; that path calls loader.register (class_loader.rs:288 -> spl_autoload_register at runtime.rs:231) which is a todo!() stub. With a 'scripts' key present, app_tester.run() panics there before the command executes"] fn test_can_list_scripts() { - todo!() + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "scripts": { + "test": "@php test", + "fix-cs": "php-cs-fixer fix", + }, + "scripts-descriptions": { + "fix-cs": "Run the codestyle fixer", + }, + })), + None, + None, + true, + ); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("run-script")), + (PhpMixed::from("--list"), PhpMixed::from(true)), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code, "assertCommandIsSuccessful"); + + let output = app_tester.get_display(); + + assert!( + output.contains("Runs the test script as defined in composer.json"), + "The default description for the test script should be printed" + ); + assert!( + output.contains("Run the codestyle fixer"), + "The custom description for the fix-cs script should be printed" + ); + + drop(tear_down); } +/// ref: RunScriptCommandTest::testCanDefineAliases #[test] -#[ignore = "requires init_temp_composer and get_application_tester (ApplicationTester) infrastructure; neither exists"] +#[serial] +#[ignore = "Application::do_run registers composer.json scripts as commands; that path calls loader.register (class_loader.rs:288 -> spl_autoload_register at runtime.rs:231) which is a todo!() stub. With a 'scripts' key present, app_tester.run() panics there before the command executes"] fn test_can_define_aliases() { - todo!() + let expected_aliases = vec!["one", "two", "three"]; + + let tear_down = init_temp_composer( + Some(&serde_json::json!({ + "scripts": { + "test": "@php test", + }, + "scripts-aliases": { + "test": expected_aliases, + }, + })), + None, + None, + true, + ); + + let mut app_tester = get_application_tester(); + let status_code = app_tester + .run( + vec![ + (PhpMixed::from("command"), PhpMixed::from("test")), + (PhpMixed::from("--help"), PhpMixed::from(true)), + (PhpMixed::from("--format"), PhpMixed::from("json")), + ], + RunOptions::default(), + ) + .unwrap(); + assert_eq!(0, status_code, "assertCommandIsSuccessful"); + + let output = app_tester.get_display(); + let array: serde_json::Value = serde_json::from_str(&output).unwrap(); + let mut actual_aliases: Vec<serde_json::Value> = array["usage"].as_array().unwrap().clone(); + actual_aliases.remove(0); + + let expected: Vec<serde_json::Value> = expected_aliases + .iter() + .map(|s| serde_json::Value::String(s.to_string())) + .collect(); + assert_eq!( + expected, actual_aliases, + "The custom aliases for the test command should be printed" + ); + + drop(tear_down); } #[test] -#[ignore = "requires init_temp_composer/get_application_tester (ApplicationTester) plus writing and executing a PHP-generated Symfony Command class (file_put_contents MyCommand.php); fundamentally unportable, no infrastructure exists"] +#[ignore = "requires writing and executing a PHP-generated Symfony Command class (file_put_contents MyCommand.php) loaded via composer autoload; fundamentally unportable, no PHP runtime command loading in shirabe"] fn test_execution_of_simple_symfony_command() { todo!() } #[test] -#[ignore = "requires init_temp_composer/get_application_tester (ApplicationTester) plus writing and executing a PHP-generated Symfony Command class (file_put_contents MyCommandWithDefinitions.php); fundamentally unportable, no infrastructure exists"] +#[ignore = "requires writing and executing a PHP-generated Symfony Command class (file_put_contents MyCommandWithDefinitions.php) loaded via composer autoload; fundamentally unportable, no PHP runtime command loading in shirabe"] fn test_execution_of_symfony_command_with_configuration() { todo!() } diff --git a/crates/shirabe/tests/command/search_command_test.rs b/crates/shirabe/tests/command/search_command_test.rs index 187d395..ebdd4bd 100644 --- a/crates/shirabe/tests/command/search_command_test.rs +++ b/crates/shirabe/tests/command/search_command_test.rs @@ -40,7 +40,10 @@ fn run_search_case(command: Vec<(PhpMixed, PhpMixed)>, expected: &str) { fn test_search() { // 'by name and description' run_search_case( - vec![("tokens".into(), PhpMixed::List(vec![PhpMixed::from("fancy")]))], + vec![( + "tokens".into(), + PhpMixed::List(vec![PhpMixed::from("fancy")]), + )], "bar/baz <warning>! Abandoned !</warning> fancy baz\nvendor-2/fancy-package", ); @@ -56,7 +59,10 @@ fn test_search() { // 'by name only' run_search_case( vec![ - ("tokens".into(), PhpMixed::List(vec![PhpMixed::from("fancy")])), + ( + "tokens".into(), + PhpMixed::List(vec![PhpMixed::from("fancy")]), + ), ("--only-name".into(), PhpMixed::from(true)), ], "vendor-2/fancy-package", @@ -74,7 +80,10 @@ fn test_search() { // 'by type' run_search_case( vec![ - ("tokens".into(), PhpMixed::List(vec![PhpMixed::from("vendor")])), + ( + "tokens".into(), + PhpMixed::List(vec![PhpMixed::from("vendor")]), + ), ("--type".into(), PhpMixed::from("foo")), ], "vendor-2/fancy-package", |
