aboutsummaryrefslogtreecommitdiffhomepage
path: root/crates/shirabe/tests/repository/vcs_repository_test.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/shirabe/tests/repository/vcs_repository_test.rs')
-rw-r--r--crates/shirabe/tests/repository/vcs_repository_test.rs220
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(", ")
+ );
}