Skip to content

Commit c31a4b9

Browse files
authored
Rollup merge of #135097 - Zalathar:coverage-test-step, r=Kobzol
bootstrap: Consolidate coverage test suite steps into a single step Now that I have more understanding of bootstrap steps, and a renewed distaste for unnecessary macros, I have managed to express the subtleties of the `tests/coverage` test suite in a single step defined in ordinary code, with no need for helper macros. Deciding which modes to run is still a bit clunky due to limitations in existing ShouldRun/PathSet APIs, but I think it's a net improvement over having to declare several different steps to handle the suite path and aliases. The interaction with `--skip` isn't as nice as I'd like, but all of the known limitations are limitations that already existed in the previous implementation. One minor change is that by default compiletest is now invoked in `coverage-run` mode even when cross-compiling. However, in that situation compiletest still knows that it should skip all of the individual coverage-run tests. r? jieyouxu (or reassign)
2 parents 68791ef + 5298f85 commit c31a4b9

File tree

3 files changed

+101
-120
lines changed

3 files changed

+101
-120
lines changed

src/bootstrap/src/core/build_steps/test.rs

+68-118
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use crate::utils::helpers::{
2727
linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date,
2828
};
2929
use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests};
30-
use crate::{CLang, DocTests, GitRepo, Mode, envify};
30+
use crate::{CLang, DocTests, GitRepo, Mode, PathSet, envify};
3131

3232
const ADB_TEST_DIR: &str = "/data/local/tmp/work";
3333

@@ -1185,53 +1185,6 @@ macro_rules! test {
11851185
};
11861186
}
11871187

