Skip to content

Commit

Permalink
Add tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
milesj committed Sep 7, 2023
1 parent a37fca6 commit 6597d2e
Show file tree
Hide file tree
Showing 7 changed files with 162 additions and 35 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
- Setting global version with `proto global`.
- Setting local version with `proto local`.
- WASM API
- Added `is_musl` and `get_target_triple` helper functions.
- Added `command_exists`, `is_musl`, and `get_target_triple` helper functions.

#### ⚙️ Internal

Expand Down
8 changes: 2 additions & 6 deletions crates/cli/src/commands/install_all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ use crate::{
helpers::create_progress_bar,
};
use futures::future::try_join_all;
use proto_core::{
load_tool_from_locator, ProtoEnvironment, ToolsConfig, UnresolvedVersionSpec, UserConfig,
};
use proto_core::{load_tool_from_locator, ProtoEnvironment, ToolsConfig, UserConfig};
use starbase::system;
use starbase_styles::color;
use std::env;
Expand Down Expand Up @@ -40,9 +38,7 @@ pub async fn install_all() {

debug!("Detected version {} for {}", version, tool.get_name());

config
.tools
.insert(name, UnresolvedVersionSpec::Version(version));
config.tools.insert(name, version.to_implicit_type());
}
}

Expand Down
7 changes: 5 additions & 2 deletions crates/cli/tests/local_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ npm = "9.0.0"

assert_eq!(
fs::read_to_string(version_file).unwrap(),
r#"node = "19"
r#"node = "~19"
npm = "9.0.0"
"#
)
Expand Down Expand Up @@ -105,6 +105,9 @@ npm = "9.0.0"
cmd.arg("local").arg("npm").arg("1.2").assert().success();

assert!(version_file.exists());
assert_eq!(fs::read_to_string(version_file).unwrap(), "npm = \"1.2\"\n")
assert_eq!(
fs::read_to_string(version_file).unwrap(),
"npm = \"~1.2\"\n"
)
}
}
6 changes: 2 additions & 4 deletions crates/core/src/tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -467,9 +467,7 @@ impl Tool {
);

resolved = true;
version = VersionSpec::Version(
resolver.resolve(&UnresolvedVersionSpec::parse(candidate)?)?,
);
version = resolver.resolve(&UnresolvedVersionSpec::parse(candidate)?)?;
}

if let Some(candidate) = result.version {
Expand All @@ -485,7 +483,7 @@ impl Tool {
}

if !resolved {
version = VersionSpec::Version(resolver.resolve(initial_version)?);
version = resolver.resolve(initial_version)?;
}

debug!(
Expand Down
56 changes: 35 additions & 21 deletions crates/core/src/version_resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ impl<'tool> VersionResolver<'tool> {
Ok(())
}

pub fn resolve(&self, candidate: &UnresolvedVersionSpec) -> miette::Result<Version> {
pub fn resolve(&self, candidate: &UnresolvedVersionSpec) -> miette::Result<VersionSpec> {
resolve_version(candidate, &self.versions, &self.aliases, self.manifest)
}
}

pub fn match_highest_version<'l, I>(req: &'l VersionReq, versions: I) -> Option<Version>
pub fn match_highest_version<'l, I>(req: &'l VersionReq, versions: I) -> Option<VersionSpec>
where
I: IntoIterator<Item = &'l Version>,
{
Expand All @@ -62,11 +62,11 @@ where
}
}

highest_match
highest_match.map(VersionSpec::Version)
}

