Skip to content

Commit

Permalink
Unrolled build for rust-lang#134111
Browse files Browse the repository at this point in the history
Rollup merge of rust-lang#134111 - jyn514:run-make-nocapture, r=jieyouxu

Fix `--nocapture` for run-make tests

This was confusing because there are three layers of output hiding.
1. libtest shoves all output into a buffer and does not print it unless the test fails or `--nocapture` is passed.
2. compiletest chooses whether to print the output from any given process.
3. run-make-support chooses what output to print.

This modifies 2 and 3.

- compiletest: Don't require both `--verbose` and `--nocapture` to show the output of run-make tests.
- compiletest: Print the output from `rmake` processes if they succeed. Previously this was only printed on failure.
- compiletest: Distinguish rustc and rmake stderr by printing the command name (e.g. "--stderr--" to "--rustc stderr--").
- run-make-support: Unconditionally print the needle/haystack being searched. Previously this was only printed on failure.

Before:
```
$ x t tests/run-make/linker-warning --force-rerun -- --nocapture
running 1 tests
.

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 377 filtered out; finished in 281.64ms
$ x t tests/run-make/linker-warning --force-rerun -v -- --nocapture 2>&1 | wc -l
1004
$ x t tests/run-make/linker-warning --force-rerun -v -- --nocapture | tail -n40
running 1 tests

------stdout------------------------------

------stderr------------------------------
warning: unused import: `std::path::Path`
 --> /home/jyn/src/rust2/tests/run-make/linker-warning/rmake.rs:1:5
  |
1 | use std::path::Path;
  |     ^^^^^^^^^^^^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

warning: unused import: `run_make_support::rfs::remove_file`
 --> /home/jyn/src/rust2/tests/run-make/linker-warning/rmake.rs:3:5
  |
3 | use run_make_support::rfs::remove_file;
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

warning: 2 warnings emitted

------------------------------------------
test [run-make] tests/run-make/linker-warning ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 377 filtered out; finished in 285.89ms
```

After:

```
Testing stage1 compiletest suite=run-make mode=run-make (x86_64-unknown-linux-gnu)

running 1 tests
------rmake stdout------------------------------

------rmake stderr------------------------------
assert_contains_regex:
=== HAYSTACK ===
error: linking with `./fake-linker` failed: exit status: 1
  |
  = note: LC_ALL="C" PATH="/home/jyn/src/rust2/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/bin:...:/bin" VSLANG="1033" "./fake-linker" "-m64" "/tmp/rustcYqdAZT/symbols.o" "main.main.d17f5fbe6225cf88-cgu.0.rcgu.o" "main.2uoctswmurc6ir5rvoay0p9ke.rcgu.o" "-Wl,--as-needed" "-Wl,-Bstatic" "-Wl,-Bdynamic" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-B/home/jyn/src/rust2/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/bin/gcc-ld" "-fuse-ld=lld" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/home/jyn/src/rust2/build/x86_64-unknown-linux-gnu/test/run-make/linker-warning/rmake_out" "-L" "/home/jyn/src/rust2/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "main" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs" "run_make_error"
  = note: error: baz

error: aborting due to 1 previous error

=== NEEDLE ===
fake-linker.*run_make_error
assert_not_contains_regex:
=== HAYSTACK ===

=== NEEDLE ===
fake-linker.*run_make_error

------------------------------------------
.

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 377 filtered out; finished in 314.81ms
```

r? `@jieyouxu`
  • Loading branch information
rust-timer authored Dec 15, 2024
2 parents d185062 + 056eb75 commit 7085015
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 56 deletions.
53 changes: 38 additions & 15 deletions src/tools/compiletest/src/runtest.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::ffi::OsString;
use std::ffi::{OsStr, OsString};
use std::fs::{self, File, create_dir_all};
use std::hash::{DefaultHasher, Hash, Hasher};
use std::io::prelude::*;
Expand Down Expand Up @@ -410,7 +410,12 @@ impl<'test> TestCx<'test> {
truncated: Truncated::No,
cmdline: format!("{cmd:?}"),
};
self.dump_output(&proc_res.stdout, &proc_res.stderr);
self.dump_output(
self.config.verbose,
&cmd.get_program().to_string_lossy(),
&proc_res.stdout,
&proc_res.stderr,
);