1188-
/// Declares an alias for running the [`Coverage`] tests in only one mode.
1189-
/// Adapted from [`test`].
1190-
macro_rules! coverage_test_alias {
1191-
(
1192-
$( #[$attr:meta] )* // allow docstrings and attributes
1193-
$name:ident {
1194-
alias_and_mode: $alias_and_mode:expr, // &'static str
1195-
default: $default:expr, // bool
1196-
only_hosts: $only_hosts:expr // bool
1197-
$( , )? // optional trailing comma
1198-
}
1199-
) => {
1200-
$( #[$attr] )*
1201-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1202-
pub struct $name {
1203-
pub compiler: Compiler,
1204-
pub target: TargetSelection,
1205-
}
1206-
1207-
impl $name {
1208-
const MODE: &'static str = $alias_and_mode;
1209-
}
1210-
1211-
impl Step for $name {
1212-
type Output = ();
1213-
const DEFAULT: bool = $default;
1214-
const ONLY_HOSTS: bool = $only_hosts;
1215-
1216-
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1217-
// Register the mode name as a command-line alias.
1218-
// This allows `x test coverage-map` and `x test coverage-run`.
1219-
run.alias($alias_and_mode)
1220-
}
1221-
1222-
fn make_run(run: RunConfig<'_>) {
1223-
let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1224-
1225-
run.builder.ensure($name { compiler, target: run.target });
1226-
}
1227-
1228-
fn run(self, builder: &Builder<'_>) {
1229-
Coverage::run_coverage_tests(builder, self.compiler, self.target, Self::MODE);
1230-
}
1231-
}
1232-
};
1233-
}
1234-
12351188
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)]
12361189
pub struct RunMakeSupport {
12371190
pub compiler: Compiler,
@@ -1473,99 +1426,96 @@ impl Step for RunMake {
14731426

14741427
test!(Assembly { path: "tests/assembly", mode: "assembly", suite: "assembly", default: true });
14751428

1476-
/// Coverage tests are a bit more complicated than other test suites, because
1477-
/// we want to run the same set of test files in multiple different modes,
1478-
/// in a way that's convenient and flexible when invoked manually.
1479-
///
1480-
/// This combined step runs the specified tests (or all of `tests/coverage`)
1481-
/// in both "coverage-map" and "coverage-run" modes.
1482-
///
1483-
/// Used by:
1484-
/// - `x test coverage`
1485-
/// - `x test tests/coverage`
1486-
/// - `x test tests/coverage/trivial.rs` (etc)
1487-
///
1488-
/// (Each individual mode also has its own step that will run the tests in
1489-
/// just that mode.)
1490-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1429+
/// Runs the coverage test suite at `tests/coverage` in some or all of the
1430+
/// coverage test modes.
1431+
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
14911432
pub struct Coverage {
14921433
pub compiler: Compiler,
14931434
pub target: TargetSelection,
1435+
pub mode: &'static str,
14941436
}
14951437

14961438
impl Coverage {
14971439
const PATH: &'static str = "tests/coverage";
14981440
const SUITE: &'static str = "coverage";
1499-
1500-
/// Runs the coverage test suite (or a user-specified subset) in one mode.
1501-
///
1502-
/// This same function is used by the multi-mode step ([`Coverage`]) and by
1503-
/// the single-mode steps ([`CoverageMap`] and [`CoverageRun`]), to help
1504-
/// ensure that they all behave consistently with each other, regardless of
1505-
/// how the coverage tests have been invoked.
1506-
fn run_coverage_tests(
1507-
builder: &Builder<'_>,
1508-
compiler: Compiler,
1509-
target: TargetSelection,
1510-
mode: &'static str,
1511-
) {
1512-
// Like many other test steps, we delegate to a `Compiletest` step to
1513-
// actually run the tests. (See `test_definitions!`.)
1514-
builder.ensure(Compiletest {
1515-
compiler,
1516-
target,
1517-
mode,
1518-
suite: Self::SUITE,
1519-
path: Self::PATH,
1520-
compare_mode: None,
1521-
});
1522-
}
1441+
const ALL_MODES: &[&str] = &["coverage-map", "coverage-run"];
15231442
}
15241443

15251444
impl Step for Coverage {
15261445
type Output = ();
1527-
/// We rely on the individual CoverageMap/CoverageRun steps to run themselves.
1528-
const DEFAULT: bool = false;
1529-
/// When manually invoked, try to run as much as possible.
1446+
const DEFAULT: bool = true;
15301447
/// Compiletest will automatically skip the "coverage-run" tests if necessary.
15311448
const ONLY_HOSTS: bool = false;
15321449

1533-
fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
1534-
// Take responsibility for command-line paths within `tests/coverage`.
1535-
run.suite_path(Self::PATH)
1450+
fn should_run(mut run: ShouldRun<'_>) -> ShouldRun<'_> {
1451+
// Support various invocation styles, including:
1452+
// - `./x test coverage`
1453+
// - `./x test tests/coverage/trivial.rs`
1454+
// - `./x test coverage-map`
1455+
// - `./x test coverage-run -- tests/coverage/trivial.rs`
1456+
run = run.suite_path(Self::PATH);
1457+
for mode in Self::ALL_MODES {
1458+
run = run.alias(mode);
1459+
}
1460+
run
15361461
}
15371462

15381463
fn make_run(run: RunConfig<'_>) {
15391464
let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple());
1465+
let target = run.target;
1466+
1467+
// List of (coverage) test modes that the coverage test suite will be
1468+
// run in. It's OK for this to contain duplicates, because the call to
1469+
// `Builder::ensure` below will take care of deduplication.
1470+
let mut modes = vec![];
1471+
1472+
// From the pathsets that were selected on the command-line (or by default),
1473+
// determine which modes to run in.
1474+
for path in &run.paths {
1475+
match path {
1476+
PathSet::Set(_) => {
1477+
for mode in Self::ALL_MODES {
1478+
if path.assert_single_path().path == Path::new(mode) {
1479+
modes.push(mode);
1480+
break;
1481+
}
1482+
}
1483+
}
1484+
PathSet::Suite(_) => {
1485+
modes.extend(Self::ALL_MODES);
1486+
break;
1487+
}
1488+
}
1489+
}
1490+
1491+
// Skip any modes that were explicitly skipped/excluded on the command-line.
1492+
// FIXME(Zalathar): Integrate this into central skip handling somehow?
1493+
modes.retain(|mode| !run.builder.config.skip.iter().any(|skip| skip == Path::new(mode)));
1494+
1495+
// FIXME(Zalathar): Make these commands skip all coverage tests, as expected:
1496+
// - `./x test --skip=tests`
1497+
// - `./x test --skip=tests/coverage`
1498+
// - `./x test --skip=coverage`
1499+
// Skip handling currently doesn't have a way to know that skipping the coverage
1500+
// suite should also skip the `coverage-map` and `coverage-run` aliases.
15401501

1541-
run.builder.ensure(Coverage { compiler, target: run.target });
1502+
for mode in modes {
1503+
run.builder.ensure(Coverage { compiler, target, mode });
1504+
}
15421505
}
15431506

15441507
fn run(self, builder: &Builder<'_>) {
1545-
// Run the specified coverage tests (possibly all of them) in both modes.
1546-
Self::run_coverage_tests(builder, self.compiler, self.target, CoverageMap::MODE);
1547-
Self::run_coverage_tests(builder, self.compiler, self.target, CoverageRun::MODE);
1548-
}
1549-
}
1550-
1551-
coverage_test_alias! {
1552-
/// Runs the `tests/coverage` test suite in "coverage-map" mode only.
1553-
/// Used by `x test` and `x test coverage-map`.
1554-
CoverageMap {
1555-
alias_and_mode: "coverage-map",
1556-
default: true,
1557-
only_hosts: false,
1558-
}
1559-
}
1560-
coverage_test_alias! {
1561-
/// Runs the `tests/coverage` test suite in "coverage-run" mode only.
1562-
/// Used by `x test` and `x test coverage-run`.
1563-
CoverageRun {
1564-
alias_and_mode: "coverage-run",
1565-
default: true,
1566-
// Compiletest knows how to automatically skip these tests when cross-compiling,
1567-
// but skipping the whole step here makes it clearer that they haven't run at all.
1568-
only_hosts: true,
1508+
let Self { compiler, target, mode } = self;
1509+
// Like other compiletest suite test steps, delegate to an internal
1510+
// compiletest task to actually run the tests.
1511+
builder.ensure(Compiletest {
1512+
compiler,
1513+
target,
1514+
mode,
1515+
suite: Self::SUITE,
1516+
path: Self::PATH,
1517+
compare_mode: None,
1518+
});
15691519
}
15701520
}
15711521

src/bootstrap/src/core/builder/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -944,8 +944,6 @@ impl<'a> Builder<'a> {
944944
test::Ui,
945945
test::Crashes,
946946
test::Coverage,
947-
test::CoverageMap,
948-
test::CoverageRun,
949947
test::MirOpt,
950948
test::Codegen,
951949
test::CodegenUnits,

src/bootstrap/src/core/builder/tests.rs

+33
Original file line numberDiff line numberDiff line change
@@ -828,3 +828,36 @@ fn test_test_compiler() {
828828

829829
assert_eq!((compiler, cranelift, gcc), (true, false, false));
830830
}
831+
832+
#[test]
833+
fn test_test_coverage() {
834+
struct Case {
835+
cmd: &'static [&'static str],
836+
expected: &'static [&'static str],
837+
}
838+
let cases = &[
839+
Case { cmd: &["test"], expected: &["coverage-map", "coverage-run"] },
840+
Case { cmd: &["test", "coverage"], expected: &["coverage-map", "coverage-run"] },
841+
Case { cmd: &["test", "coverage-map"], expected: &["coverage-map"] },
842+
Case { cmd: &["test", "coverage-run"], expected: &["coverage-run"] },
843+
Case { cmd: &["test", "coverage", "--skip=coverage"], expected: &[] },
844+
Case { cmd: &["test", "coverage", "--skip=tests/coverage"], expected: &[] },
845+
Case { cmd: &["test", "coverage", "--skip=coverage-map"], expected: &["coverage-run"] },
846+
Case { cmd: &["test", "coverage", "--skip=coverage-run"], expected: &["coverage-map"] },
847+
Case { cmd: &["test", "--skip=coverage-map", "--skip=coverage-run"], expected: &[] },
848+
Case { cmd: &["test", "coverage", "--skip=tests"], expected: &[] },
849+
];
850+
851+
for &Case { cmd, expected } in cases {
852+
// Print each test case so that if one fails, the most recently printed
853+
// case is the one that failed.
854+
println!("Testing case: {cmd:?}");
855+
let cmd = cmd.iter().copied().map(str::to_owned).collect::<Vec<_>>();
856+
let config = configure_with_args(&cmd, &[TEST_TRIPLE_1], &[TEST_TRIPLE_1]);
857+
let mut cache = run_build(&config.paths.clone(), config);
858+
859+
let modes =
860+
cache.all::<test::Coverage>().iter().map(|(step, ())| step.mode).collect::<Vec<_>>();
861+
assert_eq!(modes, expected);
862+
}
863+
}

0 commit comments

Comments
 (0)