Skip to content

Commit e029740

Browse files
committed
Auto merge of #7697 - ehuss:bin-test-env, r=alexcrichton
Set an environment variable for tests to find executables. This adds the environment variable `CARGO_BIN_EXE_<name>` so that integration tests can find binaries to execute, instead of doing things like inspecting `env::current_exe()`. The use of uppercase is primarily motivated by Windows whose Rust implementation behaves in a strange way. It always ascii-upper-cases keys to implement case-insensitive matching (which loses the original case). Seems less likely to result in confusion? Closes #5758.
2 parents 74f2b40 + 4cf531f commit e029740

File tree

8 files changed

+143
-3
lines changed

8 files changed

+143
-3
lines changed

src/cargo/core/compiler/context/compilation_files.rs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use log::info;
1010

1111
use super::{BuildContext, CompileKind, Context, FileFlavor, Layout};
1212
use crate::core::compiler::{CompileMode, CompileTarget, Unit};
13-
use crate::core::{TargetKind, Workspace};
13+
use crate::core::{Target, TargetKind, Workspace};
1414
use crate::util::{self, CargoResult};
1515

1616
/// The `Metadata` is a hash used to make unique file names for each unit in a build.
@@ -248,6 +248,36 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
248248
}
249249
}
250250

251+
/// Returns the path to the executable binary for the given bin target.
252+
///
253+
/// This should only to be used when a `Unit` is not available.
254+
pub fn bin_link_for_target(
255+
&self,
256+
target: &Target,
257+
kind: CompileKind,
258+
bcx: &BuildContext<'_, '_>,
259+
) -> CargoResult<PathBuf> {
260+
assert!(target.is_bin());
261+
let dest = self.layout(kind).dest();
262+
let info = bcx.info(kind);
263+
let file_types = info
264+
.file_types(
265+
"bin",
266+
FileFlavor::Normal,
267+
&TargetKind::Bin,
268+
kind.short_name(bcx),
269+
)?
270+
.expect("target must support `bin`");
271+
272+
let file_type = file_types
273+
.iter()
274+
.filter(|file_type| file_type.flavor == FileFlavor::Normal)
275+
.next()
276+
.expect("target must support `bin`");
277+
278+
Ok(dest.join(file_type.filename(target.name())))
279+
}
280+
251281
/// Returns the filenames that the given unit will generate.
252282
pub(super) fn outputs(
253283
&self,

src/cargo/core/compiler/mod.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,23 @@ fn build_base_args<'a, 'cfg>(
885885
cmd.arg("-Zforce-unstable-if-unmarked")
886886
.env("RUSTC_BOOTSTRAP", "1");
887887
}
888+
889+
// Add `CARGO_BIN_` environment variables for building tests.
890+
if unit.target.is_test() || unit.target.is_bench() {
891+
for bin_target in unit
892+
.pkg
893+
.manifest()
894+
.targets()
895+
.iter()
896+
.filter(|target| target.is_bin())
897+
{
898+
let exe_path = cx
899+
.files()
900+
.bin_link_for_target(bin_target, unit.kind, cx.bcx)?;
901+
let key = format!("CARGO_BIN_EXE_{}", bin_target.name());
902+
cmd.env(&key, exe_path);
903+
}
904+
}
888905
Ok(())
889906
}
890907

src/doc/man/cargo-test.adoc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ ignore the `test` flag and will always test the given target.
7474
Doc tests for libraries may be disabled by setting `doctest = false` for the
7575
library in the manifest.
7676

77+
Binary targets are automatically built if there is an integration test or
78+
benchmark. This allows an integration test to execute the binary to exercise
79+
and test its behavior. The `CARGO_BIN_EXE_<name>`
80+
linkcargo:reference/environment-variables.html#environment-variables-cargo-sets-for-crates[environment variable]
81+
is set when the integration test is built so that it can use the
82+
link:https://doc.rust-lang.org/std/macro.env.html[`env` macro] to locate the
83+
executable.
84+
7785
include::options-targets.adoc[]
7886

7987
*--doc*::

src/doc/man/generated/cargo-test.html

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,15 @@ <h3 id="cargo_test_target_selection">Target Selection</h3>
154154
library in the manifest.</p>
155155
</div>
156156
<div class="paragraph">
157+
<p>Binary targets are automatically built if there is an integration test or
158+
benchmark. This allows an integration test to execute the binary to exercise
159+
and test its behavior. The <code>CARGO_BIN_EXE_&lt;name&gt;</code>
160+
<a href="../reference/environment-variables.html#environment-variables-cargo-sets-for-crates">environment variable</a>
161+
is set when the integration test is built so that it can use the
162+
<a href="https://doc.rust-lang.org/std/macro.env.html"><code>env</code> macro</a> to locate the
163+
executable.</p>
164+
</div>
165+
<div class="paragraph">
157166
<p>Passing target selection flags will test only the
158167
specified targets.</p>
159168
</div>

src/doc/src/reference/cargo-targets.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ modules. The libtest harness will automatically find all of the `#[test]`
123123
annotated functions and run them in parallel. You can pass module names to
124124
[`cargo test`] to only run the tests within that module.
125125

