diff options
Diffstat (limited to 'crates/shirabe/tests/repository/vcs_repository_test.rs')
| -rw-r--r-- | crates/shirabe/tests/repository/vcs_repository_test.rs | 220 |
1 files changed, 204 insertions, 16 deletions
diff --git a/crates/shirabe/tests/repository/vcs_repository_test.rs b/crates/shirabe/tests/repository/vcs_repository_test.rs index d84ed51..279db04 100644 --- a/crates/shirabe/tests/repository/vcs_repository_test.rs +++ b/crates/shirabe/tests/repository/vcs_repository_test.rs @@ -1,29 +1,145 @@ //! ref: composer/tests/Composer/Test/Repository/VcsRepositoryTest.php use std::cell::RefCell; +use std::collections::HashSet; +use std::process::Command; use std::rc::Rc; use indexmap::IndexMap; +use serial_test::serial; use shirabe::config::Config; use shirabe::io::IOInterface; use shirabe::io::null_io::NullIO; -use shirabe::package::dumper::ArrayDumper; -use shirabe::repository::RepositoryInterface; use shirabe::repository::VcsRepository; +use shirabe::util::ProcessExecutor; use shirabe::util::filesystem::Filesystem; use shirabe::util::http_downloader::HttpDownloader; +use shirabe::util::r#loop::Loop; use shirabe_php_shim::PhpMixed; +use tempfile::TempDir; struct SetUp { - composer_home: std::path::PathBuf, - git_repo: std::path::PathBuf, + composer_home: TempDir, + git_repo: TempDir, } -fn set_up() -> SetUp { - // setUp lazily runs initialize(), which shells out to git to build a fixture repository - // on disk; the ExecutableFinder/ProcessExecutor-driven setup and the markTestSkipped - // skip path are not ported. - todo!() +// ref: VcsRepositoryTest::initialize. Builds a fixture git repository on disk by shelling out to +// git. Returns None when git is unavailable (mirroring markTestSkipped). +fn set_up() -> Option<SetUp> { + if which_git().is_none() { + // 'This test needs a git binary in the PATH to be able to run' + return None; + } + + let composer_home = TempDir::new().unwrap(); + let git_repo = TempDir::new().unwrap(); + let path = git_repo.path(); + + let exec = |args: &[&str]| { + let status = Command::new("git") + .args(args) + .current_dir(path) + .env("GIT_CONFIG_GLOBAL", "/dev/null") + .env("GIT_CONFIG_SYSTEM", "/dev/null") + .status() + .unwrap_or_else(|e| panic!("Failed to execute git {:?}: {}", args, e)); + if !status.success() { + panic!("Failed to execute git {:?}", args); + } + }; + let write_file = |name: &str, contents: &str| { + std::fs::write(path.join(name), contents).unwrap(); + }; + + // init + exec(&["init", "-q"]); + exec(&["checkout", "-b", "master"]); + exec(&["config", "user.email", "composertest@example.org"]); + exec(&["config", "user.name", "ComposerTest"]); + exec(&["config", "commit.gpgsign", "false"]); + write_file("foo", ""); + exec(&["add", "foo"]); + exec(&["commit", "-m", "init"]); + + // non-composed tag & branch + exec(&["tag", "0.5.0"]); + exec(&["branch", "oldbranch"]); + + // add composed tag & master branch + write_file( + "composer.json", + &shirabe::json::JsonFile::encode(&composer(None)), + ); + exec(&["add", "composer.json"]); + exec(&["commit", "-m", "addcomposer"]); + exec(&["tag", "0.6.0"]); + + // add feature-a branch + exec(&["checkout", "-b", "feature/a-1.0-B"]); + write_file("foo", "bar feature"); + exec(&["add", "foo"]); + exec(&["commit", "-m", "change-a"]); + + // add foo#bar branch which should result in dev-foo+bar + exec(&["branch", "foo#bar"]); + + // add version to composer.json + exec(&["checkout", "master"]); + write_file( + "composer.json", + &shirabe::json::JsonFile::encode(&composer(Some("1.0.0"))), + ); + exec(&["add", "composer.json"]); + exec(&["commit", "-m", "addversion"]); + + // create tag with wrong version in it + exec(&["tag", "0.9.0"]); + // create tag with correct version in it + exec(&["tag", "1.0.0"]); + + // add feature-b branch + exec(&["checkout", "-b", "feature-b"]); + write_file("foo", "baz feature"); + exec(&["add", "foo"]); + exec(&["commit", "-m", "change-b"]); + + // add 1.0 branch + exec(&["checkout", "master"]); + exec(&["branch", "1.0"]); + + // add 1.0.x branch + exec(&["branch", "1.1.x"]); + + // update master to 2.0 + write_file( + "composer.json", + &shirabe::json::JsonFile::encode(&composer(Some("2.0.0"))), + ); + exec(&["add", "composer.json"]); + exec(&["commit", "-m", "bump-version"]); + + Some(SetUp { + composer_home, + git_repo, + }) +} + +fn composer(version: Option<&str>) -> PhpMixed { + let mut m: IndexMap<String, PhpMixed> = IndexMap::new(); + m.insert("name".to_string(), PhpMixed::String("a/b".to_string())); + if let Some(version) = version { + m.insert("version".to_string(), PhpMixed::String(version.to_string())); + } + PhpMixed::Array(m) +} + +fn which_git() -> Option<()> { + Command::new("git") + .arg("--version") + .output() + .ok() + .filter(|o| o.status.success()) + .map(|_| ()) } fn tear_down(composer_home: &std::path::Path, git_repo: &std::path::Path) { @@ -52,13 +168,85 @@ impl Drop for TearDown { } } -// testLoadVersions initialises a real git repository on disk and drives a VcsRepository over -// it, then asserts the loaded package versions; the git fixture setup and constraint parsing -// (look-around regex) are not ported. In addition, VcsRepository does not implement -// RepositoryInterface and keeps its inner ArrayRepository pub(crate), so getPackages() (inherited -// from ArrayRepository in PHP) is not reachable from the test crate. #[test] -#[ignore = "VcsRepository does not expose get_packages() to the test crate; git fixture setup not ported"] +#[serial] fn test_load_versions() { - todo!() + let Some(set_up) = set_up() else { + // git binary unavailable; skip like markTestSkipped. + return; + }; + let composer_home = set_up.composer_home.path().to_path_buf(); + let git_repo = set_up.git_repo.path().to_path_buf(); + + let mut expected: HashSet<String> = [ + "0.6.0", + "1.0.0", + "1.0.x-dev", + "1.1.x-dev", + "dev-feature-b", + "dev-feature/a-1.0-B", + "dev-foo+bar", + "dev-master", + "9999999-dev", // alias of dev-master + ] + .iter() + .map(|s| s.to_string()) + .collect(); + + let mut config = Config::new(true, None); + let mut top: IndexMap<String, PhpMixed> = IndexMap::new(); + let mut config_section: IndexMap<String, PhpMixed> = IndexMap::new(); + config_section.insert( + "home".to_string(), + PhpMixed::String(composer_home.to_string_lossy().into_owned()), + ); + top.insert("config".to_string(), PhpMixed::Array(config_section)); + config.merge(&top, Config::SOURCE_UNKNOWN); + let config = Rc::new(RefCell::new(config)); + + let io: Rc<RefCell<dyn IOInterface>> = Rc::new(RefCell::new(NullIO::new())); + let http_downloader = Rc::new(RefCell::new(HttpDownloader::new( + io.clone(), + config.clone(), + IndexMap::new(), + false, + ))); + let process = Rc::new(RefCell::new(ProcessExecutor::new(Some(io.clone())))); + // VcsRepository's git driver / VersionGuesser run async git processes; constructing a Loop + // enables async on the shared ProcessExecutor. + let _loop = Loop::new(http_downloader.clone(), Some(process.clone())); + + let mut repo_config: IndexMap<String, PhpMixed> = IndexMap::new(); + repo_config.insert( + "url".to_string(), + PhpMixed::String(git_repo.to_string_lossy().into_owned()), + ); + repo_config.insert("type".to_string(), PhpMixed::String("vcs".to_string())); + + let mut repo = VcsRepository::new( + repo_config, + io, + config, + http_downloader, + None, + Some(process), + None, + None, + ) + .unwrap(); + + let _tear_down = TearDown::new(composer_home, git_repo); + + let packages = repo.__get_packages().unwrap(); + + for package in &packages { + let pretty = package.get_pretty_version(); + assert!(expected.remove(&pretty), "Unexpected version {}", pretty); + } + + assert!( + expected.is_empty(), + "Missing versions: {}", + expected.into_iter().collect::<Vec<_>>().join(", ") + ); } |
