blob: af1d5f64556b0b554293a83aa4eb4c02879800e6 [file] [log] [blame]
// These tests largely just check that basic CLI configs still work,
// and show you how you've changed the output. Yes, a lot of these
// will randomly churn (especially the help message ones, which
// contain the latest version), but this is good for two reasons:
//
// * You can easily see exactly what you changed
// * It can prompt you to update any other docs
//
// `cargo insta` automates reviewing and updating these snapshots.
// You can install `cargo insta` with:
//
// > cargo install cargo-insta
//
// Also note that `cargo test` for an application adds our binary to
// the env as `CARGO_BIN_EXE_<name>`.
use std::{
path::{Path, PathBuf},
process::{Command, Output, Stdio},
};
// NOTE: We filter out the "Blocking: waiting for file lock" lines, as they are
// printed out non-deterministically when there is file contention.
fn filter_blocking_lines(stderr: &[u8]) -> String {
std::str::from_utf8(stderr)
.unwrap()
.lines()
.filter(|line| !line.starts_with("Blocking: waiting for file lock"))
.collect::<Vec<_>>()
.join("\n")
}
fn format_outputs(output: &Output) -> String {
let stdout = std::str::from_utf8(&output.stdout).unwrap();
let stderr = filter_blocking_lines(&output.stderr);
format!("stdout:\n{stdout}\nstderr:\n{stderr}")
}
fn format_diff_outputs(output: &Output) -> String {
// Filter out lines which may contain paths so that the output is portable,
// while preserving some of the general format.
let stdout = std::str::from_utf8(&output.stdout)
.unwrap()
.lines()
.filter(|line| !line.starts_with("diff --git"))
.map(|line| {
if let Some(path) = line.strip_prefix("--- ") {
return format!(
"--- a/{}",
Path::new(path).file_name().unwrap().to_str().unwrap()
);
}
if let Some(path) = line.strip_prefix("+++ ") {
return format!(
"+++ b/{}",
Path::new(path).file_name().unwrap().to_str().unwrap()
);
}
line.to_owned()
})
.collect::<Vec<_>>()
.join("\n");
let stderr = filter_blocking_lines(&output.stderr);
format!("stdout:\n{stdout}\nstderr:\n{stderr}")
}
#[test]
fn test_version() {
let bin = env!("CARGO_BIN_EXE_cargo-vet");
let output = Command::new(bin)
.arg("vet")
.arg("-V")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.unwrap();
let stdout = String::from_utf8(output.stdout).unwrap();
let stderr = String::from_utf8(output.stderr).unwrap();
assert!(output.status.success(), "{}", stderr);
assert_eq!(stderr, "");
let (name, ver) = stdout.split_once(' ').unwrap();
assert_eq!(name, "cargo-vet");
let mut ver_parts = ver.trim().split('.');
ver_parts.next().unwrap().parse::<u8>().unwrap();
ver_parts.next().unwrap().parse::<u8>().unwrap();
ver_parts.next().unwrap().parse::<u8>().unwrap();
assert!(ver_parts.next().is_none());
}
#[test]
fn test_long_help() {
let bin = env!("CARGO_BIN_EXE_cargo-vet");
let output = Command::new(bin)
.arg("vet")
.arg("--help")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.unwrap();
insta::assert_snapshot!("long-help", format_outputs(&output));
assert!(output.status.success(), "{}", output.status);
}
#[test]
fn test_short_help() {
let bin = env!("CARGO_BIN_EXE_cargo-vet");
let output = Command::new(bin)
.arg("vet")
.arg("-h")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.unwrap();
insta::assert_snapshot!("short-help", format_outputs(&output));
assert!(output.status.success(), "{}", output.status);
}
#[test]
fn test_markdown_help() {
let bin = env!("CARGO_BIN_EXE_cargo-vet");
let output = Command::new(bin)
.arg("vet")
.arg("help-markdown")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.unwrap();
insta::assert_snapshot!("markdown-help", format_outputs(&output));
assert!(output.status.success(), "{}", output.status);
}
fn test_project_command(subcommand: Option<&str>) -> Command {
let project = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.join("tests")
.join("test-project");
let bin = env!("CARGO_BIN_EXE_cargo-vet");
let mut cmd = Command::new(bin);
cmd.current_dir(&project).arg("vet");
if let Some(sub) = subcommand {
cmd.arg(sub);
}
cmd.arg("--manifest-path")
.arg("Cargo.toml")
.arg("--cache-dir")
.arg("../cache")
.arg("--current-time")
.arg("2023-01-01 12:00:00Z");
cmd
}
#[test]
fn test_project() {
let output = test_project_command(None)
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.unwrap();
insta::assert_snapshot!("test-project", format_outputs(&output));
assert!(output.status.success(), "{}", output.status);
}
#[test]
fn test_project_json() {
let output = test_project_command(None)
.arg("--output-format=json")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.unwrap();
insta::assert_snapshot!("test-project-json", format_outputs(&output));
assert!(output.status.success(), "{}", output.status);
}
#[test]
fn test_project_suggest() {
let output = test_project_command(Some("suggest"))
.arg("--no-registry-suggestions")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.unwrap();
insta::assert_snapshot!("test-project-suggest", format_outputs(&output));
assert!(output.status.success(), "{}", output.status);
}
#[test]
fn test_project_suggest_json() {
let output = test_project_command(Some("suggest"))
.arg("--no-registry-suggestions")
.arg("--output-format=json")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.unwrap();
insta::assert_snapshot!("test-project-suggest-json", format_outputs(&output));
assert!(output.status.success(), "{}", output.status);
}
#[test]
fn test_project_dump_graph_full_json() {
let output = test_project_command(Some("dump-graph"))
.arg("--output-format=json")
.arg("--depth=full")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.unwrap();
insta::assert_snapshot!("test-project-dump-graph-full-json", format_outputs(&output));
assert!(output.status.success(), "{}", output.status);
}
#[test]
fn test_project_dump_graph_full() {
let output = test_project_command(Some("dump-graph"))
.arg("--depth=full")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.unwrap();
insta::assert_snapshot!("test-project-dump-graph-full", format_outputs(&output));
assert!(output.status.success(), "{}", output.status);
}
#[test]
fn test_project_bad_certify_human() {
let output = test_project_command(Some("certify"))
.arg("asdfsdfs")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.unwrap();
insta::assert_snapshot!("test-project-bad-certify-human", format_outputs(&output));
assert!(!output.status.success(), "{}", output.status);
}
#[test]
fn test_project_bad_certify_json() {
let output = test_project_command(Some("certify"))
.arg("--output-format=json")
.arg("asdfsdfs")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.output()
.unwrap();
insta::assert_snapshot!("test-project-bad-certify-json", format_outputs(&output));
assert!(!output.status.success(), "{}", output.status);
}
#[test]
fn test_project_diff_output() {
// Test that the diff output from `cargo vet diff` is correctly filtered to
// remove files like .cargo_vcs_info.json.
let mut child = test_project_command(Some("diff"))
.arg("--mode")
.arg("local")
.arg("syn")
.arg("1.0.90")
.arg("1.0.91")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::piped())
.spawn()
.unwrap();
std::io::Write::write_all(child.stdin.as_mut().unwrap(), b"\n").unwrap();
let output = child.wait_with_output().unwrap();
insta::assert_snapshot!("test-project-diff-output", format_diff_outputs(&output));
assert!(output.status.success(), "{}", output.status);
}
#[test]
fn test_project_diff_output_git() {
// Test that the diff output handles git revisions.
let mut child = test_project_command(Some("diff"))
.arg("--mode")
.arg("local")
.arg("proc-macro2")
.arg("1.0.37")
.arg("1.0.37@git:4445659b0f753a928059244c875a58bb12f791e9")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.stdin(Stdio::piped())
.spawn()
.unwrap();
std::io::Write::write_all(child.stdin.as_mut().unwrap(), b"\n").unwrap();
let output = child.wait_with_output().unwrap();
insta::assert_snapshot!("test-project-diff-output-git", format_diff_outputs(&output));
assert!(output.status.success(), "{}", output.status);
}