Skip to content

Set an environment variable for tests to find executables. #7697

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion src/cargo/core/compiler/context/compilation_files.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use log::info;

use super::{BuildContext, CompileKind, Context, FileFlavor, Layout};
use crate::core::compiler::{CompileMode, CompileTarget, Unit};
use crate::core::{TargetKind, Workspace};
use crate::core::{Target, TargetKind, Workspace};
use crate::util::{self, CargoResult};

/// The `Metadata` is a hash used to make unique file names for each unit in a build.
Expand Down Expand Up @@ -241,6 +241,36 @@ impl<'a, 'cfg: 'a> CompilationFiles<'a, 'cfg> {
}
}

/// Returns the path to the executable binary for the given bin target.
///
/// This should only to be used when a `Unit` is not available.
pub fn bin_link_for_target(
&self,
target: &Target,
kind: CompileKind,
bcx: &BuildContext<'_, '_>,
) -> CargoResult<PathBuf> {
assert!(target.is_bin());
let dest = self.layout(kind).dest();
let info = bcx.info(kind);
let file_types = info
.file_types(
"bin",
FileFlavor::Normal,
&TargetKind::Bin,
kind.short_name(bcx),
)?
.expect("target must support `bin`");

let file_type = file_types
.iter()
.filter(|file_type| file_type.flavor == FileFlavor::Normal)
.next()
.expect("target must support `bin`");

Ok(dest.join(file_type.filename(target.name())))
}

/// Returns the filenames that the given unit will generate.
pub(super) fn outputs(
&self,
Expand Down
17 changes: 17 additions & 0 deletions src/cargo/core/compiler/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,23 @@ fn build_base_args<'a, 'cfg>(
cmd.arg("-Zforce-unstable-if-unmarked")
.env("RUSTC_BOOTSTRAP", "1");
}

// Add `CARGO_BIN_` environment variables for building tests.
if unit.target.is_test() || unit.target.is_bench() {
for bin_target in unit
.pkg
.manifest()
.targets()
.iter()
.filter(|target| target.is_bin())
{
let exe_path = cx
.files()
.bin_link_for_target(bin_target, unit.kind, cx.bcx)?;
let key = format!("CARGO_BIN_EXE_{}", bin_target.name());
cmd.env(&key, exe_path);
}
}
Ok(())
}

Expand Down
8 changes: 8 additions & 0 deletions src/doc/man/cargo-test.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ ignore the `test` flag and will always test the given target.
Doc tests for libraries may be disabled by setting `doctest = false` for the
library in the manifest.

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

include::options-targets.adoc[]

*--doc*::
Expand Down
9 changes: 9 additions & 0 deletions src/doc/man/generated/cargo-test.html
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,15 @@ <h3 id="cargo_test_target_selection">Target Selection</h3>
library in the manifest.</p>
</div>
<div class="paragraph">
<p>Binary targets are automatically built if there is an integration test or
benchmark. This allows an integration test to execute the binary to exercise
and test its behavior. The <code>CARGO_BIN_EXE_&lt;name&gt;</code>
<a href="../reference/environment-variables.html#environment-variables-cargo-sets-for-crates">environment variable</a>
is set when the integration test is built so that it can use the
<a href="https://doc.rust-lang.org/std/macro.env.html"><code>env</code> macro</a> to locate the
executable.</p>
</div>
<div class="paragraph">
<p>Passing target selection flags will test only the
specified targets.</p>
</div>
Expand Down
9 changes: 9 additions & 0 deletions src/doc/src/reference/cargo-targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,15 @@ modules. The libtest harness will automatically find all of the `#[test]`
annotated functions and run them in parallel. You can pass module names to
[`cargo test`] to only run the tests within that module.

Binary targets are automatically built if there is an integration test. This
allows an integration test to execute the binary to exercise and test its
behavior. The `CARGO_BIN_EXE_<name>` [environment variable] is set when the
integration test is built so that it can use the [`env` macro] to locate the
executable.

[environment variable]: environment-variables.md#environment-variables-cargo-sets-for-crates
[`env` macro]: ../../std/macro.env.html

