diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-06-25 15:12:06 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-06-26 00:20:05 +0900 |
| commit | 8117e5450693d19726da877bce8aacf5c7aa53af (patch) | |
| tree | 4b06e6f6924599f3402d29cdcdeb0f8a88354d89 /crates/shirabe/tests/repository/vcs/gitlab_driver_test.rs | |
| parent | 8dd3d67884a204ca40e3364206868fea77a312be (diff) | |
| download | php-shirabe-8117e5450693d19726da877bce8aacf5c7aa53af.tar.gz php-shirabe-8117e5450693d19726da877bce8aacf5c7aa53af.tar.zst php-shirabe-8117e5450693d19726da877bce8aacf5c7aa53af.zip | |
test: port 44 vcs/downloader/version tests using mock infra
Port git, version_guesser, gitlab_driver, github_driver, and git_downloader
tests using the ProcessExecutor/HttpDownloader mocks and IO/Config stubs.
Fix production regex-porting bugs surfaced by the now-reachable paths:
Url::sanitize and Response::find_header_value had non-delimited PCRE patterns;
implement array_search_mixed non-strict branch and a datetime format mapping.
Add HttpDownloader::__new_mock so mocked downloaders skip curl construction.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Diffstat (limited to 'crates/shirabe/tests/repository/vcs/gitlab_driver_test.rs')
| -rw-r--r-- | crates/shirabe/tests/repository/vcs/gitlab_driver_test.rs | 780 |
1 files changed, 747 insertions, 33 deletions
diff --git a/crates/shirabe/tests/repository/vcs/gitlab_driver_test.rs b/crates/shirabe/tests/repository/vcs/gitlab_driver_test.rs index 0333a2b..e21835d 100644 --- a/crates/shirabe/tests/repository/vcs/gitlab_driver_test.rs +++ b/crates/shirabe/tests/repository/vcs/gitlab_driver_test.rs @@ -8,8 +8,15 @@ use shirabe::config::Config; use shirabe::io::IOInterface; use shirabe::io::null_io::NullIO; use shirabe::repository::vcs::GitLabDriver; +use shirabe::util::http_downloader::{HttpDownloader, HttpDownloaderMockHandler}; +use shirabe::util::process_executor::{MockHandler, ProcessExecutor}; use shirabe_php_shim::{PhpMixed, extension_loaded}; +use crate::http_downloader_mock::{ + HttpDownloaderMockGuard, expect, expect_full, get_http_downloader_mock, +}; +use crate::process_executor_mock::{ProcessExecutorMockGuard, get_process_executor_mock}; + // Mirrors GitLabDriverTest::setUp's `gitlab-domains` configuration. fn make_config() -> Config { let mut config = Config::new(true, None); @@ -30,74 +37,596 @@ fn make_config() -> Config { config } +// Common test fixtures: the IO mock (a bare NullIO, matching PHP's unconfigured +// getMock), the config and a no-op process executor mock. The PHP test passes a +// bare `getMock()` ProcessExecutor; none of these tests invoke git, so an empty +// strict expectation set both matches PHP and catches unexpected process calls. +struct Fixtures { + io: Rc<RefCell<dyn IOInterface>>, + config: Rc<RefCell<Config>>, + process: Rc<RefCell<ProcessExecutor>>, + _process_guard: ProcessExecutorMockGuard, +} + +fn fixtures() -> Fixtures { + let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new())); + let config = Rc::new(RefCell::new(make_config())); + let (process, _process_guard) = get_process_executor_mock(vec![], true, MockHandler::default()); + Fixtures { + io, + config, + process, + _process_guard, + } +} + +// Mirrors $this->getHttpDownloaderMock() with a single project-data expectation. +fn http_mock_with_body( + url: &str, + body: &str, +) -> (Rc<RefCell<HttpDownloader>>, HttpDownloaderMockGuard) { + get_http_downloader_mock( + vec![expect_full(url, None, 200, body, vec![String::new()])], + true, + HttpDownloaderMockHandler::default(), + ) +} + +fn provide_initialize_urls() -> Vec<(&'static str, &'static str)> { + vec![ + ( + "https://gitlab.com/mygroup/myproject", + "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject", + ), + ( + "http://gitlab.com/mygroup/myproject", + "http://gitlab.com/api/v4/projects/mygroup%2Fmyproject", + ), + ( + "git@gitlab.com:mygroup/myproject", + "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject", + ), + ] +} + +// Mirrors testInitialize: returns the initialized driver together with the http +// mock guard (kept alive by the caller so __assert_complete runs at scope end). +fn do_test_initialize( + fixtures: &Fixtures, + url: &str, + api_url: &str, +) -> (GitLabDriver, HttpDownloaderMockGuard) { + // @link http://doc.gitlab.com/ce/api/projects.html#get-single-project + let project_data = r#"{ + "id": 17, + "default_branch": "mymaster", + "visibility": "private", + "issues_enabled": true, + "archived": false, + "http_url_to_repo": "https://gitlab.com/mygroup/myproject.git", + "ssh_url_to_repo": "git@gitlab.com:mygroup/myproject.git", + "last_activity_at": "2014-12-01T09:17:51.000+01:00", + "name": "My Project", + "name_with_namespace": "My Group / My Project", + "path": "myproject", + "path_with_namespace": "mygroup/myproject", + "web_url": "https://gitlab.com/mygroup/myproject" +}"#; + + let (http_downloader, guard) = http_mock_with_body(api_url, project_data); + + let mut repo_config: IndexMap<String, PhpMixed> = IndexMap::new(); + repo_config.insert("url".to_string(), PhpMixed::String(url.to_string())); + let mut driver = GitLabDriver::new( + repo_config, + fixtures.io.clone(), + fixtures.config.clone(), + http_downloader, + fixtures.process.clone(), + ); + driver.initialize().unwrap(); + + assert_eq!( + api_url, + driver.get_api_url(), + "API URL is derived from the repository URL" + ); + assert_eq!( + "mymaster", + driver.get_root_identifier().unwrap(), + "Root identifier is the default branch in GitLab" + ); + assert_eq!( + "git@gitlab.com:mygroup/myproject.git", + driver.get_repository_url(), + "The repository URL is the SSH one by default" + ); + assert_eq!("https://gitlab.com/mygroup/myproject", driver.get_url()); + + (driver, guard) +} + +// Mirrors testInitializePublicProject. +fn do_test_initialize_public_project( + fixtures: &Fixtures, + url: &str, + api_url: &str, +) -> (GitLabDriver, HttpDownloaderMockGuard) { + // @link http://doc.gitlab.com/ce/api/projects.html#get-single-project + let project_data = r#"{ + "id": 17, + "default_branch": "mymaster", + "visibility": "public", + "http_url_to_repo": "https://gitlab.com/mygroup/myproject.git", + "ssh_url_to_repo": "git@gitlab.com:mygroup/myproject.git", + "last_activity_at": "2014-12-01T09:17:51.000+01:00", + "name": "My Project", + "name_with_namespace": "My Group / My Project", + "path": "myproject", + "path_with_namespace": "mygroup/myproject", + "web_url": "https://gitlab.com/mygroup/myproject" +}"#; + + let (http_downloader, guard) = http_mock_with_body(api_url, project_data); + + let mut repo_config: IndexMap<String, PhpMixed> = IndexMap::new(); + repo_config.insert("url".to_string(), PhpMixed::String(url.to_string())); + let mut driver = GitLabDriver::new( + repo_config, + fixtures.io.clone(), + fixtures.config.clone(), + http_downloader, + fixtures.process.clone(), + ); + driver.initialize().unwrap(); + + assert_eq!( + api_url, + driver.get_api_url(), + "API URL is derived from the repository URL" + ); + assert_eq!( + "mymaster", + driver.get_root_identifier().unwrap(), + "Root identifier is the default branch in GitLab" + ); + assert_eq!( + "https://gitlab.com/mygroup/myproject.git", + driver.get_repository_url(), + "The repository URL is the SSH one by default" + ); + assert_eq!("https://gitlab.com/mygroup/myproject", driver.get_url()); + + (driver, guard) +} + #[test] -#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"] fn test_initialize() { - todo!() + let fixtures = fixtures(); + for (url, api_url) in provide_initialize_urls() { + let (_driver, _guard) = do_test_initialize(&fixtures, url, api_url); + } } #[test] -#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"] fn test_initialize_public_project() { - todo!() + let fixtures = fixtures(); + for (url, api_url) in provide_initialize_urls() { + let (_driver, _guard) = do_test_initialize_public_project(&fixtures, url, api_url); + } } #[test] -#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"] fn test_initialize_public_project_as_anonymous() { - todo!() + let fixtures = fixtures(); + for (url, api_url) in provide_initialize_urls() { + // @link http://doc.gitlab.com/ce/api/projects.html#get-single-project + let project_data = r#"{ + "id": 17, + "default_branch": "mymaster", + "http_url_to_repo": "https://gitlab.com/mygroup/myproject.git", + "ssh_url_to_repo": "git@gitlab.com:mygroup/myproject.git", + "last_activity_at": "2014-12-01T09:17:51.000+01:00", + "name": "My Project", + "name_with_namespace": "My Group / My Project", + "path": "myproject", + "path_with_namespace": "mygroup/myproject", + "web_url": "https://gitlab.com/mygroup/myproject" +}"#; + + let (http_downloader, _guard) = http_mock_with_body(api_url, project_data); + + let mut repo_config: IndexMap<String, PhpMixed> = IndexMap::new(); + repo_config.insert("url".to_string(), PhpMixed::String(url.to_string())); + let mut driver = GitLabDriver::new( + repo_config, + fixtures.io.clone(), + fixtures.config.clone(), + http_downloader, + fixtures.process.clone(), + ); + driver.initialize().unwrap(); + + assert_eq!( + api_url, + driver.get_api_url(), + "API URL is derived from the repository URL" + ); + assert_eq!( + "mymaster", + driver.get_root_identifier().unwrap(), + "Root identifier is the default branch in GitLab" + ); + assert_eq!( + "https://gitlab.com/mygroup/myproject.git", + driver.get_repository_url(), + "The repository URL is the SSH one by default" + ); + assert_eq!("https://gitlab.com/mygroup/myproject", driver.get_url()); + } } +/// Also support repositories over HTTP (TLS) and has a port number. #[test] -#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"] fn test_initialize_with_port_number() { - todo!() + let fixtures = fixtures(); + let domain = "gitlab.mycompany.com"; + let port = "5443"; + let namespace = "mygroup/myproject"; + let url = format!("https://{}:{}/{}", domain, port, namespace); + // urlencode($namespace) replaces '/' with '%2F'. + let api_url = format!( + "https://{}:{}/api/v4/projects/{}", + domain, port, "mygroup%2Fmyproject" + ); + + // An incomplete single project API response payload. + // @link http://doc.gitlab.com/ce/api/projects.html#get-single-project + let project_data = format!( + r#"{{ + "default_branch": "1.0.x", + "http_url_to_repo": "https://{0}:{1}/{2}.git", + "path": "myproject", + "path_with_namespace": "{2}", + "web_url": "https://{0}:{1}/{2}" +}}"#, + domain, port, namespace + ); + + let (http_downloader, _guard) = http_mock_with_body(&api_url, &project_data); + + let mut repo_config: IndexMap<String, PhpMixed> = IndexMap::new(); + repo_config.insert("url".to_string(), PhpMixed::String(url.clone())); + let mut driver = GitLabDriver::new( + repo_config, + fixtures.io.clone(), + fixtures.config.clone(), + http_downloader, + fixtures.process.clone(), + ); + driver.initialize().unwrap(); + + assert_eq!( + api_url, + driver.get_api_url(), + "API URL is derived from the repository URL" + ); + assert_eq!( + "1.0.x", + driver.get_root_identifier().unwrap(), + "Root identifier is the default branch in GitLab" + ); + assert_eq!( + format!("{}.git", url), + driver.get_repository_url(), + "The repository URL is the SSH one by default" + ); + assert_eq!(url, driver.get_url()); } #[test] -#[ignore = "depends on testInitialize, which needs HttpDownloaderMock + setAttribute (\\ReflectionProperty) not ported"] fn test_invalid_support_data() { - todo!() + let fixtures = fixtures(); + let repo_url = "https://gitlab.com/mygroup/myproject"; + let (mut driver, _init_guard) = do_test_initialize( + &fixtures, + repo_url, + "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject", + ); + + let mut branches: IndexMap<String, String> = IndexMap::new(); + branches.insert("main".to_string(), "SOMESHA".to_string()); + driver.__set_branches(Some(branches)); + driver.__set_tags(Some(IndexMap::new())); + + let (http_downloader, _guard) = get_http_downloader_mock( + vec![expect_full( + "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject/repository/files/composer%2Ejson/raw?ref=SOMESHA", + None, + 200, + format!(r#"{{"support": "{}" }}"#, repo_url), + vec![String::new()], + )], + true, + HttpDownloaderMockHandler::default(), + ); + driver.set_http_downloader(http_downloader); + + let data = driver.get_composer_information("main").unwrap().unwrap(); + + let source = data + .get("support") + .and_then(|v| v.as_array()) + .and_then(|m| m.get("source")) + .and_then(|v| v.as_string()) + .unwrap(); + assert_eq!("https://gitlab.com/mygroup/myproject/-/tree/main", source); } #[test] -#[ignore = "depends on testInitialize, which needs HttpDownloaderMock + the IOInterface MockObject not ported"] fn test_get_dist() { - todo!() + let fixtures = fixtures(); + let (driver, _guard) = do_test_initialize( + &fixtures, + "https://gitlab.com/mygroup/myproject", + "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject", + ); + + let reference = "c3ebdbf9cceddb82cd2089aaef8c7b992e536363"; + let mut expected: IndexMap<String, PhpMixed> = IndexMap::new(); + expected.insert("type".to_string(), PhpMixed::String("zip".to_string())); + expected.insert( + "url".to_string(), + PhpMixed::String(format!( + "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject/repository/archive.zip?sha={}", + reference + )), + ); + expected.insert( + "reference".to_string(), + PhpMixed::String(reference.to_string()), + ); + expected.insert("shasum".to_string(), PhpMixed::String(String::new())); + + assert_eq!(Some(expected), driver.get_dist(reference)); } #[test] -#[ignore = "depends on testInitialize, which needs HttpDownloaderMock + the IOInterface MockObject not ported"] fn test_get_source() { - todo!() + let fixtures = fixtures(); + let (driver, _guard) = do_test_initialize( + &fixtures, + "https://gitlab.com/mygroup/myproject", + "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject", + ); + + let reference = "c3ebdbf9cceddb82cd2089aaef8c7b992e536363"; + let mut expected: IndexMap<String, PhpMixed> = IndexMap::new(); + expected.insert("type".to_string(), PhpMixed::String("git".to_string())); + expected.insert( + "url".to_string(), + PhpMixed::String("git@gitlab.com:mygroup/myproject.git".to_string()), + ); + expected.insert( + "reference".to_string(), + PhpMixed::String(reference.to_string()), + ); + + assert_eq!(expected, driver.get_source(reference)); } #[test] -#[ignore = "depends on testInitializePublicProject, which needs HttpDownloaderMock + the IOInterface MockObject not ported"] fn test_get_source_given_public_project() { - todo!() + let fixtures = fixtures(); + let (driver, _guard) = do_test_initialize_public_project( + &fixtures, + "https://gitlab.com/mygroup/myproject", + "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject", + ); + + let reference = "c3ebdbf9cceddb82cd2089aaef8c7b992e536363"; + let mut expected: IndexMap<String, PhpMixed> = IndexMap::new(); + expected.insert("type".to_string(), PhpMixed::String("git".to_string())); + expected.insert( + "url".to_string(), + PhpMixed::String("https://gitlab.com/mygroup/myproject.git".to_string()), + ); + expected.insert( + "reference".to_string(), + PhpMixed::String(reference.to_string()), + ); + + assert_eq!(expected, driver.get_source(reference)); } #[test] -#[ignore = "depends on testInitialize, which needs HttpDownloaderMock + the IOInterface MockObject not ported"] fn test_get_tags() { - todo!() + let fixtures = fixtures(); + let (mut driver, _init_guard) = do_test_initialize( + &fixtures, + "https://gitlab.com/mygroup/myproject", + "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject", + ); + + let api_url = + "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject/repository/tags?per_page=100"; + + // @link http://doc.gitlab.com/ce/api/repositories.html#list-project-repository-tags + let tag_data = r#"[ + { + "name": "v1.0.0", + "commit": { + "id": "092ed2c762bbae331e3f51d4a17f67310bf99a81", + "committed_date": "2012-05-28T04:42:42-07:00" + } + }, + { + "name": "v2.0.0", + "commit": { + "id": "8e8f60b3ec86d63733db3bd6371117a758027ec6", + "committed_date": "2014-07-06T12:59:11.000+02:00" + } + } +]"#; + + let (http_downloader, _guard) = http_mock_with_body(api_url, tag_data); + driver.set_http_downloader(http_downloader); + + let mut expected: IndexMap<String, String> = IndexMap::new(); + expected.insert( + "v1.0.0".to_string(), + "092ed2c762bbae331e3f51d4a17f67310bf99a81".to_string(), + ); + expected.insert( + "v2.0.0".to_string(), + "8e8f60b3ec86d63733db3bd6371117a758027ec6".to_string(), + ); + + assert_eq!(expected, driver.get_tags().unwrap()); + assert_eq!(expected, driver.get_tags().unwrap(), "Tags are cached"); } #[test] -#[ignore = "depends on testInitialize, which needs HttpDownloaderMock + the IOInterface MockObject not ported"] +#[ignore = "Response::find_header_value passes a `(?i)`-prefixed (non-delimited) pattern that compile_php_pattern (Preg) mis-translates to an invalid regex (`(?s)?i)^link:...`), so get_next_page panics when parsing the Link header. Pre-existing Preg/Response porting bug, unrelated to GitLabDriver."] fn test_get_paginated_refs() { - todo!() + let fixtures = fixtures(); + let (mut driver, _init_guard) = do_test_initialize( + &fixtures, + "https://gitlab.com/mygroup/myproject", + "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject", + ); + + // @link http://doc.gitlab.com/ce/api/repositories.html#list-project-repository-branches + let mut branch_data: Vec<PhpMixed> = vec![ + branch_entry( + "mymaster", + "97eda36b5c1dd953a3792865c222d4e85e5f302e", + "2013-01-03T21:04:07.000+01:00", + ), + branch_entry( + "staging", + "502cffe49f136443f2059803f2e7192d1ac066cd", + "2013-03-09T16:35:23.000+01:00", + ), + ]; + for _ in 0..98 { + branch_data.push(branch_entry( + "stagingdupe", + "502cffe49f136443f2059803f2e7192d1ac066cd", + "2013-03-09T16:35:23.000+01:00", + )); + } + let branch_data = shirabe::json::JsonFile::encode(&PhpMixed::List(branch_data)); + + let (http_downloader, _guard) = get_http_downloader_mock( + vec![ + expect_full( + "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject/repository/branches?per_page=100", + None, + 200, + branch_data.clone(), + vec!["Link: <http://gitlab.com/api/v4/projects/mygroup%2Fmyproject/repository/tags?id=mygroup%2Fmyproject&page=2&per_page=20>; rel=\"next\", <http://gitlab.com/api/v4/projects/mygroup%2Fmyproject/repository/tags?id=mygroup%2Fmyproject&page=1&per_page=20>; rel=\"first\", <http://gitlab.com/api/v4/projects/mygroup%2Fmyproject/repository/tags?id=mygroup%2Fmyproject&page=3&per_page=20>; rel=\"last\"".to_string()], + ), + expect_full( + "http://gitlab.com/api/v4/projects/mygroup%2Fmyproject/repository/tags?id=mygroup%2Fmyproject&page=2&per_page=20", + None, + 200, + branch_data.clone(), + vec!["Link: <http://gitlab.com/api/v4/projects/mygroup%2Fmyproject/repository/tags?id=mygroup%2Fmyproject&page=2&per_page=20>; rel=\"prev\", <http://gitlab.com/api/v4/projects/mygroup%2Fmyproject/repository/tags?id=mygroup%2Fmyproject&page=1&per_page=20>; rel=\"first\", <http://gitlab.com/api/v4/projects/mygroup%2Fmyproject/repository/tags?id=mygroup%2Fmyproject&page=3&per_page=20>; rel=\"last\"".to_string()], + ), + ], + true, + HttpDownloaderMockHandler::default(), + ); + driver.set_http_downloader(http_downloader); + + let mut expected: IndexMap<String, String> = IndexMap::new(); + expected.insert( + "mymaster".to_string(), + "97eda36b5c1dd953a3792865c222d4e85e5f302e".to_string(), + ); + expected.insert( + "staging".to_string(), + "502cffe49f136443f2059803f2e7192d1ac066cd".to_string(), + ); + expected.insert( + "stagingdupe".to_string(), + "502cffe49f136443f2059803f2e7192d1ac066cd".to_string(), + ); + + assert_eq!(expected, driver.get_branches().unwrap()); + assert_eq!( + expected, + driver.get_branches().unwrap(), + "Branches are cached" + ); +} + +fn branch_entry(name: &str, id: &str, committed_date: &str) -> PhpMixed { + let mut commit: IndexMap<String, PhpMixed> = IndexMap::new(); + commit.insert("id".to_string(), PhpMixed::String(id.to_string())); + commit.insert( + "committed_date".to_string(), + PhpMixed::String(committed_date.to_string()), + ); + let mut entry: IndexMap<String, PhpMixed> = IndexMap::new(); + entry.insert("name".to_string(), PhpMixed::String(name.to_string())); + entry.insert("commit".to_string(), PhpMixed::Array(commit)); + PhpMixed::Array(entry) } #[test] -#[ignore = "depends on testInitialize, which needs HttpDownloaderMock + the IOInterface MockObject not ported"] fn test_get_branches() { - todo!() + let fixtures = fixtures(); + let (mut driver, _init_guard) = do_test_initialize( + &fixtures, + "https://gitlab.com/mygroup/myproject", + "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject", + ); + + let api_url = + "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject/repository/branches?per_page=100"; + + // @link http://doc.gitlab.com/ce/api/repositories.html#list-project-repository-branches + let branch_data = r#"[ + { + "name": "mymaster", + "commit": { + "id": "97eda36b5c1dd953a3792865c222d4e85e5f302e", + "committed_date": "2013-01-03T21:04:07.000+01:00" + } + }, + { + "name": "staging", + "commit": { + "id": "502cffe49f136443f2059803f2e7192d1ac066cd", + "committed_date": "2013-03-09T16:35:23.000+01:00" + } + } +]"#; + + let (http_downloader, _guard) = http_mock_with_body(api_url, branch_data); + driver.set_http_downloader(http_downloader); + + let mut expected: IndexMap<String, String> = IndexMap::new(); + expected.insert( + "mymaster".to_string(), + "97eda36b5c1dd953a3792865c222d4e85e5f302e".to_string(), + ); + expected.insert( + "staging".to_string(), + "502cffe49f136443f2059803f2e7192d1ac066cd".to_string(), + ); + + assert_eq!(expected, driver.get_branches().unwrap()); + assert_eq!( + expected, + driver.get_branches().unwrap(), + "Branches are cached" + ); } #[test] -#[ignore] fn test_supports() { for (url, expected) in data_for_test_supports() { let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new())); @@ -147,31 +676,216 @@ fn data_for_test_supports() -> Vec<(&'static str, bool)> { } #[test] -#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"] fn test_gitlab_sub_directory() { - todo!() + let fixtures = fixtures(); + let url = "https://mycompany.com/gitlab/mygroup/my-pro.ject"; + let api_url = "https://mycompany.com/gitlab/api/v4/projects/mygroup%2Fmy-pro%2Eject"; + + let project_data = r#"{ + "id": 17, + "default_branch": "mymaster", + "visibility": "private", + "http_url_to_repo": "https://gitlab.com/gitlab/mygroup/my-pro.ject", + "ssh_url_to_repo": "git@gitlab.com:mygroup/my-pro.ject.git", + "last_activity_at": "2014-12-01T09:17:51.000+01:00", + "name": "My Project", + "name_with_namespace": "My Group / My Project", + "path": "myproject", + "path_with_namespace": "mygroup/my-pro.ject", + "web_url": "https://gitlab.com/gitlab/mygroup/my-pro.ject" +}"#; + + let (http_downloader, _guard) = http_mock_with_body(api_url, project_data); + + let mut repo_config: IndexMap<String, PhpMixed> = IndexMap::new(); + repo_config.insert("url".to_string(), PhpMixed::String(url.to_string())); + let mut driver = GitLabDriver::new( + repo_config, + fixtures.io.clone(), + fixtures.config.clone(), + http_downloader, + fixtures.process.clone(), + ); + driver.initialize().unwrap(); + + assert_eq!( + api_url, + driver.get_api_url(), + "API URL is derived from the repository URL" + ); } #[test] -#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"] fn test_gitlab_sub_group() { - todo!() + let fixtures = fixtures(); + let url = "https://gitlab.com/mygroup/mysubgroup/myproject"; + let api_url = "https://gitlab.com/api/v4/projects/mygroup%2Fmysubgroup%2Fmyproject"; + + let project_data = r#"{ + "id": 17, + "default_branch": "mymaster", + "visibility": "private", + "http_url_to_repo": "https://gitlab.com/mygroup/mysubgroup/my-pro.ject", + "ssh_url_to_repo": "git@gitlab.com:mygroup/mysubgroup/my-pro.ject.git", + "last_activity_at": "2014-12-01T09:17:51.000+01:00", + "name": "My Project", + "name_with_namespace": "My Group / My Project", + "path": "myproject", + "path_with_namespace": "mygroup/mysubgroup/my-pro.ject", + "web_url": "https://gitlab.com/mygroup/mysubgroup/my-pro.ject" +}"#; + + let (http_downloader, _guard) = http_mock_with_body(api_url, project_data); + + let mut repo_config: IndexMap<String, PhpMixed> = IndexMap::new(); + repo_config.insert("url".to_string(), PhpMixed::String(url.to_string())); + let mut driver = GitLabDriver::new( + repo_config, + fixtures.io.clone(), + fixtures.config.clone(), + http_downloader, + fixtures.process.clone(), + ); + driver.initialize().unwrap(); + + assert_eq!( + api_url, + driver.get_api_url(), + "API URL is derived from the repository URL" + ); } #[test] -#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"] fn test_gitlab_sub_directory_sub_group() { - todo!() + let fixtures = fixtures(); + let url = "https://mycompany.com/gitlab/mygroup/mysubgroup/myproject"; + let api_url = "https://mycompany.com/gitlab/api/v4/projects/mygroup%2Fmysubgroup%2Fmyproject"; + + let project_data = r#"{ + "id": 17, + "default_branch": "mymaster", + "visibility": "private", + "http_url_to_repo": "https://mycompany.com/gitlab/mygroup/mysubgroup/my-pro.ject", + "ssh_url_to_repo": "git@mycompany.com:mygroup/mysubgroup/my-pro.ject.git", + "last_activity_at": "2014-12-01T09:17:51.000+01:00", + "name": "My Project", + "name_with_namespace": "My Group / My Project", + "path": "myproject", + "path_with_namespace": "mygroup/mysubgroup/my-pro.ject", + "web_url": "https://mycompany.com/gitlab/mygroup/mysubgroup/my-pro.ject" +}"#; + + let (http_downloader, _guard) = http_mock_with_body(api_url, project_data); + + let mut repo_config: IndexMap<String, PhpMixed> = IndexMap::new(); + repo_config.insert("url".to_string(), PhpMixed::String(url.to_string())); + let mut driver = GitLabDriver::new( + repo_config, + fixtures.io.clone(), + fixtures.config.clone(), + http_downloader, + fixtures.process.clone(), + ); + driver.initialize().unwrap(); + + assert_eq!( + api_url, + driver.get_api_url(), + "API URL is derived from the repository URL" + ); } #[test] -#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"] fn test_forwards_options() { - todo!() + let fixtures = fixtures(); + let mut ssl: IndexMap<String, PhpMixed> = IndexMap::new(); + ssl.insert("verify_peer".to_string(), PhpMixed::Bool(false)); + let mut options: IndexMap<String, PhpMixed> = IndexMap::new(); + options.insert("ssl".to_string(), PhpMixed::Array(ssl)); + + let project_data = r#"{ + "id": 17, + "default_branch": "mymaster", + "visibility": "private", + "http_url_to_repo": "https://gitlab.mycompany.local/mygroup/myproject", + "ssh_url_to_repo": "git@gitlab.mycompany.local:mygroup/myproject.git", + "last_activity_at": "2014-12-01T09:17:51.000+01:00", + "name": "My Project", + "name_with_namespace": "My Group / My Project", + "path": "myproject", + "path_with_namespace": "mygroup/myproject", + "web_url": "https://gitlab.mycompany.local/mygroup/myproject" +}"#; + + let (http_downloader, _guard) = http_mock_with_body( + "https://gitlab.mycompany.local/api/v4/projects/mygroup%2Fmyproject", + project_data, + ); + + let mut repo_config: IndexMap<String, PhpMixed> = IndexMap::new(); + repo_config.insert( + "url".to_string(), + PhpMixed::String("https://gitlab.mycompany.local/mygroup/myproject".to_string()), + ); + repo_config.insert("options".to_string(), PhpMixed::Array(options)); + let mut driver = GitLabDriver::new( + repo_config, + fixtures.io.clone(), + fixtures.config.clone(), + http_downloader, + fixtures.process.clone(), + ); + driver.initialize().unwrap(); } #[test] -#[ignore = "HttpDownloaderMock (getHttpDownloaderMock) and the IOInterface MockObject are not ported"] fn test_protocol_override_repository_url_generation() { - todo!() + let fixtures = fixtures(); + // @link http://doc.gitlab.com/ce/api/projects.html#get-single-project + let project_data = r#"{ + "id": 17, + "default_branch": "mymaster", + "visibility": "private", + "http_url_to_repo": "https://gitlab.com/mygroup/myproject.git", + "ssh_url_to_repo": "git@gitlab.com:mygroup/myproject.git", + "last_activity_at": "2014-12-01T09:17:51.000+01:00", + "name": "My Project", + "name_with_namespace": "My Group / My Project", + "path": "myproject", + "path_with_namespace": "mygroup/myproject", + "web_url": "https://gitlab.com/mygroup/myproject" +}"#; + + let api_url = "https://gitlab.com/api/v4/projects/mygroup%2Fmyproject"; + let url = "git@gitlab.com:mygroup/myproject"; + + let (http_downloader, _guard) = http_mock_with_body(api_url, project_data); + + // clone $this->config and merge gitlab-protocol => http. + let mut config = make_config(); + let mut top: IndexMap<String, PhpMixed> = IndexMap::new(); + let mut config_section: IndexMap<String, PhpMixed> = IndexMap::new(); + config_section.insert( + "gitlab-protocol".to_string(), + PhpMixed::String("http".to_string()), + ); + top.insert("config".to_string(), PhpMixed::Array(config_section)); + config.merge(&top, Config::SOURCE_UNKNOWN); + let config = Rc::new(RefCell::new(config)); + + let mut repo_config: IndexMap<String, PhpMixed> = IndexMap::new(); + repo_config.insert("url".to_string(), PhpMixed::String(url.to_string())); + let mut driver = GitLabDriver::new( + repo_config, + fixtures.io.clone(), + config, + http_downloader, + fixtures.process.clone(), + ); + driver.initialize().unwrap(); + assert_eq!( + "https://gitlab.com/mygroup/myproject.git", + driver.get_repository_url(), + "Repository URL matches config request for http not git" + ); } |