126+
Binary targets are automatically built if there is an integration test. This
127+
allows an integration test to execute the binary to exercise and test its
128+
behavior. The `CARGO_BIN_EXE_<name>` [environment variable] is set when the
129+
integration test is built so that it can use the [`env` macro] to locate the
130+
executable.
131+
132+
[environment variable]: environment-variables.md#environment-variables-cargo-sets-for-crates
133+
[`env` macro]: ../../std/macro.env.html
134+
126135
### Benchmarks
127136

128137
Benchmarks provide a way to test the performance of your code using the

src/doc/src/reference/environment-variables.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,16 @@ let version = env!("CARGO_PKG_VERSION");
187187
* `OUT_DIR` — If the package has a build script, this is set to the folder where the build
188188
script should place its output. See below for more information.
189189
(Only set during compilation.)
190+
* `CARGO_BIN_EXE_<name>` — The absolute path to a binary target's executable.
191+
This is only set when building an [integration test] or benchmark. This may
192+
be used with the [`env` macro] to find the executable to run for testing
193+
purposes. The `<name>` is the name of the binary target, exactly as-is. For
194+
example, `CARGO_BIN_EXE_my-program` for a binary named `my-program`.
195+
Binaries are automatically built when the test is built, unless the binary
196+
has required features that are not enabled.
197+
198+
[integration test]: cargo-targets.md#integration-tests
199+
[`env` macro]: ../../std/macro.env.html
190200

191201
#### Dynamic library paths
192202

src/etc/man/cargo-test.1

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
.\" Title: cargo-test
33
.\" Author: [see the "AUTHOR(S)" section]
44
.\" Generator: Asciidoctor 2.0.10
5-
.\" Date: 2020-01-18
5+
.\" Date: 2020-02-06
66
.\" Manual: \ \&
77
.\" Source: \ \&
88
.\" Language: English
99
.\"
10-
.TH "CARGO\-TEST" "1" "2020-01-18" "\ \&" "\ \&"
10+
.TH "CARGO\-TEST" "1" "2020-02-06" "\ \&" "\ \&"
1111
.ie \n(.g .ds Aq \(aq
1212
.el .ds Aq '
1313
.ss \n[.ss] 0
@@ -206,6 +206,16 @@ ignore the \fBtest\fP flag and will always test the given target.
206206
Doc tests for libraries may be disabled by setting \fBdoctest = false\fP for the
207207
library in the manifest.
208208
.sp
209+
Binary targets are automatically built if there is an integration test or
210+
benchmark. This allows an integration test to execute the binary to exercise
211+
and test its behavior. The \fBCARGO_BIN_EXE_<name>\fP
212+
\c
213+
.URL "https://doc.rust\-lang.org/cargo/reference/environment\-variables.html#environment\-variables\-cargo\-sets\-for\-crates" "environment variable"
214+
is set when the integration test is built so that it can use the
215+
.URL "https://doc.rust\-lang.org/std/macro.env.html" "\fBenv\fP macro" " "
216+
to locate the
217+
executable.
218+
.sp
209219
Passing target selection flags will test only the
210220
specified targets.
211221
.sp

tests/testsuite/test.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3995,3 +3995,50 @@ fn panic_abort_test_profile_inherits() {
39953995
.with_status(0)
39963996
.run();
39973997
}
3998+
3999+
#[cargo_test]
4000+
fn bin_env_for_test() {
4001+
// Test for the `CARGO_BIN_` environment variables for tests.
4002+
//
4003+
// Note: The Unicode binary uses a `[[bin]]` definition because different
4004+
// filesystems normalize utf-8 in different ways. For example, HFS uses
4005+
// "gru\u{308}ßen" and APFS uses "gr\u{fc}ßen". Defining it in TOML forces
4006+
// one form to be used.
4007+
let p = project()
4008+
.file(
4009+
"Cargo.toml",
4010+
r#"
4011+
[package]
4012+
name = "foo"
4013+
version = "0.1.0"
4014+
edition = "2018"
4015+
4016+
[[bin]]
4017+
name = 'grüßen'
4018+
path = 'src/bin/grussen.rs'
4019+
"#,
4020+
)
4021+
.file("src/bin/foo.rs", "fn main() {}")
4022+
.file("src/bin/with-dash.rs", "fn main() {}")
4023+
.file("src/bin/grussen.rs", "fn main() {}")
4024+
.build();
4025+
4026+
let bin_path = |name| p.bin(name).to_string_lossy().replace("\\", "\\\\");
4027+
p.change_file(
4028+
"tests/check_env.rs",
4029+
&r#"
4030+
#[test]
4031+
fn run_bins() {
4032+
assert_eq!(env!("CARGO_BIN_EXE_foo"), "<FOO_PATH>");
4033+
assert_eq!(env!("CARGO_BIN_EXE_with-dash"), "<WITH_DASH_PATH>");
4034+
assert_eq!(env!("CARGO_BIN_EXE_grüßen"), "<GRÜSSEN_PATH>");
4035+
}
4036+
"#
4037+
.replace("<FOO_PATH>", &bin_path("foo"))
4038+
.replace("<WITH_DASH_PATH>", &bin_path("with-dash"))
4039+
.replace("<GRÜSSEN_PATH>", &bin_path("grüßen")),
4040+
);
4041+
4042+
p.cargo("test --test check_env").run();
4043+
p.cargo("check --test check_env").run();
4044+
}

0 commit comments

Comments
 (0)