### Benchmarks

Benchmarks provide a way to test the performance of your code using the
Expand Down
10 changes: 10 additions & 0 deletions src/doc/src/reference/environment-variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,16 @@ let version = env!("CARGO_PKG_VERSION");
* `OUT_DIR` — If the package has a build script, this is set to the folder where the build
script should place its output. See below for more information.
(Only set during compilation.)
* `CARGO_BIN_EXE_<name>` — The absolute path to a binary target's executable.
This is only set when building an [integration test] or benchmark. This may
be used with the [`env` macro] to find the executable to run for testing
purposes. The `<name>` is the name of the binary target, exactly as-is. For
example, `CARGO_BIN_EXE_my-program` for a binary named `my-program`.
Binaries are automatically built when the test is built, unless the binary
has required features that are not enabled.

[integration test]: cargo-targets.md#integration-tests
[`env` macro]: ../../std/macro.env.html

#### Dynamic library paths

Expand Down
14 changes: 12 additions & 2 deletions src/etc/man/cargo-test.1
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
.\" Title: cargo-test
.\" Author: [see the "AUTHOR(S)" section]
.\" Generator: Asciidoctor 2.0.10
.\" Date: 2020-01-18
.\" Date: 2020-02-06
.\" Manual: \ \&
.\" Source: \ \&
.\" Language: English
.\"
.TH "CARGO\-TEST" "1" "2020-01-18" "\ \&" "\ \&"
.TH "CARGO\-TEST" "1" "2020-02-06" "\ \&" "\ \&"
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.ss \n[.ss] 0
Expand Down Expand Up @@ -206,6 +206,16 @@ ignore the \fBtest\fP flag and will always test the given target.
Doc tests for libraries may be disabled by setting \fBdoctest = false\fP for the
library in the manifest.
.sp
Binary targets are automatically built if there is an integration test or
benchmark. This allows an integration test to execute the binary to exercise
and test its behavior. The \fBCARGO_BIN_EXE_<name>\fP
\c
.URL "https://doc.rust\-lang.org/cargo/reference/environment\-variables.html#environment\-variables\-cargo\-sets\-for\-crates" "environment variable"
is set when the integration test is built so that it can use the
.URL "https://doc.rust\-lang.org/std/macro.env.html" "\fBenv\fP macro" " "
to locate the
executable.
.sp
Passing target selection flags will test only the
specified targets.
.sp
Expand Down
47 changes: 47 additions & 0 deletions tests/testsuite/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3995,3 +3995,50 @@ fn panic_abort_test_profile_inherits() {
.with_status(0)
.run();
}

#[cargo_test]
fn bin_env_for_test() {
// Test for the `CARGO_BIN_` environment variables for tests.
//
// Note: The Unicode binary uses a `[[bin]]` definition because different
// filesystems normalize utf-8 in different ways. For example, HFS uses
// "gru\u{308}ßen" and APFS uses "gr\u{fc}ßen". Defining it in TOML forces
// one form to be used.
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2018"

[[bin]]
name = 'grüßen'
path = 'src/bin/grussen.rs'
"#,
)
.file("src/bin/foo.rs", "fn main() {}")
.file("src/bin/with-dash.rs", "fn main() {}")
.file("src/bin/grussen.rs", "fn main() {}")
.build();

let bin_path = |name| p.bin(name).to_string_lossy().replace("\\", "\\\\");
p.change_file(
"tests/check_env.rs",
&r#"
#[test]
fn run_bins() {
assert_eq!(env!("CARGO_BIN_EXE_foo"), "<FOO_PATH>");
assert_eq!(env!("CARGO_BIN_EXE_with-dash"), "<WITH_DASH_PATH>");
assert_eq!(env!("CARGO_BIN_EXE_grüßen"), "<GRÜSSEN_PATH>");
}
"#
.replace("<FOO_PATH>", &bin_path("foo"))
.replace("<WITH_DASH_PATH>", &bin_path("with-dash"))
.replace("<GRÜSSEN_PATH>", &bin_path("grüßen")),
);

p.cargo("test --test check_env").run();
p.cargo("check --test check_env").run();
}