Files
MercuryToolbox/crates/pathshadow/tests/pathshadow_cli.rs
T

158 lines
4.6 KiB
Rust

//! Integration tests for the `pathshadow` command.
use std::fs;
use assert_cmd::Command;
use pathshadow::{SourceKind, classify_source, find_command_matches};
use predicates::prelude::*;
use tempfile::tempdir;
fn cargo_command() -> Command {
Command::cargo_bin("pathshadow").expect("binary")
}
fn classify_path(path: &str) -> SourceKind {
classify_source(std::path::Path::new(path))
}
fn demo_path_fixture() -> (tempfile::TempDir, tempfile::TempDir, String) {
let first = tempdir().expect("first path");
let second = tempdir().expect("second path");
fs::write(first.path().join("demo.cmd"), "@echo first").expect("first command");
fs::write(second.path().join("demo.exe"), "binary").expect("second command");
let path_value = format!("{};{}", first.path().display(), second.path().display());
(first, second, path_value)
}
#[test]
fn classifies_common_install_roots() {
assert_eq!(
classify_path(r"C:\Users\example\scoop\shims\rg.exe"),
SourceKind::ScoopShim
);
assert_eq!(
classify_path(r"C:\Users\example\scoop\shims"),
SourceKind::ScoopShim
);
assert_eq!(
classify_path(r"C:\Users\example\.cargo\bin\cargo.exe"),
SourceKind::CargoBin
);
assert_eq!(
classify_path(r"C:\Users\example\.cargo\bin"),
SourceKind::CargoBin
);
}
#[test]
fn finds_shadowed_matches_in_path_order() {
let (first, second, _) = demo_path_fixture();
let matches = find_command_matches(
"demo",
&[first.path().to_path_buf(), second.path().to_path_buf()],
&[".CMD".into(), ".EXE".into()],
);
assert_eq!(matches.len(), 2);
assert_eq!(matches[0].path, first.path().join("demo.cmd"));
assert!(matches[0].is_primary);
assert!(!matches[1].is_primary);
}
#[test]
fn reports_duplicates_from_cli() {
let (_first, _second, path_value) = demo_path_fixture();
let mut command = cargo_command();
command
.arg("demo")
.env("PATH", path_value)
.env("PATHEXT", ".CMD;.EXE")
.assert()
.success()
.stdout(predicate::str::contains("demo"))
.stdout(predicate::str::contains("primary"))
.stdout(predicate::str::contains("shadowed"));
}
#[test]
fn supports_powershell_pipeline() {
let (_first, _second, path_value) = demo_path_fixture();
let binary = assert_cmd::cargo::cargo_bin("pathshadow");
let script = format!("'demo' | & '{}'", binary.display());
let mut command = Command::new("pwsh");
command
.arg("-NoProfile")
.arg("-Command")
.arg(script)
.env("PATH", path_value)
.env("PATHEXT", ".CMD;.EXE")
.assert()
.success()
.stdout(predicate::str::contains("demo"));
}
#[test]
fn emits_rank_reason_and_winner_in_json_output() {
let (first, _second, path_value) = demo_path_fixture();
let winner = first.path().join("demo.cmd");
let winner_json = winner.display().to_string().replace('\\', "\\\\");
let mut command = cargo_command();
command
.arg("demo")
.arg("--json")
.env("PATH", path_value)
.env("PATHEXT", ".CMD;.EXE")
.assert()
.success()
.stdout(predicate::str::contains("\"path_rank\":0"))
.stdout(predicate::str::contains("\"path_rank\":1"))
.stdout(predicate::str::contains(
"\"shadow_reason\":\"path_winner\"",
))
.stdout(predicate::str::contains(
"\"shadow_reason\":\"shadowed_by_earlier_path\"",
))
.stdout(predicate::str::contains(format!(
"\"winner_path\":\"{winner_json}\""
)));
}
#[test]
fn help_includes_path_diagnosis_examples() {
let mut command = cargo_command();
command
.arg("--help")
.assert()
.success()
.stdout(predicate::str::contains("pathshadow rg"))
.stdout(predicate::str::contains(
"pathshadow python npm --shell powershell",
))
.stdout(predicate::str::contains(
"pathshadow --all-duplicates --high-signal --summary --json",
))
.stdout(predicate::str::contains("ConvertFrom-Json"));
}
#[test]
fn reports_alias_targets_for_powershell_resolution() {
let mut command = cargo_command();
command
.arg("where")
.arg("--shell")
.arg("powershell")
.arg("--summary")
.arg("--json")
.assert()
.success()
.stdout(predicate::str::contains("\"shell_winner_type\":\"alias\""))
.stdout(predicate::str::contains(
"\"shell_winner_target\":\"Where-Object\"",
))
.stdout(predicate::str::contains("\"shell_disagrees\":true"));
}