use proto_core::{
Detector, Downloadable, Executable, Installable, Proto, Resolvable, Tool, Verifiable,
};
use proto_node::NodeLanguage;
use starbase_sandbox::create_empty_sandbox;
use std::env;
use std::{fs, path::Path};
mod node {
use super::*;
#[tokio::test]
async fn downloads_verifies_installs_tool() {
let fixture = create_empty_sandbox();
let proto = Proto::from(fixture.path());
let mut tool = NodeLanguage::new(&proto);
env::set_var("PROTO_ROOT", fixture.path().to_string_lossy().to_string());
tool.setup("18.0.0").await.unwrap();
env::remove_var("PROTO_ROOT");
assert!(tool.get_install_dir().unwrap().exists());
let base_dir = proto.tools_dir.join("node/18.0.0");
if cfg!(windows) {
assert_eq!(tool.get_bin_path().unwrap(), &base_dir.join("node.exe"));
assert!(proto.bin_dir.join("node.cmd").exists());
} else {
assert_eq!(tool.get_bin_path().unwrap(), &base_dir.join("bin/node"));
assert!(proto.bin_dir.join("node").exists());
}
}
fn create_node(dir: &Path) -> NodeLanguage {
let mut tool = NodeLanguage::new(Proto::from(dir));
tool.version = Some("18.0.0".into());
tool
}
mod detector {
use super::*;
#[tokio::test]
async fn doesnt_match_if_no_files() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
assert_eq!(
tool.detect_version_from(fixture.path()).await.unwrap(),
None
);
}
#[tokio::test]
async fn detects_nvm() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
fixture.create_file(".nvmrc", "1.2.3");
assert_eq!(
tool.detect_version_from(fixture.path()).await.unwrap(),
Some("1.2.3".into())
);
}
#[tokio::test]
async fn detects_nodenv() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
fixture.create_file(".node-version", "4.5.6\n");
assert_eq!(
tool.detect_version_from(fixture.path()).await.unwrap(),
Some("4.5.6".into())
);
}
#[tokio::test]
async fn detects_engines() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
fixture.create_file("package.json", r#"{"engines":{"node":"16.2.*"}}"#);
assert_eq!(
tool.detect_version_from(fixture.path()).await.unwrap(),
Some("16.2.*".into())
);
}
#[tokio::test]
async fn matches_engines_star() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
fixture.create_file("package.json", r#"{"engines":{"node":"16.*"}}"#);
assert_eq!(
tool.detect_version_from(fixture.path()).await.unwrap(),
Some("16.*".into())
);
}
}
mod downloader {
use super::*;
use proto_node::download::get_archive_file;
#[tokio::test]
async fn sets_path_to_temp() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
assert_eq!(
tool.get_download_path().unwrap(),
Proto::from(fixture.path())
.temp_dir
.join("node")
.join(get_archive_file("18.0.0").unwrap())
);
}
#[tokio::test]
async fn downloads_to_temp() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
let to_file = tool.get_download_path().unwrap();
assert!(!to_file.exists());
tool.download(&to_file, None).await.unwrap();
assert!(to_file.exists());
}
#[tokio::test]
async fn doesnt_download_if_file_exists() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
let to_file = tool.get_download_path().unwrap();
assert!(tool.download(&to_file, None).await.unwrap());
assert!(!tool.download(&to_file, None).await.unwrap());
}
}
mod installer {
use super::*;
#[tokio::test]
async fn sets_dir_to_tools() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
assert_eq!(
tool.get_install_dir().unwrap(),
Proto::from(fixture.path())
.tools_dir
.join("node")
.join("18.0.0")
);
}
#[tokio::test]
#[should_panic(expected = "InstallMissingDownload(\"Node.js\")")]
async fn errors_for_missing_download() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
let dir = tool.get_install_dir().unwrap();
tool.install(&dir, &tool.get_download_path().unwrap())
.await
.unwrap();
}
#[tokio::test]
async fn doesnt_install_if_dir_exists() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
let dir = tool.get_install_dir().unwrap();
fs::create_dir_all(&dir).unwrap();
assert!(!tool
.install(&dir, &tool.get_download_path().unwrap())
.await
.unwrap());
}
}
mod resolver {
use super::*;
#[tokio::test]
async fn updates_struct_version() {
let fixture = create_empty_sandbox();
let mut tool = NodeLanguage::new(Proto::from(fixture.path()));
assert_ne!(tool.resolve_version("node").await.unwrap(), "node");
assert_ne!(tool.get_resolved_version(), "node");
}
#[tokio::test]
async fn resolve_latest() {
let fixture = create_empty_sandbox();
let mut tool = NodeLanguage::new(Proto::from(fixture.path()));
assert_ne!(tool.resolve_version("latest").await.unwrap(), "latest");
}
#[tokio::test]
async fn resolve_stable() {
let fixture = create_empty_sandbox();
let mut tool = NodeLanguage::new(Proto::from(fixture.path()));
assert_ne!(tool.resolve_version("stable").await.unwrap(), "stable");
}
#[tokio::test]
async fn resolve_lts_wild() {
let fixture = create_empty_sandbox();
let mut tool = NodeLanguage::new(Proto::from(fixture.path()));
assert_ne!(tool.resolve_version("lts-*").await.unwrap(), "lts-*");
}
#[tokio::test]
async fn resolve_lts_dash() {
let fixture = create_empty_sandbox();
let mut tool = NodeLanguage::new(Proto::from(fixture.path()));
assert_ne!(
tool.resolve_version("lts-gallium").await.unwrap(),
"lts-gallium"
);
}
#[tokio::test]
async fn resolve_lts_slash() {
let fixture = create_empty_sandbox();
let mut tool = NodeLanguage::new(Proto::from(fixture.path()));
assert_ne!(
tool.resolve_version("lts/gallium").await.unwrap(),
"lts/gallium"
);
}
#[tokio::test]
async fn resolve_alias() {
let fixture = create_empty_sandbox();
let mut tool = NodeLanguage::new(Proto::from(fixture.path()));
assert_ne!(tool.resolve_version("Gallium").await.unwrap(), "Gallium");
}
#[tokio::test]
async fn resolve_version() {
let fixture = create_empty_sandbox();
let mut tool = NodeLanguage::new(Proto::from(fixture.path()));
assert_eq!(tool.resolve_version("18.0.0").await.unwrap(), "18.0.0");
}
#[tokio::test]
async fn resolve_partial_version() {
let fixture = create_empty_sandbox();
let mut tool = NodeLanguage::new(Proto::from(fixture.path()));
assert_eq!(tool.resolve_version("10.1").await.unwrap(), "10.1.0");
}
#[tokio::test]
async fn resolve_custom_alias() {
let fixture = create_empty_sandbox();
let mut tool = NodeLanguage::new(Proto::from(fixture.path()));
fixture.create_file(
"tools/node/manifest.json",
r#"{"aliases":{"example":"10.0.0"}}"#,
);
assert_eq!(tool.resolve_version("example").await.unwrap(), "10.0.0");
}
#[tokio::test]
async fn resolve_version_with_prefix() {
let fixture = create_empty_sandbox();
let mut tool = NodeLanguage::new(Proto::from(fixture.path()));
assert_eq!(tool.resolve_version("v18.0.0").await.unwrap(), "18.0.0");
}
#[tokio::test]
#[should_panic(expected = "VersionUnknownAlias(\"unknown\")")]
async fn errors_invalid_lts() {
let fixture = create_empty_sandbox();
let mut tool = NodeLanguage::new(Proto::from(fixture.path()));
tool.resolve_version("lts-unknown").await.unwrap();
}
#[tokio::test]
#[should_panic(expected = "VersionUnknownAlias(\"unknown\")")]
async fn errors_invalid_alias() {
let fixture = create_empty_sandbox();
let mut tool = NodeLanguage::new(Proto::from(fixture.path()));
tool.resolve_version("unknown").await.unwrap();
}
#[tokio::test]
#[should_panic(expected = "VersionResolveFailed(\"99.99.99\")")]
async fn errors_invalid_version() {
let fixture = create_empty_sandbox();
let mut tool = NodeLanguage::new(Proto::from(fixture.path()));
tool.resolve_version("99.99.99").await.unwrap();
}
}
mod verifier {
use super::*;
#[tokio::test]
async fn sets_path_to_temp() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
assert_eq!(
tool.get_checksum_path().unwrap(),
Proto::from(fixture.path())
.temp_dir
.join("node")
.join("v18.0.0-SHASUMS256.txt")
);
}
#[tokio::test]
async fn downloads_to_temp() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
let to_file = tool.get_checksum_path().unwrap();
assert!(!to_file.exists());
tool.download_checksum(&to_file, None).await.unwrap();
assert!(to_file.exists());
}
#[tokio::test]
async fn doesnt_download_if_file_exists() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
let to_file = tool.get_checksum_path().unwrap();
assert!(tool.download_checksum(&to_file, None).await.unwrap());
assert!(!tool.download_checksum(&to_file, None).await.unwrap());
}
#[tokio::test]
#[should_panic(expected = "VerifyInvalidChecksum")]
async fn errors_for_checksum_mismatch() {
let fixture = create_empty_sandbox();
let tool = create_node(fixture.path());
let dl_path = tool.get_download_path().unwrap();
let cs_path = tool.get_checksum_path().unwrap();
tool.download(&dl_path, None).await.unwrap();
tool.download_checksum(&cs_path, None).await.unwrap();
fs::write(&cs_path, "").unwrap();
tool.verify_checksum(&cs_path, &dl_path).await.unwrap();
}
}
}