use super::*;
use crate::cli::{
globals::{INTERNAL_ENVIRONMENT_OPTION, INTERNAL_ICP_OPTION},
help::{top_level_command, usage},
};
#[cfg(unix)]
use crate::test_support::TempDir;
fn strip_ansi(text: &str) -> String {
let mut plain = String::new();
let mut chars = text.chars().peekable();
while let Some(ch) = chars.next() {
if ch == '\x1b' && chars.peek() == Some(&'[') {
chars.next();
for ch in chars.by_ref() {
if ch == 'm' {
break;
}
}
continue;
}
plain.push(ch);
}
plain
}
#[test]
fn usage_lists_current_commands_alphabetically() {
let plain = strip_ansi(&usage());
let names = plain
.split_once("\nCommands:\n")
.expect("top-level commands section")
.1
.split_once("\nOptions:\n")
.expect("top-level options section")
.0
.lines()
.filter_map(|line| line.split_whitespace().next())
.collect::<Vec<_>>();
let command = top_level_command();
let registered = command
.get_subcommands()
.filter(|child| !child.is_hide_set())
.map(clap::Command::get_name)
.collect::<Vec<_>>();
assert!(!names.is_empty());
assert!(names.windows(2).all(|pair| pair[0] < pair[1]));
assert_eq!(names, registered);
assert!(plain.contains("Usage: canic [OPTIONS] <COMMAND>"));
}
#[test]
fn current_command_help_and_versions_return_ok() {
for command in top_level_command().get_subcommands() {
let args = [command.get_name(), "--help"];
assert!(run(args.iter().map(OsString::from)).is_ok(), "{args:?}");
}
for args in [
&["component", "apply", "--help"][..],
&["component", "plan", "--help"],
&["component", "status", "--help"],
&["fleet", "ensure", "--help"],
&["fleet", "generate", "--help"],
&["frontend", "capacity", "--help"],
&["frontend", "export", "--help"],
&["frontend", "verify", "--help"],
&["inspect", "canister", "--help"],
&["inspect", "fleet", "--help"],
&["medic", "fleet", "--help"],
&["toolchain", "install", "--help"],
] {
assert!(run(args.iter().map(OsString::from)).is_ok(), "{args:?}");
}
assert!(run([OsString::from("--version")]).is_ok());
assert!(run([OsString::from("fleet"), OsString::from("--version")]).is_ok());
}
#[test]
fn global_options_are_forwarded_only_once() {
let mut tail = vec![OsString::from("ensure"), OsString::from("staging")];
apply_global_icp("fleet", &mut tail, Some("/tmp/icp".to_string()));
apply_global_environment("fleet", &mut tail, Some("local".to_string()));
assert_eq!(
tail,
vec![
OsString::from("ensure"),
OsString::from("staging"),
OsString::from(INTERNAL_ICP_OPTION),
OsString::from("/tmp/icp"),
OsString::from(INTERNAL_ENVIRONMENT_OPTION),
OsString::from("local"),
]
);
apply_global_icp("fleet", &mut tail, Some("/other/icp".to_string()));
apply_global_environment("fleet", &mut tail, Some("other".to_string()));
assert_eq!(
tail.iter()
.filter(|value| value.as_os_str() == INTERNAL_ICP_OPTION)
.count(),
1
);
assert_eq!(
tail.iter()
.filter(|value| value.as_os_str() == INTERNAL_ENVIRONMENT_OPTION)
.count(),
1
);
}
#[test]
fn current_read_only_commands_receive_global_target_options() {
for (command, raw_tail) in [
("admission", &["status", "staging"][..]),
("auth", &["renewal", "status", "staging"][..]),
("blob-storage", &["status", "staging", "root"]),
("cycles", &["balance"]),
("info", &["list", "staging"][..]),
("inspect", &["fleet", "staging", "--role", "root"]),
("medic", &["fleet", "staging"]),
("status", &[][..]),
("token", &["balance"]),
] {
let mut tail = raw_tail.iter().map(OsString::from).collect::<Vec<_>>();
apply_global_icp(command, &mut tail, Some("/tmp/icp".to_string()));
apply_global_environment(command, &mut tail, Some("local".to_string()));
assert!(tail.iter().any(|value| value == INTERNAL_ICP_OPTION));
assert!(
tail.iter()
.any(|value| value == INTERNAL_ENVIRONMENT_OPTION)
);
}
}
#[cfg(unix)]
#[test]
fn icp_backed_command_rejects_unparseable_icp_before_effects() {
use std::{fs, os::unix::fs::PermissionsExt};
let root = TempDir::new("canic-cli-unsupported-icp");
fs::create_dir_all(&root).expect("create temp dir");
let icp = root.join("icp");
fs::write(
&icp,
"#!/bin/sh\nif [ \"$1\" = \"--version\" ]; then echo 'icp development build'; exit 0; fi\necho 'unexpected effect' >&2\nexit 42\n",
)
.expect("write fake icp");
fs::set_permissions(&icp, fs::Permissions::from_mode(0o755)).expect("chmod fake icp");
let error = run([
OsString::from("--icp"),
icp.into_os_string(),
OsString::from("replica"),
OsString::from("status"),
])
.expect_err("unsupported icp rejected");
assert!(error.to_string().contains("unsupported icp-cli version"));
assert!(!error.to_string().contains("unexpected effect"));
}
#[test]
fn state_report_failure_remains_silent_and_nonzero() {
let error = CliError::State(state::StateCommandError::AuditFailed);
assert_eq!(render_cli_error(&error), "");
assert_eq!(cli_error_exit_code(&error), 1);
}