diff --git a/Cargo.lock b/Cargo.lock index 875b2cab..b17600d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -346,6 +346,7 @@ dependencies = [ "human-panic", "ignore", "insta", + "insta-cmd", "itertools 0.13.0", "log", "predicates", @@ -1894,6 +1895,17 @@ dependencies = [ "similar", ] +[[package]] +name = "insta-cmd" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffeeefa927925cced49ccb01bf3e57c9d4cd132df21e576eb9415baeab2d3de6" +dependencies = [ + "insta", + "serde", + "serde_json", +] + [[package]] name = "ipnet" version = "2.9.0" diff --git a/Cargo.toml b/Cargo.toml index 370d191b..ad496650 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,7 @@ predicates = "3.1.0" insta = { version = "1.39.0", features = ["ron", "filters"] } fs-err = "2.11.0" regex = "1.10.6" +insta-cmd = "0.6.0" # In dev and test profiles, compile all dependencies with optimizations enabled, # but still checking debug assertions and overflows. diff --git a/test_outputs/integration_snapshots__bugreport.snap b/test_outputs/integration_snapshots__bugreport.snap new file mode 100644 index 00000000..fcc76018 --- /dev/null +++ b/test_outputs/integration_snapshots__bugreport.snap @@ -0,0 +1,58 @@ +--- +source: tests/integration_snapshots.rs +info: + program: cargo-semver-checks + args: + - semver-checks + - "--bugreport" + env: + CARGO_TERM_COLOR: never +--- +success: true +exit_code: 0 +----- stdout ----- +System information: +------------------- +#### Software version + +cargo-semver-checks [VERSION] ([HASH]) + +#### Operating system + +[OS] + +#### Command-line + +```bash +[EXECUTABLE_PATH] semver-checks --bugreport +``` + +#### cargo version + +``` +> cargo -V +cargo [CARGO_VERSION] ([CARGO_VERSION_DETAILS]) +``` + +#### Compile time information + +- Profile: [PROFILE] +- Target triple: [TARGET_TRIPLE] +- Family: [FAMILY] +- OS: [OS] +- Architecture: [ARCH] +- Pointer width: [WIDTH] +- Endian: [ENDIAN] +- CPU features: [FEATURES] +- Host: [HOST_TRIPLE] + + +Cargo build configuration: +-------------------------- +[CARGO_BUILD_TOML] +Please file an issue on GitHub reporting your bug. +Consider adding the diagnostic information above, either manually or automatically through the link below: + +https://github.com/obi1kenobi/cargo-semver-checks/issues/new?[INFO_URLENCODED] + +----- stderr ----- diff --git a/tests/integration_snapshots.rs b/tests/integration_snapshots.rs new file mode 100644 index 00000000..25f30f67 --- /dev/null +++ b/tests/integration_snapshots.rs @@ -0,0 +1,106 @@ +//! Integration snapshot tests for testing `cargo-semver-checks` binary behavior. +//! +//! These tests have greater compile time penalties than `src/snapshot_tests.rs`. +//! Prefer those unless your test needs to access behavior in the `main` function of +//! `cargo-semver-checks`. +//! +//! See the module-level doc comment on `src/snapshot_tests.rs` for information on how +//! to create and update snapshot tests. +//! +//! To write an integration test, make a `#[test]` function and call [`assert_integration_test`] +//! to configure and run an integration test on the `cargo-semver-checks` binary. + +use std::path::{Path, PathBuf}; + +use assert_cmd::cargo::CommandCargoExt; +use insta_cmd::Command; + +/// Create a snapshot of the output of a `cargo semver-checks` invocation, using [`insta_cmd`]. +/// Add arguments and mutate the command using the passed closure (you do not need to include the +/// `semver-checks` subcommand`. This also lets you modify the [`insta::Settings`], e.g., to add +/// filters. +/// +/// The snapshot will be the `test_crates/snapshot_tests/integration_snapshots__{test_name}.snap` +/// file, so make sure to check this file into version control when adding/updating a test. +/// `test_name` will often be the name of the `#[test]` function that calls this function. +fn assert_integration_test( + test_name: &str, + modify: impl FnOnce(&mut Command, &mut insta::Settings), +) { + let mut settings = insta::Settings::clone_current(); + let mut cmd = + Command::cargo_bin("cargo-semver-checks").expect("failed to get cargo-semver-checks"); + cmd.env("CARGO_TERM_COLOR", "never"); + + cmd.arg("semver-checks"); + settings.set_snapshot_path("../test_outputs/"); + + modify(&mut cmd, &mut settings); + + settings.bind(|| insta_cmd::assert_cmd_snapshot!(test_name, cmd)); +} + +/// Snapshots the behavior of the `--bugreport` argument. +#[test] +fn bugreport() { + assert_integration_test("bugreport", |cmd, settings| { + cmd.arg("--bugreport"); + // much of this is not reproducible on different machines, so we have + // to heavily filter it. + settings.add_filter( + r"cargo-semver-checks \d+\.\d+\.\d+(-[\w\.-]+)? \(\w+(-modified)?\)", + "cargo-semver-checks [VERSION] ([HASH])", + ); + settings.add_filter( + r"#### Operating system\n\n[^\n]+", + "#### Operating system\n\n[OS]", + ); + settings.add_filter( + ®ex::escape(executable_path().to_str().expect("non-UTF-8 path")), + "[EXECUTABLE_PATH]", + ); + + settings.add_filter( + r"cargo \d+\.\d+\.\d+(-[\w\.-]+)? \(.+\)", + "cargo [CARGO_VERSION] ([CARGO_VERSION_DETAILS])", + ); + + settings.add_filter(r"Profile: \w+", "Profile: [PROFILE]"); + settings.add_filter(r"Target triple: [\w-]+", "Target triple: [TARGET_TRIPLE]"); + settings.add_filter(r"Family: \w+", "Family: [FAMILY]"); + settings.add_filter(r"OS: \w+", "OS: [OS]"); + settings.add_filter(r"Architecture: \w+", "Architecture: [ARCH]"); + settings.add_filter(r"Pointer width: \d+", "Pointer width: [WIDTH]"); + settings.add_filter(r"Endian: \w+", "Endian: [ENDIAN]"); + settings.add_filter(r"CPU features: [\w,-]+", "CPU features: [FEATURES]"); + settings.add_filter(r"Host: [\w-]+", "Host: [HOST_TRIPLE]"); + + // this should be serialized TOML + settings.add_filter( + "Cargo build configuration:\\n\ + --------------------------\\n\ + [\\s\\S]*\\n\ + Please file an issue", + "Cargo build configuration:\n\ + --------------------------\n\ + [CARGO_BUILD_TOML]\n\ + Please file an issue", + ); + + settings.add_filter( + r"https://github\.com/obi1kenobi/cargo-semver-checks/issues/new\?\S+", + "https://github.com/obi1kenobi/cargo-semver-checks/issues/new?[INFO_URLENCODED]", + ); + }); +} + +/// Helper function to get a canonicalized version of the cargo executable bin. +fn executable_path() -> PathBuf { + Path::new( + Command::cargo_bin("cargo-semver-checks") + .expect("expected cargo-semver-checks") + .get_program(), + ) + .canonicalize() + .expect("error canonicalizing") +}