Skip to content

Commit

Permalink
Add tests for installing all types of extensions
Browse files Browse the repository at this point in the history
  • Loading branch information
autarch committed May 26, 2024
1 parent a981f64 commit 6973ba1
Show file tree
Hide file tree
Showing 14 changed files with 84 additions and 14 deletions.
56 changes: 54 additions & 2 deletions src/extension.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
use anyhow::Result;
use itertools::Itertools;
use std::path::Path;
use strum::{EnumIter, IntoEnumIterator};
use thiserror::Error;

#[derive(Debug, Error)]
pub(crate) enum ExtensionError {
#[error("{path:} has unknown extension {ext:}")]
UnknownExtension { path: String, ext: String },
}

#[derive(Debug, EnumIter, PartialEq, Eq)]
pub(crate) enum Extension {
Expand Down Expand Up @@ -37,13 +46,56 @@ impl Extension {
}
}

pub(crate) fn from_path<S: AsRef<str>>(path: S) -> Option<Extension> {
pub(crate) fn from_path<S: AsRef<str>>(path: S) -> Result<Option<Extension>> {
let path = path.as_ref();
// We need to try the longest extension first so that ".tar.gz"
// matches before ".gz" and so on for other compression formats.
Extension::iter()
if let Some(ext) = Extension::iter()
.sorted_by(|a, b| Ord::cmp(&a.extension().len(), &b.extension().len()))
.rev()
.find(|e| path.ends_with(e.extension()))
{
Ok(Some(ext))
} else {
if let Some(ext) = Path::new(path).extension() {
return Err(ExtensionError::UnknownExtension {
path: path.to_string(),
ext: ext.to_string_lossy().to_string(),
}
.into());
}
Ok(None)
}
}
}

#[cfg(test)]
mod test {
use super::*;
use test_case::test_case;

#[test_case("foo.bz", Ok(Some(Extension::Bz)))]
#[test_case("foo.bz2", Ok(Some(Extension::Bz2)))]
#[test_case("foo.exe", Ok(Some(Extension::Exe)))]
#[test_case("foo.gz", Ok(Some(Extension::Gz)))]
#[test_case("foo.tar.bz", Ok(Some(Extension::TarBz)))]
#[test_case("foo.tar.bz2", Ok(Some(Extension::TarBz2)))]
#[test_case("foo.tar.gz", Ok(Some(Extension::TarGz)))]
#[test_case("foo.tar.xz", Ok(Some(Extension::TarXz)))]
#[test_case("foo.xz", Ok(Some(Extension::Xz)))]
#[test_case("foo.zip", Ok(Some(Extension::Zip)))]
#[test_case("foo", Ok(None))]
#[test_case("foo.bar", Err(ExtensionError::UnknownExtension { path: "foo.bar".to_string(), ext: "bar".to_string() }.into()))]
fn from_path(path: &str, expect: Result<Option<Extension>>) {
let ext = Extension::from_path(path);
if expect.is_ok() {
assert!(ext.is_ok());
assert_eq!(ext.unwrap(), expect.unwrap());
} else {
assert_eq!(
ext.unwrap_err().to_string(),
expect.unwrap_err().to_string()
);
}
}
}
40 changes: 29 additions & 11 deletions src/installer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ impl Installer {
)
})
.to_string_lossy();
match Extension::from_path(filename) {
match Extension::from_path(filename)? {
Some(Extension::TarBz)
| Some(Extension::TarBz2)
| Some(Extension::TarGz)
Expand Down Expand Up @@ -196,22 +196,40 @@ fn open_file(path: &Path) -> Result<File> {
#[cfg(test)]
mod tests {
use super::*;
#[cfg(target_family = "unix")]
use std::os::unix::fs::PermissionsExt;
use tempfile::tempdir;

#[test]
fn extract_binary() -> Result<()> {
use test_case::test_case;

#[test_case("test-data/project.bz", "project")]
#[test_case("test-data/project.bz2", "project")]
#[test_case("test-data/project.exe", "project")]
#[test_case("test-data/project.gz", "project")]
#[test_case("test-data/project.tar.bz", "project")]
#[test_case("test-data/project.tar.bz2", "project")]
#[test_case("test-data/project.tar.gz", "project")]
#[test_case("test-data/project.tar.xz", "project")]
#[test_case("test-data/project.xz", "project")]
#[test_case("test-data/project.zip", "project")]
#[test_case("test-data/project", "project")]
fn install(archive_path: &str, exe: &str) -> Result<()> {
//crate::ubi::init_logger(log::LevelFilter::Debug)?;

let td = tempdir()?;
let mut install_path = td.path().to_path_buf();
install_path.push("project");
let installer = Installer::new(install_path, "project".to_string());
installer.extract_binary(PathBuf::from("test-data/project.tar.gz"))?;

let mut extracted_path = td.path().to_path_buf();
extracted_path.push("project");
assert!(extracted_path.exists());
assert!(extracted_path.is_file());
let installer = Installer::new(install_path.clone(), exe.to_string());
installer.install(Download {
// It doesn't matter what we use here. We're not actually going to
// put anything in this temp dir.
_temp_dir: tempdir()?,
archive_path: PathBuf::from(archive_path),
})?;

assert!(install_path.exists());
assert!(install_path.is_file());
#[cfg(target_family = "unix")]
assert!(install_path.metadata()?.permissions().mode() & 0o111 != 0);

Ok(())
}
Expand Down
2 changes: 1 addition & 1 deletion src/picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ impl<'a> AssetPicker<'a> {
for asset in assets {
debug!("matching OS against asset name = {}", asset.name);

if asset.name.contains('.') && Extension::from_path(&asset.name).is_none() {
if asset.name.contains('.') && Extension::from_path(&asset.name).is_err() {
// If the name is something like "mkcert-v1.4.4-darwin-amd46"
// then the naive approach will think that this has an
// extension of ".4-darwin-amd46" and reject it as an invalid
Expand Down
Empty file added test-data/project
Empty file.
Binary file added test-data/project.bz
Binary file not shown.
Binary file added test-data/project.bz2
Binary file not shown.
Empty file added test-data/project.exe
Empty file.
Binary file added test-data/project.gz
Binary file not shown.
Binary file added test-data/project.tar
Binary file not shown.
Binary file added test-data/project.tar.bz
Binary file not shown.
Binary file added test-data/project.tar.bz2
Binary file not shown.
Binary file added test-data/project.tar.xz
Binary file not shown.
Binary file added test-data/project.xz
Binary file not shown.
Binary file added test-data/project.zip
Binary file not shown.

0 comments on commit 6973ba1

Please sign in to comment.