diff options
Diffstat (limited to 'crates/shirabe/tests/package')
| -rw-r--r-- | crates/shirabe/tests/package/loader/root_package_loader_test.rs | 232 | ||||
| -rw-r--r-- | crates/shirabe/tests/package/version/version_selector_test.rs | 521 |
2 files changed, 715 insertions, 38 deletions
diff --git a/crates/shirabe/tests/package/loader/root_package_loader_test.rs b/crates/shirabe/tests/package/loader/root_package_loader_test.rs index 23c8beb..7fa970a 100644 --- a/crates/shirabe/tests/package/loader/root_package_loader_test.rs +++ b/crates/shirabe/tests/package/loader/root_package_loader_test.rs @@ -4,21 +4,28 @@ // ProcessExecutor / VersionGuesser or require constraints whose parsing goes through a // look-around regex the regex crate cannot compile. -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; 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::RootPackage; use shirabe::package::loader::RootPackageLoader; -use shirabe::package::version::{VersionGuesser, VersionParser}; +use shirabe::package::version::{ + VersionData, VersionGuesser, VersionGuesserInterface, VersionParser, +}; use shirabe::package::{STABILITY_ALPHA, STABILITY_DEV, STABILITY_RC}; use shirabe::repository::RepositoryManager; +use shirabe::util::Git as GitUtil; use shirabe::util::http_downloader::HttpDownloader; -use shirabe::util::process_executor::ProcessExecutor; +use shirabe::util::process_executor::{MockExpectation, MockHandler, ProcessExecutor}; use shirabe_php_shim::PhpMixed; +use crate::process_executor_mock::{cmd, cmd_full, get_process_executor_mock}; + fn null_io() -> Rc<RefCell<dyn IOInterface>> { Rc::new(RefCell::new(NullIO::new())) } @@ -35,6 +42,73 @@ fn http_downloader( ))) } +// `$config = new Config; $config->merge(['repositories' => ['packagist' => false]]);` +fn make_config() -> Rc<RefCell<Config>> { + let config = Rc::new(RefCell::new(Config::new(true, None))); + let mut repositories: IndexMap<String, PhpMixed> = IndexMap::new(); + repositories.insert("packagist".to_string(), PhpMixed::Bool(false)); + let mut merge: IndexMap<String, PhpMixed> = IndexMap::new(); + merge.insert("repositories".to_string(), PhpMixed::Array(repositories)); + config.borrow_mut().merge(&merge, "test"); + config +} + +// Stands in for `getMockBuilder('Composer\Repository\RepositoryManager')->disableOriginalConstructor()`. +// The loader only stores it and feeds it default repositories, so a real instance suffices. +fn make_manager( + io: &Rc<RefCell<dyn IOInterface>>, + config: &Rc<RefCell<Config>>, +) -> Rc<RefCell<RepositoryManager>> { + Rc::new(RefCell::new(RepositoryManager::new( + io.clone(), + config.clone(), + http_downloader(io, config), + None, + None, + ))) +} + +fn require_map(entries: &[(&str, &str)]) -> PhpMixed { + let mut m: IndexMap<String, PhpMixed> = IndexMap::new(); + for (k, v) in entries { + m.insert(k.to_string(), PhpMixed::String(v.to_string())); + } + PhpMixed::Array(m) +} + +// Resets the cached git `version` static on drop so a seeded value does not leak into other +// tests in this binary (VersionGuesserTest seeds/resets the same static). +struct GitVersionGuard; + +impl Drop for GitVersionGuard { + fn drop(&mut self) { + GitUtil::__reset_version(); + } +} + +// A test double for the concrete VersionGuesser, supplied through the VersionGuesserInterface seam. +#[derive(Debug)] +struct VersionGuesserMock { + version_data: VersionData, + guess_version_calls: Rc<Cell<u32>>, +} + +impl VersionGuesserInterface for VersionGuesserMock { + fn guess_version( + &mut self, + _package_config: &IndexMap<String, PhpMixed>, + _path: &str, + ) -> anyhow::Result<Option<VersionData>> { + self.guess_version_calls + .set(self.guess_version_calls.get() + 1); + Ok(Some(self.version_data.clone())) + } + + fn get_root_version_from_env(&self) -> anyhow::Result<String> { + unreachable!("COMPOSER_ROOT_VERSION is not set in this test") + } +} + #[test] #[ignore = "process_executor.enable_async() drives the async stream path, which calls stream_set_blocking (fcntl(2) todo!() in shirabe-php-shim::stream)"] fn test_stability_flags_parsing() { @@ -70,7 +144,8 @@ fn test_stability_flags_parsing() { Some(io.clone()), ); - let mut loader = RootPackageLoader::new(manager, config.clone(), None, Some(guesser), None); + let mut loader = + RootPackageLoader::new(manager, config.clone(), None, Some(Box::new(guesser)), None); let mut data = IndexMap::new(); data.insert( @@ -136,25 +211,158 @@ fn test_stability_flags_parsing() { } #[test] -#[ignore = "requires getProcessExecutorMock with expects(['return' => 1]); no ProcessExecutorMock mocking infrastructure exists"] +#[serial] fn test_no_version_is_visible_in_pretty_version() { - todo!() + GitUtil::__reset_version(); + let _git_guard = GitVersionGuard; + + let io = null_io(); + let config = make_config(); + let manager = make_manager(&io, &config); + + let (process, _guard) = get_process_executor_mock( + vec![], + false, + MockHandler { + r#return: 1, + ..Default::default() + }, + ); + let guesser = VersionGuesser::new(config.clone(), process, VersionParser::new(), None); + + let mut loader = + RootPackageLoader::new(manager, config.clone(), None, Some(Box::new(guesser)), None); + + let package = loader + .load(IndexMap::new(), "Composer\\Package\\RootPackage", None) + .unwrap(); + let package = package.as_root().unwrap(); + + assert_eq!("1.0.0.0", package.get_version()); + assert_eq!( + RootPackage::DEFAULT_PRETTY_VERSION, + package.get_pretty_version() + ); } #[test] -#[ignore = "requires getMockBuilder VersionGuesser mock with guessVersion expectation; no VersionGuesser mocking infrastructure exists"] +#[serial] fn test_pretty_version_for_root_package_in_version_branch() { - todo!() + // see #6845 + let io = null_io(); + let config = make_config(); + let manager = make_manager(&io, &config); + + let guess_version_calls = Rc::new(Cell::new(0u32)); + let version_guesser = VersionGuesserMock { + version_data: VersionData { + version: Some("3.0.9999999.9999999-dev".to_string()), + commit: Some("aabbccddee".to_string()), + pretty_version: Some("3.0-dev".to_string()), + feature_version: None, + feature_pretty_version: None, + }, + guess_version_calls: guess_version_calls.clone(), + }; + + let mut loader = RootPackageLoader::new( + manager, + config.clone(), + None, + Some(Box::new(version_guesser)), + None, + ); + + let package = loader + .load(IndexMap::new(), "Composer\\Package\\RootPackage", None) + .unwrap(); + + assert!(guess_version_calls.get() >= 1); + assert_eq!("3.0-dev", package.as_root().unwrap().get_pretty_version()); } #[test] -#[ignore = "requires getProcessExecutorMock with expects() git command expectations; no ProcessExecutorMock mocking infrastructure exists"] +#[ignore = "feature-branch guessing calls ProcessExecutor::execute_async, whose mock path is todo!()"] +#[serial] fn test_feature_branch_pretty_version() { - todo!() + // proc_open() is always available; the PHP markTestSkipped guard does not apply here. + GitUtil::__set_version(Some("2.52.0".to_string())); + let _git_guard = GitVersionGuard; + + let io = null_io(); + let config = make_config(); + let manager = make_manager(&io, &config); + + let expectations: Vec<MockExpectation> = vec![ + cmd_full( + ["git", "branch", "-a", "--no-color", "--no-abbrev", "-v"], + 0, + "* latest-production 38137d2f6c70e775e137b2d8a7a7d3eaebf7c7e5 Commit message\n master 4f6ed96b0bc363d2aa4404c3412de1c011f67c66 Commit message\n", + "", + ), + cmd(["git", "rev-list", "master..latest-production"]), + ]; + let (process, _guard) = get_process_executor_mock(expectations, true, MockHandler::default()); + let guesser = VersionGuesser::new(config.clone(), process, VersionParser::new(), None); + + let mut loader = + RootPackageLoader::new(manager, config.clone(), None, Some(Box::new(guesser)), None); + + let mut data = IndexMap::new(); + data.insert( + "require".to_string(), + require_map(&[("foo/bar", "self.version")]), + ); + + let package = loader + .load(data, "Composer\\Package\\RootPackage", None) + .unwrap(); + + assert_eq!( + "dev-master", + package.as_root().unwrap().get_pretty_version() + ); } #[test] -#[ignore = "requires getProcessExecutorMock with expects() git command expectations; no ProcessExecutorMock mocking infrastructure exists"] +#[serial] fn test_non_feature_branch_pretty_version() { - todo!() + // proc_open() is always available; the PHP markTestSkipped guard does not apply here. + GitUtil::__set_version(Some("2.52.0".to_string())); + let _git_guard = GitVersionGuard; + + let io = null_io(); + let config = make_config(); + let manager = make_manager(&io, &config); + + let expectations: Vec<MockExpectation> = vec![cmd_full( + ["git", "branch", "-a", "--no-color", "--no-abbrev", "-v"], + 0, + "* latest-production 38137d2f6c70e775e137b2d8a7a7d3eaebf7c7e5 Commit message\n master 4f6ed96b0bc363d2aa4404c3412de1c011f67c66 Commit message\n", + "", + )]; + let (process, _guard) = get_process_executor_mock(expectations, true, MockHandler::default()); + let guesser = VersionGuesser::new(config.clone(), process, VersionParser::new(), None); + + let mut loader = + RootPackageLoader::new(manager, config.clone(), None, Some(Box::new(guesser)), None); + + let mut data = IndexMap::new(); + data.insert( + "require".to_string(), + require_map(&[("foo/bar", "self.version")]), + ); + data.insert( + "non-feature-branches".to_string(), + PhpMixed::List(vec![PhpMixed::String("latest-.*".to_string())]), + ); + + let package = loader + .load(data, "Composer\\Package\\RootPackage", None) + .unwrap(); + + assert_eq!( + "dev-latest-production", + package.as_root().unwrap().get_pretty_version() + ); } diff --git a/crates/shirabe/tests/package/version/version_selector_test.rs b/crates/shirabe/tests/package/version/version_selector_test.rs index fa288cd..f48a6ce 100644 --- a/crates/shirabe/tests/package/version/version_selector_test.rs +++ b/crates/shirabe/tests/package/version/version_selector_test.rs @@ -1,77 +1,546 @@ //! ref: composer/tests/Composer/Test/Package/Version/VersionSelectorTest.php -// VersionSelector ranks candidate packages whose versions/constraints are parsed through a -// look-around regex the regex crate cannot compile; the setup also mocks a repository. +use std::cell::RefCell; +use std::rc::Rc; + +use indexmap::IndexMap; +use shirabe::filter::platform_requirement_filter::PlatformRequirementFilterFactory; +use shirabe::io::BufferIO; +use shirabe::io::IOInterface; +use shirabe::package::BasePackageHandle; +use shirabe::package::CompleteAliasPackageHandle; +use shirabe::package::CompletePackageHandle; +use shirabe::package::Link; +use shirabe::package::PackageInterfaceHandle; +use shirabe::package::version::VersionSelector; +use shirabe::package::version::version_parser::VersionParser; +use shirabe::repository::PlatformRepository; +use shirabe::repository::RepositorySetInterface; +use shirabe_php_shim::PhpMixed; +use shirabe_semver::constraint::AnyConstraint; + +use shirabe_external_packages::symfony::console::output::output_interface; + +use crate::test_case::get_package; + +mockall::mock! { + RepositorySet {} + impl RepositorySetInterface for RepositorySet { + fn find_packages( + &self, + name: &str, + constraint: Option<AnyConstraint>, + flags: i64, + ) -> anyhow::Result<Vec<BasePackageHandle>>; + } +} + +// `RepositorySetInterface` requires `Debug`; mockall does not generate it. +impl std::fmt::Debug for MockRepositorySet { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("MockRepositorySet") + } +} + +fn into_seam(mock: MockRepositorySet) -> Rc<RefCell<dyn RepositorySetInterface>> { + Rc::new(RefCell::new(mock)) +} + +/// Mirrors PHPUnit `assertSame($expected, $best)`: object identity, not value equality. +fn assert_same( + best: &Option<PackageInterfaceHandle>, + expected: &PackageInterfaceHandle, + msg: &str, +) { + let best = best + .as_ref() + .unwrap_or_else(|| panic!("{msg}: expected Some(_), got None")); + assert!(best.ptr_eq(expected), "{msg}"); +} + +fn require_link(package_name: &str, target: &str, pretty_constraint: &str) -> Link { + let parser = VersionParser::new(); + Link::new( + package_name.to_string(), + target.to_string(), + parser.parse_constraints(pretty_constraint).unwrap(), + Some(Link::TYPE_REQUIRE.to_string()), + pretty_constraint.to_string(), + ) +} + +fn find_best( + version_selector: &mut VersionSelector, + package_name: &str, + preferred_stability: &str, + platform_requirement_filter: Option< + std::rc::Rc< + dyn shirabe::filter::platform_requirement_filter::PlatformRequirementFilterInterface, + >, + >, + io: Option<Rc<RefCell<dyn IOInterface>>>, +) -> Option<PackageInterfaceHandle> { + version_selector + .find_best_candidate( + package_name, + None, + preferred_stability, + platform_requirement_filter, + 0, + io, + PhpMixed::Bool(true), + ) + .unwrap() +} + #[test] -#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"] fn test_latest_version_is_returned() { - todo!() + let package_name = "foo/bar"; + + let package1 = get_package("foo/bar", "1.2.1"); + let package2 = get_package("foo/bar", "1.2.2"); + let package3 = get_package("foo/bar", "1.2.0"); + let packages = vec![package1.clone(), package2.clone(), package3.clone()]; + + let mut repository_set = MockRepositorySet::new(); + repository_set + .expect_find_packages() + .times(1) + .returning_st(move |_, _, _| Ok(packages.clone())); + + let mut version_selector = VersionSelector::new(into_seam(repository_set), None).unwrap(); + let best = find_best(&mut version_selector, package_name, "stable", None, None); + + // 1.2.2 should be returned because it's the latest of the returned versions + assert_same(&best, &package2, "Latest version should be 1.2.2"); } #[test] -#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"] +#[ignore = "PlatformRepository initialization calls shirabe_php_shim::runtime::constant() which is still todo!(); unrelated to the RepositorySet seam"] fn test_latest_version_is_returned_that_matches_php_requirements() { - todo!() + let package_name = "foo/bar"; + + let mut overrides: IndexMap<String, PhpMixed> = IndexMap::new(); + overrides.insert("php".to_string(), PhpMixed::String("5.5.0".to_string())); + let mut platform = PlatformRepository::new(vec![], overrides).unwrap(); + + let package0 = get_package("foo/bar", "0.9.0"); + package0.__set_requires(IndexMap::from([( + "php".to_string(), + require_link(package_name, "php", ">=5.6"), + )])); + let package1 = get_package("foo/bar", "1.0.0"); + package1.__set_requires(IndexMap::from([( + "php".to_string(), + require_link(package_name, "php", ">=5.4"), + )])); + let package2 = get_package("foo/bar", "2.0.0"); + package2.__set_requires(IndexMap::from([( + "php".to_string(), + require_link(package_name, "php", ">=5.6"), + )])); + let package3 = get_package("foo/bar", "2.1.0"); + package3.__set_requires(IndexMap::from([( + "php".to_string(), + require_link(package_name, "php", ">=5.6"), + )])); + let packages = vec![ + package0.clone(), + package1.clone(), + package2.clone(), + package3.clone(), + ]; + + let mut repository_set = MockRepositorySet::new(); + repository_set + .expect_find_packages() + .times(3) + .returning_st(move |_, _, _| Ok(packages.clone())); + + let mut version_selector = + VersionSelector::new(into_seam(repository_set), Some(&mut platform)).unwrap(); + + let io = Rc::new(RefCell::new( + BufferIO::new(String::new(), output_interface::VERBOSITY_NORMAL, None).unwrap(), + )); + let io_dyn: Rc<RefCell<dyn IOInterface>> = io.clone(); + let best = find_best( + &mut version_selector, + package_name, + "stable", + None, + Some(io_dyn), + ); + assert_same( + &best, + &package1, + "Latest version supporting php 5.5 should be returned (1.0.0)", + ); + assert_eq!( + "<warning>Cannot use foo/bar's latest version 2.1.0 as it requires php >=5.6 which is not satisfied by your platform.\n", + io.borrow().get_output() + ); + + let io = Rc::new(RefCell::new( + BufferIO::new(String::new(), output_interface::VERBOSITY_VERBOSE, None).unwrap(), + )); + let io_dyn: Rc<RefCell<dyn IOInterface>> = io.clone(); + let best = find_best( + &mut version_selector, + package_name, + "stable", + None, + Some(io_dyn), + ); + assert_same( + &best, + &package1, + "Latest version supporting php 5.5 should be returned (1.0.0)", + ); + assert_eq!( + "<warning>Cannot use foo/bar's latest version 2.1.0 as it requires php >=5.6 which is not satisfied by your platform.\n\ + <warning>Cannot use foo/bar 2.0.0 as it requires php >=5.6 which is not satisfied by your platform.\n", + io.borrow().get_output() + ); + + let best = find_best( + &mut version_selector, + package_name, + "stable", + Some(PlatformRequirementFilterFactory::ignore_all()), + None, + ); + assert_same( + &best, + &package3, + "Latest version should be returned when ignoring platform reqs (2.1.0)", + ); } #[test] -#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"] +#[ignore = "PlatformRepository initialization calls shirabe_php_shim::runtime::constant() which is still todo!(); unrelated to the RepositorySet seam"] fn test_latest_version_is_returned_that_matches_ext_requirements() { - todo!() + let package_name = "foo/bar"; + + let mut overrides: IndexMap<String, PhpMixed> = IndexMap::new(); + overrides.insert("ext-zip".to_string(), PhpMixed::String("5.3.0".to_string())); + let mut platform = PlatformRepository::new(vec![], overrides).unwrap(); + + let package1 = get_package("foo/bar", "1.0.0"); + package1.__set_requires(IndexMap::from([( + "ext-zip".to_string(), + require_link(package_name, "ext-zip", "^5.2"), + )])); + let package2 = get_package("foo/bar", "2.0.0"); + package2.__set_requires(IndexMap::from([( + "ext-zip".to_string(), + require_link(package_name, "ext-zip", "^5.4"), + )])); + let packages = vec![package1.clone(), package2.clone()]; + + let mut repository_set = MockRepositorySet::new(); + repository_set + .expect_find_packages() + .times(2) + .returning_st(move |_, _, _| Ok(packages.clone())); + + let mut version_selector = + VersionSelector::new(into_seam(repository_set), Some(&mut platform)).unwrap(); + + let best = find_best(&mut version_selector, package_name, "stable", None, None); + assert_same( + &best, + &package1, + "Latest version supporting ext-zip 5.3.0 should be returned (1.0.0)", + ); + let best = find_best( + &mut version_selector, + package_name, + "stable", + Some(PlatformRequirementFilterFactory::ignore_all()), + None, + ); + assert_same( + &best, + &package2, + "Latest version should be returned when ignoring platform reqs (2.0.0)", + ); } #[test] -#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"] +#[ignore = "PlatformRepository initialization calls shirabe_php_shim::runtime::constant() which is still todo!(); unrelated to the RepositorySet seam"] fn test_latest_version_is_returned_that_matches_platform_ext() { - todo!() + let package_name = "foo/bar"; + + let mut platform = PlatformRepository::new(vec![], IndexMap::new()).unwrap(); + + let package1 = get_package("foo/bar", "1.0.0"); + let package2 = get_package("foo/bar", "2.0.0"); + package2.__set_requires(IndexMap::from([( + "ext-barfoo".to_string(), + require_link(package_name, "ext-barfoo", "*"), + )])); + let packages = vec![package1.clone(), package2.clone()]; + + let mut repository_set = MockRepositorySet::new(); + repository_set + .expect_find_packages() + .times(2) + .returning_st(move |_, _, _| Ok(packages.clone())); + + let mut version_selector = + VersionSelector::new(into_seam(repository_set), Some(&mut platform)).unwrap(); + + let best = find_best(&mut version_selector, package_name, "stable", None, None); + assert_same( + &best, + &package1, + "Latest version not requiring ext-barfoo should be returned (1.0.0)", + ); + let best = find_best( + &mut version_selector, + package_name, + "stable", + Some(PlatformRequirementFilterFactory::ignore_all()), + None, + ); + assert_same( + &best, + &package2, + "Latest version should be returned when ignoring platform reqs (2.0.0)", + ); } #[test] -#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"] +#[ignore = "PlatformRepository initialization calls shirabe_php_shim::runtime::constant() which is still todo!(); unrelated to the RepositorySet seam"] fn test_latest_version_is_returned_that_matches_composer_requirements() { - todo!() + let package_name = "foo/bar"; + + let mut overrides: IndexMap<String, PhpMixed> = IndexMap::new(); + overrides.insert( + "composer-runtime-api".to_string(), + PhpMixed::String("1.0.0".to_string()), + ); + let mut platform = PlatformRepository::new(vec![], overrides).unwrap(); + + let package1 = get_package("foo/bar", "1.0.0"); + package1.__set_requires(IndexMap::from([( + "composer-runtime-api".to_string(), + require_link(package_name, "composer-runtime-api", "^1.0"), + )])); + let package2 = get_package("foo/bar", "1.1.0"); + package2.__set_requires(IndexMap::from([( + "composer-runtime-api".to_string(), + require_link(package_name, "composer-runtime-api", "^2.0"), + )])); + let packages = vec![package1.clone(), package2.clone()]; + + let mut repository_set = MockRepositorySet::new(); + repository_set + .expect_find_packages() + .times(2) + .returning_st(move |_, _, _| Ok(packages.clone())); + + let mut version_selector = + VersionSelector::new(into_seam(repository_set), Some(&mut platform)).unwrap(); + + let best = find_best(&mut version_selector, package_name, "stable", None, None); + assert_same( + &best, + &package1, + "Latest version supporting composer 1 should be returned (1.0.0)", + ); + let best = find_best( + &mut version_selector, + package_name, + "stable", + Some(PlatformRequirementFilterFactory::ignore_all()), + None, + ); + assert_same( + &best, + &package2, + "Latest version should be returned when ignoring platform reqs (1.1.0)", + ); } #[test] -#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"] fn test_most_stable_version_is_returned() { - todo!() + let package_name = "foo/bar"; + + let package1 = get_package("foo/bar", "1.0.0"); + let package2 = get_package("foo/bar", "1.1.0-beta"); + let packages = vec![package1.clone(), package2.clone()]; + + let mut repository_set = MockRepositorySet::new(); + repository_set + .expect_find_packages() + .times(1) + .returning_st(move |_, _, _| Ok(packages.clone())); + + let mut version_selector = VersionSelector::new(into_seam(repository_set), None).unwrap(); + let best = find_best(&mut version_selector, package_name, "stable", None, None); + + assert_same( + &best, + &package1, + "Latest most stable version should be returned (1.0.0)", + ); } #[test] -#[ignore = "requires mocking RepositorySet::find_packages with willReturnOnConsecutiveCalls; RepositorySet is a concrete struct with no injectable/overridable find_packages"] fn test_most_stable_version_is_returned_regardless_of_order() { - todo!() + let package_name = "foo/bar"; + + let package1 = get_package("foo/bar", "2.x-dev"); + let package2 = get_package("foo/bar", "2.0.0-beta3"); + let packages = vec![package1.clone(), package2.clone()]; + let reversed: Vec<PackageInterfaceHandle> = packages.iter().rev().cloned().collect(); + + let mut repository_set = MockRepositorySet::new(); + let mut seq = mockall::Sequence::new(); + repository_set + .expect_find_packages() + .times(1) + .in_sequence(&mut seq) + .returning_st(move |_, _, _| Ok(packages.clone())); + repository_set + .expect_find_packages() + .times(1) + .in_sequence(&mut seq) + .returning_st(move |_, _, _| Ok(reversed.clone())); + + let mut version_selector = VersionSelector::new(into_seam(repository_set), None).unwrap(); + let best = find_best(&mut version_selector, package_name, "stable", None, None); + assert_same( + &best, + &package2, + "Expecting 2.0.0-beta3, cause beta is more stable than dev", + ); + + let best = find_best(&mut version_selector, package_name, "stable", None, None); + assert_same( + &best, + &package2, + "Expecting 2.0.0-beta3, cause beta is more stable than dev", + ); } #[test] -#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"] fn test_highest_version_is_returned() { - todo!() + let package_name = "foo/bar"; + + let package1 = get_package("foo/bar", "1.0.0"); + let package2 = get_package("foo/bar", "1.1.0-beta"); + let packages = vec![package1.clone(), package2.clone()]; + + let mut repository_set = MockRepositorySet::new(); + repository_set + .expect_find_packages() + .times(1) + .returning_st(move |_, _, _| Ok(packages.clone())); + + let mut version_selector = VersionSelector::new(into_seam(repository_set), None).unwrap(); + let best = find_best(&mut version_selector, package_name, "dev", None, None); + + assert_same( + &best, + &package2, + "Latest version should be returned (1.1.0-beta)", + ); } #[test] -#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"] fn test_highest_version_matching_stability_is_returned() { - todo!() + let package_name = "foo/bar"; + + let package1 = get_package("foo/bar", "1.0.0"); + let package2 = get_package("foo/bar", "1.1.0-beta"); + let package3 = get_package("foo/bar", "1.2.0-alpha"); + let packages = vec![package1.clone(), package2.clone(), package3.clone()]; + + let mut repository_set = MockRepositorySet::new(); + repository_set + .expect_find_packages() + .times(1) + .returning_st(move |_, _, _| Ok(packages.clone())); + + let mut version_selector = VersionSelector::new(into_seam(repository_set), None).unwrap(); + let best = find_best(&mut version_selector, package_name, "beta", None, None); + + assert_same( + &best, + &package2, + "Latest version should be returned (1.1.0-beta)", + ); } #[test] -#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"] fn test_most_stable_unstable_version_is_returned() { - todo!() + let package_name = "foo/bar"; + + let package2 = get_package("foo/bar", "1.1.0-beta"); + let package3 = get_package("foo/bar", "1.2.0-alpha"); + let packages = vec![package2.clone(), package3.clone()]; + + let mut repository_set = MockRepositorySet::new(); + repository_set + .expect_find_packages() + .times(1) + .returning_st(move |_, _, _| Ok(packages.clone())); + + let mut version_selector = VersionSelector::new(into_seam(repository_set), None).unwrap(); + let best = find_best(&mut version_selector, package_name, "stable", None, None); + + assert_same( + &best, + &package2, + "Latest version should be returned (1.1.0-beta)", + ); } #[test] -#[ignore = "requires mocking RepositorySet::find_packages to return fixed package objects; RepositorySet is a concrete struct with no injectable/overridable find_packages"] fn test_default_branch_alias_is_never_returned() { - todo!() + let package_name = "foo/bar"; + + let package = get_package("foo/bar", "1.1.0-beta"); + let package2 = get_package("foo/bar", "dev-main"); + let package2_complete = CompletePackageHandle::from_rc_unchecked(package2.as_rc().clone()); + let package2_alias: PackageInterfaceHandle = CompleteAliasPackageHandle::new( + package2_complete, + VersionParser::DEFAULT_BRANCH_ALIAS.to_string(), + VersionParser::DEFAULT_BRANCH_ALIAS.to_string(), + ) + .into(); + let packages = vec![package.clone(), package2_alias.clone()]; + + let mut repository_set = MockRepositorySet::new(); + repository_set + .expect_find_packages() + .times(1) + .returning_st(move |_, _, _| Ok(packages.clone())); + + let mut version_selector = VersionSelector::new(into_seam(repository_set), None).unwrap(); + let best = find_best(&mut version_selector, package_name, "dev", None, None); + + assert_same( + &best, + &package2, + "Latest version should be returned (dev-main)", + ); } #[test] -#[ignore = "requires mocking RepositorySet::find_packages to return an empty list; RepositorySet is a concrete struct with no injectable/overridable find_packages"] fn test_false_returned_on_no_packages() { - todo!() + let mut repository_set = MockRepositorySet::new(); + repository_set + .expect_find_packages() + .times(1) + .returning_st(|_, _, _| Ok(vec![])); + + let mut version_selector = VersionSelector::new(into_seam(repository_set), None).unwrap(); + let best = find_best(&mut version_selector, "foobaz", "stable", None, None); + assert!(best.is_none(), "No versions are available returns false"); } #[test] |
