use clap::Parser;
use midenup::commands::Midenup;
mod common;
use common::*;
#[test]
fn integration_miden_test() {
let _guard = common::harness::mutating_test_guard();
let test_name = "integration_miden_test";
let test_env = environment_setup(test_name);
const FILE: &str =
full_path_manifest!("tests/data/integration_miden_test/channel-manifest.json");
let (mut local_manifest, config) = test_setup(&test_env, FILE);
let toolchain_dir = test_env.midenup_home.join("toolchains");
let command = Midenup::try_parse_from(["miden", "help", "client"]).unwrap();
command
.execute_with_state(&config, &mut local_manifest)
.expect("failed to get client version");
assert!(test_env.midenup_home.exists());
assert!(toolchain_dir.exists());
assert!(test_env.cargo_home.join("bin").join("miden").exists());
let latest_toolchain = toolchain_dir.join("0.16.0");
assert!(latest_toolchain.exists());
let mainnet_dir = toolchain_dir.join("mainnet");
assert!(mainnet_dir.exists());
assert!(mainnet_dir.is_symlink());
let command = Midenup::try_parse_from(["midenup", "override", "0.15.0"]).unwrap();
command
.execute_with_state(&config, &mut local_manifest)
.expect("failed to override toolchain");
let command = Midenup::try_parse_from(["miden", "help", "client"]).unwrap();
command
.execute_with_state(&config, &mut local_manifest)
.expect("failed to get client version");
let older_toolchain = toolchain_dir.join("0.15.0");
assert!(older_toolchain.exists());
let command = Midenup::try_parse_from(["midenup", "set", "0.14.0"]).unwrap();
command
.execute_with_state(&config, &mut local_manifest)
.expect("failed to set local toolchain");
let command = Midenup::try_parse_from(["miden", "help", "client"]).unwrap();
command
.execute_with_state(&config, &mut local_manifest)
.expect("failed to get client version");
let oldest_toolchain = toolchain_dir.join("0.14.0");
assert!(oldest_toolchain.exists());
let installed_toolchains = ["0.14.0", "0.15.0", "0.16.0"].iter().map(|version| {
semver::Version::parse(version)
.unwrap_or_else(|_| panic!("Failed to turn {version} into semver::Version"))
});
local_manifest
.installations
.iter()
.map(|i| i.as_channel())
.map(|channel| channel.name.clone())
.eq(installed_toolchains);
}
#[test]
#[cfg(unix)]
fn integration_miden_preserves_component_exit_code() {
let _guard = common::harness::mutating_test_guard();
let test_env = environment_setup("integration_miden_preserves_component_exit_code");
let fixture = common::harness::OfflineFixture::create(test_env.tmp_dir.path(), "0.15.0");
let vm_binary = fixture.dir.join("0.15.0").join("miden-vm");
std::fs::write(&vm_binary, b"#!/bin/sh\nexit 42\n").expect("failed to write fixture binary");
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
std::fs::set_permissions(&vm_binary, std::fs::Permissions::from_mode(0o755))
.expect("failed to chmod fixture binary");
}
let installed = run_midenup(&test_env, &fixture.manifest_uri, &["install", "0.15.0"]);
assert!(installed.status.success(), "{}", String::from_utf8_lossy(&installed.stderr));
let output = midenup_command(
test_env.cargo_home.join("bin").join("miden"),
&test_env,
&fixture.manifest_uri,
)
.arg("vm")
.output()
.expect("failed to run miden");
assert_eq!(output.status.code(), Some(42));
}
#[test]
fn integration_miden_toolchain_toml() {
let _guard = common::harness::mutating_test_guard();
let test_name = "integration_miden_toolchain_toml";
let test_env = environment_setup(test_name);
let pwd = &test_env.present_working_dir;
const FILE: &str =
full_path_manifest!("tests/data/integration_miden_toolchain_toml/channel-manifest.json");
let (mut local_manifest, config) = test_setup(&test_env, FILE);
let command = Midenup::try_parse_from(["midenup", "set", "0.16.0"]).unwrap();
command
.execute_with_state(&config, &mut local_manifest)
.expect("failed to set local toolchain");
let miden_toolchain_file = pwd.join("miden-toolchain.toml");
assert!(miden_toolchain_file.exists());
let command = Midenup::try_parse_from(["miden", "help", "toolchain"]).unwrap();
command
.execute_with_state(&config, &mut local_manifest)
.expect("failed to get subcommand help");
let toolchain_dir = test_env.midenup_home.join("toolchains");
assert!(toolchain_dir.exists());
let installed_channel = local_manifest.get(&semver::Version::new(0, 16, 0)).unwrap();
assert_eq!(installed_channel.components.len(), 1);
let toolchain_with_components =
full_path!("tests/data/integration_miden_toolchain_toml/miden-toolchain-2.toml");
std::fs::copy(toolchain_with_components, miden_toolchain_file).unwrap();
let command = Midenup::try_parse_from(["miden", "help", "toolchain"]).unwrap();
command
.execute_with_state(&config, &mut local_manifest)
.expect("failed to get subcommand help");
let installed_channel =
local_manifest.get(&semver::Version::new(0, 16, 0)).unwrap().as_channel();
assert_eq!(installed_channel.components.len(), 3);
let command = Midenup::try_parse_from(["midenup", "update", "0.16.0"]).unwrap();
command
.execute_with_state(&config, &mut local_manifest)
.expect("failed to update 0.16.0 toolchain");
let installed_channel = local_manifest.get(&semver::Version::new(0, 16, 0)).unwrap();
assert_eq!(installed_channel.components.len(), 3);
let command =
Midenup::try_parse_from(["midenup", "install", "stable", "--profile", "complete"]).unwrap();
command
.execute_with_state(&config, &mut local_manifest)
.expect("failed to install stable toolchain");
let installed_channel = local_manifest.get(&semver::Version::new(0, 16, 0)).unwrap();
assert_eq!(installed_channel.components.len(), 4);
}
#[test]
#[should_panic]
fn integration_midenup_catches_installation_failure() {
let _guard = common::harness::mutating_test_guard();
let test_name = "midenup_catches_installation_failure";
let test_env = environment_setup(test_name);
const FILE_PRE_UPDATE: &str = full_path_manifest!(
"tests/data/unit_test_manifest_additional/manifest-uncompilable-midenc.json"
);
let (mut local_manifest, config) = test_setup(&test_env, FILE_PRE_UPDATE);
let command = Midenup::try_parse_from(["midenup", "install", "stable"]).unwrap();
command
.execute_with_state(&config, &mut local_manifest)
.expect("failed to install stable");
let manifest = test_env.midenup_home.join("manifest").with_extension("json");
assert!(manifest.exists());
}
#[test]
fn integration_activation_unions_intent_across_projects() {
let _guard = common::harness::mutating_test_guard();
let test_env = environment_setup("integration_activation_unions_intent");
let fixture = common::harness::OfflineFixture::create(test_env.tmp_dir.path(), "0.15.0");
let (mut state, config) = test_setup(&test_env, &fixture.manifest_uri);
let channel = semver::Version::new(0, 15, 0);
let mut options = midenup::options::InstallationOptions {
profile: midenup::profile::Profile::Minimal,
components: vec!["assets".to_string()],
..Default::default()
};
let upstream = config
.upstream_manifest()
.unwrap()
.get_channel_by_name(&channel)
.unwrap()
.clone();
midenup::commands::install(&config, &upstream, &mut state, &options)
.expect("failed to install for project A");
assert!(state.get(&channel).unwrap().intent.roots.contains("assets"));
options.intent_update = Some(midenup::options::IntentUpdate::Union(
midenup::resolve::Intent::new(&[midenup::profile::Profile::Minimal], &[]),
));
options.components = Vec::new();
midenup::commands::install(&config, &upstream, &mut state, &options)
.expect("failed to activate for project B");
assert!(
state.get(&channel).unwrap().intent.roots.contains("assets"),
"activating a project that wants less must not drop another project's component"
);
options.intent_update = None;
midenup::commands::install(&config, &upstream, &mut state, &options)
.expect("failed to install directly");
assert!(
!state.get(&channel).unwrap().intent.roots.contains("assets"),
"a direct install replaces intent, so it is allowed to shrink"
);
}
#[test]
fn integration_miden_explicit_toolchain_override() {
let _guard = common::harness::mutating_test_guard();
let test_env = environment_setup("integration_miden_explicit_toolchain_override");
let fixture = common::harness::OfflineFixture::new(test_env.tmp_dir.path())
.with_channel("0.15.0")
.with_channel("0.16.0")
.build();
let (mut state, mut config) = test_setup(&test_env, &fixture.manifest_uri);
let output_handle = config.capture_output();
{
let command = Midenup::try_parse_from(["miden", "help", "vm"]).unwrap();
command
.execute_with_state(&config, &mut state)
.expect("failed to execute command with toolchain override");
let mut output = output_handle.borrow_mut();
assert!(output.status.success());
let stdout = core::mem::take(&mut output.stdout);
output.stderr.clear();
assert_eq!(core::str::from_utf8(&stdout).unwrap(), "miden-vm 0.15.0\n");
}
let command = Midenup::try_parse_from(["miden", "+0.16.0", "help", "vm"]).unwrap();
command
.execute_with_state(&config, &mut state)
.expect("failed to execute command with toolchain override");
let output = output_handle.borrow();
assert!(output.status.success());
assert_eq!(core::str::from_utf8(&output.stdout).unwrap(), "miden-vm 0.16.0\n");
}
#[test]
fn integration_miden_explicit_override_survives_environment() {
let test_env = environment_setup("explicit_override_survives_environment");
let fixture = common::harness::OfflineFixture::new(test_env.tmp_dir.path())
.with_channel("0.15.0")
.with_channel("0.16.0")
.build();
let binary = env!("CARGO_BIN_EXE_midenup");
for channel in ["0.15.0", "0.16.0"] {
let output = midenup_command(binary, &test_env, &fixture.manifest_uri)
.env_remove("MIDENUP_TOOLCHAIN")
.args(["install", channel])
.output()
.unwrap();
assert!(output.status.success(), "{}", String::from_utf8_lossy(&output.stderr));
}
for environment in ["", "../invalid", "0.16.0"] {
let output = midenup_command(binary, &test_env, &fixture.manifest_uri)
.env_remove("MIDENUP_TOOLCHAIN")
.args(["override", "0.16.0"])
.output()
.unwrap();
assert!(output.status.success(), "{}", String::from_utf8_lossy(&output.stderr));
let output = midenup_command(
test_env.cargo_home.join("bin/miden"),
&test_env,
&fixture.manifest_uri,
)
.env("MIDENUP_TOOLCHAIN", environment)
.args(["+0.15.0", "help", "vm"])
.output()
.unwrap();
assert_eq!(String::from_utf8_lossy(&output.stdout), "miden-vm 0.15.0\n");
assert!(
output.status.success(),
"command failed with MIDENUP_TOOLCHAIN={environment:?}: {}",
String::from_utf8_lossy(&output.stderr)
);
assert_eq!(
std::fs::canonicalize(test_env.midenup_home.join("opt")).unwrap(),
std::fs::canonicalize(test_env.midenup_home.join("toolchains/0.15.0/opt")).unwrap(),
"the opt link must follow the explicitly selected toolchain"
);
}
}