Skip to content

Commit

Permalink
Auto merge of #7697 - ehuss:bin-test-env, r=alexcrichton
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
bors committed Feb 18, 2020
2 parents 74f2b40 + 4cf531f commit e029740
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 3 deletions.
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 @@ -248,6 +248,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 @@ -885,6 +885,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.

This comment has been minimized.

Copy link
@jiangying000

jiangying000 Sep 26, 2022

Contributor

should this be
// Add CARGO_BIN_EXE_ 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.

This comment has been minimized.

Copy link
@jiangying000

jiangying000 Sep 26, 2022

Contributor

should this be
// Test for the CARGO_BIN_EXE_ 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();
}

0 comments on commit e029740

Please sign in to comment.