aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--crates/shirabe/tests/command/base_dependency_command_test.rs599
-rw-r--r--crates/shirabe/tests/command/dump_autoload_command_test.rs375
-rw-r--r--crates/shirabe/tests/command/exec_command_test.rs72
-rw-r--r--crates/shirabe/tests/command/licenses_command_test.rs24
-rw-r--r--crates/shirabe/tests/command/repository_command_test.rs729
-rw-r--r--crates/shirabe/tests/command/run_script_command_test.rs101
-rw-r--r--crates/shirabe/tests/command/search_command_test.rs15
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",