Skip to content

Commit 75c7b07

Browse files
committed
[cargo-nextest] fix --exact semantics
`--exact` is actually a global option, not one that takes a pattern as an argument.
1 parent 513951b commit 75c7b07

File tree

2 files changed

+52
-18
lines changed

2 files changed

+52
-18
lines changed

cargo-nextest/src/dispatch.rs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ struct TestBuildFilter {
600600
/// - --ignored: Only run ignored tests{n}
601601
/// - --include-ignored: Run both ignored and non-ignored tests{n}
602602
/// - --skip PATTERN: Skip tests that match the pattern{n}
603-
/// - --exact PATTERN: Only run tests that exactly match the pattern
603+
/// - --exact: Run tests that exactly match patterns after `--`
604604
#[arg(help_heading = None, value_name = "FILTERS_AND_ARGS", last = true)]
605605
filters: Vec<String>,
606606
}
@@ -670,6 +670,24 @@ impl TestBuildFilter {
670670
run_ignored: &mut Option<RunIgnored>,
671671
patterns: &mut TestFilterPatterns,
672672
) -> Result<()> {
673+
// First scan to see if `--exact` is specified. If so, then everything here will be added to
674+
// `--exact`.
675+
let mut is_exact = false;
676+
for arg in &self.filters {
677+
if arg == "--" {
678+
break;
679+
}
680+
if arg == "--exact" {
681+
if is_exact {
682+
return Err(ExpectedError::test_binary_args_parse_error(
683+
"duplicated",
684+
vec![arg.clone()],
685+
));
686+
}
687+
is_exact = true;
688+
}
689+
}
690+
673691
let mut ignore_filters = Vec::new();
674692
let mut read_trailing_filters = false;
675693

@@ -678,7 +696,11 @@ impl TestBuildFilter {
678696
let mut it = self.filters.iter();
679697
while let Some(arg) = it.next() {
680698
if read_trailing_filters || !arg.starts_with('-') {
681-
patterns.add_substring_pattern(arg.clone());
699+
if is_exact {
700+
patterns.add_exact_pattern(arg.clone());
701+
} else {
702+
patterns.add_substring_pattern(arg.clone());
703+
}
682704
} else if arg == "--include-ignored" {
683705
ignore_filters.push((arg.clone(), RunIgnored::All));
684706
} else if arg == "--ignored" {
@@ -695,14 +717,7 @@ impl TestBuildFilter {
695717

696718
patterns.add_skip_pattern(skip_arg.clone());
697719
} else if arg == "--exact" {
698-
let exact_arg = it.next().ok_or_else(|| {
699-
ExpectedError::test_binary_args_parse_error(
700-
"missing required argument",
701-
vec![arg.clone()],
702-
)
703-
})?;
704-
705-
patterns.add_exact_pattern(exact_arg.clone());
720+
// Already handled above.
706721
} else {
707722
unsupported_args.push(arg.clone());
708723
}
@@ -2605,13 +2620,13 @@ mod tests {
26052620
// skip and exact
26062621
// ---
26072622
(
2608-
"foo -- --skip my-pattern --skip your-pattern --exact exact1 pattern2",
2623+
"foo -- --skip my-pattern --skip your-pattern exact1 --exact pattern2",
26092624
{
26102625
let mut patterns = TestFilterPatterns::default();
26112626
patterns.add_skip_pattern("my-pattern".to_owned());
26122627
patterns.add_skip_pattern("your-pattern".to_owned());
26132628
patterns.add_exact_pattern("exact1".to_owned());
2614-
patterns.add_substring_pattern("pattern2".to_owned());
2629+
patterns.add_exact_pattern("pattern2".to_owned());
26152630
patterns
26162631
},
26172632
),
@@ -2622,6 +2637,7 @@ mod tests {
26222637
// ---
26232638
("foo -- --include-ignored --include-ignored", "duplicated"),
26242639
("foo -- --ignored --ignored", "duplicated"),
2640+
("foo -- --exact --exact", "duplicated"),
26252641
// ---
26262642
// mutually exclusive
26272643
// ---
@@ -2631,7 +2647,6 @@ mod tests {
26312647
// missing required argument
26322648
// ---
26332649
("foo -- --skip", "missing required argument"),
2634-
("foo -- --exact", "missing required argument"),
26352650
// ---
26362651
// unsupported
26372652
// ---

integration-tests/tests/integration/main.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,27 @@ fn test_run() {
396396
);
397397
check_run_output(&output.stderr, 0);
398398

399+
// --exact with nothing else should be the same as above.
400+
let output = CargoNextestCli::new()
401+
.args([
402+
"--manifest-path",
403+
p.manifest_path().as_str(),
404+
"run",
405+
"--workspace",
406+
"--all-targets",
407+
"--",
408+
"--exact",
409+
])
410+
.unchecked(true)
411+
.output();
412+
413+
assert_eq!(
414+
output.exit_status.code(),
415+
Some(NextestExitCode::TEST_RUN_FAILED),
416+
"correct exit code for command\n{output}"
417+
);
418+
check_run_output(&output.stderr, 0);
419+
399420
// Check the output with --skip.
400421
let output = CargoNextestCli::new()
401422
.args([
@@ -446,7 +467,6 @@ fn test_run() {
446467
"--workspace",
447468
"--all-targets",
448469
"--",
449-
"--exact",
450470
"test_multiply_two",
451471
"--exact",
452472
"tests::test_multiply_two_cdylib",
@@ -485,14 +505,14 @@ fn test_run() {
485505
"--workspace",
486506
"--all-targets",
487507
"--",
488-
"--exact",
489508
"test_multiply_two",
509+
// Note the position of --exact doesn't matter.
490510
"--exact",
491511
"tests::test_multiply_two_cdylib",
492512
"--skip",
493513
"cdylib",
494514
])
495-
// This should only select the test_multiply_two test, which passes. So don't pass in
515+
// This should only select the two test_multiply_two tests, which pass. So don't pass in
496516
// unchecked(true) here.
497517
.output();
498518
check_run_output(
@@ -552,12 +572,11 @@ fn test_run() {
552572
"-E",
553573
"not test(cdylib)",
554574
"--",
555-
"--exact",
556575
"test_multiply_two",
557576
"--exact",
558577
"tests::test_multiply_two_cdylib",
559578
])
560-
// This should only select the test_multiply_two test, which passes. So don't pass in
579+
// This should only select the two test_multiply_two tests, which pass. So don't pass in
561580
// unchecked(true) here.
562581
.output();
563582
check_run_output(

0 commit comments

Comments
 (0)