aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/tests/util
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2026-06-22 02:09:59 +0900
committernsfisis <nsfisis@gmail.com>2026-06-22 02:09:59 +0900
commit822d9a872807a92a5337ee8b7bab96dc9845cdbb (patch)
tree4931365df5978caffade69cad2154718a9076f66 /crates/shirabe/tests/util
parentf691b864b687f251c3b266e8cff2774d730567ba (diff)
downloadphp-shirabe-822d9a872807a92a5337ee8b7bab96dc9845cdbb.tar.gz
php-shirabe-822d9a872807a92a5337ee8b7bab96dc9845cdbb.tar.zst
php-shirabe-822d9a872807a92a5337ee8b7bab96dc9845cdbb.zip
test: port more test cases
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/tests/util')
-rw-r--r--crates/shirabe/tests/util/auth_helper_test.rs40
-rw-r--r--crates/shirabe/tests/util/bitbucket_test.rs30
-rw-r--r--crates/shirabe/tests/util/error_handler_test.rs6
-rw-r--r--crates/shirabe/tests/util/filesystem_test.rs752
-rw-r--r--crates/shirabe/tests/util/forgejo_test.rs4
-rw-r--r--crates/shirabe/tests/util/git_test.rs14
-rw-r--r--crates/shirabe/tests/util/github_test.rs4
-rw-r--r--crates/shirabe/tests/util/gitlab_test.rs4
-rw-r--r--crates/shirabe/tests/util/http/proxy_manager_test.rs202
-rw-r--r--crates/shirabe/tests/util/http_downloader_test.rs100
-rw-r--r--crates/shirabe/tests/util/metadata_minifier_test.rs2
-rw-r--r--crates/shirabe/tests/util/perforce_test.rs211
-rw-r--r--crates/shirabe/tests/util/process_executor_test.rs174
-rw-r--r--crates/shirabe/tests/util/remote_filesystem_test.rs26
-rw-r--r--crates/shirabe/tests/util/stream_context_factory_test.rs66
-rw-r--r--crates/shirabe/tests/util/svn_test.rs12
-rw-r--r--crates/shirabe/tests/util/tls_helper_test.rs4
17 files changed, 1455 insertions, 196 deletions
diff --git a/crates/shirabe/tests/util/auth_helper_test.rs b/crates/shirabe/tests/util/auth_helper_test.rs
index 9eaeac1..21bf1c6 100644
--- a/crates/shirabe/tests/util/auth_helper_test.rs
+++ b/crates/shirabe/tests/util/auth_helper_test.rs
@@ -10,121 +10,121 @@ fn set_up() {
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_without_auth_credentials() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_bearer_password() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_github_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_gitlab_oath_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_options_for_client_certificate() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_gitlab_private_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_bitbucket_oath_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_bitbucket_public_url() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_basic_http_authentication() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn(); no mocking framework"]
fn test_add_authentication_header_with_custom_headers() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config in setUp; no mocking framework"]
fn test_is_public_bit_bucket_download_with_bitbucket_public_url() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config in setUp; no mocking framework"]
fn test_is_public_bit_bucket_download_with_non_bitbucket_public_url() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock Config/ConfigSourceInterface with expects()/willReturn(); no mocking framework"]
fn test_store_auth_automatically() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config/ConfigSourceInterface with willReturnCallback(); no mocking framework"]
fn test_store_auth_with_prompt_yes_answer() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config/ConfigSourceInterface with willReturnCallback(); no mocking framework"]
fn test_store_auth_with_prompt_no_answer() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config/ConfigSourceInterface with willReturnCallback(); no mocking framework"]
fn test_store_auth_with_prompt_invalid_answer() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config with expects()/willReturnMap(); no mocking framework"]
fn test_prompt_auth_if_needed_git_lab_no_auth_change() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface/Config with willReturnMap()/willReturnCallback(); no mocking framework"]
fn test_prompt_auth_if_needed_multiple_bitbucket_downloads() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface with expects()/willReturn() plus set_error_handler; no mocking framework"]
fn test_add_authentication_header_is_working() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config to drive AuthHelper; mocking is not available"]
+#[ignore = "requires PHPUnit mock IOInterface in setUp plus set_error_handler deprecation capture; no mocking framework"]
fn test_add_authentication_header_deprecation() {
todo!()
}
diff --git a/crates/shirabe/tests/util/bitbucket_test.rs b/crates/shirabe/tests/util/bitbucket_test.rs
index 4087294..3e3fad8 100644
--- a/crates/shirabe/tests/util/bitbucket_test.rs
+++ b/crates/shirabe/tests/util/bitbucket_test.rs
@@ -10,91 +10,91 @@ fn set_up() {
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_request_access_token_with_valid_oauth_consumer() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getMockBuilder mock for Config (no mock infrastructure)"]
fn test_request_access_token_with_valid_oauth_consumer_and_valid_stored_access_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_request_access_token_with_valid_oauth_consumer_and_expired_access_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_request_access_token_with_username_and_password() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_request_access_token_with_username_and_password_with_unauthorized_response() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_request_access_token_with_username_and_password_with_not_found_response() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_username_password_authentication_flow() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mock for Config (no mock infrastructure)"]
fn test_authorize_oauth_interactively_with_empty_username() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mock for Config (no mock infrastructure)"]
fn test_authorize_oauth_interactively_with_empty_password() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_authorize_oauth_interactively_with_request_access_token_failure() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config to construct Bitbucket (no mock infrastructure)"]
fn test_get_token_without_access_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getMockBuilder mock for Config and @depends-injected Bitbucket from a mock-based test (no mock infrastructure)"]
fn test_get_token_with_access_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config to construct Bitbucket (no mock infrastructure)"]
fn test_authorize_oauth_with_wrong_origin_url() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock, getProcessExecutorMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_authorize_oauth_without_available_git_config_token() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) for the Bitbucket OAuth flow"]
+#[ignore = "needs getIOMock/IOMock, getProcessExecutorMock and getMockBuilder mocks for HttpDownloader/Config (no mock infrastructure)"]
fn test_authorize_oauth_with_available_git_config_token() {
todo!()
}
diff --git a/crates/shirabe/tests/util/error_handler_test.rs b/crates/shirabe/tests/util/error_handler_test.rs
index 8f42bca..7295cf2 100644
--- a/crates/shirabe/tests/util/error_handler_test.rs
+++ b/crates/shirabe/tests/util/error_handler_test.rs
@@ -26,20 +26,20 @@ impl Drop for TearDown {
}
}
+#[ignore = "depends on PHP runtime routing an undefined-index notice through set_error_handler; no Rust equivalent for $array['baz'] triggering ErrorHandler::handle"]
#[test]
-#[ignore = "relies on PHP's set_error_handler converting an undefined-array-key notice into an ErrorException; no Rust equivalent"]
fn test_error_handler_capture_notice() {
todo!()
}
+#[ignore = "depends on PHP runtime emitting a TypeError/warning from array_merge([], 'string') via set_error_handler; no Rust equivalent"]
#[test]
-#[ignore = "relies on PHP's runtime turning an invalid array_merge call into a TypeError/ErrorException; no Rust equivalent"]
fn test_error_handler_capture_warning() {
todo!()
}
+#[ignore = "depends on the PHP @ error-suppression operator and trigger_error routing through set_error_handler; no Rust equivalent"]
#[test]
-#[ignore = "relies on PHP's @ error-suppression operator and set_error_handler; no Rust equivalent"]
fn test_error_handler_respects_at_operator() {
todo!()
}
diff --git a/crates/shirabe/tests/util/filesystem_test.rs b/crates/shirabe/tests/util/filesystem_test.rs
index 39fa256..9e41b1f 100644
--- a/crates/shirabe/tests/util/filesystem_test.rs
+++ b/crates/shirabe/tests/util/filesystem_test.rs
@@ -1,10 +1,13 @@
//! ref: composer/tests/Composer/Test/Util/FilesystemTest.php
// These exercise Filesystem path helpers and on-disk operations (sizes, copy, symlinks and
-// junctions over a temp tree). The filesystem fixtures and platform-specific symlink/junction
-// behaviour are not ported.
+// junctions over a temp tree). The on-disk tests build their temp tree with tempfile::TempDir in
+// place of TestCase::getUniqueTmpDirectory, which is not ported.
use shirabe::util::filesystem::Filesystem;
-use shirabe_php_shim::{dirname, is_dir, is_file};
+use shirabe::util::platform::Platform;
+use shirabe_php_shim::{
+ dirname, file_exists, file_put_contents, is_dir, is_file, mkdir, symlink, touch,
+};
#[allow(dead_code)]
struct SetUp {
@@ -51,74 +54,769 @@ impl Drop for TearDown {
}
}
+/// providePathCouplesAsCode: (a, b, directory, expected, static, prefer_relative)
+fn provide_path_couples_as_code()
+-> Vec<(&'static str, &'static str, bool, &'static str, bool, bool)> {
+ vec![
+ ("/foo/bar", "/foo/bar", false, "__FILE__", false, false),
+ (
+ "/foo/bar",
+ "/foo/baz",
+ false,
+ "__DIR__.'/baz'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bin/run",
+ "/foo/vendor/acme/bin/run",
+ false,
+ "dirname(__DIR__).'/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bin/run",
+ "/bar/bin/run",
+ false,
+ "'/bar/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "c:/bin/run",
+ "c:/vendor/acme/bin/run",
+ false,
+ "dirname(__DIR__).'/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "c:\\bin\\run",
+ "c:/vendor/acme/bin/run",
+ false,
+ "dirname(__DIR__).'/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "c:/bin/run",
+ "D:/vendor/acme/bin/run",
+ false,
+ "'D:/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "c:\\bin\\run",
+ "d:/vendor/acme/bin/run",
+ false,
+ "'D:/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ ("/foo/bar", "/foo/bar", true, "__DIR__", false, false),
+ ("/foo/bar/", "/foo/bar", true, "__DIR__", false, false),
+ (
+ "/foo",
+ "/baz",
+ true,
+ "dirname(__DIR__).'/baz'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bar",
+ "/foo/baz",
+ true,
+ "dirname(__DIR__).'/baz'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bin/run",
+ "/foo/vendor/acme/bin/run",
+ true,
+ "dirname(dirname(__DIR__)).'/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bin/run",
+ "/bar/bin/run",
+ true,
+ "'/bar/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "/app/vendor/foo/bar",
+ "/lib",
+ true,
+ "dirname(dirname(dirname(dirname(__DIR__)))).'/lib'",
+ false,
+ true,
+ ),
+ ("/bin/run", "/bin/run", true, "__DIR__", false, false),
+ ("c:/bin/run", "C:\\bin/run", true, "__DIR__", false, false),
+ (
+ "c:/bin/run",
+ "c:/vendor/acme/bin/run",
+ true,
+ "dirname(dirname(__DIR__)).'/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "c:\\bin\\run",
+ "c:/vendor/acme/bin/run",
+ true,
+ "dirname(dirname(__DIR__)).'/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "c:/bin/run",
+ "d:/vendor/acme/bin/run",
+ true,
+ "'D:/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "c:\\bin\\run",
+ "d:/vendor/acme/bin/run",
+ true,
+ "'D:/vendor/acme/bin/run'",
+ false,
+ false,
+ ),
+ (
+ "C:/Temp/test",
+ "C:\\Temp",
+ true,
+ "dirname(__DIR__)",
+ false,
+ false,
+ ),
+ (
+ "C:/Temp",
+ "C:\\Temp\\test",
+ true,
+ "__DIR__ . '/test'",
+ false,
+ false,
+ ),
+ ("/tmp/test", "/tmp", true, "dirname(__DIR__)", false, false),
+ ("/tmp", "/tmp/test", true, "__DIR__ . '/test'", false, false),
+ (
+ "C:/Temp",
+ "c:\\Temp\\test",
+ true,
+ "__DIR__ . '/test'",
+ false,
+ false,
+ ),
+ ("/tmp/test/./", "/tmp/test/", true, "__DIR__", false, false),
+ (
+ "/tmp/test/../vendor",
+ "/tmp/test",
+ true,
+ "dirname(__DIR__).'/test'",
+ false,
+ false,
+ ),
+ (
+ "/tmp/test/.././vendor",
+ "/tmp/test",
+ true,
+ "dirname(__DIR__).'/test'",
+ false,
+ false,
+ ),
+ (
+ "C:/Temp",
+ "c:\\Temp\\..\\..\\test",
+ true,
+ "dirname(__DIR__).'/test'",
+ false,
+ false,
+ ),
+ (
+ "C:/Temp/../..",
+ "d:\\Temp\\..\\..\\test",
+ true,
+ "'D:/test'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bar",
+ "/foo/bar_vendor",
+ true,
+ "dirname(__DIR__).'/bar_vendor'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bar_vendor",
+ "/foo/bar",
+ true,
+ "dirname(__DIR__).'/bar'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bar_vendor",
+ "/foo/bar/src",
+ true,
+ "dirname(__DIR__).'/bar/src'",
+ false,
+ false,
+ ),
+ (
+ "/foo/bar_vendor/src2",
+ "/foo/bar/src/lib",
+ true,
+ "dirname(dirname(__DIR__)).'/bar/src/lib'",
+ false,
+ false,
+ ),
+ // static use case
+ (
+ "/tmp/test/../vendor",
+ "/tmp/test",
+ true,
+ "__DIR__ . '/..'.'/test'",
+ true,
+ false,
+ ),
+ (
+ "/tmp/test/.././vendor",
+ "/tmp/test",
+ true,
+ "__DIR__ . '/..'.'/test'",
+ true,
+ false,
+ ),
+ (
+ "C:/Temp",
+ "c:\\Temp\\..\\..\\test",
+ true,
+ "__DIR__ . '/..'.'/test'",
+ true,
+ false,
+ ),
+ (
+ "C:/Temp/../..",
+ "d:\\Temp\\..\\..\\test",
+ true,
+ "'D:/test'",
+ true,
+ false,
+ ),
+ (
+ "/foo/bar",
+ "/foo/bar_vendor",
+ true,
+ "__DIR__ . '/..'.'/bar_vendor'",
+ true,
+ false,
+ ),
+ (
+ "/foo/bar_vendor",
+ "/foo/bar",
+ true,
+ "__DIR__ . '/..'.'/bar'",
+ true,
+ false,
+ ),
+ (
+ "/foo/bar_vendor",
+ "/foo/bar/src",
+ true,
+ "__DIR__ . '/..'.'/bar/src'",
+ true,
+ false,
+ ),
+ (
+ "/foo/bar_vendor/src2",
+ "/foo/bar/src/lib",
+ true,
+ "__DIR__ . '/../..'.'/bar/src/lib'",
+ true,
+ false,
+ ),
+ ]
+}
+
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_find_shortest_path_code() {
- todo!()
+ let fs = Filesystem::new(None);
+ for (a, b, directory, expected, static_code, prefer_relative) in provide_path_couples_as_code()
+ {
+ assert_eq!(
+ expected,
+ fs.find_shortest_path_code(a, b, directory, static_code, prefer_relative)
+ );
+ }
}
+/// providePathCouples: (a, b, expected, directory, prefer_relative)
+fn provide_path_couples() -> Vec<(&'static str, &'static str, &'static str, bool, bool)> {
+ vec![
+ ("/foo/bar", "/foo/bar", "./bar", false, false),
+ ("/foo/bar", "/foo/baz", "./baz", false, false),
+ ("/foo/bar/", "/foo/baz", "./baz", false, false),
+ ("/foo/bar", "/foo/bar", "./", true, false),
+ ("/foo/bar", "/foo/baz", "../baz", true, false),
+ ("/foo/bar/", "/foo/baz", "../baz", true, false),
+ ("C:/foo/bar/", "c:/foo/baz", "../baz", true, false),
+ (
+ "/foo/bin/run",
+ "/foo/vendor/acme/bin/run",
+ "../vendor/acme/bin/run",
+ false,
+ false,
+ ),
+ ("/foo/bin/run", "/bar/bin/run", "/bar/bin/run", false, false),
+ ("/foo/bin/run", "/bar/bin/run", "/bar/bin/run", true, false),
+ (
+ "c:/foo/bin/run",
+ "d:/bar/bin/run",
+ "D:/bar/bin/run",
+ true,
+ false,
+ ),
+ (
+ "c:/bin/run",
+ "c:/vendor/acme/bin/run",
+ "../vendor/acme/bin/run",
+ false,
+ false,
+ ),
+ (
+ "c:\\bin\\run",
+ "c:/vendor/acme/bin/run",
+ "../vendor/acme/bin/run",
+ false,
+ false,
+ ),
+ (
+ "c:/bin/run",
+ "d:/vendor/acme/bin/run",
+ "D:/vendor/acme/bin/run",
+ false,
+ false,
+ ),
+ (
+ "c:\\bin\\run",
+ "d:/vendor/acme/bin/run",
+ "D:/vendor/acme/bin/run",
+ false,
+ false,
+ ),
+ ("C:/Temp/test", "C:\\Temp", "./", false, false),
+ ("/tmp/test", "/tmp", "./", false, false),
+ ("C:/Temp/test/sub", "C:\\Temp", "../", false, false),
+ ("/tmp/test/sub", "/tmp", "../", false, false),
+ ("/tmp/test/sub", "/tmp", "../../", true, false),
+ ("c:/tmp/test/sub", "c:/tmp", "../../", true, false),
+ ("/tmp", "/tmp/test", "test", false, false),
+ ("C:/Temp", "C:\\Temp\\test", "test", false, false),
+ ("C:/Temp", "c:\\Temp\\test", "test", false, false),
+ ("/tmp/test/./", "/tmp/test", "./", true, false),
+ ("/tmp/test/../vendor", "/tmp/test", "../test", true, false),
+ ("/tmp/test/.././vendor", "/tmp/test", "../test", true, false),
+ ("C:/Temp", "c:\\Temp\\..\\..\\test", "../test", true, false),
+ (
+ "C:/Temp/../..",
+ "c:\\Temp\\..\\..\\test",
+ "./test",
+ true,
+ false,
+ ),
+ (
+ "C:/Temp/../..",
+ "D:\\Temp\\..\\..\\test",
+ "D:/test",
+ true,
+ false,
+ ),
+ ("/app/vendor/foo/bar", "/lib", "../../../../lib", true, true),
+ ("/tmp", "/tmp/../../test", "../test", true, false),
+ ("/tmp", "/test", "../test", true, false),
+ ("/foo/bar", "/foo/bar_vendor", "../bar_vendor", true, false),
+ ("/foo/bar_vendor", "/foo/bar", "../bar", true, false),
+ ("/foo/bar_vendor", "/foo/bar/src", "../bar/src", true, false),
+ (
+ "/foo/bar_vendor/src2",
+ "/foo/bar/src/lib",
+ "../../bar/src/lib",
+ true,
+ false,
+ ),
+ ("C:/", "C:/foo/bar/", "foo/bar", true, false),
+ ]
+}
+
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_find_shortest_path() {
- todo!()
+ let fs = Filesystem::new(None);
+ for (a, b, expected, directory, prefer_relative) in provide_path_couples() {
+ assert_eq!(
+ expected,
+ fs.find_shortest_path(a, b, directory, prefer_relative)
+ );
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_remove_directory_php() {
- todo!()
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let working_dir = working_dir.path().to_str().unwrap().to_string();
+
+ mkdir(&format!("{working_dir}/level1/level2"), 0o777, true);
+ file_put_contents(
+ &format!("{working_dir}/level1/level2/hello.txt"),
+ b"hello world",
+ );
+
+ let mut fs = Filesystem::new(None);
+ assert!(fs.remove_directory_php(&working_dir).unwrap());
+ assert!(!file_exists(format!(
+ "{working_dir}/level1/level2/hello.txt"
+ )));
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_file_size() {
- todo!()
+ let unique_tmp = tempfile::TempDir::new().unwrap();
+ let test_file = format!("{}/composer_test_file", unique_tmp.path().to_str().unwrap());
+
+ file_put_contents(&test_file, b"Hello");
+
+ let fs = Filesystem::new(None);
+ assert!(fs.size(&test_file).unwrap() >= 5);
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_directory_size() {
- todo!()
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let working_dir = working_dir.path().to_str().unwrap().to_string();
+
+ mkdir(&working_dir, 0o777, true);
+ file_put_contents(&format!("{working_dir}/file1.txt"), b"Hello");
+ file_put_contents(&format!("{working_dir}/file2.txt"), b"World");
+
+ let fs = Filesystem::new(None);
+ assert!(fs.size(&working_dir).unwrap() >= 10);
}
+/// provideNormalizedPaths: (expected, actual)
+fn provide_normalized_paths() -> Vec<(&'static str, &'static str)> {
+ vec![
+ ("../foo", "../foo"),
+ ("C:/foo/bar", "c:/foo//bar"),
+ ("C:/foo/bar", "C:/foo/./bar"),
+ ("C:/foo/bar", "C://foo//bar"),
+ ("C:/foo/bar", "C:///foo//bar"),
+ ("C:/bar", "C:/foo/../bar"),
+ ("/bar", "/foo/../bar/"),
+ ("phar://C:/Foo", "phar://c:/Foo/Bar/.."),
+ ("phar://C:/Foo", "phar://c:///Foo/Bar/.."),
+ ("phar://C:/", "phar://c:/Foo/Bar/../../../.."),
+ ("/", "/Foo/Bar/../../../.."),
+ ("/", "/"),
+ ("/", "//"),
+ ("/", "///"),
+ ("/Foo", "///Foo"),
+ ("C:/", "c:\\"),
+ ("../src", "Foo/Bar/../../../src"),
+ ("C:../b", "c:.\\..\\a\\..\\b"),
+ ("phar://C:../Foo", "phar://c:../Foo"),
+ ("//foo/bar", "\\\\foo\\bar"),
+ ]
+}
+
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_normalize_path() {
- todo!()
+ let fs = Filesystem::new(None);
+ for (expected, actual) in provide_normalized_paths() {
+ assert_eq!(expected, fs.normalize_path(actual));
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_unlink_symlinked_directory() {
- todo!()
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let basepath = working_dir.path().to_str().unwrap().to_string();
+ let symlinked = format!("{basepath}/linked");
+ mkdir(&format!("{basepath}/real"), 0o777, true);
+ touch(&format!("{basepath}/real/FILE"));
+
+ let result = symlink(&format!("{basepath}/real"), &symlinked);
+
+ if !result {
+ // Symbolic links for directories not supported on this platform.
+ return;
+ }
+
+ if !is_dir(&symlinked) {
+ panic!("Precondition assertion failed (is_dir is false on symbolic link to directory).");
+ }
+
+ let fs = Filesystem::new(None);
+ let result = fs.unlink(&symlinked).unwrap();
+ assert!(result);
+ assert!(!file_exists(&symlinked));
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_remove_symlinked_directory_with_trailing_slash() {
- todo!()
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let working_dir = working_dir.path().to_str().unwrap().to_string();
+
+ mkdir(&format!("{working_dir}/real"), 0o777, true);
+ touch(&format!("{working_dir}/real/FILE"));
+ let symlinked = format!("{working_dir}/linked");
+ let symlinked_trailing_slash = format!("{symlinked}/");
+
+ let result = symlink(&format!("{working_dir}/real"), &symlinked);
+
+ if !result {
+ // Symbolic links for directories not supported on this platform.
+ return;
+ }
+
+ if !is_dir(&symlinked) {
+ panic!("Precondition assertion failed (is_dir is false on symbolic link to directory).");
+ }
+
+ if !is_dir(&symlinked_trailing_slash) {
+ panic!("Precondition assertion failed (is_dir false w trailing slash).");
+ }
+
+ let mut fs = Filesystem::new(None);
+
+ let result = fs.remove_directory(&symlinked_trailing_slash).unwrap();
+ assert!(result);
+ assert!(!file_exists(&symlinked_trailing_slash));
+ assert!(!file_exists(&symlinked));
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_junctions() {
- todo!()
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let working_dir = working_dir.path().to_str().unwrap().to_string();
+
+ mkdir(&format!("{working_dir}/real/nesting/testing"), 0o777, true);
+ let mut fs = Filesystem::new(None);
+
+ // Non-Windows systems do not support this and will return false on all tests, and an exception
+ // on creation.
+ if !Platform::is_windows() {
+ assert!(!fs.is_junction(&working_dir));
+ assert!(!fs.remove_junction(&working_dir).unwrap());
+
+ let target = format!("{working_dir}/real/../real/nesting");
+ let junction = format!("{working_dir}/junction");
+ let err = fs.junction(&target, &junction).unwrap_err();
+ assert!(
+ err.to_string()
+ .contains("not available on non-Windows platform")
+ );
+ return;
+ }
+
+ let target = format!("{working_dir}/real/../real/nesting");
+ let junction = format!("{working_dir}/junction");
+
+ // Create and detect junction
+ fs.junction(&target, &junction).unwrap();
+ assert!(fs.is_junction(&junction), "{junction}: is a junction");
+ assert!(!fs.is_junction(&target), "{target}: is not a junction");
+ assert!(
+ fs.is_junction(&format!("{target}/../../junction")),
+ "{target}/../../junction: is a junction"
+ );
+ assert!(
+ !fs.is_junction(&format!("{junction}/../real")),
+ "{junction}/../real: is not a junction"
+ );
+ assert!(
+ fs.is_junction(&format!("{junction}/../junction")),
+ "{junction}/../junction: is a junction"
+ );
+
+ // Remove junction
+ assert!(is_dir(&junction), "{junction} is a directory");
+ assert!(
+ fs.remove_junction(&junction).unwrap(),
+ "{junction} has been removed"
+ );
+ assert!(!is_dir(&junction), "{junction} is not a directory");
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_override_junctions() {
- todo!()
+ if !Platform::is_windows() {
+ // Only runs on windows.
+ return;
+ }
+
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let working_dir = working_dir.path().to_str().unwrap().to_string();
+
+ mkdir(&format!("{working_dir}/real/nesting/testing"), 0o777, true);
+ let mut fs = Filesystem::new(None);
+
+ let old_target = format!("{working_dir}/real/nesting/testing");
+ let target = format!("{working_dir}/real/../real/nesting");
+ let junction = format!("{working_dir}/junction");
+
+ // Override non-broken junction
+ fs.junction(&old_target, &junction).unwrap();
+ fs.junction(&target, &junction).unwrap();
+
+ assert!(fs.is_junction(&junction), "{junction}: is a junction");
+ assert!(
+ fs.is_junction(&format!("{target}/../../junction")),
+ "{target}/../../junction: is a junction"
+ );
+
+ // Remove junction
+ assert!(
+ fs.remove_junction(&junction).unwrap(),
+ "{junction} has been removed"
+ );
+
+ // Override broken junction
+ fs.junction(&old_target, &junction).unwrap();
+ fs.remove_directory(&old_target).unwrap();
+ fs.junction(&target, &junction).unwrap();
+
+ assert!(fs.is_junction(&junction), "{junction}: is a junction");
+ assert!(
+ fs.is_junction(&format!("{target}/../../junction")),
+ "{target}/../../junction: is a junction"
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_copy() {
- todo!()
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let working_dir = working_dir.path().to_str().unwrap().to_string();
+ let unique_tmp = tempfile::TempDir::new().unwrap();
+ let test_file = format!("{}/composer_test_file", unique_tmp.path().to_str().unwrap());
+
+ mkdir(&format!("{working_dir}/foo/bar"), 0o777, true);
+ mkdir(&format!("{working_dir}/foo/baz"), 0o777, true);
+ file_put_contents(&format!("{working_dir}/foo/foo.file"), b"foo");
+ file_put_contents(&format!("{working_dir}/foo/bar/foobar.file"), b"foobar");
+ file_put_contents(&format!("{working_dir}/foo/baz/foobaz.file"), b"foobaz");
+ file_put_contents(&test_file, b"testfile");
+
+ let mut fs = Filesystem::new(None);
+
+ let result1 = fs
+ .copy(
+ &format!("{working_dir}/foo"),
+ &format!("{working_dir}/foop"),
+ )
+ .unwrap();
+ assert!(result1, "Copying directory failed.");
+ assert!(
+ is_dir(format!("{working_dir}/foop")),
+ "Not a directory: {working_dir}/foop"
+ );
+ assert!(
+ is_dir(format!("{working_dir}/foop/bar")),
+ "Not a directory: {working_dir}/foop/bar"
+ );
+ assert!(
+ is_dir(format!("{working_dir}/foop/baz")),
+ "Not a directory: {working_dir}/foop/baz"
+ );
+ assert!(
+ file_exists(format!("{working_dir}/foop/foo.file")),
+ "Not a file: {working_dir}/foop/foo.file"
+ );
+ assert!(
+ file_exists(format!("{working_dir}/foop/bar/foobar.file")),
+ "Not a file: {working_dir}/foop/bar/foobar.file"
+ );
+ assert!(
+ file_exists(format!("{working_dir}/foop/baz/foobaz.file")),
+ "Not a file: {working_dir}/foop/baz/foobaz.file"
+ );
+
+ let result2 = fs
+ .copy(&test_file, &format!("{working_dir}/testfile.file"))
+ .unwrap();
+ assert!(result2);
+ assert!(file_exists(format!("{working_dir}/testfile.file")));
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (Filesystem path helpers plus on-disk size/copy/symlink/junction fixtures)"]
fn test_copy_then_remove() {
- todo!()
+ let working_dir = tempfile::TempDir::new().unwrap();
+ let working_dir = working_dir.path().to_str().unwrap().to_string();
+ let unique_tmp = tempfile::TempDir::new().unwrap();
+ let test_file = format!("{}/composer_test_file", unique_tmp.path().to_str().unwrap());
+
+ mkdir(&format!("{working_dir}/foo/bar"), 0o777, true);
+ mkdir(&format!("{working_dir}/foo/baz"), 0o777, true);
+ file_put_contents(&format!("{working_dir}/foo/foo.file"), b"foo");
+ file_put_contents(&format!("{working_dir}/foo/bar/foobar.file"), b"foobar");
+ file_put_contents(&format!("{working_dir}/foo/baz/foobaz.file"), b"foobaz");
+ file_put_contents(&test_file, b"testfile");
+
+ let mut fs = Filesystem::new(None);
+
+ fs.copy_then_remove(&test_file, &format!("{working_dir}/testfile.file"))
+ .unwrap();
+ assert!(!file_exists(&test_file), "Still a file: {test_file}");
+
+ fs.copy_then_remove(
+ &format!("{working_dir}/foo"),
+ &format!("{working_dir}/foop"),
+ )
+ .unwrap();
+ assert!(
+ !file_exists(format!("{working_dir}/foo/baz/foobaz.file")),
+ "Still a file: {working_dir}/foo/baz/foobaz.file"
+ );
+ assert!(
+ !file_exists(format!("{working_dir}/foo/bar/foobar.file")),
+ "Still a file: {working_dir}/foo/bar/foobar.file"
+ );
+ assert!(
+ !file_exists(format!("{working_dir}/foo/foo.file")),
+ "Still a file: {working_dir}/foo/foo.file"
+ );
+ assert!(
+ !is_dir(format!("{working_dir}/foo/baz")),
+ "Still a directory: {working_dir}/foo/baz"
+ );
+ assert!(
+ !is_dir(format!("{working_dir}/foo/bar")),
+ "Still a directory: {working_dir}/foo/bar"
+ );
+ assert!(
+ !is_dir(format!("{working_dir}/foo")),
+ "Still a directory: {working_dir}/foo"
+ );
}
diff --git a/crates/shirabe/tests/util/forgejo_test.rs b/crates/shirabe/tests/util/forgejo_test.rs
index 2cae2ac..e8bf766 100644
--- a/crates/shirabe/tests/util/forgejo_test.rs
+++ b/crates/shirabe/tests/util/forgejo_test.rs
@@ -5,13 +5,13 @@
// available, and a real HttpDownloader reaches curl_multi_init (todo!()).
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader for the auth flow; a real HttpDownloader reaches curl_multi_init (todo!())"]
+#[ignore = "requires getIOMock/getHttpDownloaderMock and getMockBuilder mocks of Config/JsonConfigSource with expects()/willReturn(); no mocking infrastructure exists"]
fn test_username_password_authentication_flow() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader for the auth flow; a real HttpDownloader reaches curl_multi_init (todo!())"]
+#[ignore = "requires getIOMock/getHttpDownloaderMock and getMockBuilder mocks of Config/JsonConfigSource with expects()/willReturn(); no mocking infrastructure exists"]
fn test_username_password_failure() {
todo!()
}
diff --git a/crates/shirabe/tests/util/git_test.rs b/crates/shirabe/tests/util/git_test.rs
index a78ae88..40ca9da 100644
--- a/crates/shirabe/tests/util/git_test.rs
+++ b/crates/shirabe/tests/util/git_test.rs
@@ -10,46 +10,46 @@ fn set_up() {
}
#[test]
-#[ignore = "mocks IO/Config/ProcessExecutor to drive Git; mocking is not available"]
+#[ignore = "requires mocked Config (getMockBuilder Config) and getProcessExecutorMock with expects() command expectations; no mocking infrastructure exists"]
fn test_run_command_public_git_hub_repository_not_initial_clone() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/ProcessExecutor to drive Git; mocking is not available"]
+#[ignore = "requires mocked Config and getProcessExecutorMock with expects() command expectations; no mocking infrastructure exists"]
fn test_run_command_private_git_hub_repository_not_initial_clone_not_interactive_without_authentication()
{
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/ProcessExecutor to drive Git; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock and mocked IO (getMockBuilder IOInterface with hasAuthentication/getAuthentication/isInteractive expectations); no mocking infrastructure exists"]
fn test_run_command_private_git_hub_repository_not_initial_clone_not_interactive_with_authentication()
{
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/ProcessExecutor to drive Git; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock and mocked IO/Config (getMockBuilder with hasAuthentication/getAuthentication/isInteractive expectations); no mocking infrastructure exists"]
fn test_run_command_private_bitbucket_repository_not_initial_clone_not_interactive_with_authentication()
{
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/ProcessExecutor to drive Git; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock, getHttpDownloaderMock and mocked IO/Config with askConfirmation/askAndHideAnswer/setAuthentication expectations; no mocking infrastructure exists"]
fn test_run_command_private_bitbucket_repository_not_initial_clone_interactive_with_oauth() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/ProcessExecutor to drive Git; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock with expects() command expectations and mocked Config/Filesystem (getMockBuilder removeDirectory); no mocking infrastructure exists"]
fn test_sync_mirror_sanitizes_url_after_initial_clone() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/ProcessExecutor to drive Git; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock with expects() command expectations and mocked Config; no mocking infrastructure exists"]
fn test_sync_mirror_sanitizes_url_even_after_failed_update() {
todo!()
}
diff --git a/crates/shirabe/tests/util/github_test.rs b/crates/shirabe/tests/util/github_test.rs
index 019b858..5caf5c7 100644
--- a/crates/shirabe/tests/util/github_test.rs
+++ b/crates/shirabe/tests/util/github_test.rs
@@ -5,13 +5,13 @@
// available, and a real HttpDownloader reaches curl_multi_init (todo!()).
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader for the auth flow; a real HttpDownloader reaches curl_multi_init (todo!())"]
+#[ignore = "requires getIOMock/getHttpDownloaderMock and getMockBuilder mocks of Config/JsonConfigSource with expects()/willReturn(); no mocking infrastructure exists"]
fn test_username_password_authentication_flow() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader for the auth flow; a real HttpDownloader reaches curl_multi_init (todo!())"]
+#[ignore = "requires getIOMock/getHttpDownloaderMock and getMockBuilder mocks of Config/JsonConfigSource with expects()/willReturn(); no mocking infrastructure exists"]
fn test_username_password_failure() {
todo!()
}
diff --git a/crates/shirabe/tests/util/gitlab_test.rs b/crates/shirabe/tests/util/gitlab_test.rs
index 27b7258..e7c8bf4 100644
--- a/crates/shirabe/tests/util/gitlab_test.rs
+++ b/crates/shirabe/tests/util/gitlab_test.rs
@@ -4,14 +4,14 @@
// HttpDownloader to drive the username/password authentication flow. Mocking is not
// available, and a real HttpDownloader reaches curl_multi_init (todo!()).
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config/JsonConfigSource (no mock infrastructure)"]
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader for the auth flow; a real HttpDownloader reaches curl_multi_init (todo!())"]
fn test_username_password_authentication_flow() {
todo!()
}
+#[ignore = "needs getIOMock/IOMock and getMockBuilder mocks for HttpDownloader/Config/JsonConfigSource (no mock infrastructure)"]
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader for the auth flow; a real HttpDownloader reaches curl_multi_init (todo!())"]
fn test_username_password_failure() {
todo!()
}
diff --git a/crates/shirabe/tests/util/http/proxy_manager_test.rs b/crates/shirabe/tests/util/http/proxy_manager_test.rs
index 0c177f7..dede524 100644
--- a/crates/shirabe/tests/util/http/proxy_manager_test.rs
+++ b/crates/shirabe/tests/util/http/proxy_manager_test.rs
@@ -38,7 +38,7 @@ impl Drop for TearDown {
}
#[test]
-#[ignore = "not yet ported (ProxyManager is driven by proxy environment variables)"]
+#[ignore = "ProxyManager::get_instance returns a shared &'static Mutex, so instance identity (=== / after reset) cannot be expressed through the public API"]
fn test_instantiation() {
let _tear_down = TearDown;
set_up();
@@ -46,49 +46,225 @@ fn test_instantiation() {
}
#[test]
-#[ignore = "not yet ported (ProxyManager is driven by proxy environment variables)"]
+#[ignore]
fn test_get_proxy_for_request_throws_on_bad_proxy_url() {
let _tear_down = TearDown;
set_up();
- todo!()
+
+ Platform::put_env("http_proxy", "localhost");
+ ProxyManager::reset();
+ let mutex = ProxyManager::get_instance();
+ let guard = mutex.lock().unwrap();
+ let proxy_manager = guard.as_ref().unwrap();
+
+ assert!(
+ proxy_manager
+ .get_proxy_for_request("http://example.com")
+ .is_err()
+ );
}
#[test]
-#[ignore = "not yet ported (ProxyManager is driven by proxy environment variables)"]
+#[ignore]
fn test_lowercase_overrides_uppercase() {
let _tear_down = TearDown;
set_up();
- todo!()
+
+ // server, url, expectedUrl
+ let cases: Vec<(Vec<(&str, &str)>, &str, &str)> = vec![
+ (
+ vec![
+ ("HTTP_PROXY", "http://upper.com"),
+ ("http_proxy", "http://lower.com"),
+ ],
+ "http://repo.org",
+ "http://lower.com:80",
+ ),
+ (
+ vec![
+ ("CGI_HTTP_PROXY", "http://upper.com"),
+ ("cgi_http_proxy", "http://lower.com"),
+ ],
+ "http://repo.org",
+ "http://lower.com:80",
+ ),
+ (
+ vec![
+ ("HTTPS_PROXY", "http://upper.com"),
+ ("https_proxy", "http://lower.com"),
+ ],
+ "https://repo.org",
+ "http://lower.com:80",
+ ),
+ ];
+
+ for (server, url, expected_url) in cases {
+ set_up();
+ for (name, value) in &server {
+ Platform::put_env(name, value);
+ }
+ ProxyManager::reset();
+
+ let mutex = ProxyManager::get_instance();
+ let guard = mutex.lock().unwrap();
+ let proxy = guard.as_ref().unwrap().get_proxy_for_request(url).unwrap();
+ assert_eq!(expected_url, proxy.get_status(None).unwrap());
+ }
}
#[test]
-#[ignore = "not yet ported (ProxyManager is driven by proxy environment variables)"]
+#[ignore]
fn test_cgi_proxy_is_only_used_when_no_http_proxy() {
let _tear_down = TearDown;
set_up();
- todo!()
+
+ // server, expectedUrl
+ let cases: Vec<(Vec<(&str, &str)>, &str)> = vec![
+ (
+ vec![("CGI_HTTP_PROXY", "http://cgi.com:80")],
+ "http://cgi.com:80",
+ ),
+ (
+ vec![
+ ("http_proxy", "http://http.com:80"),
+ ("CGI_HTTP_PROXY", "http://cgi.com:80"),
+ ],
+ "http://http.com:80",
+ ),
+ ];
+
+ for (server, expected_url) in cases {
+ set_up();
+ for (name, value) in &server {
+ Platform::put_env(name, value);
+ }
+ ProxyManager::reset();
+
+ let mutex = ProxyManager::get_instance();
+ let guard = mutex.lock().unwrap();
+ let proxy = guard
+ .as_ref()
+ .unwrap()
+ .get_proxy_for_request("http://repo.org")
+ .unwrap();
+ assert_eq!(expected_url, proxy.get_status(None).unwrap());
+ }
}
#[test]
-#[ignore = "not yet ported (ProxyManager is driven by proxy environment variables)"]
+#[ignore]
fn test_no_http_proxy_does_not_use_https_proxy() {
let _tear_down = TearDown;
set_up();
- todo!()
+
+ Platform::put_env("https_proxy", "https://proxy.com:443");
+ ProxyManager::reset();
+ let mutex = ProxyManager::get_instance();
+ let guard = mutex.lock().unwrap();
+ let proxy = guard
+ .as_ref()
+ .unwrap()
+ .get_proxy_for_request("http://repo.org")
+ .unwrap();
+ assert_eq!("", proxy.get_status(None).unwrap());
}
#[test]
-#[ignore = "not yet ported (ProxyManager is driven by proxy environment variables)"]
+#[ignore]
fn test_no_https_proxy_does_not_use_http_proxy() {
let _tear_down = TearDown;
set_up();
- todo!()
+
+ Platform::put_env("http_proxy", "http://proxy.com:80");
+ ProxyManager::reset();
+ let mutex = ProxyManager::get_instance();
+ let guard = mutex.lock().unwrap();
+ let proxy = guard
+ .as_ref()
+ .unwrap()
+ .get_proxy_for_request("https://repo.org")
+ .unwrap();
+ assert_eq!("", proxy.get_status(None).unwrap());
}
#[test]
-#[ignore = "not yet ported (ProxyManager is driven by proxy environment variables)"]
+#[ignore]
fn test_get_proxy_for_request() {
+ use indexmap::IndexMap;
+ use shirabe_php_shim::PhpMixed;
+
let _tear_down = TearDown;
set_up();
- todo!()
+
+ let server = vec![
+ ("http_proxy", "http://user:p%40ss@proxy.com"),
+ ("https_proxy", "https://proxy.com:443"),
+ ("no_proxy", "other.repo.org"),
+ ];
+
+ let http_options =
+ |pairs: &[(&str, PhpMixed)]| -> Option<IndexMap<String, IndexMap<String, PhpMixed>>> {
+ let mut http: IndexMap<String, PhpMixed> = IndexMap::new();
+ for (k, v) in pairs {
+ http.insert((*k).to_string(), v.clone());
+ }
+ let mut options: IndexMap<String, IndexMap<String, PhpMixed>> = IndexMap::new();
+ options.insert("http".to_string(), http);
+ Some(options)
+ };
+
+ // server, url, options, status, excluded
+ let cases: Vec<(
+ Vec<(&str, &str)>,
+ &str,
+ Option<IndexMap<String, IndexMap<String, PhpMixed>>>,
+ &str,
+ bool,
+ )> = vec![
+ (vec![], "http://repo.org", None, "", false),
+ (
+ server.clone(),
+ "http://repo.org",
+ http_options(&[
+ ("proxy", PhpMixed::String("tcp://proxy.com:80".to_string())),
+ (
+ "header",
+ PhpMixed::String("Proxy-Authorization: Basic dXNlcjpwQHNz".to_string()),
+ ),
+ ("request_fulluri", PhpMixed::Bool(true)),
+ ]),
+ "http://***:***@proxy.com:80",
+ false,
+ ),
+ (
+ server.clone(),
+ "https://repo.org",
+ http_options(&[("proxy", PhpMixed::String("ssl://proxy.com:443".to_string()))]),
+ "https://proxy.com:443",
+ false,
+ ),
+ (
+ server.clone(),
+ "https://other.repo.org",
+ None,
+ "excluded by no_proxy",
+ true,
+ ),
+ ];
+
+ for (srv, url, options, status, excluded) in cases {
+ set_up();
+ for (name, value) in &srv {
+ Platform::put_env(name, value);
+ }
+ ProxyManager::reset();
+
+ let mutex = ProxyManager::get_instance();
+ let guard = mutex.lock().unwrap();
+ let proxy = guard.as_ref().unwrap().get_proxy_for_request(url).unwrap();
+
+ assert_eq!(options.as_ref(), proxy.get_context_options());
+ assert_eq!(status, proxy.get_status(None).unwrap());
+ assert_eq!(excluded, proxy.is_excluded_by_no_proxy());
+ }
}
diff --git a/crates/shirabe/tests/util/http_downloader_test.rs b/crates/shirabe/tests/util/http_downloader_test.rs
index 238fe83..5c34e19 100644
--- a/crates/shirabe/tests/util/http_downloader_test.rs
+++ b/crates/shirabe/tests/util/http_downloader_test.rs
@@ -1,13 +1,107 @@
//! ref: composer/tests/Composer/Test/Util/HttpDownloaderTest.php
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::io::IOInterface;
+use shirabe::io::buffer_io::BufferIO;
+use shirabe::util::http_downloader::HttpDownloader;
+use shirabe_external_packages::symfony::console::output::output_interface::VERBOSITY_NORMAL;
+use shirabe_php_shim::{PHP_EOL, PhpMixed};
+
#[test]
-#[ignore = "constructs a real HttpDownloader (curl_multi_init is todo!()) and mocks a Config; performs a network request"]
+#[ignore = "asserts IOInterface mock ->expects()->method('setAuthentication')->with(...) and performs a live HTTP get; no mock infrastructure exists"]
fn test_capture_authentication_params_from_url() {
todo!()
}
#[test]
-#[ignore = "constructs a real HttpDownloader (curl_multi_init is todo!()) and mocks a Config; performs a network request"]
+#[ignore]
fn test_output_warnings() {
- todo!()
+ let io: Rc<RefCell<BufferIO>> = Rc::new(RefCell::new(
+ BufferIO::new(String::new(), VERBOSITY_NORMAL, None).unwrap(),
+ ));
+ let io_dyn: Rc<RefCell<dyn IOInterface>> = io.clone();
+
+ HttpDownloader::output_warnings(io_dyn.clone(), "$URL", &IndexMap::new()).unwrap();
+ assert_eq!("", io.borrow().get_output());
+
+ let mut data: IndexMap<String, PhpMixed> = IndexMap::new();
+ data.insert(
+ "warning".to_string(),
+ PhpMixed::String("old warning msg".to_string()),
+ );
+ data.insert(
+ "warning-versions".to_string(),
+ PhpMixed::String(">=2.0".to_string()),
+ );
+ data.insert(
+ "info".to_string(),
+ PhpMixed::String("old info msg".to_string()),
+ );
+ data.insert(
+ "info-versions".to_string(),
+ PhpMixed::String(">=2.0".to_string()),
+ );
+
+ let mut warning_should_not = IndexMap::new();
+ warning_should_not.insert(
+ "message".to_string(),
+ PhpMixed::String("should not appear".to_string()),
+ );
+ warning_should_not.insert("versions".to_string(), PhpMixed::String("<2.2".to_string()));
+ let mut warning_visible = IndexMap::new();
+ warning_visible.insert(
+ "message".to_string(),
+ PhpMixed::String("visible warning".to_string()),
+ );
+ warning_visible.insert(
+ "versions".to_string(),
+ PhpMixed::String(">=2.2-dev".to_string()),
+ );
+ data.insert(
+ "warnings".to_string(),
+ PhpMixed::List(vec![
+ PhpMixed::Array(warning_should_not),
+ PhpMixed::Array(warning_visible),
+ ]),
+ );
+
+ let mut info_should_not = IndexMap::new();
+ info_should_not.insert(
+ "message".to_string(),
+ PhpMixed::String("should not appear".to_string()),
+ );
+ info_should_not.insert("versions".to_string(), PhpMixed::String("<2.2".to_string()));
+ let mut info_visible = IndexMap::new();
+ info_visible.insert(
+ "message".to_string(),
+ PhpMixed::String("visible info".to_string()),
+ );
+ info_visible.insert(
+ "versions".to_string(),
+ PhpMixed::String(">=2.2-dev".to_string()),
+ );
+ data.insert(
+ "infos".to_string(),
+ PhpMixed::List(vec![
+ PhpMixed::Array(info_should_not),
+ PhpMixed::Array(info_visible),
+ ]),
+ );
+
+ HttpDownloader::output_warnings(io_dyn.clone(), "$URL", &data).unwrap();
+
+ // the <info> tag are consumed by the OutputFormatter, but not <warning> as that is not a default output format
+ assert_eq!(
+ format!(
+ "<warning>Warning from $URL: old warning msg</warning>{eol}\
+ Info from $URL: old info msg{eol}\
+ <warning>Warning from $URL: visible warning</warning>{eol}\
+ Info from $URL: visible info{eol}",
+ eol = PHP_EOL
+ ),
+ io.borrow().get_output()
+ );
}
diff --git a/crates/shirabe/tests/util/metadata_minifier_test.rs b/crates/shirabe/tests/util/metadata_minifier_test.rs
index 03bee8e..85ed507 100644
--- a/crates/shirabe/tests/util/metadata_minifier_test.rs
+++ b/crates/shirabe/tests/util/metadata_minifier_test.rs
@@ -1,7 +1,7 @@
//! ref: composer/tests/Composer/Test/Util/MetadataMinifierTest.php
#[test]
-#[ignore = "MetadataMinifier::minify is intentionally not ported in shirabe_external_packages (unused by Composer itself)"]
+#[ignore = "MetadataMinifier::minify is not ported (intentionally absent in metadata_minifier.rs)"]
fn test_minify_expand() {
todo!()
}
diff --git a/crates/shirabe/tests/util/perforce_test.rs b/crates/shirabe/tests/util/perforce_test.rs
index fb517ba..0a62ebb 100644
--- a/crates/shirabe/tests/util/perforce_test.rs
+++ b/crates/shirabe/tests/util/perforce_test.rs
@@ -3,6 +3,55 @@
// These mock IO and a ProcessExecutor to drive Perforce client/stream/command behaviour;
// mocking is not available here.
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use indexmap::IndexMap;
+use shirabe::io::{IOInterface, NullIO};
+use shirabe::util::{Perforce, ProcessExecutor};
+use shirabe_php_shim::PhpMixed;
+
+const TEST_DEPOT: &str = "depot";
+const TEST_BRANCH: &str = "branch";
+const TEST_P4USER: &str = "user";
+const TEST_CLIENT_NAME: &str = "TEST";
+const TEST_PORT: &str = "port";
+const TEST_PATH: &str = "path";
+
+fn get_test_repo_config() -> IndexMap<String, PhpMixed> {
+ let mut config = IndexMap::new();
+ config.insert(
+ "depot".to_string(),
+ PhpMixed::String(TEST_DEPOT.to_string()),
+ );
+ config.insert(
+ "branch".to_string(),
+ PhpMixed::String(TEST_BRANCH.to_string()),
+ );
+ config.insert(
+ "p4user".to_string(),
+ PhpMixed::String(TEST_P4USER.to_string()),
+ );
+ config.insert(
+ "unique_perforce_client_name".to_string(),
+ PhpMixed::String(TEST_CLIENT_NAME.to_string()),
+ );
+ config
+}
+
+fn create_new_perforce_with_windows_flag(flag: bool) -> Perforce {
+ let process = Rc::new(RefCell::new(ProcessExecutor::new(None)));
+ let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new()));
+ Perforce::new(
+ get_test_repo_config(),
+ TEST_PORT.to_string(),
+ TEST_PATH.to_string(),
+ process,
+ flag,
+ io,
+ )
+}
+
#[allow(dead_code)]
fn set_up() {
// Builds mocked ProcessExecutor/IO, the test repo config, and a Windows-flagged Perforce;
@@ -10,230 +59,296 @@ fn set_up() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_get_client_without_stream() {
- todo!()
+ let mut perforce = create_new_perforce_with_windows_flag(true);
+
+ let client = perforce.get_client();
+
+ let expected = "composer_perforce_TEST_depot";
+ assert_eq!(expected, client);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_get_client_from_stream() {
- todo!()
+ let mut perforce = create_new_perforce_with_windows_flag(true);
+ perforce.set_stream("//depot/branch");
+
+ let client = perforce.get_client();
+
+ let expected = "composer_perforce_TEST_depot_branch";
+ assert_eq!(expected, client);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_get_stream_without_stream() {
- todo!()
+ let mut perforce = create_new_perforce_with_windows_flag(true);
+
+ let stream = perforce.get_stream();
+ assert_eq!("//depot", stream);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_get_stream_with_stream() {
- todo!()
+ let mut perforce = create_new_perforce_with_windows_flag(true);
+ perforce.set_stream("//depot/branch");
+
+ let stream = perforce.get_stream();
+ assert_eq!("//depot/branch", stream);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_get_stream_without_label_with_stream_without_label() {
- todo!()
+ let perforce = create_new_perforce_with_windows_flag(true);
+
+ let stream = perforce.get_stream_without_label("//depot/branch");
+ assert_eq!("//depot/branch", stream);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_get_stream_without_label_with_stream_with_label() {
- todo!()
+ let perforce = create_new_perforce_with_windows_flag(true);
+
+ let stream = perforce.get_stream_without_label("//depot/branching@label");
+ assert_eq!("//depot/branching", stream);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_get_client_spec() {
- todo!()
+ let mut perforce = create_new_perforce_with_windows_flag(true);
+
+ let client_spec = perforce.get_p4_client_spec();
+ let expected = "path/composer_perforce_TEST_depot.p4.spec";
+ assert_eq!(expected, client_spec);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_generate_p4_command() {
- todo!()
+ let mut perforce = create_new_perforce_with_windows_flag(true);
+
+ let p4_command =
+ perforce.generate_p4_command(vec!["do".to_string(), "something".to_string()], true);
+ let expected = vec![
+ "p4".to_string(),
+ "-u".to_string(),
+ "user".to_string(),
+ "-c".to_string(),
+ "composer_perforce_TEST_depot".to_string(),
+ "-p".to_string(),
+ "port".to_string(),
+ "do".to_string(),
+ "something".to_string(),
+ ];
+ assert_eq!(expected, p4_command);
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_query_p4_user_with_user_already_set() {
- todo!()
+ let mut perforce = create_new_perforce_with_windows_flag(true);
+
+ perforce.query_p4_user();
+ assert_eq!(Some(TEST_P4USER.to_string()), perforce.get_user());
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock with expects() command stdout stubbing (p4 set => P4USER=...); no mocking infrastructure exists"]
fn test_query_p4_user_with_user_set_in_p4_variables_with_windows_os() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock with expects() command stdout stubbing (echo $P4USER => ...); no mocking infrastructure exists"]
fn test_query_p4_user_with_user_set_in_p4_variables_not_windows_os() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires mocked IOInterface ask()->willReturn and getProcessExecutorMock; no mocking infrastructure exists"]
fn test_query_p4_user_queries_for_user() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires mocked IOInterface ask()->willReturn and getProcessExecutorMock expects() command verification; no mocking infrastructure exists"]
fn test_query_p4_user_stores_response_to_query_for_user_with_windows() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires mocked IOInterface ask()->willReturn and getProcessExecutorMock expects() command verification; no mocking infrastructure exists"]
fn test_query_p4_user_stores_response_to_query_for_user_without_windows() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires mocked IOInterface ask()->willReturn and getProcessExecutorMock expects() command verification; no mocking infrastructure exists"]
fn test_query_p4_user_escapes_injection_on_windows() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires mocked IOInterface ask()->willReturn and getProcessExecutorMock expects() command verification; no mocking infrastructure exists"]
fn test_query_p4_user_escapes_injection_on_unix() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
fn test_query_p4_password_with_password_already_set() {
- todo!()
+ let mut repo_config = IndexMap::new();
+ repo_config.insert("depot".to_string(), PhpMixed::String("depot".to_string()));
+ repo_config.insert("branch".to_string(), PhpMixed::String("branch".to_string()));
+ repo_config.insert("p4user".to_string(), PhpMixed::String("user".to_string()));
+ repo_config.insert(
+ "p4password".to_string(),
+ PhpMixed::String("TEST_PASSWORD".to_string()),
+ );
+ let process = Rc::new(RefCell::new(ProcessExecutor::new(None)));
+ let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new()));
+ let mut perforce = Perforce::new(
+ repo_config,
+ "port".to_string(),
+ "path".to_string(),
+ process,
+ false,
+ io,
+ );
+
+ let password = perforce.query_p4_password();
+ assert_eq!(Some("TEST_PASSWORD".to_string()), password);
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock with expects() command stdout stubbing (p4 set => P4PASSWD=...); no mocking infrastructure exists"]
fn test_query_p4_password_with_password_set_in_p4_variables_with_windows_os() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock with expects() command stdout stubbing (echo $P4PASSWD => ...); no mocking infrastructure exists"]
fn test_query_p4_password_with_password_set_in_p4_variables_not_windows_os() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires mocked IOInterface askAndHideAnswer()->willReturn; no mocking infrastructure exists"]
fn test_query_p4_password_queries_for_password() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command verification for the p4 client spec write; no mocking infrastructure exists"]
fn test_write_p4_client_spec_without_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command verification for the p4 client spec write; no mocking infrastructure exists"]
fn test_write_p4_client_spec_with_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 login -s; no mocking infrastructure exists"]
fn test_is_logged_in() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 streams; no mocking infrastructure exists"]
fn test_get_branches_with_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 changes; no mocking infrastructure exists"]
fn test_get_branches_without_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 changes; no mocking infrastructure exists"]
fn test_get_tags_without_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 changes; no mocking infrastructure exists"]
fn test_get_tags_with_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 streams; no mocking infrastructure exists"]
fn test_check_stream_without_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 streams; no mocking infrastructure exists"]
fn test_check_stream_with_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 print composer.json; no mocking infrastructure exists"]
fn test_get_composer_information_without_label_without_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 print composer.json; no mocking infrastructure exists"]
fn test_get_composer_information_with_label_without_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 print composer.json; no mocking infrastructure exists"]
fn test_get_composer_information_without_label_with_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 print composer.json; no mocking infrastructure exists"]
fn test_get_composer_information_with_label_with_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command verification for p4 sync; no mocking infrastructure exists"]
fn test_sync_code_base_without_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command verification for p4 sync; no mocking infrastructure exists"]
fn test_sync_code_base_with_stream() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 info -s; no mocking infrastructure exists"]
fn test_check_server_exists() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command stdout stubbing for p4 info -s; no mocking infrastructure exists"]
fn test_check_server_client_error() {
todo!()
}
#[test]
-#[ignore = "mocks IO/ProcessExecutor to drive Perforce; mocking is not available"]
+#[ignore = "requires getProcessExecutorMock expects() command verification for p4 client -d; no mocking infrastructure exists"]
fn test_cleanup_client_spec_should_delete_client() {
todo!()
}
diff --git a/crates/shirabe/tests/util/process_executor_test.rs b/crates/shirabe/tests/util/process_executor_test.rs
index 88449f1..f17f162 100644
--- a/crates/shirabe/tests/util/process_executor_test.rs
+++ b/crates/shirabe/tests/util/process_executor_test.rs
@@ -3,68 +3,206 @@
// These run real subprocesses (capturing output/stderr/timeout) and assert ProcessExecutor's
// password hiding, line splitting and argument escaping; the subprocess execution and mocked
// IO are not ported.
+
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use shirabe::io::ConsoleIO;
+use shirabe::io::IOInterface;
+use shirabe::io::buffer_io::BufferIO;
+use shirabe::util::process_executor::ProcessExecutor;
+use shirabe_external_packages::symfony::console::helper::HelperSet;
+use shirabe_external_packages::symfony::console::input::array_input::ArrayInput;
+use shirabe_external_packages::symfony::console::input::input_interface::InputInterface;
+use shirabe_external_packages::symfony::console::output::buffered_output::BufferedOutput;
+use shirabe_external_packages::symfony::console::output::output_interface::{
+ OutputInterface, VERBOSITY_DEBUG, VERBOSITY_NORMAL,
+};
+use shirabe_php_shim::{PHP_EOL, trim};
+
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_execute_captures_output() {
- todo!()
+ let mut process = ProcessExecutor::new(None);
+ let mut output = String::new();
+ process.execute("echo foo", &mut output, ()).unwrap();
+ assert_eq!(format!("foo{}", PHP_EOL), output);
}
+#[ignore = "requires PHP output buffering (ob_start/ob_get_clean) to capture stdout; no equivalent symbol"]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_execute_outputs_if_not_captured() {
todo!()
}
+#[ignore = "requires getMockBuilder('IOInterface') with expects()->once()->method('writeRaw')->with() expectation verification; no mocking framework"]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_use_io_is_not_null_and_if_not_captured() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_execute_captures_stderr() {
- todo!()
+ let mut process = ProcessExecutor::new(None);
+ let mut output = String::new();
+ process.execute("cat foo", &mut output, ()).unwrap();
+ assert!(
+ process
+ .get_error_output()
+ .contains("foo: No such file or directory")
+ );
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_timeout() {
- todo!()
+ ProcessExecutor::set_timeout(1_i64);
+ let process = ProcessExecutor::new(None);
+ assert_eq!(1, ProcessExecutor::get_timeout());
+ let _ = &process;
+ ProcessExecutor::set_timeout(60_i64);
+}
+
+fn hide_password_provider() -> Vec<(&'static str, &'static str)> {
+ vec![
+ (
+ "echo https://foo:bar@example.org/",
+ "echo https://foo:***@example.org/",
+ ),
+ ("echo http://foo@example.org", "echo http://foo@example.org"),
+ (
+ "echo http://abcdef1234567890234578:x-oauth-token@github.com/",
+ "echo http://***:***@github.com/",
+ ),
+ (
+ "echo http://github_pat_1234567890abcdefghijkl_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVW:x-oauth-token@github.com/",
+ "echo http://***:***@github.com/",
+ ),
+ (
+ "svn ls --verbose --non-interactive --username 'foo' --password 'bar' 'https://foo.example.org/svn/'",
+ "svn ls --verbose --non-interactive --username 'foo' --password '***' 'https://foo.example.org/svn/'",
+ ),
+ (
+ "svn ls --verbose --non-interactive --username 'foo' --password 'bar 'bar' 'https://foo.example.org/svn/'",
+ "svn ls --verbose --non-interactive --username 'foo' --password '***' 'https://foo.example.org/svn/'",
+ ),
+ ]
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_hide_passwords() {
- todo!()
+ for (command, expected_command_output) in hide_password_provider() {
+ let buffer = Rc::new(RefCell::new(
+ BufferIO::new(String::new(), VERBOSITY_DEBUG, None).unwrap(),
+ ));
+ let mut process =
+ ProcessExecutor::new(Some(buffer.clone() as Rc<RefCell<dyn IOInterface>>));
+ let mut output = String::new();
+ process.execute(command, &mut output, ()).unwrap();
+ assert_eq!(
+ format!("Executing command (CWD): {}", expected_command_output),
+ trim(&buffer.borrow().get_output(), None)
+ );
+ }
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_doesnt_hide_ports() {
- todo!()
+ let buffer = Rc::new(RefCell::new(
+ BufferIO::new(String::new(), VERBOSITY_DEBUG, None).unwrap(),
+ ));
+ let mut process = ProcessExecutor::new(Some(buffer.clone() as Rc<RefCell<dyn IOInterface>>));
+ let mut output = String::new();
+ process
+ .execute("echo https://localhost:1234/", &mut output, ())
+ .unwrap();
+ assert_eq!(
+ "Executing command (CWD): echo https://localhost:1234/",
+ trim(&buffer.borrow().get_output(), None)
+ );
}
+#[ignore = "splitLines is called with null in the PHP test, but split_lines accepts only &str (no ?string/Option overload)"]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_split_lines() {
todo!()
}
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_console_io_does_not_format_symfony_console_style() {
- todo!()
+ let output = Rc::new(RefCell::new(BufferedOutput::new(
+ Some(VERBOSITY_NORMAL),
+ true,
+ None,
+ )));
+ let input: Rc<RefCell<dyn InputInterface>> =
+ Rc::new(RefCell::new(ArrayInput::new(vec![], None).unwrap()));
+ let console_io = ConsoleIO::new(
+ input,
+ output.clone() as Rc<RefCell<dyn OutputInterface>>,
+ HelperSet::default(),
+ );
+ let mut process = ProcessExecutor::new(Some(
+ Rc::new(RefCell::new(console_io)) as Rc<RefCell<dyn IOInterface>>
+ ));
+
+ process
+ .execute(
+ r#"php -ddisplay_errors=0 -derror_reporting=0 -r "echo '<error>foo</error>'.PHP_EOL;""#,
+ (),
+ (),
+ )
+ .unwrap();
+ assert_eq!(
+ format!("<error>foo</error>{}", PHP_EOL),
+ output.borrow().fetch()
+ );
}
+#[ignore = "executeAsync returns a Process, not a cancelable promise; no promise/cancel symbol exists"]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_execute_async_cancel() {
todo!()
}
+fn data_escape_arguments() -> Vec<(&'static str, &'static str)> {
+ // (argument, unix-expected). Not on Windows, so the unix column is used.
+ // null and false arguments are coerced to the empty string.
+ vec![
+ ("", "''"),
+ ("", "''"),
+ ("", "''"),
+ ("a'bc", "'a'\\''bc'"),
+ ("a\nb\nc", "'a\nb\nc'"),
+ ("a b c", "'a b c'"),
+ ("a\tb\tc", "'a\tb\tc'"),
+ ("abc", "'abc'"),
+ ("a,bc", "'a,bc'"),
+ ("a\"bc", "'a\"bc'"),
+ ("a\\\"bc", "'a\\\"bc'"),
+ ("ab\\\\c\\", "'ab\\\\c\\'"),
+ ("a b c\\\\", "'a b c\\\\'"),
+ ("a \"b\" c", "'a \"b\" c'"),
+ ("%path%", "'%path%'"),
+ ("%path", "'%path'"),
+ ("%%path", "'%%path'"),
+ ("!path!", "'!path!'"),
+ ("!path", "'!path'"),
+ ("!!path", "'!!path'"),
+ ("<>\"&|()^", "'<>\"&|()^'"),
+ ("<> &| ()^", "'<> &| ()^'"),
+ ("<>&|()^", "'<>&|()^'"),
+ ]
+}
+
+#[ignore]
#[test]
-#[ignore = "not yet ported (runs subprocesses / mocks IO; argument-escaping and split helpers included)"]
fn test_escape_argument() {
- todo!()
+ for (argument, unix) in data_escape_arguments() {
+ assert_eq!(unix, ProcessExecutor::escape(argument));
+ }
}
diff --git a/crates/shirabe/tests/util/remote_filesystem_test.rs b/crates/shirabe/tests/util/remote_filesystem_test.rs
index 1fc9f7e..b39a2dd 100644
--- a/crates/shirabe/tests/util/remote_filesystem_test.rs
+++ b/crates/shirabe/tests/util/remote_filesystem_test.rs
@@ -4,79 +4,79 @@
// building and downloads; mocking/reflection are not available and a real HttpDownloader
// reaches curl_multi_init (todo!()).
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface (expects(once())->hasAuthentication) and ReflectionMethod to invoke private get_options_for_url plus ReflectionProperty on private file_url; no mocking/reflection infrastructure exists"]
fn test_get_options_for_url() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface (expects(once())->hasAuthentication/getAuthentication) and ReflectionMethod to invoke private get_options_for_url plus ReflectionProperty on private file_url; no mocking/reflection infrastructure exists"]
fn test_get_options_for_url_with_authorization() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface (expects(once())->hasAuthentication/getAuthentication) and ReflectionMethod to invoke private get_options_for_url plus ReflectionProperty on private file_url; no mocking/reflection infrastructure exists"]
fn test_get_options_for_url_with_stream_options() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface (expects(once())->hasAuthentication/getAuthentication) and ReflectionMethod to invoke private get_options_for_url plus ReflectionProperty on private file_url; no mocking/reflection infrastructure exists"]
fn test_get_options_for_url_with_call_options_keeps_header() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface and ReflectionMethod to invoke private callback_get plus ReflectionProperty to read private bytes_max; no mocking/reflection infrastructure exists"]
fn test_callback_get_file_size() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface (expects(once())->overwriteError) and ReflectionProperty to set private bytes_max/progress and read private last_progress; no mocking/reflection infrastructure exists"]
fn test_callback_get_notify_progress() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface and ReflectionMethod to invoke private callback_get; no mocking/reflection infrastructure exists"]
fn test_callback_get_passes_through404() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface and a real get_contents which bottoms at curl_multi_init (todo!()); no mocking infrastructure exists"]
fn test_get_contents() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface and a real copy which bottoms at curl_multi_init (todo!()); no mocking infrastructure exists"]
fn test_copy() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a MockObject subclass of RemoteFilesystem overriding private get_remote_contents; no mocking infrastructure exists"]
fn test_copy_with_no_retry_on_failure() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires MockObject subclasses overriding RemoteFilesystem::get_remote_contents and AuthHelper::prompt_auth_if_needed; no mocking infrastructure exists"]
fn test_copy_with_success_on_retry() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked IOInterface and ReflectionMethod to invoke private get_options_for_url plus ReflectionProperty on private file_url; no mocking/reflection infrastructure exists"]
fn test_get_options_for_url_creates_secure_tls_defaults() {
todo!()
}
#[test]
-#[ignore = "mocks IO/Config/HttpDownloader (curl_multi_init todo!()) and uses reflection; not ported"]
+#[ignore = "requires a mocked ConsoleIO (getMockBuilder disableOriginalConstructor) and a real getContents network download reaching curl_multi_init (todo!()); no mocking infrastructure exists"]
fn test_bit_bucket_public_download() {
todo!()
}
diff --git a/crates/shirabe/tests/util/stream_context_factory_test.rs b/crates/shirabe/tests/util/stream_context_factory_test.rs
index f58ee75..23d4392 100644
--- a/crates/shirabe/tests/util/stream_context_factory_test.rs
+++ b/crates/shirabe/tests/util/stream_context_factory_test.rs
@@ -3,8 +3,11 @@
// These build a stream context and assert proxy/option handling driven by HTTP(S)_PROXY /
// no_proxy environment variables; the env-dependent setup (without its setUp/tearDown
// isolation) is not ported.
+use indexmap::IndexMap;
use shirabe::util::http::proxy_manager::ProxyManager;
use shirabe::util::platform::Platform;
+use shirabe::util::stream_context_factory::StreamContextFactory;
+use shirabe_php_shim::{PhpMixed, implode, stripos};
fn set_up() {
Platform::clear_env("HTTP_PROXY");
@@ -35,7 +38,7 @@ impl Drop for TearDown {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options/stream_context_get_params shim functions do not exist; cannot read back created context to assert"]
fn test_get_context() {
let _tear_down = TearDown;
set_up();
@@ -43,7 +46,7 @@ fn test_get_context() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_http_proxy() {
let _tear_down = TearDown;
set_up();
@@ -51,7 +54,7 @@ fn test_http_proxy() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_http_proxy_with_no_proxy() {
let _tear_down = TearDown;
set_up();
@@ -59,7 +62,7 @@ fn test_http_proxy_with_no_proxy() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_http_proxy_with_no_proxy_wildcard() {
let _tear_down = TearDown;
set_up();
@@ -67,7 +70,7 @@ fn test_http_proxy_with_no_proxy_wildcard() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_options_are_preserved() {
let _tear_down = TearDown;
set_up();
@@ -75,7 +78,7 @@ fn test_options_are_preserved() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_http_proxy_without_port() {
let _tear_down = TearDown;
set_up();
@@ -83,7 +86,7 @@ fn test_http_proxy_without_port() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_https_proxy_override() {
let _tear_down = TearDown;
set_up();
@@ -91,7 +94,7 @@ fn test_https_proxy_override() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_ssl_proxy() {
let _tear_down = TearDown;
set_up();
@@ -99,7 +102,7 @@ fn test_ssl_proxy() {
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore = "stream_context_get_options shim function does not exist; cannot read back created context to assert"]
fn test_ensure_thatfix_http_header_field_moves_content_type_to_end_of_options() {
let _tear_down = TearDown;
set_up();
@@ -107,17 +110,54 @@ fn test_ensure_thatfix_http_header_field_moves_content_type_to_end_of_options()
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore]
fn test_init_options_does_include_proxy_auth_headers() {
let _tear_down = TearDown;
set_up();
- todo!()
+ Platform::put_env(
+ "https_proxy",
+ "http://username:password@proxyserver.net:3128/",
+ );
+
+ let options: IndexMap<String, PhpMixed> = IndexMap::new();
+ let options =
+ StreamContextFactory::init_options("https://example.org", options, false).unwrap();
+ let header_list: Vec<String> = options
+ .get("http")
+ .and_then(|v| v.as_array())
+ .and_then(|a| a.get("header"))
+ .and_then(|v| v.as_list())
+ .unwrap()
+ .iter()
+ .filter_map(|item| item.as_string().map(|s| s.to_string()))
+ .collect();
+ let headers = implode(" ", &header_list);
+
+ assert!(stripos(&headers, "Proxy-Authorization").is_some());
}
#[test]
-#[ignore = "not yet ported (StreamContextFactory proxy/option building is driven by proxy env vars)"]
+#[ignore]
fn test_init_options_for_curl_does_not_include_proxy_auth_headers() {
let _tear_down = TearDown;
set_up();
- todo!()
+ Platform::put_env(
+ "http_proxy",
+ "http://username:password@proxyserver.net:3128/",
+ );
+
+ let options: IndexMap<String, PhpMixed> = IndexMap::new();
+ let options = StreamContextFactory::init_options("https://example.org", options, true).unwrap();
+ let header_list: Vec<String> = options
+ .get("http")
+ .and_then(|v| v.as_array())
+ .and_then(|a| a.get("header"))
+ .and_then(|v| v.as_list())
+ .unwrap()
+ .iter()
+ .filter_map(|item| item.as_string().map(|s| s.to_string()))
+ .collect();
+ let headers = implode(" ", &header_list);
+
+ assert!(stripos(&headers, "Proxy-Authorization").is_none());
}
diff --git a/crates/shirabe/tests/util/svn_test.rs b/crates/shirabe/tests/util/svn_test.rs
index 5e2775f..90a6b45 100644
--- a/crates/shirabe/tests/util/svn_test.rs
+++ b/crates/shirabe/tests/util/svn_test.rs
@@ -1,33 +1,31 @@
//! ref: composer/tests/Composer/Test/Util/SvnTest.php
-// These mock IO/Config and use reflection to drive Svn's credential handling; mocking and
-// reflection are not available here.
+#[ignore = "Svn::get_credential_args is pub(crate) (crate-private); unreachable from an integration test"]
#[test]
-#[ignore = "mocks IO/Config and uses reflection to drive Svn credentials; not ported"]
fn test_credentials() {
todo!()
}
+#[ignore = "Svn::get_command is pub(crate) (crate-private); unreachable from an integration test"]
#[test]
-#[ignore = "mocks IO/Config and uses reflection to drive Svn credentials; not ported"]
fn test_interactive_string() {
todo!()
}
+#[ignore = "Svn::get_credential_args is pub(crate) (crate-private); unreachable from an integration test"]
#[test]
-#[ignore = "mocks IO/Config and uses reflection to drive Svn credentials; not ported"]
fn test_credentials_from_config() {
todo!()
}
+#[ignore = "Svn::get_credential_args is pub(crate) (crate-private); unreachable from an integration test"]
#[test]
-#[ignore = "mocks IO/Config and uses reflection to drive Svn credentials; not ported"]
fn test_credentials_from_config_with_cache_credentials_true() {
todo!()
}
+#[ignore = "Svn::get_credential_args is pub(crate) (crate-private); unreachable from an integration test"]
#[test]
-#[ignore = "mocks IO/Config and uses reflection to drive Svn credentials; not ported"]
fn test_credentials_from_config_with_cache_credentials_false() {
todo!()
}
diff --git a/crates/shirabe/tests/util/tls_helper_test.rs b/crates/shirabe/tests/util/tls_helper_test.rs
index 260ff47..4717282 100644
--- a/crates/shirabe/tests/util/tls_helper_test.rs
+++ b/crates/shirabe/tests/util/tls_helper_test.rs
@@ -1,13 +1,13 @@
//! ref: composer/tests/Composer/Test/Util/TlsHelperTest.php
#[test]
-#[ignore = "Composer\\Util\\TlsHelper is not yet ported"]
+#[ignore = "TlsHelper::check_certificate_host not implemented in crates/shirabe/src"]
fn test_check_certificate_host() {
todo!()
}
#[test]
-#[ignore = "Composer\\Util\\TlsHelper is not yet ported"]
+#[ignore = "TlsHelper::get_certificate_names not implemented in crates/shirabe/src"]
fn test_get_certificate_names() {
todo!()
}