proc_res
}
Expand Down Expand Up @@ -1401,7 +1406,12 @@ impl<'test> TestCx<'test> {
cmdline,
};

self.dump_output(&result.stdout, &result.stderr);
self.dump_output(
self.config.verbose,
&command.get_program().to_string_lossy(),
&result.stdout,
&result.stderr,
);

result
}
Expand Down Expand Up @@ -1816,12 +1826,35 @@ impl<'test> TestCx<'test> {
}
}

fn dump_output(&self, out: &str, err: &str) {
fn dump_output(&self, print_output: bool, proc_name: &str, out: &str, err: &str) {
let revision = if let Some(r) = self.revision { format!("{}.", r) } else { String::new() };

self.dump_output_file(out, &format!("{}out", revision));
self.dump_output_file(err, &format!("{}err", revision));
self.maybe_dump_to_stdout(out, err);

if !print_output {
return;
}

let path = Path::new(proc_name);
let proc_name = if path.file_stem().is_some_and(|p| p == "rmake") {
OsString::from_iter(
path.parent()
.unwrap()
.file_name()
.into_iter()
.chain(Some(OsStr::new("/")))
.chain(path.file_name()),
)
} else {
path.file_name().unwrap().into()
};
let proc_name = proc_name.to_string_lossy();
println!("------{proc_name} stdout------------------------------");
println!("{}", out);
println!("------{proc_name} stderr------------------------------");
println!("{}", err);
println!("------------------------------------------");
}

fn dump_output_file(&self, out: &str, extension: &str) {
Expand Down Expand Up @@ -1874,16 +1907,6 @@ impl<'test> TestCx<'test> {
output_base_name(self.config, self.testpaths, self.safe_revision())
}

fn maybe_dump_to_stdout(&self, out: &str, err: &str) {
if self.config.verbose {
println!("------stdout------------------------------");
println!("{}", out);
println!("------stderr------------------------------");
println!("{}", err);
println!("------------------------------------------");
}
}

fn error(&self, err: &str) {
match self.revision {
Some(rev) => println!("\nerror in revision `{}`: {}", rev, err),
Expand Down
13 changes: 6 additions & 7 deletions src/tools/compiletest/src/runtest/run_make.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,14 +517,13 @@ impl TestCx<'_> {

let proc = disable_error_reporting(|| cmd.spawn().expect("failed to spawn `rmake`"));
let (Output { stdout, stderr, status }, truncated) = self.read2_abbreviated(proc);
let stdout = String::from_utf8_lossy(&stdout).into_owned();
let stderr = String::from_utf8_lossy(&stderr).into_owned();
// This conditions on `status.success()` so we don't print output twice on error.
// NOTE: this code is called from a libtest thread, so it's hidden by default unless --nocapture is passed.
self.dump_output(status.success(), &cmd.get_program().to_string_lossy(), &stdout, &stderr);
if !status.success() {
let res = ProcRes {
status,
stdout: String::from_utf8_lossy(&stdout).into_owned(),
stderr: String::from_utf8_lossy(&stderr).into_owned(),
truncated,
cmdline: format!("{:?}", cmd),
};
let res = ProcRes { status, stdout, stderr, truncated, cmdline: format!("{:?}", cmd) };
self.fatal_proc_rec("rmake recipe failed to complete", &res);
}
}
Expand Down
58 changes: 24 additions & 34 deletions src/tools/run-make-support/src/assertion_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,88 +5,78 @@ use std::path::Path;

use crate::{fs, regex};

fn print<'a, 'e, A: AsRef<str>, E: AsRef<str>>(
assertion_kind: &str,
haystack: &'a A,
needle: &'e E,
) -> (&'a str, &'e str) {
let haystack = haystack.as_ref();
let needle = needle.as_ref();
eprintln!("{assertion_kind}:");
eprintln!("=== HAYSTACK ===");
eprintln!("{}", haystack);
eprintln!("=== NEEDLE ===");
eprintln!("{}", needle);
(haystack, needle)
}

/// Assert that `actual` is equal to `expected`.
#[track_caller]
pub fn assert_equals<A: AsRef<str>, E: AsRef<str>>(actual: A, expected: E) {
let actual = actual.as_ref();
let expected = expected.as_ref();
eprintln!("=== ACTUAL TEXT ===");
eprintln!("{}", actual);
eprintln!("=== EXPECTED ===");
eprintln!("{}", expected);
if actual != expected {
eprintln!("=== ACTUAL TEXT ===");
eprintln!("{}", actual);
eprintln!("=== EXPECTED ===");
eprintln!("{}", expected);
panic!("expected text was not found in actual text");
}
}

/// Assert that `haystack` contains `needle`.
#[track_caller]
pub fn assert_contains<H: AsRef<str>, N: AsRef<str>>(haystack: H, needle: N) {
let haystack = haystack.as_ref();
let needle = needle.as_ref();
let (haystack, needle) = print("assert_contains", &haystack, &needle);
if !haystack.contains(needle) {
eprintln!("=== HAYSTACK ===");
eprintln!("{}", haystack);
eprintln!("=== NEEDLE ===");
eprintln!("{}", needle);
panic!("needle was not found in haystack");
}
}

/// Assert that `haystack` does not contain `needle`.
#[track_caller]
pub fn assert_not_contains<H: AsRef<str>, N: AsRef<str>>(haystack: H, needle: N) {
let haystack = haystack.as_ref();
let needle = needle.as_ref();
let (haystack, needle) = print("assert_not_contains", &haystack, &needle);
if haystack.contains(needle) {
eprintln!("=== HAYSTACK ===");
eprintln!("{}", haystack);
eprintln!("=== NEEDLE ===");
eprintln!("{}", needle);
panic!("needle was unexpectedly found in haystack");
}
}

/// Assert that `haystack` contains the regex pattern `needle`.
#[track_caller]
pub fn assert_contains_regex<H: AsRef<str>, N: AsRef<str>>(haystack: H, needle: N) {
let haystack = haystack.as_ref();
let needle = needle.as_ref();
let (haystack, needle) = print("assert_contains_regex", &haystack, &needle);
let re = regex::Regex::new(needle).unwrap();
if !re.is_match(haystack) {
eprintln!("=== HAYSTACK ===");
eprintln!("{}", haystack);
eprintln!("=== NEEDLE ===");
eprintln!("{}", needle);
panic!("needle was not found in haystack");
}
}

/// Assert that `haystack` does not contain the regex pattern `needle`.
#[track_caller]
pub fn assert_not_contains_regex<H: AsRef<str>, N: AsRef<str>>(haystack: H, needle: N) {
let haystack = haystack.as_ref();
let needle = needle.as_ref();
let (haystack, needle) = print("assert_not_contains_regex", &haystack, &needle);
let re = regex::Regex::new(needle).unwrap();
if re.is_match(haystack) {
eprintln!("=== HAYSTACK ===");
eprintln!("{}", haystack);
eprintln!("=== NEEDLE ===");
eprintln!("{}", needle);
panic!("needle was unexpectedly found in haystack");
}
}

/// Assert that `haystack` contains `needle` a `count` number of times.
#[track_caller]
pub fn assert_count_is<H: AsRef<str>, N: AsRef<str>>(count: usize, haystack: H, needle: N) {
let haystack = haystack.as_ref();
let needle = needle.as_ref();
let (haystack, needle) = print("assert_count_is", &haystack, &needle);
if count != haystack.matches(needle).count() {
eprintln!("=== HAYSTACK ===");
eprintln!("{}", haystack);
eprintln!("=== NEEDLE ===");
eprintln!("{}", needle);
panic!("needle did not appear {count} times in haystack");
}
}
Expand Down

0 comments on commit 7085015

Please sign in to comment.