// Filter out aliases because they cannot be matched against
fn extract_installed_versions(installed: &HashSet<VersionSpec>) -> Vec<&Version> {
fn extract_installed_versions(installed: &HashSet<VersionSpec>) -> HashSet<&Version> {
installed
.iter()
.filter_map(|item| match item {
Expand All @@ -81,53 +81,67 @@ pub fn resolve_version(
versions: &[Version],
aliases: &BTreeMap<String, UnresolvedVersionSpec>,
manifest: Option<&ToolManifest>,
) -> miette::Result<Version> {
) -> miette::Result<VersionSpec> {
let installed_versions = if let Some(manifest) = manifest {
extract_installed_versions(&manifest.installed_versions)
} else {
HashSet::new()
};

match &candidate {
UnresolvedVersionSpec::Alias(alias) => {
let mut alias_value = None;

if let Some(manifest) = manifest {
if let Some(alias_type) = manifest.aliases.get(alias) {
return resolve_version(alias_type, versions, aliases, Some(manifest));
}
alias_value = manifest.aliases.get(alias);
}

if alias_value.is_none() {
alias_value = aliases.get(alias);
}

if let Some(alias_type) = aliases.get(alias) {
return resolve_version(alias_type, versions, aliases, manifest);
if let Some(value) = alias_value {
return resolve_version(value, versions, aliases, manifest);
}
}
UnresolvedVersionSpec::Req(req) => {
if let Some(manifest) = manifest {
if let Some(version) = match_highest_version(
req,
extract_installed_versions(&manifest.installed_versions),
) {
// Check locally installed versions first
if !installed_versions.is_empty() {
if let Some(version) = match_highest_version(req, installed_versions) {
return Ok(version);
}
}

// Otherwise we'll need to download from remote
if let Some(version) = match_highest_version(req, versions) {
return Ok(version);
}
}
UnresolvedVersionSpec::ReqAny(reqs) => {
for req in reqs {
if let Some(manifest) = manifest {
if let Some(version) = match_highest_version(
req,
extract_installed_versions(&manifest.installed_versions),
) {
// Check locally installed versions first
if !installed_versions.is_empty() {
if let Some(version) = match_highest_version(req, installed_versions.clone()) {
return Ok(version);
}
}

// Otherwise we'll need to download from remote
if let Some(version) = match_highest_version(req, versions) {
return Ok(version);
}
}
}
UnresolvedVersionSpec::Version(ver) => {
// Check locally installed versions first
if installed_versions.contains(ver) {
return Ok(VersionSpec::Version(ver.to_owned()));
}

// Otherwise we'll need to download from remote
for version in versions {
if ver == version {
return Ok(ver.to_owned());
return Ok(VersionSpec::Version(ver.to_owned()));
}
}
}
Expand Down
100 changes: 99 additions & 1 deletion crates/core/tests/version_resolver_test.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use proto_core::{resolve_version, UnresolvedVersionSpec};
use proto_core::{resolve_version, ToolManifest, UnresolvedVersionSpec, VersionSpec};
use semver::Version;
use std::collections::BTreeMap;

Expand Down Expand Up @@ -40,6 +40,28 @@ mod version_resolver {
])
}

fn create_manifest() -> ToolManifest {
let mut manifest = ToolManifest::default();

manifest.aliases.insert(
"latest-manifest".into(),
UnresolvedVersionSpec::Version(Version::new(8, 0, 0)),
);
manifest.aliases.insert(
"stable-manifest".into(),
UnresolvedVersionSpec::Alias("stable".into()),
);

manifest
.installed_versions
.insert(VersionSpec::parse("3.0.0").unwrap());
manifest
.installed_versions
.insert(VersionSpec::parse("3.3.3").unwrap());

manifest
}

#[test]
fn resolves_aliases() {
let versions = create_versions();
Expand Down Expand Up @@ -68,6 +90,35 @@ mod version_resolver {
);
}

#[test]
fn resolves_aliases_from_manifest() {
let versions = create_versions();
let aliases = create_aliases();
let manifest = create_manifest();

assert_eq!(
resolve_version(
&UnresolvedVersionSpec::Alias("latest-manifest".into()),
&versions,
&aliases,
Some(&manifest),
)
.unwrap(),
Version::new(8, 0, 0)
);

assert_eq!(
resolve_version(
&UnresolvedVersionSpec::Alias("stable-manifest".into()),
&versions,
&aliases,
Some(&manifest),
)
.unwrap(),
Version::new(10, 0, 0)
);
}

#[test]
#[should_panic(expected = "Failed to resolve a semantic version for unknown.")]
fn errors_unknown_alias() {
Expand Down Expand Up @@ -141,6 +192,24 @@ mod version_resolver {
);
}

#[test]
fn resolves_versions_from_manifest() {
let versions = create_versions();
let aliases = create_aliases();
let manifest = create_manifest();

assert_eq!(
resolve_version(
&UnresolvedVersionSpec::Version(Version::new(3, 0, 0)),
&versions,
&aliases,
Some(&manifest),
)
.unwrap(),
Version::new(3, 0, 0)
);
}

#[test]
fn resolves_partial_versions() {
let versions = create_versions();
Expand Down Expand Up @@ -180,6 +249,35 @@ mod version_resolver {
);
}

#[test]
fn resolves_partial_versions_with_manifest() {
let versions = create_versions();
let aliases = create_aliases();
let manifest = create_manifest();

assert_eq!(
resolve_version(
&UnresolvedVersionSpec::parse("3.3").unwrap(),
&versions,
&aliases,
Some(&manifest),
)
.unwrap(),
Version::new(3, 3, 3)
);

assert_eq!(
resolve_version(
&UnresolvedVersionSpec::parse("3").unwrap(),
&versions,
&aliases,
Some(&manifest),
)
.unwrap(),
Version::new(3, 3, 3)
);
}

#[test]
fn removes_v_prefix() {
let versions = create_versions();
Expand Down
18 changes: 18 additions & 0 deletions crates/pdk/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,24 @@ pub fn check_supported_os_and_arch(
Ok(())
}

/// Check whether a command exists or not on the host machine.
pub fn command_exists(env: &HostEnvironment, command: &str) -> bool {
let result = if env.os == HostOS::Windows {
let line = format!("Get-Command {command}");

unsafe {
exec_command(Json(ExecCommandInput::pipe(
"powershell",
["-Command", &line],
)))
}
} else {
unsafe { exec_command(Json(ExecCommandInput::pipe("which", [command]))) }
};

result.is_err() || result.is_ok_and(|out| out.0.exit_code != 0)
}

/// Detect whether the current OS is utilizing musl instead of gnu.
pub fn is_musl(env: &HostEnvironment) -> bool {
if !env.os.is_linux() {
Expand Down

0 comments on commit 6597d2e

Please sign in to comment.