#![cfg(not(windows))]
use crate::common::wt_command;
use insta::Settings;
use insta_cmd::assert_cmd_snapshot;
use rstest::rstest;
fn snapshot_help(test_name: &str, args: &[&str]) {
let mut settings = Settings::clone_current();
settings.set_snapshot_path("../snapshots");
settings.bind(|| {
let mut cmd = wt_command();
cmd.args(args);
let output = cmd.output().expect("failed to run command");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
!stdout.contains("\n\n\n"),
"Double blank line in help output for `wt {}`",
args.join(" ")
);
let mut cmd = wt_command();
cmd.args(args);
assert_cmd_snapshot!(test_name, cmd);
});
}
#[rstest]
#[case("help_root_short", "-h")]
#[case("help_root_long", "--help")]
#[case("help_no_args", "")]
#[case("help_config_short", "config -h")]
#[case("help_config_long", "config --help")]
#[case("help_list_short", "list -h")]
#[case("help_list_long", "list --help")]
#[case("help_switch_short", "switch -h")]
#[case("help_switch_long", "switch --help")]
#[case("help_remove_short", "remove -h")]
#[case("help_remove_long", "remove --help")]
#[case("help_merge_short", "merge -h")]
#[case("help_merge_long", "merge --help")]
#[case("help_step_short", "step -h")]
#[case("help_step_long", "step --help")]
#[case("help_step_promote", "step promote --help")]
#[case("help_config_shell", "config shell --help")]
#[case("help_config_create", "config create --help")]
#[case("help_config_show", "config show --help")]
#[case("help_config_state", "config state --help")]
#[case(
"help_config_state_default_branch",
"config state default-branch --help"
)]
#[case(
"help_config_state_previous_branch",
"config state previous-branch --help"
)]
#[case("help_config_state_ci_status", "config state ci-status --help")]
#[case("help_config_state_marker", "config state marker --help")]
#[case("help_config_state_logs", "config state logs --help")]
#[case("help_config_state_get", "config state get --help")]
#[case("help_config_state_clear", "config state clear --help")]
#[case("help_config_approvals", "config approvals --help")]
#[case("help_config_approvals_add", "config approvals add --help")]
#[case("help_config_approvals_clear", "config approvals clear --help")]
fn test_help(#[case] test_name: &str, #[case] args_str: &str) {
let args: Vec<&str> = if args_str.is_empty() {
vec![]
} else {
args_str.split_whitespace().collect()
};
snapshot_help(test_name, &args);
}
#[test]
fn test_version() {
let mut settings = Settings::clone_current();
settings.set_snapshot_path("../snapshots");
settings.add_filter(
r"wt (v\d+\.\d+\.\d+(-[\w.-]+)?|[a-f0-9]{7,40}(?:-dirty)?)",
"wt [VERSION]",
);
settings.bind(|| {
let mut cmd = wt_command();
cmd.arg("--version");
assert_cmd_snapshot!("version", cmd);
});
}
#[test]
fn test_help_goes_to_stdout() {
for args in [&["--help"][..], &["-h"][..], &["merge", "--help"][..]] {
let output = wt_command()
.args(args)
.output()
.unwrap_or_else(|e| panic!("failed to run wt {args:?}: {e}"));
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stdout.contains("Usage:"),
"wt {args:?} should write help to stdout, but stdout was: {stdout:?} (stderr: {stderr:?})"
);
assert!(
stderr.trim().is_empty(),
"wt {args:?} should not write to stderr, but stderr was: {stderr:?}"
);
}
}
#[test]
fn test_help_strips_ansi_when_piped() {
let output = std::process::Command::new(env!("CARGO_BIN_EXE_wt"))
.arg("--help")
.env_remove("CLICOLOR_FORCE")
.env("NO_COLOR", "1")
.output()
.expect("failed to run wt --help");
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
!stdout.contains('\x1b'),
"wt --help piped to a file must not contain ANSI escapes; got: {stdout:?}"
);
}
#[test]
fn test_version_goes_to_stdout() {
let output = wt_command()
.arg("--version")
.output()
.expect("failed to run wt --version");
let stdout = String::from_utf8_lossy(&output.stdout);
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stdout.contains("wt "),
"wt --version should write to stdout, but stdout was: {stdout:?} (stderr: {stderr:?})"
);
assert!(
stderr.trim().is_empty(),
"wt --version should not write to stderr, but stderr was: {stderr:?}"
);
}
#[test]
fn test_help_md() {
let mut settings = Settings::clone_current();
settings.set_snapshot_path("../snapshots");
settings.bind(|| {
let mut cmd = wt_command();
cmd.args(["--help-md"]);
assert_cmd_snapshot!("help_md_root", cmd);
});
}
#[test]
fn test_help_md_subcommand() {
let mut settings = Settings::clone_current();
settings.set_snapshot_path("../snapshots");
settings.bind(|| {
let mut cmd = wt_command();
cmd.args(["merge", "--help-md"]);
assert_cmd_snapshot!("help_md_merge", cmd);
});
}
#[test]
fn test_help_list_narrow_terminal() {
let mut settings = Settings::clone_current();
settings.set_snapshot_path("../snapshots");
settings.bind(|| {
let mut cmd = wt_command();
cmd.env("COLUMNS", "80");
cmd.args(["list", "--help"]);
assert_cmd_snapshot!("help_list_narrow_80", cmd);
});
}
#[rstest]
#[case("switch", "Switch to a worktree; create if needed.")]
#[case(
"merge",
"Merge current branch into the target branch. Squash & rebase"
)]
#[case("hook", "Run configured hooks.")]
fn test_help_description(#[case] cmd: &str, #[case] expected_prefix: &str) {
let output = wt_command()
.args([cmd, "--help-description"])
.output()
.expect("failed to run wt --help-description");
assert!(output.status.success());
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.starts_with(expected_prefix),
"Expected description for '{cmd}' to start with '{expected_prefix}', got: {stdout}"
);
}
#[test]
fn test_help_description_no_subcommand() {
let output = wt_command()
.args(["--help-description"])
.output()
.expect("failed to run wt --help-description");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("Usage:"),
"Expected usage hint, got: {stderr}"
);
}
#[test]
fn test_help_description_unknown_command() {
let output = wt_command()
.args(["nonexistent", "--help-description"])
.output()
.expect("failed to run wt --help-description");
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains("Unknown command"),
"Expected unknown command error, got: {stderr}"
);
}
#[rstest]
#[case("nested_subcommand_step_squash", "squash", "wt step squash")]
#[case("nested_subcommand_step_commit", "commit", "wt step commit")]
#[case("nested_subcommand_hook_pre_merge", "pre-merge", "wt hook pre-merge")]
#[case("nested_subcommand_hook_pre_start", "pre-start", "wt hook pre-start")]
fn test_nested_subcommand_suggestion(
#[case] test_name: &str,
#[case] subcommand: &str,
#[case] expected_suggestion: &str,
) {
let mut settings = Settings::clone_current();
settings.set_snapshot_path("../snapshots");
settings.bind(|| {
let mut cmd = wt_command();
cmd.arg(subcommand);
let output = cmd.output().expect("failed to run wt");
assert_eq!(output.status.code(), Some(2));
let stderr = String::from_utf8_lossy(&output.stderr);
assert!(
stderr.contains(expected_suggestion),
"Expected stderr to contain '{expected_suggestion}', got:\n{stderr}"
);
assert_cmd_snapshot!(test_name, cmd);
});
}