blob: 849157908511be497a227b0d899192b05cb6356c [file] [log] [blame]
//! A test suite for `-Zbuild-std` which is much more expensive than the
//! standard test suite.
//!
//! This test suite attempts to perform a full integration test where we
//! actually compile the standard library from source (like the real one) and
//! the various tests associated with that.
//!
//! YOU SHOULD IDEALLY NOT WRITE TESTS HERE.
//!
//! If possible, use `tests/testsuite/standard_lib.rs` instead. That uses a
//! 'mock' sysroot which is much faster to compile. The tests here are
//! extremely intensive and are only intended to run on CI and are theoretically
//! not catching any regressions that `tests/testsuite/standard_lib.rs` isn't
//! already catching.
//!
//! All tests here should use `#[cargo_test(build_std_real)]` to indicate that
//! boilerplate should be generated to require the nightly toolchain and the
//! `CARGO_RUN_BUILD_STD_TESTS` env var to be set to actually run these tests.
//! Otherwise the tests are skipped.
#![allow(clippy::disallowed_methods)]
use cargo_test_support::*;
use std::env;
use std::path::Path;
fn enable_build_std(e: &mut Execs, arg: Option<&str>) {
e.env_remove("CARGO_HOME");
e.env_remove("HOME");
// And finally actually enable `build-std` for now
let arg = match arg {
Some(s) => format!("-Zbuild-std={}", s),
None => "-Zbuild-std".to_string(),
};
e.arg(arg).arg("-Zpublic-dependency");
e.masquerade_as_nightly_cargo(&["build-std"]);
}
// Helper methods used in the tests below
trait BuildStd: Sized {
fn build_std(&mut self) -> &mut Self;
fn build_std_arg(&mut self, arg: &str) -> &mut Self;
fn target_host(&mut self) -> &mut Self;
}
impl BuildStd for Execs {
fn build_std(&mut self) -> &mut Self {
enable_build_std(self, None);
self
}
fn build_std_arg(&mut self, arg: &str) -> &mut Self {
enable_build_std(self, Some(arg));
self
}
fn target_host(&mut self) -> &mut Self {
self.arg("--target").arg(rustc_host());
self
}
}
#[cargo_test(build_std_real)]
fn basic() {
let p = project()
.file(
"src/main.rs",
"
fn main() {
foo::f();
}
#[test]
fn smoke_bin_unit() {
foo::f();
}
",
)
.file(
"src/lib.rs",
"
extern crate alloc;
extern crate proc_macro;
/// ```
/// foo::f();
/// ```
pub fn f() {
}
#[test]
fn smoke_lib_unit() {
f();
}
",
)
.file(
"tests/smoke.rs",
"
#[test]
fn smoke_integration() {
foo::f();
}
",
)
.build();
p.cargo("check").build_std().target_host().run();
p.cargo("build")
.build_std()
.target_host()
// Importantly, this should not say [UPDATING]
// There have been multiple bugs where every build triggers and update.
.with_stderr(
"[COMPILING] foo v0.0.1 [..]\n\
[FINISHED] `dev` profile [..]",
)
.run();
p.cargo("run").build_std().target_host().run();
p.cargo("test").build_std().target_host().run();
// Check for hack that removes dylibs.
let deps_dir = Path::new("target")
.join(rustc_host())
.join("debug")
.join("deps");
assert!(p.glob(deps_dir.join("*.rlib")).count() > 0);
assert_eq!(p.glob(deps_dir.join("*.dylib")).count(), 0);
}
#[cargo_test(build_std_real)]
fn cross_custom() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2018"
[target.custom-target.dependencies]
dep = { path = "dep" }
"#,
)
.file(
"src/lib.rs",
"#![no_std] pub fn f() -> u32 { dep::answer() }",
)
.file("dep/Cargo.toml", &basic_manifest("dep", "0.1.0"))
.file("dep/src/lib.rs", "#![no_std] pub fn answer() -> u32 { 42 }")
.file(
"custom-target.json",
r#"
{
"llvm-target": "x86_64-unknown-none-gnu",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"os": "none",
"linker-flavor": "ld.lld"
}
"#,
)
.build();
p.cargo("build --target custom-target.json -v")
.build_std_arg("core")
.run();
}
#[cargo_test(build_std_real)]
fn custom_test_framework() {
let p = project()
.file(
"src/lib.rs",
r#"
#![no_std]
#![cfg_attr(test, no_main)]
#![feature(custom_test_frameworks)]
#![test_runner(crate::test_runner)]
pub fn test_runner(_tests: &[&dyn Fn()]) {}
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
loop {}
}
"#,
)
.file(
"target.json",
r#"
{
"llvm-target": "x86_64-unknown-none-gnu",
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
"arch": "x86_64",
"target-endian": "little",
"target-pointer-width": "64",
"target-c-int-width": "32",
"os": "none",
"linker-flavor": "ld.lld",
"linker": "rust-lld",
"executables": true,
"panic-strategy": "abort"
}
"#,
)
.build();
// This is a bit of a hack to use the rust-lld that ships with most toolchains.
let sysroot = paths::sysroot();
let sysroot = Path::new(&sysroot);
let sysroot_bin = sysroot
.join("lib")
.join("rustlib")
.join(rustc_host())
.join("bin");
let path = env::var_os("PATH").unwrap_or_default();
let mut paths = env::split_paths(&path).collect::<Vec<_>>();
paths.insert(0, sysroot_bin);
let new_path = env::join_paths(paths).unwrap();
p.cargo("test --target target.json --no-run -v")
.env("PATH", new_path)
.build_std_arg("core")
.run();
}
// Fixing rust-lang/rust#117839.
// on macOS it never gets remapped.
// Might be a separate issue, so only run on Linux.
#[cargo_test(build_std_real)]
#[cfg(target_os = "linux")]
fn remap_path_scope() {
let p = project()
.file(
"src/main.rs",
"
fn main() {
panic!(\"remap to /rustc/<hash>\");
}
",
)
.file(
".cargo/config.toml",
"
[profile.release]
debug = \"line-tables-only\"
",
)
.build();
p.cargo("run --release -Ztrim-paths")
.masquerade_as_nightly_cargo(&["-Ztrim-paths"])
.env("RUST_BACKTRACE", "1")
.build_std()
.target_host()
.with_status(101)
.with_stderr_contains(
"\
[FINISHED] `release` profile [optimized + debuginfo] [..]
[RUNNING] [..]
[..]thread '[..]' panicked at [..]src/main.rs:3:[..]",
)
.with_stderr_contains("remap to /rustc/<hash>")
.with_stderr_contains("[..]at /rustc/[..]/library/std/src/[..]")
.with_stderr_contains("[..]at src/main.rs:3[..]")
.with_stderr_contains("[..]at /rustc/[..]/library/core/src/[..]")
.run();
}