Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions cli/tests/complete_word.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use assert_cmd::assert::Assert;
use assert_cmd::cargo;
use std::env;
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use assert_cmd::prelude::*;
Expand All @@ -20,22 +21,48 @@ use predicates::str::contains;
/// The probe runs a script and checks that it exited cleanly, rather than only that something
/// spawned. On Windows `sh` can resolve to a program that starts and then fails, which would
/// otherwise read as a working shell and put the tests back in the confusing state above.
///
/// `sh` starting is necessary but not sufficient, so a fixture is run as well. Its shebang is
/// `usage bash`, and on Windows the two need not be the same family: `sh` can be Git Bash while
/// a bare `bash` is the WSL launcher that System32 puts ahead of `PATH`, which cannot open the
/// absolute path `sh` hands its shebang. Probing only `sh` reported such a machine as usable
/// and left these tests failing rather than skipping. `USAGE_SHELL_BASH` is the way out, and
/// the probe sees it because the fixture runs through `usage bash` too.
fn skip_if_posix_shell_missing() -> bool {
let usable = Command::new("sh")
let sh_runs = Command::new("sh")
.arg("-c")
.arg("exit 0")
.output()
.is_ok_and(|out| out.status.success());
if usable {
if sh_runs && mount_fixture_runs() {
return false;
}
if env::var("CI").is_ok_and(|v| !v.is_empty()) {
panic!("no usable POSIX shell (`sh`) but CI is set — refusing to skip");
panic!("no shell that can run the mount fixtures but CI is set — refusing to skip");
}
eprintln!("Skipping test - no usable POSIX shell (`sh`)");
eprintln!("Skipping test - no shell that can run the mount fixtures");
true
}

/// Whether a mount fixture actually runs, given as the absolute path `sh` would hand it.
fn mount_fixture_runs() -> bool {
// Built from `CARGO_MANIFEST_DIR`, not `fs::canonicalize`. On Windows canonicalize returns
// a `\\?\`-prefixed path, which usage cannot open — the probe would then fail on the shape
// of the path rather than on the shell, and every mount test would skip on a machine where
// they work perfectly well.
let fixture = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.unwrap()
.join("examples")
.join("mounted.sh");
Command::new(cargo::cargo_bin!("usage"))
.arg("bash")
.arg(fixture)
.arg("--mount")
.output()
.is_ok_and(|out| out.status.success())
}

#[test]
fn complete_word_completer() {
assert_cmd("basic.usage.kdl", &["plugins", "install", "pl"])
Expand Down
22 changes: 7 additions & 15 deletions cli/tests/examples.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,18 @@
use assert_cmd::cargo;
use assert_cmd::prelude::*;
use predicates::str::contains;
use std::{env, process::Command};
use std::process::Command;

/// Test that examples/test-empty-defaults.sh runs successfully and demonstrates
/// the correct behavior of default="" vs no default
#[test]
fn test_empty_defaults_example() {
// Set up PATH to include the usage binary
let mut path = env::split_paths(&env::var("PATH").unwrap()).collect::<Vec<_>>();
path.insert(
0,
env::current_dir()
.unwrap()
.join("..")
.join("target")
.join("debug"),
);
path.insert(0, env::current_dir().unwrap().join("..").join("examples"));

let mut cmd = Command::new("../examples/test-empty-defaults.sh");
cmd.env("PATH", env::join_paths(path).unwrap());
// Through `usage bash`, like every other test here, rather than spawning the script and
// letting its `#!/usr/bin/env -S usage bash` shebang do the work. Windows cannot execute a
// `.sh` at all — the spawn fails with os error 193 before the shebang is ever read — and
// going through the binary also drops the PATH juggling that let the shebang find `usage`.
let mut cmd = Command::new(cargo::cargo_bin!("usage"));
cmd.args(["bash", "../examples/test-empty-defaults.sh"]);

let assert = cmd.assert().success();

Expand Down
Loading
Loading