Skip to content

Commit 19d5e48

Browse files
Add macro and deprecate function
Ed Page (@epage) suggested replacing the function with a macro. This is because Cargo is planning to move where the output is written. Signed-off-by: Michael Mc Donnell <michael@mcdonnell.dk>
1 parent 3f6ded8 commit 19d5e48

File tree

6 files changed

+153
-80
lines changed

6 files changed

+153
-80
lines changed

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
### Fixed
13+
14+
## [0.5.0] - 2025-07-11
15+
16+
### Added
17+
18+
- A macro was added and the old function was deprecated by [@MichaelMcDonnell](https://github.com/MichaelMcDonnell) at the suggestion of [@epage](https://github.com/epage).
1219
- Windows and cross (Linux musl) CI by [@MichaelMcDonnell](https://github.com/MichaelMcDonnell).
1320

1421
### Fixed
@@ -43,7 +50,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4350

4451
- The initial release by [@MichaelMcDonnell](https://github.com/MichaelMcDonnell).
4552

46-
[Unreleased]: https://github.com/MichaelMcDonnell/test_bin/compare/v0.4.0...HEAD
53+
[Unreleased]: https://github.com/MichaelMcDonnell/test_bin/compare/v0.5.0...HEAD
54+
[0.5.0]: https://github.com/MichaelMcDonnell/test_bin/compare/v0.4.0...v0.5.0
4755
[0.4.0]: https://github.com/MichaelMcDonnell/test_bin/compare/v0.3.0...v0.4.0
4856
[0.3.0]: https://github.com/MichaelMcDonnell/test_bin/compare/v0.2.0...v0.3.0
4957
[0.2.0]: https://github.com/MichaelMcDonnell/test_bin/compare/v0.1.0...v0.2.0

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "test_bin"
3-
version = "0.4.0"
3+
version = "0.5.0"
44
authors = ["Michael Mc Donnell <michael@mcdonnell.dk>"]
55
edition = "2018"
66
license = "MIT OR Apache-2.0"

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ If you are writing a command-line interface app then it is useful to write an in
99
Here is the basic usage:
1010

1111
```rust
12-
let output = test_bin::get_test_bin("my_cli_app")
12+
let output = test_bin::get_test_bin!("my_cli_app")
1313
.output()
1414
.expect("Failed to start my_binary");
1515
assert_eq!(
@@ -18,12 +18,20 @@ assert_eq!(
1818
);
1919
```
2020

21+
NOTE: The `get_test_bin` function was deprecated in version 0.5.0. Please use
22+
the macro instead.
23+
2124
## Acknowledgements
2225

2326
The `cargo` and `ripgrep` crates were used as inspiration. They both test their
2427
binaries using a similar approach. The `cargo` crate's documentation and license
2528
was used as a starting point.
2629

30+
Thanks to Ewan Higgs (@ehiggs), and Chris Greenaway (@ChrisGreenaway) for their
31+
fixes.
32+
33+
The code was later changed to a macro via a suggestion by Ed Page (@epage).
34+
2735
## Contributing
2836

2937
See CONTRIBUTING.md.

src/lib.rs

Lines changed: 108 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,108 @@
1-
//! A module for getting the crate binary in an integration test.
2-
//!
3-
//! If you are writing a command-line interface app then it is useful to write
4-
//! an integration test that uses the binary. You most likely want to launch the
5-
//! binary and inspect the output. This module lets you get the binary so it can
6-
//! be tested.
7-
//!
8-
//! # Examples
9-
//!
10-
//! basic usage:
11-
//!
12-
//! ```no_run
13-
//! let output = test_bin::get_test_bin("my_cli_app")
14-
//! .output()
15-
//! .expect("Failed to start my_binary");
16-
//! assert_eq!(
17-
//! String::from_utf8_lossy(&output.stdout),
18-
//! "Output from my CLI app!\n"
19-
//! );
20-
//! ```
21-
//!
22-
//! Refer to the [`std::process::Command` documentation](https://doc.rust-lang.org/std/process/struct.Command.html)
23-
//! for how to pass arguments, check exit status and more.
24-
25-
/// Returns the crate's binary as a `Command` that can be used for integration
26-
/// tests.
27-
///
28-
/// # Arguments
29-
///
30-
/// * `bin_name` - The name of the binary you want to test.
31-
///
32-
/// # Remarks
33-
///
34-
/// It panics on error. This is by design so the test that uses it fails.
35-
pub fn get_test_bin(bin_name: &str) -> std::process::Command {
36-
// Create full path to binary
37-
let mut path = get_test_bin_dir();
38-
path.push(bin_name);
39-
path.set_extension(std::env::consts::EXE_EXTENSION);
40-
41-
assert!(path.exists());
42-
43-
// Create command
44-
std::process::Command::new(path.into_os_string())
45-
}
46-
47-
/// Returns the directory of the crate's binary.
48-
///
49-
/// # Remarks
50-
///
51-
/// It panics on error. This is by design so the test that uses it fails.
52-
fn get_test_bin_dir() -> std::path::PathBuf {
53-
// Cargo puts the integration test binary in target/debug/deps
54-
let current_exe =
55-
std::env::current_exe().expect("Failed to get the path of the integration test binary");
56-
let current_dir = current_exe
57-
.parent()
58-
.expect("Failed to get the directory of the integration test binary");
59-
60-
let test_bin_dir = current_dir
61-
.parent()
62-
.expect("Failed to get the binary folder");
63-
test_bin_dir.to_owned()
64-
}
1+
//! A module for getting the crate binary in an integration test.
2+
//!
3+
//! If you are writing a command-line interface app then it is useful to write
4+
//! an integration test that uses the binary. You most likely want to launch the
5+
//! binary and inspect the output. This module lets you get the binary so it can
6+
//! be tested.
7+
//!
8+
//! # Examples
9+
//!
10+
//! basic usage:
11+
//!
12+
//! ```no_run
13+
//! let output = test_bin::get_test_bin!("my_cli_app")
14+
//! .output()
15+
//! .expect("Failed to start my_binary");
16+
//! assert_eq!(
17+
//! String::from_utf8_lossy(&output.stdout),
18+
//! "Output from my CLI app!\n"
19+
//! );
20+
//! ```
21+
//!
22+
//! Refer to the [`std::process::Command` documentation](https://doc.rust-lang.org/std/process/struct.Command.html)
23+
//! for how to pass arguments, check exit status and more.
24+
//!
25+
//! NOTE: There is also the older non-macro `get_test_bin` which has been
26+
//! deprecated. I has been deprecated because there is work to allow cargo to
27+
//! write its output to new paths. See [Cargo issue 14125](https://github.com/rust-lang/cargo/issues/14125).
28+
//!
29+
//! The `get_test_bin` macro uses the `CARGO_BIN_EXE_<name>` environment
30+
//! variable which was introduced in [Rust 1.43 released on 23 April 2020](https://releases.rs/docs/1.43.0/).
31+
//!
32+
33+
// Returns the crate's binary as a `Command` that can be used for integration
34+
/// tests.
35+
///
36+
/// # Arguments
37+
///
38+
/// * `bin_name` - The name of the binary you want to test.
39+
///
40+
/// # Remarks
41+
///
42+
/// It will fail to compile if the `bin_name` is incorrect. The `bin_name` is
43+
/// used for creating an environment variable.
44+
#[macro_export]
45+
macro_rules! get_test_bin {
46+
($x:expr) => {
47+
{
48+
// Get path string. See the CARGO_BIN_EXE_<name> documentation:
49+
// https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates
50+
let path_str = env!(concat!("CARGO_BIN_EXE_", $x));
51+
// Create command
52+
std::process::Command::new(path_str)
53+
}
54+
};
55+
}
56+
57+
/// Returns the crate's binary as a `Command` that can be used for integration
58+
/// tests.
59+
///
60+
/// # Arguments
61+
///
62+
/// * `bin_name` - The name of the binary you want to test.
63+
///
64+
/// # Remarks
65+
///
66+
/// It panics on error. This is by design so the test that uses it fails.
67+
#[deprecated(since = "0.5.0", note = "please use `get_test_bin!` macro instead")]
68+
pub fn get_test_bin(bin_name: &str) -> std::process::Command {
69+
// Create full path to binary
70+
let mut path = get_test_bin_dir();
71+
path.push(bin_name);
72+
path.set_extension(std::env::consts::EXE_EXTENSION);
73+
74+
if !path.exists() {
75+
// Print all environment variables.
76+
for (key, value) in std::env::vars() {
77+
println!("{key}: {value}");
78+
}
79+
let path: &'static str = env!("PATH");
80+
println!("the $PATH variable at the time of compiling was: {path}");
81+
let build_dir = std::env::var("CARGO_BIN_EXE_test_bin").unwrap();
82+
panic!("Environment variable is {}", build_dir);
83+
}
84+
85+
assert!(path.exists());
86+
87+
// Create command
88+
std::process::Command::new(path.into_os_string())
89+
}
90+
91+
/// Returns the directory of the crate's binary.
92+
///
93+
/// # Remarks
94+
///
95+
/// It panics on error. This is by design so the test that uses it fails.
96+
fn get_test_bin_dir() -> std::path::PathBuf {
97+
// Cargo puts the integration test binary in target/debug/deps
98+
let current_exe =
99+
std::env::current_exe().expect("Failed to get the path of the integration test binary");
100+
let current_dir = current_exe
101+
.parent()
102+
.expect("Failed to get the directory of the integration test binary");
103+
104+
let test_bin_dir = current_dir
105+
.parent()
106+
.expect("Failed to get the binary folder");
107+
test_bin_dir.to_owned()
108+
}

tests/integration_test.rs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,24 @@
1-
#[test]
2-
fn basic_usage() {
3-
let output = test_bin::get_test_bin("test_bin")
4-
.output()
5-
.expect("Failed to start test_bin");
6-
7-
assert_eq!(
8-
String::from_utf8_lossy(&output.stdout),
9-
"Output from my CLI app!\n"
10-
);
11-
}
1+
#[test]
2+
fn basic_usage() {
3+
let output = test_bin::get_test_bin!("test_bin")
4+
.output()
5+
.expect("Failed to start test_bin");
6+
7+
assert_eq!(
8+
String::from_utf8_lossy(&output.stdout),
9+
"Output from my CLI app!\n"
10+
);
11+
}
12+
13+
#[test]
14+
fn basic_usage_deprecated() {
15+
#[allow(deprecated)]
16+
let output = test_bin::get_test_bin("test_bin")
17+
.output()
18+
.expect("Failed to start test_bin");
19+
20+
assert_eq!(
21+
String::from_utf8_lossy(&output.stdout),
22+
"Output from my CLI app!\n"
23+
);
24+
}

0 commit comments

Comments
 (0)