From 86e81f9926ad52b79397d037cf6e0392fb6f0db2 Mon Sep 17 00:00:00 2001 From: jaisnan Date: Wed, 14 Jun 2023 20:17:12 +0000 Subject: [PATCH 1/9] Add --exact flag --- kani-driver/src/args/mod.rs | 4 + kani-driver/src/metadata.rs | 90 ++++++++++++++++--- .../check-qualified-name/expected | 2 + .../select_harness_with_module.rs | 22 +++++ tests/ui/exact-harness/check_some/expected | 3 + .../check_some/select_harnesses.rs | 19 ++++ .../incomplete-harness-name/expected | 1 + .../incomplete_harness.rs | 22 +++++ .../exact-harness/multiple_matches/expected | 3 + .../select_multiple_harnesses.rs | 39 ++++++++ .../some_matching_harnesses/expected | 2 + .../some_matching_harnesses/subset.rs | 39 ++++++++ 12 files changed, 233 insertions(+), 13 deletions(-) create mode 100644 tests/ui/exact-harness/check-qualified-name/expected create mode 100644 tests/ui/exact-harness/check-qualified-name/select_harness_with_module.rs create mode 100644 tests/ui/exact-harness/check_some/expected create mode 100644 tests/ui/exact-harness/check_some/select_harnesses.rs create mode 100644 tests/ui/exact-harness/incomplete-harness-name/expected create mode 100644 tests/ui/exact-harness/incomplete-harness-name/incomplete_harness.rs create mode 100644 tests/ui/exact-harness/multiple_matches/expected create mode 100644 tests/ui/exact-harness/multiple_matches/select_multiple_harnesses.rs create mode 100644 tests/ui/exact-harness/some_matching_harnesses/expected create mode 100644 tests/ui/exact-harness/some_matching_harnesses/subset.rs diff --git a/kani-driver/src/args/mod.rs b/kani-driver/src/args/mod.rs index dbc80fedbb99..97cd33dc8f69 100644 --- a/kani-driver/src/args/mod.rs +++ b/kani-driver/src/args/mod.rs @@ -177,6 +177,10 @@ pub struct VerificationArgs { )] pub harnesses: Vec, + /// If specified, with the fully qualified name of the harness provided, runs that specific harness and nothing more + #[arg(long, requires("harnesses"))] + pub exact: bool, + /// Link external C files referenced by Rust code. /// This is an experimental feature and requires `-Z c-ffi` to be used #[arg(long, hide = true, num_args(1..))] diff --git a/kani-driver/src/metadata.rs b/kani-driver/src/metadata.rs index 613129d8188c..54dea2e55d51 100644 --- a/kani-driver/src/metadata.rs +++ b/kani-driver/src/metadata.rs @@ -124,7 +124,8 @@ impl KaniSession { if harnesses.is_empty() { Ok(Vec::from(all_harnesses)) } else { - let harnesses = find_proof_harnesses(harnesses, all_harnesses); + let harnesses: Vec<&HarnessMetadata> = + find_proof_harnesses(harnesses, all_harnesses, self.args.exact); Ok(harnesses) } } @@ -169,18 +170,29 @@ pub fn mock_proof_harness( fn find_proof_harnesses<'a>( targets: BTreeSet<&String>, all_harnesses: &[&'a HarnessMetadata], + exact_filter: bool, ) -> Vec<&'a HarnessMetadata> { debug!(?targets, "find_proof_harness"); let mut result = vec![]; for md in all_harnesses.iter() { - // Either an exact match, or a substring match. We check the exact first since it's cheaper. - if targets.contains(&md.pretty_name) - || targets.contains(&md.get_harness_name_unqualified().to_string()) - || targets.iter().any(|target| md.pretty_name.contains(*target)) - { - result.push(*md); + // Check for exact match only + if exact_filter { + if targets.contains(&md.pretty_name) { + // if exact match found, stop searching + result.push(*md); + } else { + trace!(skip = md.pretty_name, "find_proof_harnesses"); + } } else { - trace!(skip = md.pretty_name, "find_proof_harnesses"); + // Either an exact match, or a substring match. We check the exact first since it's cheaper. + if targets.contains(&md.pretty_name) + || targets.contains(&md.get_harness_name_unqualified().to_string()) + || targets.iter().any(|target| md.pretty_name.contains(*target)) + { + result.push(*md); + } else { + trace!(skip = md.pretty_name, "find_proof_harnesses"); + } } } result @@ -191,31 +203,83 @@ mod tests { use super::*; #[test] - fn check_find_proof_harness() { + fn check_find_proof_harness_without_exact() { let harnesses = vec![ mock_proof_harness("check_one", None, None, None), mock_proof_harness("module::check_two", None, None, None), mock_proof_harness("module::not_check_three", None, None, None), ]; let ref_harnesses = harnesses.iter().collect::>(); + + // Check with harness filtering assert_eq!( - find_proof_harnesses(BTreeSet::from([&"check_three".to_string()]), &ref_harnesses) - .len(), + find_proof_harnesses( + BTreeSet::from([&"check_three".to_string()]), + &ref_harnesses, + false + ) + .len(), 1 ); assert!( - find_proof_harnesses(BTreeSet::from([&"check_two".to_string()]), &ref_harnesses) + find_proof_harnesses(BTreeSet::from([&"check_two".to_string()]), &ref_harnesses, false) .first() .unwrap() .mangled_name == "module::check_two" ); assert!( - find_proof_harnesses(BTreeSet::from([&"check_one".to_string()]), &ref_harnesses) + find_proof_harnesses(BTreeSet::from([&"check_one".to_string()]), &ref_harnesses, false) .first() .unwrap() .mangled_name == "check_one" ); + + // Check with exact match + assert_eq!( + find_proof_harnesses( + BTreeSet::from([&"check_three".to_string()]), + &ref_harnesses, + true + ) + .len(), + 0 + ); + assert_eq!( + find_proof_harnesses(BTreeSet::from([&"check_two".to_string()]), &ref_harnesses, true) + .first() + .is_none(), + true + ); + assert_eq!( + find_proof_harnesses(BTreeSet::from([&"check_one".to_string()]), &ref_harnesses, true) + .first() + .unwrap() + .mangled_name, + "check_one" + ); + assert_ne!( + find_proof_harnesses( + BTreeSet::from([&"module::not_check_three".to_string()]), + &ref_harnesses, + true + ) + .first() + .unwrap() + .mangled_name, + "not_check_three" + ); + assert_eq!( + find_proof_harnesses( + BTreeSet::from([&"module::not_check_three".to_string()]), + &ref_harnesses, + true + ) + .first() + .unwrap() + .mangled_name, + "module::not_check_three" + ); } } diff --git a/tests/ui/exact-harness/check-qualified-name/expected b/tests/ui/exact-harness/check-qualified-name/expected new file mode 100644 index 000000000000..f8295f7a0c73 --- /dev/null +++ b/tests/ui/exact-harness/check-qualified-name/expected @@ -0,0 +1,2 @@ +Checking harness first::check_foo... +VERIFICATION:- SUCCESSFUL diff --git a/tests/ui/exact-harness/check-qualified-name/select_harness_with_module.rs b/tests/ui/exact-harness/check-qualified-name/select_harness_with_module.rs new file mode 100644 index 000000000000..981472f67a9c --- /dev/null +++ b/tests/ui/exact-harness/check-qualified-name/select_harness_with_module.rs @@ -0,0 +1,22 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT +// kani-flags: --harness first::check_foo --exact +//! Ensure that the set of harnesses run is the union of all arguments. + +mod first { + #[kani::proof] + fn check_foo() { + assert!(1 == 1); + } + + #[kani::proof] + fn check_blah() { + assert!(2 == 2); + } + + /// A harness that will fail verification if it is run. + #[kani::proof] + fn ignore_third_harness() { + assert!(3 == 2); + } +} diff --git a/tests/ui/exact-harness/check_some/expected b/tests/ui/exact-harness/check_some/expected new file mode 100644 index 000000000000..875c01a46612 --- /dev/null +++ b/tests/ui/exact-harness/check_some/expected @@ -0,0 +1,3 @@ +Checking harness check_second_harness... +Checking harness check_first_harness... +Complete - 2 successfully verified harnesses, 0 failures, 2 total. diff --git a/tests/ui/exact-harness/check_some/select_harnesses.rs b/tests/ui/exact-harness/check_some/select_harnesses.rs new file mode 100644 index 000000000000..0ac125fde552 --- /dev/null +++ b/tests/ui/exact-harness/check_some/select_harnesses.rs @@ -0,0 +1,19 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT +// kani-flags: --harness check_first_harness --harness check_second_harness --exact +//! Ensure that we can select multiple harnesses at a time. +#[kani::proof] +fn check_first_harness() { + assert!(1 == 1); +} + +#[kani::proof] +fn check_second_harness() { + assert!(2 == 2); +} + +/// A harness that will fail verification if it is run. +#[kani::proof] +fn ignore_third_harness() { + assert!(3 == 2); +} diff --git a/tests/ui/exact-harness/incomplete-harness-name/expected b/tests/ui/exact-harness/incomplete-harness-name/expected new file mode 100644 index 000000000000..8cf6d54f0a28 --- /dev/null +++ b/tests/ui/exact-harness/incomplete-harness-name/expected @@ -0,0 +1 @@ +error: no harnesses matched the harness filter: `check_blah` diff --git a/tests/ui/exact-harness/incomplete-harness-name/incomplete_harness.rs b/tests/ui/exact-harness/incomplete-harness-name/incomplete_harness.rs new file mode 100644 index 000000000000..d73137d1f04f --- /dev/null +++ b/tests/ui/exact-harness/incomplete-harness-name/incomplete_harness.rs @@ -0,0 +1,22 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT +// kani-flags: --harness check_blah --exact +//! Check that we just ignore non-matching filters + +mod first { + #[kani::proof] + fn check_foo() { + assert!(1 == 1); + } + + #[kani::proof] + fn check_blah() { + assert!(2 == 2); + } + + /// A harness that will fail verification if it is run. + #[kani::proof] + fn ignore_third_harness() { + assert!(3 == 2); + } +} diff --git a/tests/ui/exact-harness/multiple_matches/expected b/tests/ui/exact-harness/multiple_matches/expected new file mode 100644 index 000000000000..8c2420d08c77 --- /dev/null +++ b/tests/ui/exact-harness/multiple_matches/expected @@ -0,0 +1,3 @@ +Checking harness second::verify_foo... +Checking harness first::check_blah... +Complete - 2 successfully verified harnesses, 0 failures, 2 total. diff --git a/tests/ui/exact-harness/multiple_matches/select_multiple_harnesses.rs b/tests/ui/exact-harness/multiple_matches/select_multiple_harnesses.rs new file mode 100644 index 000000000000..5a49072dce17 --- /dev/null +++ b/tests/ui/exact-harness/multiple_matches/select_multiple_harnesses.rs @@ -0,0 +1,39 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT +// kani-flags: --harness first::check_blah --exact --harness second::verify_foo +//! Ensure that the set of harnesses run is the union of all arguments. + +mod first { + #[kani::proof] + fn check_foo() { + assert!(1 == 1); + } + + #[kani::proof] + fn check_blah() { + assert!(2 == 2); + } + + /// A harness that will fail verification if it is run. + #[kani::proof] + fn ignore_third_harness() { + assert!(3 == 2); + } +} + +mod second { + #[kani::proof] + fn verify_foo() { + assert!(1 == 1); + } + + #[kani::proof] + fn verify_blah() { + assert!(2 == 2); + } + + #[kani::proof] + fn verify_harness() { + assert!(3 == 3); + } +} diff --git a/tests/ui/exact-harness/some_matching_harnesses/expected b/tests/ui/exact-harness/some_matching_harnesses/expected new file mode 100644 index 000000000000..e3401ff858c2 --- /dev/null +++ b/tests/ui/exact-harness/some_matching_harnesses/expected @@ -0,0 +1,2 @@ +Checking harness existing... +VERIFICATION:- SUCCESSFUL diff --git a/tests/ui/exact-harness/some_matching_harnesses/subset.rs b/tests/ui/exact-harness/some_matching_harnesses/subset.rs new file mode 100644 index 000000000000..7b7ed5358889 --- /dev/null +++ b/tests/ui/exact-harness/some_matching_harnesses/subset.rs @@ -0,0 +1,39 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT +// kani-flags: --harness existing --harness check_blah --exact +//! Check that we just ignore non-matching filters + +mod first { + #[kani::proof] + fn check_foo() { + assert!(1 == 1); + } + + #[kani::proof] + fn check_blah() { + assert!(2 == 2); + } + + /// A harness that will fail verification if it is run. + #[kani::proof] + fn ignore_third_harness() { + assert!(3 == 2); + } +} + +// This harness will be picked up +#[kani::proof] +fn existing() { + assert!(1 == 1); +} + +#[kani::proof] +fn existing_harness() { + assert!(2 == 2); +} + +/// A harness that will fail verification if it is run. +#[kani::proof] +fn ignored_harness() { + assert!(3 == 2); +} From 00a367fcb325dfd411204607c01034c0163e3b70 Mon Sep 17 00:00:00 2001 From: jaisnan Date: Thu, 15 Jun 2023 20:39:00 +0000 Subject: [PATCH 2/9] Add completion status to single harness, and address PR feedback --- kani-driver/src/args/mod.rs | 1 + kani-driver/src/harness_runner.rs | 22 ++++++++---- kani-driver/src/metadata.rs | 35 +++++++++---------- .../check_summary_for_single_harness/expected | 2 ++ .../single_harness.rs | 9 +++++ .../check-qualified-name/expected | 2 +- .../select_harness_with_module.rs | 2 +- .../check_substring_not_matching/expected | 2 ++ .../select_harness_with_module.rs | 23 ++++++++++++ .../incomplete-harness-name/expected | 2 +- .../select_multiple_harnesses.rs | 2 +- .../some_matching_harnesses/expected | 1 + .../some_matching_harnesses/subset.rs | 4 +-- 13 files changed, 76 insertions(+), 31 deletions(-) create mode 100644 tests/ui/check_summary_for_single_harness/expected create mode 100644 tests/ui/check_summary_for_single_harness/single_harness.rs create mode 100644 tests/ui/exact-harness/check_substring_not_matching/expected create mode 100644 tests/ui/exact-harness/check_substring_not_matching/select_harness_with_module.rs diff --git a/kani-driver/src/args/mod.rs b/kani-driver/src/args/mod.rs index 97cd33dc8f69..44a09197be5c 100644 --- a/kani-driver/src/args/mod.rs +++ b/kani-driver/src/args/mod.rs @@ -169,6 +169,7 @@ pub struct VerificationArgs { pub function: Option, /// If specified, only run harnesses that match this filter. This option can be provided /// multiple times, which will run all tests matching any of the filters. + /// If used with --exact, the filter is removed and only exact matches are run. #[arg( long = "harness", conflicts_with = "function", diff --git a/kani-driver/src/harness_runner.rs b/kani-driver/src/harness_runner.rs index f1f0befc4ddd..a5bd69e3390a 100644 --- a/kani-driver/src/harness_runner.rs +++ b/kani-driver/src/harness_runner.rs @@ -154,7 +154,7 @@ impl KaniSession { } // We currently omit a summary if there was just 1 harness - if !self.args.common_args.quiet && !self.args.visualize && total != 1 { + if !self.args.common_args.quiet && !self.args.visualize { if failing > 0 { println!("Summary:"); } @@ -177,12 +177,22 @@ impl KaniSession { ) } ([harness], None) => { - bail!("no harnesses matched the harness filter: `{harness}`") + if !self.args.exact { + bail!("no harnesses matched the harness filter: `{harness}`") + } else { + bail!("no harnesses matched the name: `{harness}`") + } + } + (harnesses, None) => { + if !self.args.exact { + bail!( + "no harnesses matched the harness filters: `{}`", + harnesses.join("`, `") + ) + } else { + bail!("no harnesses matched the names: `{}`", harnesses.join("`, `")) + } } - (harnesses, None) => bail!( - "no harnesses matched the harness filters: `{}`", - harnesses.join("`, `") - ), ([], Some(func)) => error(&format!("No function named {func} was found")), _ => unreachable!( "invalid configuration. Cannot specify harness and function at the same time" diff --git a/kani-driver/src/metadata.rs b/kani-driver/src/metadata.rs index 54dea2e55d51..8d9bc24ae226 100644 --- a/kani-driver/src/metadata.rs +++ b/kani-driver/src/metadata.rs @@ -175,8 +175,8 @@ fn find_proof_harnesses<'a>( debug!(?targets, "find_proof_harness"); let mut result = vec![]; for md in all_harnesses.iter() { - // Check for exact match only if exact_filter { + // Check for exact match only if targets.contains(&md.pretty_name) { // if exact match found, stop searching result.push(*md); @@ -235,22 +235,30 @@ mod tests { .mangled_name == "check_one" ); + } + #[test] + fn check_find_proof_harness_with_exact() { // Check with exact match - assert_eq!( + + let harnesses = vec![ + mock_proof_harness("check_one", None, None, None), + mock_proof_harness("module::check_two", None, None, None), + mock_proof_harness("module::not_check_three", None, None, None), + ]; + let ref_harnesses = harnesses.iter().collect::>(); + + assert!( find_proof_harnesses( BTreeSet::from([&"check_three".to_string()]), &ref_harnesses, true ) - .len(), - 0 + .is_empty() ); - assert_eq!( + assert!( find_proof_harnesses(BTreeSet::from([&"check_two".to_string()]), &ref_harnesses, true) - .first() - .is_none(), - true + .is_empty() ); assert_eq!( find_proof_harnesses(BTreeSet::from([&"check_one".to_string()]), &ref_harnesses, true) @@ -259,17 +267,6 @@ mod tests { .mangled_name, "check_one" ); - assert_ne!( - find_proof_harnesses( - BTreeSet::from([&"module::not_check_three".to_string()]), - &ref_harnesses, - true - ) - .first() - .unwrap() - .mangled_name, - "not_check_three" - ); assert_eq!( find_proof_harnesses( BTreeSet::from([&"module::not_check_three".to_string()]), diff --git a/tests/ui/check_summary_for_single_harness/expected b/tests/ui/check_summary_for_single_harness/expected new file mode 100644 index 000000000000..17aaa37eee0c --- /dev/null +++ b/tests/ui/check_summary_for_single_harness/expected @@ -0,0 +1,2 @@ +Checking harness check_foo... +Complete - 1 successfully verified harnesses, 0 failures, 1 total. diff --git a/tests/ui/check_summary_for_single_harness/single_harness.rs b/tests/ui/check_summary_for_single_harness/single_harness.rs new file mode 100644 index 000000000000..3d032881d446 --- /dev/null +++ b/tests/ui/check_summary_for_single_harness/single_harness.rs @@ -0,0 +1,9 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT +// kani-flags: --harness check_foo --exact +//! Check for the summary line at the end of the verification output + +#[kani::proof] +fn check_foo() { + assert!(1 == 1); +} diff --git a/tests/ui/exact-harness/check-qualified-name/expected b/tests/ui/exact-harness/check-qualified-name/expected index f8295f7a0c73..458e90d9d2de 100644 --- a/tests/ui/exact-harness/check-qualified-name/expected +++ b/tests/ui/exact-harness/check-qualified-name/expected @@ -1,2 +1,2 @@ Checking harness first::check_foo... -VERIFICATION:- SUCCESSFUL +Complete - 1 successfully verified harnesses, 0 failures, 1 total. diff --git a/tests/ui/exact-harness/check-qualified-name/select_harness_with_module.rs b/tests/ui/exact-harness/check-qualified-name/select_harness_with_module.rs index 981472f67a9c..63ad24196127 100644 --- a/tests/ui/exact-harness/check-qualified-name/select_harness_with_module.rs +++ b/tests/ui/exact-harness/check-qualified-name/select_harness_with_module.rs @@ -1,7 +1,7 @@ // Copyright Kani Contributors // SPDX-License-Identifier: Apache-2.0 OR MIT // kani-flags: --harness first::check_foo --exact -//! Ensure that the set of harnesses run is the union of all arguments. +//! Ensure that only the specified harness is run mod first { #[kani::proof] diff --git a/tests/ui/exact-harness/check_substring_not_matching/expected b/tests/ui/exact-harness/check_substring_not_matching/expected new file mode 100644 index 000000000000..50b34e8d0b2d --- /dev/null +++ b/tests/ui/exact-harness/check_substring_not_matching/expected @@ -0,0 +1,2 @@ +Checking harness first::harness... +VERIFICATION:- SUCCESSFUL diff --git a/tests/ui/exact-harness/check_substring_not_matching/select_harness_with_module.rs b/tests/ui/exact-harness/check_substring_not_matching/select_harness_with_module.rs new file mode 100644 index 000000000000..f46deb719f74 --- /dev/null +++ b/tests/ui/exact-harness/check_substring_not_matching/select_harness_with_module.rs @@ -0,0 +1,23 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT +// kani-flags: --harness first::harness --exact +//! Ensure that only the harness specified with --exact is picked up + +mod first { + #[kani::proof] + fn harness() { + assert!(1 == 1); + } + + /// A harness that will fail verification if it is picked up. + #[kani::proof] + fn harness_1() { + assert!(1 == 2); + } + + /// A harness that will fail verification if it is picked up. + #[kani::proof] + fn harness_2() { + assert!(3 == 2); + } +} diff --git a/tests/ui/exact-harness/incomplete-harness-name/expected b/tests/ui/exact-harness/incomplete-harness-name/expected index 8cf6d54f0a28..b1cca2c68b25 100644 --- a/tests/ui/exact-harness/incomplete-harness-name/expected +++ b/tests/ui/exact-harness/incomplete-harness-name/expected @@ -1 +1 @@ -error: no harnesses matched the harness filter: `check_blah` +error: no harnesses matched the name: `check_blah` diff --git a/tests/ui/exact-harness/multiple_matches/select_multiple_harnesses.rs b/tests/ui/exact-harness/multiple_matches/select_multiple_harnesses.rs index 5a49072dce17..68aa59fbfa69 100644 --- a/tests/ui/exact-harness/multiple_matches/select_multiple_harnesses.rs +++ b/tests/ui/exact-harness/multiple_matches/select_multiple_harnesses.rs @@ -1,7 +1,7 @@ // Copyright Kani Contributors // SPDX-License-Identifier: Apache-2.0 OR MIT // kani-flags: --harness first::check_blah --exact --harness second::verify_foo -//! Ensure that the set of harnesses run is the union of all arguments. +//! Ensure that only the specified harnesses are run mod first { #[kani::proof] diff --git a/tests/ui/exact-harness/some_matching_harnesses/expected b/tests/ui/exact-harness/some_matching_harnesses/expected index e3401ff858c2..45a411f32c0d 100644 --- a/tests/ui/exact-harness/some_matching_harnesses/expected +++ b/tests/ui/exact-harness/some_matching_harnesses/expected @@ -1,2 +1,3 @@ Checking harness existing... VERIFICATION:- SUCCESSFUL +Complete - 1 successfully verified harnesses, 0 failures, 1 total. diff --git a/tests/ui/exact-harness/some_matching_harnesses/subset.rs b/tests/ui/exact-harness/some_matching_harnesses/subset.rs index 7b7ed5358889..02d14c39d1c7 100644 --- a/tests/ui/exact-harness/some_matching_harnesses/subset.rs +++ b/tests/ui/exact-harness/some_matching_harnesses/subset.rs @@ -6,7 +6,7 @@ mod first { #[kani::proof] fn check_foo() { - assert!(1 == 1); + assert!(1 == 2); } #[kani::proof] @@ -29,7 +29,7 @@ fn existing() { #[kani::proof] fn existing_harness() { - assert!(2 == 2); + assert!(1 == 2); } /// A harness that will fail verification if it is run. From 2bbf0f80ea2fcb7802cc9c6c8c0c9a4f170a4ba1 Mon Sep 17 00:00:00 2001 From: jaisnan Date: Thu, 15 Jun 2023 20:43:29 +0000 Subject: [PATCH 3/9] Add doc comments --- kani-driver/src/args/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kani-driver/src/args/mod.rs b/kani-driver/src/args/mod.rs index 44a09197be5c..31cae95e2a61 100644 --- a/kani-driver/src/args/mod.rs +++ b/kani-driver/src/args/mod.rs @@ -169,7 +169,7 @@ pub struct VerificationArgs { pub function: Option, /// If specified, only run harnesses that match this filter. This option can be provided /// multiple times, which will run all tests matching any of the filters. - /// If used with --exact, the filter is removed and only exact matches are run. + /// If used with --exact, the harness filter will only match the exact fully qualified name of a harness. #[arg( long = "harness", conflicts_with = "function", @@ -178,7 +178,7 @@ pub struct VerificationArgs { )] pub harnesses: Vec, - /// If specified, with the fully qualified name of the harness provided, runs that specific harness and nothing more + /// When specified, the harness filter will only match the exact fully qualified name of a harness #[arg(long, requires("harnesses"))] pub exact: bool, From 85936fe35efdfb1b6dfc478cb988846b01fc6b0f Mon Sep 17 00:00:00 2001 From: jaisnan Date: Thu, 15 Jun 2023 21:03:48 +0000 Subject: [PATCH 4/9] Add summary to tests --- tests/ui/exact-harness/check-qualified-name/expected | 1 + .../check-qualified-name/select_harness_with_module.rs | 3 ++- tests/ui/exact-harness/check_substring_not_matching/expected | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/ui/exact-harness/check-qualified-name/expected b/tests/ui/exact-harness/check-qualified-name/expected index 458e90d9d2de..59ff06ae136d 100644 --- a/tests/ui/exact-harness/check-qualified-name/expected +++ b/tests/ui/exact-harness/check-qualified-name/expected @@ -1,2 +1,3 @@ Checking harness first::check_foo... +VERIFICATION:- SUCCESSFUL Complete - 1 successfully verified harnesses, 0 failures, 1 total. diff --git a/tests/ui/exact-harness/check-qualified-name/select_harness_with_module.rs b/tests/ui/exact-harness/check-qualified-name/select_harness_with_module.rs index 63ad24196127..9269b93afa37 100644 --- a/tests/ui/exact-harness/check-qualified-name/select_harness_with_module.rs +++ b/tests/ui/exact-harness/check-qualified-name/select_harness_with_module.rs @@ -9,9 +9,10 @@ mod first { assert!(1 == 1); } + /// A harness that will fail verification if it is run. #[kani::proof] fn check_blah() { - assert!(2 == 2); + assert!(1 == 2); } /// A harness that will fail verification if it is run. diff --git a/tests/ui/exact-harness/check_substring_not_matching/expected b/tests/ui/exact-harness/check_substring_not_matching/expected index 50b34e8d0b2d..6db88e2b537f 100644 --- a/tests/ui/exact-harness/check_substring_not_matching/expected +++ b/tests/ui/exact-harness/check_substring_not_matching/expected @@ -1,2 +1,4 @@ Checking harness first::harness... VERIFICATION:- SUCCESSFUL +Complete - 1 successfully verified harnesses, 0 failures, 1 total. + From cd72692f5ca7f8a9c75e2b6b46a48314cc0e781f Mon Sep 17 00:00:00 2001 From: jaisnan Date: Fri, 16 Jun 2023 19:51:50 +0000 Subject: [PATCH 5/9] Add failure on any exact match failing --- kani-driver/src/harness_runner.rs | 20 +++++-------------- kani-driver/src/metadata.rs | 14 ++++++++++--- .../incomplete-harness-name/expected | 2 +- .../some_matching_harnesses/expected | 4 +--- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/kani-driver/src/harness_runner.rs b/kani-driver/src/harness_runner.rs index a5bd69e3390a..fdafa8a5c18b 100644 --- a/kani-driver/src/harness_runner.rs +++ b/kani-driver/src/harness_runner.rs @@ -177,22 +177,12 @@ impl KaniSession { ) } ([harness], None) => { - if !self.args.exact { - bail!("no harnesses matched the harness filter: `{harness}`") - } else { - bail!("no harnesses matched the name: `{harness}`") - } - } - (harnesses, None) => { - if !self.args.exact { - bail!( - "no harnesses matched the harness filters: `{}`", - harnesses.join("`, `") - ) - } else { - bail!("no harnesses matched the names: `{}`", harnesses.join("`, `")) - } + bail!("no harnesses matched the harness filter: `{harness}`") } + (harnesses, None) => bail!( + "no harnesses matched the harness filters: `{}`", + harnesses.join("`, `") + ), ([], Some(func)) => error(&format!("No function named {func} was found")), _ => unreachable!( "invalid configuration. Cannot specify harness and function at the same time" diff --git a/kani-driver/src/metadata.rs b/kani-driver/src/metadata.rs index 8d9bc24ae226..bb855596b4aa 100644 --- a/kani-driver/src/metadata.rs +++ b/kani-driver/src/metadata.rs @@ -1,7 +1,7 @@ // Copyright Kani Contributors // SPDX-License-Identifier: Apache-2.0 OR MIT -use anyhow::Result; +use anyhow::{bail, Result}; use std::path::{Path, PathBuf}; use tracing::{debug, trace}; @@ -121,12 +121,20 @@ impl KaniSession { BTreeSet::from_iter(self.args.harnesses.iter()) }; + let total_harnesses = harnesses.len(); + if harnesses.is_empty() { Ok(Vec::from(all_harnesses)) } else { - let harnesses: Vec<&HarnessMetadata> = + let harnesses_found: Vec<&HarnessMetadata> = find_proof_harnesses(harnesses, all_harnesses, self.args.exact); - Ok(harnesses) + if self.args.exact && harnesses_found.len() < total_harnesses { + bail!( + "Please provide exact harness name. One or more of the harnesses provided don't contain the full name.", + ); + } + + Ok(harnesses_found) } } } diff --git a/tests/ui/exact-harness/incomplete-harness-name/expected b/tests/ui/exact-harness/incomplete-harness-name/expected index b1cca2c68b25..c0c96ff536a5 100644 --- a/tests/ui/exact-harness/incomplete-harness-name/expected +++ b/tests/ui/exact-harness/incomplete-harness-name/expected @@ -1 +1 @@ -error: no harnesses matched the name: `check_blah` +error: Please provide exact harness name. One or more of the harnesses provided don't contain the full name. diff --git a/tests/ui/exact-harness/some_matching_harnesses/expected b/tests/ui/exact-harness/some_matching_harnesses/expected index 45a411f32c0d..c0c96ff536a5 100644 --- a/tests/ui/exact-harness/some_matching_harnesses/expected +++ b/tests/ui/exact-harness/some_matching_harnesses/expected @@ -1,3 +1 @@ -Checking harness existing... -VERIFICATION:- SUCCESSFUL -Complete - 1 successfully verified harnesses, 0 failures, 1 total. +error: Please provide exact harness name. One or more of the harnesses provided don't contain the full name. From ad8529ac4f2af4a32522ed2be41ccc1dcfad605d Mon Sep 17 00:00:00 2001 From: jaisnan Date: Fri, 16 Jun 2023 22:37:10 +0000 Subject: [PATCH 6/9] add error on any missing harness with --exact --- kani-driver/src/metadata.rs | 21 ++++++++++++++++++- .../ui/exact-harness/fail_on_missing/expected | 1 + .../subset.rs | 2 +- .../incomplete-harness-name/expected | 2 +- .../incomplete_harness.rs | 2 +- .../some_matching_harnesses/expected | 1 - 6 files changed, 24 insertions(+), 5 deletions(-) create mode 100644 tests/ui/exact-harness/fail_on_missing/expected rename tests/ui/exact-harness/{some_matching_harnesses => fail_on_missing}/subset.rs (89%) delete mode 100644 tests/ui/exact-harness/some_matching_harnesses/expected diff --git a/kani-driver/src/metadata.rs b/kani-driver/src/metadata.rs index bb855596b4aa..a971c95e8ee8 100644 --- a/kani-driver/src/metadata.rs +++ b/kani-driver/src/metadata.rs @@ -122,15 +122,34 @@ impl KaniSession { }; let total_harnesses = harnesses.len(); + let all_targets = harnesses.clone(); if harnesses.is_empty() { Ok(Vec::from(all_harnesses)) } else { let harnesses_found: Vec<&HarnessMetadata> = find_proof_harnesses(harnesses, all_harnesses, self.args.exact); + + // If even one harness was not found with --exact, return an error to user if self.args.exact && harnesses_found.len() < total_harnesses { + let mut harness_found_names: BTreeSet<&String> = BTreeSet::new(); + + for harness in harnesses_found.clone() { + harness_found_names.insert(&harness.pretty_name); + } + + // Check which harnesses are missing from the difference of targets and harnesses_found + let harnesses_missing: Vec<&String> = + all_targets.difference(&harness_found_names).cloned().collect(); + let joined_string = harnesses_missing + .iter() + .map(|&s| (*s).clone()) + .collect::>() + .join("`, `"); + bail!( - "Please provide exact harness name. One or more of the harnesses provided don't contain the full name.", + "Please provide exact harness name. The harnesses `{}` don't contain the full name.", + joined_string ); } diff --git a/tests/ui/exact-harness/fail_on_missing/expected b/tests/ui/exact-harness/fail_on_missing/expected new file mode 100644 index 000000000000..f3d4920229cb --- /dev/null +++ b/tests/ui/exact-harness/fail_on_missing/expected @@ -0,0 +1 @@ +error: Please provide exact harness name. The harnesses `check_blah`, `check_foo` don't contain the full name. diff --git a/tests/ui/exact-harness/some_matching_harnesses/subset.rs b/tests/ui/exact-harness/fail_on_missing/subset.rs similarity index 89% rename from tests/ui/exact-harness/some_matching_harnesses/subset.rs rename to tests/ui/exact-harness/fail_on_missing/subset.rs index 02d14c39d1c7..943b2073ca30 100644 --- a/tests/ui/exact-harness/some_matching_harnesses/subset.rs +++ b/tests/ui/exact-harness/fail_on_missing/subset.rs @@ -1,6 +1,6 @@ // Copyright Kani Contributors // SPDX-License-Identifier: Apache-2.0 OR MIT -// kani-flags: --harness existing --harness check_blah --exact +// kani-flags: --harness existing --harness check_blah --harness check_foo --exact //! Check that we just ignore non-matching filters mod first { diff --git a/tests/ui/exact-harness/incomplete-harness-name/expected b/tests/ui/exact-harness/incomplete-harness-name/expected index c0c96ff536a5..2f90b834ad9b 100644 --- a/tests/ui/exact-harness/incomplete-harness-name/expected +++ b/tests/ui/exact-harness/incomplete-harness-name/expected @@ -1 +1 @@ -error: Please provide exact harness name. One or more of the harnesses provided don't contain the full name. +error: Please provide exact harness name. The harnesses `ignore_third_harness` don't contain the full name. diff --git a/tests/ui/exact-harness/incomplete-harness-name/incomplete_harness.rs b/tests/ui/exact-harness/incomplete-harness-name/incomplete_harness.rs index d73137d1f04f..c2bc0e2a35ed 100644 --- a/tests/ui/exact-harness/incomplete-harness-name/incomplete_harness.rs +++ b/tests/ui/exact-harness/incomplete-harness-name/incomplete_harness.rs @@ -1,6 +1,6 @@ // Copyright Kani Contributors // SPDX-License-Identifier: Apache-2.0 OR MIT -// kani-flags: --harness check_blah --exact +// kani-flags: --harness ignore_third_harness --exact //! Check that we just ignore non-matching filters mod first { diff --git a/tests/ui/exact-harness/some_matching_harnesses/expected b/tests/ui/exact-harness/some_matching_harnesses/expected deleted file mode 100644 index c0c96ff536a5..000000000000 --- a/tests/ui/exact-harness/some_matching_harnesses/expected +++ /dev/null @@ -1 +0,0 @@ -error: Please provide exact harness name. One or more of the harnesses provided don't contain the full name. From 90ee54ee8814bcb4a3d5a228a631409c29b86b00 Mon Sep 17 00:00:00 2001 From: jaisnan Date: Mon, 19 Jun 2023 16:26:19 +0000 Subject: [PATCH 7/9] Address PR comments --- kani-driver/src/metadata.rs | 29 ++++++++----------- .../exact-harness/fail_on_missing/subset.rs | 2 +- .../incomplete_harness.rs | 2 +- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/kani-driver/src/metadata.rs b/kani-driver/src/metadata.rs index a971c95e8ee8..80bc3094d0ba 100644 --- a/kani-driver/src/metadata.rs +++ b/kani-driver/src/metadata.rs @@ -122,21 +122,17 @@ impl KaniSession { }; let total_harnesses = harnesses.len(); - let all_targets = harnesses.clone(); + let all_targets = &harnesses; if harnesses.is_empty() { Ok(Vec::from(all_harnesses)) } else { let harnesses_found: Vec<&HarnessMetadata> = - find_proof_harnesses(harnesses, all_harnesses, self.args.exact); + find_proof_harnesses(&harnesses, all_harnesses, self.args.exact); // If even one harness was not found with --exact, return an error to user if self.args.exact && harnesses_found.len() < total_harnesses { - let mut harness_found_names: BTreeSet<&String> = BTreeSet::new(); - - for harness in harnesses_found.clone() { - harness_found_names.insert(&harness.pretty_name); - } + let harness_found_names: BTreeSet<&String> = harnesses_found.iter().map(|&h| &h.pretty_name).collect(); // Check which harnesses are missing from the difference of targets and harnesses_found let harnesses_missing: Vec<&String> = @@ -148,8 +144,7 @@ impl KaniSession { .join("`, `"); bail!( - "Please provide exact harness name. The harnesses `{}` don't contain the full name.", - joined_string + "Failed to match the following harness(es):\n{joined_string}\nPlease specify the fully-qualified name of a harness.", ); } @@ -195,7 +190,7 @@ pub fn mock_proof_harness( /// At the present time, we use `no_mangle` so collisions shouldn't happen, /// but this function is written to be robust against that changing in the future. fn find_proof_harnesses<'a>( - targets: BTreeSet<&String>, + targets: &BTreeSet<&String>, all_harnesses: &[&'a HarnessMetadata], exact_filter: bool, ) -> Vec<&'a HarnessMetadata> { @@ -241,7 +236,7 @@ mod tests { // Check with harness filtering assert_eq!( find_proof_harnesses( - BTreeSet::from([&"check_three".to_string()]), + &BTreeSet::from([&"check_three".to_string()]), &ref_harnesses, false ) @@ -249,14 +244,14 @@ mod tests { 1 ); assert!( - find_proof_harnesses(BTreeSet::from([&"check_two".to_string()]), &ref_harnesses, false) + find_proof_harnesses(&BTreeSet::from([&"check_two".to_string()]), &ref_harnesses, false) .first() .unwrap() .mangled_name == "module::check_two" ); assert!( - find_proof_harnesses(BTreeSet::from([&"check_one".to_string()]), &ref_harnesses, false) + find_proof_harnesses(&BTreeSet::from([&"check_one".to_string()]), &ref_harnesses, false) .first() .unwrap() .mangled_name @@ -277,18 +272,18 @@ mod tests { assert!( find_proof_harnesses( - BTreeSet::from([&"check_three".to_string()]), + &BTreeSet::from([&"check_three".to_string()]), &ref_harnesses, true ) .is_empty() ); assert!( - find_proof_harnesses(BTreeSet::from([&"check_two".to_string()]), &ref_harnesses, true) + find_proof_harnesses(&BTreeSet::from([&"check_two".to_string()]), &ref_harnesses, true) .is_empty() ); assert_eq!( - find_proof_harnesses(BTreeSet::from([&"check_one".to_string()]), &ref_harnesses, true) + find_proof_harnesses(&BTreeSet::from([&"check_one".to_string()]), &ref_harnesses, true) .first() .unwrap() .mangled_name, @@ -296,7 +291,7 @@ mod tests { ); assert_eq!( find_proof_harnesses( - BTreeSet::from([&"module::not_check_three".to_string()]), + &BTreeSet::from([&"module::not_check_three".to_string()]), &ref_harnesses, true ) diff --git a/tests/ui/exact-harness/fail_on_missing/subset.rs b/tests/ui/exact-harness/fail_on_missing/subset.rs index 943b2073ca30..6fe025dd44a3 100644 --- a/tests/ui/exact-harness/fail_on_missing/subset.rs +++ b/tests/ui/exact-harness/fail_on_missing/subset.rs @@ -1,7 +1,7 @@ // Copyright Kani Contributors // SPDX-License-Identifier: Apache-2.0 OR MIT // kani-flags: --harness existing --harness check_blah --harness check_foo --exact -//! Check that we just ignore non-matching filters +//! Check that we error out with non-matching filters when --exact is used mod first { #[kani::proof] diff --git a/tests/ui/exact-harness/incomplete-harness-name/incomplete_harness.rs b/tests/ui/exact-harness/incomplete-harness-name/incomplete_harness.rs index c2bc0e2a35ed..0a1d6b44ed7f 100644 --- a/tests/ui/exact-harness/incomplete-harness-name/incomplete_harness.rs +++ b/tests/ui/exact-harness/incomplete-harness-name/incomplete_harness.rs @@ -1,7 +1,7 @@ // Copyright Kani Contributors // SPDX-License-Identifier: Apache-2.0 OR MIT // kani-flags: --harness ignore_third_harness --exact -//! Check that we just ignore non-matching filters +//! Check that we error out with non-matching filters when --exact is used mod first { #[kani::proof] From f03062f67d7e7df2630858f5c1817966d914da2c Mon Sep 17 00:00:00 2001 From: jaisnan Date: Mon, 19 Jun 2023 16:26:33 +0000 Subject: [PATCH 8/9] add formatting --- kani-driver/src/metadata.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/kani-driver/src/metadata.rs b/kani-driver/src/metadata.rs index 80bc3094d0ba..871be621c6b0 100644 --- a/kani-driver/src/metadata.rs +++ b/kani-driver/src/metadata.rs @@ -132,7 +132,8 @@ impl KaniSession { // If even one harness was not found with --exact, return an error to user if self.args.exact && harnesses_found.len() < total_harnesses { - let harness_found_names: BTreeSet<&String> = harnesses_found.iter().map(|&h| &h.pretty_name).collect(); + let harness_found_names: BTreeSet<&String> = + harnesses_found.iter().map(|&h| &h.pretty_name).collect(); // Check which harnesses are missing from the difference of targets and harnesses_found let harnesses_missing: Vec<&String> = @@ -244,17 +245,25 @@ mod tests { 1 ); assert!( - find_proof_harnesses(&BTreeSet::from([&"check_two".to_string()]), &ref_harnesses, false) - .first() - .unwrap() - .mangled_name + find_proof_harnesses( + &BTreeSet::from([&"check_two".to_string()]), + &ref_harnesses, + false + ) + .first() + .unwrap() + .mangled_name == "module::check_two" ); assert!( - find_proof_harnesses(&BTreeSet::from([&"check_one".to_string()]), &ref_harnesses, false) - .first() - .unwrap() - .mangled_name + find_proof_harnesses( + &BTreeSet::from([&"check_one".to_string()]), + &ref_harnesses, + false + ) + .first() + .unwrap() + .mangled_name == "check_one" ); } From 6b3febebcf04fca0ad06d42abfacba80d79e74a4 Mon Sep 17 00:00:00 2001 From: jaisnan Date: Mon, 19 Jun 2023 16:37:53 +0000 Subject: [PATCH 9/9] Fix expected files --- tests/ui/exact-harness/fail_on_missing/expected | 4 +++- tests/ui/exact-harness/incomplete-harness-name/expected | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/ui/exact-harness/fail_on_missing/expected b/tests/ui/exact-harness/fail_on_missing/expected index f3d4920229cb..45cc61032413 100644 --- a/tests/ui/exact-harness/fail_on_missing/expected +++ b/tests/ui/exact-harness/fail_on_missing/expected @@ -1 +1,3 @@ -error: Please provide exact harness name. The harnesses `check_blah`, `check_foo` don't contain the full name. +error: Failed to match the following harness(es): +check_blah`, `check_foo +Please specify the fully-qualified name of a harness. diff --git a/tests/ui/exact-harness/incomplete-harness-name/expected b/tests/ui/exact-harness/incomplete-harness-name/expected index 2f90b834ad9b..93ef322aeebb 100644 --- a/tests/ui/exact-harness/incomplete-harness-name/expected +++ b/tests/ui/exact-harness/incomplete-harness-name/expected @@ -1 +1,3 @@ -error: Please provide exact harness name. The harnesses `ignore_third_harness` don't contain the full name. +error: Failed to match the following harness(es): +ignore_third_harness +Please specify the fully-qualified name of a harness.