From 21014e2ef518258a1a02b238aad5f32954ee24af Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Fri, 1 Jul 2022 15:30:58 -0400 Subject: [PATCH 01/80] Added proptest test cases. --- tests/proptest/primitive/single-arg.rs | 42 ++++++++++++++++++++ tests/proptest/primitive/single-strategy.rs | 44 +++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 tests/proptest/primitive/single-arg.rs create mode 100644 tests/proptest/primitive/single-strategy.rs diff --git a/tests/proptest/primitive/single-arg.rs b/tests/proptest/primitive/single-arg.rs new file mode 100644 index 000000000000..2dff1ad40ec2 --- /dev/null +++ b/tests/proptest/primitive/single-arg.rs @@ -0,0 +1,42 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT + +//! Proptests with a single primitive input + +macro_rules! unsigned_single_input_proptest { + ($fn_name:ident, $type:ty) => { + kani::proptest! { + #[kani::proof] + fn $fn_name (input_1 : $type) { + assert!(input_1 + input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } + } + }; +} + +unsigned_single_input_proptest!(proptest_u8, u8); +unsigned_single_input_proptest!(proptest_u16, u16); +unsigned_single_input_proptest!(proptest_u32, u32); +unsigned_single_input_proptest!(proptest_u64, u64); +unsigned_single_input_proptest!(proptest_u128, u128); +unsigned_single_input_proptest!(proptest_usize, usize); + +macro_rules! signed_single_input_proptest { + ($fn_name:ident, $type:ty) => { + kani::proptest! { + #[kani::proof] + fn $fn_name (input_1 : $type) { + assert!(input_1 * input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } + } + }; +} + +signed_single_input_proptest!(proptest_i8, i8); +signed_single_input_proptest!(proptest_i16, i16); +signed_single_input_proptest!(proptest_i32, i32); +signed_single_input_proptest!(proptest_i64, i64); +signed_single_input_proptest!(proptest_i128, i128); +signed_single_input_proptest!(proptest_isize, isize); diff --git a/tests/proptest/primitive/single-strategy.rs b/tests/proptest/primitive/single-strategy.rs new file mode 100644 index 000000000000..507398e9a679 --- /dev/null +++ b/tests/proptest/primitive/single-strategy.rs @@ -0,0 +1,44 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT + +//! Proptests with a single primitive strategy. + +macro_rules! unsigned_single_input_proptest { + ($fn_name:ident, $type:ty) => { + kani::proptest! { + #[kani::proof] + fn $fn_name (input_1 in proptest::arbitrary::any< $type >) { + assert!(input_1 + input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } + } + }; +} + + + +unsigned_single_input_proptest!(proptest_u8, u8); +unsigned_single_input_proptest!(proptest_u16, u16); +unsigned_single_input_proptest!(proptest_u32, u32); +unsigned_single_input_proptest!(proptest_u64, u64); +unsigned_single_input_proptest!(proptest_u128, u128); +unsigned_single_input_proptest!(proptest_usize, usize); + +macro_rules! signed_single_input_proptest { + ($fn_name:ident, $type:ty) => { + kani::proptest! { + #[kani::proof] + fn $fn_name (input_1 in proptest::arbitrary::any< $type >) { + assert!(input_1 * input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } + } + }; +} + +signed_single_input_proptest!(proptest_i8, i8); +signed_single_input_proptest!(proptest_i16, i16); +signed_single_input_proptest!(proptest_i32, i32); +signed_single_input_proptest!(proptest_i64, i64); +signed_single_input_proptest!(proptest_i128, i128); +signed_single_input_proptest!(proptest_isize, isize); From e79796442eab20d4be2c3fb502156d4bad79d27a Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Tue, 5 Jul 2022 18:44:17 -0400 Subject: [PATCH 02/80] Added prototype translator. --- library/kani_macros/src/lib.rs | 67 +++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/library/kani_macros/src/lib.rs b/library/kani_macros/src/lib.rs index 43c709832a62..cbc8a8ef6180 100644 --- a/library/kani_macros/src/lib.rs +++ b/library/kani_macros/src/lib.rs @@ -9,7 +9,12 @@ // RUSTFLAGS="-Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(kanitool)" // proc_macro::quote is nightly-only, so we'll cobble things together instead -use proc_macro::TokenStream; +use proc_macro::{ + Ident, + TokenStream, + TokenTree, +}; + #[cfg(all(not(kani), not(test)))] #[proc_macro_attribute] @@ -73,3 +78,63 @@ pub fn unwind(attr: TokenStream, item: TokenStream) -> TokenStream { result.extend(item); result } + + + +/// This proc macro does one of the following. (1) if kani is +/// configured, then it substitutes all occurrences of the proptest +/// crate with a custom kani_proptest crate. (2) otherwise, it keeps +/// the body and pastes it in. +/// +/// Implementation of the rewrite is done via a state machine in the +/// .1 position of the fold accumulator. After seeing "proptest" +/// token, it puts the span of this token in the option. If "proptest" +/// is followed by ":" or ";", then a re-write is +/// triggered. Otherwise, it pushes the same token and goes back to +/// the original state until "proptest" is seen again. +#[proc_macro] +pub fn kani_proptest_translate(input: TokenStream) -> TokenStream { + const REWRITE_FROM : &str = "proptest"; + const REWRITE_TO : &str = "kani_proptest"; + + if std::env::var_os("CARGO_CFG_KANI").is_some() { + input.into_iter() + .fold( + (TokenStream::new(), None), + |(mut acc, maybe_proptest_span), cur| + if let TokenTree::Ident(ident) = cur { + if &ident.to_string() == REWRITE_FROM { + (acc, Some(ident.span())) + } else { + acc.extend(vec![TokenTree::Ident(ident)]); + (acc, maybe_proptest_span) + } + } else if let TokenTree::Punct(punctuation) = cur { + if let Some(proptest_span) = maybe_proptest_span { + acc.extend(vec![ + TokenTree::Ident( + Ident::new_raw( + if punctuation.as_char() == ':' || punctuation.as_char() == ';' { + REWRITE_TO + } else { + REWRITE_FROM + }, + proptest_span + ) + ), + TokenTree::Punct(punctuation)] + ); + (acc, None) + } else { + acc.extend(vec![TokenTree::Punct(punctuation)]); + (acc, None) + } + } else { + acc.extend(vec![cur]); + (acc, None) + } + ).0 + } else { + input + } +} From 988892c1acc4f5d23b782294a3d2d3eeb257e1fe Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Tue, 5 Jul 2022 19:14:32 -0400 Subject: [PATCH 03/80] Added missing recurisve case. Separated to helper. --- library/kani_macros/src/lib.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/library/kani_macros/src/lib.rs b/library/kani_macros/src/lib.rs index cbc8a8ef6180..53462d01230a 100644 --- a/library/kani_macros/src/lib.rs +++ b/library/kani_macros/src/lib.rs @@ -11,6 +11,7 @@ // proc_macro::quote is nightly-only, so we'll cobble things together instead use proc_macro::{ Ident, + Group, TokenStream, TokenTree, }; @@ -97,7 +98,7 @@ pub fn kani_proptest_translate(input: TokenStream) -> TokenStream { const REWRITE_FROM : &str = "proptest"; const REWRITE_TO : &str = "kani_proptest"; - if std::env::var_os("CARGO_CFG_KANI").is_some() { + fn translate_recursive_helper(input: TokenStream) -> TokenStream { input.into_iter() .fold( (TokenStream::new(), None), @@ -129,11 +130,22 @@ pub fn kani_proptest_translate(input: TokenStream) -> TokenStream { acc.extend(vec![TokenTree::Punct(punctuation)]); (acc, None) } + } else if let TokenTree::Group(group) = cur { + let delimiter = group.delimiter(); + let stream = translate_recursive_helper(group.stream()); + acc.extend(vec![TokenTree::Group(Group::new(delimiter, stream))]); + (acc, None) } else { acc.extend(vec![cur]); (acc, None) } ).0 + } + + + if std::env::var_os("CARGO_CFG_KANI").is_some() { + let result = translate_recursive_helper(input); + panic!("{}", result) } else { input } From 7b4568afbfd62616989dbac6f38a52bba33ebd5a Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 6 Jul 2022 09:47:37 -0400 Subject: [PATCH 04/80] Removed panic put in for debugging. --- library/kani_macros/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/kani_macros/src/lib.rs b/library/kani_macros/src/lib.rs index 53462d01230a..7c2539fdceaf 100644 --- a/library/kani_macros/src/lib.rs +++ b/library/kani_macros/src/lib.rs @@ -145,7 +145,7 @@ pub fn kani_proptest_translate(input: TokenStream) -> TokenStream { if std::env::var_os("CARGO_CFG_KANI").is_some() { let result = translate_recursive_helper(input); - panic!("{}", result) + result } else { input } From a0669f5742bfa969b6a55defea25f84a07045e1f Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 6 Jul 2022 10:19:54 -0400 Subject: [PATCH 05/80] Changed name of translator --- library/kani_macros/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/kani_macros/src/lib.rs b/library/kani_macros/src/lib.rs index 7c2539fdceaf..e5ec18ea5765 100644 --- a/library/kani_macros/src/lib.rs +++ b/library/kani_macros/src/lib.rs @@ -94,7 +94,7 @@ pub fn unwind(attr: TokenStream, item: TokenStream) -> TokenStream { /// triggered. Otherwise, it pushes the same token and goes back to /// the original state until "proptest" is seen again. #[proc_macro] -pub fn kani_proptest_translate(input: TokenStream) -> TokenStream { +pub fn translate_from_proptest(input: TokenStream) -> TokenStream { const REWRITE_FROM : &str = "proptest"; const REWRITE_TO : &str = "kani_proptest"; From 005bb7c21f20314a4d9a38d33ff762d70ed630ae Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 6 Jul 2022 10:20:20 -0400 Subject: [PATCH 06/80] Refactored test case for proptest integration. --- tests/proptest/primitive/fixme-single-arg.rs | 104 ++++++++++++++++++ .../primitive/fixme-single-strategy.rs | 103 +++++++++++++++++ tests/proptest/primitive/single-arg.rs | 42 ------- tests/proptest/primitive/single-strategy.rs | 44 -------- 4 files changed, 207 insertions(+), 86 deletions(-) create mode 100644 tests/proptest/primitive/fixme-single-arg.rs create mode 100644 tests/proptest/primitive/fixme-single-strategy.rs delete mode 100644 tests/proptest/primitive/single-arg.rs delete mode 100644 tests/proptest/primitive/single-strategy.rs diff --git a/tests/proptest/primitive/fixme-single-arg.rs b/tests/proptest/primitive/fixme-single-arg.rs new file mode 100644 index 000000000000..880a7c9dc427 --- /dev/null +++ b/tests/proptest/primitive/fixme-single-arg.rs @@ -0,0 +1,104 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT + +//! Proptests with a single primitive input. This repetition should be +//! done with macros, but since we have already 2 nested macros, I +//! pre-expanded for clarity. + +kani::translate_from_proptest!{ +proptest! { + #[kani::proof] + fn proptest_u8 (input_1 : u8) { + assert!(input_1 + input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_u16 (input_1 : u16) { + assert!(input_1 + input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_u32 (input_1 : u32) { + assert!(input_1 + input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_u64 (input_1 : u64) { + assert!(input_1 + input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_u128 (input_1 : u128) { + assert!(input_1 + input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_usize (input_1 : usize) { + assert!(input_1 + input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_i8 (input_1 : i8) { + assert!(input_1 * input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_i16 (input_1 : i16) { + assert!(input_1 * input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_i32 (input_1 : i32) { + assert!(input_1 * input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_i64 (input_1 : i64) { + assert!(input_1 * input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_i128 (input_1 : i128) { + assert!(input_1 * input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_isize (input_1 : isize) { + assert!(input_1 * input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} +} diff --git a/tests/proptest/primitive/fixme-single-strategy.rs b/tests/proptest/primitive/fixme-single-strategy.rs new file mode 100644 index 000000000000..5890e7293432 --- /dev/null +++ b/tests/proptest/primitive/fixme-single-strategy.rs @@ -0,0 +1,103 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT + +//! Proptests with a single primitive strategy. Also expanded for +//! clarity during testing. + +kani::translate_from_proptest!{ +proptest! { + #[kani::proof] + fn proptest_u8 (input_ in proptest::arbitrary::any) { + assert!(input_1 + input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_u16 (input_ in proptest::arbitrary::any) { + assert!(input_1 + input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_u32 (input_ in proptest::arbitrary::any) { + assert!(input_1 + input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_u64 (input_ in proptest::arbitrary::any) { + assert!(input_1 + input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_u128 (input_ in proptest::arbitrary::any) { + assert!(input_1 + input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_usize (input_ in proptest::arbitrary::any) { + assert!(input_1 + input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_i8 (input_ in proptest::arbitrary::any) { + assert!(input_1 * input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_i16 (input_ in proptest::arbitrary::any) { + assert!(input_1 * input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_i32 (input_ in proptest::arbitrary::any) { + assert!(input_1 * input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_i64 (input_ in proptest::arbitrary::any) { + assert!(input_1 * input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_i128 (input_ in proptest::arbitrary::any) { + assert!(input_1 * input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} + +proptest! { + #[kani::proof] + fn proptest_isize (input_ in proptest::arbitrary::any) { + assert!(input_1 * input_1 >= 0); + assert_eq!(input_1 - input_1, 0); + } +} +} diff --git a/tests/proptest/primitive/single-arg.rs b/tests/proptest/primitive/single-arg.rs deleted file mode 100644 index 2dff1ad40ec2..000000000000 --- a/tests/proptest/primitive/single-arg.rs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright Kani Contributors -// SPDX-License-Identifier: Apache-2.0 OR MIT - -//! Proptests with a single primitive input - -macro_rules! unsigned_single_input_proptest { - ($fn_name:ident, $type:ty) => { - kani::proptest! { - #[kani::proof] - fn $fn_name (input_1 : $type) { - assert!(input_1 + input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } - } - }; -} - -unsigned_single_input_proptest!(proptest_u8, u8); -unsigned_single_input_proptest!(proptest_u16, u16); -unsigned_single_input_proptest!(proptest_u32, u32); -unsigned_single_input_proptest!(proptest_u64, u64); -unsigned_single_input_proptest!(proptest_u128, u128); -unsigned_single_input_proptest!(proptest_usize, usize); - -macro_rules! signed_single_input_proptest { - ($fn_name:ident, $type:ty) => { - kani::proptest! { - #[kani::proof] - fn $fn_name (input_1 : $type) { - assert!(input_1 * input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } - } - }; -} - -signed_single_input_proptest!(proptest_i8, i8); -signed_single_input_proptest!(proptest_i16, i16); -signed_single_input_proptest!(proptest_i32, i32); -signed_single_input_proptest!(proptest_i64, i64); -signed_single_input_proptest!(proptest_i128, i128); -signed_single_input_proptest!(proptest_isize, isize); diff --git a/tests/proptest/primitive/single-strategy.rs b/tests/proptest/primitive/single-strategy.rs deleted file mode 100644 index 507398e9a679..000000000000 --- a/tests/proptest/primitive/single-strategy.rs +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright Kani Contributors -// SPDX-License-Identifier: Apache-2.0 OR MIT - -//! Proptests with a single primitive strategy. - -macro_rules! unsigned_single_input_proptest { - ($fn_name:ident, $type:ty) => { - kani::proptest! { - #[kani::proof] - fn $fn_name (input_1 in proptest::arbitrary::any< $type >) { - assert!(input_1 + input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } - } - }; -} - - - -unsigned_single_input_proptest!(proptest_u8, u8); -unsigned_single_input_proptest!(proptest_u16, u16); -unsigned_single_input_proptest!(proptest_u32, u32); -unsigned_single_input_proptest!(proptest_u64, u64); -unsigned_single_input_proptest!(proptest_u128, u128); -unsigned_single_input_proptest!(proptest_usize, usize); - -macro_rules! signed_single_input_proptest { - ($fn_name:ident, $type:ty) => { - kani::proptest! { - #[kani::proof] - fn $fn_name (input_1 in proptest::arbitrary::any< $type >) { - assert!(input_1 * input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } - } - }; -} - -signed_single_input_proptest!(proptest_i8, i8); -signed_single_input_proptest!(proptest_i16, i16); -signed_single_input_proptest!(proptest_i32, i32); -signed_single_input_proptest!(proptest_i64, i64); -signed_single_input_proptest!(proptest_i128, i128); -signed_single_input_proptest!(proptest_isize, isize); From 6b0c65e11b8184d0e8bcabed27c490dbdbb1f95b Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 6 Jul 2022 10:40:04 -0400 Subject: [PATCH 07/80] Fixed typo in variable name. --- .../primitive/fixme-single-strategy.rs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/tests/proptest/primitive/fixme-single-strategy.rs b/tests/proptest/primitive/fixme-single-strategy.rs index 5890e7293432..57146f841013 100644 --- a/tests/proptest/primitive/fixme-single-strategy.rs +++ b/tests/proptest/primitive/fixme-single-strategy.rs @@ -7,7 +7,7 @@ kani::translate_from_proptest!{ proptest! { #[kani::proof] - fn proptest_u8 (input_ in proptest::arbitrary::any) { + fn proptest_u8 (input_1 in proptest::arbitrary::any) { assert!(input_1 + input_1 >= 0); assert_eq!(input_1 - input_1, 0); } @@ -15,7 +15,7 @@ proptest! { proptest! { #[kani::proof] - fn proptest_u16 (input_ in proptest::arbitrary::any) { + fn proptest_u16 (input_1 in proptest::arbitrary::any) { assert!(input_1 + input_1 >= 0); assert_eq!(input_1 - input_1, 0); } @@ -23,7 +23,7 @@ proptest! { proptest! { #[kani::proof] - fn proptest_u32 (input_ in proptest::arbitrary::any) { + fn proptest_u32 (input_1 in proptest::arbitrary::any) { assert!(input_1 + input_1 >= 0); assert_eq!(input_1 - input_1, 0); } @@ -31,7 +31,7 @@ proptest! { proptest! { #[kani::proof] - fn proptest_u64 (input_ in proptest::arbitrary::any) { + fn proptest_u64 (input_1 in proptest::arbitrary::any) { assert!(input_1 + input_1 >= 0); assert_eq!(input_1 - input_1, 0); } @@ -39,7 +39,7 @@ proptest! { proptest! { #[kani::proof] - fn proptest_u128 (input_ in proptest::arbitrary::any) { + fn proptest_u128 (input_1 in proptest::arbitrary::any) { assert!(input_1 + input_1 >= 0); assert_eq!(input_1 - input_1, 0); } @@ -47,7 +47,7 @@ proptest! { proptest! { #[kani::proof] - fn proptest_usize (input_ in proptest::arbitrary::any) { + fn proptest_usize (input_1 in proptest::arbitrary::any) { assert!(input_1 + input_1 >= 0); assert_eq!(input_1 - input_1, 0); } @@ -55,7 +55,7 @@ proptest! { proptest! { #[kani::proof] - fn proptest_i8 (input_ in proptest::arbitrary::any) { + fn proptest_i8 (input_1 in proptest::arbitrary::any) { assert!(input_1 * input_1 >= 0); assert_eq!(input_1 - input_1, 0); } @@ -63,7 +63,7 @@ proptest! { proptest! { #[kani::proof] - fn proptest_i16 (input_ in proptest::arbitrary::any) { + fn proptest_i16 (input_1 in proptest::arbitrary::any) { assert!(input_1 * input_1 >= 0); assert_eq!(input_1 - input_1, 0); } @@ -71,7 +71,7 @@ proptest! { proptest! { #[kani::proof] - fn proptest_i32 (input_ in proptest::arbitrary::any) { + fn proptest_i32 (input_1 in proptest::arbitrary::any) { assert!(input_1 * input_1 >= 0); assert_eq!(input_1 - input_1, 0); } @@ -79,7 +79,7 @@ proptest! { proptest! { #[kani::proof] - fn proptest_i64 (input_ in proptest::arbitrary::any) { + fn proptest_i64 (input_1 in proptest::arbitrary::any) { assert!(input_1 * input_1 >= 0); assert_eq!(input_1 - input_1, 0); } @@ -87,7 +87,7 @@ proptest! { proptest! { #[kani::proof] - fn proptest_i128 (input_ in proptest::arbitrary::any) { + fn proptest_i128 (input_1 in proptest::arbitrary::any) { assert!(input_1 * input_1 >= 0); assert_eq!(input_1 - input_1, 0); } @@ -95,7 +95,7 @@ proptest! { proptest! { #[kani::proof] - fn proptest_isize (input_ in proptest::arbitrary::any) { + fn proptest_isize (input_1 in proptest::arbitrary::any) { assert!(input_1 * input_1 >= 0); assert_eq!(input_1 - input_1, 0); } From 7d43e49582a3fffccb350a140bb1bca7514b6d45 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 6 Jul 2022 10:40:38 -0400 Subject: [PATCH 08/80] Added multi-argument and combo tests for proptest. --- tests/proptest/primitive/fixme-multi-arg.rs | 39 +++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/proptest/primitive/fixme-multi-arg.rs diff --git a/tests/proptest/primitive/fixme-multi-arg.rs b/tests/proptest/primitive/fixme-multi-arg.rs new file mode 100644 index 000000000000..8f415445c35c --- /dev/null +++ b/tests/proptest/primitive/fixme-multi-arg.rs @@ -0,0 +1,39 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT + +//! Proptests with a single primitive input. This repetition should be +//! done with macros, but since we have already 2 nested macros, I +//! pre-expanded for clarity during development. + +kani::translate_from_proptest!{ +proptest! { + #[kani::proof] + fn proptest_two_types(input_1 : u8, input_2 : i32) { + let derived = input_2 << input_1; + assert!(derived + derived >= 0); + assert_eq!(derived - derived, 0); + } + + #[kani::proof] + fn proptest_two_strategies(input_1 : proptest::arbitrary::any, input_2 : proptest::arbitrary::any) { + let derived = input_2 << input_1; + assert!(derived + derived >= 0); + assert_eq!(derived - derived, 0); + } + + #[kani::proof] + fn proptest_two_mixed_type_first(input_1 : u8, input_2 : proptest::arbitrary::any) { + let derived = input_2 << input_1; + assert!(derived + derived >= 0); + assert_eq!(derived - derived, 0); + } + + #[kani::proof] + fn proptest_two_mixed_type_first(input_1 : proptest::arbitrary::any, input_2 : i32) { + let derived = input_2 << input_1; + assert!(derived + derived >= 0); + assert_eq!(derived - derived, 0); + } +} +} + From 690d1faa7436edf66e98ee6bd884e1af451fb7e8 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 6 Jul 2022 10:49:05 -0400 Subject: [PATCH 09/80] purged redundant spaces. --- library/kani_macros/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/kani_macros/src/lib.rs b/library/kani_macros/src/lib.rs index e5ec18ea5765..739a49b87f72 100644 --- a/library/kani_macros/src/lib.rs +++ b/library/kani_macros/src/lib.rs @@ -80,8 +80,6 @@ pub fn unwind(attr: TokenStream, item: TokenStream) -> TokenStream { result } - - /// This proc macro does one of the following. (1) if kani is /// configured, then it substitutes all occurrences of the proptest /// crate with a custom kani_proptest crate. (2) otherwise, it keeps From 7f9836d9b5bab060ea5b95fa7cd1f17e552db555 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Fri, 8 Jul 2022 15:09:30 -0400 Subject: [PATCH 10/80] Rustfmt on library/kani_macros/src/lib.rs --- library/kani_macros/src/lib.rs | 45 ++++++++++++++-------------------- 1 file changed, 18 insertions(+), 27 deletions(-) diff --git a/library/kani_macros/src/lib.rs b/library/kani_macros/src/lib.rs index 739a49b87f72..12425edfc2ba 100644 --- a/library/kani_macros/src/lib.rs +++ b/library/kani_macros/src/lib.rs @@ -9,13 +9,7 @@ // RUSTFLAGS="-Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(kanitool)" // proc_macro::quote is nightly-only, so we'll cobble things together instead -use proc_macro::{ - Ident, - Group, - TokenStream, - TokenTree, -}; - +use proc_macro::{Group, Ident, TokenStream, TokenTree}; #[cfg(all(not(kani), not(test)))] #[proc_macro_attribute] @@ -93,14 +87,13 @@ pub fn unwind(attr: TokenStream, item: TokenStream) -> TokenStream { /// the original state until "proptest" is seen again. #[proc_macro] pub fn translate_from_proptest(input: TokenStream) -> TokenStream { - const REWRITE_FROM : &str = "proptest"; - const REWRITE_TO : &str = "kani_proptest"; + const REWRITE_FROM: &str = "proptest"; + const REWRITE_TO: &str = "kani_proptest"; fn translate_recursive_helper(input: TokenStream) -> TokenStream { - input.into_iter() - .fold( - (TokenStream::new(), None), - |(mut acc, maybe_proptest_span), cur| + input + .into_iter() + .fold((TokenStream::new(), None), |(mut acc, maybe_proptest_span), cur| { if let TokenTree::Ident(ident) = cur { if &ident.to_string() == REWRITE_FROM { (acc, Some(ident.span())) @@ -111,18 +104,16 @@ pub fn translate_from_proptest(input: TokenStream) -> TokenStream { } else if let TokenTree::Punct(punctuation) = cur { if let Some(proptest_span) = maybe_proptest_span { acc.extend(vec![ - TokenTree::Ident( - Ident::new_raw( - if punctuation.as_char() == ':' || punctuation.as_char() == ';' { - REWRITE_TO - } else { - REWRITE_FROM - }, - proptest_span - ) - ), - TokenTree::Punct(punctuation)] - ); + TokenTree::Ident(Ident::new_raw( + if punctuation.as_char() == ':' || punctuation.as_char() == ';' { + REWRITE_TO + } else { + REWRITE_FROM + }, + proptest_span, + )), + TokenTree::Punct(punctuation), + ]); (acc, None) } else { acc.extend(vec![TokenTree::Punct(punctuation)]); @@ -137,10 +128,10 @@ pub fn translate_from_proptest(input: TokenStream) -> TokenStream { acc.extend(vec![cur]); (acc, None) } - ).0 + }) + .0 } - if std::env::var_os("CARGO_CFG_KANI").is_some() { let result = translate_recursive_helper(input); result From 334ec6ea5ad356799879189521618f1ccca42c82 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Fri, 8 Jul 2022 19:53:02 -0400 Subject: [PATCH 11/80] Initial prototype to hijack proptest. --- Cargo.lock | 4 + Cargo.toml | 1 + kani-compiler/build.rs | 1 + kani-compiler/src/main.rs | 7 + library/proptest/Cargo.toml | 8 + library/proptest/src/lib.rs | 1111 +++++++++++++++++++++++++++++++++++ 6 files changed, 1132 insertions(+) create mode 100644 library/proptest/Cargo.toml create mode 100644 library/proptest/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c5f8fcf23e8f..00e62e0be6df 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -552,6 +552,10 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proptest" +version = "0.1.0" + [[package]] name = "pulldown-cmark" version = "0.9.1" diff --git a/Cargo.toml b/Cargo.toml index de945228a7a4..6a5e9d5a70b0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,6 +38,7 @@ strip = "debuginfo" members = [ "library/kani", "library/std", + "library/proptest", "tools/bookrunner", "tools/compiletest", "tools/make-kani-release", diff --git a/kani-compiler/build.rs b/kani-compiler/build.rs index c42fc62a55b8..82babc4de40e 100644 --- a/kani-compiler/build.rs +++ b/kani-compiler/build.rs @@ -65,5 +65,6 @@ pub fn main() { setup_lib(&out_dir, &lib_out, "kani"); setup_lib(&out_dir, &lib_out, "kani_macros"); setup_lib(&out_dir, &lib_out, "std"); + setup_lib(&out_dir, &lib_out, "proptest"); println!("cargo:rustc-env=KANI_LIB_PATH={}", lib_out); } diff --git a/kani-compiler/src/main.rs b/kani-compiler/src/main.rs index 6755d4473dcf..4f248c7425e6 100644 --- a/kani-compiler/src/main.rs +++ b/kani-compiler/src/main.rs @@ -47,6 +47,10 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { // for more details. let kani_std_rlib = PathBuf::from(lib_path).join("libstd.rlib"); let kani_std_wrapper = format!("noprelude:std={}", kani_std_rlib.to_str().unwrap()); + let kani_proptest_rlib = PathBuf::from(lib_path).join("libproptest.rlib"); + let kani_proptest_wrapper = + format!("noprelude:proptest={}", kani_proptest_rlib.to_str().unwrap()); + // println!("libproptest wrapper is: {}", &kani_proptest_wrapper); let args = vec![ "-C", "overflow-checks=on", @@ -71,6 +75,9 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { "kani", "--extern", kani_std_wrapper.as_str(), + "--extern", + // "proptest=/Users/ytakashl/Desktop/kani/target/debug/libproptest.rlib", + kani_proptest_wrapper.as_str(), ]; args.iter().map(|s| s.to_string()).collect() } diff --git a/library/proptest/Cargo.toml b/library/proptest/Cargo.toml new file mode 100644 index 000000000000..1f4118cb6fff --- /dev/null +++ b/library/proptest/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "proptest" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs new file mode 100644 index 000000000000..d67795a2ed3a --- /dev/null +++ b/library/proptest/src/lib.rs @@ -0,0 +1,1111 @@ +//- +// Copyright 2017, 2019 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// use crate::std_facade::fmt; + +/// Easily define `proptest` tests. +/// +/// Within `proptest!`, define one or more functions without return type +/// normally, except instead of putting `: type` after each parameter, write +/// `in strategy`, where `strategy` is an expression evaluating to some +/// `Strategy`. +/// +/// Each function will be wrapped in a function which sets up a `TestRunner`, +/// and then invokes the function body with inputs generated according to the +/// strategies. +/// +/// ### Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn test_addition(a in 0..10, b in 0..10) { +/// prop_assert!(a + b <= 18); +/// } +/// +/// # /* +/// #[test] +/// # */ +/// fn test_string_concat(a in ".*", b in ".*") { +/// let cat = format!("{}{}", a, b); +/// prop_assert_eq!(a.len() + b.len(), cat.len()); +/// } +/// } +/// # +/// # fn main() { test_addition(); test_string_concat(); } +/// ``` +/// +/// You can also use the normal argument syntax `pattern: type` as in: +/// +/// ```rust +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn addition_is_commutative(a: u8, b: u8) { +/// prop_assert_eq!(a as u16 + b as u16, b as u16 + a as u16); +/// } +/// +/// # /* +/// #[test] +/// # */ +/// fn test_string_concat(a in ".*", b: String) { +/// let cat = format!("{}{}", a, b); +/// prop_assert_eq!(a.len() + b.len(), cat.len()); +/// } +/// } +/// # +/// # fn main() { addition_is_commutative(); test_string_concat(); } +/// ``` +/// +/// As you can see, you can mix `pattern: type` and `pattern in expr`. +/// Due to limitations in `macro_rules!`, `pattern: type` does not work in +/// all circumstances. In such a case, use `(pattern): type` instead. +/// +/// To override the default configuration, you can start the `proptest!` block +/// with `#![proptest_config(expr)]`, where `expr` is an expression that +/// evaluates to a `proptest::test_runner::Config` (or a reference to one). +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// #![proptest_config(ProptestConfig { +/// cases: 99, .. ProptestConfig::default() +/// })] +/// # /* +/// #[test] +/// # */ +/// fn test_addition(a in 0..10, b in 0..10) { +/// prop_assert!(a + b <= 18); +/// } +/// } +/// # +/// # fn main() { test_addition(); } +/// ``` +/// +/// ## Closure-Style Invocation +/// +/// As of proptest 0.8.1, an alternative, "closure-style" invocation is +/// supported. In this form, `proptest!` is a function-like macro taking a +/// closure-esque argument. This makes it possible to run multiple tests that +/// require some expensive setup process. Note that the "fork" and "timeout" +/// features are _not_ supported in closure style. +/// +/// To use a custom configuration, pass the `Config` object as a first +/// argument. +/// +/// ### Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// #[derive(Debug)] +/// struct BigStruct { /* Lots of fields ... */ } +/// +/// fn very_expensive_function() -> BigStruct { +/// // Lots of code... +/// BigStruct { /* fields */ } +/// } +/// +/// # /* +/// #[test] +/// # */ +/// fn my_test() { +/// // We create just one `BigStruct` +/// let big_struct = very_expensive_function(); +/// +/// // But now can run multiple tests without needing to build it every time. +/// // Note the extra parentheses around the arguments are currently +/// // required. +/// proptest!(|(x in 0u32..42u32, y in 1000u32..100000u32)| { +/// // Test stuff +/// }); +/// +/// // `move` closures are also supported +/// proptest!(move |(x in 0u32..42u32)| { +/// // Test other stuff +/// }); +/// +/// // You can pass a custom configuration as the first argument +/// proptest!(ProptestConfig::with_cases(1000), |(x: i32)| { +/// // Test more stuff +/// }); +/// } +/// # +/// # fn main() { my_test(); } +/// ``` +#[macro_export] +macro_rules! proptest { + (#![proptest_config($config:expr)] + $( + $(#[$meta:meta])* + fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block + )*) => { + $( + $(#[$meta])* + fn $test_name() { + let mut config = $config.clone(); + config.test_name = Some( + concat!(module_path!(), "::", stringify!($test_name))); + $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body); + } + )* + }; + (#![proptest_config($config:expr)] + $( + $(#[$meta:meta])* + fn $test_name:ident($($arg:tt)+) $body:block + )*) => { + $( + $(#[$meta])* + fn $test_name() { + let mut config = $config.clone(); + config.test_name = Some( + concat!(module_path!(), "::", stringify!($test_name))); + $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); + } + )* + }; + + ($( + $(#[$meta:meta])* + fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block + )*) => { $crate::proptest! { + #![proptest_config($crate::test_runner::Config::default())] + $($(#[$meta])* + fn $test_name($($parm in $strategy),+) $body)* + } }; + + ($( + $(#[$meta:meta])* + fn $test_name:ident($($arg:tt)+) $body:block + )*) => { $crate::proptest! { + #![proptest_config($crate::test_runner::Config::default())] + $($(#[$meta])* + fn $test_name($($arg)+) $body)* + } }; + + (|($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + |($($parm in $strategy),+)| $body) + }; + + (move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + move |($($parm in $strategy),+)| $body) + }; + + (|($($arg:tt)+)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + |($($arg)+)| $body) + }; + + (move |($($arg:tt)+)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + move |($($arg)+)| $body) + }; + + ($config:expr, |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body) + } }; + + ($config:expr, move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [move] $body) + } }; + + ($config:expr, |($($arg:tt)+)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); + } }; + + ($config:expr, move |($($arg:tt)+)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY2 config ($($arg)+) [move] $body); + } }; +} + +/// Rejects the test input if assumptions are not met. +/// +/// Used directly within a function defined with `proptest!` or in any function +/// returning `Result<_, TestCaseError>`. +/// +/// This is invoked as `prop_assume!(condition, format, args...)`. `condition` +/// is evaluated; if it is false, `Err(TestCaseError::Reject)` is returned. The +/// message includes the point of invocation and the format message. `format` +/// and `args` may be omitted to simply use the condition itself as the +/// message. +#[macro_export] +macro_rules! prop_assume { + ($expr:expr) => { + $crate::prop_assume!($expr, "{}", stringify!($expr)) + }; + + ($expr:expr, $fmt:tt $(, $fmt_arg:expr),* $(,)?) => { + if !$expr { + return ::core::result::Result::Err( + $crate::test_runner::TestCaseError::reject( + format!(concat!("{}:{}:{}: ", $fmt), + file!(), line!(), column!() + $(, $fmt_arg)*))); + } + }; +} + +/// Produce a strategy which picks one of the listed choices. +/// +/// This is conceptually equivalent to calling `prop_union` on the first two +/// elements and then chaining `.or()` onto the rest after implicitly boxing +/// all of them. As with `Union`, values shrink across elements on the +/// assumption that earlier ones are "simpler", so they should be listed in +/// order of ascending complexity when possible. +/// +/// The macro invocation has two forms. The first is to simply list the +/// strategies separated by commas; this will cause value generation to pick +/// from the strategies uniformly. The other form is to provide a weight in the +/// form of a `u32` before each strategy, separated from the strategy with +/// `=>`. +/// +/// Note that the exact type returned by the macro varies depending on how many +/// inputs there are. In particular, if given exactly one option, it will +/// return it unmodified. It is not recommended to depend on the particular +/// type produced by this macro. +/// +/// ## Example +/// +/// ```rust,no_run +/// use proptest::prelude::*; +/// +/// #[derive(Clone, Copy, Debug)] +/// enum MyEnum { +/// Big(u64), +/// Medium(u32), +/// Little(i16), +/// } +/// +/// # #[allow(unused_variables)] +/// # fn main() { +/// let my_enum_strategy = prop_oneof![ +/// prop::num::i16::ANY.prop_map(MyEnum::Little), +/// prop::num::u32::ANY.prop_map(MyEnum::Medium), +/// prop::num::u64::ANY.prop_map(MyEnum::Big), +/// ]; +/// +/// let my_weighted_strategy = prop_oneof![ +/// 1 => prop::num::i16::ANY.prop_map(MyEnum::Little), +/// // Chose `Medium` twice as frequently as either `Little` or `Big`; i.e., +/// // around 50% of values will be `Medium`, and 25% for each of `Little` +/// // and `Big`. +/// 2 => prop::num::u32::ANY.prop_map(MyEnum::Medium), +/// 1 => prop::num::u64::ANY.prop_map(MyEnum::Big), +/// ]; +/// # } +/// ``` +#[macro_export] +macro_rules! prop_oneof { + ($($item:expr),+ $(,)?) => { + $crate::prop_oneof![ + $(1 => $item),* + ] + }; + + ($_weight0:expr => $item0:expr $(,)?) => { $item0 }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)), + ($weight7, $crate::std_facade::Arc::new($item7)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr, + $weight8:expr => $item8:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)), + ($weight7, $crate::std_facade::Arc::new($item7)), + ($weight8, $crate::std_facade::Arc::new($item8)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr, + $weight8:expr => $item8:expr, + $weight9:expr => $item9:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)), + ($weight7, $crate::std_facade::Arc::new($item7)), + ($weight8, $crate::std_facade::Arc::new($item8)), + ($weight9, $crate::std_facade::Arc::new($item9)))) + }; + + ($($weight:expr => $item:expr),+ $(,)?) => { + $crate::strategy::Union::new_weighted(vec![ + $(($weight, $crate::strategy::Strategy::boxed($item))),* + ]) + }; +} + +/// Convenience to define functions which produce new strategies. +/// +/// The macro has two general forms. In the first, you define a function with +/// two argument lists. The first argument list uses the usual syntax and +/// becomes exactly the argument list of the defined function. The second +/// argument list uses the `in strategy` syntax as with `proptest!`, and is +/// used to generate the other inputs for the function. The second argument +/// list has access to all arguments in the first. The return type indicates +/// the type of value being generated; the final return type of the function is +/// `impl Strategy`. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// use proptest::prelude::*; +/// +/// #[derive(Clone, Debug)] +/// struct MyStruct { +/// integer: u32, +/// string: String, +/// } +/// +/// prop_compose! { +/// fn my_struct_strategy(max_integer: u32) +/// (integer in 0..max_integer, string in ".*") +/// -> MyStruct { +/// MyStruct { integer, string } +/// } +/// } +/// # +/// # fn main() { } +/// ``` +/// +/// This form is simply sugar around making a tuple and then calling `prop_map` +/// on it. You can also use `arg: type` as in `proptest! { .. }`: +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// # use proptest::prelude::*; +/// # +/// # #[derive(Clone, Debug)] +/// # struct MyStruct { +/// # integer: u32, +/// # string: String, +/// # } +/// +/// prop_compose! { +/// fn my_struct_strategy(max_integer: u32) +/// (integer in 0..max_integer, string: String) +/// -> MyStruct { +/// MyStruct { integer, string } +/// } +/// } +/// # +/// # fn main() { } +/// ``` +/// +/// The second form is mostly the same, except that it takes _three_ argument +/// lists. The third argument list can see all values in both prior, which +/// permits producing strategies based on other strategies. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// use proptest::prelude::*; +/// +/// prop_compose! { +/// fn nearby_numbers()(centre in -1000..1000) +/// (a in centre-10..centre+10, +/// b in centre-10..centre+10) +/// -> (i32, i32) { +/// (a, b) +/// } +/// } +/// # +/// # fn main() { } +/// ``` +/// +/// However, the body of the function does _not_ have access to the second +/// argument list. If the body needs access to those values, they must be +/// passed through explicitly. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// use proptest::prelude::*; +/// +/// prop_compose! { +/// fn vec_and_index +/// (max_length: usize) +/// (vec in prop::collection::vec(1..10, 1..max_length)) +/// (index in 0..vec.len(), vec in Just(vec)) +/// -> (Vec, usize) +/// { +/// (vec, index) +/// } +/// } +/// # fn main() { } +/// ``` +/// +/// The second form is sugar around making a strategy tuple, calling +/// `prop_flat_map()`, then `prop_map()`. +/// +/// To give the function any modifier which isn't a visibility modifier, put it +/// in brackets before the `fn` token but after any visibility modifier. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// use proptest::prelude::*; +/// +/// prop_compose! { +/// pub(crate) [unsafe] fn pointer()(v in prop::num::usize::ANY) +/// -> *const () { +/// v as *const () +/// } +/// } +/// # fn main() { } +/// ``` +/// +/// ## Comparison with Hypothesis' `@composite` +/// +/// `prop_compose!` makes it easy to do a lot of things you can do with +/// [Hypothesis' `@composite`](https://hypothesis.readthedocs.io/en/latest/data.html#composite-strategies), +/// but not everything. +/// +/// - You can't filter via this macro. For filtering, you need to make the +/// strategy the "normal" way and use `prop_filter()`. +/// +/// - More than two layers of strategies or arbitrary logic between the two +/// layers. If you need either of these, you can achieve them by calling +/// `prop_flat_map()` by hand. +#[macro_export] +macro_rules! prop_compose { + ($(#[$meta:meta])* + $vis:vis + $([$($modi:tt)*])? fn $name:ident $params:tt + ($($var:pat in $strategy:expr),+ $(,)?) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $vis + $($($modi)*)? fn $name $params + -> impl $crate::strategy::Strategy { + let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); + $crate::strategy::Strategy::prop_map(strat, + move |$crate::proptest_helper!(@_WRAPPAT ($($var),*))| $body) + } + }; + + ($(#[$meta:meta])* + $vis:vis + $([$($modi:tt)*])? fn $name:ident $params:tt + ($($var:pat in $strategy:expr),+ $(,)?) + ($($var2:pat in $strategy2:expr),+ $(,)?) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $vis + $($($modi)*)? fn $name $params + -> impl $crate::strategy::Strategy { + let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); + let strat = $crate::strategy::Strategy::prop_flat_map( + strat, + move |$crate::proptest_helper!(@_WRAPPAT ($($var),*))| + $crate::proptest_helper!(@_WRAP ($($strategy2)*))); + $crate::strategy::Strategy::prop_map(strat, + move |$crate::proptest_helper!(@_WRAPPAT ($($var2),*))| $body) + } + }; + + ($(#[$meta:meta])* + $vis:vis + $([$($modi:tt)*])? fn $name:ident $params:tt + ($($arg:tt)+) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $vis + $($($modi)*)? fn $name $params + -> impl $crate::strategy::Strategy { + let strat = $crate::proptest_helper!(@_EXT _STRAT ($($arg)+)); + $crate::strategy::Strategy::prop_map(strat, + move |$crate::proptest_helper!(@_EXT _PAT ($($arg)+))| $body) + } + }; + + ($(#[$meta:meta])* + $vis:vis + $([$($modi:tt)*])? fn $name:ident $params:tt + ($($arg:tt)+ $(,)?) + ($($arg2:tt)+ $(,)?) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $vis + $($($modi)*)? fn $name $params + -> impl $crate::strategy::Strategy { + let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); + let strat = $crate::strategy::Strategy::prop_flat_map( + strat, + move |$crate::proptest_helper!(@_EXT _PAT ($($arg)+))| + $crate::proptest_helper!(@_EXT _STRAT ($($arg2)*))); + $crate::strategy::Strategy::prop_map(strat, + move |$crate::proptest_helper!(@_EXT _PAT ($($arg2)*))| $body) + } + }; +} + +/// Similar to `assert!` from std, but returns a test failure instead of +/// panicking if the condition fails. +/// +/// This can be used in any function that returns a `Result<_, TestCaseError>`, +/// including the top-level function inside `proptest!`. +/// +/// Both panicking via `assert!` and returning a test case failure have the +/// same effect as far as proptest is concerned; however, the Rust runtime +/// implicitly prints every panic to stderr by default (including a backtrace +/// if enabled), which can make test failures unnecessarily noisy. By using +/// `prop_assert!` instead, the only output on a failing test case is the final +/// panic including the minimal test case. +/// +/// ## Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn triangle_inequality(a in 0.0f64..10.0, b in 0.0f64..10.0) { +/// // Called with just a condition will print the condition on failure +/// prop_assert!((a*a + b*b).sqrt() <= a + b); +/// // You can also provide a custom failure message +/// prop_assert!((a*a + b*b).sqrt() <= a + b, +/// "Triangle inequality didn't hold for ({}, {})", a, b); +/// // If calling another function that can return failure, don't forget +/// // the `?` to propagate the failure. +/// assert_from_other_function(a, b)?; +/// } +/// } +/// +/// // The macro can be used from another function provided it has a compatible +/// // return type. +/// fn assert_from_other_function(a: f64, b: f64) -> Result<(), TestCaseError> { +/// prop_assert!((a*a + b*b).sqrt() <= a + b); +/// Ok(()) +/// } +/// # +/// # fn main() { triangle_inequality(); } +/// ``` +#[macro_export] +macro_rules! prop_assert { + ($cond:expr) => { + $crate::prop_assert!($cond, concat!("assertion failed: ", stringify!($cond))) + }; + + ($cond:expr, $($fmt:tt)*) => { + if !$cond { + let message = format!($($fmt)*); + let message = format!("{} at {}:{}", message, file!(), line!()); + return ::core::result::Result::Err( + $crate::test_runner::TestCaseError::fail(message)); + } + }; +} + +/// Similar to `assert_eq!` from std, but returns a test failure instead of +/// panicking if the condition fails. +/// +/// See `prop_assert!` for a more in-depth discussion. +/// +/// ## Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn concat_string_length(ref a in ".*", ref b in ".*") { +/// let cat = format!("{}{}", a, b); +/// // Use with default message +/// prop_assert_eq!(a.len() + b.len(), cat.len()); +/// // Can also provide custom message (added after the normal +/// // assertion message) +/// prop_assert_eq!(a.len() + b.len(), cat.len(), +/// "a = {:?}, b = {:?}", a, b); +/// } +/// } +/// # +/// # fn main() { concat_string_length(); } +/// ``` +#[macro_export] +macro_rules! prop_assert_eq { + ($left:expr, $right:expr) => {{ + let left = $left; + let right = $right; + $crate::prop_assert!( + left == right, + "assertion failed: `(left == right)` \ + \n left: `{:?}`,\n right: `{:?}`", + left, right); + }}; + + ($left:expr, $right:expr, $fmt:tt $($args:tt)*) => {{ + let left = $left; + let right = $right; + $crate::prop_assert!( + left == right, + concat!( + "assertion failed: `(left == right)` \ + \n left: `{:?}`, \n right: `{:?}`: ", $fmt), + left, right $($args)*); + }}; +} + +/// Similar to `assert_ne!` from std, but returns a test failure instead of +/// panicking if the condition fails. +/// +/// See `prop_assert!` for a more in-depth discussion. +/// +/// ## Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn test_addition(a in 0i32..100i32, b in 1i32..100i32) { +/// // Use with default message +/// prop_assert_ne!(a, a + b); +/// // Can also provide custom message added after the common message +/// prop_assert_ne!(a, a + b, "a = {}, b = {}", a, b); +/// } +/// } +/// # +/// # fn main() { test_addition(); } +/// ``` +#[macro_export] +macro_rules! prop_assert_ne { + ($left:expr, $right:expr) => {{ + let left = $left; + let right = $right; + prop_assert!( + left != right, + "assertion failed: `(left != right)`\ + \n left: `{:?}`,\n right: `{:?}`", + left, right); + }}; + + ($left:expr, $right:expr, $fmt:tt $($args:tt)*) => {{ + let left = $left; + let right = $right; + prop_assert!(left != right, concat!( + "assertion failed: `(left != right)`\ + \n left: `{:?}`,\n right: `{:?}`: ", $fmt), + left, right $($args)*); + }}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! proptest_helper { + (@_WRAP ($a:tt)) => { $a }; + (@_WRAP ($a0:tt $a1:tt)) => { ($a0, $a1) }; + (@_WRAP ($a0:tt $a1:tt $a2:tt)) => { ($a0, $a1, $a2) }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt)) => { ($a0, $a1, $a2, $a3) }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt)) => { + ($a0, $a1, $a2, $a3, $a4) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt $a5:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt $a5:tt $a6:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt + $a4:tt $a5:tt $a6:tt $a7:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt + $a5:tt $a6:tt $a7:tt $a8:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt + $a5:tt $a6:tt $a7:tt $a8:tt $a9:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9) + }; + (@_WRAP ($a:tt $($rest:tt)*)) => { + ($a, $crate::proptest_helper!(@_WRAP ($($rest)*))) + }; + (@_WRAPPAT ($item:pat)) => { $item }; + (@_WRAPPAT ($a0:pat, $a1:pat)) => { ($a0, $a1) }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat)) => { ($a0, $a1, $a2) }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat)) => { + ($a0, $a1, $a2, $a3) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat)) => { + ($a0, $a1, $a2, $a3, $a4) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, $a5:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat, $a7:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat, $a9:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9) + }; + (@_WRAPPAT ($a:pat, $($rest:pat),*)) => { + ($a, $crate::proptest_helper!(@_WRAPPAT ($($rest),*))) + }; + (@_WRAPSTR ($item:pat)) => { stringify!($item) }; + (@_WRAPSTR ($a0:pat, $a1:pat)) => { (stringify!($a0), stringify!($a1)) }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), + stringify!($a3), stringify!($a4)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, $a5:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat, $a7:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7), + stringify!($a8)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat, $a9:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7), + stringify!($a8), stringify!($a9)) + }; + (@_WRAPSTR ($a:pat, $($rest:pat),*)) => { + (stringify!($a), $crate::proptest_helper!(@_WRAPSTR ($($rest),*))) + }; + // build a property testing block that when executed, executes the full property test. + (@_BODY $config:ident ($($parm:pat in $strategy:expr),+) [$($mod:tt)*] $body:expr) => {{ + $config.source_file = Some(file!()); + let mut runner = $crate::test_runner::TestRunner::new($config); + let names = $crate::proptest_helper!(@_WRAPSTR ($($parm),*)); + match runner.run( + &$crate::strategy::Strategy::prop_map( + $crate::proptest_helper!(@_WRAP ($($strategy)*)), + |values| $crate::sugar::NamedArguments(names, values)), + $($mod)* |$crate::sugar::NamedArguments( + _, $crate::proptest_helper!(@_WRAPPAT ($($parm),*)))| + { + let _: () = $body; + Ok(()) + }) + { + Ok(_) => (), + Err(e) => panic!("{}\n{}", e, runner), + } + }}; + // build a property testing block that when executed, executes the full property test. + (@_BODY2 $config:ident ($($arg:tt)+) [$($mod:tt)*] $body:expr) => {{ + $config.source_file = Some(file!()); + let mut runner = $crate::test_runner::TestRunner::new($config); + let names = $crate::proptest_helper!(@_EXT _STR ($($arg)*)); + match runner.run( + &$crate::strategy::Strategy::prop_map( + $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), + |values| $crate::sugar::NamedArguments(names, values)), + $($mod)* |$crate::sugar::NamedArguments( + _, $crate::proptest_helper!(@_EXT _PAT ($($arg)*)))| + { + let _: () = $body; + Ok(()) + }) + { + Ok(_) => (), + Err(e) => panic!("{}\n{}", e, runner), + } + }}; + + // The logic below helps support `pat: type` in the proptest! macro. + + // These matchers define the actual logic: + (@_STRAT [$s:ty] [$p:pat]) => { $crate::arbitrary::any::<$s>() }; + (@_PAT [$s:ty] [$p:pat]) => { $p }; + (@_STR [$s:ty] [$p:pat]) => { stringify!($p) }; + (@_STRAT in [$s:expr] [$p:pat]) => { $s }; + (@_PAT in [$s:expr] [$p:pat]) => { $p }; + (@_STR in [$s:expr] [$p:pat]) => { stringify!($p) }; + + // These matchers rewrite into the above extractors. + // We have to do this because `:` can't FOLLOW(pat). + // Note that this is not the full `pat` grammar... + // See https://docs.rs/syn/0.14.2/syn/enum.Pat.html for that. + (@_EXT $cmd:ident ($p:pat in $s:expr $(,)?)) => { + $crate::proptest_helper!(@$cmd in [$s] [$p]) + }; + (@_EXT $cmd:ident (($p:pat) : $s:ty $(,)?)) => { + // Users can wrap in parens as a last resort. + $crate::proptest_helper!(@$cmd [$s] [$p]) + }; + (@_EXT $cmd:ident (_ : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [_]) + }; + (@_EXT $cmd:ident (ref mut $p:ident : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [ref mut $p]) + }; + (@_EXT $cmd:ident (ref $p:ident : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [ref $p]) + }; + (@_EXT $cmd:ident (mut $p:ident : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [mut $p]) + }; + (@_EXT $cmd:ident ($p:ident : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [$p]) + }; + (@_EXT $cmd:ident ([$($p:tt)*] : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [[$($p)*]]) + }; + + // Rewrite, Inductive case: + (@_EXT $cmd:ident ($p:pat in $s:expr, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd in [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (($p:pat) : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (_ : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [_]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (ref mut $p:ident : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [ref mut $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (ref $p:ident : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [ref $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (mut $p:ident : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [mut $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident ($p:ident : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident ([$($p:tt)*] : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [[$($p)*]]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; +} + +// macro_rules! named_arguments_tuple { +// ($($ix:tt $argn:ident $argv:ident)*) => { +// impl<'a, $($argn : Copy),*, $($argv),*> fmt::Debug +// for NamedArguments<($($argn,)*),&'a ($($argv,)*)> +// where $(NamedArguments<$argn, &'a $argv> : fmt::Debug),*, +// $($argv : 'a),* +// { +// #[allow(unused_assignments)] +// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +// let mut first = true; +// $( +// if !first { +// write!(f, ", ")?; +// } +// first = false; +// fmt::Debug::fmt( +// &NamedArguments((self.0).$ix, &(self.1).$ix), f)?; +// )* +// Ok(()) +// } +// } + +// impl<$($argn : Copy),*, $($argv),*> fmt::Debug +// for NamedArguments<($($argn,)*), ($($argv,)*)> +// where $(for<'a> NamedArguments<$argn, &'a $argv> : fmt::Debug),* +// { +// #[allow(unused_assignments)] +// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +// let mut first = true; +// $( +// if !first { +// write!(f, ", ")?; +// } +// first = false; +// fmt::Debug::fmt( +// &NamedArguments((self.0).$ix, &(self.1).$ix), f)?; +// )* +// Ok(()) +// } +// } +// } +// } + +// named_arguments_tuple!(0 AN AV); +// named_arguments_tuple!(0 AN AV 1 BN BV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV +// 5 FN FV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV +// 5 FN FV 6 GN GV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV +// 5 FN FV 6 GN GV 7 HN HV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV +// 5 FN FV 6 GN GV 7 HN HV 8 IN IV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV +// 5 FN FV 6 GN GV 7 HN HV 8 IN IV 9 JN JV); From 5697a90685fc546f407adab955d10da71f3bd991 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Fri, 8 Jul 2022 20:10:07 -0400 Subject: [PATCH 12/80] Added todo not for hard-coded path. --- kani-compiler/src/main.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/kani-compiler/src/main.rs b/kani-compiler/src/main.rs index 4f248c7425e6..301d0a1cc60f 100644 --- a/kani-compiler/src/main.rs +++ b/kani-compiler/src/main.rs @@ -48,7 +48,7 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { let kani_std_rlib = PathBuf::from(lib_path).join("libstd.rlib"); let kani_std_wrapper = format!("noprelude:std={}", kani_std_rlib.to_str().unwrap()); let kani_proptest_rlib = PathBuf::from(lib_path).join("libproptest.rlib"); - let kani_proptest_wrapper = + let _kani_proptest_wrapper = format!("noprelude:proptest={}", kani_proptest_rlib.to_str().unwrap()); // println!("libproptest wrapper is: {}", &kani_proptest_wrapper); let args = vec![ @@ -76,8 +76,9 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { "--extern", kani_std_wrapper.as_str(), "--extern", - // "proptest=/Users/ytakashl/Desktop/kani/target/debug/libproptest.rlib", - kani_proptest_wrapper.as_str(), + "proptest=/Users/ytakashl/Desktop/kani/target/debug/libproptest.rlib", + // todo! why does this need to be hard-coded??? + // kani_proptest_wrapper.as_str(), //Why is the other one off? ]; args.iter().map(|s| s.to_string()).collect() } From a26fbcf601be5f814a01f7a22556730343962d8e Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Fri, 8 Jul 2022 20:53:34 -0400 Subject: [PATCH 13/80] Partially working cargo kani hack. Recovery is not running though. --- scripts/cargo-kani | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/cargo-kani b/scripts/cargo-kani index 14b91dfbecc1..31ff138175b1 100755 --- a/scripts/cargo-kani +++ b/scripts/cargo-kani @@ -19,4 +19,16 @@ then fi KANI_PATH=${KANI_CANDIDATES[0]} +CARGO_TOML_SAVE_FILE='.save-cargo.toml' +if [[ "$PROPTEST" == "1" ]]; then + cp Cargo.toml $CARGO_TOML_SAVE_FILE + cat Cargo.toml | sed 's/^\s*proptest.*$//g' | tee Cargo.toml 1>/dev/null + +fi + exec -a cargo-kani "${KANI_PATH}" "$@" +EXIT_CODE="$?" + +# todo! Somehow, this is not running. Exits fro cargo kani error. +cat $CARGO_TOML_SAVE_FILE > Cargo.toml +exit $EXIT_CODE From ef368d0087e6603cef674aa4780996ad8f97361a Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Sat, 9 Jul 2022 08:00:44 -0400 Subject: [PATCH 14/80] fixed empty var check --- scripts/cargo-kani | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/cargo-kani b/scripts/cargo-kani index 31ff138175b1..3561d90690ef 100755 --- a/scripts/cargo-kani +++ b/scripts/cargo-kani @@ -20,7 +20,7 @@ fi KANI_PATH=${KANI_CANDIDATES[0]} CARGO_TOML_SAVE_FILE='.save-cargo.toml' -if [[ "$PROPTEST" == "1" ]]; then +if [[ "${PROPTEST+x}" == "1" ]]; then cp Cargo.toml $CARGO_TOML_SAVE_FILE cat Cargo.toml | sed 's/^\s*proptest.*$//g' | tee Cargo.toml 1>/dev/null From 8c604f0af18660ceb6bbc9123ea2eba965249cf4 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 13 Jul 2022 21:55:41 -0400 Subject: [PATCH 15/80] Added expanded macro printing to kani-compiler. Remove later. --- kani-compiler/src/main.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/kani-compiler/src/main.rs b/kani-compiler/src/main.rs index 301d0a1cc60f..0a09541bb182 100644 --- a/kani-compiler/src/main.rs +++ b/kani-compiler/src/main.rs @@ -69,6 +69,11 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { "crate-attr=feature(register_tool)", "-Z", "crate-attr=register_tool(kanitool)", + + // Prints expanded macro. For proptest devops only, remove after done + "-Z", + "unpretty=expanded", + "-L", lib_path, "--extern", From b34431df64f74c5160c345f57893b0bb70ab903e Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Thu, 14 Jul 2022 12:57:43 -0400 Subject: [PATCH 16/80] Added flags to mark rules in expanded form. --- library/proptest/src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index d67795a2ed3a..5678846d9e6a 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -156,10 +156,10 @@ macro_rules! proptest { )*) => { $( $(#[$meta])* - fn $test_name() { + fn $test_name() { //rule meta_strategy let mut config = $config.clone(); config.test_name = Some( - concat!(module_path!(), "::", stringify!($test_name))); + concat!(module_path!(), "::meta_strategy::", stringify!($test_name))); $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body); } )* @@ -171,10 +171,10 @@ macro_rules! proptest { )*) => { $( $(#[$meta])* - fn $test_name() { + fn $test_name() { //rule meta_type let mut config = $config.clone(); config.test_name = Some( - concat!(module_path!(), "::", stringify!($test_name))); + concat!(module_path!(), "::meta_type::", stringify!($test_name))); $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); } )* From 75a86217388003e087079ee082285a86086d06d6 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Thu, 14 Jul 2022 20:19:14 -0400 Subject: [PATCH 17/80] Make the var names unique to detect rule firing. --- library/proptest/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index 5678846d9e6a..1ba16989f07d 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -966,12 +966,12 @@ macro_rules! proptest_helper { // build a property testing block that when executed, executes the full property test. (@_BODY2 $config:ident ($($arg:tt)+) [$($mod:tt)*] $body:expr) => {{ $config.source_file = Some(file!()); - let mut runner = $crate::test_runner::TestRunner::new($config); - let names = $crate::proptest_helper!(@_EXT _STR ($($arg)*)); - match runner.run( + let mut runner2 = $crate::test_runner::TestRunner::new($config); + let names2 = $crate::proptest_helper!(@_EXT _STR ($($arg)*)); + match runner2.run( &$crate::strategy::Strategy::prop_map( $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), - |values| $crate::sugar::NamedArguments(names, values)), + |values| $crate::sugar::NamedArguments(names2, values)), $($mod)* |$crate::sugar::NamedArguments( _, $crate::proptest_helper!(@_EXT _PAT ($($arg)*)))| { @@ -980,7 +980,7 @@ macro_rules! proptest_helper { }) { Ok(_) => (), - Err(e) => panic!("{}\n{}", e, runner), + Err(e) => panic!("{}\n{}", e, runner2), } }}; From c71f185016e573633673930fd0fbcd652161eb31 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Thu, 14 Jul 2022 20:42:48 -0400 Subject: [PATCH 18/80] Prototyped new BODY2 rule. Need to push the API side for testing. TOOD: API implementation, BODY1 --- library/proptest/src/lib.rs | 54 +++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 23 deletions(-) diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index 1ba16989f07d..ce69b91636f5 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -155,11 +155,12 @@ macro_rules! proptest { fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block )*) => { $( + #[kani::proof] $(#[$meta])* fn $test_name() { //rule meta_strategy - let mut config = $config.clone(); - config.test_name = Some( - concat!(module_path!(), "::meta_strategy::", stringify!($test_name))); + // let mut config = $config.clone(); + // config.test_name = Some( + // concat!(module_path!(), "::meta_strategy::", stringify!($test_name))); $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body); } )* @@ -170,11 +171,12 @@ macro_rules! proptest { fn $test_name:ident($($arg:tt)+) $body:block )*) => { $( + #[kani::proof] $(#[$meta])* fn $test_name() { //rule meta_type - let mut config = $config.clone(); - config.test_name = Some( - concat!(module_path!(), "::meta_type::", stringify!($test_name))); + // let mut config = $config.clone(); + // config.test_name = Some( + // concat!(module_path!(), "::meta_type::", stringify!($test_name))); $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); } )* @@ -965,23 +967,29 @@ macro_rules! proptest_helper { }}; // build a property testing block that when executed, executes the full property test. (@_BODY2 $config:ident ($($arg:tt)+) [$($mod:tt)*] $body:expr) => {{ - $config.source_file = Some(file!()); - let mut runner2 = $crate::test_runner::TestRunner::new($config); - let names2 = $crate::proptest_helper!(@_EXT _STR ($($arg)*)); - match runner2.run( - &$crate::strategy::Strategy::prop_map( - $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), - |values| $crate::sugar::NamedArguments(names2, values)), - $($mod)* |$crate::sugar::NamedArguments( - _, $crate::proptest_helper!(@_EXT _PAT ($($arg)*)))| - { - let _: () = $body; - Ok(()) - }) - { - Ok(_) => (), - Err(e) => panic!("{}\n{}", e, runner2), - } + // $config.source_file = Some(file!()); + // let mut runner2 = $crate::test_runner::TestRunner::new($config); + // let names2 = $crate::proptest_helper!(@_EXT _STR ($($arg)*)); + // match runner2.run( + // &$crate::strategy::Strategy::prop_map( + // $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), + // |values| $crate::sugar::NamedArguments(names2, values)), + // $($mod)* |$crate::sugar::NamedArguments( + // _, $crate::proptest_helper!(@_EXT _PAT ($($arg)*)))| + // { + // let _: () = $body; + // Ok(()) + // }) + // { + // Ok(_) => (), + // Err(e) => panic!("{}\n{}", e, runner2), + // } + $crate::test_runner::TestRunner::run_kani( + $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), + |$crate::proptest_helper!(@_EXT _PAT ($($arg)*))| { + $body + } + ); }}; // The logic below helps support `pat: type` in the proptest! macro. From 52733ec56e3647a9f938cca10c2a7dcb5e708aaf Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 18 Jul 2022 10:42:20 -0400 Subject: [PATCH 19/80] Moved macros out to proper sugar.rs file. --- library/proptest/src/lib.rs | 1198 +++------------------------------ library/proptest/src/sugar.rs | 1119 ++++++++++++++++++++++++++++++ 2 files changed, 1208 insertions(+), 1109 deletions(-) create mode 100644 library/proptest/src/sugar.rs diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index ce69b91636f5..68074bba04b4 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -1,5 +1,5 @@ //- -// Copyright 2017, 2019 The proptest developers +// Copyright 2017, 2018 Jason Lingle // // Licensed under the Apache License, Version 2.0 or the MIT license @@ -7,1113 +7,93 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// use crate::std_facade::fmt; - -/// Easily define `proptest` tests. -/// -/// Within `proptest!`, define one or more functions without return type -/// normally, except instead of putting `: type` after each parameter, write -/// `in strategy`, where `strategy` is an expression evaluating to some -/// `Strategy`. -/// -/// Each function will be wrapped in a function which sets up a `TestRunner`, -/// and then invokes the function body with inputs generated according to the -/// strategies. -/// -/// ### Example -/// -/// ``` -/// use proptest::prelude::*; -/// -/// proptest! { -/// # /* -/// #[test] -/// # */ -/// fn test_addition(a in 0..10, b in 0..10) { -/// prop_assert!(a + b <= 18); -/// } -/// -/// # /* -/// #[test] -/// # */ -/// fn test_string_concat(a in ".*", b in ".*") { -/// let cat = format!("{}{}", a, b); -/// prop_assert_eq!(a.len() + b.len(), cat.len()); -/// } -/// } -/// # -/// # fn main() { test_addition(); test_string_concat(); } -/// ``` -/// -/// You can also use the normal argument syntax `pattern: type` as in: -/// -/// ```rust -/// use proptest::prelude::*; -/// -/// proptest! { -/// # /* -/// #[test] -/// # */ -/// fn addition_is_commutative(a: u8, b: u8) { -/// prop_assert_eq!(a as u16 + b as u16, b as u16 + a as u16); -/// } -/// -/// # /* -/// #[test] -/// # */ -/// fn test_string_concat(a in ".*", b: String) { -/// let cat = format!("{}{}", a, b); -/// prop_assert_eq!(a.len() + b.len(), cat.len()); -/// } -/// } -/// # -/// # fn main() { addition_is_commutative(); test_string_concat(); } -/// ``` -/// -/// As you can see, you can mix `pattern: type` and `pattern in expr`. -/// Due to limitations in `macro_rules!`, `pattern: type` does not work in -/// all circumstances. In such a case, use `(pattern): type` instead. -/// -/// To override the default configuration, you can start the `proptest!` block -/// with `#![proptest_config(expr)]`, where `expr` is an expression that -/// evaluates to a `proptest::test_runner::Config` (or a reference to one). -/// -/// ``` -/// use proptest::prelude::*; -/// -/// proptest! { -/// #![proptest_config(ProptestConfig { -/// cases: 99, .. ProptestConfig::default() -/// })] -/// # /* -/// #[test] -/// # */ -/// fn test_addition(a in 0..10, b in 0..10) { -/// prop_assert!(a + b <= 18); -/// } -/// } -/// # -/// # fn main() { test_addition(); } -/// ``` -/// -/// ## Closure-Style Invocation -/// -/// As of proptest 0.8.1, an alternative, "closure-style" invocation is -/// supported. In this form, `proptest!` is a function-like macro taking a -/// closure-esque argument. This makes it possible to run multiple tests that -/// require some expensive setup process. Note that the "fork" and "timeout" -/// features are _not_ supported in closure style. -/// -/// To use a custom configuration, pass the `Config` object as a first -/// argument. -/// -/// ### Example -/// -/// ``` -/// use proptest::prelude::*; -/// -/// #[derive(Debug)] -/// struct BigStruct { /* Lots of fields ... */ } -/// -/// fn very_expensive_function() -> BigStruct { -/// // Lots of code... -/// BigStruct { /* fields */ } -/// } -/// -/// # /* -/// #[test] -/// # */ -/// fn my_test() { -/// // We create just one `BigStruct` -/// let big_struct = very_expensive_function(); -/// -/// // But now can run multiple tests without needing to build it every time. -/// // Note the extra parentheses around the arguments are currently -/// // required. -/// proptest!(|(x in 0u32..42u32, y in 1000u32..100000u32)| { -/// // Test stuff -/// }); -/// -/// // `move` closures are also supported -/// proptest!(move |(x in 0u32..42u32)| { -/// // Test other stuff -/// }); -/// -/// // You can pass a custom configuration as the first argument -/// proptest!(ProptestConfig::with_cases(1000), |(x: i32)| { -/// // Test more stuff -/// }); -/// } -/// # -/// # fn main() { my_test(); } -/// ``` -#[macro_export] -macro_rules! proptest { - (#![proptest_config($config:expr)] - $( - $(#[$meta:meta])* - fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block - )*) => { - $( - #[kani::proof] - $(#[$meta])* - fn $test_name() { //rule meta_strategy - // let mut config = $config.clone(); - // config.test_name = Some( - // concat!(module_path!(), "::meta_strategy::", stringify!($test_name))); - $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body); - } - )* - }; - (#![proptest_config($config:expr)] - $( - $(#[$meta:meta])* - fn $test_name:ident($($arg:tt)+) $body:block - )*) => { - $( - #[kani::proof] - $(#[$meta])* - fn $test_name() { //rule meta_type - // let mut config = $config.clone(); - // config.test_name = Some( - // concat!(module_path!(), "::meta_type::", stringify!($test_name))); - $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); - } - )* - }; - - ($( - $(#[$meta:meta])* - fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block - )*) => { $crate::proptest! { - #![proptest_config($crate::test_runner::Config::default())] - $($(#[$meta])* - fn $test_name($($parm in $strategy),+) $body)* - } }; - - ($( - $(#[$meta:meta])* - fn $test_name:ident($($arg:tt)+) $body:block - )*) => { $crate::proptest! { - #![proptest_config($crate::test_runner::Config::default())] - $($(#[$meta])* - fn $test_name($($arg)+) $body)* - } }; - - (|($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { - $crate::proptest!( - $crate::test_runner::Config::default(), - |($($parm in $strategy),+)| $body) - }; - - (move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { - $crate::proptest!( - $crate::test_runner::Config::default(), - move |($($parm in $strategy),+)| $body) - }; - - (|($($arg:tt)+)| $body:expr) => { - $crate::proptest!( - $crate::test_runner::Config::default(), - |($($arg)+)| $body) - }; - - (move |($($arg:tt)+)| $body:expr) => { - $crate::proptest!( - $crate::test_runner::Config::default(), - move |($($arg)+)| $body) - }; - - ($config:expr, |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { { - let mut config = $config.__sugar_to_owned(); - $crate::sugar::force_no_fork(&mut config); - $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body) - } }; - - ($config:expr, move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { { - let mut config = $config.__sugar_to_owned(); - $crate::sugar::force_no_fork(&mut config); - $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [move] $body) - } }; - - ($config:expr, |($($arg:tt)+)| $body:expr) => { { - let mut config = $config.__sugar_to_owned(); - $crate::sugar::force_no_fork(&mut config); - $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); - } }; - - ($config:expr, move |($($arg:tt)+)| $body:expr) => { { - let mut config = $config.__sugar_to_owned(); - $crate::sugar::force_no_fork(&mut config); - $crate::proptest_helper!(@_BODY2 config ($($arg)+) [move] $body); - } }; -} - -/// Rejects the test input if assumptions are not met. -/// -/// Used directly within a function defined with `proptest!` or in any function -/// returning `Result<_, TestCaseError>`. -/// -/// This is invoked as `prop_assume!(condition, format, args...)`. `condition` -/// is evaluated; if it is false, `Err(TestCaseError::Reject)` is returned. The -/// message includes the point of invocation and the format message. `format` -/// and `args` may be omitted to simply use the condition itself as the -/// message. -#[macro_export] -macro_rules! prop_assume { - ($expr:expr) => { - $crate::prop_assume!($expr, "{}", stringify!($expr)) - }; - - ($expr:expr, $fmt:tt $(, $fmt_arg:expr),* $(,)?) => { - if !$expr { - return ::core::result::Result::Err( - $crate::test_runner::TestCaseError::reject( - format!(concat!("{}:{}:{}: ", $fmt), - file!(), line!(), column!() - $(, $fmt_arg)*))); - } - }; -} - -/// Produce a strategy which picks one of the listed choices. -/// -/// This is conceptually equivalent to calling `prop_union` on the first two -/// elements and then chaining `.or()` onto the rest after implicitly boxing -/// all of them. As with `Union`, values shrink across elements on the -/// assumption that earlier ones are "simpler", so they should be listed in -/// order of ascending complexity when possible. -/// -/// The macro invocation has two forms. The first is to simply list the -/// strategies separated by commas; this will cause value generation to pick -/// from the strategies uniformly. The other form is to provide a weight in the -/// form of a `u32` before each strategy, separated from the strategy with -/// `=>`. -/// -/// Note that the exact type returned by the macro varies depending on how many -/// inputs there are. In particular, if given exactly one option, it will -/// return it unmodified. It is not recommended to depend on the particular -/// type produced by this macro. -/// -/// ## Example -/// -/// ```rust,no_run -/// use proptest::prelude::*; -/// -/// #[derive(Clone, Copy, Debug)] -/// enum MyEnum { -/// Big(u64), -/// Medium(u32), -/// Little(i16), -/// } -/// -/// # #[allow(unused_variables)] -/// # fn main() { -/// let my_enum_strategy = prop_oneof![ -/// prop::num::i16::ANY.prop_map(MyEnum::Little), -/// prop::num::u32::ANY.prop_map(MyEnum::Medium), -/// prop::num::u64::ANY.prop_map(MyEnum::Big), -/// ]; -/// -/// let my_weighted_strategy = prop_oneof![ -/// 1 => prop::num::i16::ANY.prop_map(MyEnum::Little), -/// // Chose `Medium` twice as frequently as either `Little` or `Big`; i.e., -/// // around 50% of values will be `Medium`, and 25% for each of `Little` -/// // and `Big`. -/// 2 => prop::num::u32::ANY.prop_map(MyEnum::Medium), -/// 1 => prop::num::u64::ANY.prop_map(MyEnum::Big), -/// ]; -/// # } -/// ``` -#[macro_export] -macro_rules! prop_oneof { - ($($item:expr),+ $(,)?) => { - $crate::prop_oneof![ - $(1 => $item),* - ] - }; - - ($_weight0:expr => $item0:expr $(,)?) => { $item0 }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr, - $weight3:expr => $item3:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)), - ($weight3, $crate::std_facade::Arc::new($item3)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr, - $weight3:expr => $item3:expr, - $weight4:expr => $item4:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)), - ($weight3, $crate::std_facade::Arc::new($item3)), - ($weight4, $crate::std_facade::Arc::new($item4)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr, - $weight3:expr => $item3:expr, - $weight4:expr => $item4:expr, - $weight5:expr => $item5:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)), - ($weight3, $crate::std_facade::Arc::new($item3)), - ($weight4, $crate::std_facade::Arc::new($item4)), - ($weight5, $crate::std_facade::Arc::new($item5)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr, - $weight3:expr => $item3:expr, - $weight4:expr => $item4:expr, - $weight5:expr => $item5:expr, - $weight6:expr => $item6:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)), - ($weight3, $crate::std_facade::Arc::new($item3)), - ($weight4, $crate::std_facade::Arc::new($item4)), - ($weight5, $crate::std_facade::Arc::new($item5)), - ($weight6, $crate::std_facade::Arc::new($item6)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr, - $weight3:expr => $item3:expr, - $weight4:expr => $item4:expr, - $weight5:expr => $item5:expr, - $weight6:expr => $item6:expr, - $weight7:expr => $item7:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)), - ($weight3, $crate::std_facade::Arc::new($item3)), - ($weight4, $crate::std_facade::Arc::new($item4)), - ($weight5, $crate::std_facade::Arc::new($item5)), - ($weight6, $crate::std_facade::Arc::new($item6)), - ($weight7, $crate::std_facade::Arc::new($item7)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr, - $weight3:expr => $item3:expr, - $weight4:expr => $item4:expr, - $weight5:expr => $item5:expr, - $weight6:expr => $item6:expr, - $weight7:expr => $item7:expr, - $weight8:expr => $item8:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)), - ($weight3, $crate::std_facade::Arc::new($item3)), - ($weight4, $crate::std_facade::Arc::new($item4)), - ($weight5, $crate::std_facade::Arc::new($item5)), - ($weight6, $crate::std_facade::Arc::new($item6)), - ($weight7, $crate::std_facade::Arc::new($item7)), - ($weight8, $crate::std_facade::Arc::new($item8)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr, - $weight3:expr => $item3:expr, - $weight4:expr => $item4:expr, - $weight5:expr => $item5:expr, - $weight6:expr => $item6:expr, - $weight7:expr => $item7:expr, - $weight8:expr => $item8:expr, - $weight9:expr => $item9:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)), - ($weight3, $crate::std_facade::Arc::new($item3)), - ($weight4, $crate::std_facade::Arc::new($item4)), - ($weight5, $crate::std_facade::Arc::new($item5)), - ($weight6, $crate::std_facade::Arc::new($item6)), - ($weight7, $crate::std_facade::Arc::new($item7)), - ($weight8, $crate::std_facade::Arc::new($item8)), - ($weight9, $crate::std_facade::Arc::new($item9)))) - }; - - ($($weight:expr => $item:expr),+ $(,)?) => { - $crate::strategy::Union::new_weighted(vec![ - $(($weight, $crate::strategy::Strategy::boxed($item))),* - ]) - }; -} - -/// Convenience to define functions which produce new strategies. -/// -/// The macro has two general forms. In the first, you define a function with -/// two argument lists. The first argument list uses the usual syntax and -/// becomes exactly the argument list of the defined function. The second -/// argument list uses the `in strategy` syntax as with `proptest!`, and is -/// used to generate the other inputs for the function. The second argument -/// list has access to all arguments in the first. The return type indicates -/// the type of value being generated; the final return type of the function is -/// `impl Strategy`. -/// -/// ```rust,no_run -/// # #![allow(dead_code)] -/// use proptest::prelude::*; -/// -/// #[derive(Clone, Debug)] -/// struct MyStruct { -/// integer: u32, -/// string: String, -/// } -/// -/// prop_compose! { -/// fn my_struct_strategy(max_integer: u32) -/// (integer in 0..max_integer, string in ".*") -/// -> MyStruct { -/// MyStruct { integer, string } -/// } -/// } -/// # -/// # fn main() { } -/// ``` -/// -/// This form is simply sugar around making a tuple and then calling `prop_map` -/// on it. You can also use `arg: type` as in `proptest! { .. }`: -/// -/// ```rust,no_run -/// # #![allow(dead_code)] -/// # use proptest::prelude::*; -/// # -/// # #[derive(Clone, Debug)] -/// # struct MyStruct { -/// # integer: u32, -/// # string: String, -/// # } -/// -/// prop_compose! { -/// fn my_struct_strategy(max_integer: u32) -/// (integer in 0..max_integer, string: String) -/// -> MyStruct { -/// MyStruct { integer, string } -/// } -/// } -/// # -/// # fn main() { } -/// ``` -/// -/// The second form is mostly the same, except that it takes _three_ argument -/// lists. The third argument list can see all values in both prior, which -/// permits producing strategies based on other strategies. -/// -/// ```rust,no_run -/// # #![allow(dead_code)] -/// use proptest::prelude::*; -/// -/// prop_compose! { -/// fn nearby_numbers()(centre in -1000..1000) -/// (a in centre-10..centre+10, -/// b in centre-10..centre+10) -/// -> (i32, i32) { -/// (a, b) -/// } -/// } -/// # -/// # fn main() { } -/// ``` -/// -/// However, the body of the function does _not_ have access to the second -/// argument list. If the body needs access to those values, they must be -/// passed through explicitly. -/// -/// ```rust,no_run -/// # #![allow(dead_code)] -/// use proptest::prelude::*; -/// -/// prop_compose! { -/// fn vec_and_index -/// (max_length: usize) -/// (vec in prop::collection::vec(1..10, 1..max_length)) -/// (index in 0..vec.len(), vec in Just(vec)) -/// -> (Vec, usize) -/// { -/// (vec, index) -/// } -/// } -/// # fn main() { } -/// ``` -/// -/// The second form is sugar around making a strategy tuple, calling -/// `prop_flat_map()`, then `prop_map()`. -/// -/// To give the function any modifier which isn't a visibility modifier, put it -/// in brackets before the `fn` token but after any visibility modifier. -/// -/// ```rust,no_run -/// # #![allow(dead_code)] -/// use proptest::prelude::*; -/// -/// prop_compose! { -/// pub(crate) [unsafe] fn pointer()(v in prop::num::usize::ANY) -/// -> *const () { -/// v as *const () -/// } -/// } -/// # fn main() { } -/// ``` -/// -/// ## Comparison with Hypothesis' `@composite` -/// -/// `prop_compose!` makes it easy to do a lot of things you can do with -/// [Hypothesis' `@composite`](https://hypothesis.readthedocs.io/en/latest/data.html#composite-strategies), -/// but not everything. -/// -/// - You can't filter via this macro. For filtering, you need to make the -/// strategy the "normal" way and use `prop_filter()`. -/// -/// - More than two layers of strategies or arbitrary logic between the two -/// layers. If you need either of these, you can achieve them by calling -/// `prop_flat_map()` by hand. -#[macro_export] -macro_rules! prop_compose { - ($(#[$meta:meta])* - $vis:vis - $([$($modi:tt)*])? fn $name:ident $params:tt - ($($var:pat in $strategy:expr),+ $(,)?) - -> $return_type:ty $body:block) => - { - #[must_use = "strategies do nothing unless used"] - $(#[$meta])* - $vis - $($($modi)*)? fn $name $params - -> impl $crate::strategy::Strategy { - let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); - $crate::strategy::Strategy::prop_map(strat, - move |$crate::proptest_helper!(@_WRAPPAT ($($var),*))| $body) - } - }; - - ($(#[$meta:meta])* - $vis:vis - $([$($modi:tt)*])? fn $name:ident $params:tt - ($($var:pat in $strategy:expr),+ $(,)?) - ($($var2:pat in $strategy2:expr),+ $(,)?) - -> $return_type:ty $body:block) => - { - #[must_use = "strategies do nothing unless used"] - $(#[$meta])* - $vis - $($($modi)*)? fn $name $params - -> impl $crate::strategy::Strategy { - let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); - let strat = $crate::strategy::Strategy::prop_flat_map( - strat, - move |$crate::proptest_helper!(@_WRAPPAT ($($var),*))| - $crate::proptest_helper!(@_WRAP ($($strategy2)*))); - $crate::strategy::Strategy::prop_map(strat, - move |$crate::proptest_helper!(@_WRAPPAT ($($var2),*))| $body) - } - }; - - ($(#[$meta:meta])* - $vis:vis - $([$($modi:tt)*])? fn $name:ident $params:tt - ($($arg:tt)+) - -> $return_type:ty $body:block) => - { - #[must_use = "strategies do nothing unless used"] - $(#[$meta])* - $vis - $($($modi)*)? fn $name $params - -> impl $crate::strategy::Strategy { - let strat = $crate::proptest_helper!(@_EXT _STRAT ($($arg)+)); - $crate::strategy::Strategy::prop_map(strat, - move |$crate::proptest_helper!(@_EXT _PAT ($($arg)+))| $body) - } - }; - - ($(#[$meta:meta])* - $vis:vis - $([$($modi:tt)*])? fn $name:ident $params:tt - ($($arg:tt)+ $(,)?) - ($($arg2:tt)+ $(,)?) - -> $return_type:ty $body:block) => - { - #[must_use = "strategies do nothing unless used"] - $(#[$meta])* - $vis - $($($modi)*)? fn $name $params - -> impl $crate::strategy::Strategy { - let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); - let strat = $crate::strategy::Strategy::prop_flat_map( - strat, - move |$crate::proptest_helper!(@_EXT _PAT ($($arg)+))| - $crate::proptest_helper!(@_EXT _STRAT ($($arg2)*))); - $crate::strategy::Strategy::prop_map(strat, - move |$crate::proptest_helper!(@_EXT _PAT ($($arg2)*))| $body) - } - }; -} - -/// Similar to `assert!` from std, but returns a test failure instead of -/// panicking if the condition fails. -/// -/// This can be used in any function that returns a `Result<_, TestCaseError>`, -/// including the top-level function inside `proptest!`. -/// -/// Both panicking via `assert!` and returning a test case failure have the -/// same effect as far as proptest is concerned; however, the Rust runtime -/// implicitly prints every panic to stderr by default (including a backtrace -/// if enabled), which can make test failures unnecessarily noisy. By using -/// `prop_assert!` instead, the only output on a failing test case is the final -/// panic including the minimal test case. -/// -/// ## Example -/// -/// ``` -/// use proptest::prelude::*; -/// -/// proptest! { -/// # /* -/// #[test] -/// # */ -/// fn triangle_inequality(a in 0.0f64..10.0, b in 0.0f64..10.0) { -/// // Called with just a condition will print the condition on failure -/// prop_assert!((a*a + b*b).sqrt() <= a + b); -/// // You can also provide a custom failure message -/// prop_assert!((a*a + b*b).sqrt() <= a + b, -/// "Triangle inequality didn't hold for ({}, {})", a, b); -/// // If calling another function that can return failure, don't forget -/// // the `?` to propagate the failure. -/// assert_from_other_function(a, b)?; -/// } -/// } -/// -/// // The macro can be used from another function provided it has a compatible -/// // return type. -/// fn assert_from_other_function(a: f64, b: f64) -> Result<(), TestCaseError> { -/// prop_assert!((a*a + b*b).sqrt() <= a + b); -/// Ok(()) -/// } -/// # -/// # fn main() { triangle_inequality(); } -/// ``` -#[macro_export] -macro_rules! prop_assert { - ($cond:expr) => { - $crate::prop_assert!($cond, concat!("assertion failed: ", stringify!($cond))) - }; - - ($cond:expr, $($fmt:tt)*) => { - if !$cond { - let message = format!($($fmt)*); - let message = format!("{} at {}:{}", message, file!(), line!()); - return ::core::result::Result::Err( - $crate::test_runner::TestCaseError::fail(message)); - } - }; -} - -/// Similar to `assert_eq!` from std, but returns a test failure instead of -/// panicking if the condition fails. -/// -/// See `prop_assert!` for a more in-depth discussion. -/// -/// ## Example -/// -/// ``` -/// use proptest::prelude::*; -/// -/// proptest! { -/// # /* -/// #[test] -/// # */ -/// fn concat_string_length(ref a in ".*", ref b in ".*") { -/// let cat = format!("{}{}", a, b); -/// // Use with default message -/// prop_assert_eq!(a.len() + b.len(), cat.len()); -/// // Can also provide custom message (added after the normal -/// // assertion message) -/// prop_assert_eq!(a.len() + b.len(), cat.len(), -/// "a = {:?}, b = {:?}", a, b); -/// } -/// } -/// # -/// # fn main() { concat_string_length(); } -/// ``` -#[macro_export] -macro_rules! prop_assert_eq { - ($left:expr, $right:expr) => {{ - let left = $left; - let right = $right; - $crate::prop_assert!( - left == right, - "assertion failed: `(left == right)` \ - \n left: `{:?}`,\n right: `{:?}`", - left, right); - }}; - - ($left:expr, $right:expr, $fmt:tt $($args:tt)*) => {{ - let left = $left; - let right = $right; - $crate::prop_assert!( - left == right, - concat!( - "assertion failed: `(left == right)` \ - \n left: `{:?}`, \n right: `{:?}`: ", $fmt), - left, right $($args)*); - }}; -} - -/// Similar to `assert_ne!` from std, but returns a test failure instead of -/// panicking if the condition fails. -/// -/// See `prop_assert!` for a more in-depth discussion. -/// -/// ## Example -/// -/// ``` -/// use proptest::prelude::*; -/// -/// proptest! { -/// # /* -/// #[test] -/// # */ -/// fn test_addition(a in 0i32..100i32, b in 1i32..100i32) { -/// // Use with default message -/// prop_assert_ne!(a, a + b); -/// // Can also provide custom message added after the common message -/// prop_assert_ne!(a, a + b, "a = {}, b = {}", a, b); -/// } -/// } -/// # -/// # fn main() { test_addition(); } -/// ``` -#[macro_export] -macro_rules! prop_assert_ne { - ($left:expr, $right:expr) => {{ - let left = $left; - let right = $right; - prop_assert!( - left != right, - "assertion failed: `(left != right)`\ - \n left: `{:?}`,\n right: `{:?}`", - left, right); - }}; - - ($left:expr, $right:expr, $fmt:tt $($args:tt)*) => {{ - let left = $left; - let right = $right; - prop_assert!(left != right, concat!( - "assertion failed: `(left != right)`\ - \n left: `{:?}`,\n right: `{:?}`: ", $fmt), - left, right $($args)*); - }}; -} +//! # Proptest Reference Documentation +//! +//! This is the reference documentation for the proptest API. +//! +//! For documentation on how to get started with proptest and general usage +//! advice, please refer to the [Proptest Book](https://altsysrq.github.io/proptest-book/intro.html). + +#![forbid(future_incompatible)] +#![deny(missing_docs, bare_trait_objects)] +#![no_std] +#![cfg_attr(feature = "cargo-clippy", allow( + doc_markdown, + // We have a lot of these lints for associated types... And we don't care. + type_complexity +))] +#![cfg_attr( + feature = "unstable", + feature(allocator_api, try_trait, generator_trait, never_type, try_reserve) +)] +#![cfg_attr(all(feature = "std", feature = "unstable"), feature(ip))] +#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(core_intrinsics))] + +// // std_facade is used in a few macros, so it needs to be public. +// #[macro_use] +// #[doc(hidden)] +// pub mod std_facade; + +// #[cfg(any(feature = "std", test))] +// #[macro_use] +// extern crate std; + +// #[cfg(all(feature = "alloc", not(feature = "std")))] +// #[macro_use] +// extern crate alloc; + +// #[cfg(feature = "frunk")] +// #[macro_use] +// extern crate frunk_core; + +// #[cfg(feature = "frunk")] +// #[macro_use] +// mod product_frunk; + +// #[cfg(not(feature = "frunk"))] +// #[macro_use] +// mod product_tuple; + +// #[macro_use] +// extern crate bitflags; +// #[cfg(feature = "bit-set")] +// extern crate bit_set; + +// #[cfg(feature = "std")] +// #[macro_use] +// extern crate lazy_static; + +// // Only required for the string module. +// #[cfg(feature = "std")] +// #[macro_use] +// extern crate quick_error; + +// #[cfg(feature = "fork")] +// #[macro_use] +// extern crate rusty_fork; + +// #[macro_use] +// mod macros; #[doc(hidden)] -#[macro_export] -macro_rules! proptest_helper { - (@_WRAP ($a:tt)) => { $a }; - (@_WRAP ($a0:tt $a1:tt)) => { ($a0, $a1) }; - (@_WRAP ($a0:tt $a1:tt $a2:tt)) => { ($a0, $a1, $a2) }; - (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt)) => { ($a0, $a1, $a2, $a3) }; - (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt)) => { - ($a0, $a1, $a2, $a3, $a4) - }; - (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt $a5:tt)) => { - ($a0, $a1, $a2, $a3, $a4, $a5) - }; - (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt $a5:tt $a6:tt)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6) - }; - (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt - $a4:tt $a5:tt $a6:tt $a7:tt)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7) - }; - (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt - $a5:tt $a6:tt $a7:tt $a8:tt)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8) - }; - (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt - $a5:tt $a6:tt $a7:tt $a8:tt $a9:tt)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9) - }; - (@_WRAP ($a:tt $($rest:tt)*)) => { - ($a, $crate::proptest_helper!(@_WRAP ($($rest)*))) - }; - (@_WRAPPAT ($item:pat)) => { $item }; - (@_WRAPPAT ($a0:pat, $a1:pat)) => { ($a0, $a1) }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat)) => { ($a0, $a1, $a2) }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat)) => { - ($a0, $a1, $a2, $a3) - }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat)) => { - ($a0, $a1, $a2, $a3, $a4) - }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, $a5:pat)) => { - ($a0, $a1, $a2, $a3, $a4, $a5) - }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, - $a4:pat, $a5:pat, $a6:pat)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6) - }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, - $a4:pat, $a5:pat, $a6:pat, $a7:pat)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7) - }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, - $a5:pat, $a6:pat, $a7:pat, $a8:pat)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8) - }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, - $a5:pat, $a6:pat, $a7:pat, $a8:pat, $a9:pat)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9) - }; - (@_WRAPPAT ($a:pat, $($rest:pat),*)) => { - ($a, $crate::proptest_helper!(@_WRAPPAT ($($rest),*))) - }; - (@_WRAPSTR ($item:pat)) => { stringify!($item) }; - (@_WRAPSTR ($a0:pat, $a1:pat)) => { (stringify!($a0), stringify!($a1)) }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2)) - }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3)) - }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2), - stringify!($a3), stringify!($a4)) - }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, $a5:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), - stringify!($a4), stringify!($a5)) - }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, - $a4:pat, $a5:pat, $a6:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), - stringify!($a4), stringify!($a5), stringify!($a6)) - }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, - $a4:pat, $a5:pat, $a6:pat, $a7:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), - stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7)) - }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, - $a5:pat, $a6:pat, $a7:pat, $a8:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), - stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7), - stringify!($a8)) - }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, - $a5:pat, $a6:pat, $a7:pat, $a8:pat, $a9:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), - stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7), - stringify!($a8), stringify!($a9)) - }; - (@_WRAPSTR ($a:pat, $($rest:pat),*)) => { - (stringify!($a), $crate::proptest_helper!(@_WRAPSTR ($($rest),*))) - }; - // build a property testing block that when executed, executes the full property test. - (@_BODY $config:ident ($($parm:pat in $strategy:expr),+) [$($mod:tt)*] $body:expr) => {{ - $config.source_file = Some(file!()); - let mut runner = $crate::test_runner::TestRunner::new($config); - let names = $crate::proptest_helper!(@_WRAPSTR ($($parm),*)); - match runner.run( - &$crate::strategy::Strategy::prop_map( - $crate::proptest_helper!(@_WRAP ($($strategy)*)), - |values| $crate::sugar::NamedArguments(names, values)), - $($mod)* |$crate::sugar::NamedArguments( - _, $crate::proptest_helper!(@_WRAPPAT ($($parm),*)))| - { - let _: () = $body; - Ok(()) - }) - { - Ok(_) => (), - Err(e) => panic!("{}\n{}", e, runner), - } - }}; - // build a property testing block that when executed, executes the full property test. - (@_BODY2 $config:ident ($($arg:tt)+) [$($mod:tt)*] $body:expr) => {{ - // $config.source_file = Some(file!()); - // let mut runner2 = $crate::test_runner::TestRunner::new($config); - // let names2 = $crate::proptest_helper!(@_EXT _STR ($($arg)*)); - // match runner2.run( - // &$crate::strategy::Strategy::prop_map( - // $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), - // |values| $crate::sugar::NamedArguments(names2, values)), - // $($mod)* |$crate::sugar::NamedArguments( - // _, $crate::proptest_helper!(@_EXT _PAT ($($arg)*)))| - // { - // let _: () = $body; - // Ok(()) - // }) - // { - // Ok(_) => (), - // Err(e) => panic!("{}\n{}", e, runner2), - // } - $crate::test_runner::TestRunner::run_kani( - $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), - |$crate::proptest_helper!(@_EXT _PAT ($($arg)*))| { - $body - } - ); - }}; - - // The logic below helps support `pat: type` in the proptest! macro. - - // These matchers define the actual logic: - (@_STRAT [$s:ty] [$p:pat]) => { $crate::arbitrary::any::<$s>() }; - (@_PAT [$s:ty] [$p:pat]) => { $p }; - (@_STR [$s:ty] [$p:pat]) => { stringify!($p) }; - (@_STRAT in [$s:expr] [$p:pat]) => { $s }; - (@_PAT in [$s:expr] [$p:pat]) => { $p }; - (@_STR in [$s:expr] [$p:pat]) => { stringify!($p) }; - - // These matchers rewrite into the above extractors. - // We have to do this because `:` can't FOLLOW(pat). - // Note that this is not the full `pat` grammar... - // See https://docs.rs/syn/0.14.2/syn/enum.Pat.html for that. - (@_EXT $cmd:ident ($p:pat in $s:expr $(,)?)) => { - $crate::proptest_helper!(@$cmd in [$s] [$p]) - }; - (@_EXT $cmd:ident (($p:pat) : $s:ty $(,)?)) => { - // Users can wrap in parens as a last resort. - $crate::proptest_helper!(@$cmd [$s] [$p]) - }; - (@_EXT $cmd:ident (_ : $s:ty $(,)?)) => { - $crate::proptest_helper!(@$cmd [$s] [_]) - }; - (@_EXT $cmd:ident (ref mut $p:ident : $s:ty $(,)?)) => { - $crate::proptest_helper!(@$cmd [$s] [ref mut $p]) - }; - (@_EXT $cmd:ident (ref $p:ident : $s:ty $(,)?)) => { - $crate::proptest_helper!(@$cmd [$s] [ref $p]) - }; - (@_EXT $cmd:ident (mut $p:ident : $s:ty $(,)?)) => { - $crate::proptest_helper!(@$cmd [$s] [mut $p]) - }; - (@_EXT $cmd:ident ($p:ident : $s:ty $(,)?)) => { - $crate::proptest_helper!(@$cmd [$s] [$p]) - }; - (@_EXT $cmd:ident ([$($p:tt)*] : $s:ty $(,)?)) => { - $crate::proptest_helper!(@$cmd [$s] [[$($p)*]]) - }; - - // Rewrite, Inductive case: - (@_EXT $cmd:ident ($p:pat in $s:expr, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd in [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; - (@_EXT $cmd:ident (($p:pat) : $s:ty, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; - (@_EXT $cmd:ident (_ : $s:ty, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd [$s] [_]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; - (@_EXT $cmd:ident (ref mut $p:ident : $s:ty, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd [$s] [ref mut $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; - (@_EXT $cmd:ident (ref $p:ident : $s:ty, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd [$s] [ref $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; - (@_EXT $cmd:ident (mut $p:ident : $s:ty, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd [$s] [mut $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; - (@_EXT $cmd:ident ($p:ident : $s:ty, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; - (@_EXT $cmd:ident ([$($p:tt)*] : $s:ty, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd [$s] [[$($p)*]]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; -} - -// macro_rules! named_arguments_tuple { -// ($($ix:tt $argn:ident $argv:ident)*) => { -// impl<'a, $($argn : Copy),*, $($argv),*> fmt::Debug -// for NamedArguments<($($argn,)*),&'a ($($argv,)*)> -// where $(NamedArguments<$argn, &'a $argv> : fmt::Debug),*, -// $($argv : 'a),* -// { -// #[allow(unused_assignments)] -// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -// let mut first = true; -// $( -// if !first { -// write!(f, ", ")?; -// } -// first = false; -// fmt::Debug::fmt( -// &NamedArguments((self.0).$ix, &(self.1).$ix), f)?; -// )* -// Ok(()) -// } -// } - -// impl<$($argn : Copy),*, $($argv),*> fmt::Debug -// for NamedArguments<($($argn,)*), ($($argv,)*)> -// where $(for<'a> NamedArguments<$argn, &'a $argv> : fmt::Debug),* -// { -// #[allow(unused_assignments)] -// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -// let mut first = true; -// $( -// if !first { -// write!(f, ", ")?; -// } -// first = false; -// fmt::Debug::fmt( -// &NamedArguments((self.0).$ix, &(self.1).$ix), f)?; -// )* -// Ok(()) -// } -// } -// } -// } - -// named_arguments_tuple!(0 AN AV); -// named_arguments_tuple!(0 AN AV 1 BN BV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV -// 5 FN FV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV -// 5 FN FV 6 GN GV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV -// 5 FN FV 6 GN GV 7 HN HV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV -// 5 FN FV 6 GN GV 7 HN HV 8 IN IV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV -// 5 FN FV 6 GN GV 7 HN HV 8 IN IV 9 JN JV); +#[macro_use] +pub mod sugar; + +// pub mod arbitrary; +// pub mod array; +// pub mod bits; +// pub mod bool; +// pub mod char; +// pub mod collection; +// pub mod num; +// pub mod strategy; +// pub mod test_runner; +// pub mod tuple; + +// pub mod option; +// pub mod result; +// pub mod sample; +// #[cfg(feature = "std")] +// pub mod string; + +// pub mod prelude; diff --git a/library/proptest/src/sugar.rs b/library/proptest/src/sugar.rs new file mode 100644 index 000000000000..ce69b91636f5 --- /dev/null +++ b/library/proptest/src/sugar.rs @@ -0,0 +1,1119 @@ +//- +// Copyright 2017, 2019 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// use crate::std_facade::fmt; + +/// Easily define `proptest` tests. +/// +/// Within `proptest!`, define one or more functions without return type +/// normally, except instead of putting `: type` after each parameter, write +/// `in strategy`, where `strategy` is an expression evaluating to some +/// `Strategy`. +/// +/// Each function will be wrapped in a function which sets up a `TestRunner`, +/// and then invokes the function body with inputs generated according to the +/// strategies. +/// +/// ### Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn test_addition(a in 0..10, b in 0..10) { +/// prop_assert!(a + b <= 18); +/// } +/// +/// # /* +/// #[test] +/// # */ +/// fn test_string_concat(a in ".*", b in ".*") { +/// let cat = format!("{}{}", a, b); +/// prop_assert_eq!(a.len() + b.len(), cat.len()); +/// } +/// } +/// # +/// # fn main() { test_addition(); test_string_concat(); } +/// ``` +/// +/// You can also use the normal argument syntax `pattern: type` as in: +/// +/// ```rust +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn addition_is_commutative(a: u8, b: u8) { +/// prop_assert_eq!(a as u16 + b as u16, b as u16 + a as u16); +/// } +/// +/// # /* +/// #[test] +/// # */ +/// fn test_string_concat(a in ".*", b: String) { +/// let cat = format!("{}{}", a, b); +/// prop_assert_eq!(a.len() + b.len(), cat.len()); +/// } +/// } +/// # +/// # fn main() { addition_is_commutative(); test_string_concat(); } +/// ``` +/// +/// As you can see, you can mix `pattern: type` and `pattern in expr`. +/// Due to limitations in `macro_rules!`, `pattern: type` does not work in +/// all circumstances. In such a case, use `(pattern): type` instead. +/// +/// To override the default configuration, you can start the `proptest!` block +/// with `#![proptest_config(expr)]`, where `expr` is an expression that +/// evaluates to a `proptest::test_runner::Config` (or a reference to one). +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// #![proptest_config(ProptestConfig { +/// cases: 99, .. ProptestConfig::default() +/// })] +/// # /* +/// #[test] +/// # */ +/// fn test_addition(a in 0..10, b in 0..10) { +/// prop_assert!(a + b <= 18); +/// } +/// } +/// # +/// # fn main() { test_addition(); } +/// ``` +/// +/// ## Closure-Style Invocation +/// +/// As of proptest 0.8.1, an alternative, "closure-style" invocation is +/// supported. In this form, `proptest!` is a function-like macro taking a +/// closure-esque argument. This makes it possible to run multiple tests that +/// require some expensive setup process. Note that the "fork" and "timeout" +/// features are _not_ supported in closure style. +/// +/// To use a custom configuration, pass the `Config` object as a first +/// argument. +/// +/// ### Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// #[derive(Debug)] +/// struct BigStruct { /* Lots of fields ... */ } +/// +/// fn very_expensive_function() -> BigStruct { +/// // Lots of code... +/// BigStruct { /* fields */ } +/// } +/// +/// # /* +/// #[test] +/// # */ +/// fn my_test() { +/// // We create just one `BigStruct` +/// let big_struct = very_expensive_function(); +/// +/// // But now can run multiple tests without needing to build it every time. +/// // Note the extra parentheses around the arguments are currently +/// // required. +/// proptest!(|(x in 0u32..42u32, y in 1000u32..100000u32)| { +/// // Test stuff +/// }); +/// +/// // `move` closures are also supported +/// proptest!(move |(x in 0u32..42u32)| { +/// // Test other stuff +/// }); +/// +/// // You can pass a custom configuration as the first argument +/// proptest!(ProptestConfig::with_cases(1000), |(x: i32)| { +/// // Test more stuff +/// }); +/// } +/// # +/// # fn main() { my_test(); } +/// ``` +#[macro_export] +macro_rules! proptest { + (#![proptest_config($config:expr)] + $( + $(#[$meta:meta])* + fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block + )*) => { + $( + #[kani::proof] + $(#[$meta])* + fn $test_name() { //rule meta_strategy + // let mut config = $config.clone(); + // config.test_name = Some( + // concat!(module_path!(), "::meta_strategy::", stringify!($test_name))); + $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body); + } + )* + }; + (#![proptest_config($config:expr)] + $( + $(#[$meta:meta])* + fn $test_name:ident($($arg:tt)+) $body:block + )*) => { + $( + #[kani::proof] + $(#[$meta])* + fn $test_name() { //rule meta_type + // let mut config = $config.clone(); + // config.test_name = Some( + // concat!(module_path!(), "::meta_type::", stringify!($test_name))); + $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); + } + )* + }; + + ($( + $(#[$meta:meta])* + fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block + )*) => { $crate::proptest! { + #![proptest_config($crate::test_runner::Config::default())] + $($(#[$meta])* + fn $test_name($($parm in $strategy),+) $body)* + } }; + + ($( + $(#[$meta:meta])* + fn $test_name:ident($($arg:tt)+) $body:block + )*) => { $crate::proptest! { + #![proptest_config($crate::test_runner::Config::default())] + $($(#[$meta])* + fn $test_name($($arg)+) $body)* + } }; + + (|($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + |($($parm in $strategy),+)| $body) + }; + + (move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + move |($($parm in $strategy),+)| $body) + }; + + (|($($arg:tt)+)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + |($($arg)+)| $body) + }; + + (move |($($arg:tt)+)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + move |($($arg)+)| $body) + }; + + ($config:expr, |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body) + } }; + + ($config:expr, move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [move] $body) + } }; + + ($config:expr, |($($arg:tt)+)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); + } }; + + ($config:expr, move |($($arg:tt)+)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY2 config ($($arg)+) [move] $body); + } }; +} + +/// Rejects the test input if assumptions are not met. +/// +/// Used directly within a function defined with `proptest!` or in any function +/// returning `Result<_, TestCaseError>`. +/// +/// This is invoked as `prop_assume!(condition, format, args...)`. `condition` +/// is evaluated; if it is false, `Err(TestCaseError::Reject)` is returned. The +/// message includes the point of invocation and the format message. `format` +/// and `args` may be omitted to simply use the condition itself as the +/// message. +#[macro_export] +macro_rules! prop_assume { + ($expr:expr) => { + $crate::prop_assume!($expr, "{}", stringify!($expr)) + }; + + ($expr:expr, $fmt:tt $(, $fmt_arg:expr),* $(,)?) => { + if !$expr { + return ::core::result::Result::Err( + $crate::test_runner::TestCaseError::reject( + format!(concat!("{}:{}:{}: ", $fmt), + file!(), line!(), column!() + $(, $fmt_arg)*))); + } + }; +} + +/// Produce a strategy which picks one of the listed choices. +/// +/// This is conceptually equivalent to calling `prop_union` on the first two +/// elements and then chaining `.or()` onto the rest after implicitly boxing +/// all of them. As with `Union`, values shrink across elements on the +/// assumption that earlier ones are "simpler", so they should be listed in +/// order of ascending complexity when possible. +/// +/// The macro invocation has two forms. The first is to simply list the +/// strategies separated by commas; this will cause value generation to pick +/// from the strategies uniformly. The other form is to provide a weight in the +/// form of a `u32` before each strategy, separated from the strategy with +/// `=>`. +/// +/// Note that the exact type returned by the macro varies depending on how many +/// inputs there are. In particular, if given exactly one option, it will +/// return it unmodified. It is not recommended to depend on the particular +/// type produced by this macro. +/// +/// ## Example +/// +/// ```rust,no_run +/// use proptest::prelude::*; +/// +/// #[derive(Clone, Copy, Debug)] +/// enum MyEnum { +/// Big(u64), +/// Medium(u32), +/// Little(i16), +/// } +/// +/// # #[allow(unused_variables)] +/// # fn main() { +/// let my_enum_strategy = prop_oneof![ +/// prop::num::i16::ANY.prop_map(MyEnum::Little), +/// prop::num::u32::ANY.prop_map(MyEnum::Medium), +/// prop::num::u64::ANY.prop_map(MyEnum::Big), +/// ]; +/// +/// let my_weighted_strategy = prop_oneof![ +/// 1 => prop::num::i16::ANY.prop_map(MyEnum::Little), +/// // Chose `Medium` twice as frequently as either `Little` or `Big`; i.e., +/// // around 50% of values will be `Medium`, and 25% for each of `Little` +/// // and `Big`. +/// 2 => prop::num::u32::ANY.prop_map(MyEnum::Medium), +/// 1 => prop::num::u64::ANY.prop_map(MyEnum::Big), +/// ]; +/// # } +/// ``` +#[macro_export] +macro_rules! prop_oneof { + ($($item:expr),+ $(,)?) => { + $crate::prop_oneof![ + $(1 => $item),* + ] + }; + + ($_weight0:expr => $item0:expr $(,)?) => { $item0 }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)), + ($weight7, $crate::std_facade::Arc::new($item7)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr, + $weight8:expr => $item8:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)), + ($weight7, $crate::std_facade::Arc::new($item7)), + ($weight8, $crate::std_facade::Arc::new($item8)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr, + $weight8:expr => $item8:expr, + $weight9:expr => $item9:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)), + ($weight7, $crate::std_facade::Arc::new($item7)), + ($weight8, $crate::std_facade::Arc::new($item8)), + ($weight9, $crate::std_facade::Arc::new($item9)))) + }; + + ($($weight:expr => $item:expr),+ $(,)?) => { + $crate::strategy::Union::new_weighted(vec![ + $(($weight, $crate::strategy::Strategy::boxed($item))),* + ]) + }; +} + +/// Convenience to define functions which produce new strategies. +/// +/// The macro has two general forms. In the first, you define a function with +/// two argument lists. The first argument list uses the usual syntax and +/// becomes exactly the argument list of the defined function. The second +/// argument list uses the `in strategy` syntax as with `proptest!`, and is +/// used to generate the other inputs for the function. The second argument +/// list has access to all arguments in the first. The return type indicates +/// the type of value being generated; the final return type of the function is +/// `impl Strategy`. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// use proptest::prelude::*; +/// +/// #[derive(Clone, Debug)] +/// struct MyStruct { +/// integer: u32, +/// string: String, +/// } +/// +/// prop_compose! { +/// fn my_struct_strategy(max_integer: u32) +/// (integer in 0..max_integer, string in ".*") +/// -> MyStruct { +/// MyStruct { integer, string } +/// } +/// } +/// # +/// # fn main() { } +/// ``` +/// +/// This form is simply sugar around making a tuple and then calling `prop_map` +/// on it. You can also use `arg: type` as in `proptest! { .. }`: +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// # use proptest::prelude::*; +/// # +/// # #[derive(Clone, Debug)] +/// # struct MyStruct { +/// # integer: u32, +/// # string: String, +/// # } +/// +/// prop_compose! { +/// fn my_struct_strategy(max_integer: u32) +/// (integer in 0..max_integer, string: String) +/// -> MyStruct { +/// MyStruct { integer, string } +/// } +/// } +/// # +/// # fn main() { } +/// ``` +/// +/// The second form is mostly the same, except that it takes _three_ argument +/// lists. The third argument list can see all values in both prior, which +/// permits producing strategies based on other strategies. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// use proptest::prelude::*; +/// +/// prop_compose! { +/// fn nearby_numbers()(centre in -1000..1000) +/// (a in centre-10..centre+10, +/// b in centre-10..centre+10) +/// -> (i32, i32) { +/// (a, b) +/// } +/// } +/// # +/// # fn main() { } +/// ``` +/// +/// However, the body of the function does _not_ have access to the second +/// argument list. If the body needs access to those values, they must be +/// passed through explicitly. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// use proptest::prelude::*; +/// +/// prop_compose! { +/// fn vec_and_index +/// (max_length: usize) +/// (vec in prop::collection::vec(1..10, 1..max_length)) +/// (index in 0..vec.len(), vec in Just(vec)) +/// -> (Vec, usize) +/// { +/// (vec, index) +/// } +/// } +/// # fn main() { } +/// ``` +/// +/// The second form is sugar around making a strategy tuple, calling +/// `prop_flat_map()`, then `prop_map()`. +/// +/// To give the function any modifier which isn't a visibility modifier, put it +/// in brackets before the `fn` token but after any visibility modifier. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// use proptest::prelude::*; +/// +/// prop_compose! { +/// pub(crate) [unsafe] fn pointer()(v in prop::num::usize::ANY) +/// -> *const () { +/// v as *const () +/// } +/// } +/// # fn main() { } +/// ``` +/// +/// ## Comparison with Hypothesis' `@composite` +/// +/// `prop_compose!` makes it easy to do a lot of things you can do with +/// [Hypothesis' `@composite`](https://hypothesis.readthedocs.io/en/latest/data.html#composite-strategies), +/// but not everything. +/// +/// - You can't filter via this macro. For filtering, you need to make the +/// strategy the "normal" way and use `prop_filter()`. +/// +/// - More than two layers of strategies or arbitrary logic between the two +/// layers. If you need either of these, you can achieve them by calling +/// `prop_flat_map()` by hand. +#[macro_export] +macro_rules! prop_compose { + ($(#[$meta:meta])* + $vis:vis + $([$($modi:tt)*])? fn $name:ident $params:tt + ($($var:pat in $strategy:expr),+ $(,)?) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $vis + $($($modi)*)? fn $name $params + -> impl $crate::strategy::Strategy { + let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); + $crate::strategy::Strategy::prop_map(strat, + move |$crate::proptest_helper!(@_WRAPPAT ($($var),*))| $body) + } + }; + + ($(#[$meta:meta])* + $vis:vis + $([$($modi:tt)*])? fn $name:ident $params:tt + ($($var:pat in $strategy:expr),+ $(,)?) + ($($var2:pat in $strategy2:expr),+ $(,)?) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $vis + $($($modi)*)? fn $name $params + -> impl $crate::strategy::Strategy { + let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); + let strat = $crate::strategy::Strategy::prop_flat_map( + strat, + move |$crate::proptest_helper!(@_WRAPPAT ($($var),*))| + $crate::proptest_helper!(@_WRAP ($($strategy2)*))); + $crate::strategy::Strategy::prop_map(strat, + move |$crate::proptest_helper!(@_WRAPPAT ($($var2),*))| $body) + } + }; + + ($(#[$meta:meta])* + $vis:vis + $([$($modi:tt)*])? fn $name:ident $params:tt + ($($arg:tt)+) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $vis + $($($modi)*)? fn $name $params + -> impl $crate::strategy::Strategy { + let strat = $crate::proptest_helper!(@_EXT _STRAT ($($arg)+)); + $crate::strategy::Strategy::prop_map(strat, + move |$crate::proptest_helper!(@_EXT _PAT ($($arg)+))| $body) + } + }; + + ($(#[$meta:meta])* + $vis:vis + $([$($modi:tt)*])? fn $name:ident $params:tt + ($($arg:tt)+ $(,)?) + ($($arg2:tt)+ $(,)?) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $vis + $($($modi)*)? fn $name $params + -> impl $crate::strategy::Strategy { + let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); + let strat = $crate::strategy::Strategy::prop_flat_map( + strat, + move |$crate::proptest_helper!(@_EXT _PAT ($($arg)+))| + $crate::proptest_helper!(@_EXT _STRAT ($($arg2)*))); + $crate::strategy::Strategy::prop_map(strat, + move |$crate::proptest_helper!(@_EXT _PAT ($($arg2)*))| $body) + } + }; +} + +/// Similar to `assert!` from std, but returns a test failure instead of +/// panicking if the condition fails. +/// +/// This can be used in any function that returns a `Result<_, TestCaseError>`, +/// including the top-level function inside `proptest!`. +/// +/// Both panicking via `assert!` and returning a test case failure have the +/// same effect as far as proptest is concerned; however, the Rust runtime +/// implicitly prints every panic to stderr by default (including a backtrace +/// if enabled), which can make test failures unnecessarily noisy. By using +/// `prop_assert!` instead, the only output on a failing test case is the final +/// panic including the minimal test case. +/// +/// ## Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn triangle_inequality(a in 0.0f64..10.0, b in 0.0f64..10.0) { +/// // Called with just a condition will print the condition on failure +/// prop_assert!((a*a + b*b).sqrt() <= a + b); +/// // You can also provide a custom failure message +/// prop_assert!((a*a + b*b).sqrt() <= a + b, +/// "Triangle inequality didn't hold for ({}, {})", a, b); +/// // If calling another function that can return failure, don't forget +/// // the `?` to propagate the failure. +/// assert_from_other_function(a, b)?; +/// } +/// } +/// +/// // The macro can be used from another function provided it has a compatible +/// // return type. +/// fn assert_from_other_function(a: f64, b: f64) -> Result<(), TestCaseError> { +/// prop_assert!((a*a + b*b).sqrt() <= a + b); +/// Ok(()) +/// } +/// # +/// # fn main() { triangle_inequality(); } +/// ``` +#[macro_export] +macro_rules! prop_assert { + ($cond:expr) => { + $crate::prop_assert!($cond, concat!("assertion failed: ", stringify!($cond))) + }; + + ($cond:expr, $($fmt:tt)*) => { + if !$cond { + let message = format!($($fmt)*); + let message = format!("{} at {}:{}", message, file!(), line!()); + return ::core::result::Result::Err( + $crate::test_runner::TestCaseError::fail(message)); + } + }; +} + +/// Similar to `assert_eq!` from std, but returns a test failure instead of +/// panicking if the condition fails. +/// +/// See `prop_assert!` for a more in-depth discussion. +/// +/// ## Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn concat_string_length(ref a in ".*", ref b in ".*") { +/// let cat = format!("{}{}", a, b); +/// // Use with default message +/// prop_assert_eq!(a.len() + b.len(), cat.len()); +/// // Can also provide custom message (added after the normal +/// // assertion message) +/// prop_assert_eq!(a.len() + b.len(), cat.len(), +/// "a = {:?}, b = {:?}", a, b); +/// } +/// } +/// # +/// # fn main() { concat_string_length(); } +/// ``` +#[macro_export] +macro_rules! prop_assert_eq { + ($left:expr, $right:expr) => {{ + let left = $left; + let right = $right; + $crate::prop_assert!( + left == right, + "assertion failed: `(left == right)` \ + \n left: `{:?}`,\n right: `{:?}`", + left, right); + }}; + + ($left:expr, $right:expr, $fmt:tt $($args:tt)*) => {{ + let left = $left; + let right = $right; + $crate::prop_assert!( + left == right, + concat!( + "assertion failed: `(left == right)` \ + \n left: `{:?}`, \n right: `{:?}`: ", $fmt), + left, right $($args)*); + }}; +} + +/// Similar to `assert_ne!` from std, but returns a test failure instead of +/// panicking if the condition fails. +/// +/// See `prop_assert!` for a more in-depth discussion. +/// +/// ## Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn test_addition(a in 0i32..100i32, b in 1i32..100i32) { +/// // Use with default message +/// prop_assert_ne!(a, a + b); +/// // Can also provide custom message added after the common message +/// prop_assert_ne!(a, a + b, "a = {}, b = {}", a, b); +/// } +/// } +/// # +/// # fn main() { test_addition(); } +/// ``` +#[macro_export] +macro_rules! prop_assert_ne { + ($left:expr, $right:expr) => {{ + let left = $left; + let right = $right; + prop_assert!( + left != right, + "assertion failed: `(left != right)`\ + \n left: `{:?}`,\n right: `{:?}`", + left, right); + }}; + + ($left:expr, $right:expr, $fmt:tt $($args:tt)*) => {{ + let left = $left; + let right = $right; + prop_assert!(left != right, concat!( + "assertion failed: `(left != right)`\ + \n left: `{:?}`,\n right: `{:?}`: ", $fmt), + left, right $($args)*); + }}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! proptest_helper { + (@_WRAP ($a:tt)) => { $a }; + (@_WRAP ($a0:tt $a1:tt)) => { ($a0, $a1) }; + (@_WRAP ($a0:tt $a1:tt $a2:tt)) => { ($a0, $a1, $a2) }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt)) => { ($a0, $a1, $a2, $a3) }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt)) => { + ($a0, $a1, $a2, $a3, $a4) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt $a5:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt $a5:tt $a6:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt + $a4:tt $a5:tt $a6:tt $a7:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt + $a5:tt $a6:tt $a7:tt $a8:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt + $a5:tt $a6:tt $a7:tt $a8:tt $a9:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9) + }; + (@_WRAP ($a:tt $($rest:tt)*)) => { + ($a, $crate::proptest_helper!(@_WRAP ($($rest)*))) + }; + (@_WRAPPAT ($item:pat)) => { $item }; + (@_WRAPPAT ($a0:pat, $a1:pat)) => { ($a0, $a1) }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat)) => { ($a0, $a1, $a2) }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat)) => { + ($a0, $a1, $a2, $a3) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat)) => { + ($a0, $a1, $a2, $a3, $a4) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, $a5:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat, $a7:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat, $a9:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9) + }; + (@_WRAPPAT ($a:pat, $($rest:pat),*)) => { + ($a, $crate::proptest_helper!(@_WRAPPAT ($($rest),*))) + }; + (@_WRAPSTR ($item:pat)) => { stringify!($item) }; + (@_WRAPSTR ($a0:pat, $a1:pat)) => { (stringify!($a0), stringify!($a1)) }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), + stringify!($a3), stringify!($a4)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, $a5:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat, $a7:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7), + stringify!($a8)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat, $a9:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7), + stringify!($a8), stringify!($a9)) + }; + (@_WRAPSTR ($a:pat, $($rest:pat),*)) => { + (stringify!($a), $crate::proptest_helper!(@_WRAPSTR ($($rest),*))) + }; + // build a property testing block that when executed, executes the full property test. + (@_BODY $config:ident ($($parm:pat in $strategy:expr),+) [$($mod:tt)*] $body:expr) => {{ + $config.source_file = Some(file!()); + let mut runner = $crate::test_runner::TestRunner::new($config); + let names = $crate::proptest_helper!(@_WRAPSTR ($($parm),*)); + match runner.run( + &$crate::strategy::Strategy::prop_map( + $crate::proptest_helper!(@_WRAP ($($strategy)*)), + |values| $crate::sugar::NamedArguments(names, values)), + $($mod)* |$crate::sugar::NamedArguments( + _, $crate::proptest_helper!(@_WRAPPAT ($($parm),*)))| + { + let _: () = $body; + Ok(()) + }) + { + Ok(_) => (), + Err(e) => panic!("{}\n{}", e, runner), + } + }}; + // build a property testing block that when executed, executes the full property test. + (@_BODY2 $config:ident ($($arg:tt)+) [$($mod:tt)*] $body:expr) => {{ + // $config.source_file = Some(file!()); + // let mut runner2 = $crate::test_runner::TestRunner::new($config); + // let names2 = $crate::proptest_helper!(@_EXT _STR ($($arg)*)); + // match runner2.run( + // &$crate::strategy::Strategy::prop_map( + // $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), + // |values| $crate::sugar::NamedArguments(names2, values)), + // $($mod)* |$crate::sugar::NamedArguments( + // _, $crate::proptest_helper!(@_EXT _PAT ($($arg)*)))| + // { + // let _: () = $body; + // Ok(()) + // }) + // { + // Ok(_) => (), + // Err(e) => panic!("{}\n{}", e, runner2), + // } + $crate::test_runner::TestRunner::run_kani( + $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), + |$crate::proptest_helper!(@_EXT _PAT ($($arg)*))| { + $body + } + ); + }}; + + // The logic below helps support `pat: type` in the proptest! macro. + + // These matchers define the actual logic: + (@_STRAT [$s:ty] [$p:pat]) => { $crate::arbitrary::any::<$s>() }; + (@_PAT [$s:ty] [$p:pat]) => { $p }; + (@_STR [$s:ty] [$p:pat]) => { stringify!($p) }; + (@_STRAT in [$s:expr] [$p:pat]) => { $s }; + (@_PAT in [$s:expr] [$p:pat]) => { $p }; + (@_STR in [$s:expr] [$p:pat]) => { stringify!($p) }; + + // These matchers rewrite into the above extractors. + // We have to do this because `:` can't FOLLOW(pat). + // Note that this is not the full `pat` grammar... + // See https://docs.rs/syn/0.14.2/syn/enum.Pat.html for that. + (@_EXT $cmd:ident ($p:pat in $s:expr $(,)?)) => { + $crate::proptest_helper!(@$cmd in [$s] [$p]) + }; + (@_EXT $cmd:ident (($p:pat) : $s:ty $(,)?)) => { + // Users can wrap in parens as a last resort. + $crate::proptest_helper!(@$cmd [$s] [$p]) + }; + (@_EXT $cmd:ident (_ : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [_]) + }; + (@_EXT $cmd:ident (ref mut $p:ident : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [ref mut $p]) + }; + (@_EXT $cmd:ident (ref $p:ident : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [ref $p]) + }; + (@_EXT $cmd:ident (mut $p:ident : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [mut $p]) + }; + (@_EXT $cmd:ident ($p:ident : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [$p]) + }; + (@_EXT $cmd:ident ([$($p:tt)*] : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [[$($p)*]]) + }; + + // Rewrite, Inductive case: + (@_EXT $cmd:ident ($p:pat in $s:expr, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd in [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (($p:pat) : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (_ : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [_]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (ref mut $p:ident : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [ref mut $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (ref $p:ident : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [ref $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (mut $p:ident : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [mut $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident ($p:ident : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident ([$($p:tt)*] : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [[$($p)*]]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; +} + +// macro_rules! named_arguments_tuple { +// ($($ix:tt $argn:ident $argv:ident)*) => { +// impl<'a, $($argn : Copy),*, $($argv),*> fmt::Debug +// for NamedArguments<($($argn,)*),&'a ($($argv,)*)> +// where $(NamedArguments<$argn, &'a $argv> : fmt::Debug),*, +// $($argv : 'a),* +// { +// #[allow(unused_assignments)] +// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +// let mut first = true; +// $( +// if !first { +// write!(f, ", ")?; +// } +// first = false; +// fmt::Debug::fmt( +// &NamedArguments((self.0).$ix, &(self.1).$ix), f)?; +// )* +// Ok(()) +// } +// } + +// impl<$($argn : Copy),*, $($argv),*> fmt::Debug +// for NamedArguments<($($argn,)*), ($($argv,)*)> +// where $(for<'a> NamedArguments<$argn, &'a $argv> : fmt::Debug),* +// { +// #[allow(unused_assignments)] +// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +// let mut first = true; +// $( +// if !first { +// write!(f, ", ")?; +// } +// first = false; +// fmt::Debug::fmt( +// &NamedArguments((self.0).$ix, &(self.1).$ix), f)?; +// )* +// Ok(()) +// } +// } +// } +// } + +// named_arguments_tuple!(0 AN AV); +// named_arguments_tuple!(0 AN AV 1 BN BV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV +// 5 FN FV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV +// 5 FN FV 6 GN GV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV +// 5 FN FV 6 GN GV 7 HN HV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV +// 5 FN FV 6 GN GV 7 HN HV 8 IN IV); +// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV +// 5 FN FV 6 GN GV 7 HN HV 8 IN IV 9 JN JV); From e3e4226c048bea5cfcbb8057a4027a2ce19460d6 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 18 Jul 2022 16:32:34 -0400 Subject: [PATCH 20/80] Supported Minimum Strategy. --- library/proptest/src/lib.rs | 8 +- library/proptest/src/std_facade.rs | 74 ++ library/proptest/src/strategy/mod.rs | 37 + library/proptest/src/strategy/traits.rs | 1025 ++++++++++++++++++++ library/proptest/src/test_runner/config.rs | 448 +++++++++ library/proptest/src/test_runner/mod.rs | 15 + library/proptest/src/test_runner/reason.rs | 54 ++ library/proptest/src/test_runner/runner.rs | 29 + 8 files changed, 1686 insertions(+), 4 deletions(-) create mode 100644 library/proptest/src/std_facade.rs create mode 100644 library/proptest/src/strategy/mod.rs create mode 100644 library/proptest/src/strategy/traits.rs create mode 100644 library/proptest/src/test_runner/config.rs create mode 100644 library/proptest/src/test_runner/mod.rs create mode 100644 library/proptest/src/test_runner/reason.rs create mode 100644 library/proptest/src/test_runner/runner.rs diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index 68074bba04b4..563015942734 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -16,7 +16,7 @@ #![forbid(future_incompatible)] #![deny(missing_docs, bare_trait_objects)] -#![no_std] +// #![no_std] #![cfg_attr(feature = "cargo-clippy", allow( doc_markdown, // We have a lot of these lints for associated types... And we don't care. @@ -32,7 +32,7 @@ // // std_facade is used in a few macros, so it needs to be public. // #[macro_use] // #[doc(hidden)] -// pub mod std_facade; +pub mod std_facade; // #[cfg(any(feature = "std", test))] // #[macro_use] @@ -86,8 +86,8 @@ pub mod sugar; // pub mod char; // pub mod collection; // pub mod num; -// pub mod strategy; -// pub mod test_runner; +pub mod strategy; +pub mod test_runner; // pub mod tuple; // pub mod option; diff --git a/library/proptest/src/std_facade.rs b/library/proptest/src/std_facade.rs new file mode 100644 index 000000000000..c7734bd17bcc --- /dev/null +++ b/library/proptest/src/std_facade.rs @@ -0,0 +1,74 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! This module provides #[cfg(..)]ed type aliases over features. + +macro_rules! multiplex_alloc { + ($($alloc: path, $std: path),*) => { + $( + // #[cfg(all(feature = "alloc", not(feature = "std")))] + // pub use $alloc; + // #[cfg(feature = "std")] + pub use $std; + )* + }; +} + +macro_rules! multiplex_core { + ($($core: path, $std: path),*) => { + $( + // #[cfg(not(feature = "std"))] + // pub use $core; + // #[cfg(feature = "std")] + pub use $std; + )* + }; +} + +multiplex_alloc! { + alloc::borrow::Cow, ::std::borrow::Cow, + alloc::borrow::ToOwned, ::std::borrow::ToOwned, + alloc::boxed::Box, ::std::boxed::Box, + alloc::string::String, ::std::string::String, + alloc::string, ::std::string, + alloc::sync::Arc, ::std::sync::Arc, + alloc::rc::Rc, ::std::rc::Rc, + alloc::vec::Vec, ::std::vec::Vec, + alloc::vec, ::std::vec, + alloc::collections::VecDeque, std::collections::VecDeque, + alloc::collections::vec_deque, std::collections::vec_deque, + alloc::collections::BinaryHeap, ::std::collections::BinaryHeap, + alloc::collections::binary_heap, ::std::collections::binary_heap, + alloc::collections::LinkedList, ::std::collections::LinkedList, + alloc::collections::linked_list, ::std::collections::linked_list, + alloc::collections::BTreeSet, ::std::collections::BTreeSet, + alloc::collections::BTreeMap, ::std::collections::BTreeMap, + alloc::collections::btree_map, ::std::collections::btree_map, + alloc::collections::btree_set, ::std::collections::btree_set +} + +#[cfg(feature = "std")] +multiplex_alloc! { + hashmap_core::HashMap, ::std::collections::HashMap, + hashmap_core::HashSet, ::std::collections::HashSet +} + +//#[cfg(not(feature = "std"))] +//pub(crate) use hashmap_core::map as hash_map; +#[cfg(feature = "std")] +pub use ::std::collections::hash_map; +//#[cfg(not(feature = "std"))] +//pub(crate) use hashmap_core::set as hash_set; +#[cfg(feature = "std")] +pub use ::std::collections::hash_set; + +multiplex_core! { + core::fmt, ::std::fmt, + core::cell::Cell, ::std::cell::Cell +} diff --git a/library/proptest/src/strategy/mod.rs b/library/proptest/src/strategy/mod.rs new file mode 100644 index 000000000000..4fcf3772562a --- /dev/null +++ b/library/proptest/src/strategy/mod.rs @@ -0,0 +1,37 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Defines the core traits used by Proptest. + +// mod filter; +// mod filter_map; +// mod flatten; +// mod fuse; +// mod just; +// mod lazy; +// mod map; +// mod recursive; +// mod shuffle; +mod traits; +// mod unions; + +// pub use self::filter::*; +// pub use self::filter_map::*; +// pub use self::flatten::*; +// pub use self::fuse::*; +// pub use self::just::*; +// pub use self::lazy::*; +// pub use self::lazy::*; +// pub use self::map::*; +// pub use self::recursive::*; +// pub use self::shuffle::*; +pub use self::traits::*; +// pub use self::unions::*; + +// pub mod statics; diff --git a/library/proptest/src/strategy/traits.rs b/library/proptest/src/strategy/traits.rs new file mode 100644 index 000000000000..0b582437df78 --- /dev/null +++ b/library/proptest/src/strategy/traits.rs @@ -0,0 +1,1025 @@ +// Copyright Kani Contributors, the proptest developers +// SPDX-License-Identifier: Apache-2.0 OR MIT + +//! This file defines the strategy trait, which replaces +//! proptest::strategy::Strategy + + +use crate::std_facade::{fmt, Arc, Box, Rc}; +use core::cmp; + +// use crate::strategy::*; +use crate::test_runner::*; + +//============================================================================== +// Traits +//============================================================================== + +/// A new [`ValueTree`] from a [`Strategy`] when [`Ok`] or otherwise [`Err`] +/// when a new value-tree can not be produced for some reason such as +/// in the case of filtering with a predicate which always returns false. +/// You should pass in your strategy as the type parameter. +/// +/// [`Strategy`]: trait.Strategy.html +/// [`ValueTree`]: trait.ValueTree.html +/// [`Ok`]: https://doc.rust-lang.org/nightly/std/result/enum.Result.html#variant.Ok +/// [`Err`]: https://doc.rust-lang.org/nightly/std/result/enum.Result.html#variant.Err +pub type NewTree = Result<::Tree, Reason>; + +/// A strategy for producing arbitrary values of a given type. +/// +/// `fmt::Debug` is a hard requirement for all strategies currently due to +/// `prop_flat_map()`. This constraint will be removed when specialisation +/// becomes stable. +#[must_use = "strategies do nothing unless used"] +pub trait Strategy: fmt::Debug { + /// The value tree generated by this `Strategy`. + type Tree: ValueTree; + + /// The type of value used by functions under test generated by this Strategy. + /// + /// This corresponds to the same type as the associated type `Value` + /// in `Self::Tree`. It is provided here to simplify usage particularly + /// in conjunction with `-> impl Strategy`. + type Value: fmt::Debug; + + /// Generate a new value tree from the given runner. + /// + /// This may fail if there are constraints on the generated value and the + /// generator is unable to produce anything that satisfies them. Any + /// failure is wrapped in `TestError::Abort`. + /// + /// This method is generally expected to be deterministic. That is, given a + /// `TestRunner` with its RNG in a particular state, this should produce an + /// identical `ValueTree` every time. Non-deterministic strategies do not + /// cause problems during normal operation, but they do break failure + /// persistence since it is implemented by simply saving the seed used to + /// generate the test case. + fn new_tree(&self, runner: &mut TestRunner) -> NewTree; + + // /// Returns a strategy which produces values transformed by the function + // /// `fun`. + // /// + // /// There is no need (or possibility, for that matter) to define how the + // /// output is to be shrunken. Shrinking continues to take place in terms of + // /// the source value. + // /// + // /// `fun` should be a deterministic function. That is, for a given input + // /// value, it should produce an equivalent output value on every call. + // /// Proptest assumes that it can call the function as many times as needed + // /// to generate as many identical values as needed. For this reason, `F` is + // /// `Fn` rather than `FnMut`. + // fn prop_map O>(self, fun: F) -> Map + // where + // Self: Sized, + // { + // Map { source: self, fun: Arc::new(fun) } + // } + + // /// Returns a strategy which produces values of type `O` by transforming + // /// `Self` with `Into`. + // /// + // /// You should always prefer this operation instead of `prop_map` when + // /// you can as it is both clearer and also currently more efficient. + // /// + // /// There is no need (or possibility, for that matter) to define how the + // /// output is to be shrunken. Shrinking continues to take place in terms of + // /// the source value. + // fn prop_map_into(self) -> MapInto + // where + // Self: Sized, + // Self::Value: Into, + // { + // MapInto::new(self) + // } + + // /// Returns a strategy which produces values transformed by the function + // /// `fun`, which is additionally given a random number generator. + // /// + // /// This is exactly like `prop_map()` except for the addition of the second + // /// argument to the function. This allows introducing chaotic variations to + // /// generated values that are not easily expressed otherwise while allowing + // /// shrinking to proceed reasonably. + // /// + // /// During shrinking, `fun` is always called with an identical random + // /// number generator, so if it is a pure function it will always perform + // /// the same perturbation. + // /// + // /// ## Example + // /// + // /// ``` + // /// // The prelude also gets us the `Rng` trait. + // /// use proptest::prelude::*; + // /// + // /// proptest! { + // /// #[test] + // /// fn test_something(a in (0i32..10).prop_perturb( + // /// // Perturb the integer `a` (range 0..10) to a pair of that + // /// // integer and another that's ± 10 of it. + // /// // Note that this particular case would be better implemented as + // /// // `(0i32..10, -10i32..10).prop_map(|(a, b)| (a, a + b))` + // /// // but is shown here for simplicity. + // /// |centre, rng| (centre, centre + rng.gen_range(-10, 10)))) + // /// { + // /// // Test stuff + // /// } + // /// } + // /// # fn main() { } + // /// ``` + // fn prop_perturb O>( + // self, + // fun: F, + // ) -> Perturb + // where + // Self: Sized, + // { + // Perturb { source: self, fun: Arc::new(fun) } + // } + + // /// Maps values produced by this strategy into new strategies and picks + // /// values from those strategies. + // /// + // /// `fun` is used to transform the values produced by this strategy into + // /// other strategies. Values are then chosen from the derived strategies. + // /// Shrinking proceeds by shrinking individual values as well as shrinking + // /// the input used to generate the internal strategies. + // /// + // /// ## Shrinking + // /// + // /// In the case of test failure, shrinking will not only shrink the output + // /// from the combinator itself, but also the input, i.e., the strategy used + // /// to generate the output itself. Doing this requires searching the new + // /// derived strategy for a new failing input. The combinator will generate + // /// up to `Config::cases` values for this search. + // /// + // /// As a result, nested `prop_flat_map`/`Flatten` combinators risk + // /// exponential run time on this search for new failing values. To ensure + // /// that test failures occur within a reasonable amount of time, all of + // /// these combinators share a single "flat map regen" counter, and will + // /// stop generating new values if it exceeds `Config::max_flat_map_regens`. + // /// + // /// ## Example + // /// + // /// Generate two integers, where the second is always less than the first, + // /// without using filtering: + // /// + // /// ``` + // /// use proptest::prelude::*; + // /// + // /// proptest! { + // /// # /* + // /// #[test] + // /// # */ + // /// fn test_two( + // /// // Pick integers in the 1..65536 range, and derive a strategy + // /// // which emits a tuple of that integer and another one which is + // /// // some value less than it. + // /// (a, b) in (1..65536).prop_flat_map(|a| (Just(a), 0..a)) + // /// ) { + // /// prop_assert!(b < a); + // /// } + // /// } + // /// # + // /// # fn main() { test_two(); } + // /// ``` + // /// + // /// ## Choosing the right flat-map + // /// + // /// `Strategy` has three "flat-map" combinators. They look very similar at + // /// first, and can be used to produce superficially identical test results. + // /// For example, the following three expressions all produce inputs which + // /// are 2-tuples `(a,b)` where the `b` component is less than `a`. + // /// + // /// ```no_run + // /// # #![allow(unused_variables)] + // /// use proptest::prelude::*; + // /// + // /// let flat_map = (1..10).prop_flat_map(|a| (Just(a), 0..a)); + // /// let ind_flat_map = (1..10).prop_ind_flat_map(|a| (Just(a), 0..a)); + // /// let ind_flat_map2 = (1..10).prop_ind_flat_map2(|a| 0..a); + // /// ``` + // /// + // /// The three do differ however in terms of how they shrink. + // /// + // /// For `flat_map`, both `a` and `b` will shrink, and the invariant that + // /// `b < a` is maintained. This is a "dependent" or "higher-order" strategy + // /// in that it remembers that the strategy for choosing `b` is dependent on + // /// the value chosen for `a`. + // /// + // /// For `ind_flat_map`, the invariant `b < a` is maintained, but only + // /// because `a` does not shrink. This is due to the fact that the + // /// dependency between the strategies is not tracked; `a` is simply seen as + // /// a constant. + // /// + // /// Finally, for `ind_flat_map2`, the invariant `b < a` is _not_ + // /// maintained, because `a` can shrink independently of `b`, again because + // /// the dependency between the two variables is not tracked, but in this + // /// case the derivation of `a` is still exposed to the shrinking system. + // /// + // /// The use-cases for the independent flat-map variants is pretty narrow. + // /// For the majority of cases where invariants need to be maintained and + // /// you want all components to shrink, `prop_flat_map` is the way to go. + // /// `prop_ind_flat_map` makes the most sense when the input to the map + // /// function is not exposed in the output and shrinking across strategies + // /// is not expected to be useful. `prop_ind_flat_map2` is useful for using + // /// related values as starting points while not constraining them to that + // /// relation. + // fn prop_flat_map S>(self, fun: F) -> Flatten> + // where + // Self: Sized, + // { + // Flatten::new(Map { source: self, fun: Arc::new(fun) }) + // } + + // /// Maps values produced by this strategy into new strategies and picks + // /// values from those strategies while considering the new strategies to be + // /// independent. + // /// + // /// This is very similar to `prop_flat_map()`, but shrinking will *not* + // /// attempt to shrink the input that produces the derived strategies. This + // /// is appropriate for when the derived strategies already fully shrink in + // /// the desired way. + // /// + // /// In most cases, you want `prop_flat_map()`. + // /// + // /// See `prop_flat_map()` for a more detailed explanation on how the + // /// three flat-map combinators differ. + // fn prop_ind_flat_map S>( + // self, + // fun: F, + // ) -> IndFlatten> + // where + // Self: Sized, + // { + // IndFlatten(Map { source: self, fun: Arc::new(fun) }) + // } + + // /// Similar to `prop_ind_flat_map()`, but produces 2-tuples with the input + // /// generated from `self` in slot 0 and the derived strategy in slot 1. + // /// + // /// See `prop_flat_map()` for a more detailed explanation on how the + // /// three flat-map combinators differ differ. + // fn prop_ind_flat_map2 S>( + // self, + // fun: F, + // ) -> IndFlattenMap + // where + // Self: Sized, + // { + // IndFlattenMap { source: self, fun: Arc::new(fun) } + // } + + // /// Returns a strategy which only produces values accepted by `fun`. + // /// + // /// This results in a very naïve form of rejection sampling and should only + // /// be used if (a) relatively few values will actually be rejected; (b) it + // /// isn't easy to express what you want by using another strategy and/or + // /// `map()`. + // /// + // /// There are a lot of downsides to this form of filtering. It slows + // /// testing down, since values must be generated but then discarded. + // /// Proptest only allows a limited number of rejects this way (across the + // /// entire `TestRunner`). Rejection can interfere with shrinking; + // /// particularly, complex filters may largely or entirely prevent shrinking + // /// from substantially altering the original value. + // /// + // /// Local rejection sampling is still preferable to rejecting the entire + // /// input to a test (via `TestCaseError::Reject`), however, and the default + // /// number of local rejections allowed is much higher than the number of + // /// whole-input rejections. + // /// + // /// `whence` is used to record where and why the rejection occurred. + // fn prop_filter, F: Fn(&Self::Value) -> bool>( + // self, + // whence: R, + // fun: F, + // ) -> Filter + // where + // Self: Sized, + // { + // Filter::new(self, whence.into(), fun) + // } + + // /// Returns a strategy which only produces transformed values where `fun` + // /// returns `Some(value)` and rejects those where `fun` returns `None`. + // /// + // /// Using this method is preferable to using `.prop_map(..).prop_filter(..)`. + // /// + // /// This results in a very naïve form of rejection sampling and should only + // /// be used if (a) relatively few values will actually be rejected; (b) it + // /// isn't easy to express what you want by using another strategy and/or + // /// `map()`. + // /// + // /// There are a lot of downsides to this form of filtering. It slows + // /// testing down, since values must be generated but then discarded. + // /// Proptest only allows a limited number of rejects this way (across the + // /// entire `TestRunner`). Rejection can interfere with shrinking; + // /// particularly, complex filters may largely or entirely prevent shrinking + // /// from substantially altering the original value. + // /// + // /// Local rejection sampling is still preferable to rejecting the entire + // /// input to a test (via `TestCaseError::Reject`), however, and the default + // /// number of local rejections allowed is much higher than the number of + // /// whole-input rejections. + // /// + // /// `whence` is used to record where and why the rejection occurred. + // fn prop_filter_map Option, O: fmt::Debug>( + // self, + // whence: impl Into, + // fun: F, + // ) -> FilterMap + // where + // Self: Sized, + // { + // FilterMap::new(self, whence.into(), fun) + // } + + // /// Returns a strategy which picks uniformly from `self` and `other`. + // /// + // /// When shrinking, if a value from `other` was originally chosen but that + // /// value can be shrunken no further, it switches to a value from `self` + // /// and starts shrinking that. + // /// + // /// Be aware that chaining `prop_union` calls will result in a very + // /// right-skewed distribution. If this is not what you want, you can call + // /// the `.or()` method on the `Union` to add more values to the same union, + // /// or directly call `Union::new()`. + // /// + // /// Both `self` and `other` must be of the same type. To combine + // /// heterogeneous strategies, call the `boxed()` method on both `self` and + // /// `other` to erase the type differences before calling `prop_union()`. + // fn prop_union(self, other: Self) -> Union + // where + // Self: Sized, + // { + // Union::new(vec![self, other]) + // } + + // /// Generate a recursive structure with `self` items as leaves. + // /// + // /// `recurse` is applied to various strategies that produce the same type + // /// as `self` with nesting depth _n_ to create a strategy that produces the + // /// same type with nesting depth _n+1_. Generated structures will have a + // /// depth between 0 and `depth` and will usually have up to `desired_size` + // /// total elements, though they may have more. `expected_branch_size` gives + // /// the expected maximum size for any collection which may contain + // /// recursive elements and is used to control branch probability to achieve + // /// the desired size. Passing a too small value can result in trees vastly + // /// larger than desired. + // /// + // /// Note that `depth` only counts branches; i.e., `depth = 0` is a single + // /// leaf, and `depth = 1` is a leaf or a branch containing only leaves. + // /// + // /// In practise, generated values usually have a lower depth than `depth` + // /// (but `depth` is a hard limit) and almost always under + // /// `expected_branch_size` (though it is not a hard limit) since the + // /// underlying code underestimates probabilities. + // /// + // /// Shrinking shrinks both the inner values and attempts switching from + // /// recursive to non-recursive cases. + // /// + // /// ## Example + // /// + // /// ```rust,no_run + // /// # #![allow(unused_variables)] + // /// use std::collections::HashMap; + // /// + // /// use proptest::prelude::*; + // /// + // /// /// Define our own JSON AST type + // /// #[derive(Debug, Clone)] + // /// enum JsonNode { + // /// Null, + // /// Bool(bool), + // /// Number(f64), + // /// String(String), + // /// Array(Vec), + // /// Map(HashMap), + // /// } + // /// + // /// # fn main() { + // /// # + // /// // Define a strategy for generating leaf nodes of the AST + // /// let json_leaf = prop_oneof![ + // /// Just(JsonNode::Null), + // /// prop::bool::ANY.prop_map(JsonNode::Bool), + // /// prop::num::f64::ANY.prop_map(JsonNode::Number), + // /// ".*".prop_map(JsonNode::String), + // /// ]; + // /// + // /// // Now define a strategy for a whole tree + // /// let json_tree = json_leaf.prop_recursive( + // /// 4, // No more than 4 branch levels deep + // /// 64, // Target around 64 total elements + // /// 16, // Each collection is up to 16 elements long + // /// |element| prop_oneof![ + // /// // NB `element` is an `Arc` and we'll need to reference it twice, + // /// // so we clone it the first time. + // /// prop::collection::vec(element.clone(), 0..16) + // /// .prop_map(JsonNode::Array), + // /// prop::collection::hash_map(".*", element, 0..16) + // /// .prop_map(JsonNode::Map) + // /// ]); + // /// # } + // /// ``` + // fn prop_recursive< + // R: Strategy + 'static, + // F: Fn(BoxedStrategy) -> R, + // >( + // self, + // depth: u32, + // desired_size: u32, + // expected_branch_size: u32, + // recurse: F, + // ) -> Recursive + // where + // Self: Sized + 'static, + // { + // Recursive::new(self, depth, desired_size, expected_branch_size, recurse) + // } + + // /// Shuffle the contents of the values produced by this strategy. + // /// + // /// That is, this modifies a strategy producing a `Vec`, slice, etc, to + // /// shuffle the contents of that `Vec`/slice/etc. + // /// + // /// Initially, the value is fully shuffled. During shrinking, the input + // /// value will initially be unchanged while the result will gradually be + // /// restored to its original order. Once de-shuffling either completes or + // /// is cancelled by calls to `complicate()` pinning it to a particular + // /// permutation, the inner value will be simplified. + // /// + // /// ## Example + // /// + // /// ``` + // /// use proptest::prelude::*; + // /// + // /// static VALUES: &'static [u32] = &[0, 1, 2, 3, 4]; + // /// + // /// fn is_permutation(orig: &[u32], mut actual: Vec) -> bool { + // /// actual.sort(); + // /// orig == &actual[..] + // /// } + // /// + // /// proptest! { + // /// # /* + // /// #[test] + // /// # */ + // /// fn test_is_permutation( + // /// ref perm in Just(VALUES.to_owned()).prop_shuffle() + // /// ) { + // /// assert!(is_permutation(VALUES, perm.clone())); + // /// } + // /// } + // /// # + // /// # fn main() { test_is_permutation(); } + // /// ``` + // fn prop_shuffle(self) -> Shuffle + // where + // Self: Sized, + // Self::Value: Shuffleable, + // { + // Shuffle(self) + // } + + // /// Erases the type of this `Strategy` so it can be passed around as a + // /// simple trait object. + // /// + // /// See also `sboxed()` if this `Strategy` is `Send` and `Sync` and you + // /// want to preserve that information. + // /// + // /// Strategies of this type afford cheap shallow cloning via reference + // /// counting by using an `Arc` internally. + // fn boxed(self) -> BoxedStrategy + // where + // Self: Sized + 'static, + // { + // BoxedStrategy(Arc::new(BoxedStrategyWrapper(self))) + // } + + // /// Erases the type of this `Strategy` so it can be passed around as a + // /// simple trait object. + // /// + // /// Unlike `boxed()`, this conversion retains the `Send` and `Sync` traits + // /// on the output. + // /// + // /// Strategies of this type afford cheap shallow cloning via reference + // /// counting by using an `Arc` internally. + // fn sboxed(self) -> SBoxedStrategy + // where + // Self: Sized + Send + Sync + 'static, + // { + // SBoxedStrategy(Arc::new(BoxedStrategyWrapper(self))) + // } + + // /// Wraps this strategy to prevent values from being subject to shrinking. + // /// + // /// Suppressing shrinking is useful when testing things like linear + // /// approximation functions. Ordinarily, proptest will tend to shrink the + // /// input to the function until the result is just barely outside the + // /// acceptable range whereas the original input may have produced a result + // /// far outside of it. Since this makes it harder to see what the actual + // /// problem is, making the input `NoShrink` allows learning about inputs + // /// that produce more incorrect results. + // fn no_shrink(self) -> NoShrink + // where + // Self: Sized, + // { + // NoShrink(self) + // } +} + +/// A generated value and its associated shrinker. +/// +/// Conceptually, a `ValueTree` represents a spectrum between a "minimally +/// complex" value and a starting, randomly-chosen value. For values such as +/// numbers, this can be thought of as a simple binary search, and this is how +/// the `ValueTree` state machine is defined. +/// +/// The `ValueTree` state machine notionally has three fields: low, current, +/// and high. Initially, low is the "minimally complex" value for the type, and +/// high and current are both the initially chosen value. It can be queried for +/// its current state. When shrinking, the controlling code tries simplifying +/// the value one step. If the test failure still happens with the simplified +/// value, further simplification occurs. Otherwise, the code steps back up +/// towards the prior complexity. +/// +/// The main invariants here are that the "high" value always corresponds to a +/// failing test case, and that repeated calls to `complicate()` will return +/// `false` only once the "current" value has returned to what it was before +/// the last call to `simplify()`. +/// +/// While it would be possible for default do-nothing implementations of +/// `simplify()` and `complicate()` to be provided, this was not done +/// deliberately since the majority of strategies will want to define their own +/// shrinking anyway, and the minority that do not must call it out explicitly +/// by their own implementation. +pub trait ValueTree { + /// The type of the value produced by this `ValueTree`. + type Value: fmt::Debug; + + /// Returns the current value. + fn current(&self) -> Self::Value; + /// Attempts to simplify the current value. Notionally, this sets the + /// "high" value to the current value, and the current value to a "halfway + /// point" between high and low, rounding towards low. + /// + /// Returns whether any state changed as a result of this call. This does + /// not necessarily imply that the value of `current()` has changed, since + /// in the most general case, it is not possible for an implementation to + /// determine this. + /// + /// This call needs to correctly handle being called even immediately after + /// it had been called previously and returned `false`. + fn simplify(&mut self) -> bool; + /// Attempts to partially undo the last simplification. Notionally, this + /// sets the "low" value to one plus the current value, and the current + /// value to a "halfway point" between high and the new low, rounding + /// towards low. + /// + /// Returns whether any state changed as a result of this call. This does + /// not necessarily imply that the value of `current()` has changed, since + /// in the most general case, it is not possible for an implementation to + /// determine this. + /// + /// It is usually expected that, immediately after a call to `simplify()` + /// which returns true, this call will itself return true. However, this is + /// not always the case; in some strategies, particularly those that use + /// some form of rejection sampling, the act of trying to simplify may + /// change the state such that `simplify()` returns true, yet ultimately + /// left the resulting value unchanged, in which case there is nothing left + /// to complicate. + /// + /// This call does not need to gracefully handle being called before + /// `simplify()` was ever called, but does need to correctly handle being + /// called even immediately after it had been called previously and + /// returned `false`. + fn complicate(&mut self) -> bool; +} + +//============================================================================== +// NoShrink +//============================================================================== + +/// Wraps a `Strategy` or `ValueTree` to suppress shrinking of generated +/// values. +/// +/// See `Strategy::no_shrink()` for more details. +#[derive(Clone, Copy, Debug)] +#[must_use = "strategies do nothing unless used"] +pub struct NoShrink(T); + +impl Strategy for NoShrink { + type Tree = NoShrink; + type Value = T::Value; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + self.0.new_tree(runner).map(NoShrink) + } +} + +impl ValueTree for NoShrink { + type Value = T::Value; + + fn current(&self) -> T::Value { + self.0.current() + } + + fn simplify(&mut self) -> bool { + false + } + fn complicate(&mut self) -> bool { + false + } +} + +//============================================================================== +// Trait objects +//============================================================================== + +macro_rules! proxy_strategy { + ($typ:ty $(, $lt:tt)*) => { + impl<$($lt,)* S : Strategy + ?Sized> Strategy for $typ { + type Tree = S::Tree; + type Value = S::Value; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + (**self).new_tree(runner) + } + } + }; +} +proxy_strategy!(Box); +proxy_strategy!(&'a S, 'a); +proxy_strategy!(&'a mut S, 'a); +proxy_strategy!(Rc); +proxy_strategy!(Arc); + +impl ValueTree for Box { + type Value = T::Value; + fn current(&self) -> Self::Value { + (**self).current() + } + fn simplify(&mut self) -> bool { + (**self).simplify() + } + fn complicate(&mut self) -> bool { + (**self).complicate() + } +} + +/// A boxed `ValueTree`. +type BoxedVT = Box>; + +/// A boxed `Strategy` trait object as produced by `Strategy::boxed()`. +/// +/// Strategies of this type afford cheap shallow cloning via reference +/// counting by using an `Arc` internally. +#[derive(Debug)] +#[must_use = "strategies do nothing unless used"] +pub struct BoxedStrategy(Arc>>); + +/// A boxed `Strategy` trait object which is also `Sync` and +/// `Send`, as produced by `Strategy::sboxed()`. +/// +/// Strategies of this type afford cheap shallow cloning via reference +/// counting by using an `Arc` internally. +#[derive(Debug)] +#[must_use = "strategies do nothing unless used"] +pub struct SBoxedStrategy(Arc> + Sync + Send>); + +impl Clone for BoxedStrategy { + fn clone(&self) -> Self { + BoxedStrategy(Arc::clone(&self.0)) + } +} + +impl Clone for SBoxedStrategy { + fn clone(&self) -> Self { + SBoxedStrategy(Arc::clone(&self.0)) + } +} + +impl Strategy for BoxedStrategy { + type Tree = BoxedVT; + type Value = T; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + self.0.new_tree(runner) + } + + // Optimization: Don't rebox the strategy. + + // fn boxed(self) -> BoxedStrategy + // where + // Self: Sized + 'static, + // { + // self + // } +} + +impl Strategy for SBoxedStrategy { + type Tree = BoxedVT; + type Value = T; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + self.0.new_tree(runner) + } + + // Optimization: Don't rebox the strategy. + + // fn sboxed(self) -> SBoxedStrategy + // where + // Self: Sized + Send + Sync + 'static, + // { + // self + // } + + // fn boxed(self) -> BoxedStrategy + // where + // Self: Sized + 'static, + // { + // BoxedStrategy(self.0) + // } +} + +#[derive(Debug)] +struct BoxedStrategyWrapper(T); +impl Strategy for BoxedStrategyWrapper +where + T::Tree: 'static, +{ + type Tree = Box>; + type Value = T::Value; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(Box::new(self.0.new_tree(runner)?)) + } +} + +//============================================================================== +// Sanity checking +//============================================================================== + +/// Options passed to `check_strategy_sanity()`. +#[derive(Clone, Copy, Debug)] +pub struct CheckStrategySanityOptions { + /// If true (the default), require that `complicate()` return `true` at + /// least once after any call to `simplify()` which itself returns once. + /// + /// This property is not required by contract, but many strategies are + /// designed in a way that this is expected to hold. + pub strict_complicate_after_simplify: bool, + + /// If true, cause local rejects to return an error instead of retrying. + /// Defaults to false. Useful for testing behaviors around error handling. + pub error_on_local_rejects: bool, + + // Needs to be public for FRU syntax. + #[allow(missing_docs)] + #[doc(hidden)] + pub _non_exhaustive: (), +} + +impl Default for CheckStrategySanityOptions { + fn default() -> Self { + CheckStrategySanityOptions { + strict_complicate_after_simplify: true, + error_on_local_rejects: false, + _non_exhaustive: (), + } + } +} + +/// Run some tests on the given `Strategy` to ensure that it upholds the +/// simplify/complicate contracts. +/// +/// This is used to internally test proptest, but is made generally available +/// for external implementations to use as well. +/// +/// `options` can be passed to configure the test; if `None`, the defaults are +/// used. Note that the defaults check for certain properties which are **not** +/// actually required by the `Strategy` and `ValueTree` contracts; if you think +/// your code is right but it fails the test, consider whether a non-default +/// configuration is necessary. +/// +/// This can work with fallible strategies, but limits how many times it will +/// retry failures. +pub fn check_strategy_sanity(strategy: S, options: Option) +where + S::Tree: Clone + fmt::Debug, + S::Value: cmp::PartialEq, +{ + // Like assert_eq!, but also pass if both values do not equal themselves. + // This allows the test to work correctly with things like NaN. + macro_rules! assert_same { + ($a:expr, $b:expr, $($stuff:tt)*) => { { + let a = $a; + let b = $b; + if a == a || b == b { + assert_eq!(a, b, $($stuff)*); + } + } } + } + + let options = options.unwrap_or_else(CheckStrategySanityOptions::default); + let mut config = Config::default(); + if options.error_on_local_rejects { + config.max_local_rejects = 0; + } + let mut runner = TestRunner::new(config); + + for _ in 0..1024 { + let mut gen_tries = 0; + let mut state; + loop { + let err = match strategy.new_tree(&mut runner) { + Ok(s) => { + state = s; + break; + } + Err(e) => e, + }; + + gen_tries += 1; + if gen_tries > 100 { + panic!( + "Strategy passed to check_strategy_sanity failed \ + to generate a value over 100 times in a row; \ + last failure reason: {}", + err + ); + } + } + + { + let mut state = state.clone(); + let mut count = 0; + while state.simplify() || state.complicate() { + count += 1; + if count > 65536 { + panic!("Failed to converge on any value. State:\n{:#?}", state); + } + } + } + + let mut num_simplifies = 0; + let mut before_simplified; + loop { + before_simplified = state.clone(); + if !state.simplify() { + break; + } + + let mut complicated = state.clone(); + let before_complicated = state.clone(); + if options.strict_complicate_after_simplify { + assert!( + complicated.complicate(), + "complicate() returned false immediately after \ + simplify() returned true. internal state after \ + {} calls to simplify():\n\ + {:#?}\n\ + simplified to:\n\ + {:#?}\n\ + complicated to:\n\ + {:#?}", + num_simplifies, + before_simplified, + state, + complicated + ); + } + + let mut prev_complicated = complicated.clone(); + let mut num_complications = 0; + loop { + if !complicated.complicate() { + break; + } + prev_complicated = complicated.clone(); + num_complications += 1; + + if num_complications > 65_536 { + panic!( + "complicate() returned true over 65536 times in a \ + row; aborting due to possible infinite loop. \ + If this is not an infinite loop, it may be \ + necessary to reconsider how shrinking is \ + implemented or use a simpler test strategy. \ + Internal state:\n{:#?}", + state + ); + } + } + + assert_same!( + before_simplified.current(), + complicated.current(), + "Calling simplify(), then complicate() until it \ + returned false, did not return to the value before \ + simplify. Expected:\n\ + {:#?}\n\ + Actual:\n\ + {:#?}\n\ + Internal state after {} calls to simplify():\n\ + {:#?}\n\ + Internal state after another call to simplify():\n\ + {:#?}\n\ + Internal state after {} subsequent calls to \ + complicate():\n\ + {:#?}", + before_simplified.current(), + complicated.current(), + num_simplifies, + before_simplified, + before_complicated, + num_complications + 1, + complicated + ); + + for iter in 1..16 { + assert_same!( + prev_complicated.current(), + complicated.current(), + "complicate() returned false but changed the output \ + value anyway.\n\ + Old value:\n\ + {:#?}\n\ + New value:\n\ + {:#?}\n\ + Old internal state:\n\ + {:#?}\n\ + New internal state after {} calls to complicate()\ + including the :\n\ + {:#?}", + prev_complicated.current(), + complicated.current(), + prev_complicated, + iter, + complicated + ); + + assert!( + !complicated.complicate(), + "complicate() returned true after having returned \ + false;\n\ + Internal state before:\n{:#?}\n\ + Internal state after calling complicate() {} times:\n\ + {:#?}", + prev_complicated, + iter + 1, + complicated + ); + } + + num_simplifies += 1; + if num_simplifies > 65_536 { + panic!( + "simplify() returned true over 65536 times in a row, \ + aborting due to possible infinite loop. If this is not \ + an infinite loop, it may be necessary to reconsider \ + how shrinking is implemented or use a simpler test \ + strategy. Internal state:\n{:#?}", + state + ); + } + } + + for iter in 0..16 { + assert_same!( + before_simplified.current(), + state.current(), + "simplify() returned false but changed the output \ + value anyway.\n\ + Old value:\n\ + {:#?}\n\ + New value:\n\ + {:#?}\n\ + Previous internal state:\n\ + {:#?}\n\ + New internal state after calling simplify() {} times:\n\ + {:#?}", + before_simplified.current(), + state.current(), + before_simplified, + iter, + state + ); + + if state.simplify() { + panic!( + "simplify() returned true after having returned false. \ + Previous internal state:\n\ + {:#?}\n\ + New internal state after calling simplify() {} times:\n\ + {:#?}", + before_simplified, + iter + 1, + state + ); + } + } + } +} + diff --git a/library/proptest/src/test_runner/config.rs b/library/proptest/src/test_runner/config.rs new file mode 100644 index 000000000000..a9e6893c3b4b --- /dev/null +++ b/library/proptest/src/test_runner/config.rs @@ -0,0 +1,448 @@ +//- +// Copyright 2017, 2018, 2019 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// use crate::std_facade::Box; +use core::u32; + +#[cfg(feature = "std")] +use std::env; +#[cfg(feature = "std")] +use std::ffi::OsString; +#[cfg(feature = "std")] +use std::fmt; +#[cfg(feature = "std")] +use std::str::FromStr; + +// use crate::test_runner::result_cache::{noop_result_cache, ResultCache}; +// use crate::test_runner::rng::RngAlgorithm; +// use crate::test_runner::FailurePersistence; +#[cfg(feature = "std")] +use crate::test_runner::FileFailurePersistence; + +#[cfg(feature = "std")] +const CASES: &str = "PROPTEST_CASES"; +#[cfg(feature = "std")] +const MAX_LOCAL_REJECTS: &str = "PROPTEST_MAX_LOCAL_REJECTS"; +#[cfg(feature = "std")] +const MAX_GLOBAL_REJECTS: &str = "PROPTEST_MAX_GLOBAL_REJECTS"; +#[cfg(feature = "std")] +const MAX_FLAT_MAP_REGENS: &str = "PROPTEST_MAX_FLAT_MAP_REGENS"; +#[cfg(feature = "std")] +const MAX_SHRINK_TIME: &str = "PROPTEST_MAX_SHRINK_TIME"; +#[cfg(feature = "std")] +const MAX_SHRINK_ITERS: &str = "PROPTEST_MAX_SHRINK_ITERS"; +#[cfg(feature = "fork")] +const FORK: &str = "PROPTEST_FORK"; +#[cfg(feature = "timeout")] +const TIMEOUT: &str = "PROPTEST_TIMEOUT"; +#[cfg(feature = "std")] +const VERBOSE: &str = "PROPTEST_VERBOSE"; + + +#[cfg(feature = "std")] +fn contextualize_config(mut result: Config) -> Config { + fn parse_or_warn(src: &OsString, dst: &mut T, typ: &str, var: &str) { + if let Some(src) = src.to_str() { + if let Ok(value) = src.parse() { + *dst = value; + } else { + eprintln!( + "proptest: The env-var {}={} can't be parsed as {}, \ + using default of {}.", + var, src, typ, *dst + ); + } + } else { + eprintln!( + "proptest: The env-var {} is not valid, using \ + default of {}.", + var, *dst + ); + } + } + + result.failure_persistence = Some(Box::new(FileFailurePersistence::default())); + for (var, value) in env::vars_os().filter_map(|(k, v)| k.into_string().ok().map(|k| (k, v))) { + match var.as_str() { + CASES => parse_or_warn(&value, &mut result.cases, "u32", CASES), + MAX_LOCAL_REJECTS => { + parse_or_warn(&value, &mut result.max_local_rejects, "u32", MAX_LOCAL_REJECTS) + } + MAX_GLOBAL_REJECTS => { + parse_or_warn(&value, &mut result.max_global_rejects, "u32", MAX_GLOBAL_REJECTS) + } + MAX_FLAT_MAP_REGENS => { + parse_or_warn(&value, &mut result.max_flat_map_regens, "u32", MAX_FLAT_MAP_REGENS) + } + #[cfg(feature = "fork")] + FORK => parse_or_warn(&value, &mut result.fork, "bool", FORK), + #[cfg(feature = "timeout")] + TIMEOUT => parse_or_warn(&value, &mut result.timeout, "timeout", TIMEOUT), + MAX_SHRINK_TIME => { + parse_or_warn(&value, &mut result.max_shrink_time, "u32", MAX_SHRINK_TIME) + } + MAX_SHRINK_ITERS => { + parse_or_warn(&value, &mut result.max_shrink_iters, "u32", MAX_SHRINK_ITERS) + } + VERBOSE => parse_or_warn(&value, &mut result.verbose, "u32", VERBOSE), + RNG_ALGORITHM => { + parse_or_warn(&value, &mut result.rng_algorithm, "RngAlgorithm", RNG_ALGORITHM) + } + + _ => { + if var.starts_with("PROPTEST_") { + eprintln!("proptest: Ignoring unknown env-var {}.", var); + } + } + } + } + + result +} + +fn default_default_config() -> Config { + Config { + cases: 256, + max_local_rejects: 65_536, + max_global_rejects: 1024, + max_flat_map_regens: 1_000_000, + // failure_persistence: None, + source_file: None, + test_name: None, + #[cfg(feature = "fork")] + fork: false, + #[cfg(feature = "timeout")] + timeout: 0, + #[cfg(feature = "std")] + max_shrink_time: 0, + max_shrink_iters: u32::MAX, + // result_cache: noop_result_cache, + #[cfg(feature = "std")] + verbose: 0, + // rng_algorithm: RngAlgorithm::default(), + _non_exhaustive: (), + } +} + +// The default config, computed by combining environment variables and +// defaults. +#[cfg(feature = "std")] +lazy_static! { + static ref DEFAULT_CONFIG: Config = contextualize_config(default_default_config()); +} + +/// Configuration for how a proptest test should be run. +#[derive(Clone, Debug, PartialEq)] +pub struct Config { + /// The number of successful test cases that must execute for the test as a + /// whole to pass. + /// + /// This does not include implicitly-replayed persisted failing cases. + /// + /// The default is 256, which can be overridden by setting the + /// `PROPTEST_CASES` environment variable. + pub cases: u32, + + /// The maximum number of individual inputs that may be rejected before the + /// test as a whole aborts. + /// + /// The default is 65536, which can be overridden by setting the + /// `PROPTEST_MAX_LOCAL_REJECTS` environment variable. + pub max_local_rejects: u32, + + /// The maximum number of combined inputs that may be rejected before the + /// test as a whole aborts. + /// + /// The default is 1024, which can be overridden by setting the + /// `PROPTEST_MAX_GLOBAL_REJECTS` environment variable. + pub max_global_rejects: u32, + + /// The maximum number of times all `Flatten` combinators will attempt to + /// regenerate values. This puts a limit on the worst-case exponential + /// explosion that can happen with nested `Flatten`s. + /// + /// The default is 1_000_000, which can be overridden by setting the + /// `PROPTEST_MAX_FLAT_MAP_REGENS` environment variable. + pub max_flat_map_regens: u32, + + /// Indicates whether and how to persist failed test results. + /// + /// When compiling with "std" feature (i.e. the standard library is available), the default + /// is `Some(Box::new(FileFailurePersistence::SourceParallel("proptest-regressions")))`. + /// + /// Without the standard library, the default is `None`, and no persistence occurs. + /// + /// See the docs of [`FileFailurePersistence`](enum.FileFailurePersistence.html) + /// and [`MapFailurePersistence`](struct.MapFailurePersistence.html) for more information. + /// + /// The default cannot currently be overridden by an environment variable. + // pub failure_persistence: Option>, + + /// File location of the current test, relevant for persistence + /// and debugging. + /// + /// Note the use of `&str` rather than `Path` to be compatible with + /// `#![no_std]` use cases where `Path` is unavailable. + /// + /// See the docs of [`FileFailurePersistence`](enum.FileFailurePersistence.html) + /// for more information on how it may be used for persistence. + pub source_file: Option<&'static str>, + + /// The fully-qualified name of the test being run, as would be passed to + /// the test executable to run just that test. + /// + /// This must be set if `fork` is `true`. Otherwise, it is unused. It is + /// automatically set by `proptest!`. + /// + /// This must include the crate name at the beginning, as produced by + /// `module_path!()`. + pub test_name: Option<&'static str>, + + /// If true, tests are run in a subprocess. + /// + /// Forking allows proptest to work with tests which may fail by aborting + /// the process, causing a segmentation fault, etc, but can be a lot slower + /// in certain environments or when running a very large number of tests. + /// + /// For forking to work correctly, both the `Strategy` and the content of + /// the test case itself must be deterministic. + /// + /// This requires the "fork" feature, enabled by default. + /// + /// The default is `false`, which can be overridden by setting the + /// `PROPTEST_FORK` environment variable. + #[cfg(feature = "fork")] + pub fork: bool, + + /// If non-zero, tests are run in a subprocess and each generated case + /// fails if it takes longer than this number of milliseconds. + /// + /// This implicitly enables forking, even if the `fork` field is `false`. + /// + /// The type here is plain `u32` (rather than + /// `Option`) for the sake of ergonomics. + /// + /// This requires the "timeout" feature, enabled by default. + /// + /// Setting a timeout to less than the time it takes the process to start + /// up and initialise the first test case will cause the whole test to be + /// aborted. + /// + /// The default is `0` (i.e., no timeout), which can be overridden by + /// setting the `PROPTEST_TIMEOUT` environment variable. + #[cfg(feature = "timeout")] + pub timeout: u32, + + /// If non-zero, give up the shrinking process after this many milliseconds + /// have elapsed since the start of the shrinking process. + /// + /// This will not cause currently running test cases to be interrupted. + /// + /// This configuration is only available when the `std` feature is enabled + /// (which it is by default). + /// + /// The default is `0` (i.e., no limit), which can be overridden by setting + /// the `PROPTEST_MAX_SHRINK_TIME` environment variable. + #[cfg(feature = "std")] + pub max_shrink_time: u32, + + /// Give up on shrinking if more than this number of iterations of the test + /// code are run. + /// + /// Setting this to `std::u32::MAX` causes the actual limit to be four + /// times the number of test cases. + /// + /// Setting this value to `0` disables shrinking altogether. + /// + /// Note that the type of this field will change in a future version of + /// proptest to better accommodate its special values. + /// + /// The default is `std::u32::MAX`, which can be overridden by setting the + /// `PROPTEST_MAX_SHRINK_ITERS` environment variable. + pub max_shrink_iters: u32, + + // A function to create new result caches. + + // The default is to do no caching. The easiest way to enable caching is + // to set this field to `basic_result_cache` (though that is currently + // only available with the `std` feature). + + // This is useful for strategies which have a tendency to produce + // duplicate values, or for tests where shrinking can take a very long + // time due to exploring the same output multiple times. + + // When caching is enabled, generated values themselves are not stored, so + // this does not pose a risk of memory exhaustion for large test inputs + // unless using extraordinarily large test case counts. + + // Caching incurs its own overhead, and may very well make your test run + // more slowly. + // pub result_cache: fn() -> Box, + + /// Set to non-zero values to cause proptest to emit human-targeted + /// messages to stderr as it runs. + /// + /// Greater values cause greater amounts of logs to be emitted. The exact + /// meaning of certain levels other than 0 is subject to change. + /// + /// - 0: No extra output. + /// - 1: Log test failure messages. + /// - 2: Trace low-level details. + /// + /// This is only available with the `std` feature (enabled by default) + /// since on nostd proptest has no way to produce output. + /// + /// The default is `0`, which can be overridden by setting the + /// `PROPTEST_VERBOSE` environment variable. + #[cfg(feature = "std")] + pub verbose: u32, + + // The RNG algorithm to use when not using a user-provided RNG. + + // The default is `RngAlgorithm::default()`, which can be overridden by + // setting the `PROPTEST_RNG_ALGORITHM` environment variable to one of the following: + + // - `xs` — `RngAlgorithm::XorShift` + // - `cc` — `RngAlgorithm::ChaCha` + // pub rng_algorithm: RngAlgorithm, + + // Needs to be public so FRU syntax can be used. + #[doc(hidden)] + pub _non_exhaustive: (), +} + +impl Config { + /// Constructs a `Config` only differing from the `default()` in the + /// number of test cases required to pass the test successfully. + /// + /// This is simply a more concise alternative to using field-record update + /// syntax: + /// + /// ``` + /// # use proptest::test_runner::Config; + /// assert_eq!( + /// Config::with_cases(42), + /// Config { cases: 42, .. Config::default() } + /// ); + /// ``` + pub fn with_cases(cases: u32) -> Self { + Self { cases, ..Config::default() } + } + + /// Constructs a `Config` only differing from the `default()` in the + /// source_file of the present test. + /// + /// This is simply a more concise alternative to using field-record update + /// syntax: + /// + /// ``` + /// # use proptest::test_runner::Config; + /// assert_eq!( + /// Config::with_source_file("computer/question"), + /// Config { source_file: Some("computer/question"), .. Config::default() } + /// ); + /// ``` + pub fn with_source_file(source_file: &'static str) -> Self { + Self { source_file: Some(source_file), ..Config::default() } + } + + /// Constructs a `Config` only differing from the provided Config instance, `self`, + /// in the source_file of the present test. + /// + /// This is simply a more concise alternative to using field-record update + /// syntax: + /// + /// ``` + /// # use proptest::test_runner::Config; + /// let a = Config::with_source_file("computer/question"); + /// let b = a.clone_with_source_file("answer/42"); + /// assert_eq!( + /// a, + /// Config { source_file: Some("computer/question"), .. Config::default() } + /// ); + /// assert_eq!( + /// b, + /// Config { source_file: Some("answer/42"), .. Config::default() } + /// ); + /// ``` + pub fn clone_with_source_file(&self, source_file: &'static str) -> Self { + let mut result = self.clone(); + result.source_file = Some(source_file); + result + } + + /// Return whether this configuration implies forking. + /// + /// This method exists even if the "fork" feature is disabled, in which + /// case it simply returns false. + pub fn fork(&self) -> bool { + self._fork() || self.timeout() > 0 + } + + #[cfg(feature = "fork")] + fn _fork(&self) -> bool { + self.fork + } + + #[cfg(not(feature = "fork"))] + fn _fork(&self) -> bool { + false + } + + /// Returns the configured timeout. + /// + /// This method exists even if the "timeout" feature is disabled, in which + /// case it simply returns 0. + #[cfg(feature = "timeout")] + pub fn timeout(&self) -> u32 { + self.timeout + } + + /// Returns the configured timeout. + /// + /// This method exists even if the "timeout" feature is disabled, in which + /// case it simply returns 0. + #[cfg(not(feature = "timeout"))] + pub fn timeout(&self) -> u32 { + 0 + } + + /// Returns the configured limit on shrinking iterations. + /// + /// This takes into account the special "automatic" behaviour. + pub fn max_shrink_iters(&self) -> u32 { + if u32::MAX == self.max_shrink_iters { + self.cases.saturating_mul(4) + } else { + self.max_shrink_iters + } + } + + // Used by macros to force the config to be owned without depending on + // certain traits being `use`d. + #[allow(missing_docs)] + #[doc(hidden)] + pub fn __sugar_to_owned(&self) -> Self { + self.clone() + } +} + +#[cfg(feature = "std")] +impl Default for Config { + fn default() -> Self { + DEFAULT_CONFIG.clone() + } +} + +#[cfg(not(feature = "std"))] +impl Default for Config { + fn default() -> Self { + default_default_config() + } +} diff --git a/library/proptest/src/test_runner/mod.rs b/library/proptest/src/test_runner/mod.rs new file mode 100644 index 000000000000..d93afcccddf8 --- /dev/null +++ b/library/proptest/src/test_runner/mod.rs @@ -0,0 +1,15 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT + +//! Module for test runner. Significantly scaled back compared to +//! original. + +mod reason; +mod runner; +mod config; + + +pub use reason::*; +pub use runner::*; +pub use config::*; + diff --git a/library/proptest/src/test_runner/reason.rs b/library/proptest/src/test_runner/reason.rs new file mode 100644 index 000000000000..38cc7e322633 --- /dev/null +++ b/library/proptest/src/test_runner/reason.rs @@ -0,0 +1,54 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::std_facade::{fmt, Box, Cow, String}; + +/// The reason for why something, such as a generated value, was rejected. +/// +/// Currently this is merely a wrapper around a message, but more properties +/// may be added in the future. +/// +/// This is constructed via `.into()` on a `String`, `&'static str`, or +/// `Box`. +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Reason(Cow<'static, str>); + +impl Reason { + /// Return the message for this `Reason`. + /// + /// The message is intended for human consumption, and is not guaranteed to + /// have any format in particular. + pub fn message(&self) -> &str { + &*self.0 + } +} + +impl From<&'static str> for Reason { + fn from(s: &'static str) -> Self { + Reason(s.into()) + } +} + +impl From for Reason { + fn from(s: String) -> Self { + Reason(s.into()) + } +} + +impl From> for Reason { + fn from(s: Box) -> Self { + Reason(String::from(s).into()) + } +} + +impl fmt::Display for Reason { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(self.message(), f) + } +} diff --git a/library/proptest/src/test_runner/runner.rs b/library/proptest/src/test_runner/runner.rs new file mode 100644 index 000000000000..e029721ad697 --- /dev/null +++ b/library/proptest/src/test_runner/runner.rs @@ -0,0 +1,29 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT + +//! This file implements a Kani-specific test runner that mirrors the +//! one in proptest. In contrast to the original, this test runner +//! will run once but with symbolic inputs. + +use crate::strategy::{ + Strategy, + ValueTree, +}; +use crate::test_runner::Config; + +/// Fake test runner that keeps no state. +pub struct TestRunner {} + +impl TestRunner { + + /// Creates new + pub fn new(_: Config) -> Self { Self {} } + + /// Run the test function with a Kani symbolic value given a test function that takes that type. + pub fn run_kani(strategy: S, test_fn: impl Fn(S::Value) -> ()) { + let mut runner = Self::new(Config::default()); + let tree = strategy.new_tree(&mut runner).unwrap(); + test_fn(tree.current()); + } + +} From 0386207633f7dea01d25d2162a8b29800edeb099 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 18 Jul 2022 22:11:11 -0400 Subject: [PATCH 21/80] Got new proptest to type check. TODO: cleanup --- Cargo.lock | 3 + kani-compiler/src/main.rs | 4 +- library/proptest/Cargo.toml | 1 + .../proptest/src/arbitrary/_alloc/alloc.rs | 57 + .../proptest/src/arbitrary/_alloc/borrow.rs | 27 + .../proptest/src/arbitrary/_alloc/boxed.rs | 19 + library/proptest/src/arbitrary/_alloc/char.rs | 89 ++ .../src/arbitrary/_alloc/collections.rs | 284 ++++ library/proptest/src/arbitrary/_alloc/hash.rs | 32 + library/proptest/src/arbitrary/_alloc/mod.rs | 22 + library/proptest/src/arbitrary/_alloc/ops.rs | 97 ++ library/proptest/src/arbitrary/_alloc/rc.rs | 21 + library/proptest/src/arbitrary/_alloc/str.rs | 49 + library/proptest/src/arbitrary/_alloc/sync.rs | 76 + library/proptest/src/arbitrary/_core/ascii.rs | 23 + library/proptest/src/arbitrary/_core/cell.rs | 48 + library/proptest/src/arbitrary/_core/cmp.rs | 33 + .../proptest/src/arbitrary/_core/convert.rs | 16 + library/proptest/src/arbitrary/_core/fmt.rs | 18 + library/proptest/src/arbitrary/_core/iter.rs | 173 +++ .../proptest/src/arbitrary/_core/marker.rs | 19 + library/proptest/src/arbitrary/_core/mem.rs | 42 + library/proptest/src/arbitrary/_core/mod.rs | 22 + library/proptest/src/arbitrary/_core/num.rs | 55 + .../proptest/src/arbitrary/_core/option.rs | 60 + .../proptest/src/arbitrary/_core/result.rs | 104 ++ library/proptest/src/arbitrary/_std/env.rs | 139 ++ library/proptest/src/arbitrary/_std/ffi.rs | 100 ++ library/proptest/src/arbitrary/_std/fs.rs | 30 + library/proptest/src/arbitrary/_std/io.rs | 164 +++ library/proptest/src/arbitrary/_std/mod.rs | 22 + library/proptest/src/arbitrary/_std/net.rs | 117 ++ library/proptest/src/arbitrary/_std/panic.rs | 19 + library/proptest/src/arbitrary/_std/path.rs | 23 + library/proptest/src/arbitrary/_std/string.rs | 312 +++++ library/proptest/src/arbitrary/_std/sync.rs | 162 +++ library/proptest/src/arbitrary/_std/thread.rs | 81 ++ library/proptest/src/arbitrary/_std/time.rs | 50 + library/proptest/src/arbitrary/arrays.rs | 38 + library/proptest/src/arbitrary/functor.rs | 214 +++ library/proptest/src/arbitrary/macros.rs | 115 ++ library/proptest/src/arbitrary/mod.rs | 67 + library/proptest/src/arbitrary/primitives.rs | 47 + library/proptest/src/arbitrary/sample.rs | 31 + library/proptest/src/arbitrary/traits.rs | 295 ++++ library/proptest/src/arbitrary/tuples.rs | 45 + library/proptest/src/lib.rs | 4 +- library/proptest/src/num.rs | 1231 +++++++++++++++++ library/proptest/src/strategy/just.rs | 141 ++ library/proptest/src/strategy/mod.rs | 4 +- 50 files changed, 4839 insertions(+), 6 deletions(-) create mode 100644 library/proptest/src/arbitrary/_alloc/alloc.rs create mode 100644 library/proptest/src/arbitrary/_alloc/borrow.rs create mode 100644 library/proptest/src/arbitrary/_alloc/boxed.rs create mode 100644 library/proptest/src/arbitrary/_alloc/char.rs create mode 100644 library/proptest/src/arbitrary/_alloc/collections.rs create mode 100644 library/proptest/src/arbitrary/_alloc/hash.rs create mode 100644 library/proptest/src/arbitrary/_alloc/mod.rs create mode 100644 library/proptest/src/arbitrary/_alloc/ops.rs create mode 100644 library/proptest/src/arbitrary/_alloc/rc.rs create mode 100644 library/proptest/src/arbitrary/_alloc/str.rs create mode 100644 library/proptest/src/arbitrary/_alloc/sync.rs create mode 100644 library/proptest/src/arbitrary/_core/ascii.rs create mode 100644 library/proptest/src/arbitrary/_core/cell.rs create mode 100644 library/proptest/src/arbitrary/_core/cmp.rs create mode 100644 library/proptest/src/arbitrary/_core/convert.rs create mode 100644 library/proptest/src/arbitrary/_core/fmt.rs create mode 100644 library/proptest/src/arbitrary/_core/iter.rs create mode 100644 library/proptest/src/arbitrary/_core/marker.rs create mode 100644 library/proptest/src/arbitrary/_core/mem.rs create mode 100644 library/proptest/src/arbitrary/_core/mod.rs create mode 100644 library/proptest/src/arbitrary/_core/num.rs create mode 100644 library/proptest/src/arbitrary/_core/option.rs create mode 100644 library/proptest/src/arbitrary/_core/result.rs create mode 100644 library/proptest/src/arbitrary/_std/env.rs create mode 100644 library/proptest/src/arbitrary/_std/ffi.rs create mode 100644 library/proptest/src/arbitrary/_std/fs.rs create mode 100644 library/proptest/src/arbitrary/_std/io.rs create mode 100644 library/proptest/src/arbitrary/_std/mod.rs create mode 100644 library/proptest/src/arbitrary/_std/net.rs create mode 100644 library/proptest/src/arbitrary/_std/panic.rs create mode 100644 library/proptest/src/arbitrary/_std/path.rs create mode 100644 library/proptest/src/arbitrary/_std/string.rs create mode 100644 library/proptest/src/arbitrary/_std/sync.rs create mode 100644 library/proptest/src/arbitrary/_std/thread.rs create mode 100644 library/proptest/src/arbitrary/_std/time.rs create mode 100644 library/proptest/src/arbitrary/arrays.rs create mode 100644 library/proptest/src/arbitrary/functor.rs create mode 100644 library/proptest/src/arbitrary/macros.rs create mode 100644 library/proptest/src/arbitrary/mod.rs create mode 100644 library/proptest/src/arbitrary/primitives.rs create mode 100644 library/proptest/src/arbitrary/sample.rs create mode 100644 library/proptest/src/arbitrary/traits.rs create mode 100644 library/proptest/src/arbitrary/tuples.rs create mode 100644 library/proptest/src/num.rs create mode 100644 library/proptest/src/strategy/just.rs diff --git a/Cargo.lock b/Cargo.lock index e6ff032a6bb4..68af8ef9b54e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -555,6 +555,9 @@ dependencies = [ [[package]] name = "proptest" version = "0.1.0" +dependencies = [ + "kani", +] [[package]] name = "pulldown-cmark" diff --git a/kani-compiler/src/main.rs b/kani-compiler/src/main.rs index 0a09541bb182..e9d25ef77048 100644 --- a/kani-compiler/src/main.rs +++ b/kani-compiler/src/main.rs @@ -50,7 +50,7 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { let kani_proptest_rlib = PathBuf::from(lib_path).join("libproptest.rlib"); let _kani_proptest_wrapper = format!("noprelude:proptest={}", kani_proptest_rlib.to_str().unwrap()); - // println!("libproptest wrapper is: {}", &kani_proptest_wrapper); + // println!("kani_std wrapper is: {}", &kani_std_wrapper.as_str()); let args = vec![ "-C", "overflow-checks=on", @@ -81,7 +81,7 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { "--extern", kani_std_wrapper.as_str(), "--extern", - "proptest=/Users/ytakashl/Desktop/kani/target/debug/libproptest.rlib", + "proptest=/Users/ytakashl/Desktop/kani/target/debug/build/kani-compiler-913e19dc97ff67d3/out/lib/libproptest.rlib", // todo! why does this need to be hard-coded??? // kani_proptest_wrapper.as_str(), //Why is the other one off? ]; diff --git a/library/proptest/Cargo.toml b/library/proptest/Cargo.toml index 1f4118cb6fff..e1dcfb7e4a8e 100644 --- a/library/proptest/Cargo.toml +++ b/library/proptest/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +kani = { path = "../kani" } \ No newline at end of file diff --git a/library/proptest/src/arbitrary/_alloc/alloc.rs b/library/proptest/src/arbitrary/_alloc/alloc.rs new file mode 100644 index 000000000000..f403d0519314 --- /dev/null +++ b/library/proptest/src/arbitrary/_alloc/alloc.rs @@ -0,0 +1,57 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::hash`. + +use core::cmp; +use core::ops::Range; +use core::usize; + +multiplex_alloc!(::alloc::alloc, ::std::alloc); + +use crate::arbitrary::*; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +arbitrary!(self::alloc::Global; self::alloc::Global); + +// Not Debug. +//lazy_just!(System, || System); + +arbitrary!(self::alloc::Layout, SFnPtrMap<(Range, StrategyFor), Self>; + // 1. align must be a power of two and <= (1 << 31): + // 2. "when rounded up to the nearest multiple of align, must not overflow". + static_map((0u8..32u8, any::()), |(align_power, size)| { + let align = 1usize << align_power; + let max_size = 0usize.wrapping_sub(align); + // Not quite a uniform distribution due to clamping, + // but probably good enough + self::alloc::Layout::from_size_align(cmp::min(max_size, size), align).unwrap() + }) +); + +arbitrary!(self::alloc::AllocError, Just; Just(self::alloc::AllocError)); +/* 2018-07-28 CollectionAllocErr is not currently available outside of using + * the `alloc` crate, which would require a different nightly feature. For now, + * disable. +arbitrary!(alloc::collections::CollectionAllocErr, TupleUnion<(WA>, WA>)>; + prop_oneof![Just(alloc::collections::CollectionAllocErr::AllocErr), + Just(alloc::collections::CollectionAllocErr::CapacityOverflow)]); + */ + +#[cfg(test)] +mod test { + multiplex_alloc!(::alloc::alloc, ::std::alloc); + + no_panic_test!( + layout => self::alloc::Layout, + alloc_err => self::alloc::AllocErr + //collection_alloc_err => alloc::collections::CollectionAllocErr + ); +} diff --git a/library/proptest/src/arbitrary/_alloc/borrow.rs b/library/proptest/src/arbitrary/_alloc/borrow.rs new file mode 100644 index 000000000000..153115e1839d --- /dev/null +++ b/library/proptest/src/arbitrary/_alloc/borrow.rs @@ -0,0 +1,27 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for std::borrow. + +use crate::std_facade::fmt; +use crate::std_facade::{Cow, ToOwned}; +use core::borrow::Borrow; + +use crate::arbitrary::{any_with, Arbitrary, SMapped}; +use crate::strategy::statics::static_map; + +arbitrary!( + [A: Arbitrary + Borrow, B: ToOwned + fmt::Debug + ?Sized] + Cow<'static, B>, SMapped, A::Parameters; + args => static_map(any_with::(args), Cow::Owned) +); + +lift1!([Borrow + 'static, B: ToOwned + fmt::Debug + ?Sized] + Cow<'static, B>; base => static_map(base, Cow::Owned) +); diff --git a/library/proptest/src/arbitrary/_alloc/boxed.rs b/library/proptest/src/arbitrary/_alloc/boxed.rs new file mode 100644 index 000000000000..222362504d82 --- /dev/null +++ b/library/proptest/src/arbitrary/_alloc/boxed.rs @@ -0,0 +1,19 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::boxed`. + +use crate::std_facade::Box; + +wrap_from!(Box); + +#[cfg(test)] +mod test { + no_panic_test!(boxed => Box); +} diff --git a/library/proptest/src/arbitrary/_alloc/char.rs b/library/proptest/src/arbitrary/_alloc/char.rs new file mode 100644 index 000000000000..fab9dd824be8 --- /dev/null +++ b/library/proptest/src/arbitrary/_alloc/char.rs @@ -0,0 +1,89 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::char`. + +use crate::std_facade::Vec; +use core::char::*; +use core::iter::once; +use core::ops::Range; + +use crate::collection::vec; + +multiplex_alloc! { + core::char::DecodeUtf16, std::char::DecodeUtf16, + core::char::DecodeUtf16Error, std::char::DecodeUtf16Error, + core::char::decode_utf16, std::char::decode_utf16 +} + +const VEC_MAX: usize = ::core::u16::MAX as usize; + +use crate::arbitrary::*; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +macro_rules! impl_wrap_char { + ($type: ty, $mapper: expr) => { + arbitrary!($type, SMapped; + static_map(any::(), $mapper)); + }; +} + +impl_wrap_char!(EscapeDebug, char::escape_debug); +impl_wrap_char!(EscapeDefault, char::escape_default); +impl_wrap_char!(EscapeUnicode, char::escape_unicode); +#[cfg(feature = "unstable")] +impl_wrap_char!(ToLowercase, char::to_lowercase); +#[cfg(feature = "unstable")] +impl_wrap_char!(ToUppercase, char::to_uppercase); + +#[cfg(feature = "break-dead-code")] +arbitrary!(DecodeUtf16< as IntoIterator>::IntoIter>, + SMapped, Self>; + static_map(vec(any::(), ..VEC_MAX), decode_utf16) +); + +arbitrary!(ParseCharError, IndFlatten>>; + any::().prop_ind_flat_map(|is_two| + Just((if is_two { "__" } else { "" }).parse::().unwrap_err())) +); + +#[cfg(feature = "unstable")] +arbitrary!(CharTryFromError; { + use core::convert::TryFrom; + char::try_from(0xD800 as u32).unwrap_err() +}); + +arbitrary!(DecodeUtf16Error, SFnPtrMap, Self>; + static_map(0xD800..0xE000, |x| + decode_utf16(once(x)).next().unwrap().unwrap_err()) +); + +#[cfg(test)] +mod test { + no_panic_test!( + escape_debug => EscapeDebug, + escape_default => EscapeDefault, + escape_unicode => EscapeUnicode, + parse_char_error => ParseCharError, + decode_utf16_error => DecodeUtf16Error + ); + + #[cfg(feature = "break-dead-code")] + no_panic_test!( + decode_utf16 => DecodeUtf16< as IntoIterator>::IntoIter> + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + to_lowercase => ToLowercase, + to_uppercase => ToUppercase, + char_try_from_error => CharTryFromError + ); +} diff --git a/library/proptest/src/arbitrary/_alloc/collections.rs b/library/proptest/src/arbitrary/_alloc/collections.rs new file mode 100644 index 000000000000..59e02f000cc1 --- /dev/null +++ b/library/proptest/src/arbitrary/_alloc/collections.rs @@ -0,0 +1,284 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::collections`. + +//#![cfg_attr(feature="cargo-clippy", allow(implicit_hasher))] + +//============================================================================== +// Imports: +//============================================================================== + +use crate::std_facade::{ + binary_heap, btree_map, btree_set, fmt, linked_list, vec, vec_deque, Arc, BTreeMap, BTreeSet, + BinaryHeap, Box, LinkedList, Rc, Vec, VecDeque, +}; +use core::hash::Hash; +use core::ops::{Bound, RangeInclusive}; + +#[cfg(feature = "std")] +use crate::std_facade::{hash_map, hash_set, HashMap, HashSet}; + +use crate::arbitrary::*; +use crate::collection::*; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +//============================================================================== +// Macros: +//============================================================================== + +/// Parameters for configuring the generation of `StrategyFor<...>`. +type RangedParams1 = product_type![SizeRange, A]; + +/// Parameters for configuring the generation of `StrategyFor<...>`. +type RangedParams2 = product_type![SizeRange, A, B]; + +macro_rules! impl_1 { + ($typ: ident, $strat: ident, $($bound : path),* => $fun: ident) => { + arbitrary!([A: Arbitrary $(+ $bound)*] $typ, + $strat, RangedParams1; + args => { + let product_unpack![range, a] = args; + $fun(any_with::(a), range) + }); + + lift1!([$($bound+)*] $typ, SizeRange; + base, args => $fun(base, args)); + }; +} + +arbitrary!(SizeRange, MapInto>, Self>; + any::>().prop_map_into() +); + +//============================================================================== +// Vec, VecDeque, LinkedList, BTreeSet, BinaryHeap, HashSet, HashMap: +//============================================================================== + +macro_rules! dst_wrapped { + ($($w: ident),*) => { + $(arbitrary!([A: Arbitrary] $w<[A]>, + MapInto>, Self>, + as Arbitrary>::Parameters; + a => any_with::>(a).prop_map_into() + );)* + }; +} + +impl_1!(Vec, VecStrategy, => vec); +dst_wrapped!(Box, Rc, Arc); +impl_1!(VecDeque, VecDequeStrategy, => vec_deque); +impl_1!(LinkedList, LinkedListStrategy, => linked_list); +impl_1!(BTreeSet, BTreeSetStrategy, Ord => btree_set); +impl_1!(BinaryHeap, BinaryHeapStrategy, Ord => binary_heap); +#[cfg(feature = "std")] +impl_1!(HashSet, HashSetStrategy, Hash, Eq => hash_set); + +//============================================================================== +// IntoIterator: +//============================================================================== + +macro_rules! into_iter_1 { + ($module: ident, $type: ident $(, $bound : path)*) => { + arbitrary!([A: Arbitrary $(+ $bound)*] + $module::IntoIter, + SMapped<$type, Self>, + <$type as Arbitrary>::Parameters; + args => static_map(any_with::<$type>(args), $type::into_iter)); + + lift1!(['static + $($bound+)*] $module::IntoIter, SizeRange; + base, args => + $module(base, args).prop_map($type::into_iter)); + }; +} + +into_iter_1!(vec, Vec); +into_iter_1!(vec_deque, VecDeque); +into_iter_1!(linked_list, LinkedList); +into_iter_1!(btree_set, BTreeSet, Ord); +into_iter_1!(binary_heap, BinaryHeap, Ord); +#[cfg(feature = "std")] +into_iter_1!(hash_set, HashSet, Hash, Eq); + +//============================================================================== +// HashMap: +//============================================================================== + +#[cfg(feature = "std")] +arbitrary!([A: Arbitrary + Hash + Eq, B: Arbitrary] HashMap, +HashMapStrategy, +RangedParams2; +args => { + let product_unpack![range, a, b] = args; + hash_map(any_with::(a), any_with::(b), range) +}); + +#[cfg(feature = "std")] +arbitrary!([A: Arbitrary + Hash + Eq, B: Arbitrary] hash_map::IntoIter, + SMapped, Self>, + as Arbitrary>::Parameters; + args => static_map(any_with::>(args), HashMap::into_iter)); + +#[cfg(feature = "std")] +lift1!([, K: Hash + Eq + Arbitrary + 'static] HashMap, + RangedParams1; + base, args => { + let product_unpack![range, k] = args; + hash_map(any_with::(k), base, range) + } +); + +#[cfg(feature = "std")] +lift1!(['static, K: Hash + Eq + Arbitrary + 'static] hash_map::IntoIter, + RangedParams1; + base, args => { + let product_unpack![range, k] = args; + static_map(hash_map(any_with::(k), base, range), HashMap::into_iter) + } +); + +#[cfg(feature = "std")] +impl functor::ArbitraryF2 for HashMap { + type Parameters = SizeRange; + + fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + hash_map(fst, snd, args).boxed() + } +} + +#[cfg(feature = "std")] +impl functor::ArbitraryF2 + for hash_map::IntoIter +{ + type Parameters = SizeRange; + + fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + static_map(hash_map(fst, snd, args), HashMap::into_iter).boxed() + } +} + +//============================================================================== +// BTreeMap: +//============================================================================== + +arbitrary!([A: Arbitrary + Ord, B: Arbitrary] BTreeMap, +BTreeMapStrategy, +RangedParams2; +args => { + let product_unpack![range, a, b] = args; + btree_map(any_with::(a), any_with::(b), range) +}); + +lift1!([, K: Ord + Arbitrary + 'static] BTreeMap, + RangedParams1; + base, args => { + let product_unpack![range, k] = args; + btree_map(any_with::(k), base, range) + } +); + +impl functor::ArbitraryF2 for BTreeMap { + type Parameters = SizeRange; + fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + btree_map(fst, snd, args).boxed() + } +} + +arbitrary!([A: Arbitrary + Ord, B: Arbitrary] btree_map::IntoIter, + SMapped, Self>, + as Arbitrary>::Parameters; + args => static_map(any_with::>(args), BTreeMap::into_iter)); + +impl functor::ArbitraryF2 + for btree_map::IntoIter +{ + type Parameters = SizeRange; + + fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + static_map(btree_map(fst, snd, args), BTreeMap::into_iter).boxed() + } +} + +//============================================================================== +// Bound: +//============================================================================== + +arbitrary!([A: Arbitrary] Bound, + TupleUnion<( + WA, Self>>, + WA, Self>>, + WA> + )>, + A::Parameters; + args => { + let base = Arc::new(any_with::(args)); + prop_oneof![ + 2 => static_map(base.clone(), Bound::Included), + 2 => static_map(base, Bound::Excluded), + 1 => LazyJust::new(|| Bound::Unbounded), + ] + } +); + +lift1!(['static] Bound; base => { + let base = Rc::new(base); + prop_oneof![ + 2 => base.clone().prop_map(Bound::Included), + 2 => base.prop_map(Bound::Excluded), + 1 => LazyJustFn::new(|| Bound::Unbounded), + ] +}); + +#[cfg(test)] +mod test { + no_panic_test!( + size_bounds => SizeRange, + vec => Vec, + box_slice => Box<[u8]>, + rc_slice => Rc<[u8]>, + arc_slice => Arc<[u8]>, + vec_deque => VecDeque, + linked_list => LinkedList, + btree_set => BTreeSet, + btree_map => BTreeMap, + bound => Bound, + binary_heap => BinaryHeap, + into_iter_vec => vec::IntoIter, + into_iter_vec_deque => vec_deque::IntoIter, + into_iter_linked_list => linked_list::IntoIter, + into_iter_binary_heap => binary_heap::IntoIter, + into_iter_btree_set => btree_set::IntoIter, + into_iter_btree_map => btree_map::IntoIter + ); + + #[cfg(feature = "std")] + no_panic_test!( + hash_set => HashSet, + hash_map => HashMap, + into_iter_hash_set => hash_set::IntoIter, + into_iter_hash_map => hash_map::IntoIter + ); +} diff --git a/library/proptest/src/arbitrary/_alloc/hash.rs b/library/proptest/src/arbitrary/_alloc/hash.rs new file mode 100644 index 000000000000..8979bafca47b --- /dev/null +++ b/library/proptest/src/arbitrary/_alloc/hash.rs @@ -0,0 +1,32 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::hash`. + +#[cfg(feature = "std")] +use crate::std_facade::hash_map::{DefaultHasher, RandomState}; +use core::hash::{BuildHasherDefault, Hasher}; + +// NOTE: don't impl for std::hash::SipHasher.. since deprecated! + +// over-constrain on purpose! +arbitrary!([H: Default + Hasher] BuildHasherDefault; Default::default()); + +#[cfg(feature = "std")] +lazy_just!(DefaultHasher, Default::default; RandomState, Default::default); + +#[cfg(test)] +mod test { + #[cfg(feature = "std")] + no_panic_test!( + default_hasher => DefaultHasher, + random_state => RandomState, + build_hasher_default => BuildHasherDefault + ); +} diff --git a/library/proptest/src/arbitrary/_alloc/mod.rs b/library/proptest/src/arbitrary/_alloc/mod.rs new file mode 100644 index 000000000000..f286cab6d87f --- /dev/null +++ b/library/proptest/src/arbitrary/_alloc/mod.rs @@ -0,0 +1,22 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for liballoc. + +#[cfg(feature = "unstable")] +mod alloc; +mod borrow; +mod boxed; +mod char; +mod collections; +mod hash; +mod ops; +mod rc; +mod str; +mod sync; diff --git a/library/proptest/src/arbitrary/_alloc/ops.rs b/library/proptest/src/arbitrary/_alloc/ops.rs new file mode 100644 index 000000000000..ad9b6fc23179 --- /dev/null +++ b/library/proptest/src/arbitrary/_alloc/ops.rs @@ -0,0 +1,97 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::ops`. + +use crate::std_facade::Arc; +use core::ops::*; + +use crate::arbitrary::*; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +arbitrary!(RangeFull; ..); +wrap_ctor!(RangeFrom, |a| a..); +wrap_ctor!(RangeTo, |a| ..a); + +wrap_ctor!(RangeToInclusive, |a| ..=a); + +arbitrary!( + [A: PartialOrd + Arbitrary] RangeInclusive, + SMapped<(A, A), Self>, product_type![A::Parameters, A::Parameters]; + args => static_map(any_with::<(A, A)>(args), + |(a, b)| if b < a { b..=a } else { a..=b }) +); + +lift1!([PartialOrd] RangeInclusive; base => { + let base = Arc::new(base); + (base.clone(), base).prop_map(|(a, b)| if b < a { b..=a } else { a..=b }) +}); + +arbitrary!( + [A: PartialOrd + Arbitrary] Range, + SMapped<(A, A), Self>, product_type![A::Parameters, A::Parameters]; + args => static_map(any_with::<(A, A)>(args), + |(a, b)| if b < a { b..a } else { a..b }) +); + +lift1!([PartialOrd] Range; base => { + let base = Arc::new(base); + (base.clone(), base).prop_map(|(a, b)| if b < a { b..a } else { a..b }) +}); + +#[cfg(feature = "unstable")] +arbitrary!( + [Y: Arbitrary, R: Arbitrary] GeneratorState, + TupleUnion<(WA>, WA>)>, + product_type![Y::Parameters, R::Parameters]; + args => { + let product_unpack![y, r] = args; + prop_oneof![ + static_map(any_with::(y), GeneratorState::Yielded), + static_map(any_with::(r), GeneratorState::Complete) + ] + } +); + +#[cfg(feature = "unstable")] +use core::fmt; + +#[cfg(feature = "unstable")] +impl functor::ArbitraryF2 + for GeneratorState +{ + type Parameters = (); + + fn lift2_with(fst: AS, snd: BS, _args: Self::Parameters) -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + prop_oneof![fst.prop_map(GeneratorState::Yielded), snd.prop_map(GeneratorState::Complete)] + .boxed() + } +} + +#[cfg(test)] +mod test { + no_panic_test!( + range_full => RangeFull, + range_from => RangeFrom, + range_to => RangeTo, + range => Range, + range_inclusive => RangeInclusive, + range_to_inclusive => RangeToInclusive + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + generator_state => GeneratorState + ); +} diff --git a/library/proptest/src/arbitrary/_alloc/rc.rs b/library/proptest/src/arbitrary/_alloc/rc.rs new file mode 100644 index 000000000000..1ddb6aa00b54 --- /dev/null +++ b/library/proptest/src/arbitrary/_alloc/rc.rs @@ -0,0 +1,21 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::rc`. + +use crate::std_facade::Rc; + +// Weak would always give None on upgrade since there's no owned Rc. + +wrap_from!(Rc); + +#[cfg(test)] +mod test { + no_panic_test!(rc => Rc); +} diff --git a/library/proptest/src/arbitrary/_alloc/str.rs b/library/proptest/src/arbitrary/_alloc/str.rs new file mode 100644 index 000000000000..72ba248da95f --- /dev/null +++ b/library/proptest/src/arbitrary/_alloc/str.rs @@ -0,0 +1,49 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::str`. + +use crate::std_facade::Vec; +use core::iter::repeat; +use core::str::{from_utf8, ParseBoolError, Utf8Error}; + +use crate::arbitrary::*; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +arbitrary!(ParseBoolError; "".parse::().unwrap_err()); + +type ELSeq = WA>; +type ELSeqs = TupleUnion<(ELSeq, ELSeq, ELSeq, ELSeq)>; + +fn gen_el_seqs() -> ELSeqs { + prop_oneof![ + Just(&[0xC2]), // None + Just(&[0x80]), // Some(1) + Just(&[0xE0, 0xA0, 0x00]), // Some(2) + Just(&[0xF0, 0x90, 0x80, 0x00]) // Some(3) + ] +} + +arbitrary!(Utf8Error, SFnPtrMap<(StrategyFor, ELSeqs), Utf8Error>; + static_map((any::(), gen_el_seqs()), |(vut, elseq)| { + let v = repeat(b'_').take(vut as usize) + .chain(elseq.iter().cloned()) + .collect::>(); + from_utf8(&v).unwrap_err() + }) +); + +#[cfg(test)] +mod test { + no_panic_test!( + parse_bool_errror => ParseBoolError, + utf8_error => Utf8Error + ); +} diff --git a/library/proptest/src/arbitrary/_alloc/sync.rs b/library/proptest/src/arbitrary/_alloc/sync.rs new file mode 100644 index 000000000000..ebc22258155f --- /dev/null +++ b/library/proptest/src/arbitrary/_alloc/sync.rs @@ -0,0 +1,76 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::sync`. + +use crate::std_facade::Arc; +use core::sync::atomic::*; + +use crate::arbitrary::*; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +wrap_from!(Arc); + +macro_rules! atomic { + ($($type: ident, $base: ty);+) => { + $(arbitrary!($type, SMapped<$base, Self>; + static_map(any::<$base>(), $type::new) + );)+ + }; +} + +// impl_wrap_gen!(AtomicPtr); // We don't have impl Arbitrary for *mut T yet. +atomic!(AtomicBool, bool; AtomicIsize, isize; AtomicUsize, usize); + +#[cfg(feature = "unstable")] +atomic!(AtomicI8, i8; AtomicI16, i16; AtomicI32, i32; + AtomicU8, u8; AtomicU16, u16; AtomicU32, u32); + +#[cfg(all(feature = "unstable", feature = "atomic64bit"))] +atomic!(AtomicI64, i64; AtomicU64, u64); + +arbitrary!(Ordering, + TupleUnion<(WA>, WA>, WA>, + WA>, WA>)>; + prop_oneof![ + Just(Ordering::Relaxed), + Just(Ordering::Release), + Just(Ordering::Acquire), + Just(Ordering::AcqRel), + Just(Ordering::SeqCst) + ] +); + +#[cfg(test)] +mod test { + no_panic_test!( + arc => Arc, + atomic_bool => AtomicBool, + atomic_isize => AtomicIsize, + atomic_usize => AtomicUsize, + ordering => Ordering + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + atomic_i8 => AtomicI8, + atomic_i16 => AtomicI16, + atomic_i32 => AtomicI32, + atomic_u8 => AtomicU8, + atomic_u16 => AtomicU16, + atomic_u32 => AtomicU32 + ); + + #[cfg(all(feature = "unstable", feature = "atomic64bit"))] + no_panic_test!( + atomic_i64 => AtomicI64, + atomic_u64 => AtomicU64 + ); +} diff --git a/library/proptest/src/arbitrary/_core/ascii.rs b/library/proptest/src/arbitrary/_core/ascii.rs new file mode 100644 index 000000000000..ded19289bf73 --- /dev/null +++ b/library/proptest/src/arbitrary/_core/ascii.rs @@ -0,0 +1,23 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::ascii`. + +use core::ascii::{escape_default, EscapeDefault}; + +use crate::arbitrary::*; +use crate::strategy::statics::static_map; + +arbitrary!(EscapeDefault, SMapped; + static_map(any::(), escape_default)); + +#[cfg(test)] +mod test { + no_panic_test!(escape_default => EscapeDefault); +} diff --git a/library/proptest/src/arbitrary/_core/cell.rs b/library/proptest/src/arbitrary/_core/cell.rs new file mode 100644 index 000000000000..c10148fb99b5 --- /dev/null +++ b/library/proptest/src/arbitrary/_core/cell.rs @@ -0,0 +1,48 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::cell`. + +use core::cell::{BorrowError, BorrowMutError, Cell, RefCell, UnsafeCell}; + +wrap_from!([Copy] Cell); +wrap_from!(RefCell); +wrap_from!(UnsafeCell); + +lazy_just!(BorrowError, || { + // False positive: + #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))] + { + let _rc = RefCell::new(()); + let _bm = _rc.borrow_mut(); + let _tb = _rc.try_borrow(); + let ret = _rc.try_borrow().expect_err("reborrowed RefCell"); + ret + } +}); +lazy_just!(BorrowMutError, || { + // False positive: + #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))] + { + let _rc = RefCell::new(()); + let _bm = _rc.borrow_mut(); + let _tb = _rc.try_borrow(); + let ret = _rc.try_borrow_mut().expect_err("reborrowed RefCell"); + ret + } +}); + +#[cfg(test)] +mod test { + no_panic_test!( + cell => Cell, + ref_cell => RefCell, + unsafe_cell => UnsafeCell + ); +} diff --git a/library/proptest/src/arbitrary/_core/cmp.rs b/library/proptest/src/arbitrary/_core/cmp.rs new file mode 100644 index 000000000000..75637d45c2f3 --- /dev/null +++ b/library/proptest/src/arbitrary/_core/cmp.rs @@ -0,0 +1,33 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::cmp`. + +use core::cmp::{Ordering, Reverse}; + +use crate::strategy::{Just, TupleUnion, WA}; + +wrap_ctor!(Reverse, Reverse); + +type WAJO = WA>; +arbitrary!(Ordering, TupleUnion<(WAJO, WAJO, WAJO)>; + prop_oneof![ + Just(Ordering::Equal), + Just(Ordering::Less), + Just(Ordering::Greater) + ] +); + +#[cfg(test)] +mod test { + no_panic_test!( + reverse => Reverse, + ordering => Ordering + ); +} diff --git a/library/proptest/src/arbitrary/_core/convert.rs b/library/proptest/src/arbitrary/_core/convert.rs new file mode 100644 index 000000000000..b74d786204ec --- /dev/null +++ b/library/proptest/src/arbitrary/_core/convert.rs @@ -0,0 +1,16 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::convert`. + +// No sensible Arbitrary impl exists for void-like types like +// std::convert::Infallible. +// +// Auto-deriving should take care to simply not include such +// types in generation instead! diff --git a/library/proptest/src/arbitrary/_core/fmt.rs b/library/proptest/src/arbitrary/_core/fmt.rs new file mode 100644 index 000000000000..b16b8968c18c --- /dev/null +++ b/library/proptest/src/arbitrary/_core/fmt.rs @@ -0,0 +1,18 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::fmt`. + +use core::fmt::Error; +arbitrary!(Error; Error); + +#[cfg(test)] +mod test { + no_panic_test!(error => Error); +} diff --git a/library/proptest/src/arbitrary/_core/iter.rs b/library/proptest/src/arbitrary/_core/iter.rs new file mode 100644 index 000000000000..5e48a01d8591 --- /dev/null +++ b/library/proptest/src/arbitrary/_core/iter.rs @@ -0,0 +1,173 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::iter`. + +use core::fmt; +use core::iter::Fuse; +use core::iter::*; + +use crate::arbitrary::*; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +// TODO: Filter, FilterMap, FlatMap, Map, Inspect, Scan, SkipWhile +// Might be possible with CoArbitrary + +wrap_ctor!(Once, once); +wrap_ctor!([Clone] Repeat, repeat); +wrap_ctor!([Iterator + Clone] Cycle, Iterator::cycle); +wrap_ctor!([Iterator] Enumerate, Iterator::enumerate); +wrap_ctor!([Iterator] Fuse, Iterator::fuse); +wrap_ctor!([Iterator, T: fmt::Debug] Peekable, Iterator::peekable); +wrap_ctor!([DoubleEndedIterator] Rev, Iterator::rev); + +arbitrary!(['a, T: 'a + Clone, A: Arbitrary + Iterator] + Cloned, SMapped, A::Parameters; + args => static_map(any_with::(args), Iterator::cloned)); + +impl> + functor::ArbitraryF1 for Cloned +{ + type Parameters = (); + + fn lift1_with(base: S, _args: Self::Parameters) -> BoxedStrategy + where + S: Strategy + 'static, + { + base.prop_map(Iterator::cloned).boxed() + } +} + +arbitrary!([A] Empty; empty()); + +arbitrary!( + [A: Arbitrary + Iterator, B: Arbitrary + Iterator] + Zip, SMapped<(A, B), Self>, + product_type![A::Parameters, B::Parameters]; + args => static_map(any_with::<(A, B)>(args), |(a, b)| a.zip(b)) +); + +lift1!( + [fmt::Debug + 'static + Iterator, B: 'static + Arbitrary + Iterator] + Zip, + B::Parameters; + base, args => + (any_with::(args), base).prop_map(|(b, a)| b.zip(a)).boxed() +); + +impl functor::ArbitraryF2 for Zip { + type Parameters = (); + + fn lift2_with(fst: AS, snd: BS, _args: Self::Parameters) -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + (fst, snd).prop_map(|(a, b)| a.zip(b)).boxed() + } +} + +arbitrary!( + [T, + A: Arbitrary + Iterator, + B: Arbitrary + Iterator] + Chain, SMapped<(A, B), Self>, + product_type![A::Parameters, B::Parameters]; + args => static_map(any_with::<(A, B)>(args), |(a, b)| a.chain(b)) +); + +lift1!([fmt::Debug + 'static + Iterator, + B: 'static + Arbitrary + Iterator, + T] + Chain, + B::Parameters; + base, args => + (any_with::(args), base).prop_map(|(b, a)| b.chain(a)).boxed() +); + +impl, B: fmt::Debug + Iterator> + functor::ArbitraryF2 for Chain +{ + type Parameters = (); + + fn lift2_with(fst: AS, snd: BS, _args: Self::Parameters) -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + (fst, snd).prop_map(|(a, b)| a.chain(b)).boxed() + } +} + +macro_rules! usize_mod { + ($type: ident, $mapper: ident) => { + arbitrary!([A: Arbitrary + Iterator] $type, + SMapped<(A, usize), Self>, A::Parameters; + a => static_map( + any_with::<(A, usize)>(product_pack![a, ()]), + |(a, b)| a.$mapper(b) + ) + ); + + lift1!([Iterator] $type; + base => (base, any::()).prop_map(|(a, b)| a.$mapper(b)) + ); + }; +} + +usize_mod!(Skip, skip); +usize_mod!(Take, take); + +#[cfg(feature = "unstable")] +usize_mod!(StepBy, step_by); + +#[cfg(test)] +mod test { + use super::*; + + use std::ops::Range; + const DUMMY: &'static [u8] = &[0, 1, 2, 3, 4]; + #[derive(Debug)] + struct Dummy(u8); + arbitrary!(Dummy, SFnPtrMap, Self>; static_map(0..5, Dummy)); + impl Iterator for Dummy { + type Item = &'static u8; + fn next(&mut self) -> Option { + if self.0 < 5 { + let r = &DUMMY[self.0 as usize]; + self.0 += 1; + Some(r) + } else { + None + } + } + } + + no_panic_test!( + empty => Empty, + once => Once, + repeat => Repeat, + cloned => Cloned, + cycle => Cycle>, + enumerate => Enumerate>, + fuse => Fuse>, + peekable => Peekable>, + rev => Rev<::std::vec::IntoIter>, + zip => Zip, Repeat>, + chain => Chain, Once>, + skip => Skip>, + take => Take> + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + step_by => StepBy> + ); +} diff --git a/library/proptest/src/arbitrary/_core/marker.rs b/library/proptest/src/arbitrary/_core/marker.rs new file mode 100644 index 000000000000..6558f57ab7f3 --- /dev/null +++ b/library/proptest/src/arbitrary/_core/marker.rs @@ -0,0 +1,19 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::marker`. + +use core::marker::PhantomData; + +arbitrary!([T: ?Sized] PhantomData; PhantomData); + +#[cfg(test)] +mod test { + no_panic_test!(phantom_data => PhantomData); +} diff --git a/library/proptest/src/arbitrary/_core/mem.rs b/library/proptest/src/arbitrary/_core/mem.rs new file mode 100644 index 000000000000..700e40fbe998 --- /dev/null +++ b/library/proptest/src/arbitrary/_core/mem.rs @@ -0,0 +1,42 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::mem`. + +use core::mem::*; + +use crate::arbitrary::*; +use crate::strategy::statics::static_map; + +arbitrary!([A: Arbitrary] Discriminant, + SMapped, A::Parameters; + args => static_map(any_with::(args), |x| discriminant(&x)) +); + +lift1!(['static] Discriminant; + base => static_map(base, |x| discriminant(&x)) +); + +// Not supported at the moment since the user won't be able to call +// https://doc.rust-lang.org/nightly/std/mem/union.ManuallyDrop.html#method.drop +// in any case so the use case is not great for this. +//wrap_ctor!(ManuallyDrop); + +#[cfg(test)] +mod test { + #[derive(Copy, Clone, Debug)] + struct DummyStruct; + arbitrary!(DummyStruct; DummyStruct); + + no_panic_test!( + //manually_drop => ManuallyDrop, // Trivial destructor. + discriminant_struct => Discriminant, + discriminant_enum => Discriminant<::std::num::FpCategory> + ); +} diff --git a/library/proptest/src/arbitrary/_core/mod.rs b/library/proptest/src/arbitrary/_core/mod.rs new file mode 100644 index 000000000000..5fc3742e490e --- /dev/null +++ b/library/proptest/src/arbitrary/_core/mod.rs @@ -0,0 +1,22 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for libcore. + +mod ascii; +mod cell; +mod cmp; +mod convert; +mod fmt; +mod iter; +mod marker; +mod mem; +mod num; +mod option; +mod result; diff --git a/library/proptest/src/arbitrary/_core/num.rs b/library/proptest/src/arbitrary/_core/num.rs new file mode 100644 index 000000000000..f2988ecf0f3e --- /dev/null +++ b/library/proptest/src/arbitrary/_core/num.rs @@ -0,0 +1,55 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::num`. + +use core::num::*; + +use crate::strategy::*; + +arbitrary!(ParseFloatError; "".parse::().unwrap_err()); +arbitrary!(ParseIntError; "".parse::().unwrap_err()); + +#[cfg(feature = "unstable")] +arbitrary!(TryFromIntError; { + use core::convert::TryFrom; + u8::try_from(-1).unwrap_err() +}); + +wrap_ctor!(Wrapping, Wrapping); + +arbitrary!(FpCategory, + TupleUnion<(WA>, WA>, WA>, + WA>, WA>)>; + { + use core::num::FpCategory::*; + prop_oneof![ + Just(Nan), + Just(Infinite), + Just(Zero), + Just(Subnormal), + Just(Normal), + ] + } +); + +#[cfg(test)] +mod test { + no_panic_test!( + parse_float_error => ParseFloatError, + parse_int_error => ParseIntError, + wrapping => Wrapping, + fp_category => FpCategory + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + try_from_int_error => TryFromIntError + ); +} diff --git a/library/proptest/src/arbitrary/_core/option.rs b/library/proptest/src/arbitrary/_core/option.rs new file mode 100644 index 000000000000..1e7d2c33457b --- /dev/null +++ b/library/proptest/src/arbitrary/_core/option.rs @@ -0,0 +1,60 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::option`. + +use crate::std_facade::string; +use core::ops::RangeInclusive; +use core::option as opt; + +use crate::arbitrary::*; +use crate::option::{weighted, OptionStrategy, Probability}; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +arbitrary!(Probability, MapInto, Self>; + (0.0..=1.0).prop_map_into() +); + +// These are Option impls: + +arbitrary!(Option; None); +#[cfg(feature = "unstable")] +arbitrary!(Option; None); + +arbitrary!([A: Arbitrary] opt::Option, OptionStrategy, + product_type![Probability, A::Parameters]; + args => { + let product_unpack![prob, a] = args; + weighted(prob, any_with::(a)) + } +); + +lift1!([] Option, Probability; base, prob => weighted(prob, base)); + +arbitrary!([A: Arbitrary] opt::IntoIter, SMapped, Self>, + as Arbitrary>::Parameters; + args => static_map(any_with::>(args), Option::into_iter)); + +lift1!(['static] opt::IntoIter, Probability; + base, prob => weighted(prob, base).prop_map(Option::into_iter) +); + +#[cfg(feature = "unstable")] +arbitrary!(opt::NoneError; opt::NoneError); + +#[cfg(test)] +mod test { + no_panic_test!( + probability => Probability, + option => Option, + option_iter => opt::IntoIter, + option_parse_error => Option + ); +} diff --git a/library/proptest/src/arbitrary/_core/result.rs b/library/proptest/src/arbitrary/_core/result.rs new file mode 100644 index 000000000000..7da3324f7e32 --- /dev/null +++ b/library/proptest/src/arbitrary/_core/result.rs @@ -0,0 +1,104 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::result`. + +use crate::std_facade::string; +use core::fmt; +use core::result::IntoIter; + +use crate::arbitrary::*; +use crate::result::*; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +// These are Result with uninhabited type in some variant: +arbitrary!([A: Arbitrary] Result, + SMapped, A::Parameters; + args => static_map(any_with::(args), Result::Ok) +); +arbitrary!([A: Arbitrary] Result, + SMapped, A::Parameters; + args => static_map(any_with::(args), Result::Err) +); +#[cfg(feature = "unstable")] +arbitrary!([A: Arbitrary] Result, + SMapped, A::Parameters; + args => static_map(any_with::(args), Result::Ok) +); +#[cfg(feature = "unstable")] +arbitrary!([A: Arbitrary] Result, + SMapped, A::Parameters; + args => static_map(any_with::(args), Result::Err) +); + +lift1!([] Result; Result::Ok); +#[cfg(feature = "unstable")] +lift1!([] Result; Result::Ok); + +// We assume that `MaybeOk` is canonical as it's the most likely Strategy +// a user wants. + +arbitrary!([A: Arbitrary, B: Arbitrary] Result, + MaybeOk, + product_type![Probability, A::Parameters, B::Parameters]; + args => { + let product_unpack![prob, a, b] = args; + let (p, a, b) = (prob, any_with::(a), any_with::(b)); + maybe_ok_weighted(p, a, b) + } +); + +impl functor::ArbitraryF1 for Result +where + E::Strategy: 'static, +{ + type Parameters = product_type![Probability, E::Parameters]; + + fn lift1_with(base: AS, args: Self::Parameters) -> BoxedStrategy + where + AS: Strategy + 'static, + { + let product_unpack![prob, e] = args; + let (p, a, e) = (prob, base, any_with::(e)); + maybe_ok_weighted(p, a, e).boxed() + } +} + +impl functor::ArbitraryF2 for Result { + type Parameters = Probability; + + fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + maybe_ok_weighted(args, fst, snd).boxed() + } +} + +arbitrary!([A: Arbitrary] IntoIter, + SMapped, Self>, + as Arbitrary>::Parameters; + args => static_map(any_with::>(args), Result::into_iter) +); + +lift1!(['static] IntoIter, Probability; base, args => { + maybe_ok_weighted(args, base, Just(())).prop_map(Result::into_iter) +}); + +#[cfg(test)] +mod test { + no_panic_test!( + result => Result, + into_iter => IntoIter, + result_a_parse_error => Result, + result_parse_error_a => Result<::std::string::ParseError, u8> + ); +} diff --git a/library/proptest/src/arbitrary/_std/env.rs b/library/proptest/src/arbitrary/_std/env.rs new file mode 100644 index 000000000000..384945c79e57 --- /dev/null +++ b/library/proptest/src/arbitrary/_std/env.rs @@ -0,0 +1,139 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::env`. + +use std::env::*; +use std::ffi::OsString; +use std::iter::once; + +use crate::arbitrary::*; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +// FIXME: SplitPaths when lifetimes in strategies are possible. + +lazy_just!( + Args, args; + ArgsOs, args_os; + Vars, vars; + VarsOs, vars_os; + JoinPathsError, jpe +); + +#[cfg(not(target_os = "windows"))] +fn jpe() -> JoinPathsError { + join_paths(once(":")).unwrap_err() +} + +#[cfg(target_os = "windows")] +fn jpe() -> JoinPathsError { + join_paths(once("\"")).unwrap_err() +} + +// Algorithm from: https://stackoverflow.com/questions/47749164 +#[cfg(any(target_os = "windows", test))] +fn make_utf16_invalid(buf: &mut [u16], p: usize) { + // Verify that length is non-empty. + // An empty string is always valid UTF-16. + assert!(buf.len() > 0); + + // If first elem or previous entry is not a leading surrogate. + let gen_trail = 0 == p || 0xd800 != (buf[p - 1] & 0xfc00); + // If last element or succeeding entry is not a traililng surrogate. + let gen_lead = p == buf.len() - 1 || 0xdc00 != (buf[p + 1] & 0xfc00); + let (force_bits_mask, force_bits_value) = if gen_trail { + if gen_lead { + // Trailing or leading surrogate. + (0xf800, 0xd800) + } else { + // Trailing surrogate. + (0xfc00, 0xdc00) + } + } else { + // Leading surrogate. + // Note that `gen_lead` and `gen_trail` could both be false here if `p` + // lies exactly between a leading and a trailing surrogate. In this + // case, it doesn't matter what we do because the UTF-16 will be + // invalid regardless, so just always force a leading surrogate. + (0xfc00, 0xd800) + }; + debug_assert_eq!(0, (force_bits_value & !force_bits_mask)); + buf[p] = (buf[p] & !force_bits_mask) | force_bits_value; +} + +#[cfg(not(target_arch = "wasm32"))] +mod var_error { + use super::*; + + /// Generates the set of `WTF-16 \ UTF-16` and makes + /// an `OsString` that is not a valid String from it. + #[cfg(target_os = "windows")] + fn osstring_invalid_string() -> impl Strategy { + use std::os::windows::ffi::OsStringExt; + let size = 1..::std::u16::MAX as usize; + let vec_gen = crate::collection::vec(..::std::u16::MAX, size.clone()); + (size, vec_gen).prop_map(|(p, mut sbuf)| { + // Not quite a uniform distribution due to clamping, + // but probably good enough + let p = ::std::cmp::min(p, sbuf.len() - 1); + make_utf16_invalid(&mut sbuf, p); + OsString::from_wide(sbuf.as_slice()).into_string().unwrap_err() + }) + } + + #[cfg(not(target_os = "windows"))] + fn osstring_invalid_string() -> impl Strategy { + use crate::arbitrary::_std::string::not_utf8_bytes; + use std::os::unix::ffi::OsStringExt; + static_map(not_utf8_bytes(true), OsString::from_vec) + } + + arbitrary!(VarError, + TupleUnion<( + WA>, + WA, Self>> + )>; + prop_oneof![ + Just(VarError::NotPresent), + static_map(osstring_invalid_string().boxed(), VarError::NotUnicode) + ] + ); +} + +#[cfg(test)] +mod test { + use super::*; + use crate::num; + use crate::test_runner::Config; + + no_panic_test!( + args => Args, + args_os => ArgsOs, + vars => Vars, + vars_os => VarsOs, + join_paths_error => JoinPathsError, + var_error => VarError + ); + + proptest! { + #![proptest_config(Config { + cases: 65536, + .. Config::default() + })] + + #[test] + fn make_utf16_invalid_doesnt_panic( + mut buf in [num::u16::ANY; 3], + p in 0usize..3 + ) { + make_utf16_invalid(&mut buf, p); + } + } +} diff --git a/library/proptest/src/arbitrary/_std/ffi.rs b/library/proptest/src/arbitrary/_std/ffi.rs new file mode 100644 index 000000000000..288b3947ad98 --- /dev/null +++ b/library/proptest/src/arbitrary/_std/ffi.rs @@ -0,0 +1,100 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::ffi`. + +use crate::std_facade::{Box, String, Vec}; +use std::ffi::*; +use std::ops::RangeInclusive; + +use crate::arbitrary::*; +use crate::collection::*; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +use super::string::not_utf8_bytes; + +arbitrary!(CString, + SFnPtrMap>, Self>, SizeRange; + args => static_map(vec(1..=::std::u8::MAX, args + 1), |mut vec| { + vec.pop().unwrap(); + // Could use: Self::from_vec_unchecked(vec) safely. + Self::new(vec).unwrap() + }) +); + +arbitrary!(OsString, MapInto, Self>, + ::Parameters; + a => any_with::(a).prop_map_into() +); + +macro_rules! dst_wrapped { + ($($w: ident),*) => { + $(arbitrary!($w, MapInto, Self>, SizeRange; + a => any_with::(a).prop_map_into() + );)* + $(arbitrary!($w, MapInto, Self>, + ::Parameters; + a => any_with::(a).prop_map_into() + );)* + }; +} + +dst_wrapped!(Box); + +#[cfg(feature = "unstable")] +use std::rc::Rc; +#[cfg(feature = "unstable")] +use std::sync::Arc; +#[cfg(feature = "unstable")] +dst_wrapped!(Rc, Arc); + +arbitrary!(FromBytesWithNulError, SMapped, Self>; { + static_map(any::>(), |opt_pos| { + // We make some assumptions about the internal structure of + // FromBytesWithNulError. However, these assumptions do not + // involve any non-public API. + if let Some(pos) = opt_pos { + let pos = pos as usize; + // Allocate pos + 2 so that we never reallocate: + let mut v = Vec::::with_capacity(pos + 2); + v.extend(::std::iter::repeat(1).take(pos)); + v.push(0); + v.push(1); + CStr::from_bytes_with_nul(v.as_slice()).unwrap_err() + } else { + CStr::from_bytes_with_nul(b"").unwrap_err() + } + }) +}); + +arbitrary!(IntoStringError, SFnPtrMap>, Self>; + static_map(not_utf8_bytes(false).boxed(), |bytes| + CString::new(bytes).unwrap().into_string().unwrap_err() + ) +); + +#[cfg(test)] +mod test { + no_panic_test!( + c_string => CString, + os_string => OsString, + box_c_str => Box, + box_os_str => Box, + into_string_error => IntoStringError, + from_bytes_with_nul => FromBytesWithNulError + ); + #[cfg(feature = "unstable")] + no_panic_test!( + rc_c_str => Rc, + rc_os_str => Rc, + arc_c_str => Arc, + arc_os_str => Arc + ); +} diff --git a/library/proptest/src/arbitrary/_std/fs.rs b/library/proptest/src/arbitrary/_std/fs.rs new file mode 100644 index 000000000000..66d18ca1ada6 --- /dev/null +++ b/library/proptest/src/arbitrary/_std/fs.rs @@ -0,0 +1,30 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::fs`. + +use std::fs::DirBuilder; + +use crate::arbitrary::{any, SMapped}; +use crate::strategy::statics::static_map; + +// TODO: other parts (figure out workable semantics). + +arbitrary!(DirBuilder, SMapped; { + static_map(any::(), |recursive| { + let mut db = DirBuilder::new(); + db.recursive(recursive); + db + }) +}); + +#[cfg(test)] +mod test { + no_panic_test!(dir_builder => DirBuilder); +} diff --git a/library/proptest/src/arbitrary/_std/io.rs b/library/proptest/src/arbitrary/_std/io.rs new file mode 100644 index 000000000000..34ee9da32ac4 --- /dev/null +++ b/library/proptest/src/arbitrary/_std/io.rs @@ -0,0 +1,164 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::io`. + +use crate::std_facade::String; +#[cfg(test)] +use crate::std_facade::Vec; +use std::io::ErrorKind::*; +use std::io::*; + +use crate::arbitrary::*; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +// TODO: IntoInnerError +// Consider: std::io::Initializer + +macro_rules! buffer { + ($type: ident, $bound: path) => { + arbitrary!( + [A: Arbitrary + $bound] $type, + SMapped<(A, Option), Self>, A::Parameters; + args => static_map( + arbitrary_with(product_pack![args, Default::default()]), + |(inner, cap)| { + if let Some(cap) = cap { + $type::with_capacity(cap as usize, inner) + } else { + $type::new(inner) + } + } + ) + ); + + lift1!([$bound] $type; base => + (base, any::>()).prop_map(|(inner, cap)| { + if let Some(cap) = cap { + $type::with_capacity(cap as usize, inner) + } else { + $type::new(inner) + } + }) + ); + }; +} + +buffer!(BufReader, Read); +buffer!(BufWriter, Write); +buffer!(LineWriter, Write); + +arbitrary!( + [A: Read + Arbitrary, B: Read + Arbitrary] Chain, + SMapped<(A, B), Self>, product_type![A::Parameters, B::Parameters]; + args => static_map(arbitrary_with(args), |(a, b)| a.chain(b)) +); + +wrap_ctor!(Cursor); + +lazy_just!( + Empty, empty + ; Sink, sink + ; Stderr, stderr + ; Stdin, stdin + ; Stdout, stdout +); + +wrap_ctor!([BufRead] Lines, BufRead::lines); + +arbitrary!(Repeat, SMapped; static_map(any::(), repeat)); + +arbitrary!( + [A: BufRead + Arbitrary] Split, SMapped<(A, u8), Self>, A::Parameters; + args => static_map( + arbitrary_with(product_pack![args, Default::default()]), + |(a, b)| a.split(b) + ) +); +lift1!(['static + BufRead] Split; + base => (base, any::()).prop_map(|(a, b)| a.split(b))); + +arbitrary!( + [A: Read + Arbitrary] Take, SMapped<(A, u64), Self>, A::Parameters; + args => static_map( + arbitrary_with(product_pack![args, Default::default()]), + |(a, b)| a.take(b) + ) +); +lift1!(['static + Read] Take; + base => (base, any::()).prop_map(|(a, b)| a.take(b))); + +arbitrary!(ErrorKind, Union>; + Union::new( + [ NotFound + , PermissionDenied + , ConnectionRefused + , ConnectionReset + , ConnectionAborted + , NotConnected + , AddrInUse + , AddrNotAvailable + , BrokenPipe + , AlreadyExists + , WouldBlock + , InvalidInput + , InvalidData + , TimedOut + , WriteZero + , Interrupted + , Other + , UnexpectedEof + // TODO: watch this type for variant-additions. + ].iter().cloned().map(Just)) +); + +arbitrary!( + SeekFrom, + TupleUnion<( + WA>, + WA>, + WA>, + )>; + prop_oneof![ + static_map(any::(), SeekFrom::Start), + static_map(any::(), SeekFrom::End), + static_map(any::(), SeekFrom::Current) + ] +); + +arbitrary!(Error, SMapped<(ErrorKind, Option), Self>; + static_map(arbitrary(), |(k, os)| + if let Some(s) = os { Error::new(k, s) } else { k.into() } + ) +); + +#[cfg(test)] +mod test { + + no_panic_test!( + buf_reader => BufReader, + buf_writer => BufWriter, + line_writer => LineWriter, + chain => Chain>, + cursor => Cursor, + empty => Empty, + sink => Sink, + stderr => Stderr, + stdin => Stdin, + stdout => Stdout, + lines => Lines, + repeat => Repeat, + split => Split>>, + take => Take, + error_kind => ErrorKind, + seek_from => SeekFrom, + error => Error + ); +} diff --git a/library/proptest/src/arbitrary/_std/mod.rs b/library/proptest/src/arbitrary/_std/mod.rs new file mode 100644 index 000000000000..4360f5e0763e --- /dev/null +++ b/library/proptest/src/arbitrary/_std/mod.rs @@ -0,0 +1,22 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for libstd. + +mod env; +mod ffi; +mod fs; +mod io; +mod net; +mod panic; +mod path; +mod string; +mod sync; +mod thread; +mod time; diff --git a/library/proptest/src/arbitrary/_std/net.rs b/library/proptest/src/arbitrary/_std/net.rs new file mode 100644 index 000000000000..fcbec4d61624 --- /dev/null +++ b/library/proptest/src/arbitrary/_std/net.rs @@ -0,0 +1,117 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::net`. + +use std::net::*; + +use crate::arbitrary::*; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +// TODO: Can we design a workable semantic for PBT wrt. actual networking +// connections? + +arbitrary!(AddrParseError; "".parse::().unwrap_err()); + +arbitrary!(Ipv4Addr, + TupleUnion<( + WA>, + WA>, + WA, Self>> + )>; + prop_oneof![ + 1 => Just(Self::new(0, 0, 0, 0)), + 4 => Just(Self::new(127, 0, 0, 1)), + 10 => any::().prop_map_into() + ] +); + +arbitrary!(Ipv6Addr, + TupleUnion<( + WA>, + WA, Self>> + )>; + prop_oneof![ + 2 => static_map(any::(), |ip| ip.to_ipv6_mapped()), + 1 => any::<[u16; 8]>().prop_map_into() + ] +); + +arbitrary!(SocketAddrV4, SMapped<(Ipv4Addr, u16), Self>; + static_map(any::<(Ipv4Addr, u16)>(), |(a, b)| Self::new(a, b)) +); + +arbitrary!(SocketAddrV6, SMapped<(Ipv6Addr, u16, u32, u32), Self>; + static_map(any::<(Ipv6Addr, u16, u32, u32)>(), + |(a, b, c, d)| Self::new(a, b, c, d)) +); + +arbitrary!(IpAddr, + TupleUnion<(WA, Self>>, + WA, Self>>)>; + prop_oneof![ + any::().prop_map_into(), + any::().prop_map_into() + ] +); + +arbitrary!(Shutdown, + TupleUnion<(WA>, WA>, WA>)>; + { + use std::net::Shutdown::*; + prop_oneof![Just(Both), Just(Read), Just(Write)] + } +); +arbitrary!(SocketAddr, + TupleUnion<(WA, Self>>, + WA, Self>>)>; + prop_oneof![ + any::().prop_map_into(), + any::().prop_map_into() + ] +); + +#[cfg(feature = "unstable")] +arbitrary!(Ipv6MulticastScope, + TupleUnion<(WA>, WA>, WA>, + WA>, WA>, WA>, + WA>)>; + { + use std::net::Ipv6MulticastScope::*; + prop_oneof![ + Just(InterfaceLocal), + Just(LinkLocal), + Just(RealmLocal), + Just(AdminLocal), + Just(SiteLocal), + Just(OrganizationLocal), + Just(Global), + ] + } +); + +#[cfg(test)] +mod test { + no_panic_test!( + addr_parse_error => AddrParseError, + ipv4_addr => Ipv4Addr, + ipv6_addr => Ipv6Addr, + socket_addr_v4 => SocketAddrV4, + socket_addr_v6 => SocketAddrV6, + ip_addr => IpAddr, + shutdown => Shutdown, + socket_addr => SocketAddr + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + ipv6_multicast_scope => Ipv6MulticastScope + ); +} diff --git a/library/proptest/src/arbitrary/_std/panic.rs b/library/proptest/src/arbitrary/_std/panic.rs new file mode 100644 index 000000000000..c2bd40cd4a1d --- /dev/null +++ b/library/proptest/src/arbitrary/_std/panic.rs @@ -0,0 +1,19 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::panic`. + +use std::panic::AssertUnwindSafe; + +wrap_ctor!(AssertUnwindSafe, AssertUnwindSafe); + +#[cfg(test)] +mod test { + no_panic_test!(assert_unwind_safe => AssertUnwindSafe); +} diff --git a/library/proptest/src/arbitrary/_std/path.rs b/library/proptest/src/arbitrary/_std/path.rs new file mode 100644 index 000000000000..e7d063c1716e --- /dev/null +++ b/library/proptest/src/arbitrary/_std/path.rs @@ -0,0 +1,23 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::path`. + +use std::path::*; + +// TODO: Figure out PathBuf and then Box/Rc/Box. + +arbitrary!(StripPrefixError; Path::new("").strip_prefix("a").unwrap_err()); + +#[cfg(test)] +mod test { + no_panic_test!( + strip_prefix_error => StripPrefixError + ); +} diff --git a/library/proptest/src/arbitrary/_std/string.rs b/library/proptest/src/arbitrary/_std/string.rs new file mode 100644 index 000000000000..aab3b9a9a521 --- /dev/null +++ b/library/proptest/src/arbitrary/_std/string.rs @@ -0,0 +1,312 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::string`. + +use crate::std_facade::{Box, String, Vec}; +use std::iter; +use std::rc::Rc; +use std::slice; +use std::sync::Arc; + +multiplex_alloc! { + alloc::string::FromUtf8Error, ::std::string::FromUtf8Error, + alloc::string::FromUtf16Error, ::std::string::FromUtf16Error +} + +use crate::arbitrary::*; +use crate::collection; +use crate::strategy::statics::static_map; +use crate::strategy::*; +use crate::string::StringParam; + +impl Arbitrary for String { + type Parameters = StringParam; + type Strategy = &'static str; + + /// ## Panics + /// + /// This implementation panics if the input is not a valid regex proptest + /// can handle. + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + args.into() + } +} + +macro_rules! dst_wrapped { + ($($w: ident),*) => { + $(arbitrary!($w, MapInto, Self>, StringParam; + a => any_with::(a).prop_map_into() + );)* + }; +} + +dst_wrapped!(Box, Rc, Arc); + +lazy_just!(FromUtf16Error, || String::from_utf16(&[0xD800]).unwrap_err()); + +// This is a void-like type, it needs to be handled by the user of +// the type by simply never constructing the variant in an enum or for +// structs by inductively not generating the struct. +// The same applies to ! and Infallible. +// generator!(ParseError, || panic!()); + +arbitrary!(FromUtf8Error, SFnPtrMap>, Self>; + static_map(not_utf8_bytes(true).boxed(), + |bs| String::from_utf8(bs).unwrap_err()) +); + +/// This strategy produces sequences of bytes that are guaranteed to be illegal +/// wrt. UTF-8 with the goal of producing a suffix of bytes in the end of +/// an otherwise legal UTF-8 string that causes the string to be illegal. +/// This is used primarily to generate the `Utf8Error` type and similar. +pub(crate) fn not_utf8_bytes(allow_null: bool) -> impl Strategy> { + let prefix = collection::vec(any::(), ..::std::u16::MAX as usize); + let suffix = gen_el_bytes(allow_null); + (prefix, suffix).prop_map(move |(prefix_bytes, el_bytes)| { + let iter = prefix_bytes.iter(); + let string: String = + if allow_null { iter.collect() } else { iter.filter(|&&x| x != '\u{0}').collect() }; + let mut bytes = string.into_bytes(); + bytes.extend(el_bytes.into_iter()); + bytes + }) +} + +/// Stands for "error_length" bytes and contains a suffix of bytes that +/// will cause the whole string to become invalid UTF-8. +/// See `gen_el_bytes` for more details. +#[derive(Debug)] +enum ELBytes { + B1([u8; 1]), + B2([u8; 2]), + B3([u8; 3]), + B4([u8; 4]), +} + +impl<'a> IntoIterator for &'a ELBytes { + type Item = u8; + type IntoIter = iter::Cloned>; + fn into_iter(self) -> Self::IntoIter { + use self::ELBytes::*; + (match *self { + B1(ref a) => a.iter(), + B2(ref a) => a.iter(), + B3(ref a) => a.iter(), + B4(ref a) => a.iter(), + }) + .cloned() + } +} + +// By analysis of run_utf8_validation defined at: +// https://doc.rust-lang.org/nightly/src/core/str/mod.rs.html#1429 +// we know that .error_len() \in {None, Some(1), Some(2), Some(3)}. +// We represent this with the range [0..4) and generate a valid +// sequence from that. +fn gen_el_bytes(allow_null: bool) -> impl Strategy { + fn b1(a: u8) -> ELBytes { + ELBytes::B1([a]) + } + fn b2(a: (u8, u8)) -> ELBytes { + ELBytes::B2([a.0, a.1]) + } + fn b3(a: ((u8, u8), u8)) -> ELBytes { + ELBytes::B3([(a.0).0, (a.0).1, a.1]) + } + fn b4(a: ((u8, u8), u8, u8)) -> ELBytes { + ELBytes::B4([(a.0).0, (a.0).1, a.1, a.2]) + } + + /* + // https://tools.ietf.org/html/rfc3629 + static UTF8_CHAR_WIDTH: [u8; 256] = [ + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3F + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5F + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7F + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9F + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBF + 0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDF + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEF + 4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, // 0xFF + ]; + + /// Mask of the value bits of a continuation byte. + const CONT_MASK: u8 = 0b0011_1111; + /// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte. + const TAG_CONT_U8: u8 = 0b1000_0000; + */ + + // Continuation byte: + let succ_byte = 0x80u8..0xC0u8; + + // Do we allow the nul byte or not? + let start_byte = if allow_null { 0x00u8 } else { 0x01u8 }; + + // Invalid continuation byte: + let fail_byte = prop_oneof![start_byte..0x7Fu8, 0xC1u8..]; + + // Matches zero in the UTF8_CHAR_WIDTH table above. + let byte0_w0 = prop_oneof![0x80u8..0xC0u8, 0xF5u8..]; + + // Start of a 3 (width) byte sequence: + // Leads here: https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1479 + let byte0_w2 = 0xC2u8..0xE0u8; + + // Start of a 3 (width) byte sequence: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1484 + // See the left column in the match. + let byte0_w3 = 0xE0u8..0xF0u8; + + // Start of a 4 (width) byte sequence: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1495 + // See the left column in the match. + let byte0_w4 = 0xF0u8..0xF5u8; + + // The 2 first (valid) bytes of a 3 (width) byte sequence: + // The first byte is byte0_w3. The second is the ones produced on the right. + let byte01_w3 = byte0_w3.clone().prop_flat_map(|x| { + ( + Just(x), + match x { + 0xE0u8 => 0xA0u8..0xC0u8, + 0xE1u8..=0xECu8 => 0x80u8..0xC0u8, + 0xEDu8 => 0x80u8..0xA0u8, + 0xEEu8..=0xEFu8 => 0x80u8..0xA0u8, + _ => panic!(), + }, + ) + }); + + // In a 3 (width) byte sequence, an invalid second byte is chosen such that + // it will yield an error length of Some(1). The second byte is on + // the right of the match arms. + let byte01_w3_e1 = byte0_w3.clone().prop_flat_map(move |x| { + ( + Just(x), + match x { + 0xE0u8 => prop_oneof![start_byte..0xA0u8, 0xC0u8..], + 0xE1u8..=0xECu8 => prop_oneof![start_byte..0x80u8, 0xC0u8..], + 0xEDu8 => prop_oneof![start_byte..0x80u8, 0xA0u8..], + 0xEEu8..=0xEFu8 => prop_oneof![start_byte..0x80u8, 0xA0u8..], + _ => panic!(), + }, + ) + }); + + // In a 4 (width) byte sequence, an invalid second byte is chosen such that + // it will yield an error length of Some(1). The second byte is on + // the right of the match arms. + let byte01_w4_e1 = byte0_w4.clone().prop_flat_map(move |x| { + ( + Just(x), + match x { + 0xF0u8 => prop_oneof![start_byte..0x90u8, 0xA0u8..], + 0xF1u8..=0xF3u8 => prop_oneof![start_byte..0x80u8, 0xA0u8..], + 0xF4u8 => prop_oneof![start_byte..0x80u8, 0x90u8..], + _ => panic!(), + }, + ) + }); + + // The 2 first (valid) bytes of a 4 (width) byte sequence: + // The first byte is byte0_w4. The second is the ones produced on the right. + let byte01_w4 = byte0_w4.clone().prop_flat_map(|x| { + ( + Just(x), + match x { + 0xF0u8 => 0x90u8..0xA0u8, + 0xF1u8..=0xF3u8 => 0x80u8..0xA0u8, + 0xF4u8 => 0x80u8..0x90u8, + _ => panic!(), + }, + ) + }); + + prop_oneof![ + // error_len = None + // These are all happen when next!() fails to provide a byte. + prop_oneof![ + // width = 2 + // lacking 1 bytes: + static_map(byte0_w2.clone(), b1), + // width = 3 + // lacking 2 bytes: + static_map(byte0_w3, b1), + // lacking 1 bytes: + static_map(byte01_w3.clone(), b2), + // width = 4 + // lacking 3 bytes: + static_map(byte0_w4, b1), + // lacking 2 bytes: + static_map(byte01_w4.clone(), b2), + // lacking 1 byte: + static_map((byte01_w4.clone(), succ_byte.clone()), b3), + ], + // error_len = Some(1) + prop_oneof![ + // width = 1 is not represented. + // width = 0 + // path taken: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1508 + static_map(byte0_w0, b1), + // width = 2 + // path taken: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1480 + static_map((byte0_w2, fail_byte.clone()), b2), + // width = 3 + // path taken: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1488 + static_map(byte01_w3_e1, b2), + // width = 4 + // path taken: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1499 + static_map(byte01_w4_e1, b2), + ], + // error_len = Some(2) + static_map( + prop_oneof![ + // width = 3 + // path taken: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1491 + (byte01_w3, fail_byte.clone()), + // width = 4 + // path taken: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1502 + (byte01_w4.clone(), fail_byte.clone()) + ], + b3 + ), + // error_len = Some(3), width = 4 + // path taken: + // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1505 + static_map((byte01_w4, succ_byte, fail_byte), b4), + ] + .boxed() +} + +#[cfg(test)] +mod test { + no_panic_test!( + string => String, + str_box => Box, + str_rc => Rc, + str_arc => Arc, + from_utf16_error => FromUtf16Error, + from_utf8_error => FromUtf8Error + ); +} diff --git a/library/proptest/src/arbitrary/_std/sync.rs b/library/proptest/src/arbitrary/_std/sync.rs new file mode 100644 index 000000000000..a615f9d3505b --- /dev/null +++ b/library/proptest/src/arbitrary/_std/sync.rs @@ -0,0 +1,162 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::sync`. + +use std::fmt; +use std::sync::mpsc::*; +use std::sync::*; +use std::thread; +use std::time::Duration; + +use crate::arbitrary::*; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +// OnceState can not escape Once::call_once_force. +// PoisonError depends implicitly on the lifetime on MutexGuard, etc. +// This transitively applies to TryLockError. + +// Not doing Weak because .upgrade() would always return None. + +#[cfg(not(feature = "unstable"))] +wrap_ctor!(Mutex); +#[cfg(feature = "unstable")] +wrap_from!(Mutex); + +#[cfg(not(feature = "unstable"))] +wrap_ctor!(RwLock); +#[cfg(feature = "unstable")] +wrap_from!(RwLock); + +arbitrary!(Barrier, SMapped; // usize would be extreme! + static_map(any::(), |n| Barrier::new(n as usize)) +); + +arbitrary!(BarrierWaitResult, + TupleUnion<(WA>, WA>)>; + prop_oneof![LazyJust::new(bwr_true), LazyJust::new(bwr_false)] +); + +lazy_just!( + Condvar, Default::default; + Once, Once::new +); + +arbitrary!(WaitTimeoutResult, TupleUnion<(WA>, WA>)>; + prop_oneof![Just(wtr_true()), Just(wtr_false())] +); + +fn bwr_true() -> BarrierWaitResult { + Barrier::new(1).wait() +} + +fn bwr_false() -> BarrierWaitResult { + let barrier = Arc::new(Barrier::new(2)); + let b2 = barrier.clone(); + let jh = thread::spawn(move || b2.wait()); + let bwr1 = barrier.wait(); + let bwr2 = jh.join().unwrap(); + if bwr1.is_leader() { bwr2 } else { bwr1 } +} + +fn wtr_false() -> WaitTimeoutResult { + let cvar = Arc::new(Condvar::new()); + let cvar2 = cvar.clone(); + thread::spawn(move || { + cvar2.notify_one(); + }); + let lock = Mutex::new(()); + let wt = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(1)); + let (_, wtr) = wt.unwrap(); + wtr +} + +fn wtr_true() -> WaitTimeoutResult { + let cvar = Condvar::new(); + let lock = Mutex::new(()); + let wt = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(0)); + let (_, wtr) = wt.unwrap(); + wtr +} + +arbitrary!(RecvError; RecvError); + +arbitrary!([T: Arbitrary] SendError, SMapped, T::Parameters; + args => static_map(any_with::(args), SendError) +); + +arbitrary!(RecvTimeoutError, TupleUnion<(WA>, WA>)>; + prop_oneof![ + Just(RecvTimeoutError::Disconnected), + Just(RecvTimeoutError::Timeout) + ] +); + +arbitrary!(TryRecvError, TupleUnion<(WA>, WA>)>; + prop_oneof![ + Just(TryRecvError::Disconnected), + Just(TryRecvError::Empty) + ] +); + +arbitrary!( + [P: Clone + Default, T: Arbitrary] TrySendError, + TupleUnion<(WA>, WA>)>, P; + args => prop_oneof![ + static_map(any_with::(args.clone()), TrySendError::Disconnected), + static_map(any_with::(args), TrySendError::Full), + ] +); + +// If only half of a pair is generated then you will get a hang-up. +// Thus the only meaningful impls are in pairs. +arbitrary!([A] (Sender, Receiver), LazyJustFn; + LazyJust::new(channel) +); + +arbitrary!([A: fmt::Debug] (Sender, IntoIter), LazyJustFn; + LazyJust::new(|| { + let (rx, tx) = channel(); + (rx, tx.into_iter()) + }) +); + +arbitrary!([A] (SyncSender, Receiver), SMapped; + static_map(any::(), |size| sync_channel(size as usize)) +); + +arbitrary!([A: fmt::Debug] (SyncSender, IntoIter), SMapped; + static_map(any::(), |size| { + let (rx, tx) = sync_channel(size as usize); + (rx, tx.into_iter()) + }) +); + +#[cfg(test)] +mod test { + no_panic_test!( + mutex => Mutex, + rw_lock => RwLock, + barrier => Barrier, + barrier_wait_result => BarrierWaitResult, + condvar => Condvar, + once => Once, + wait_timeout_result => WaitTimeoutResult, + recv_error => RecvError, + send_error => SendError, + recv_timeout_error => RecvTimeoutError, + try_recv_error => TryRecvError, + try_send_error => TrySendError, + rx_tx => (Sender, Receiver), + rx_txiter => (Sender, IntoIter), + syncrx_tx => (SyncSender, Receiver), + syncrx_txiter => (SyncSender, IntoIter) + ); +} diff --git a/library/proptest/src/arbitrary/_std/thread.rs b/library/proptest/src/arbitrary/_std/thread.rs new file mode 100644 index 000000000000..3a9b2b3fe114 --- /dev/null +++ b/library/proptest/src/arbitrary/_std/thread.rs @@ -0,0 +1,81 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::thread`. + +use crate::std_facade::String; +use std::thread::*; + +use crate::arbitrary::*; +use crate::option::prob; +use crate::strategy::statics::static_map; + +arbitrary!(Builder, SMapped<(Option, Option), Self>; { + let prob = prob(0.7); + let args = product_pack![ + product_pack![prob, Default::default()], + product_pack![prob, Default::default()] + ]; + static_map(arbitrary_with(args), |(os, on)| { + let mut b = Builder::new(); + b = if let Some(size) = os { b.stack_size(size) } else { b }; + if let Some(name) = on { b.name(name) } else { b } + }) +}); + +/* + * The usefulness of this impl is debatable - as are its semantics. + * Perhaps a CoArbitrary-based solution is preferable. + +arbitrary!([A: 'static + Send + Arbitrary<'a>] JoinHandle, + SMapped<'a, (A, Option<()>, u8), Self>, A::Parameters; + args => { + let prob = prob(0.1); + let args2 = product_pack![ + args, + product_pack![prob, default()], + default() + ]; + any_with_smap(args2, |(val, panic, sleep)| thread::spawn(move || { + // Sleep a random amount: + use std::time::Duration; + thread::sleep(Duration::from_millis(sleep as u64)); + + // Randomly panic: + if panic.is_some() { + panic!("Arbitrary for JoinHandle randomly paniced!"); + } + + // Move value into thread and then just return it: + val + })) + } +); +*/ + +#[cfg(test)] +mod test { + no_panic_test!( + builder => Builder + ); + + /* + use super::*; + proptest! { + #[test] + fn join_handle_works(ref jh in any::>()) { + use std::panic::catch_unwind; + catch_unwind(|| { + jh.join(); + () + }) + } + } + */ +} diff --git a/library/proptest/src/arbitrary/_std/time.rs b/library/proptest/src/arbitrary/_std/time.rs new file mode 100644 index 000000000000..7d940439a799 --- /dev/null +++ b/library/proptest/src/arbitrary/_std/time.rs @@ -0,0 +1,50 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for `std::time`. + +use core::ops::Range; +use std::time::*; + +use crate::arbitrary::*; +use crate::num; +use crate::strategy::statics::{self, static_map}; + +arbitrary!(Duration, SMapped<(u64, u32), Self>; + static_map(any::<(u64, u32)>(), |(a, b)| Duration::new(a, b)) +); + +// Instant::now() "never" returns the same Instant, so no shrinking may occur! +arbitrary!(Instant; Self::now()); + +arbitrary!( + // We can't use `any::()` because the addition to `SystemTime` + // can overflow and panic. To be conservative, we only allow seconds to go + // to i32::MAX since a certain popular OS still uses `i32` to represent the + // seconds counter. + SystemTime, statics::Map<(num::i32::Any, Range), + fn ((i32, u32)) -> SystemTime>; + static_map((num::i32::ANY, 0..1_000_000_000u32), + |(sec, ns)| { + if sec >= 0 { + UNIX_EPOCH + Duration::new(sec as u64, ns) + } else { + UNIX_EPOCH - Duration::new((-(sec as i64)) as u64, ns) + } + }) +); + +#[cfg(test)] +mod test { + no_panic_test!( + duration => Duration, + instant => Instant, + system_time => SystemTime + ); +} diff --git a/library/proptest/src/arbitrary/arrays.rs b/library/proptest/src/arbitrary/arrays.rs new file mode 100644 index 000000000000..0fe3e2225e97 --- /dev/null +++ b/library/proptest/src/arbitrary/arrays.rs @@ -0,0 +1,38 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for arrays. + +use crate::arbitrary::{any_with, Arbitrary}; +use crate::array::UniformArrayStrategy; + +macro_rules! array { + ($($n: expr),*) => { $( + impl Arbitrary for [A; $n] { + type Parameters = A::Parameters; + type Strategy = UniformArrayStrategy; + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + let base = any_with::(args); + UniformArrayStrategy::new(base) + } + } + )* }; +} + +array!( + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, + 27, 28, 29, 30, 31, 32 +); + +#[cfg(test)] +mod test { + no_panic_test!( + array_16 => [u8; 16] + ); +} diff --git a/library/proptest/src/arbitrary/functor.rs b/library/proptest/src/arbitrary/functor.rs new file mode 100644 index 000000000000..855dbeb66940 --- /dev/null +++ b/library/proptest/src/arbitrary/functor.rs @@ -0,0 +1,214 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Provides higher order `Arbitrary` traits. +//! This is mainly for use by `proptest_derive`. +//! +//! ## Stability note +//! +//! This trait is mainly defined for `proptest_derive` to simplify the +//! mechanics of deriving recursive types. If you have custom containers +//! and want to support recursive for those, it is a good idea to implement +//! this trait. +//! +//! There are clearer and terser ways that work better with +//! inference such as using `proptest::collection::vec(..)` +//! to achieve the same result. +//! +//! For these reasons, the traits here are deliberately +//! not exported in a convenient way. + +use crate::std_facade::fmt; + +use crate::strategy::{BoxedStrategy, Strategy}; + +/// `ArbitraryF1` lets you lift a [`Strategy`] to unary +/// type constructors such as `Box`, `Vec`, and `Option`. +/// +/// The trait corresponds to +/// [Haskell QuickCheck's `Arbitrary1` type class][HaskellQC]. +/// +/// [HaskellQC]: +/// https://hackage.haskell.org/package/QuickCheck-2.10.1/docs/Test-QuickCheck-Arbitrary.html#t:Arbitrary1 +/// +/// [`Strategy`]: ../proptest/strategy/trait.Strategy.html +pub trait ArbitraryF1: fmt::Debug + Sized { + //========================================================================== + // Implementation note #1 + //========================================================================== + // It might be better to do this with generic associated types by + // having an associated type: + // + // `type Strategy: Strategy;` + // + // But with this setup we will likely loose the ability to add bounds + // such as `Hash + Eq` on `A` which is needed for `HashSet`. We might + // be able to regain this ability with a ConstraintKinds feature. + // + // This alternate formulation will likely work better with type inference. + // + //========================================================================== + // Implementation note #2 + //========================================================================== + // + // Until `-> impl Trait` has been stabilized, `BoxedStrategy` must be + // used. This incurs an unfortunate performance penalty - but since + // we are dealing with testing, it is better to provide slowed down and + // somewhat less general functionality than no functionality at all. + // Implementations should just use `.boxed()` in the end. + //========================================================================== + + /// The type of parameters that [`lift1_with`] accepts for + /// configuration of the lifted and generated [`Strategy`]. Parameters + /// must implement [`Default`]. + /// + /// [`lift1_with`]: + /// trait.ArbitraryF1.html#tymethod.lift1_with + /// + /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html + /// [`Default`]: + /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html + type Parameters: Default; + + /// Lifts a given [`Strategy`] to a new [`Strategy`] for the (presumably) + /// bigger type. This is useful for lifting a `Strategy` for `SomeType` + /// to a container such as `Vec`. + /// + /// Calling this for the type `X` is the equivalent of using + /// [`X::lift1_with(base, Default::default())`]. + /// + /// This method is defined in the trait for optimization for the + /// default if you want to do that. It is a logic error to not + /// preserve the semantics when overriding. + /// + /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html + /// + /// [`X::lift1_with(base, Default::default())`]: + /// trait.ArbitraryF1.html#tymethod.lift1_with + fn lift1(base: AS) -> BoxedStrategy + where + AS: Strategy + 'static, + { + Self::lift1_with(base, Self::Parameters::default()) + } + + /// Lifts a given [`Strategy`] to a new [`Strategy`] for the (presumably) + /// bigger type. This is useful for lifting a `Strategy` for `SomeType` + /// to a container such as `Vec` of `SomeType`. The composite strategy is + /// passed the arguments given in `args`. + /// + /// If you wish to use the [`default()`] arguments, + /// use [`lift1`] instead. + /// + /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html + /// + /// [`lift1`]: trait.ArbitraryF1.html#method.lift1 + /// + /// [`default()`]: + /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html + fn lift1_with(base: AS, args: Self::Parameters) -> BoxedStrategy + where + AS: Strategy + 'static; +} + +/// `ArbitraryF2` lets you lift [`Strategy`] to binary +/// type constructors such as `Result`, `HashMap`. +/// +/// The trait corresponds to +/// [Haskell QuickCheck's `Arbitrary2` type class][HaskellQC]. +/// +/// [HaskellQC]: +/// https://hackage.haskell.org/package/QuickCheck-2.10.1/docs/Test-QuickCheck-Arbitrary.html#t:Arbitrary2 +/// +/// [`Strategy`]: ../proptest/strategy/trait.Strategy.html +pub trait ArbitraryF2: fmt::Debug + Sized { + /// The type of parameters that [`lift2_with`] accepts for + /// configuration of the lifted and generated [`Strategy`]. Parameters + /// must implement [`Default`]. + /// + /// [`lift2_with`]: trait.ArbitraryF2.html#tymethod.lift2_with + /// + /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html + /// + /// [`Default`]: + /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html + type Parameters: Default; + + /// Lifts two given strategies to a new [`Strategy`] for the (presumably) + /// bigger type. This is useful for lifting a `Strategy` for `Type1` + /// and one for `Type2` to a container such as `HashMap`. + /// + /// Calling this for the type `X` is the equivalent of using + /// [`X::lift2_with(base, Default::default())`]. + /// + /// This method is defined in the trait for optimization for the + /// default if you want to do that. It is a logic error to not + /// preserve the semantics when overriding. + /// + /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html + /// + /// [`X::lift2_with(base, Default::default())`]: + /// trait.Arbitrary.html#tymethod.lift2_with + fn lift2(fst: AS, snd: BS) -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static, + { + Self::lift2_with(fst, snd, Self::Parameters::default()) + } + + /// Lifts two given strategies to a new [`Strategy`] for the (presumably) + /// bigger type. This is useful for lifting a `Strategy` for `Type1` + /// and one for `Type2` to a container such as `HashMap`. + /// The composite strategy is passed the arguments given in `args`. + /// + /// If you wish to use the [`default()`] arguments, + /// use [`lift2`] instead. + /// + /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html + /// + /// [`lift2`]: trait.ArbitraryF2.html#method.lift2 + /// + /// [`default()`]: + /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html + fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) -> BoxedStrategy + where + AS: Strategy + 'static, + BS: Strategy + 'static; +} + +macro_rules! lift1 { + ([$($bounds : tt)*] $typ: ty, $params: ty; + $base: ident, $args: ident => $logic: expr) => { + impl + $crate::arbitrary::functor::ArbitraryF1 + for $typ { + type Parameters = $params; + + fn lift1_with($base: S, $args: Self::Parameters) + -> $crate::strategy::BoxedStrategy + where + S: $crate::strategy::Strategy + 'static + { + $crate::strategy::Strategy::boxed($logic) + } + } + }; + ([$($bounds : tt)*] $typ: ty; $base: ident => $logic: expr) => { + lift1!([$($bounds)*] $typ, (); $base, _args => $logic); + }; + ([$($bounds : tt)*] $typ: ty; $mapper: expr) => { + lift1!(['static + $($bounds)*] $typ; base => + $crate::strategy::Strategy::prop_map(base, $mapper)); + }; + ([$($bounds : tt)*] $typ: ty) => { + lift1!(['static + $($bounds)*] $typ; base => + $crate::strategy::Strategy::prop_map_into(base)); + }; +} diff --git a/library/proptest/src/arbitrary/macros.rs b/library/proptest/src/arbitrary/macros.rs new file mode 100644 index 000000000000..8edf2a6eaa7f --- /dev/null +++ b/library/proptest/src/arbitrary/macros.rs @@ -0,0 +1,115 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg_attr(not(feature = "std"), allow(unused_macros))] + +//============================================================================== +// Macros for quick implementing: +//============================================================================== + +macro_rules! arbitrary { + ([$($bounds : tt)*] $typ: ty, $strat: ty, $params: ty; + $args: ident => $logic: expr) => { + impl<$($bounds)*> $crate::arbitrary::Arbitrary for $typ { + type Parameters = $params; + type Strategy = $strat; + fn arbitrary_with($args: Self::Parameters) -> Self::Strategy { + $logic + } + } + }; + ([$($bounds : tt)*] $typ: ty, $strat: ty; $logic: expr) => { + arbitrary!([$($bounds)*] $typ, $strat, (); _args => $logic); + }; + ([$($bounds : tt)*] $typ: ty; $logic: expr) => { + arbitrary!([$($bounds)*] $typ, + $crate::strategy::Just, (); + _args => $crate::strategy::Just($logic) + ); + }; + ($typ: ty, $strat: ty, $params: ty; $args: ident => $logic: expr) => { + arbitrary!([] $typ, $strat, $params; $args => $logic); + }; + ($typ: ty, $strat: ty; $logic: expr) => { + arbitrary!([] $typ, $strat; $logic); + }; + ($strat: ty; $logic: expr) => { + arbitrary!([] $strat; $logic); + }; + ($($typ: ident),*) => { + $(arbitrary!($typ, $typ::Any; $typ::ANY);)* + }; +} + +macro_rules! wrap_ctor { + ($wrap: ident) => { + wrap_ctor!([] $wrap); + }; + ($wrap: ident, $maker: expr) => { + wrap_ctor!([] $wrap, $maker); + }; + ([$($bound : tt)*] $wrap: ident) => { + wrap_ctor!([$($bound)*] $wrap, $wrap::new); + }; + ([$($bound : tt)*] $wrap: ident, $maker: expr) => { + arbitrary!([A: $crate::arbitrary::Arbitrary + $($bound)*] $wrap, + $crate::arbitrary::SMapped, A::Parameters; + args => $crate::strategy::statics::static_map( + $crate::arbitrary::any_with::(args), $maker)); + + lift1!([$($bound)*] $wrap; $maker); + }; +} + +macro_rules! wrap_from { + ($wrap: ident) => { + wrap_from!([] $wrap); + }; + ([$($bound : tt)*] $wrap: ident) => { + arbitrary!([A: $crate::arbitrary::Arbitrary + $($bound)*] $wrap, + $crate::strategy::MapInto, A::Parameters; + args => $crate::strategy::Strategy::prop_map_into( + $crate::arbitrary::any_with::(args))); + + lift1!([$($bound)*] $wrap); + }; +} + +macro_rules! lazy_just { + ($($self: ty, $fun: expr);+) => { + $( + arbitrary!($self, $crate::strategy::LazyJust Self>; + $crate::strategy::LazyJust::new($fun)); + )+ + }; +} + +//============================================================================== +// Macros for testing: +//============================================================================== + +/// We are mostly interested in ensuring that generating input from our +/// strategies is able to construct a value, therefore ensuring that +/// no panic occurs is mostly sufficient. Shrinking for strategies that +/// use special shrinking methods can be handled separately. +#[cfg(test)] +macro_rules! no_panic_test { + ($($module: ident => $self: ty),+) => { + $( + mod $module { + #[allow(unused_imports)] + use super::super::*; + proptest! { + #[test] + fn no_panic(_ in $crate::arbitrary::any::<$self>()) {} + } + } + )+ + }; +} diff --git a/library/proptest/src/arbitrary/mod.rs b/library/proptest/src/arbitrary/mod.rs new file mode 100644 index 000000000000..10fa6f346755 --- /dev/null +++ b/library/proptest/src/arbitrary/mod.rs @@ -0,0 +1,67 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Defines the `Arbitrary` trait and related free functions +//! and type aliases. +//! +//! See the [`Arbitrary`] trait for more information. +//! +//! [`Arbitrary`]: trait.Arbitrary.html + +// use crate::strategy::statics; +// use crate::strategy::{Map, Strategy}; + +//============================================================================== +// Trait and impls +//============================================================================== + +mod traits; + +// #[macro_use] +// pub mod functor; + +#[macro_use] +mod macros; + +// mod arrays; +mod primitives; +// mod sample; +// mod tuples; + +// mod _core; + +//#[cfg(any(feature = "std", feature = "alloc"))] +// mod _alloc; + +//#[cfg(feature = "std")] +// mod _std; + +pub use self::traits::*; + +//============================================================================== +// SMapped + Mapped aliases to make documentation clearer. +//============================================================================== + +// pub(crate) type SFnPtrMap = statics::Map::Value) -> O>; + +// /// A static map from a strategy of `I` to `O`. +// /// +// /// # Stability +// /// +// /// This is provided to make documentation more readable. +// /// Do not rely on it existing in your own code. +// pub type SMapped = statics::Map, fn(I) -> O>; + +// /// A normal map from a strategy of `I` to `O`. +// /// +// /// # Stability +// /// +// /// This is provided to make documentation more readable. +// /// Do not rely on it existing in your own code. +// pub type Mapped = Map, fn(I) -> O>; diff --git a/library/proptest/src/arbitrary/primitives.rs b/library/proptest/src/arbitrary/primitives.rs new file mode 100644 index 000000000000..04ba45761e28 --- /dev/null +++ b/library/proptest/src/arbitrary/primitives.rs @@ -0,0 +1,47 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for primitive types. + +// use crate::bool; +// use crate::char; +use crate::num::{ i16, i32, i64, i8, isize, u16, u32, u64, u8, usize}; //todo: implement f32, f64, +#[cfg(not(target_arch = "wasm32"))] +use crate::num::{i128, u128}; + +arbitrary!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize); //bool, + +#[cfg(not(target_arch = "wasm32"))] +arbitrary!(i128, u128); + +// Note that for floating point types we limit the space since a lot of code +// isn't prepared for (and is not intended to be) things like NaN and infinity. + +//todo: implement f32, f64, + +// arbitrary!(f32, f32::Any; { +// f32::POSITIVE | f32::NEGATIVE | f32::ZERO | f32::SUBNORMAL | f32::NORMAL +// }); +// arbitrary!(f64, f64::Any; { +// f64::POSITIVE | f64::NEGATIVE | f64::ZERO | f64::SUBNORMAL | f64::NORMAL +// }); + +// arbitrary!(char, char::CharStrategy<'static>; char::any()); + +#[cfg(test)] +mod test { + no_panic_test!( + bool => bool, + char => char, + f32 => f32, f64 => f64, + isize => isize, usize => usize, + i8 => i8, i16 => i16, i32 => i32, i64 => i64, i128 => i128, + u8 => u8, u16 => u16, u32 => u32, u64 => u64, u128 => u128 + ); +} diff --git a/library/proptest/src/arbitrary/sample.rs b/library/proptest/src/arbitrary/sample.rs new file mode 100644 index 000000000000..81758213d3c7 --- /dev/null +++ b/library/proptest/src/arbitrary/sample.rs @@ -0,0 +1,31 @@ +//- +// Copyright 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::arbitrary::Arbitrary; +use crate::sample::{Index, IndexStrategy, Selector, SelectorStrategy}; + +impl Arbitrary for Index { + type Parameters = (); + + type Strategy = IndexStrategy; + + fn arbitrary_with(_: ()) -> IndexStrategy { + IndexStrategy::new() + } +} + +impl Arbitrary for Selector { + type Parameters = (); + + type Strategy = SelectorStrategy; + + fn arbitrary_with(_: ()) -> SelectorStrategy { + SelectorStrategy::new() + } +} diff --git a/library/proptest/src/arbitrary/traits.rs b/library/proptest/src/arbitrary/traits.rs new file mode 100644 index 000000000000..83f021425baf --- /dev/null +++ b/library/proptest/src/arbitrary/traits.rs @@ -0,0 +1,295 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use core::fmt; + +use crate::strategy::Strategy; + +//============================================================================== +// Arbitrary trait +//============================================================================== + +/// Arbitrary determines a canonical [`Strategy`] for the implementing type. +/// +/// It provides the method `arbitrary_with` which generates a `Strategy` for +/// producing arbitrary values of the implementing type *(`Self`)*. In general, +/// these strategies will produce the entire set of values possible for the +/// type, up to some size limitation or constraints set by their parameters. +/// When this is not desired, strategies to produce the desired values can be +/// built by combining [`Strategy`]s as described in the crate documentation. +/// +/// This trait analogous to +/// [Haskell QuickCheck's implementation of `Arbitrary`][HaskellQC]. +/// In this interpretation of `Arbitrary`, `Strategy` is the equivalent of +/// the `Gen` monad. Unlike in QuickCheck, `Arbitrary` is not a core component; +/// types do not need to implement `Arbitrary` unless one wants to use +/// [`any`](fn.any.html) or other free functions in this module. +/// +/// `Arbitrary` currently only works for types which represent owned data as +/// opposed to borrowed data. This is a fundamental restriction of `proptest` +/// which may be lifted in the future as the [generic associated types (GAT)] +/// feature of Rust is implemented and stabilized. +/// +/// [generic associated types (GAT)]: https://github.com/rust-lang/rust/issues/44265 +/// +/// [`Strategy`]: ../strategy/trait.Strategy.html +/// +/// [HaskellQC]: +/// https://hackage.haskell.org/package/QuickCheck/docs/Test-QuickCheck-Arbitrary.html +pub trait Arbitrary: Sized + fmt::Debug { + /// The type of parameters that [`arbitrary_with`] accepts for configuration + /// of the generated [`Strategy`]. Parameters must implement [`Default`]. + /// + /// [`arbitrary_with`]: trait.Arbitrary.html#tymethod.arbitrary_with + /// + /// [`Strategy`]: ../strategy/trait.Strategy.html + /// [`Default`]: + /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html + type Parameters: Default; + + /// Generates a [`Strategy`] for producing arbitrary values + /// of type the implementing type (`Self`). + /// + /// Calling this for the type `X` is the equivalent of using + /// [`X::arbitrary_with(Default::default())`]. + /// + /// This method is defined in the trait for optimization for the + /// default if you want to do that. It is a logic error to not + /// preserve the semantics when overriding. + /// + /// [`Strategy`]: ../strategy/trait.Strategy.html + /// [`X::arbitrary_with(Default::default())`]: + /// trait.Arbitrary.html#tymethod.arbitrary_with + fn arbitrary() -> Self::Strategy { + Self::arbitrary_with(Default::default()) + } + + /// Generates a [`Strategy`] for producing arbitrary values of type the + /// implementing type (`Self`). The strategy is passed the arguments given + /// in args. + /// + /// If you wish to use the [`default()`] arguments, + /// use [`arbitrary`] instead. + /// + /// [`Strategy`]: ../strategy/trait.Strategy.html + /// + /// [`arbitrary`]: trait.Arbitrary.html#method.arbitrary + /// + /// [`default()`]: + /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy; + + /// The type of [`Strategy`] used to generate values of type `Self`. + /// + /// [`Strategy`]: ../strategy/trait.Strategy.html + type Strategy: Strategy; +} + +//============================================================================== +// Type aliases for associated types +//============================================================================== + +/// `StrategyFor` allows you to mention the type of [`Strategy`] for the input +/// type `A` without directly using associated types or without resorting to +/// existential types. This way, if implementation of [`Arbitrary`] changes, +/// your tests should not break. This can be especially beneficial when the +/// type of `Strategy` that you are dealing with is very long in name +/// (the case with generics). +/// +/// [`Arbitrary`]: trait.Arbitrary.html +/// [`Strategy`]: ../strategy/trait.Strategy.html +pub type StrategyFor = ::Strategy; + +/// `ParamsFor` allows you to mention the type of [`Parameters`] for the input +/// type `A` without directly using associated types or without resorting to +/// existential types. This way, if implementation of [`Arbitrary`] changes, +/// your tests should not break. +/// +/// [`Parameters`]: trait.Arbitrary.html#associatedtype.Parameters +/// [`Arbitrary`]: trait.Arbitrary.html +/// [`Strategy`]: ../strategy/trait.Strategy.html +pub type ParamsFor = ::Parameters; + +//============================================================================== +// Free functions that people should use +//============================================================================== + +/// Generates a [`Strategy`] producing [`Arbitrary`][trait Arbitrary] values of +/// `A`. Unlike [`arbitrary`][fn arbitrary], it should be used for being +/// explicit on what `A` is. For clarity, this may be a good idea. +/// +/// Use this version instead of [`arbitrary`][fn arbitrary] if you want to be +/// clear which type you want to generate a `Strategy` for, or if you don't +/// have an anchoring type for type inference to work with. +/// +/// If you want to customize how the strategy is generated, use +/// [`any_with::(args)`] where `args` are any arguments accepted by +/// the `Arbitrary` impl in question. +/// +/// # Example +/// +/// The function can be used as: +/// +/// ```rust +/// use proptest::prelude::*; +/// +/// proptest! { +/// fn reverse_reverse_is_identity(ref vec in any::>()) { +/// let vec2 = vec.iter().cloned().rev().rev().collect::>(); +/// prop_assert_eq!(vec, &vec2); +/// } +/// } +/// +/// fn main() { +/// reverse_reverse_is_identity(); +/// } +/// ``` +/// +/// [`any_with::(args)`]: fn.any_with.html +/// [fn arbitrary]: fn.arbitrary.html +/// [trait Arbitrary]: trait.Arbitrary.html +/// [`Strategy`]: ../strategy/trait.Strategy.html +#[must_use = "strategies do nothing unless used"] +pub fn any() -> StrategyFor { + // ^-- We use a shorter name so that turbofish becomes more ergonomic. + A::arbitrary() +} + +/// Generates a [`Strategy`] producing [`Arbitrary`] values of `A` with the +/// given configuration arguments passed in `args`. Unlike [`arbitrary_with`], +/// it should be used for being explicit on what `A` is. +/// For clarity, this may be a good idea. +/// +/// Use this version instead of [`arbitrary_with`] if you want to be clear which +/// type you want to generate a `Strategy` for, or if you don't have an anchoring +/// type for type inference to work with. +/// +/// If you don't want to specify any arguments and instead use the default +/// behavior, you should use [`any::()`]. +/// +/// # Example +/// +/// The function can be used as: +/// +/// ```rust +/// use proptest::prelude::*; +/// use proptest::collection::size_range; +/// +/// proptest! { +/// fn reverse_reverse_is_identity +/// (ref vec in any_with::>(size_range(1000).lift())) +/// { +/// let vec2 = vec.iter().cloned().rev().rev().collect::>(); +/// prop_assert_eq!(vec, &vec2); +/// } +/// } +/// +/// fn main() { +/// reverse_reverse_is_identity(); +/// } +/// ``` +/// +/// [`any::()`]: fn.any.html +/// [`arbitrary_with`]: fn.arbitrary_with.html +/// [`Arbitrary`]: trait.Arbitrary.html +/// [`Strategy`]: ../strategy/trait.Strategy.html +#[must_use = "strategies do nothing unless used"] +pub fn any_with(args: ParamsFor) -> StrategyFor { + // ^-- We use a shorter name so that turbofish becomes more ergonomic. + A::arbitrary_with(args) +} + +/// Generates a [`Strategy`] producing [`Arbitrary`] values of `A`. +/// Works better with type inference than [`any::()`]. +/// +/// With this version, you shouldn't need to specify any of the (many) type +/// parameters explicitly. This can have a positive effect on type inference. +/// However, if you want specify `A`, you should use [`any::()`] instead. +/// +/// For clarity, it is often a good idea to specify the type generated, and +/// so using [`any::()`] can be a good idea. +/// +/// If you want to customize how the strategy is generated, use +/// [`arbitrary_with(args)`] where `args` is of type +/// `::Parameters`. +/// +/// # Example +/// +/// The function can be used as: +/// +/// ```rust +/// extern crate proptest; +/// use proptest::arbitrary::{arbitrary, StrategyFor}; +/// +/// fn gen_vec_usize() -> StrategyFor> { +/// arbitrary() +/// } +/// +/// # fn main() {} +/// ``` +/// +/// [`arbitrary_with(args)`]: fn.arbitrary_with.html +/// [`any::()`]: fn.any.html +/// [`Arbitrary`]: trait.Arbitrary.html +/// [`Strategy`]: ../strategy/trait.Strategy.html +#[must_use = "strategies do nothing unless used"] +pub fn arbitrary() -> S +where + // The backlinking here cause an injection which helps type inference. + S: Strategy, + A: Arbitrary, +{ + A::arbitrary() +} + +/// Generates a [`Strategy`] producing [`Arbitrary`] values of `A` with the +/// given configuration arguments passed in `args`. +/// Works better with type inference than [`any_with::(args)`]. +/// +/// With this version, you shouldn't need to specify any of the (many) type +/// parameters explicitly. This can have a positive effect on type inference. +/// However, if you want specify `A`, you should use +/// [`any_with::(args)`] instead. +/// +/// For clarity, it is often a good idea to specify the type generated, and +/// so using [`any_with::(args)`] can be a good idea. +/// +/// If you don't want to specify any arguments and instead use the default +/// behavior, you should use [`arbitrary()`]. +/// +/// # Example +/// +/// The function can be used as: +/// +/// ```rust +/// extern crate proptest; +/// use proptest::arbitrary::{arbitrary_with, StrategyFor}; +/// use proptest::collection::size_range; +/// +/// fn gen_vec_10_u32() -> StrategyFor> { +/// arbitrary_with(size_range(10).lift()) +/// } +/// +/// # fn main() {} +/// ``` +/// +/// [`any_with::(args)`]: fn.any_with.html +/// [`arbitrary()`]: fn.arbitrary.html +/// [`Arbitrary`]: trait.Arbitrary.html +/// [`Strategy`]: ../strategy/trait.Strategy.html +#[must_use = "strategies do nothing unless used"] +pub fn arbitrary_with(args: P) -> S +where + P: Default, + // The backlinking here cause an injection which helps type inference. + S: Strategy, + A: Arbitrary, +{ + A::arbitrary_with(args) +} diff --git a/library/proptest/src/arbitrary/tuples.rs b/library/proptest/src/arbitrary/tuples.rs new file mode 100644 index 000000000000..5df3088a3c2d --- /dev/null +++ b/library/proptest/src/arbitrary/tuples.rs @@ -0,0 +1,45 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Arbitrary implementations for tuples. + +use crate::arbitrary::{any_with, Arbitrary}; + +macro_rules! impl_tuple { + ($($typ: ident),*) => { + impl<$($typ : Arbitrary),*> Arbitrary for ($($typ,)*) { + type Parameters = product_type![$($typ::Parameters,)*]; + type Strategy = ($($typ::Strategy,)*); + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + #[allow(non_snake_case)] + let product_unpack![$($typ),*] = args; + ($(any_with::<$typ>($typ)),*,) + } + } + }; +} + +arbitrary!((); ()); +impl_tuple!(T0); +impl_tuple!(T0, T1); +impl_tuple!(T0, T1, T2); +impl_tuple!(T0, T1, T2, T3); +impl_tuple!(T0, T1, T2, T3, T4); +impl_tuple!(T0, T1, T2, T3, T4, T5); +impl_tuple!(T0, T1, T2, T3, T4, T5, T6); +impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7); +impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8); +impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9); + +#[cfg(test)] +mod test { + no_panic_test!( + tuple_n10 => ((), bool, u8, u16, u32, u64, i8, i16, i32, i64) + ); +} diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index 563015942734..22c6b43b5581 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -79,13 +79,13 @@ pub mod std_facade; #[macro_use] pub mod sugar; -// pub mod arbitrary; +pub mod arbitrary; // pub mod array; // pub mod bits; // pub mod bool; // pub mod char; // pub mod collection; -// pub mod num; +pub mod num; pub mod strategy; pub mod test_runner; // pub mod tuple; diff --git a/library/proptest/src/num.rs b/library/proptest/src/num.rs new file mode 100644 index 000000000000..1007c8c7e98d --- /dev/null +++ b/library/proptest/src/num.rs @@ -0,0 +1,1231 @@ +//- +// Copyright 2017, 2018 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Strategies to generate numeric values (as opposed to integers used as bit +//! fields). +//! +//! All strategies in this module shrink by binary searching towards 0. + +use crate::test_runner::TestRunner; +use core::ops::Range; + +// Below 2 functions are the source of Kani symbolic variables. + +/// Produce an symbolic value from a range. +pub(crate) fn sample_uniform(run: &mut TestRunner, range: Range) -> X { + let value: X = kani::any(); + kani::assume(range.contains(&value)); + value +} + +/// Produce an symbolic value start and end values. End is inclusive. +pub(crate) fn sample_uniform_incl(run: &mut TestRunner, start: X, end: X) -> X { + let value: X = kani::any(); + kani::assume(value <= end); + kani::assume(value >= start); + value +} + +macro_rules! int_any { + ($typ: ident) => { + /// Type of the `ANY` constant. + #[derive(Clone, Copy, Debug)] + #[must_use = "strategies do nothing unless used"] + pub struct Any(()); + /// Generates integers with completely arbitrary values, uniformly + /// distributed over the whole range. + pub const ANY: Any = Any(()); + + impl Strategy for Any { + type Tree = BinarySearch; + type Value = $typ; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(BinarySearch::new(kani::any::<$typ>())) + } + } + }; +} + +macro_rules! numeric_api { + ($typ:ident, $epsilon:expr) => { + impl Strategy for ::core::ops::Range<$typ> { + type Tree = BinarySearch; + type Value = $typ; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(BinarySearch::new_clamped( + self.start, + $crate::num::sample_uniform(runner, self.clone()), + self.end - $epsilon, + )) + } + } + + impl Strategy for ::core::ops::RangeInclusive<$typ> { + type Tree = BinarySearch; + type Value = $typ; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(BinarySearch::new_clamped( + *self.start(), + $crate::num::sample_uniform_incl(runner, *self.start(), *self.end()), + *self.end(), + )) + } + } + + impl Strategy for ::core::ops::RangeFrom<$typ> { + type Tree = BinarySearch; + type Value = $typ; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(BinarySearch::new_clamped( + self.start, + $crate::num::sample_uniform_incl(runner, self.start, ::core::$typ::MAX), + ::core::$typ::MAX, + )) + } + } + + impl Strategy for ::core::ops::RangeTo<$typ> { + type Tree = BinarySearch; + type Value = $typ; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(BinarySearch::new_clamped( + ::core::$typ::MIN, + $crate::num::sample_uniform(runner, ::core::$typ::MIN..self.end), + self.end, + )) + } + } + + impl Strategy for ::core::ops::RangeToInclusive<$typ> { + type Tree = BinarySearch; + type Value = $typ; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + Ok(BinarySearch::new_clamped( + ::core::$typ::MIN, + $crate::num::sample_uniform_incl(runner, ::core::$typ::MIN, self.end), + self.end, + )) + } + } + }; +} + +macro_rules! signed_integer_bin_search { + ($typ:ident) => { + #[allow(missing_docs)] + pub mod $typ { + + use crate::strategy::*; + use crate::test_runner::TestRunner; + + int_any!($typ); + + /// Shrinks an integer towards 0, using binary search to find + /// boundary points. + #[derive(Clone, Copy, Debug)] + pub struct BinarySearch { + lo: $typ, // todo: these are not necessary, purge. + curr: $typ, + hi: $typ, // todo: these are not necessary, purge. + } + impl BinarySearch { + /// Creates a new binary searcher starting at the given value. + pub fn new(start: $typ) -> Self { + BinarySearch { lo: 0, curr: start, hi: start } + } + + /// Creates a new binary searcher which will not produce values + /// on the other side of `lo` or `hi` from `start`. `lo` is + /// inclusive, `hi` is exclusive. + fn new_clamped(lo: $typ, start: $typ, hi: $typ) -> Self { + use core::cmp::{max, min}; + + BinarySearch { + lo: if start < 0 { min(0, hi - 1) } else { max(0, lo) }, + hi: start, + curr: start, + } + } + } + impl ValueTree for BinarySearch { + type Value = $typ; + + fn current(&self) -> $typ { + self.curr + } + + fn simplify(&mut self) -> bool { + return false; + } + + fn complicate(&mut self) -> bool { + return false; + } + } + + numeric_api!($typ, 1); + } + }; +} + +macro_rules! unsigned_integer_bin_search { + ($typ:ident) => { + #[allow(missing_docs)] + pub mod $typ { + + use crate::strategy::*; + use crate::test_runner::TestRunner; + + int_any!($typ); + + /// Shrinks an integer towards 0, using binary search to find + /// boundary points. + #[derive(Clone, Copy, Debug)] + pub struct BinarySearch { + lo: $typ, // todo: these are not necessary, purge. + curr: $typ, + hi: $typ, // todo: these are not necessary, purge. + } + impl BinarySearch { + /// Creates a new binary searcher starting at the given value. + pub fn new(start: $typ) -> Self { + BinarySearch { lo: 0, curr: start, hi: start } + } + + /// Creates a new binary searcher which will not search below + /// the given `lo` value. + fn new_clamped(lo: $typ, start: $typ, _hi: $typ) -> Self { + BinarySearch { lo: lo, curr: start, hi: start } + } + + /// Creates a new binary searcher which will not search below + /// the given `lo` value. + pub fn new_above(lo: $typ, start: $typ) -> Self { + BinarySearch::new_clamped(lo, start, start) + } + } + impl ValueTree for BinarySearch { + type Value = $typ; + + fn current(&self) -> $typ { + self.curr + } + + fn simplify(&mut self) -> bool { + return false; + } + + fn complicate(&mut self) -> bool { + return false; + } + } + + numeric_api!($typ, 1); + } + }; +} + +signed_integer_bin_search!(i8); +signed_integer_bin_search!(i16); +signed_integer_bin_search!(i32); +signed_integer_bin_search!(i64); +#[cfg(not(target_arch = "wasm32"))] +signed_integer_bin_search!(i128); +signed_integer_bin_search!(isize); +unsigned_integer_bin_search!(u8); +unsigned_integer_bin_search!(u16); +unsigned_integer_bin_search!(u32); +unsigned_integer_bin_search!(u64); +#[cfg(not(target_arch = "wasm32"))] +unsigned_integer_bin_search!(u128); +unsigned_integer_bin_search!(usize); + +// todo! support float types + +// bitflags! { +// pub(crate) struct FloatTypes: u32 { +// const POSITIVE = 0b0000_0001; +// const NEGATIVE = 0b0000_0010; +// const NORMAL = 0b0000_0100; +// const SUBNORMAL = 0b0000_1000; +// const ZERO = 0b0001_0000; +// const INFINITE = 0b0010_0000; +// const QUIET_NAN = 0b0100_0000; +// const SIGNALING_NAN = 0b1000_0000; +// const ANY = +// Self::POSITIVE.bits | +// Self::NEGATIVE.bits | +// Self::NORMAL.bits | +// Self::SUBNORMAL.bits | +// Self::ZERO.bits | +// Self::INFINITE.bits | +// Self::QUIET_NAN.bits; +// } +// } + +// impl FloatTypes { +// fn normalise(mut self) -> Self { +// if !self.intersects(FloatTypes::POSITIVE | FloatTypes::NEGATIVE) { +// self |= FloatTypes::POSITIVE; +// } + +// if !self.intersects( +// FloatTypes::NORMAL +// | FloatTypes::SUBNORMAL +// | FloatTypes::ZERO +// | FloatTypes::INFINITE +// | FloatTypes::QUIET_NAN +// | FloatTypes::SIGNALING_NAN, +// ) { +// self |= FloatTypes::NORMAL; +// } +// self +// } +// } + +// trait FloatLayout +// where +// Standard: Distribution, +// { +// type Bits: Copy; + +// const SIGN_MASK: Self::Bits; +// const EXP_MASK: Self::Bits; +// const EXP_ZERO: Self::Bits; +// const MANTISSA_MASK: Self::Bits; +// } + +// impl FloatLayout for f32 { +// type Bits = u32; + +// const SIGN_MASK: u32 = 0x8000_0000; +// const EXP_MASK: u32 = 0x7F80_0000; +// const EXP_ZERO: u32 = 0x3F80_0000; +// const MANTISSA_MASK: u32 = 0x007F_FFFF; +// } + +// impl FloatLayout for f64 { +// type Bits = u64; + +// const SIGN_MASK: u64 = 0x8000_0000_0000_0000; +// const EXP_MASK: u64 = 0x7FF0_0000_0000_0000; +// const EXP_ZERO: u64 = 0x3FF0_0000_0000_0000; +// const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF; +// } + +// macro_rules! float_any { +// ($typ:ident) => { +// /// Strategies which produce floating-point values from particular +// /// classes. See the various `Any`-typed constants in this module. +// /// +// /// Note that this usage is fairly advanced and primarily useful to +// /// implementors of algorithms that need to handle wild values in a +// /// particular way. For testing things like graphics processing or game +// /// physics, simply using ranges (e.g., `-1.0..2.0`) will often be more +// /// practical. +// /// +// /// `Any` can be OR'ed to combine multiple classes. For example, +// /// `POSITIVE | INFINITE` will generate arbitrary positive, non-NaN +// /// floats, including positive infinity (but not negative infinity, of +// /// course). +// /// +// /// If neither `POSITIVE` nor `NEGATIVE` has been OR'ed into an `Any` +// /// but a type to be generated requires a sign, `POSITIVE` is assumed. +// /// If no classes are OR'ed into an `Any` (i.e., only `POSITIVE` and/or +// /// `NEGATIVE` are given), `NORMAL` is assumed. +// /// +// /// The various float classes are assigned fixed weights for generation +// /// which are believed to be reasonable for most applications. Roughly: +// /// +// /// - If `POSITIVE | NEGATIVE`, the sign is evenly distributed between +// /// both options. +// /// +// /// - Classes are weighted as follows, in descending order: +// /// `NORMAL` > `ZERO` > `SUBNORMAL` > `INFINITE` > `QUIET_NAN` = +// /// `SIGNALING_NAN`. +// #[derive(Clone, Copy, Debug)] +// #[must_use = "strategies do nothing unless used"] +// pub struct Any(FloatTypes); + +// #[cfg(test)] +// impl Any { +// pub(crate) fn from_bits(bits: u32) -> Self { +// Any(FloatTypes::from_bits_truncate(bits)) +// } + +// pub(crate) fn normal_bits(&self) -> FloatTypes { +// self.0.normalise() +// } +// } + +// impl ops::BitOr for Any { +// type Output = Self; + +// fn bitor(self, rhs: Self) -> Self { +// Any(self.0 | rhs.0) +// } +// } + +// impl ops::BitOrAssign for Any { +// fn bitor_assign(&mut self, rhs: Self) { +// self.0 |= rhs.0 +// } +// } + +// /// Generates positive floats +// /// +// /// By itself, implies the `NORMAL` class, unless another class is +// /// OR'ed in. That is, using `POSITIVE` as a strategy by itself will +// /// generate arbitrary values between the type's `MIN_POSITIVE` and +// /// `MAX`, while `POSITIVE | INFINITE` would only allow generating +// /// positive infinity. +// pub const POSITIVE: Any = Any(FloatTypes::POSITIVE); +// /// Generates negative floats. +// /// +// /// By itself, implies the `NORMAL` class, unless another class is +// /// OR'ed in. That is, using `POSITIVE` as a strategy by itself will +// /// generate arbitrary values between the type's `MIN` and +// /// `-MIN_POSITIVE`, while `NEGATIVE | INFINITE` would only allow +// /// generating positive infinity. +// pub const NEGATIVE: Any = Any(FloatTypes::NEGATIVE); +// /// Generates "normal" floats. +// /// +// /// These are finite values where the first bit of the mantissa is an +// /// implied `1`. When positive, this represents the range +// /// `MIN_POSITIVE` through `MAX`, both inclusive. +// /// +// /// Generated values are uniform over the discrete floating-point +// /// space, which means the numeric distribution is an inverse +// /// exponential step function. For example, values between 1.0 and 2.0 +// /// are generated with the same frequency as values between 2.0 and +// /// 4.0, even though the latter covers twice the numeric range. +// /// +// /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, +// /// `POSITIVE` is implied. +// pub const NORMAL: Any = Any(FloatTypes::NORMAL); +// /// Generates subnormal floats. +// /// +// /// These are finite non-zero values where the first bit of the +// /// mantissa is not an implied zero. When positive, this represents the +// /// range `MIN`, inclusive, through `MIN_POSITIVE`, exclusive. +// /// +// /// Subnormals are generated with a uniform distribution both in terms +// /// of discrete floating-point space and numerically. +// /// +// /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, +// /// `POSITIVE` is implied. +// pub const SUBNORMAL: Any = Any(FloatTypes::SUBNORMAL); +// /// Generates zero-valued floats. +// /// +// /// Note that IEEE floats support both positive and negative zero, so +// /// this class does interact with the sign flags. +// /// +// /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, +// /// `POSITIVE` is implied. +// pub const ZERO: Any = Any(FloatTypes::ZERO); +// /// Generates infinity floats. +// /// +// /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, +// /// `POSITIVE` is implied. +// pub const INFINITE: Any = Any(FloatTypes::INFINITE); +// /// Generates "Quiet NaN" floats. +// /// +// /// Operations on quiet NaNs generally simply propagate the NaN rather +// /// than invoke any exception mechanism. +// /// +// /// The payload of the NaN is uniformly distributed over the possible +// /// values which safe Rust allows, including the sign bit (as +// /// controlled by `POSITIVE` and `NEGATIVE`). +// /// +// /// Note however that in Rust 1.23.0 and earlier, this constitutes only +// /// one particular payload due to apparent issues with particular MIPS +// /// and PA-RISC processors which fail to implement IEEE 754-2008 +// /// correctly. +// /// +// /// On Rust 1.24.0 and later, this does produce arbitrary payloads as +// /// documented. +// /// +// /// On platforms where the CPU and the IEEE standard disagree on the +// /// format of a quiet NaN, values generated conform to the hardware's +// /// expectations. +// pub const QUIET_NAN: Any = Any(FloatTypes::QUIET_NAN); +// /// Generates "Signaling NaN" floats if allowed by the platform. +// /// +// /// On most platforms, signalling NaNs by default behave the same as +// /// quiet NaNs, but it is possible to configure the OS or CPU to raise +// /// an asynchronous exception if an operation is performed on a +// /// signalling NaN. +// /// +// /// In Rust 1.23.0 and earlier, this silently behaves the same as +// /// [`QUIET_NAN`](const.QUIET_NAN.html). +// /// +// /// On platforms where the CPU and the IEEE standard disagree on the +// /// format of a quiet NaN, values generated conform to the hardware's +// /// expectations. +// /// +// /// Note that certain platforms — most notably, x86/AMD64 — allow the +// /// architecture to turn a signalling NaN into a quiet NaN with the +// /// same payload. Whether this happens can depend on what registers the +// /// compiler decides to use to pass the value around, what CPU flags +// /// are set, and what compiler settings are in use. +// pub const SIGNALING_NAN: Any = Any(FloatTypes::SIGNALING_NAN); + +// /// Generates literally arbitrary floating-point values, including +// /// infinities and quiet NaNs (but not signaling NaNs). +// /// +// /// Equivalent to `POSITIVE | NEGATIVE | NORMAL | SUBNORMAL | ZERO | +// /// INFINITE | QUIET_NAN`. +// /// +// /// See [`SIGNALING_NAN`](const.SIGNALING_NAN.html) if you also want to +// /// generate signalling NaNs. This signalling NaNs are not included by +// /// default since in most contexts they either make no difference, or +// /// if the process enabled the relevant CPU mode, result in +// /// hardware-triggered exceptions that usually just abort the process. +// /// +// /// Before proptest 0.4.1, this erroneously generated values in the +// /// range 0.0..1.0. +// pub const ANY: Any = Any(FloatTypes::ANY); + +// impl Strategy for Any { +// type Tree = BinarySearch; +// type Value = $typ; + +// fn new_tree(&self, runner: &mut TestRunner) -> NewTree { +// let flags = self.0.normalise(); +// let sign_mask = if flags.contains(FloatTypes::NEGATIVE) { +// $typ::SIGN_MASK +// } else { +// 0 +// }; +// let sign_or = if flags.contains(FloatTypes::POSITIVE) { +// 0 +// } else { +// $typ::SIGN_MASK +// }; + +// macro_rules! weight { +// ($case:ident, $weight:expr) => { +// if flags.contains(FloatTypes::$case) { +// $weight +// } else { +// 0 +// } +// } +// } + +// // A few CPUs disagree with IEEE about the meaning of the +// // signalling bit. Assume the `NAN` constant is a quiet NaN as +// // interpreted by the hardware and generate values based on +// // that. +// let quiet_or = ::core::$typ::NAN.to_bits() & +// ($typ::EXP_MASK | ($typ::EXP_MASK >> 1)); +// let signaling_or = (quiet_or ^ ($typ::EXP_MASK >> 1)) | +// $typ::EXP_MASK; + +// let (class_mask, class_or, allow_edge_exp, allow_zero_mant) = +// prop_oneof![ +// weight!(NORMAL, 20) => Just( +// ($typ::EXP_MASK | $typ::MANTISSA_MASK, 0, +// false, true)), +// weight!(SUBNORMAL, 3) => Just( +// ($typ::MANTISSA_MASK, 0, true, false)), +// weight!(ZERO, 4) => Just( +// (0, 0, true, true)), +// weight!(INFINITE, 2) => Just( +// (0, $typ::EXP_MASK, true, true)), +// weight!(QUIET_NAN, 1) => Just( +// ($typ::MANTISSA_MASK >> 1, quiet_or, +// true, false)), +// weight!(SIGNALING_NAN, 1) => Just( +// ($typ::MANTISSA_MASK >> 1, signaling_or, +// true, false)), +// ].new_tree(runner)?.current(); + +// let mut generated_value: <$typ as FloatLayout>::Bits = +// runner.rng().gen(); +// generated_value &= sign_mask | class_mask; +// generated_value |= sign_or | class_or; +// let exp = generated_value & $typ::EXP_MASK; +// if !allow_edge_exp && (0 == exp || $typ::EXP_MASK == exp) { +// generated_value &= !$typ::EXP_MASK; +// generated_value |= $typ::EXP_ZERO; +// } +// if !allow_zero_mant && +// 0 == generated_value & $typ::MANTISSA_MASK +// { +// generated_value |= 1; +// } + +// Ok(BinarySearch::new_with_types( +// $typ::from_bits(generated_value), flags)) +// } +// } +// } +// } + +// macro_rules! float_bin_search { +// ($typ:ident) => { +// #[allow(missing_docs)] +// pub mod $typ { +// use core::ops; +// #[cfg(not(feature = "std"))] +// use num_traits::float::FloatCore; + +// use rand::Rng; + +// use super::{FloatLayout, FloatTypes}; +// use crate::strategy::*; +// use crate::test_runner::TestRunner; + +// float_any!($typ); + +// /// Shrinks a float towards 0, using binary search to find boundary +// /// points. +// /// +// /// Non-finite values immediately shrink to 0. +// #[derive(Clone, Copy, Debug)] +// pub struct BinarySearch { +// lo: $typ, +// curr: $typ, +// hi: $typ, +// allowed: FloatTypes, +// } + +// impl BinarySearch { +// /// Creates a new binary searcher starting at the given value. +// pub fn new(start: $typ) -> Self { +// BinarySearch { lo: 0.0, curr: start, hi: start, allowed: FloatTypes::all() } +// } + +// fn new_with_types(start: $typ, allowed: FloatTypes) -> Self { +// BinarySearch { lo: 0.0, curr: start, hi: start, allowed } +// } + +// /// Creates a new binary searcher which will not produce values +// /// on the other side of `lo` or `hi` from `start`. `lo` is +// /// inclusive, `hi` is exclusive. +// fn new_clamped(lo: $typ, start: $typ, hi: $typ) -> Self { +// BinarySearch { +// lo: if start.is_sign_negative() { hi.min(0.0) } else { lo.max(0.0) }, +// hi: start, +// curr: start, +// allowed: FloatTypes::all(), +// } +// } + +// fn current_allowed(&self) -> bool { +// use core::num::FpCategory::*; + +// // Don't reposition if the new value is not allowed +// let class_allowed = match self.curr.classify() { +// Nan => +// // We don't need to inspect whether the +// // signallingness of the NaN matches the allowed +// // set, as we never try to switch between them, +// // instead shrinking to 0. +// { +// self.allowed.contains(FloatTypes::QUIET_NAN) +// || self.allowed.contains(FloatTypes::SIGNALING_NAN) +// } +// Infinite => self.allowed.contains(FloatTypes::INFINITE), +// Zero => self.allowed.contains(FloatTypes::ZERO), +// Subnormal => self.allowed.contains(FloatTypes::SUBNORMAL), +// Normal => self.allowed.contains(FloatTypes::NORMAL), +// }; +// let signum = self.curr.signum(); +// let sign_allowed = if signum > 0.0 { +// self.allowed.contains(FloatTypes::POSITIVE) +// } else if signum < 0.0 { +// self.allowed.contains(FloatTypes::NEGATIVE) +// } else { +// true +// }; + +// class_allowed && sign_allowed +// } + +// fn ensure_acceptable(&mut self) { +// while !self.current_allowed() { +// if !self.complicate_once() { +// panic!( +// "Unable to complicate floating-point back \ +// to acceptable value" +// ); +// } +// } +// } + +// fn reposition(&mut self) -> bool { +// let interval = self.hi - self.lo; +// let interval = if interval.is_finite() { interval } else { 0.0 }; +// let new_mid = self.lo + interval / 2.0; + +// let new_mid = +// if new_mid == self.curr || 0.0 == interval { new_mid } else { self.lo }; + +// if new_mid == self.curr { +// false +// } else { +// self.curr = new_mid; +// true +// } +// } + +// fn done(lo: $typ, hi: $typ) -> bool { +// (lo.abs() > hi.abs() && !hi.is_nan()) || lo.is_nan() +// } + +// fn complicate_once(&mut self) -> bool { +// if BinarySearch::done(self.lo, self.hi) { +// return false; +// } + +// self.lo = if self.curr == self.lo { self.hi } else { self.curr }; + +// self.reposition() +// } +// } +// impl ValueTree for BinarySearch { +// type Value = $typ; + +// fn current(&self) -> $typ { +// self.curr +// } + +// fn simplify(&mut self) -> bool { +// if BinarySearch::done(self.lo, self.hi) { +// return false; +// } + +// self.hi = self.curr; +// if self.reposition() { +// self.ensure_acceptable(); +// true +// } else { +// false +// } +// } + +// fn complicate(&mut self) -> bool { +// if self.complicate_once() { +// self.ensure_acceptable(); +// true +// } else { +// false +// } +// } +// } + +// numeric_api!($typ, 0.0); +// } +// }; +// } + +// float_bin_search!(f32); +// float_bin_search!(f64); + +// #[cfg(test)] +// mod test { +// use crate::strategy::*; +// use crate::test_runner::*; + +// use super::*; + +// #[test] +// fn u8_inclusive_end_included() { +// let mut runner = TestRunner::deterministic(); +// let mut ok = 0; +// for _ in 0..20 { +// let tree = (0..=1).new_tree(&mut runner).unwrap(); +// let test = runner.run_one(tree, |v| { +// prop_assert_eq!(v, 1); +// Ok(()) +// }); +// if test.is_ok() { +// ok += 1; +// } +// } +// assert!(ok > 1, "inclusive end not included."); +// } + +// #[test] +// fn u8_inclusive_to_end_included() { +// let mut runner = TestRunner::deterministic(); +// let mut ok = 0; +// for _ in 0..20 { +// let tree = (..=1u8).new_tree(&mut runner).unwrap(); +// let test = runner.run_one(tree, |v| { +// prop_assert_eq!(v, 1); +// Ok(()) +// }); +// if test.is_ok() { +// ok += 1; +// } +// } +// assert!(ok > 1, "inclusive end not included."); +// } + +// #[test] +// fn i8_binary_search_always_converges() { +// fn assert_converges bool>(start: i8, pass: P) { +// let mut state = i8::BinarySearch::new(start); +// loop { +// if !pass(state.current() as i32) { +// if !state.simplify() { +// break; +// } +// } else { +// if !state.complicate() { +// break; +// } +// } +// } + +// assert!(!pass(state.current() as i32)); +// assert!(pass(state.current() as i32 - 1) || pass(state.current() as i32 + 1)); +// } + +// for start in -128..0 { +// for target in start + 1..1 { +// assert_converges(start as i8, |v| v > target); +// } +// } + +// for start in 0..128 { +// for target in 0..start { +// assert_converges(start as i8, |v| v < target); +// } +// } +// } + +// #[test] +// fn u8_binary_search_always_converges() { +// fn assert_converges bool>(start: u8, pass: P) { +// let mut state = u8::BinarySearch::new(start); +// loop { +// if !pass(state.current() as u32) { +// if !state.simplify() { +// break; +// } +// } else { +// if !state.complicate() { +// break; +// } +// } +// } + +// assert!(!pass(state.current() as u32)); +// assert!(pass(state.current() as u32 - 1)); +// } + +// for start in 0..255 { +// for target in 0..start { +// assert_converges(start as u8, |v| v <= target); +// } +// } +// } + +// #[test] +// fn signed_integer_range_including_zero_converges_to_zero() { +// let mut runner = TestRunner::default(); +// for _ in 0..100 { +// let mut state = (-42i32..64i32).new_tree(&mut runner).unwrap(); +// let init_value = state.current(); +// assert!(init_value >= -42 && init_value < 64); + +// while state.simplify() { +// let v = state.current(); +// assert!(v >= -42 && v < 64); +// } + +// assert_eq!(0, state.current()); +// } +// } + +// #[test] +// fn negative_integer_range_stays_in_bounds() { +// let mut runner = TestRunner::default(); +// for _ in 0..100 { +// let mut state = (..-42i32).new_tree(&mut runner).unwrap(); +// let init_value = state.current(); +// assert!(init_value < -42); + +// while state.simplify() { +// assert!(state.current() < -42, "Violated bounds: {}", state.current()); +// } + +// assert_eq!(-43, state.current()); +// } +// } + +// #[test] +// fn positive_signed_integer_range_stays_in_bounds() { +// let mut runner = TestRunner::default(); +// for _ in 0..100 { +// let mut state = (42i32..).new_tree(&mut runner).unwrap(); +// let init_value = state.current(); +// assert!(init_value >= 42); + +// while state.simplify() { +// assert!(state.current() >= 42, "Violated bounds: {}", state.current()); +// } + +// assert_eq!(42, state.current()); +// } +// } + +// #[test] +// fn unsigned_integer_range_stays_in_bounds() { +// let mut runner = TestRunner::default(); +// for _ in 0..100 { +// let mut state = (42u32..56u32).new_tree(&mut runner).unwrap(); +// let init_value = state.current(); +// assert!(init_value >= 42 && init_value < 56); + +// while state.simplify() { +// assert!(state.current() >= 42, "Violated bounds: {}", state.current()); +// } + +// assert_eq!(42, state.current()); +// } +// } + +// mod contract_sanity { +// macro_rules! contract_sanity { +// ($t:tt) => { +// mod $t { +// use crate::strategy::check_strategy_sanity; + +// const FOURTY_TWO: $t = 42 as $t; +// const FIFTY_SIX: $t = 56 as $t; + +// #[test] +// fn range() { +// check_strategy_sanity(FOURTY_TWO..FIFTY_SIX, None); +// } + +// #[test] +// fn range_inclusive() { +// check_strategy_sanity(FOURTY_TWO..=FIFTY_SIX, None); +// } + +// #[test] +// fn range_to() { +// check_strategy_sanity(..FIFTY_SIX, None); +// } + +// #[test] +// fn range_to_inclusive() { +// check_strategy_sanity(..=FIFTY_SIX, None); +// } + +// #[test] +// fn range_from() { +// check_strategy_sanity(FOURTY_TWO.., None); +// } +// } +// }; +// } +// contract_sanity!(u8); +// contract_sanity!(i8); +// contract_sanity!(u16); +// contract_sanity!(i16); +// contract_sanity!(u32); +// contract_sanity!(i32); +// contract_sanity!(u64); +// contract_sanity!(i64); +// contract_sanity!(usize); +// contract_sanity!(isize); +// contract_sanity!(f32); +// contract_sanity!(f64); +// } + +// #[test] +// fn unsigned_integer_binsearch_simplify_complicate_contract_upheld() { +// check_strategy_sanity(0u32..1000u32, None); +// check_strategy_sanity(0u32..1u32, None); +// } + +// #[test] +// fn signed_integer_binsearch_simplify_complicate_contract_upheld() { +// check_strategy_sanity(0i32..1000i32, None); +// check_strategy_sanity(0i32..1i32, None); +// } + +// #[test] +// fn positive_float_simplifies_to_zero() { +// let mut runner = TestRunner::default(); +// let mut value = (0.0f64..2.0).new_tree(&mut runner).unwrap(); + +// while value.simplify() {} + +// assert_eq!(0.0, value.current()); +// } + +// #[test] +// fn positive_float_simplifies_to_base() { +// let mut runner = TestRunner::default(); +// let mut value = (1.0f64..2.0).new_tree(&mut runner).unwrap(); + +// while value.simplify() {} + +// assert_eq!(1.0, value.current()); +// } + +// #[test] +// fn negative_float_simplifies_to_zero() { +// let mut runner = TestRunner::default(); +// let mut value = (-2.0f64..0.0).new_tree(&mut runner).unwrap(); + +// while value.simplify() {} + +// assert_eq!(0.0, value.current()); +// } + +// #[test] +// fn positive_float_complicates_to_original() { +// let mut runner = TestRunner::default(); +// let mut value = (1.0f64..2.0).new_tree(&mut runner).unwrap(); +// let orig = value.current(); + +// assert!(value.simplify()); +// while value.complicate() {} + +// assert_eq!(orig, value.current()); +// } + +// #[test] +// fn positive_infinity_simplifies_directly_to_zero() { +// let mut value = f64::BinarySearch::new(::std::f64::INFINITY); + +// assert!(value.simplify()); +// assert_eq!(0.0, value.current()); +// assert!(value.complicate()); +// assert_eq!(::std::f64::INFINITY, value.current()); +// assert!(!value.clone().complicate()); +// assert!(!value.clone().simplify()); +// } + +// #[test] +// fn negative_infinity_simplifies_directly_to_zero() { +// let mut value = f64::BinarySearch::new(::std::f64::NEG_INFINITY); + +// assert!(value.simplify()); +// assert_eq!(0.0, value.current()); +// assert!(value.complicate()); +// assert_eq!(::std::f64::NEG_INFINITY, value.current()); +// assert!(!value.clone().complicate()); +// assert!(!value.clone().simplify()); +// } + +// #[test] +// fn nan_simplifies_directly_to_zero() { +// let mut value = f64::BinarySearch::new(::std::f64::NAN); + +// assert!(value.simplify()); +// assert_eq!(0.0, value.current()); +// assert!(value.complicate()); +// assert!(value.current().is_nan()); +// assert!(!value.clone().complicate()); +// assert!(!value.clone().simplify()); +// } + +// #[test] +// fn float_simplifies_to_smallest_normal() { +// let mut runner = TestRunner::default(); +// let mut value = (::std::f64::MIN_POSITIVE..2.0).new_tree(&mut runner).unwrap(); + +// while value.simplify() {} + +// assert_eq!(::std::f64::MIN_POSITIVE, value.current()); +// } + +// macro_rules! float_generation_test_body { +// ($strategy:ident, $typ:ident) => { +// use std::num::FpCategory; + +// let strategy = $strategy; +// let bits = strategy.normal_bits(); + +// let mut seen_positive = 0; +// let mut seen_negative = 0; +// let mut seen_normal = 0; +// let mut seen_subnormal = 0; +// let mut seen_zero = 0; +// let mut seen_infinite = 0; +// let mut seen_quiet_nan = 0; +// let mut seen_signaling_nan = 0; +// let mut runner = TestRunner::deterministic(); + +// // Check whether this version of Rust honours the NaN payload in +// // from_bits +// let fidelity_1 = f32::from_bits(0x7F80_0001).to_bits(); +// let fidelity_2 = f32::from_bits(0xFF80_0001).to_bits(); +// let nan_fidelity = fidelity_1 != fidelity_2; + +// for _ in 0..1024 { +// let mut tree = strategy.new_tree(&mut runner).unwrap(); +// let mut increment = 1; + +// loop { +// let value = tree.current(); + +// let sign = value.signum(); // So we correctly handle -0 +// if sign < 0.0 { +// prop_assert!(bits.contains(FloatTypes::NEGATIVE)); +// seen_negative += increment; +// } else if sign > 0.0 { +// // i.e., not NaN +// prop_assert!(bits.contains(FloatTypes::POSITIVE)); +// seen_positive += increment; +// } + +// match value.classify() { +// FpCategory::Nan if nan_fidelity => { +// let raw = value.to_bits(); +// let is_negative = raw << 1 >> 1 != raw; +// if is_negative { +// prop_assert!(bits.contains(FloatTypes::NEGATIVE)); +// seen_negative += increment; +// } else { +// prop_assert!(bits.contains(FloatTypes::POSITIVE)); +// seen_positive += increment; +// } + +// let is_quiet = raw & ($typ::EXP_MASK >> 1) +// == ::std::$typ::NAN.to_bits() & ($typ::EXP_MASK >> 1); +// if is_quiet { +// // x86/AMD64 turn signalling NaNs into quiet +// // NaNs quite aggressively depending on what +// // registers LLVM decides to use to pass the +// // value around, so accept either case here. +// prop_assert!( +// bits.contains(FloatTypes::QUIET_NAN) +// || bits.contains(FloatTypes::SIGNALING_NAN) +// ); +// seen_quiet_nan += increment; +// seen_signaling_nan += increment; +// } else { +// prop_assert!(bits.contains(FloatTypes::SIGNALING_NAN)); +// seen_signaling_nan += increment; +// } +// } + +// FpCategory::Nan => { +// // Since safe Rust doesn't currently allow +// // generating any NaN other than one particular +// // payload, don't check the sign or signallingness +// // and consider this to be both signs and +// // signallingness for counting purposes. +// seen_positive += increment; +// seen_negative += increment; +// seen_quiet_nan += increment; +// seen_signaling_nan += increment; +// prop_assert!( +// bits.contains(FloatTypes::QUIET_NAN) +// || bits.contains(FloatTypes::SIGNALING_NAN) +// ); +// } +// FpCategory::Infinite => { +// prop_assert!(bits.contains(FloatTypes::INFINITE)); +// seen_infinite += increment; +// } +// FpCategory::Zero => { +// prop_assert!(bits.contains(FloatTypes::ZERO)); +// seen_zero += increment; +// } +// FpCategory::Subnormal => { +// prop_assert!(bits.contains(FloatTypes::SUBNORMAL)); +// seen_subnormal += increment; +// } +// FpCategory::Normal => { +// prop_assert!(bits.contains(FloatTypes::NORMAL)); +// seen_normal += increment; +// } +// } + +// // Don't count simplified values towards the counts +// increment = 0; +// if !tree.simplify() { +// break; +// } +// } +// } + +// if bits.contains(FloatTypes::POSITIVE) { +// prop_assert!(seen_positive > 200); +// } +// if bits.contains(FloatTypes::NEGATIVE) { +// prop_assert!(seen_negative > 200); +// } +// if bits.contains(FloatTypes::NORMAL) { +// prop_assert!(seen_normal > 100); +// } +// if bits.contains(FloatTypes::SUBNORMAL) { +// prop_assert!(seen_subnormal > 5); +// } +// if bits.contains(FloatTypes::ZERO) { +// prop_assert!(seen_zero > 5); +// } +// if bits.contains(FloatTypes::INFINITE) { +// prop_assert!(seen_infinite > 0); +// } +// if bits.contains(FloatTypes::QUIET_NAN) { +// prop_assert!(seen_quiet_nan > 0); +// } +// if bits.contains(FloatTypes::SIGNALING_NAN) { +// prop_assert!(seen_signaling_nan > 0); +// } +// }; +// } + +// proptest! { +// #![proptest_config(crate::test_runner::Config::with_cases(1024))] + +// #[test] +// fn f32_any_generates_desired_values( +// strategy in crate::bits::u32::ANY.prop_map(f32::Any::from_bits) +// ) { +// float_generation_test_body!(strategy, f32); +// } + +// #[test] +// fn f32_any_sanity( +// strategy in crate::bits::u32::ANY.prop_map(f32::Any::from_bits) +// ) { +// check_strategy_sanity(strategy, Some(CheckStrategySanityOptions { +// strict_complicate_after_simplify: false, +// .. CheckStrategySanityOptions::default() +// })); +// } + +// #[test] +// fn f64_any_generates_desired_values( +// strategy in crate::bits::u32::ANY.prop_map(f64::Any::from_bits) +// ) { +// float_generation_test_body!(strategy, f64); +// } + +// #[test] +// fn f64_any_sanity( +// strategy in crate::bits::u32::ANY.prop_map(f64::Any::from_bits) +// ) { +// check_strategy_sanity(strategy, Some(CheckStrategySanityOptions { +// strict_complicate_after_simplify: false, +// .. CheckStrategySanityOptions::default() +// })); +// } +// } +// } diff --git a/library/proptest/src/strategy/just.rs b/library/proptest/src/strategy/just.rs new file mode 100644 index 000000000000..34e69ef16bee --- /dev/null +++ b/library/proptest/src/strategy/just.rs @@ -0,0 +1,141 @@ +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use crate::std_facade::fmt; + +use crate::strategy::{NewTree, Strategy, ValueTree}; +use crate::test_runner::TestRunner; + +macro_rules! noshrink { + () => { + fn simplify(&mut self) -> bool { + false + } + fn complicate(&mut self) -> bool { + false + } + }; +} + +//============================================================================== +// Just +//============================================================================== + +/// A `Strategy` which always produces a single value value and never +/// simplifies. +#[derive(Clone, Copy, Debug)] +#[must_use = "strategies do nothing unless used"] +pub struct Just( + /// The value produced by this strategy. + pub T, +); + +impl Strategy for Just { + type Tree = Self; + type Value = T; + + fn new_tree(&self, _: &mut TestRunner) -> NewTree { + Ok(self.clone()) + } +} + +impl ValueTree for Just { + type Value = T; + noshrink!(); + fn current(&self) -> T { + kani::any() + } +} + +//============================================================================== +// LazyJust +//============================================================================== + +/// A `Strategy` which always produces a single value value and never +/// simplifies. If `T` is `Clone`, you should use `Just` instead. +/// +/// This is a generalization of `Just` and works by calling +/// the provided `Fn () -> T` in `.current()` every time. This is not a +/// very interesting strategy, but is required in cases where `T` is +/// not `Clone`. It is also used in `proptest_derive` where we can't +/// assume that your type is `Clone`. +/// +/// **It is important that the function used be pure.** +#[must_use = "strategies do nothing unless used"] +pub struct LazyJust T> { + /// The function executed in `.current()`. + _function: F, +} + +/// Shorthand for `LazyJust T>`. +pub type LazyJustFn = LazyJust V>; + +impl T> LazyJust { + /// Constructs a `LazyJust` strategy given the function/closure + /// that produces the value. + /// + /// **It is important that the function used be pure.** + pub fn new(function: F) -> Self { + Self { _function: function } + } +} + +impl T> Strategy for LazyJust { + type Tree = Self; + type Value = T; + + fn new_tree(&self, _: &mut TestRunner) -> NewTree { + Ok(self.clone()) + } +} + +impl T> ValueTree for LazyJust { + type Value = T; + noshrink!(); + fn current(&self) -> Self::Value { + kani::any() + } +} + +impl T> Copy for LazyJust {} + +impl T> Clone for LazyJust { + fn clone(&self) -> Self { + Self { _function: self._function.clone() } + } +} + +impl T> fmt::Debug for LazyJust { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("LazyJust").field("function", &"").finish() + } +} + +//============================================================================== +// Any `fn () -> T` is a Strategy +//============================================================================== + +// TODO: try 'F: Fn () -> T' instead when we've got specialization. + +impl Strategy for fn() -> T { + type Tree = Self; + type Value = T; + + fn new_tree(&self, _: &mut TestRunner) -> NewTree { + Ok(*self) + } +} + +impl ValueTree for fn() -> T { + type Value = T; + noshrink!(); + fn current(&self) -> Self::Value { + self() + } +} diff --git a/library/proptest/src/strategy/mod.rs b/library/proptest/src/strategy/mod.rs index 4fcf3772562a..aa286f871dc0 100644 --- a/library/proptest/src/strategy/mod.rs +++ b/library/proptest/src/strategy/mod.rs @@ -13,7 +13,7 @@ // mod filter_map; // mod flatten; // mod fuse; -// mod just; +mod just; // mod lazy; // mod map; // mod recursive; @@ -25,7 +25,7 @@ mod traits; // pub use self::filter_map::*; // pub use self::flatten::*; // pub use self::fuse::*; -// pub use self::just::*; +pub use self::just::*; // pub use self::lazy::*; // pub use self::lazy::*; // pub use self::map::*; From 490f87ba4cf322ebb14869820329982ca6a669c5 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Tue, 19 Jul 2022 16:18:19 -0400 Subject: [PATCH 22/80] Removed expansion. Somehow fixes the "finding proof" issue. --- kani-compiler/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kani-compiler/src/main.rs b/kani-compiler/src/main.rs index e9d25ef77048..b6c5d485eded 100644 --- a/kani-compiler/src/main.rs +++ b/kani-compiler/src/main.rs @@ -71,8 +71,8 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { "crate-attr=register_tool(kanitool)", // Prints expanded macro. For proptest devops only, remove after done - "-Z", - "unpretty=expanded", + // "-Z", + // "unpretty=expanded", "-L", lib_path, From efe3cb4d5efb0acb094816af6d4f6c0e60ec5f18 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Tue, 19 Jul 2022 16:19:03 -0400 Subject: [PATCH 23/80] Fixed missing tuple implementation. --- library/proptest/src/lib.rs | 2 +- library/proptest/src/test_runner/runner.rs | 3 + library/proptest/src/tuple.rs | 129 +++++++++++++++++++++ 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 library/proptest/src/tuple.rs diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index 22c6b43b5581..9a4c7443a256 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -88,7 +88,7 @@ pub mod arbitrary; pub mod num; pub mod strategy; pub mod test_runner; -// pub mod tuple; +pub mod tuple; // pub mod option; // pub mod result; diff --git a/library/proptest/src/test_runner/runner.rs b/library/proptest/src/test_runner/runner.rs index e029721ad697..d07319972170 100644 --- a/library/proptest/src/test_runner/runner.rs +++ b/library/proptest/src/test_runner/runner.rs @@ -19,6 +19,9 @@ impl TestRunner { /// Creates new pub fn new(_: Config) -> Self { Self {} } + /// default test runner. + pub fn default() -> Self { Self {} } + /// Run the test function with a Kani symbolic value given a test function that takes that type. pub fn run_kani(strategy: S, test_fn: impl Fn(S::Value) -> ()) { let mut runner = Self::new(Config::default()); diff --git a/library/proptest/src/tuple.rs b/library/proptest/src/tuple.rs new file mode 100644 index 000000000000..56bbe348577a --- /dev/null +++ b/library/proptest/src/tuple.rs @@ -0,0 +1,129 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Support for combining strategies into tuples. +//! +//! There is no explicit "tuple strategy"; simply make a tuple containing the +//! strategy and that tuple is itself a strategy. + +use crate::strategy::*; +use crate::test_runner::*; + +/// Common `ValueTree` implementation for all tuple strategies. +#[derive(Clone, Copy, Debug)] +pub struct TupleValueTree { + tree: T, +} + +impl TupleValueTree { + /// Create a new `TupleValueTree` wrapping `inner`. + /// + /// It only makes sense for `inner` to be a tuple of an arity for which the + /// type implements `ValueTree`. + pub fn new(inner: T) -> Self { + TupleValueTree { tree: inner } + } +} + +macro_rules! tuple { + ($($fld:tt : $typ:ident),*) => { + impl<$($typ : Strategy),*> Strategy for ($($typ,)*) { + type Tree = TupleValueTree<($($typ::Tree,)*)>; + type Value = ($($typ::Value,)*); + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + let values = ($(self.$fld.new_tree(runner)?,)*); + Ok(TupleValueTree::new(values)) + } + } + + impl<$($typ : ValueTree),*> ValueTree + for TupleValueTree<($($typ,)*)> { + type Value = ($($typ::Value,)*); + + fn current(&self) -> Self::Value { + ($(self.tree.$fld.current(),)*) + } + + fn simplify(&mut self) -> bool { + false + } + + fn complicate(&mut self) -> bool { + false + } + } + } +} + +tuple!(0: A); +tuple!(0: A, 1: B); +tuple!(0: A, 1: B, 2: C); +tuple!(0: A, 1: B, 2: C, 3: D); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K); +tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L); + +#[cfg(test)] +mod test { + use crate::strategy::*; + + use super::*; + + #[test] + fn shrinks_fully_ltr() { + fn pass(a: (i32, i32)) -> bool { + a.0 * a.1 <= 9 + } + + let input = (0..32, 0..32); + let mut runner = TestRunner::default(); + + let mut cases_tested = 0; + for _ in 0..256 { + // Find a failing test case + let mut case = input.new_tree(&mut runner).unwrap(); + if pass(case.current()) { + continue; + } + + loop { + if pass(case.current()) { + if !case.complicate() { + break; + } + } else { + if !case.simplify() { + break; + } + } + } + + let last = case.current(); + assert!(!pass(last)); + // Maximally shrunken + assert!(pass((last.0 - 1, last.1))); + assert!(pass((last.0, last.1 - 1))); + + cases_tested += 1; + } + + assert!(cases_tested > 32, "Didn't find enough test cases"); + } + + #[test] + fn test_sanity() { + check_strategy_sanity((0i32..100, 0i32..1000, 0i32..10000), None); + } +} From eac76a7efc954a37d0e8f4f44a45fd9f34f975f4 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Tue, 19 Jul 2022 18:21:32 -0400 Subject: [PATCH 24/80] Externalized arbitrary value generation. (Commit before macro try) --- library/proptest/src/strategy/just.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/proptest/src/strategy/just.rs b/library/proptest/src/strategy/just.rs index 34e69ef16bee..4838098cc688 100644 --- a/library/proptest/src/strategy/just.rs +++ b/library/proptest/src/strategy/just.rs @@ -49,7 +49,7 @@ impl ValueTree for Just { type Value = T; noshrink!(); fn current(&self) -> T { - kani::any() + self.0.clone() } } From 67a6494ba135d3fbe3bb11bdb9b57868c8231711 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Tue, 19 Jul 2022 20:29:03 -0400 Subject: [PATCH 25/80] Added hack translator for from strategy to kani. --- library/proptest/src/sugar.rs | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/library/proptest/src/sugar.rs b/library/proptest/src/sugar.rs index ce69b91636f5..77c65360977e 100644 --- a/library/proptest/src/sugar.rs +++ b/library/proptest/src/sugar.rs @@ -153,7 +153,14 @@ macro_rules! proptest { $( $(#[$meta:meta])* fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block - )*) => { + )*) => { + fn strategy_to_kani(_ : S) -> S::Value + where + V: kani::Invariant, + S: $crate::strategy::Strategy, + { + kani::any() + } $( #[kani::proof] $(#[$meta])* @@ -169,7 +176,14 @@ macro_rules! proptest { $( $(#[$meta:meta])* fn $test_name:ident($($arg:tt)+) $body:block - )*) => { + )*) => { + fn strategy_to_kani(_ : S) -> S::Value + where + V: kani::Invariant, + S: $crate::strategy::Strategy, + { + kani::any() + } $( #[kani::proof] $(#[$meta])* @@ -952,7 +966,7 @@ macro_rules! proptest_helper { let names = $crate::proptest_helper!(@_WRAPSTR ($($parm),*)); match runner.run( &$crate::strategy::Strategy::prop_map( - $crate::proptest_helper!(@_WRAP ($($strategy)*)), + strategy_to_kani($crate::proptest_helper!(@_WRAP ($($strategy)*))), |values| $crate::sugar::NamedArguments(names, values)), $($mod)* |$crate::sugar::NamedArguments( _, $crate::proptest_helper!(@_WRAPPAT ($($parm),*)))| @@ -984,12 +998,11 @@ macro_rules! proptest_helper { // Ok(_) => (), // Err(e) => panic!("{}\n{}", e, runner2), // } - $crate::test_runner::TestRunner::run_kani( - $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), - |$crate::proptest_helper!(@_EXT _PAT ($($arg)*))| { - $body - } - ); + // $crate::test_runner::TestRunner::run_kani( + let $crate::proptest_helper!(@_EXT _PAT ($($arg)*)) = + strategy_to_kani($crate::proptest_helper!(@_EXT _STRAT ($($arg)*))); + + $body }}; // The logic below helps support `pat: type` in the proptest! macro. From 59e301614707681b0b907dfeaae075cbdd1b87d8 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Tue, 19 Jul 2022 20:52:13 -0400 Subject: [PATCH 26/80] Implemented Invariant for tuples. --- library/kani/src/invariant.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/library/kani/src/invariant.rs b/library/kani/src/invariant.rs index dbbcc87d474a..a9cf96dbae43 100644 --- a/library/kani/src/invariant.rs +++ b/library/kani/src/invariant.rs @@ -52,6 +52,30 @@ empty_invariant!(f64); empty_invariant!(()); +macro_rules! tuple_invariant { + ($($fld:tt : $typ:ident),*) => { + unsafe impl<$($typ : Invariant),*> Invariant for ($($typ,)*) { + #[inline(always)] + fn is_valid(&self) -> bool { + ($(self.$fld.is_valid() &&)* true) + } + } + } +} + +tuple_invariant!(0: A); +tuple_invariant!(0: A, 1: B); +tuple_invariant!(0: A, 1: B, 2: C); +tuple_invariant!(0: A, 1: B, 2: C, 3: D); +tuple_invariant!(0: A, 1: B, 2: C, 3: D, 4: E); +tuple_invariant!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F); +tuple_invariant!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G); +tuple_invariant!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H); +tuple_invariant!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I); +tuple_invariant!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J); +tuple_invariant!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K); +tuple_invariant!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L); + unsafe impl Invariant for bool { #[inline(always)] fn is_valid(&self) -> bool { From 53d4eb98c33b42d1fc1407f447627e39624fa1e6 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Tue, 19 Jul 2022 20:52:28 -0400 Subject: [PATCH 27/80] Just use kani::any by itself for now. --- library/proptest/src/sugar.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/proptest/src/sugar.rs b/library/proptest/src/sugar.rs index 77c65360977e..3ee9e74c80c8 100644 --- a/library/proptest/src/sugar.rs +++ b/library/proptest/src/sugar.rs @@ -1000,7 +1000,8 @@ macro_rules! proptest_helper { // } // $crate::test_runner::TestRunner::run_kani( let $crate::proptest_helper!(@_EXT _PAT ($($arg)*)) = - strategy_to_kani($crate::proptest_helper!(@_EXT _STRAT ($($arg)*))); + kani::any(); + // strategy_to_kani($crate::proptest_helper!(@_EXT _STRAT ($($arg)*))); $body }}; From 4855fc588f7798e67fe1f28ccb35b9cccf0afb32 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Thu, 28 Jul 2022 16:33:06 -0400 Subject: [PATCH 28/80] Reverted proptest macro. --- library/proptest/src/sugar.rs | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/library/proptest/src/sugar.rs b/library/proptest/src/sugar.rs index 3ee9e74c80c8..ce69b91636f5 100644 --- a/library/proptest/src/sugar.rs +++ b/library/proptest/src/sugar.rs @@ -153,14 +153,7 @@ macro_rules! proptest { $( $(#[$meta:meta])* fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block - )*) => { - fn strategy_to_kani(_ : S) -> S::Value - where - V: kani::Invariant, - S: $crate::strategy::Strategy, - { - kani::any() - } + )*) => { $( #[kani::proof] $(#[$meta])* @@ -176,14 +169,7 @@ macro_rules! proptest { $( $(#[$meta:meta])* fn $test_name:ident($($arg:tt)+) $body:block - )*) => { - fn strategy_to_kani(_ : S) -> S::Value - where - V: kani::Invariant, - S: $crate::strategy::Strategy, - { - kani::any() - } + )*) => { $( #[kani::proof] $(#[$meta])* @@ -966,7 +952,7 @@ macro_rules! proptest_helper { let names = $crate::proptest_helper!(@_WRAPSTR ($($parm),*)); match runner.run( &$crate::strategy::Strategy::prop_map( - strategy_to_kani($crate::proptest_helper!(@_WRAP ($($strategy)*))), + $crate::proptest_helper!(@_WRAP ($($strategy)*)), |values| $crate::sugar::NamedArguments(names, values)), $($mod)* |$crate::sugar::NamedArguments( _, $crate::proptest_helper!(@_WRAPPAT ($($parm),*)))| @@ -998,12 +984,12 @@ macro_rules! proptest_helper { // Ok(_) => (), // Err(e) => panic!("{}\n{}", e, runner2), // } - // $crate::test_runner::TestRunner::run_kani( - let $crate::proptest_helper!(@_EXT _PAT ($($arg)*)) = - kani::any(); - // strategy_to_kani($crate::proptest_helper!(@_EXT _STRAT ($($arg)*))); - - $body + $crate::test_runner::TestRunner::run_kani( + $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), + |$crate::proptest_helper!(@_EXT _PAT ($($arg)*))| { + $body + } + ); }}; // The logic below helps support `pat: type` in the proptest! macro. From 701725fcc76af1f5393b83dbbb13b674af9bc580 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Thu, 28 Jul 2022 16:33:22 -0400 Subject: [PATCH 29/80] Temporary commit: hard-coded kani output path. --- kani-compiler/src/main.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/kani-compiler/src/main.rs b/kani-compiler/src/main.rs index b6c5d485eded..5bb0ad49d580 100644 --- a/kani-compiler/src/main.rs +++ b/kani-compiler/src/main.rs @@ -81,7 +81,8 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { "--extern", kani_std_wrapper.as_str(), "--extern", - "proptest=/Users/ytakashl/Desktop/kani/target/debug/build/kani-compiler-913e19dc97ff67d3/out/lib/libproptest.rlib", + "proptest=/Users/ytakashl/Desktop/bin-proptest/aarch64-apple-darwin/debug/deps/libproptest-4eedccdf5f7f3c3f.rlib", + // "proptest=/Users/ytakashl/Desktop/kani/target/debug/build/kani-compiler-913e19dc97ff67d3/out/lib/libproptest.rlib", // todo! why does this need to be hard-coded??? // kani_proptest_wrapper.as_str(), //Why is the other one off? ]; From fd6dff4d2f5edca838733f50afacd11ca95102c1 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Fri, 29 Jul 2022 18:02:11 -0400 Subject: [PATCH 30/80] Implemented custom compile script to get symtabs for proptest. --- kani-compiler/build.rs | 1 - library/proptest/Cargo.toml | 2 +- scripts/refresh-kani-proptest.sh | 30 ++++++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100755 scripts/refresh-kani-proptest.sh diff --git a/kani-compiler/build.rs b/kani-compiler/build.rs index 82babc4de40e..c42fc62a55b8 100644 --- a/kani-compiler/build.rs +++ b/kani-compiler/build.rs @@ -65,6 +65,5 @@ pub fn main() { setup_lib(&out_dir, &lib_out, "kani"); setup_lib(&out_dir, &lib_out, "kani_macros"); setup_lib(&out_dir, &lib_out, "std"); - setup_lib(&out_dir, &lib_out, "proptest"); println!("cargo:rustc-env=KANI_LIB_PATH={}", lib_out); } diff --git a/library/proptest/Cargo.toml b/library/proptest/Cargo.toml index e1dcfb7e4a8e..545fd71ff6a8 100644 --- a/library/proptest/Cargo.toml +++ b/library/proptest/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -[dependencies] +[target.'cfg(not(kani))'.dependencies] kani = { path = "../kani" } \ No newline at end of file diff --git a/scripts/refresh-kani-proptest.sh b/scripts/refresh-kani-proptest.sh new file mode 100755 index 000000000000..d2b57c053a79 --- /dev/null +++ b/scripts/refresh-kani-proptest.sh @@ -0,0 +1,30 @@ +#!/bin/bash +# Copyright Kani Contributors +# SPDX-License-Identifier: Apache-2.0 OR MIT + +# This file checks that the proptest rlib and symtab are up to are up +# to date compared to the kani binary. If not, `cargo kani` is called +# on proptest to refresh the symtab and rlib. This script is not meant +# to called manually, but rather from `scripts/kani` and +# `scripts/cargo-kani`. + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) +KANI_REPO_ROOT="$SCRIPT_DIR/.." + +PROPTEST_SYMTAB_PATH="$(find $KANI_REPO_ROOT/target -name '*symtab.json' | head -1)" +KANI_BINARY_PATH="$KANI_REPO_ROOT/debug/kani-compiler" + +if [ ! -f "$PROPTEST_SYMTAB_PATH" ] || [[ "$PROPTEST_SYMTAB_PATH" -ot "$KANI_BINARY_PATH" ]]; then + echo 'Proptest symtab not found or too old. (Re)compiling proptest..' + ( + cd $KANI_REPO_ROOT/library/proptest; + cargo kani --only-codegen; + + # TODO: not needed after workspace PR #1421 merges. + cp -r ./target $KANI_REPO_ROOT; + rm -rf ./target + ) +fi + +# delete the normal rlib to avoid confusion. +rm $(find $KANI_REPO_ROOT/target/debug -name '*libproptest*.rlib') || true From b22d99653efe7c8dc28964b1f9799e60bc9d89d4 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Fri, 29 Jul 2022 19:08:28 -0400 Subject: [PATCH 31/80] Added automatic local target detection. --- kani-compiler/build.rs | 1 + kani-compiler/src/main.rs | 17 +++++++++-------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/kani-compiler/build.rs b/kani-compiler/build.rs index c42fc62a55b8..8a96a81cbb9c 100644 --- a/kani-compiler/build.rs +++ b/kani-compiler/build.rs @@ -66,4 +66,5 @@ pub fn main() { setup_lib(&out_dir, &lib_out, "kani_macros"); setup_lib(&out_dir, &lib_out, "std"); println!("cargo:rustc-env=KANI_LIB_PATH={}", lib_out); + println!("cargo:rustc-env=TARGET={}", env::var("TARGET").unwrap()); } diff --git a/kani-compiler/src/main.rs b/kani-compiler/src/main.rs index 5bb0ad49d580..c88285fb3b42 100644 --- a/kani-compiler/src/main.rs +++ b/kani-compiler/src/main.rs @@ -47,10 +47,12 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { // for more details. let kani_std_rlib = PathBuf::from(lib_path).join("libstd.rlib"); let kani_std_wrapper = format!("noprelude:std={}", kani_std_rlib.to_str().unwrap()); - let kani_proptest_rlib = PathBuf::from(lib_path).join("libproptest.rlib"); - let _kani_proptest_wrapper = - format!("noprelude:proptest={}", kani_proptest_rlib.to_str().unwrap()); - // println!("kani_std wrapper is: {}", &kani_std_wrapper.as_str()); + + let build_target = env!("TARGET"); // see build.rs + let kani_extern_lib_path = + PathBuf::from(lib_path) + .join(format!("../../../../../{}/debug/deps", build_target)); + let args = vec![ "-C", "overflow-checks=on", @@ -80,11 +82,10 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { "kani", "--extern", kani_std_wrapper.as_str(), + "-L", + kani_extern_lib_path.to_str().unwrap(), "--extern", - "proptest=/Users/ytakashl/Desktop/bin-proptest/aarch64-apple-darwin/debug/deps/libproptest-4eedccdf5f7f3c3f.rlib", - // "proptest=/Users/ytakashl/Desktop/kani/target/debug/build/kani-compiler-913e19dc97ff67d3/out/lib/libproptest.rlib", - // todo! why does this need to be hard-coded??? - // kani_proptest_wrapper.as_str(), //Why is the other one off? + "proptest", ]; args.iter().map(|s| s.to_string()).collect() } From b94a9b07060f0d4d1783049927dc05f960bc156d Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Fri, 29 Jul 2022 20:33:55 -0400 Subject: [PATCH 32/80] Ignored expected error message. --- scripts/refresh-kani-proptest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/refresh-kani-proptest.sh b/scripts/refresh-kani-proptest.sh index d2b57c053a79..7d3ebab0646a 100755 --- a/scripts/refresh-kani-proptest.sh +++ b/scripts/refresh-kani-proptest.sh @@ -27,4 +27,4 @@ if [ ! -f "$PROPTEST_SYMTAB_PATH" ] || [[ "$PROPTEST_SYMTAB_PATH" -ot "$KANI_BIN fi # delete the normal rlib to avoid confusion. -rm $(find $KANI_REPO_ROOT/target/debug -name '*libproptest*.rlib') || true +rm $(find $KANI_REPO_ROOT/target/debug -name '*libproptest*.rlib') 2> /dev/null || true From 276d1557ec7ddb32a5ccc019bd476ce740e11aaf Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Fri, 29 Jul 2022 20:36:57 -0400 Subject: [PATCH 33/80] implemented search of kani extern path for symtabs. --- kani-driver/build.rs | 6 +++++- kani-driver/src/call_cargo.rs | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/kani-driver/build.rs b/kani-driver/build.rs index 58b4f8f6dbe5..621e33d02c70 100644 --- a/kani-driver/build.rs +++ b/kani-driver/build.rs @@ -9,5 +9,9 @@ fn main() { // https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates // https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts // So "repeat" the info from build script (here) to our crate's build environment. - println!("cargo:rustc-env=TARGET={}", var("TARGET").unwrap()); + + let target = var("TARGET").unwrap(); + let out_dir = var("OUT_DIR").unwrap(); + println!("cargo:rustc-env=KANI_EXTERN_DIR={}/../../../../{}/debug/deps", out_dir, target); + println!("cargo:rustc-env=TARGET={}", target); } diff --git a/kani-driver/src/call_cargo.rs b/kani-driver/src/call_cargo.rs index 97bfc9d166db..c6e9d74f9c75 100644 --- a/kani-driver/src/call_cargo.rs +++ b/kani-driver/src/call_cargo.rs @@ -28,6 +28,9 @@ impl KaniSession { let target_dir = self.args.target_dir.as_ref().unwrap_or(&PathBuf::from("target")).clone(); let outdir = target_dir.join(build_target).join("debug/deps"); + let kani_extern_lib_path = + PathBuf::from(std::env!("KANI_EXTERN_DIR")); + let flag_env = { let rustc_args = self.kani_rustc_flags(); crate::util::join_osstring(&rustc_args, " ") @@ -72,8 +75,18 @@ impl KaniSession { Ok(CargoOutputs { outdir: outdir.clone(), - symtabs: glob(&outdir.join("*.symtab.json"))?, - metadata: glob(&outdir.join("*.kani-metadata.json"))?, + symtabs: glob(&outdir.join("*.symtab.json"))? + .into_iter() + .chain( + glob(&kani_extern_lib_path.join("*.symtab.json"))? + ) + .collect(), + metadata: glob(&outdir.join("*.kani-metadata.json"))? + .into_iter() + .chain( + glob(&kani_extern_lib_path.join("*.kani-metadata.json"))? + ) + .collect(), restrictions: self.args.restrict_vtable().then(|| outdir), }) } From 45f36894eda1d7cb46ada74cba2d42a26f1aa827 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Fri, 29 Jul 2022 20:42:37 -0400 Subject: [PATCH 34/80] Added proptest refresh to `kani` and `cargo kani` scripts.. --- scripts/cargo-kani | 1 + scripts/kani | 2 ++ 2 files changed, 3 insertions(+) diff --git a/scripts/cargo-kani b/scripts/cargo-kani index 3561d90690ef..8a33f592807e 100755 --- a/scripts/cargo-kani +++ b/scripts/cargo-kani @@ -19,6 +19,7 @@ then fi KANI_PATH=${KANI_CANDIDATES[0]} +$SCRIPT_DIR/refresh-kani-proptest.sh CARGO_TOML_SAVE_FILE='.save-cargo.toml' if [[ "${PROPTEST+x}" == "1" ]]; then cp Cargo.toml $CARGO_TOML_SAVE_FILE diff --git a/scripts/kani b/scripts/kani index 1ed225b2cb8d..03a5b7968a48 100755 --- a/scripts/kani +++ b/scripts/kani @@ -19,4 +19,6 @@ then fi KANI_PATH=${KANI_CANDIDATES[0]} +$SCRIPT_DIR/refresh-kani-proptest.sh + exec -a kani "${KANI_PATH}" "$@" From 814ace31a93e0093cd3f5f1322fccd080aba88cc Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Fri, 29 Jul 2022 21:05:20 -0400 Subject: [PATCH 35/80] Removed redundant part after PR1420 merged. --- scripts/refresh-kani-proptest.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/scripts/refresh-kani-proptest.sh b/scripts/refresh-kani-proptest.sh index 7d3ebab0646a..0cbe366a1fa0 100755 --- a/scripts/refresh-kani-proptest.sh +++ b/scripts/refresh-kani-proptest.sh @@ -19,10 +19,6 @@ if [ ! -f "$PROPTEST_SYMTAB_PATH" ] || [[ "$PROPTEST_SYMTAB_PATH" -ot "$KANI_BIN ( cd $KANI_REPO_ROOT/library/proptest; cargo kani --only-codegen; - - # TODO: not needed after workspace PR #1421 merges. - cp -r ./target $KANI_REPO_ROOT; - rm -rf ./target ) fi From 6a911502c8fdaddcc81f16c270c398a94e6f64ef Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 1 Aug 2022 20:09:51 -0400 Subject: [PATCH 36/80] Added back floating point support. --- library/proptest/src/arbitrary/primitives.rs | 18 +- library/proptest/src/num.rs | 1389 ++++++------------ 2 files changed, 418 insertions(+), 989 deletions(-) diff --git a/library/proptest/src/arbitrary/primitives.rs b/library/proptest/src/arbitrary/primitives.rs index 04ba45761e28..4404dfde66cd 100644 --- a/library/proptest/src/arbitrary/primitives.rs +++ b/library/proptest/src/arbitrary/primitives.rs @@ -11,11 +11,11 @@ // use crate::bool; // use crate::char; -use crate::num::{ i16, i32, i64, i8, isize, u16, u32, u64, u8, usize}; //todo: implement f32, f64, +use crate::num::{ i16, i32, i64, i8, isize, u16, u32, u64, u8, usize, f32, f64,}; #[cfg(not(target_arch = "wasm32"))] use crate::num::{i128, u128}; -arbitrary!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize); //bool, +arbitrary!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize); //todo bool, #[cfg(not(target_arch = "wasm32"))] arbitrary!(i128, u128); @@ -23,14 +23,12 @@ arbitrary!(i128, u128); // Note that for floating point types we limit the space since a lot of code // isn't prepared for (and is not intended to be) things like NaN and infinity. -//todo: implement f32, f64, - -// arbitrary!(f32, f32::Any; { -// f32::POSITIVE | f32::NEGATIVE | f32::ZERO | f32::SUBNORMAL | f32::NORMAL -// }); -// arbitrary!(f64, f64::Any; { -// f64::POSITIVE | f64::NEGATIVE | f64::ZERO | f64::SUBNORMAL | f64::NORMAL -// }); +arbitrary!(f32, f32::Any; { + f32::POSITIVE | f32::NEGATIVE | f32::ZERO | f32::SUBNORMAL | f32::NORMAL +}); +arbitrary!(f64, f64::Any; { + f64::POSITIVE | f64::NEGATIVE | f64::ZERO | f64::SUBNORMAL | f64::NORMAL +}); // arbitrary!(char, char::CharStrategy<'static>; char::any()); diff --git a/library/proptest/src/num.rs b/library/proptest/src/num.rs index 1007c8c7e98d..7c4d752511a3 100644 --- a/library/proptest/src/num.rs +++ b/library/proptest/src/num.rs @@ -18,14 +18,14 @@ use core::ops::Range; // Below 2 functions are the source of Kani symbolic variables. /// Produce an symbolic value from a range. -pub(crate) fn sample_uniform(run: &mut TestRunner, range: Range) -> X { +pub(crate) fn sample_uniform(run: &mut TestRunner, range: Range) -> X { let value: X = kani::any(); kani::assume(range.contains(&value)); value } /// Produce an symbolic value start and end values. End is inclusive. -pub(crate) fn sample_uniform_incl(run: &mut TestRunner, start: X, end: X) -> X { +pub(crate) fn sample_uniform_incl(run: &mut TestRunner, start: X, end: X) -> X { let value: X = kani::any(); kani::assume(value <= end); kani::assume(value >= start); @@ -252,980 +252,411 @@ unsigned_integer_bin_search!(u64); unsigned_integer_bin_search!(u128); unsigned_integer_bin_search!(usize); -// todo! support float types - -// bitflags! { -// pub(crate) struct FloatTypes: u32 { -// const POSITIVE = 0b0000_0001; -// const NEGATIVE = 0b0000_0010; -// const NORMAL = 0b0000_0100; -// const SUBNORMAL = 0b0000_1000; -// const ZERO = 0b0001_0000; -// const INFINITE = 0b0010_0000; -// const QUIET_NAN = 0b0100_0000; -// const SIGNALING_NAN = 0b1000_0000; -// const ANY = -// Self::POSITIVE.bits | -// Self::NEGATIVE.bits | -// Self::NORMAL.bits | -// Self::SUBNORMAL.bits | -// Self::ZERO.bits | -// Self::INFINITE.bits | -// Self::QUIET_NAN.bits; -// } -// } - -// impl FloatTypes { -// fn normalise(mut self) -> Self { -// if !self.intersects(FloatTypes::POSITIVE | FloatTypes::NEGATIVE) { -// self |= FloatTypes::POSITIVE; -// } - -// if !self.intersects( -// FloatTypes::NORMAL -// | FloatTypes::SUBNORMAL -// | FloatTypes::ZERO -// | FloatTypes::INFINITE -// | FloatTypes::QUIET_NAN -// | FloatTypes::SIGNALING_NAN, -// ) { -// self |= FloatTypes::NORMAL; -// } -// self -// } -// } - -// trait FloatLayout -// where -// Standard: Distribution, -// { -// type Bits: Copy; - -// const SIGN_MASK: Self::Bits; -// const EXP_MASK: Self::Bits; -// const EXP_ZERO: Self::Bits; -// const MANTISSA_MASK: Self::Bits; -// } - -// impl FloatLayout for f32 { -// type Bits = u32; - -// const SIGN_MASK: u32 = 0x8000_0000; -// const EXP_MASK: u32 = 0x7F80_0000; -// const EXP_ZERO: u32 = 0x3F80_0000; -// const MANTISSA_MASK: u32 = 0x007F_FFFF; -// } - -// impl FloatLayout for f64 { -// type Bits = u64; - -// const SIGN_MASK: u64 = 0x8000_0000_0000_0000; -// const EXP_MASK: u64 = 0x7FF0_0000_0000_0000; -// const EXP_ZERO: u64 = 0x3FF0_0000_0000_0000; -// const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF; -// } - -// macro_rules! float_any { -// ($typ:ident) => { -// /// Strategies which produce floating-point values from particular -// /// classes. See the various `Any`-typed constants in this module. -// /// -// /// Note that this usage is fairly advanced and primarily useful to -// /// implementors of algorithms that need to handle wild values in a -// /// particular way. For testing things like graphics processing or game -// /// physics, simply using ranges (e.g., `-1.0..2.0`) will often be more -// /// practical. -// /// -// /// `Any` can be OR'ed to combine multiple classes. For example, -// /// `POSITIVE | INFINITE` will generate arbitrary positive, non-NaN -// /// floats, including positive infinity (but not negative infinity, of -// /// course). -// /// -// /// If neither `POSITIVE` nor `NEGATIVE` has been OR'ed into an `Any` -// /// but a type to be generated requires a sign, `POSITIVE` is assumed. -// /// If no classes are OR'ed into an `Any` (i.e., only `POSITIVE` and/or -// /// `NEGATIVE` are given), `NORMAL` is assumed. -// /// -// /// The various float classes are assigned fixed weights for generation -// /// which are believed to be reasonable for most applications. Roughly: -// /// -// /// - If `POSITIVE | NEGATIVE`, the sign is evenly distributed between -// /// both options. -// /// -// /// - Classes are weighted as follows, in descending order: -// /// `NORMAL` > `ZERO` > `SUBNORMAL` > `INFINITE` > `QUIET_NAN` = -// /// `SIGNALING_NAN`. -// #[derive(Clone, Copy, Debug)] -// #[must_use = "strategies do nothing unless used"] -// pub struct Any(FloatTypes); - -// #[cfg(test)] -// impl Any { -// pub(crate) fn from_bits(bits: u32) -> Self { -// Any(FloatTypes::from_bits_truncate(bits)) -// } - -// pub(crate) fn normal_bits(&self) -> FloatTypes { -// self.0.normalise() -// } -// } - -// impl ops::BitOr for Any { -// type Output = Self; - -// fn bitor(self, rhs: Self) -> Self { -// Any(self.0 | rhs.0) -// } -// } - -// impl ops::BitOrAssign for Any { -// fn bitor_assign(&mut self, rhs: Self) { -// self.0 |= rhs.0 -// } -// } - -// /// Generates positive floats -// /// -// /// By itself, implies the `NORMAL` class, unless another class is -// /// OR'ed in. That is, using `POSITIVE` as a strategy by itself will -// /// generate arbitrary values between the type's `MIN_POSITIVE` and -// /// `MAX`, while `POSITIVE | INFINITE` would only allow generating -// /// positive infinity. -// pub const POSITIVE: Any = Any(FloatTypes::POSITIVE); -// /// Generates negative floats. -// /// -// /// By itself, implies the `NORMAL` class, unless another class is -// /// OR'ed in. That is, using `POSITIVE` as a strategy by itself will -// /// generate arbitrary values between the type's `MIN` and -// /// `-MIN_POSITIVE`, while `NEGATIVE | INFINITE` would only allow -// /// generating positive infinity. -// pub const NEGATIVE: Any = Any(FloatTypes::NEGATIVE); -// /// Generates "normal" floats. -// /// -// /// These are finite values where the first bit of the mantissa is an -// /// implied `1`. When positive, this represents the range -// /// `MIN_POSITIVE` through `MAX`, both inclusive. -// /// -// /// Generated values are uniform over the discrete floating-point -// /// space, which means the numeric distribution is an inverse -// /// exponential step function. For example, values between 1.0 and 2.0 -// /// are generated with the same frequency as values between 2.0 and -// /// 4.0, even though the latter covers twice the numeric range. -// /// -// /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, -// /// `POSITIVE` is implied. -// pub const NORMAL: Any = Any(FloatTypes::NORMAL); -// /// Generates subnormal floats. -// /// -// /// These are finite non-zero values where the first bit of the -// /// mantissa is not an implied zero. When positive, this represents the -// /// range `MIN`, inclusive, through `MIN_POSITIVE`, exclusive. -// /// -// /// Subnormals are generated with a uniform distribution both in terms -// /// of discrete floating-point space and numerically. -// /// -// /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, -// /// `POSITIVE` is implied. -// pub const SUBNORMAL: Any = Any(FloatTypes::SUBNORMAL); -// /// Generates zero-valued floats. -// /// -// /// Note that IEEE floats support both positive and negative zero, so -// /// this class does interact with the sign flags. -// /// -// /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, -// /// `POSITIVE` is implied. -// pub const ZERO: Any = Any(FloatTypes::ZERO); -// /// Generates infinity floats. -// /// -// /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, -// /// `POSITIVE` is implied. -// pub const INFINITE: Any = Any(FloatTypes::INFINITE); -// /// Generates "Quiet NaN" floats. -// /// -// /// Operations on quiet NaNs generally simply propagate the NaN rather -// /// than invoke any exception mechanism. -// /// -// /// The payload of the NaN is uniformly distributed over the possible -// /// values which safe Rust allows, including the sign bit (as -// /// controlled by `POSITIVE` and `NEGATIVE`). -// /// -// /// Note however that in Rust 1.23.0 and earlier, this constitutes only -// /// one particular payload due to apparent issues with particular MIPS -// /// and PA-RISC processors which fail to implement IEEE 754-2008 -// /// correctly. -// /// -// /// On Rust 1.24.0 and later, this does produce arbitrary payloads as -// /// documented. -// /// -// /// On platforms where the CPU and the IEEE standard disagree on the -// /// format of a quiet NaN, values generated conform to the hardware's -// /// expectations. -// pub const QUIET_NAN: Any = Any(FloatTypes::QUIET_NAN); -// /// Generates "Signaling NaN" floats if allowed by the platform. -// /// -// /// On most platforms, signalling NaNs by default behave the same as -// /// quiet NaNs, but it is possible to configure the OS or CPU to raise -// /// an asynchronous exception if an operation is performed on a -// /// signalling NaN. -// /// -// /// In Rust 1.23.0 and earlier, this silently behaves the same as -// /// [`QUIET_NAN`](const.QUIET_NAN.html). -// /// -// /// On platforms where the CPU and the IEEE standard disagree on the -// /// format of a quiet NaN, values generated conform to the hardware's -// /// expectations. -// /// -// /// Note that certain platforms — most notably, x86/AMD64 — allow the -// /// architecture to turn a signalling NaN into a quiet NaN with the -// /// same payload. Whether this happens can depend on what registers the -// /// compiler decides to use to pass the value around, what CPU flags -// /// are set, and what compiler settings are in use. -// pub const SIGNALING_NAN: Any = Any(FloatTypes::SIGNALING_NAN); - -// /// Generates literally arbitrary floating-point values, including -// /// infinities and quiet NaNs (but not signaling NaNs). -// /// -// /// Equivalent to `POSITIVE | NEGATIVE | NORMAL | SUBNORMAL | ZERO | -// /// INFINITE | QUIET_NAN`. -// /// -// /// See [`SIGNALING_NAN`](const.SIGNALING_NAN.html) if you also want to -// /// generate signalling NaNs. This signalling NaNs are not included by -// /// default since in most contexts they either make no difference, or -// /// if the process enabled the relevant CPU mode, result in -// /// hardware-triggered exceptions that usually just abort the process. -// /// -// /// Before proptest 0.4.1, this erroneously generated values in the -// /// range 0.0..1.0. -// pub const ANY: Any = Any(FloatTypes::ANY); - -// impl Strategy for Any { -// type Tree = BinarySearch; -// type Value = $typ; - -// fn new_tree(&self, runner: &mut TestRunner) -> NewTree { -// let flags = self.0.normalise(); -// let sign_mask = if flags.contains(FloatTypes::NEGATIVE) { -// $typ::SIGN_MASK -// } else { -// 0 -// }; -// let sign_or = if flags.contains(FloatTypes::POSITIVE) { -// 0 -// } else { -// $typ::SIGN_MASK -// }; - -// macro_rules! weight { -// ($case:ident, $weight:expr) => { -// if flags.contains(FloatTypes::$case) { -// $weight -// } else { -// 0 -// } -// } -// } - -// // A few CPUs disagree with IEEE about the meaning of the -// // signalling bit. Assume the `NAN` constant is a quiet NaN as -// // interpreted by the hardware and generate values based on -// // that. -// let quiet_or = ::core::$typ::NAN.to_bits() & -// ($typ::EXP_MASK | ($typ::EXP_MASK >> 1)); -// let signaling_or = (quiet_or ^ ($typ::EXP_MASK >> 1)) | -// $typ::EXP_MASK; - -// let (class_mask, class_or, allow_edge_exp, allow_zero_mant) = -// prop_oneof![ -// weight!(NORMAL, 20) => Just( -// ($typ::EXP_MASK | $typ::MANTISSA_MASK, 0, -// false, true)), -// weight!(SUBNORMAL, 3) => Just( -// ($typ::MANTISSA_MASK, 0, true, false)), -// weight!(ZERO, 4) => Just( -// (0, 0, true, true)), -// weight!(INFINITE, 2) => Just( -// (0, $typ::EXP_MASK, true, true)), -// weight!(QUIET_NAN, 1) => Just( -// ($typ::MANTISSA_MASK >> 1, quiet_or, -// true, false)), -// weight!(SIGNALING_NAN, 1) => Just( -// ($typ::MANTISSA_MASK >> 1, signaling_or, -// true, false)), -// ].new_tree(runner)?.current(); - -// let mut generated_value: <$typ as FloatLayout>::Bits = -// runner.rng().gen(); -// generated_value &= sign_mask | class_mask; -// generated_value |= sign_or | class_or; -// let exp = generated_value & $typ::EXP_MASK; -// if !allow_edge_exp && (0 == exp || $typ::EXP_MASK == exp) { -// generated_value &= !$typ::EXP_MASK; -// generated_value |= $typ::EXP_ZERO; -// } -// if !allow_zero_mant && -// 0 == generated_value & $typ::MANTISSA_MASK -// { -// generated_value |= 1; -// } - -// Ok(BinarySearch::new_with_types( -// $typ::from_bits(generated_value), flags)) -// } -// } -// } -// } - -// macro_rules! float_bin_search { -// ($typ:ident) => { -// #[allow(missing_docs)] -// pub mod $typ { -// use core::ops; -// #[cfg(not(feature = "std"))] -// use num_traits::float::FloatCore; - -// use rand::Rng; - -// use super::{FloatLayout, FloatTypes}; -// use crate::strategy::*; -// use crate::test_runner::TestRunner; - -// float_any!($typ); - -// /// Shrinks a float towards 0, using binary search to find boundary -// /// points. -// /// -// /// Non-finite values immediately shrink to 0. -// #[derive(Clone, Copy, Debug)] -// pub struct BinarySearch { -// lo: $typ, -// curr: $typ, -// hi: $typ, -// allowed: FloatTypes, -// } - -// impl BinarySearch { -// /// Creates a new binary searcher starting at the given value. -// pub fn new(start: $typ) -> Self { -// BinarySearch { lo: 0.0, curr: start, hi: start, allowed: FloatTypes::all() } -// } - -// fn new_with_types(start: $typ, allowed: FloatTypes) -> Self { -// BinarySearch { lo: 0.0, curr: start, hi: start, allowed } -// } - -// /// Creates a new binary searcher which will not produce values -// /// on the other side of `lo` or `hi` from `start`. `lo` is -// /// inclusive, `hi` is exclusive. -// fn new_clamped(lo: $typ, start: $typ, hi: $typ) -> Self { -// BinarySearch { -// lo: if start.is_sign_negative() { hi.min(0.0) } else { lo.max(0.0) }, -// hi: start, -// curr: start, -// allowed: FloatTypes::all(), -// } -// } - -// fn current_allowed(&self) -> bool { -// use core::num::FpCategory::*; - -// // Don't reposition if the new value is not allowed -// let class_allowed = match self.curr.classify() { -// Nan => -// // We don't need to inspect whether the -// // signallingness of the NaN matches the allowed -// // set, as we never try to switch between them, -// // instead shrinking to 0. -// { -// self.allowed.contains(FloatTypes::QUIET_NAN) -// || self.allowed.contains(FloatTypes::SIGNALING_NAN) -// } -// Infinite => self.allowed.contains(FloatTypes::INFINITE), -// Zero => self.allowed.contains(FloatTypes::ZERO), -// Subnormal => self.allowed.contains(FloatTypes::SUBNORMAL), -// Normal => self.allowed.contains(FloatTypes::NORMAL), -// }; -// let signum = self.curr.signum(); -// let sign_allowed = if signum > 0.0 { -// self.allowed.contains(FloatTypes::POSITIVE) -// } else if signum < 0.0 { -// self.allowed.contains(FloatTypes::NEGATIVE) -// } else { -// true -// }; - -// class_allowed && sign_allowed -// } - -// fn ensure_acceptable(&mut self) { -// while !self.current_allowed() { -// if !self.complicate_once() { -// panic!( -// "Unable to complicate floating-point back \ -// to acceptable value" -// ); -// } -// } -// } - -// fn reposition(&mut self) -> bool { -// let interval = self.hi - self.lo; -// let interval = if interval.is_finite() { interval } else { 0.0 }; -// let new_mid = self.lo + interval / 2.0; - -// let new_mid = -// if new_mid == self.curr || 0.0 == interval { new_mid } else { self.lo }; - -// if new_mid == self.curr { -// false -// } else { -// self.curr = new_mid; -// true -// } -// } - -// fn done(lo: $typ, hi: $typ) -> bool { -// (lo.abs() > hi.abs() && !hi.is_nan()) || lo.is_nan() -// } - -// fn complicate_once(&mut self) -> bool { -// if BinarySearch::done(self.lo, self.hi) { -// return false; -// } - -// self.lo = if self.curr == self.lo { self.hi } else { self.curr }; - -// self.reposition() -// } -// } -// impl ValueTree for BinarySearch { -// type Value = $typ; - -// fn current(&self) -> $typ { -// self.curr -// } - -// fn simplify(&mut self) -> bool { -// if BinarySearch::done(self.lo, self.hi) { -// return false; -// } - -// self.hi = self.curr; -// if self.reposition() { -// self.ensure_acceptable(); -// true -// } else { -// false -// } -// } - -// fn complicate(&mut self) -> bool { -// if self.complicate_once() { -// self.ensure_acceptable(); -// true -// } else { -// false -// } -// } -// } - -// numeric_api!($typ, 0.0); -// } -// }; -// } - -// float_bin_search!(f32); -// float_bin_search!(f64); - -// #[cfg(test)] -// mod test { -// use crate::strategy::*; -// use crate::test_runner::*; - -// use super::*; - -// #[test] -// fn u8_inclusive_end_included() { -// let mut runner = TestRunner::deterministic(); -// let mut ok = 0; -// for _ in 0..20 { -// let tree = (0..=1).new_tree(&mut runner).unwrap(); -// let test = runner.run_one(tree, |v| { -// prop_assert_eq!(v, 1); -// Ok(()) -// }); -// if test.is_ok() { -// ok += 1; -// } -// } -// assert!(ok > 1, "inclusive end not included."); -// } - -// #[test] -// fn u8_inclusive_to_end_included() { -// let mut runner = TestRunner::deterministic(); -// let mut ok = 0; -// for _ in 0..20 { -// let tree = (..=1u8).new_tree(&mut runner).unwrap(); -// let test = runner.run_one(tree, |v| { -// prop_assert_eq!(v, 1); -// Ok(()) -// }); -// if test.is_ok() { -// ok += 1; -// } -// } -// assert!(ok > 1, "inclusive end not included."); -// } - -// #[test] -// fn i8_binary_search_always_converges() { -// fn assert_converges bool>(start: i8, pass: P) { -// let mut state = i8::BinarySearch::new(start); -// loop { -// if !pass(state.current() as i32) { -// if !state.simplify() { -// break; -// } -// } else { -// if !state.complicate() { -// break; -// } -// } -// } - -// assert!(!pass(state.current() as i32)); -// assert!(pass(state.current() as i32 - 1) || pass(state.current() as i32 + 1)); -// } - -// for start in -128..0 { -// for target in start + 1..1 { -// assert_converges(start as i8, |v| v > target); -// } -// } - -// for start in 0..128 { -// for target in 0..start { -// assert_converges(start as i8, |v| v < target); -// } -// } -// } - -// #[test] -// fn u8_binary_search_always_converges() { -// fn assert_converges bool>(start: u8, pass: P) { -// let mut state = u8::BinarySearch::new(start); -// loop { -// if !pass(state.current() as u32) { -// if !state.simplify() { -// break; -// } -// } else { -// if !state.complicate() { -// break; -// } -// } -// } - -// assert!(!pass(state.current() as u32)); -// assert!(pass(state.current() as u32 - 1)); -// } - -// for start in 0..255 { -// for target in 0..start { -// assert_converges(start as u8, |v| v <= target); -// } -// } -// } - -// #[test] -// fn signed_integer_range_including_zero_converges_to_zero() { -// let mut runner = TestRunner::default(); -// for _ in 0..100 { -// let mut state = (-42i32..64i32).new_tree(&mut runner).unwrap(); -// let init_value = state.current(); -// assert!(init_value >= -42 && init_value < 64); - -// while state.simplify() { -// let v = state.current(); -// assert!(v >= -42 && v < 64); -// } - -// assert_eq!(0, state.current()); -// } -// } - -// #[test] -// fn negative_integer_range_stays_in_bounds() { -// let mut runner = TestRunner::default(); -// for _ in 0..100 { -// let mut state = (..-42i32).new_tree(&mut runner).unwrap(); -// let init_value = state.current(); -// assert!(init_value < -42); - -// while state.simplify() { -// assert!(state.current() < -42, "Violated bounds: {}", state.current()); -// } - -// assert_eq!(-43, state.current()); -// } -// } - -// #[test] -// fn positive_signed_integer_range_stays_in_bounds() { -// let mut runner = TestRunner::default(); -// for _ in 0..100 { -// let mut state = (42i32..).new_tree(&mut runner).unwrap(); -// let init_value = state.current(); -// assert!(init_value >= 42); - -// while state.simplify() { -// assert!(state.current() >= 42, "Violated bounds: {}", state.current()); -// } - -// assert_eq!(42, state.current()); -// } -// } - -// #[test] -// fn unsigned_integer_range_stays_in_bounds() { -// let mut runner = TestRunner::default(); -// for _ in 0..100 { -// let mut state = (42u32..56u32).new_tree(&mut runner).unwrap(); -// let init_value = state.current(); -// assert!(init_value >= 42 && init_value < 56); - -// while state.simplify() { -// assert!(state.current() >= 42, "Violated bounds: {}", state.current()); -// } - -// assert_eq!(42, state.current()); -// } -// } - -// mod contract_sanity { -// macro_rules! contract_sanity { -// ($t:tt) => { -// mod $t { -// use crate::strategy::check_strategy_sanity; - -// const FOURTY_TWO: $t = 42 as $t; -// const FIFTY_SIX: $t = 56 as $t; - -// #[test] -// fn range() { -// check_strategy_sanity(FOURTY_TWO..FIFTY_SIX, None); -// } - -// #[test] -// fn range_inclusive() { -// check_strategy_sanity(FOURTY_TWO..=FIFTY_SIX, None); -// } - -// #[test] -// fn range_to() { -// check_strategy_sanity(..FIFTY_SIX, None); -// } - -// #[test] -// fn range_to_inclusive() { -// check_strategy_sanity(..=FIFTY_SIX, None); -// } - -// #[test] -// fn range_from() { -// check_strategy_sanity(FOURTY_TWO.., None); -// } -// } -// }; -// } -// contract_sanity!(u8); -// contract_sanity!(i8); -// contract_sanity!(u16); -// contract_sanity!(i16); -// contract_sanity!(u32); -// contract_sanity!(i32); -// contract_sanity!(u64); -// contract_sanity!(i64); -// contract_sanity!(usize); -// contract_sanity!(isize); -// contract_sanity!(f32); -// contract_sanity!(f64); -// } - -// #[test] -// fn unsigned_integer_binsearch_simplify_complicate_contract_upheld() { -// check_strategy_sanity(0u32..1000u32, None); -// check_strategy_sanity(0u32..1u32, None); -// } - -// #[test] -// fn signed_integer_binsearch_simplify_complicate_contract_upheld() { -// check_strategy_sanity(0i32..1000i32, None); -// check_strategy_sanity(0i32..1i32, None); -// } - -// #[test] -// fn positive_float_simplifies_to_zero() { -// let mut runner = TestRunner::default(); -// let mut value = (0.0f64..2.0).new_tree(&mut runner).unwrap(); - -// while value.simplify() {} - -// assert_eq!(0.0, value.current()); -// } - -// #[test] -// fn positive_float_simplifies_to_base() { -// let mut runner = TestRunner::default(); -// let mut value = (1.0f64..2.0).new_tree(&mut runner).unwrap(); - -// while value.simplify() {} - -// assert_eq!(1.0, value.current()); -// } - -// #[test] -// fn negative_float_simplifies_to_zero() { -// let mut runner = TestRunner::default(); -// let mut value = (-2.0f64..0.0).new_tree(&mut runner).unwrap(); - -// while value.simplify() {} - -// assert_eq!(0.0, value.current()); -// } - -// #[test] -// fn positive_float_complicates_to_original() { -// let mut runner = TestRunner::default(); -// let mut value = (1.0f64..2.0).new_tree(&mut runner).unwrap(); -// let orig = value.current(); - -// assert!(value.simplify()); -// while value.complicate() {} - -// assert_eq!(orig, value.current()); -// } - -// #[test] -// fn positive_infinity_simplifies_directly_to_zero() { -// let mut value = f64::BinarySearch::new(::std::f64::INFINITY); - -// assert!(value.simplify()); -// assert_eq!(0.0, value.current()); -// assert!(value.complicate()); -// assert_eq!(::std::f64::INFINITY, value.current()); -// assert!(!value.clone().complicate()); -// assert!(!value.clone().simplify()); -// } - -// #[test] -// fn negative_infinity_simplifies_directly_to_zero() { -// let mut value = f64::BinarySearch::new(::std::f64::NEG_INFINITY); - -// assert!(value.simplify()); -// assert_eq!(0.0, value.current()); -// assert!(value.complicate()); -// assert_eq!(::std::f64::NEG_INFINITY, value.current()); -// assert!(!value.clone().complicate()); -// assert!(!value.clone().simplify()); -// } - -// #[test] -// fn nan_simplifies_directly_to_zero() { -// let mut value = f64::BinarySearch::new(::std::f64::NAN); - -// assert!(value.simplify()); -// assert_eq!(0.0, value.current()); -// assert!(value.complicate()); -// assert!(value.current().is_nan()); -// assert!(!value.clone().complicate()); -// assert!(!value.clone().simplify()); -// } - -// #[test] -// fn float_simplifies_to_smallest_normal() { -// let mut runner = TestRunner::default(); -// let mut value = (::std::f64::MIN_POSITIVE..2.0).new_tree(&mut runner).unwrap(); - -// while value.simplify() {} - -// assert_eq!(::std::f64::MIN_POSITIVE, value.current()); -// } - -// macro_rules! float_generation_test_body { -// ($strategy:ident, $typ:ident) => { -// use std::num::FpCategory; - -// let strategy = $strategy; -// let bits = strategy.normal_bits(); - -// let mut seen_positive = 0; -// let mut seen_negative = 0; -// let mut seen_normal = 0; -// let mut seen_subnormal = 0; -// let mut seen_zero = 0; -// let mut seen_infinite = 0; -// let mut seen_quiet_nan = 0; -// let mut seen_signaling_nan = 0; -// let mut runner = TestRunner::deterministic(); - -// // Check whether this version of Rust honours the NaN payload in -// // from_bits -// let fidelity_1 = f32::from_bits(0x7F80_0001).to_bits(); -// let fidelity_2 = f32::from_bits(0xFF80_0001).to_bits(); -// let nan_fidelity = fidelity_1 != fidelity_2; - -// for _ in 0..1024 { -// let mut tree = strategy.new_tree(&mut runner).unwrap(); -// let mut increment = 1; - -// loop { -// let value = tree.current(); - -// let sign = value.signum(); // So we correctly handle -0 -// if sign < 0.0 { -// prop_assert!(bits.contains(FloatTypes::NEGATIVE)); -// seen_negative += increment; -// } else if sign > 0.0 { -// // i.e., not NaN -// prop_assert!(bits.contains(FloatTypes::POSITIVE)); -// seen_positive += increment; -// } - -// match value.classify() { -// FpCategory::Nan if nan_fidelity => { -// let raw = value.to_bits(); -// let is_negative = raw << 1 >> 1 != raw; -// if is_negative { -// prop_assert!(bits.contains(FloatTypes::NEGATIVE)); -// seen_negative += increment; -// } else { -// prop_assert!(bits.contains(FloatTypes::POSITIVE)); -// seen_positive += increment; -// } - -// let is_quiet = raw & ($typ::EXP_MASK >> 1) -// == ::std::$typ::NAN.to_bits() & ($typ::EXP_MASK >> 1); -// if is_quiet { -// // x86/AMD64 turn signalling NaNs into quiet -// // NaNs quite aggressively depending on what -// // registers LLVM decides to use to pass the -// // value around, so accept either case here. -// prop_assert!( -// bits.contains(FloatTypes::QUIET_NAN) -// || bits.contains(FloatTypes::SIGNALING_NAN) -// ); -// seen_quiet_nan += increment; -// seen_signaling_nan += increment; -// } else { -// prop_assert!(bits.contains(FloatTypes::SIGNALING_NAN)); -// seen_signaling_nan += increment; -// } -// } - -// FpCategory::Nan => { -// // Since safe Rust doesn't currently allow -// // generating any NaN other than one particular -// // payload, don't check the sign or signallingness -// // and consider this to be both signs and -// // signallingness for counting purposes. -// seen_positive += increment; -// seen_negative += increment; -// seen_quiet_nan += increment; -// seen_signaling_nan += increment; -// prop_assert!( -// bits.contains(FloatTypes::QUIET_NAN) -// || bits.contains(FloatTypes::SIGNALING_NAN) -// ); -// } -// FpCategory::Infinite => { -// prop_assert!(bits.contains(FloatTypes::INFINITE)); -// seen_infinite += increment; -// } -// FpCategory::Zero => { -// prop_assert!(bits.contains(FloatTypes::ZERO)); -// seen_zero += increment; -// } -// FpCategory::Subnormal => { -// prop_assert!(bits.contains(FloatTypes::SUBNORMAL)); -// seen_subnormal += increment; -// } -// FpCategory::Normal => { -// prop_assert!(bits.contains(FloatTypes::NORMAL)); -// seen_normal += increment; -// } -// } - -// // Don't count simplified values towards the counts -// increment = 0; -// if !tree.simplify() { -// break; -// } -// } -// } - -// if bits.contains(FloatTypes::POSITIVE) { -// prop_assert!(seen_positive > 200); -// } -// if bits.contains(FloatTypes::NEGATIVE) { -// prop_assert!(seen_negative > 200); -// } -// if bits.contains(FloatTypes::NORMAL) { -// prop_assert!(seen_normal > 100); -// } -// if bits.contains(FloatTypes::SUBNORMAL) { -// prop_assert!(seen_subnormal > 5); -// } -// if bits.contains(FloatTypes::ZERO) { -// prop_assert!(seen_zero > 5); -// } -// if bits.contains(FloatTypes::INFINITE) { -// prop_assert!(seen_infinite > 0); -// } -// if bits.contains(FloatTypes::QUIET_NAN) { -// prop_assert!(seen_quiet_nan > 0); -// } -// if bits.contains(FloatTypes::SIGNALING_NAN) { -// prop_assert!(seen_signaling_nan > 0); -// } -// }; -// } - -// proptest! { -// #![proptest_config(crate::test_runner::Config::with_cases(1024))] - -// #[test] -// fn f32_any_generates_desired_values( -// strategy in crate::bits::u32::ANY.prop_map(f32::Any::from_bits) -// ) { -// float_generation_test_body!(strategy, f32); -// } - -// #[test] -// fn f32_any_sanity( -// strategy in crate::bits::u32::ANY.prop_map(f32::Any::from_bits) -// ) { -// check_strategy_sanity(strategy, Some(CheckStrategySanityOptions { -// strict_complicate_after_simplify: false, -// .. CheckStrategySanityOptions::default() -// })); -// } - -// #[test] -// fn f64_any_generates_desired_values( -// strategy in crate::bits::u32::ANY.prop_map(f64::Any::from_bits) -// ) { -// float_generation_test_body!(strategy, f64); -// } - -// #[test] -// fn f64_any_sanity( -// strategy in crate::bits::u32::ANY.prop_map(f64::Any::from_bits) -// ) { -// check_strategy_sanity(strategy, Some(CheckStrategySanityOptions { -// strict_complicate_after_simplify: false, -// .. CheckStrategySanityOptions::default() -// })); -// } -// } -// } +#[derive(Clone, Copy, Debug)] +pub(crate) struct FloatTypes(u32); + +impl std::ops::BitOr for FloatTypes { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self { + Self(self.0 | rhs.0) + } +} + +impl std::ops::BitOrAssign for FloatTypes { + fn bitor_assign(&mut self, rhs: Self) { + self.0 |= rhs.0 + } +} + +impl FloatTypes { + const POSITIVE : FloatTypes = FloatTypes(0b0000_0001); + const NEGATIVE : FloatTypes = FloatTypes(0b0000_0010); + const NORMAL : FloatTypes = FloatTypes(0b0000_0100); + const SUBNORMAL : FloatTypes = FloatTypes(0b0000_1000); + const ZERO : FloatTypes = FloatTypes(0b0001_0000); + const INFINITE : FloatTypes = FloatTypes(0b0010_0000); + const QUIET_NAN : FloatTypes = FloatTypes(0b0100_0000); + const SIGNALING_NAN : FloatTypes = FloatTypes(0b1000_0000); + const ANY : FloatTypes = FloatTypes(0b1111_1111); + + fn intersects(&self , other: Self) -> bool { + let intersection = self.0 & other.0; + intersection != 0 + } + + fn contains(&self , other: Self) -> bool { + let intersection = self.0 & other.0; + intersection == other.0 + } + + fn all() -> Self { + Self::ANY + } + + fn normalise(mut self) -> Self { + if !self.intersects(FloatTypes::POSITIVE | FloatTypes::NEGATIVE) { + self |= FloatTypes::POSITIVE; + } + + if !self.intersects( + FloatTypes::NORMAL + | FloatTypes::SUBNORMAL + | FloatTypes::ZERO + | FloatTypes::INFINITE + | FloatTypes::QUIET_NAN + | FloatTypes::SIGNALING_NAN, + ) { + self |= FloatTypes::NORMAL; + } + self + } +} + +trait FloatLayout +{ + type Bits: Copy; + + const SIGN_MASK: Self::Bits; + const EXP_MASK: Self::Bits; + const EXP_ZERO: Self::Bits; + const MANTISSA_MASK: Self::Bits; +} + +impl FloatLayout for f32 { + type Bits = u32; + + const SIGN_MASK: u32 = 0x8000_0000; + const EXP_MASK: u32 = 0x7F80_0000; + const EXP_ZERO: u32 = 0x3F80_0000; + const MANTISSA_MASK: u32 = 0x007F_FFFF; +} + +impl FloatLayout for f64 { + type Bits = u64; + + const SIGN_MASK: u64 = 0x8000_0000_0000_0000; + const EXP_MASK: u64 = 0x7FF0_0000_0000_0000; + const EXP_ZERO: u64 = 0x3FF0_0000_0000_0000; + const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF; +} + +macro_rules! float_any { + ($typ:ident) => { + /// Strategies which produce floating-point values from particular + /// classes. See the various `Any`-typed constants in this module. + /// + /// Note that this usage is fairly advanced and primarily useful to + /// implementors of algorithms that need to handle wild values in a + /// particular way. For testing things like graphics processing or game + /// physics, simply using ranges (e.g., `-1.0..2.0`) will often be more + /// practical. + /// + /// `Any` can be OR'ed to combine multiple classes. For example, + /// `POSITIVE | INFINITE` will generate arbitrary positive, non-NaN + /// floats, including positive infinity (but not negative infinity, of + /// course). + /// + /// If neither `POSITIVE` nor `NEGATIVE` has been OR'ed into an `Any` + /// but a type to be generated requires a sign, `POSITIVE` is assumed. + /// If no classes are OR'ed into an `Any` (i.e., only `POSITIVE` and/or + /// `NEGATIVE` are given), `NORMAL` is assumed. + /// + /// The various float classes are assigned fixed weights for generation + /// which are believed to be reasonable for most applications. Roughly: + /// + /// - If `POSITIVE | NEGATIVE`, the sign is evenly distributed between + /// both options. + /// + /// - Classes are weighted as follows, in descending order: + /// `NORMAL` > `ZERO` > `SUBNORMAL` > `INFINITE` > `QUIET_NAN` = + /// `SIGNALING_NAN`. + #[derive(Clone, Copy, Debug)] + #[must_use = "strategies do nothing unless used"] + pub struct Any(FloatTypes); + + impl ops::BitOr for Any { + type Output = Self; + + fn bitor(self, rhs: Self) -> Self { + Any(self.0 | rhs.0) + } + } + + impl ops::BitOrAssign for Any { + fn bitor_assign(&mut self, rhs: Self) { + self.0 |= rhs.0 + } + } + + /// Generates positive floats + /// + /// By itself, implies the `NORMAL` class, unless another class is + /// OR'ed in. That is, using `POSITIVE` as a strategy by itself will + /// generate arbitrary values between the type's `MIN_POSITIVE` and + /// `MAX`, while `POSITIVE | INFINITE` would only allow generating + /// positive infinity. + pub const POSITIVE: Any = Any(FloatTypes::POSITIVE); + /// Generates negative floats. + /// + /// By itself, implies the `NORMAL` class, unless another class is + /// OR'ed in. That is, using `POSITIVE` as a strategy by itself will + /// generate arbitrary values between the type's `MIN` and + /// `-MIN_POSITIVE`, while `NEGATIVE | INFINITE` would only allow + /// generating positive infinity. + pub const NEGATIVE: Any = Any(FloatTypes::NEGATIVE); + /// Generates "normal" floats. + /// + /// These are finite values where the first bit of the mantissa is an + /// implied `1`. When positive, this represents the range + /// `MIN_POSITIVE` through `MAX`, both inclusive. + /// + /// Generated values are uniform over the discrete floating-point + /// space, which means the numeric distribution is an inverse + /// exponential step function. For example, values between 1.0 and 2.0 + /// are generated with the same frequency as values between 2.0 and + /// 4.0, even though the latter covers twice the numeric range. + /// + /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, + /// `POSITIVE` is implied. + pub const NORMAL: Any = Any(FloatTypes::NORMAL); + /// Generates subnormal floats. + /// + /// These are finite non-zero values where the first bit of the + /// mantissa is not an implied zero. When positive, this represents the + /// range `MIN`, inclusive, through `MIN_POSITIVE`, exclusive. + /// + /// Subnormals are generated with a uniform distribution both in terms + /// of discrete floating-point space and numerically. + /// + /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, + /// `POSITIVE` is implied. + pub const SUBNORMAL: Any = Any(FloatTypes::SUBNORMAL); + /// Generates zero-valued floats. + /// + /// Note that IEEE floats support both positive and negative zero, so + /// this class does interact with the sign flags. + /// + /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, + /// `POSITIVE` is implied. + pub const ZERO: Any = Any(FloatTypes::ZERO); + /// Generates infinity floats. + /// + /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, + /// `POSITIVE` is implied. + pub const INFINITE: Any = Any(FloatTypes::INFINITE); + /// Generates "Quiet NaN" floats. + /// + /// Operations on quiet NaNs generally simply propagate the NaN rather + /// than invoke any exception mechanism. + /// + /// The payload of the NaN is uniformly distributed over the possible + /// values which safe Rust allows, including the sign bit (as + /// controlled by `POSITIVE` and `NEGATIVE`). + /// + /// Note however that in Rust 1.23.0 and earlier, this constitutes only + /// one particular payload due to apparent issues with particular MIPS + /// and PA-RISC processors which fail to implement IEEE 754-2008 + /// correctly. + /// + /// On Rust 1.24.0 and later, this does produce arbitrary payloads as + /// documented. + /// + /// On platforms where the CPU and the IEEE standard disagree on the + /// format of a quiet NaN, values generated conform to the hardware's + /// expectations. + pub const QUIET_NAN: Any = Any(FloatTypes::QUIET_NAN); + /// Generates "Signaling NaN" floats if allowed by the platform. + /// + /// On most platforms, signalling NaNs by default behave the same as + /// quiet NaNs, but it is possible to configure the OS or CPU to raise + /// an asynchronous exception if an operation is performed on a + /// signalling NaN. + /// + /// In Rust 1.23.0 and earlier, this silently behaves the same as + /// [`QUIET_NAN`](const.QUIET_NAN.html). + /// + /// On platforms where the CPU and the IEEE standard disagree on the + /// format of a quiet NaN, values generated conform to the hardware's + /// expectations. + /// + /// Note that certain platforms — most notably, x86/AMD64 — allow the + /// architecture to turn a signalling NaN into a quiet NaN with the + /// same payload. Whether this happens can depend on what registers the + /// compiler decides to use to pass the value around, what CPU flags + /// are set, and what compiler settings are in use. + pub const SIGNALING_NAN: Any = Any(FloatTypes::SIGNALING_NAN); + + /// Generates literally arbitrary floating-point values, including + /// infinities and quiet NaNs (but not signaling NaNs). + /// + /// Equivalent to `POSITIVE | NEGATIVE | NORMAL | SUBNORMAL | ZERO | + /// INFINITE | QUIET_NAN`. + /// + /// See [`SIGNALING_NAN`](const.SIGNALING_NAN.html) if you also want to + /// generate signalling NaNs. This signalling NaNs are not included by + /// default since in most contexts they either make no difference, or + /// if the process enabled the relevant CPU mode, result in + /// hardware-triggered exceptions that usually just abort the process. + /// + /// Before proptest 0.4.1, this erroneously generated values in the + /// range 0.0..1.0. + pub const ANY: Any = Any(FloatTypes::ANY); + + impl Strategy for Any { + type Tree = BinarySearch; + type Value = $typ; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + let flags = self.0.normalise(); + let sign_mask = if flags.contains(FloatTypes::NEGATIVE) { + $typ::SIGN_MASK + } else { + 0 + }; + let sign_or = if flags.contains(FloatTypes::POSITIVE) { + 0 + } else { + $typ::SIGN_MASK + }; + + // A few CPUs disagree with IEEE about the meaning of the + // signalling bit. Assume the `NAN` constant is a quiet NaN as + // interpreted by the hardware and generate values based on + // that. + let quiet_or = ::core::$typ::NAN.to_bits() & + ($typ::EXP_MASK | ($typ::EXP_MASK >> 1)); + let signaling_or = (quiet_or ^ ($typ::EXP_MASK >> 1)) | + $typ::EXP_MASK; + + let (class_mask, class_or, allow_edge_exp, allow_zero_mant) = + || -> (_, _, bool, bool) { + let can_match_after = + flags.contains(FloatTypes::SUBNORMAL) || + flags.contains(FloatTypes::ZERO) || + flags.contains(FloatTypes::INFINITE) || + flags.contains(FloatTypes::QUIET_NAN) || + flags.contains(FloatTypes::SIGNALING_NAN); + if flags.contains(FloatTypes::NORMAL) && (!can_match_after || kani::any()) { + return ($typ::EXP_MASK | $typ::MANTISSA_MASK, 0, false, true); + } + + let can_match_after = + flags.contains(FloatTypes::ZERO) || + flags.contains(FloatTypes::INFINITE) || + flags.contains(FloatTypes::QUIET_NAN) || + flags.contains(FloatTypes::SIGNALING_NAN); + if flags.contains(FloatTypes::SUBNORMAL) && (!can_match_after || kani::any()) { + return ($typ::MANTISSA_MASK, 0, true, false) + } + + let can_match_after = + flags.contains(FloatTypes::INFINITE) || + flags.contains(FloatTypes::QUIET_NAN) || + flags.contains(FloatTypes::SIGNALING_NAN); + if flags.contains(FloatTypes::ZERO) && (!can_match_after || kani::any()) { + return (0, 0, true, true); + } + + let can_match_after = + flags.contains(FloatTypes::QUIET_NAN) || + flags.contains(FloatTypes::SIGNALING_NAN); + if flags.contains(FloatTypes::INFINITE) && (!can_match_after || kani::any()) { + return (0, $typ::EXP_MASK, true, true); + } + + let can_match_after = flags.contains(FloatTypes::SIGNALING_NAN); + if flags.contains(FloatTypes::QUIET_NAN) && (!can_match_after || kani::any()) { + return ($typ::MANTISSA_MASK >> 1, quiet_or, true, false); + } + + if flags.contains(FloatTypes::SIGNALING_NAN) { + return ($typ::MANTISSA_MASK >> 1, signaling_or,true, false); + } + + panic!("This should not be reachable. This is a bug in Kani or Kani's proptest library") + }(); + + let mut generated_value: <$typ as FloatLayout>::Bits = kani::any(); + generated_value &= sign_mask | class_mask; + generated_value |= sign_or | class_or; + let exp = generated_value & $typ::EXP_MASK; + if !allow_edge_exp && (0 == exp || $typ::EXP_MASK == exp) { + generated_value &= !$typ::EXP_MASK; + generated_value |= $typ::EXP_ZERO; + } + if !allow_zero_mant && + 0 == generated_value & $typ::MANTISSA_MASK + { + generated_value |= 1; + } + + Ok(BinarySearch::new_with_types( + $typ::from_bits(generated_value), flags)) + } + } + } +} + +macro_rules! float_bin_search { + ($typ:ident) => { + #[allow(missing_docs)] + pub mod $typ { + use core::ops; + use super::{FloatLayout, FloatTypes}; + use crate::strategy::*; + use crate::test_runner::TestRunner; + + float_any!($typ); + + /// Binary Search Strategy Modified for Kani. It does not + /// perform any random search, but rather returns a + /// symbolic current value. + #[derive(Clone, Copy, Debug)] + pub struct BinarySearch { + curr: $typ, + } + + impl BinarySearch { + /// Creates a new binary searcher starting at the given value. + pub fn new(start: $typ) -> Self { + BinarySearch { curr: start, } + } + + fn new_with_types(start: $typ, _: FloatTypes) -> Self { + BinarySearch { curr: start, } + } + + /// Creates a new binary searcher which will not produce values + /// on the other side of `lo` or `hi` from `start`. `lo` is + /// inclusive, `hi` is exclusive. + fn new_clamped(_: $typ, start: $typ, _: $typ) -> Self { + BinarySearch { + curr: start, + } + } + } + + impl ValueTree for BinarySearch { + type Value = $typ; + + fn current(&self) -> $typ { + self.curr + } + + fn simplify(&mut self) -> bool { + false + } + + fn complicate(&mut self) -> bool { + false + } + } + + numeric_api!($typ, 0.0); + } + }; +} + +float_bin_search!(f32); +float_bin_search!(f64); From cad9f1d23e1e1d1c6528cdb9818fae57c3b71a58 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 1 Aug 2022 20:22:53 -0400 Subject: [PATCH 37/80] Cleaned up warnings and clippy complaints. --- library/proptest/Cargo.toml | 3 ++- library/proptest/src/lib.rs | 5 ++-- library/proptest/src/num.rs | 30 +++++++--------------- library/proptest/src/strategy/traits.rs | 2 +- library/proptest/src/test_runner/runner.rs | 2 +- 5 files changed, 16 insertions(+), 26 deletions(-) diff --git a/library/proptest/Cargo.toml b/library/proptest/Cargo.toml index 545fd71ff6a8..867e9c6736bb 100644 --- a/library/proptest/Cargo.toml +++ b/library/proptest/Cargo.toml @@ -2,8 +2,9 @@ name = "proptest" version = "0.1.0" edition = "2021" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [target.'cfg(not(kani))'.dependencies] -kani = { path = "../kani" } \ No newline at end of file +kani = { path = "../kani" } diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index 9a4c7443a256..8afe738ad491 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -18,9 +18,10 @@ #![deny(missing_docs, bare_trait_objects)] // #![no_std] #![cfg_attr(feature = "cargo-clippy", allow( - doc_markdown, + clippy::doc_markdown, // We have a lot of these lints for associated types... And we don't care. - type_complexity + clippy::type_complexity, + clippy::needless_doctest_main ))] #![cfg_attr( feature = "unstable", diff --git a/library/proptest/src/num.rs b/library/proptest/src/num.rs index 7c4d752511a3..cecf5adea478 100644 --- a/library/proptest/src/num.rs +++ b/library/proptest/src/num.rs @@ -18,14 +18,14 @@ use core::ops::Range; // Below 2 functions are the source of Kani symbolic variables. /// Produce an symbolic value from a range. -pub(crate) fn sample_uniform(run: &mut TestRunner, range: Range) -> X { +pub(crate) fn sample_uniform(_: &mut TestRunner, range: Range) -> X { let value: X = kani::any(); kani::assume(range.contains(&value)); value } /// Produce an symbolic value start and end values. End is inclusive. -pub(crate) fn sample_uniform_incl(run: &mut TestRunner, start: X, end: X) -> X { +pub(crate) fn sample_uniform_incl(_: &mut TestRunner, start: X, end: X) -> X { let value: X = kani::any(); kani::assume(value <= end); kani::assume(value >= start); @@ -46,7 +46,7 @@ macro_rules! int_any { type Tree = BinarySearch; type Value = $typ; - fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + fn new_tree(&self, _: &mut TestRunner) -> NewTree { Ok(BinarySearch::new(kani::any::<$typ>())) } } @@ -136,25 +136,19 @@ macro_rules! signed_integer_bin_search { /// boundary points. #[derive(Clone, Copy, Debug)] pub struct BinarySearch { - lo: $typ, // todo: these are not necessary, purge. curr: $typ, - hi: $typ, // todo: these are not necessary, purge. } impl BinarySearch { /// Creates a new binary searcher starting at the given value. pub fn new(start: $typ) -> Self { - BinarySearch { lo: 0, curr: start, hi: start } + BinarySearch { curr: start, } } /// Creates a new binary searcher which will not produce values /// on the other side of `lo` or `hi` from `start`. `lo` is /// inclusive, `hi` is exclusive. - fn new_clamped(lo: $typ, start: $typ, hi: $typ) -> Self { - use core::cmp::{max, min}; - + fn new_clamped(_: $typ, start: $typ, _: $typ) -> Self { BinarySearch { - lo: if start < 0 { min(0, hi - 1) } else { max(0, lo) }, - hi: start, curr: start, } } @@ -194,20 +188,18 @@ macro_rules! unsigned_integer_bin_search { /// boundary points. #[derive(Clone, Copy, Debug)] pub struct BinarySearch { - lo: $typ, // todo: these are not necessary, purge. curr: $typ, - hi: $typ, // todo: these are not necessary, purge. } impl BinarySearch { /// Creates a new binary searcher starting at the given value. pub fn new(start: $typ) -> Self { - BinarySearch { lo: 0, curr: start, hi: start } + BinarySearch { curr: start, } } /// Creates a new binary searcher which will not search below /// the given `lo` value. - fn new_clamped(lo: $typ, start: $typ, _hi: $typ) -> Self { - BinarySearch { lo: lo, curr: start, hi: start } + fn new_clamped(_: $typ, start: $typ, _: $typ) -> Self { + BinarySearch { curr: start, } } /// Creates a new binary searcher which will not search below @@ -290,10 +282,6 @@ impl FloatTypes { intersection == other.0 } - fn all() -> Self { - Self::ANY - } - fn normalise(mut self) -> Self { if !self.intersects(FloatTypes::POSITIVE | FloatTypes::NEGATIVE) { self |= FloatTypes::POSITIVE; @@ -507,7 +495,7 @@ macro_rules! float_any { type Tree = BinarySearch; type Value = $typ; - fn new_tree(&self, runner: &mut TestRunner) -> NewTree { + fn new_tree(&self, _: &mut TestRunner) -> NewTree { let flags = self.0.normalise(); let sign_mask = if flags.contains(FloatTypes::NEGATIVE) { $typ::SIGN_MASK diff --git a/library/proptest/src/strategy/traits.rs b/library/proptest/src/strategy/traits.rs index 0b582437df78..bb2d5b673657 100644 --- a/library/proptest/src/strategy/traits.rs +++ b/library/proptest/src/strategy/traits.rs @@ -822,7 +822,7 @@ where } } } - let options = options.unwrap_or_else(CheckStrategySanityOptions::default); + let options: CheckStrategySanityOptions = options.unwrap_or_default(); let mut config = Config::default(); if options.error_on_local_rejects { config.max_local_rejects = 0; diff --git a/library/proptest/src/test_runner/runner.rs b/library/proptest/src/test_runner/runner.rs index d07319972170..5ba7cfb0a9c1 100644 --- a/library/proptest/src/test_runner/runner.rs +++ b/library/proptest/src/test_runner/runner.rs @@ -23,7 +23,7 @@ impl TestRunner { pub fn default() -> Self { Self {} } /// Run the test function with a Kani symbolic value given a test function that takes that type. - pub fn run_kani(strategy: S, test_fn: impl Fn(S::Value) -> ()) { + pub fn run_kani(strategy: S, test_fn: impl Fn(S::Value)) { let mut runner = Self::new(Config::default()); let tree = strategy.new_tree(&mut runner).unwrap(); test_fn(tree.current()); From 4f6dd5967a5532209770b997cdfeb998e79d0d29 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 1 Aug 2022 21:48:24 -0400 Subject: [PATCH 38/80] Added support for booleans. --- library/proptest/src/arbitrary/primitives.rs | 4 +- library/proptest/src/bool.rs | 86 ++++++++++++++++++++ library/proptest/src/lib.rs | 2 +- 3 files changed, 89 insertions(+), 3 deletions(-) create mode 100644 library/proptest/src/bool.rs diff --git a/library/proptest/src/arbitrary/primitives.rs b/library/proptest/src/arbitrary/primitives.rs index 4404dfde66cd..fb0647b2ec00 100644 --- a/library/proptest/src/arbitrary/primitives.rs +++ b/library/proptest/src/arbitrary/primitives.rs @@ -9,13 +9,13 @@ //! Arbitrary implementations for primitive types. -// use crate::bool; +use crate::bool; // use crate::char; use crate::num::{ i16, i32, i64, i8, isize, u16, u32, u64, u8, usize, f32, f64,}; #[cfg(not(target_arch = "wasm32"))] use crate::num::{i128, u128}; -arbitrary!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize); //todo bool, +arbitrary!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, bool); #[cfg(not(target_arch = "wasm32"))] arbitrary!(i128, u128); diff --git a/library/proptest/src/bool.rs b/library/proptest/src/bool.rs new file mode 100644 index 000000000000..30828bdd3a80 --- /dev/null +++ b/library/proptest/src/bool.rs @@ -0,0 +1,86 @@ +//- +// Copyright 2017 Jason Lingle +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Strategies for generating `bool` values. + +use crate::strategy::*; +use crate::test_runner::*; + +/// The type of the `ANY` constant. +#[derive(Clone, Copy, Debug)] +pub struct Any(()); + +/// Generates boolean values by picking `true` or `false` uniformly. +/// +/// Shrinks `true` to `false`. +pub const ANY: Any = Any(()); + +impl Strategy for Any { + type Tree = BoolValueTree; + type Value = bool; + + fn new_tree(&self, _: &mut TestRunner) -> NewTree { + Ok(BoolValueTree::new(kani::any())) + } +} + +/// Generates boolean values by picking `true` with the given `probability` +/// (1.0 = always true, 0.0 = always false). +/// +/// Shrinks `true` to `false`. +pub fn weighted(probability: f64) -> Weighted { + Weighted(probability) +} + +/// The return type from `weighted()`. +#[must_use = "strategies do nothing unless used"] +#[derive(Clone, Copy, Debug)] +pub struct Weighted(f64); + +impl Strategy for Weighted { + type Tree = BoolValueTree; + type Value = bool; + + fn new_tree(&self, _: &mut TestRunner) -> NewTree { + if self.0 >= 1.0 { + Ok(BoolValueTree::new(true)) + } else if self.0 <= 0.0 { + Ok(BoolValueTree::new(false)) + } else { + Ok(BoolValueTree::new(kani::any())) + } + } +} + +/// The `ValueTree` to shrink booleans to false. +#[derive(Clone, Copy, Debug)] +pub struct BoolValueTree { + current: bool, +} + +impl BoolValueTree { + fn new(current: bool) -> Self { + BoolValueTree { current, } + } +} + +impl ValueTree for BoolValueTree { + type Value = bool; + + fn current(&self) -> bool { + self.current + } + fn simplify(&mut self) -> bool { + false + } + fn complicate(&mut self) -> bool { + false + } +} + diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index 8afe738ad491..cf608d618dc8 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -83,7 +83,7 @@ pub mod sugar; pub mod arbitrary; // pub mod array; // pub mod bits; -// pub mod bool; +pub mod bool; // pub mod char; // pub mod collection; pub mod num; From c718138d72ffbf5c34803f98495e0044d4ed96ed Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 1 Aug 2022 21:48:44 -0400 Subject: [PATCH 39/80] Removed proptest translator not needed. --- library/kani_macros/src/lib.rs | 68 +--------------------------------- 1 file changed, 1 insertion(+), 67 deletions(-) diff --git a/library/kani_macros/src/lib.rs b/library/kani_macros/src/lib.rs index e0ae02281dc6..97888cdbfdf2 100644 --- a/library/kani_macros/src/lib.rs +++ b/library/kani_macros/src/lib.rs @@ -9,7 +9,7 @@ // RUSTFLAGS="-Zcrate-attr=feature(register_tool) -Zcrate-attr=register_tool(kanitool)" // proc_macro::quote is nightly-only, so we'll cobble things together instead -use proc_macro::{Group, Ident, TokenStream, TokenTree}; +use proc_macro::TokenStream; #[cfg(all(not(kani), not(test)))] #[proc_macro_attribute] @@ -73,69 +73,3 @@ pub fn unwind(attr: TokenStream, item: TokenStream) -> TokenStream { result.extend(item); result } - -/// This proc macro does one of the following. (1) if kani is -/// configured, then it substitutes all occurrences of the proptest -/// crate with a custom kani_proptest crate. (2) otherwise, it keeps -/// the body and pastes it in. -/// -/// Implementation of the rewrite is done via a state machine in the -/// .1 position of the fold accumulator. After seeing "proptest" -/// token, it puts the span of this token in the option. If "proptest" -/// is followed by ":" or ";", then a re-write is -/// triggered. Otherwise, it pushes the same token and goes back to -/// the original state until "proptest" is seen again. -#[proc_macro] -pub fn translate_from_proptest(input: TokenStream) -> TokenStream { - const REWRITE_FROM: &str = "proptest"; - const REWRITE_TO: &str = "kani_proptest"; - - fn translate_recursive_helper(input: TokenStream) -> TokenStream { - input - .into_iter() - .fold((TokenStream::new(), None), |(mut acc, maybe_proptest_span), cur| { - if let TokenTree::Ident(ident) = cur { - if &ident.to_string() == REWRITE_FROM { - (acc, Some(ident.span())) - } else { - acc.extend(vec![TokenTree::Ident(ident)]); - (acc, maybe_proptest_span) - } - } else if let TokenTree::Punct(punctuation) = cur { - if let Some(proptest_span) = maybe_proptest_span { - acc.extend(vec![ - TokenTree::Ident(Ident::new_raw( - if punctuation.as_char() == ':' || punctuation.as_char() == ';' { - REWRITE_TO - } else { - REWRITE_FROM - }, - proptest_span, - )), - TokenTree::Punct(punctuation), - ]); - (acc, None) - } else { - acc.extend(vec![TokenTree::Punct(punctuation)]); - (acc, None) - } - } else if let TokenTree::Group(group) = cur { - let delimiter = group.delimiter(); - let stream = translate_recursive_helper(group.stream()); - acc.extend(vec![TokenTree::Group(Group::new(delimiter, stream))]); - (acc, None) - } else { - acc.extend(vec![cur]); - (acc, None) - } - }) - .0 - } - - if std::env::var_os("CARGO_CFG_KANI").is_some() { - let result = translate_recursive_helper(input); - result - } else { - input - } -} From 7d7f105b16296c3917dbe6070c6331565181c5b5 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 1 Aug 2022 21:55:55 -0400 Subject: [PATCH 40/80] Fixed infinite recursion. --- scripts/cargo-kani | 6 +++++- scripts/refresh-kani-proptest.sh | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/cargo-kani b/scripts/cargo-kani index 8a33f592807e..c3452c85ece4 100755 --- a/scripts/cargo-kani +++ b/scripts/cargo-kani @@ -19,7 +19,11 @@ then fi KANI_PATH=${KANI_CANDIDATES[0]} -$SCRIPT_DIR/refresh-kani-proptest.sh +if [ -z "${CARGO_KANI_IS_CHILD+x}" ]; then + # avoid infinite recursion as below script also calls `cargo kani` + $SCRIPT_DIR/refresh-kani-proptest.sh +fi + CARGO_TOML_SAVE_FILE='.save-cargo.toml' if [[ "${PROPTEST+x}" == "1" ]]; then cp Cargo.toml $CARGO_TOML_SAVE_FILE diff --git a/scripts/refresh-kani-proptest.sh b/scripts/refresh-kani-proptest.sh index 0cbe366a1fa0..61909bb668f9 100755 --- a/scripts/refresh-kani-proptest.sh +++ b/scripts/refresh-kani-proptest.sh @@ -18,6 +18,7 @@ if [ ! -f "$PROPTEST_SYMTAB_PATH" ] || [[ "$PROPTEST_SYMTAB_PATH" -ot "$KANI_BIN echo 'Proptest symtab not found or too old. (Re)compiling proptest..' ( cd $KANI_REPO_ROOT/library/proptest; + export CARGO_KANI_IS_CHILD=1 cargo kani --only-codegen; ) fi From 83bf62b442219fb1d5bad610c60637863d97f8f3 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 1 Aug 2022 22:34:44 -0400 Subject: [PATCH 41/80] Fixed recompiling criteria. --- scripts/refresh-kani-proptest.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/refresh-kani-proptest.sh b/scripts/refresh-kani-proptest.sh index 61909bb668f9..99e7f8e4f87e 100755 --- a/scripts/refresh-kani-proptest.sh +++ b/scripts/refresh-kani-proptest.sh @@ -12,9 +12,9 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) KANI_REPO_ROOT="$SCRIPT_DIR/.." PROPTEST_SYMTAB_PATH="$(find $KANI_REPO_ROOT/target -name '*symtab.json' | head -1)" -KANI_BINARY_PATH="$KANI_REPO_ROOT/debug/kani-compiler" +KANI_TARGET="$KANI_REPO_ROOT/target/debug/libproptest.d" -if [ ! -f "$PROPTEST_SYMTAB_PATH" ] || [[ "$PROPTEST_SYMTAB_PATH" -ot "$KANI_BINARY_PATH" ]]; then +if [ ! -f "$PROPTEST_SYMTAB_PATH" ] || [[ "$PROPTEST_SYMTAB_PATH" -ot "$KANI_TARGET" ]]; then echo 'Proptest symtab not found or too old. (Re)compiling proptest..' ( cd $KANI_REPO_ROOT/library/proptest; From 7a1564e88f3f7c10e2dc8bc9f1d60b443651f03b Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 1 Aug 2022 22:53:45 -0400 Subject: [PATCH 42/80] Added prelude module. --- library/proptest/src/lib.rs | 2 +- library/proptest/src/prelude.rs | 50 +++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 library/proptest/src/prelude.rs diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index cf608d618dc8..bad28f74db8d 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -97,4 +97,4 @@ pub mod tuple; // #[cfg(feature = "std")] // pub mod string; -// pub mod prelude; +pub mod prelude; diff --git a/library/proptest/src/prelude.rs b/library/proptest/src/prelude.rs new file mode 100644 index 000000000000..d7bc235fde45 --- /dev/null +++ b/library/proptest/src/prelude.rs @@ -0,0 +1,50 @@ +//- +// Copyright 2017, 2018, 2019 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Re-exports the most commonly-needed APIs of proptest. +//! +//! This module is intended to be wildcard-imported, i.e., +//! `use proptest::prelude::*;`. Note that it re-exports the whole crate itself +//! under the name `prop`, so you don't need a separate `use proptest;` line. +//! +//! In addition to Proptest's own APIs, this also reexports a small portion of +//! the `rand` crate sufficient to easily use `prop_perturb` and other +//! functionality that exposes random number generators. Please note that this +//! is will always be a direct reexport; using these in preference to using the +//! `rand` crate directly will not provide insulation from the upcoming +//! revision to the `rand` crate. + +pub use crate::arbitrary::{any, any_with, Arbitrary}; +pub use crate::strategy::{BoxedStrategy, Just, SBoxedStrategy, Strategy}; +pub use crate::test_runner::Config as ProptestConfig; +pub use crate::{ + prop_assert, prop_assert_eq, prop_assert_ne, prop_assume, prop_compose, prop_oneof, proptest, +}; + +/// Re-exports the entire public API of proptest so that an import of `prelude` +/// allows simply writing, for example, `prop::num::i32::ANY` rather than +/// `proptest::num::i32::ANY` plus a separate `use proptest;`. +pub mod prop { + pub use crate::arbitrary; + // todo: Implement the missing proptest features. + // pub use crate::array; + // pub use crate::bits; + pub use crate::bool; + // pub use crate::char; + // pub use crate::collection; + pub use crate::num; + // pub use crate::option; + // pub use crate::result; + // pub use crate::sample; + pub use crate::strategy; + #[cfg(feature = "std")] + pub use crate::string; + pub use crate::test_runner; + pub use crate::tuple; +} From b9e018d627b2401b1155098d992b6f5273155b99 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Tue, 2 Aug 2022 00:01:29 -0400 Subject: [PATCH 43/80] Fixed license for PR. --- library/proptest/src/arbitrary/_alloc/alloc.rs | 2 ++ library/proptest/src/arbitrary/_alloc/borrow.rs | 2 ++ library/proptest/src/arbitrary/_alloc/boxed.rs | 2 ++ library/proptest/src/arbitrary/_alloc/char.rs | 2 ++ .../proptest/src/arbitrary/_alloc/collections.rs | 2 ++ library/proptest/src/arbitrary/_alloc/hash.rs | 2 ++ library/proptest/src/arbitrary/_alloc/mod.rs | 2 ++ library/proptest/src/arbitrary/_alloc/ops.rs | 2 ++ library/proptest/src/arbitrary/_alloc/rc.rs | 2 ++ library/proptest/src/arbitrary/_alloc/str.rs | 2 ++ library/proptest/src/arbitrary/_alloc/sync.rs | 2 ++ library/proptest/src/arbitrary/_core/ascii.rs | 2 ++ library/proptest/src/arbitrary/_core/cell.rs | 2 ++ library/proptest/src/arbitrary/_core/cmp.rs | 2 ++ library/proptest/src/arbitrary/_core/convert.rs | 2 ++ library/proptest/src/arbitrary/_core/fmt.rs | 2 ++ library/proptest/src/arbitrary/_core/iter.rs | 2 ++ library/proptest/src/arbitrary/_core/marker.rs | 2 ++ library/proptest/src/arbitrary/_core/mem.rs | 2 ++ library/proptest/src/arbitrary/_core/mod.rs | 2 ++ library/proptest/src/arbitrary/_core/num.rs | 2 ++ library/proptest/src/arbitrary/_core/option.rs | 2 ++ library/proptest/src/arbitrary/_core/result.rs | 2 ++ library/proptest/src/arbitrary/_std/env.rs | 2 ++ library/proptest/src/arbitrary/_std/ffi.rs | 2 ++ library/proptest/src/arbitrary/_std/fs.rs | 2 ++ library/proptest/src/arbitrary/_std/io.rs | 2 ++ library/proptest/src/arbitrary/_std/mod.rs | 2 ++ library/proptest/src/arbitrary/_std/net.rs | 2 ++ library/proptest/src/arbitrary/_std/panic.rs | 2 ++ library/proptest/src/arbitrary/_std/path.rs | 2 ++ library/proptest/src/arbitrary/_std/string.rs | 2 ++ library/proptest/src/arbitrary/_std/sync.rs | 2 ++ library/proptest/src/arbitrary/_std/thread.rs | 2 ++ library/proptest/src/arbitrary/_std/time.rs | 2 ++ library/proptest/src/arbitrary/arrays.rs | 2 ++ library/proptest/src/arbitrary/functor.rs | 2 ++ library/proptest/src/arbitrary/macros.rs | 2 ++ library/proptest/src/arbitrary/mod.rs | 2 ++ library/proptest/src/arbitrary/primitives.rs | 2 ++ library/proptest/src/arbitrary/sample.rs | 2 ++ library/proptest/src/arbitrary/traits.rs | 2 ++ library/proptest/src/arbitrary/tuples.rs | 2 ++ library/proptest/src/bool.rs | 2 ++ library/proptest/src/lib.rs | 2 ++ library/proptest/src/num.rs | 2 ++ library/proptest/src/prelude.rs | 2 ++ library/proptest/src/std_facade.rs | 2 ++ library/proptest/src/strategy/just.rs | 2 ++ library/proptest/src/strategy/mod.rs | 2 ++ library/proptest/src/strategy/traits.rs | 13 +++++++++++-- library/proptest/src/sugar.rs | 2 ++ library/proptest/src/test_runner/config.rs | 2 ++ library/proptest/src/test_runner/mod.rs | 2 ++ library/proptest/src/test_runner/reason.rs | 2 ++ library/proptest/src/test_runner/runner.rs | 12 ++++++++++-- library/proptest/src/tuple.rs | 2 ++ 57 files changed, 131 insertions(+), 4 deletions(-) diff --git a/library/proptest/src/arbitrary/_alloc/alloc.rs b/library/proptest/src/arbitrary/_alloc/alloc.rs index f403d0519314..80172cda9975 100644 --- a/library/proptest/src/arbitrary/_alloc/alloc.rs +++ b/library/proptest/src/arbitrary/_alloc/alloc.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::hash`. diff --git a/library/proptest/src/arbitrary/_alloc/borrow.rs b/library/proptest/src/arbitrary/_alloc/borrow.rs index 153115e1839d..8c3de0aceaa5 100644 --- a/library/proptest/src/arbitrary/_alloc/borrow.rs +++ b/library/proptest/src/arbitrary/_alloc/borrow.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for std::borrow. diff --git a/library/proptest/src/arbitrary/_alloc/boxed.rs b/library/proptest/src/arbitrary/_alloc/boxed.rs index 222362504d82..914d7d761444 100644 --- a/library/proptest/src/arbitrary/_alloc/boxed.rs +++ b/library/proptest/src/arbitrary/_alloc/boxed.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::boxed`. diff --git a/library/proptest/src/arbitrary/_alloc/char.rs b/library/proptest/src/arbitrary/_alloc/char.rs index fab9dd824be8..95607425973f 100644 --- a/library/proptest/src/arbitrary/_alloc/char.rs +++ b/library/proptest/src/arbitrary/_alloc/char.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::char`. diff --git a/library/proptest/src/arbitrary/_alloc/collections.rs b/library/proptest/src/arbitrary/_alloc/collections.rs index 59e02f000cc1..9c84ed568d1a 100644 --- a/library/proptest/src/arbitrary/_alloc/collections.rs +++ b/library/proptest/src/arbitrary/_alloc/collections.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::collections`. diff --git a/library/proptest/src/arbitrary/_alloc/hash.rs b/library/proptest/src/arbitrary/_alloc/hash.rs index 8979bafca47b..6f0cde280ab1 100644 --- a/library/proptest/src/arbitrary/_alloc/hash.rs +++ b/library/proptest/src/arbitrary/_alloc/hash.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::hash`. diff --git a/library/proptest/src/arbitrary/_alloc/mod.rs b/library/proptest/src/arbitrary/_alloc/mod.rs index f286cab6d87f..4abcbba1e538 100644 --- a/library/proptest/src/arbitrary/_alloc/mod.rs +++ b/library/proptest/src/arbitrary/_alloc/mod.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for liballoc. diff --git a/library/proptest/src/arbitrary/_alloc/ops.rs b/library/proptest/src/arbitrary/_alloc/ops.rs index ad9b6fc23179..1d7469e5450b 100644 --- a/library/proptest/src/arbitrary/_alloc/ops.rs +++ b/library/proptest/src/arbitrary/_alloc/ops.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::ops`. diff --git a/library/proptest/src/arbitrary/_alloc/rc.rs b/library/proptest/src/arbitrary/_alloc/rc.rs index 1ddb6aa00b54..cd426da7dc7c 100644 --- a/library/proptest/src/arbitrary/_alloc/rc.rs +++ b/library/proptest/src/arbitrary/_alloc/rc.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::rc`. diff --git a/library/proptest/src/arbitrary/_alloc/str.rs b/library/proptest/src/arbitrary/_alloc/str.rs index 72ba248da95f..d3c82fccc9fd 100644 --- a/library/proptest/src/arbitrary/_alloc/str.rs +++ b/library/proptest/src/arbitrary/_alloc/str.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::str`. diff --git a/library/proptest/src/arbitrary/_alloc/sync.rs b/library/proptest/src/arbitrary/_alloc/sync.rs index ebc22258155f..8ff686cb9c74 100644 --- a/library/proptest/src/arbitrary/_alloc/sync.rs +++ b/library/proptest/src/arbitrary/_alloc/sync.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::sync`. diff --git a/library/proptest/src/arbitrary/_core/ascii.rs b/library/proptest/src/arbitrary/_core/ascii.rs index ded19289bf73..2fd8093f40f6 100644 --- a/library/proptest/src/arbitrary/_core/ascii.rs +++ b/library/proptest/src/arbitrary/_core/ascii.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::ascii`. diff --git a/library/proptest/src/arbitrary/_core/cell.rs b/library/proptest/src/arbitrary/_core/cell.rs index c10148fb99b5..b3e2f69875cb 100644 --- a/library/proptest/src/arbitrary/_core/cell.rs +++ b/library/proptest/src/arbitrary/_core/cell.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::cell`. diff --git a/library/proptest/src/arbitrary/_core/cmp.rs b/library/proptest/src/arbitrary/_core/cmp.rs index 75637d45c2f3..fafe9778919b 100644 --- a/library/proptest/src/arbitrary/_core/cmp.rs +++ b/library/proptest/src/arbitrary/_core/cmp.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::cmp`. diff --git a/library/proptest/src/arbitrary/_core/convert.rs b/library/proptest/src/arbitrary/_core/convert.rs index b74d786204ec..24736c9ce286 100644 --- a/library/proptest/src/arbitrary/_core/convert.rs +++ b/library/proptest/src/arbitrary/_core/convert.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::convert`. diff --git a/library/proptest/src/arbitrary/_core/fmt.rs b/library/proptest/src/arbitrary/_core/fmt.rs index b16b8968c18c..e2b9dc93bd4c 100644 --- a/library/proptest/src/arbitrary/_core/fmt.rs +++ b/library/proptest/src/arbitrary/_core/fmt.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::fmt`. diff --git a/library/proptest/src/arbitrary/_core/iter.rs b/library/proptest/src/arbitrary/_core/iter.rs index 5e48a01d8591..d208de35bfa8 100644 --- a/library/proptest/src/arbitrary/_core/iter.rs +++ b/library/proptest/src/arbitrary/_core/iter.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::iter`. diff --git a/library/proptest/src/arbitrary/_core/marker.rs b/library/proptest/src/arbitrary/_core/marker.rs index 6558f57ab7f3..b51761148a43 100644 --- a/library/proptest/src/arbitrary/_core/marker.rs +++ b/library/proptest/src/arbitrary/_core/marker.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::marker`. diff --git a/library/proptest/src/arbitrary/_core/mem.rs b/library/proptest/src/arbitrary/_core/mem.rs index 700e40fbe998..bfb13578afb0 100644 --- a/library/proptest/src/arbitrary/_core/mem.rs +++ b/library/proptest/src/arbitrary/_core/mem.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::mem`. diff --git a/library/proptest/src/arbitrary/_core/mod.rs b/library/proptest/src/arbitrary/_core/mod.rs index 5fc3742e490e..40c102295198 100644 --- a/library/proptest/src/arbitrary/_core/mod.rs +++ b/library/proptest/src/arbitrary/_core/mod.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for libcore. diff --git a/library/proptest/src/arbitrary/_core/num.rs b/library/proptest/src/arbitrary/_core/num.rs index f2988ecf0f3e..bb496d278fbe 100644 --- a/library/proptest/src/arbitrary/_core/num.rs +++ b/library/proptest/src/arbitrary/_core/num.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::num`. diff --git a/library/proptest/src/arbitrary/_core/option.rs b/library/proptest/src/arbitrary/_core/option.rs index 1e7d2c33457b..7bb2832620ee 100644 --- a/library/proptest/src/arbitrary/_core/option.rs +++ b/library/proptest/src/arbitrary/_core/option.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::option`. diff --git a/library/proptest/src/arbitrary/_core/result.rs b/library/proptest/src/arbitrary/_core/result.rs index 7da3324f7e32..69acf6d35a17 100644 --- a/library/proptest/src/arbitrary/_core/result.rs +++ b/library/proptest/src/arbitrary/_core/result.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::result`. diff --git a/library/proptest/src/arbitrary/_std/env.rs b/library/proptest/src/arbitrary/_std/env.rs index 384945c79e57..a11f40a9bb07 100644 --- a/library/proptest/src/arbitrary/_std/env.rs +++ b/library/proptest/src/arbitrary/_std/env.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::env`. diff --git a/library/proptest/src/arbitrary/_std/ffi.rs b/library/proptest/src/arbitrary/_std/ffi.rs index 288b3947ad98..776a8f679d05 100644 --- a/library/proptest/src/arbitrary/_std/ffi.rs +++ b/library/proptest/src/arbitrary/_std/ffi.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::ffi`. diff --git a/library/proptest/src/arbitrary/_std/fs.rs b/library/proptest/src/arbitrary/_std/fs.rs index 66d18ca1ada6..4383fa4093ab 100644 --- a/library/proptest/src/arbitrary/_std/fs.rs +++ b/library/proptest/src/arbitrary/_std/fs.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::fs`. diff --git a/library/proptest/src/arbitrary/_std/io.rs b/library/proptest/src/arbitrary/_std/io.rs index 34ee9da32ac4..768a5b797927 100644 --- a/library/proptest/src/arbitrary/_std/io.rs +++ b/library/proptest/src/arbitrary/_std/io.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::io`. diff --git a/library/proptest/src/arbitrary/_std/mod.rs b/library/proptest/src/arbitrary/_std/mod.rs index 4360f5e0763e..d4f07e8d5862 100644 --- a/library/proptest/src/arbitrary/_std/mod.rs +++ b/library/proptest/src/arbitrary/_std/mod.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for libstd. diff --git a/library/proptest/src/arbitrary/_std/net.rs b/library/proptest/src/arbitrary/_std/net.rs index fcbec4d61624..4b4fe4b670e6 100644 --- a/library/proptest/src/arbitrary/_std/net.rs +++ b/library/proptest/src/arbitrary/_std/net.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::net`. diff --git a/library/proptest/src/arbitrary/_std/panic.rs b/library/proptest/src/arbitrary/_std/panic.rs index c2bd40cd4a1d..b15cc9efb61f 100644 --- a/library/proptest/src/arbitrary/_std/panic.rs +++ b/library/proptest/src/arbitrary/_std/panic.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::panic`. diff --git a/library/proptest/src/arbitrary/_std/path.rs b/library/proptest/src/arbitrary/_std/path.rs index e7d063c1716e..766e4eee177b 100644 --- a/library/proptest/src/arbitrary/_std/path.rs +++ b/library/proptest/src/arbitrary/_std/path.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::path`. diff --git a/library/proptest/src/arbitrary/_std/string.rs b/library/proptest/src/arbitrary/_std/string.rs index aab3b9a9a521..8c49db3c682f 100644 --- a/library/proptest/src/arbitrary/_std/string.rs +++ b/library/proptest/src/arbitrary/_std/string.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::string`. diff --git a/library/proptest/src/arbitrary/_std/sync.rs b/library/proptest/src/arbitrary/_std/sync.rs index a615f9d3505b..3a0454e78826 100644 --- a/library/proptest/src/arbitrary/_std/sync.rs +++ b/library/proptest/src/arbitrary/_std/sync.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::sync`. diff --git a/library/proptest/src/arbitrary/_std/thread.rs b/library/proptest/src/arbitrary/_std/thread.rs index 3a9b2b3fe114..87ed046fbd2b 100644 --- a/library/proptest/src/arbitrary/_std/thread.rs +++ b/library/proptest/src/arbitrary/_std/thread.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::thread`. diff --git a/library/proptest/src/arbitrary/_std/time.rs b/library/proptest/src/arbitrary/_std/time.rs index 7d940439a799..fe0a537bc037 100644 --- a/library/proptest/src/arbitrary/_std/time.rs +++ b/library/proptest/src/arbitrary/_std/time.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for `std::time`. diff --git a/library/proptest/src/arbitrary/arrays.rs b/library/proptest/src/arbitrary/arrays.rs index 0fe3e2225e97..72d4f72df8c9 100644 --- a/library/proptest/src/arbitrary/arrays.rs +++ b/library/proptest/src/arbitrary/arrays.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for arrays. diff --git a/library/proptest/src/arbitrary/functor.rs b/library/proptest/src/arbitrary/functor.rs index 855dbeb66940..f779595dd8fa 100644 --- a/library/proptest/src/arbitrary/functor.rs +++ b/library/proptest/src/arbitrary/functor.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Provides higher order `Arbitrary` traits. //! This is mainly for use by `proptest_derive`. diff --git a/library/proptest/src/arbitrary/macros.rs b/library/proptest/src/arbitrary/macros.rs index 8edf2a6eaa7f..5b373544b5a0 100644 --- a/library/proptest/src/arbitrary/macros.rs +++ b/library/proptest/src/arbitrary/macros.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details #![cfg_attr(not(feature = "std"), allow(unused_macros))] diff --git a/library/proptest/src/arbitrary/mod.rs b/library/proptest/src/arbitrary/mod.rs index 10fa6f346755..cd6e0c398e34 100644 --- a/library/proptest/src/arbitrary/mod.rs +++ b/library/proptest/src/arbitrary/mod.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Defines the `Arbitrary` trait and related free functions //! and type aliases. diff --git a/library/proptest/src/arbitrary/primitives.rs b/library/proptest/src/arbitrary/primitives.rs index fb0647b2ec00..abb7f5f754a1 100644 --- a/library/proptest/src/arbitrary/primitives.rs +++ b/library/proptest/src/arbitrary/primitives.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for primitive types. diff --git a/library/proptest/src/arbitrary/sample.rs b/library/proptest/src/arbitrary/sample.rs index 81758213d3c7..842fd9f03020 100644 --- a/library/proptest/src/arbitrary/sample.rs +++ b/library/proptest/src/arbitrary/sample.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details use crate::arbitrary::Arbitrary; use crate::sample::{Index, IndexStrategy, Selector, SelectorStrategy}; diff --git a/library/proptest/src/arbitrary/traits.rs b/library/proptest/src/arbitrary/traits.rs index 83f021425baf..e28d50bba87b 100644 --- a/library/proptest/src/arbitrary/traits.rs +++ b/library/proptest/src/arbitrary/traits.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details use core::fmt; diff --git a/library/proptest/src/arbitrary/tuples.rs b/library/proptest/src/arbitrary/tuples.rs index 5df3088a3c2d..db86599304de 100644 --- a/library/proptest/src/arbitrary/tuples.rs +++ b/library/proptest/src/arbitrary/tuples.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Arbitrary implementations for tuples. diff --git a/library/proptest/src/bool.rs b/library/proptest/src/bool.rs index 30828bdd3a80..47aca6273f92 100644 --- a/library/proptest/src/bool.rs +++ b/library/proptest/src/bool.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Strategies for generating `bool` values. diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index bad28f74db8d..cac77d5d86bd 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! # Proptest Reference Documentation //! diff --git a/library/proptest/src/num.rs b/library/proptest/src/num.rs index cecf5adea478..8ee74efa20f1 100644 --- a/library/proptest/src/num.rs +++ b/library/proptest/src/num.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Strategies to generate numeric values (as opposed to integers used as bit //! fields). diff --git a/library/proptest/src/prelude.rs b/library/proptest/src/prelude.rs index d7bc235fde45..a218fecb6bc6 100644 --- a/library/proptest/src/prelude.rs +++ b/library/proptest/src/prelude.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Re-exports the most commonly-needed APIs of proptest. //! diff --git a/library/proptest/src/std_facade.rs b/library/proptest/src/std_facade.rs index c7734bd17bcc..427008183480 100644 --- a/library/proptest/src/std_facade.rs +++ b/library/proptest/src/std_facade.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! This module provides #[cfg(..)]ed type aliases over features. diff --git a/library/proptest/src/strategy/just.rs b/library/proptest/src/strategy/just.rs index 4838098cc688..45633e52d339 100644 --- a/library/proptest/src/strategy/just.rs +++ b/library/proptest/src/strategy/just.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details use crate::std_facade::fmt; diff --git a/library/proptest/src/strategy/mod.rs b/library/proptest/src/strategy/mod.rs index aa286f871dc0..711fd2312457 100644 --- a/library/proptest/src/strategy/mod.rs +++ b/library/proptest/src/strategy/mod.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Defines the core traits used by Proptest. diff --git a/library/proptest/src/strategy/traits.rs b/library/proptest/src/strategy/traits.rs index bb2d5b673657..32c7524bc08b 100644 --- a/library/proptest/src/strategy/traits.rs +++ b/library/proptest/src/strategy/traits.rs @@ -1,11 +1,20 @@ -// Copyright Kani Contributors, the proptest developers -// SPDX-License-Identifier: Apache-2.0 OR MIT +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! This file defines the strategy trait, which replaces //! proptest::strategy::Strategy use crate::std_facade::{fmt, Arc, Box, Rc}; + use core::cmp; // use crate::strategy::*; diff --git a/library/proptest/src/sugar.rs b/library/proptest/src/sugar.rs index ce69b91636f5..4f0fb4bc1091 100644 --- a/library/proptest/src/sugar.rs +++ b/library/proptest/src/sugar.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details // use crate::std_facade::fmt; diff --git a/library/proptest/src/test_runner/config.rs b/library/proptest/src/test_runner/config.rs index a9e6893c3b4b..3a618a8a9809 100644 --- a/library/proptest/src/test_runner/config.rs +++ b/library/proptest/src/test_runner/config.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details // use crate::std_facade::Box; use core::u32; diff --git a/library/proptest/src/test_runner/mod.rs b/library/proptest/src/test_runner/mod.rs index d93afcccddf8..f32a49cbcf02 100644 --- a/library/proptest/src/test_runner/mod.rs +++ b/library/proptest/src/test_runner/mod.rs @@ -6,6 +6,8 @@ mod reason; mod runner; +// Modifications Copyright Kani Contributors +// See GitHub history for details mod config; diff --git a/library/proptest/src/test_runner/reason.rs b/library/proptest/src/test_runner/reason.rs index 38cc7e322633..df991b831cb4 100644 --- a/library/proptest/src/test_runner/reason.rs +++ b/library/proptest/src/test_runner/reason.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details use crate::std_facade::{fmt, Box, Cow, String}; diff --git a/library/proptest/src/test_runner/runner.rs b/library/proptest/src/test_runner/runner.rs index 5ba7cfb0a9c1..e8a0ab806af4 100644 --- a/library/proptest/src/test_runner/runner.rs +++ b/library/proptest/src/test_runner/runner.rs @@ -1,5 +1,13 @@ -// Copyright Kani Contributors -// SPDX-License-Identifier: Apache-2.0 OR MIT +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! This file implements a Kani-specific test runner that mirrors the //! one in proptest. In contrast to the original, this test runner diff --git a/library/proptest/src/tuple.rs b/library/proptest/src/tuple.rs index 56bbe348577a..8a972e29a55d 100644 --- a/library/proptest/src/tuple.rs +++ b/library/proptest/src/tuple.rs @@ -6,6 +6,8 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details //! Support for combining strategies into tuples. //! From 31ad28a32d2daf3c0060308e3d62ee51ee49f952 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Tue, 2 Aug 2022 11:53:04 -0400 Subject: [PATCH 44/80] Applied `cargo fmt`. --- kani-compiler/src/main.rs | 5 +- kani-driver/src/call_cargo.rs | 11 +--- library/proptest/src/arbitrary/primitives.rs | 2 +- library/proptest/src/bool.rs | 3 +- library/proptest/src/num.rs | 60 ++++++++++---------- library/proptest/src/strategy/traits.rs | 2 - library/proptest/src/test_runner/config.rs | 2 - library/proptest/src/test_runner/mod.rs | 4 +- library/proptest/src/test_runner/runner.rs | 15 +++-- 9 files changed, 45 insertions(+), 59 deletions(-) diff --git a/kani-compiler/src/main.rs b/kani-compiler/src/main.rs index c88285fb3b42..d15ddd57c9ba 100644 --- a/kani-compiler/src/main.rs +++ b/kani-compiler/src/main.rs @@ -50,8 +50,7 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { let build_target = env!("TARGET"); // see build.rs let kani_extern_lib_path = - PathBuf::from(lib_path) - .join(format!("../../../../../{}/debug/deps", build_target)); + PathBuf::from(lib_path).join(format!("../../../../../{}/debug/deps", build_target)); let args = vec![ "-C", @@ -71,11 +70,9 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { "crate-attr=feature(register_tool)", "-Z", "crate-attr=register_tool(kanitool)", - // Prints expanded macro. For proptest devops only, remove after done // "-Z", // "unpretty=expanded", - "-L", lib_path, "--extern", diff --git a/kani-driver/src/call_cargo.rs b/kani-driver/src/call_cargo.rs index 5dd705d2460a..1910809609fe 100644 --- a/kani-driver/src/call_cargo.rs +++ b/kani-driver/src/call_cargo.rs @@ -38,8 +38,7 @@ impl KaniSession { let target_dir = self.args.target_dir.as_ref().unwrap_or(&find_target_dir()).clone(); let outdir = target_dir.join(build_target).join("debug/deps"); - let kani_extern_lib_path = - PathBuf::from(std::env!("KANI_EXTERN_DIR")); + let kani_extern_lib_path = PathBuf::from(std::env!("KANI_EXTERN_DIR")); let flag_env = { let rustc_args = self.kani_rustc_flags(); @@ -87,15 +86,11 @@ impl KaniSession { outdir: outdir.clone(), symtabs: glob(&outdir.join("*.symtab.json"))? .into_iter() - .chain( - glob(&kani_extern_lib_path.join("*.symtab.json"))? - ) + .chain(glob(&kani_extern_lib_path.join("*.symtab.json"))?) .collect(), metadata: glob(&outdir.join("*.kani-metadata.json"))? .into_iter() - .chain( - glob(&kani_extern_lib_path.join("*.kani-metadata.json"))? - ) + .chain(glob(&kani_extern_lib_path.join("*.kani-metadata.json"))?) .collect(), restrictions: self.args.restrict_vtable().then(|| outdir), }) diff --git a/library/proptest/src/arbitrary/primitives.rs b/library/proptest/src/arbitrary/primitives.rs index abb7f5f754a1..bf9b49bad682 100644 --- a/library/proptest/src/arbitrary/primitives.rs +++ b/library/proptest/src/arbitrary/primitives.rs @@ -13,7 +13,7 @@ use crate::bool; // use crate::char; -use crate::num::{ i16, i32, i64, i8, isize, u16, u32, u64, u8, usize, f32, f64,}; +use crate::num::{f32, f64, i16, i32, i64, i8, isize, u16, u32, u64, u8, usize}; #[cfg(not(target_arch = "wasm32"))] use crate::num::{i128, u128}; diff --git a/library/proptest/src/bool.rs b/library/proptest/src/bool.rs index 47aca6273f92..fca7ded985ae 100644 --- a/library/proptest/src/bool.rs +++ b/library/proptest/src/bool.rs @@ -68,7 +68,7 @@ pub struct BoolValueTree { impl BoolValueTree { fn new(current: bool) -> Self { - BoolValueTree { current, } + BoolValueTree { current } } } @@ -85,4 +85,3 @@ impl ValueTree for BoolValueTree { false } } - diff --git a/library/proptest/src/num.rs b/library/proptest/src/num.rs index 8ee74efa20f1..1913586856a1 100644 --- a/library/proptest/src/num.rs +++ b/library/proptest/src/num.rs @@ -20,14 +20,21 @@ use core::ops::Range; // Below 2 functions are the source of Kani symbolic variables. /// Produce an symbolic value from a range. -pub(crate) fn sample_uniform(_: &mut TestRunner, range: Range) -> X { +pub(crate) fn sample_uniform( + _: &mut TestRunner, + range: Range, +) -> X { let value: X = kani::any(); kani::assume(range.contains(&value)); value } /// Produce an symbolic value start and end values. End is inclusive. -pub(crate) fn sample_uniform_incl(_: &mut TestRunner, start: X, end: X) -> X { +pub(crate) fn sample_uniform_incl( + _: &mut TestRunner, + start: X, + end: X, +) -> X { let value: X = kani::any(); kani::assume(value <= end); kani::assume(value >= start); @@ -143,16 +150,14 @@ macro_rules! signed_integer_bin_search { impl BinarySearch { /// Creates a new binary searcher starting at the given value. pub fn new(start: $typ) -> Self { - BinarySearch { curr: start, } + BinarySearch { curr: start } } /// Creates a new binary searcher which will not produce values /// on the other side of `lo` or `hi` from `start`. `lo` is /// inclusive, `hi` is exclusive. fn new_clamped(_: $typ, start: $typ, _: $typ) -> Self { - BinarySearch { - curr: start, - } + BinarySearch { curr: start } } } impl ValueTree for BinarySearch { @@ -195,13 +200,13 @@ macro_rules! unsigned_integer_bin_search { impl BinarySearch { /// Creates a new binary searcher starting at the given value. pub fn new(start: $typ) -> Self { - BinarySearch { curr: start, } + BinarySearch { curr: start } } /// Creates a new binary searcher which will not search below /// the given `lo` value. fn new_clamped(_: $typ, start: $typ, _: $typ) -> Self { - BinarySearch { curr: start, } + BinarySearch { curr: start } } /// Creates a new binary searcher which will not search below @@ -247,7 +252,7 @@ unsigned_integer_bin_search!(u128); unsigned_integer_bin_search!(usize); #[derive(Clone, Copy, Debug)] -pub(crate) struct FloatTypes(u32); +pub(crate) struct FloatTypes(u32); impl std::ops::BitOr for FloatTypes { type Output = Self; @@ -264,22 +269,22 @@ impl std::ops::BitOrAssign for FloatTypes { } impl FloatTypes { - const POSITIVE : FloatTypes = FloatTypes(0b0000_0001); - const NEGATIVE : FloatTypes = FloatTypes(0b0000_0010); - const NORMAL : FloatTypes = FloatTypes(0b0000_0100); - const SUBNORMAL : FloatTypes = FloatTypes(0b0000_1000); - const ZERO : FloatTypes = FloatTypes(0b0001_0000); - const INFINITE : FloatTypes = FloatTypes(0b0010_0000); - const QUIET_NAN : FloatTypes = FloatTypes(0b0100_0000); - const SIGNALING_NAN : FloatTypes = FloatTypes(0b1000_0000); - const ANY : FloatTypes = FloatTypes(0b1111_1111); - - fn intersects(&self , other: Self) -> bool { + const POSITIVE: FloatTypes = FloatTypes(0b0000_0001); + const NEGATIVE: FloatTypes = FloatTypes(0b0000_0010); + const NORMAL: FloatTypes = FloatTypes(0b0000_0100); + const SUBNORMAL: FloatTypes = FloatTypes(0b0000_1000); + const ZERO: FloatTypes = FloatTypes(0b0001_0000); + const INFINITE: FloatTypes = FloatTypes(0b0010_0000); + const QUIET_NAN: FloatTypes = FloatTypes(0b0100_0000); + const SIGNALING_NAN: FloatTypes = FloatTypes(0b1000_0000); + const ANY: FloatTypes = FloatTypes(0b1111_1111); + + fn intersects(&self, other: Self) -> bool { let intersection = self.0 & other.0; intersection != 0 } - fn contains(&self , other: Self) -> bool { + fn contains(&self, other: Self) -> bool { let intersection = self.0 & other.0; intersection == other.0 } @@ -303,8 +308,7 @@ impl FloatTypes { } } -trait FloatLayout -{ +trait FloatLayout { type Bits: Copy; const SIGN_MASK: Self::Bits; @@ -592,10 +596,10 @@ macro_rules! float_bin_search { ($typ:ident) => { #[allow(missing_docs)] pub mod $typ { - use core::ops; use super::{FloatLayout, FloatTypes}; use crate::strategy::*; use crate::test_runner::TestRunner; + use core::ops; float_any!($typ); @@ -610,20 +614,18 @@ macro_rules! float_bin_search { impl BinarySearch { /// Creates a new binary searcher starting at the given value. pub fn new(start: $typ) -> Self { - BinarySearch { curr: start, } + BinarySearch { curr: start } } fn new_with_types(start: $typ, _: FloatTypes) -> Self { - BinarySearch { curr: start, } + BinarySearch { curr: start } } /// Creates a new binary searcher which will not produce values /// on the other side of `lo` or `hi` from `start`. `lo` is /// inclusive, `hi` is exclusive. fn new_clamped(_: $typ, start: $typ, _: $typ) -> Self { - BinarySearch { - curr: start, - } + BinarySearch { curr: start } } } diff --git a/library/proptest/src/strategy/traits.rs b/library/proptest/src/strategy/traits.rs index 32c7524bc08b..4e3262f796f6 100644 --- a/library/proptest/src/strategy/traits.rs +++ b/library/proptest/src/strategy/traits.rs @@ -12,7 +12,6 @@ //! This file defines the strategy trait, which replaces //! proptest::strategy::Strategy - use crate::std_facade::{fmt, Arc, Box, Rc}; use core::cmp; @@ -1031,4 +1030,3 @@ where } } } - diff --git a/library/proptest/src/test_runner/config.rs b/library/proptest/src/test_runner/config.rs index 3a618a8a9809..802be998e06c 100644 --- a/library/proptest/src/test_runner/config.rs +++ b/library/proptest/src/test_runner/config.rs @@ -46,7 +46,6 @@ const TIMEOUT: &str = "PROPTEST_TIMEOUT"; #[cfg(feature = "std")] const VERBOSE: &str = "PROPTEST_VERBOSE"; - #[cfg(feature = "std")] fn contextualize_config(mut result: Config) -> Config { fn parse_or_warn(src: &OsString, dst: &mut T, typ: &str, var: &str) { @@ -286,7 +285,6 @@ pub struct Config { // Caching incurs its own overhead, and may very well make your test run // more slowly. // pub result_cache: fn() -> Box, - /// Set to non-zero values to cause proptest to emit human-targeted /// messages to stderr as it runs. /// diff --git a/library/proptest/src/test_runner/mod.rs b/library/proptest/src/test_runner/mod.rs index f32a49cbcf02..67cc40aa5f56 100644 --- a/library/proptest/src/test_runner/mod.rs +++ b/library/proptest/src/test_runner/mod.rs @@ -10,8 +10,6 @@ mod runner; // See GitHub history for details mod config; - +pub use config::*; pub use reason::*; pub use runner::*; -pub use config::*; - diff --git a/library/proptest/src/test_runner/runner.rs b/library/proptest/src/test_runner/runner.rs index e8a0ab806af4..78931d643f5c 100644 --- a/library/proptest/src/test_runner/runner.rs +++ b/library/proptest/src/test_runner/runner.rs @@ -13,22 +13,22 @@ //! one in proptest. In contrast to the original, this test runner //! will run once but with symbolic inputs. -use crate::strategy::{ - Strategy, - ValueTree, -}; +use crate::strategy::{Strategy, ValueTree}; use crate::test_runner::Config; /// Fake test runner that keeps no state. pub struct TestRunner {} impl TestRunner { - /// Creates new - pub fn new(_: Config) -> Self { Self {} } + pub fn new(_: Config) -> Self { + Self {} + } /// default test runner. - pub fn default() -> Self { Self {} } + pub fn default() -> Self { + Self {} + } /// Run the test function with a Kani symbolic value given a test function that takes that type. pub fn run_kani(strategy: S, test_fn: impl Fn(S::Value)) { @@ -36,5 +36,4 @@ impl TestRunner { let tree = strategy.new_tree(&mut runner).unwrap(); test_fn(tree.current()); } - } From 77f9e60c5132d0d97a204fa0bf16133599a52867 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Tue, 2 Aug 2022 13:19:25 -0400 Subject: [PATCH 45/80] Added license to proptest Cargo.toml --- library/proptest/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/library/proptest/Cargo.toml b/library/proptest/Cargo.toml index 867e9c6736bb..a8b56f6ab892 100644 --- a/library/proptest/Cargo.toml +++ b/library/proptest/Cargo.toml @@ -3,6 +3,7 @@ name = "proptest" version = "0.1.0" edition = "2021" publish = false +license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html From 14bedd8eb965f1666375c53966d19d280573a38b Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Tue, 2 Aug 2022 13:19:54 -0400 Subject: [PATCH 46/80] Fixed clippy warning --- library/proptest/src/test_runner/reason.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/proptest/src/test_runner/reason.rs b/library/proptest/src/test_runner/reason.rs index df991b831cb4..d907ca7a1e39 100644 --- a/library/proptest/src/test_runner/reason.rs +++ b/library/proptest/src/test_runner/reason.rs @@ -27,7 +27,7 @@ impl Reason { /// The message is intended for human consumption, and is not guaranteed to /// have any format in particular. pub fn message(&self) -> &str { - &*self.0 + self.0.as_ref() } } From 0ce21d6e0f86f2d1be05e7d9c4e66320093c2a33 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Tue, 2 Aug 2022 15:50:12 -0400 Subject: [PATCH 47/80] Added license to proptest module. --- library/proptest/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/library/proptest/Cargo.toml b/library/proptest/Cargo.toml index a8b56f6ab892..894794e9ec6a 100644 --- a/library/proptest/Cargo.toml +++ b/library/proptest/Cargo.toml @@ -1,3 +1,6 @@ +# Copyright Kani Contributors +# SPDX-License-Identifier: Apache-2.0 OR MIT + [package] name = "proptest" version = "0.1.0" From 68c1ce0e6358aca234679b0c47eb647660e06221 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 15:21:16 -0400 Subject: [PATCH 48/80] Purged non-basic proptest files. --- .../proptest/src/arbitrary/_alloc/alloc.rs | 59 - .../proptest/src/arbitrary/_alloc/borrow.rs | 29 - .../proptest/src/arbitrary/_alloc/boxed.rs | 21 - library/proptest/src/arbitrary/_alloc/char.rs | 91 -- .../src/arbitrary/_alloc/collections.rs | 286 ----- library/proptest/src/arbitrary/_alloc/hash.rs | 34 - library/proptest/src/arbitrary/_alloc/mod.rs | 24 - library/proptest/src/arbitrary/_alloc/ops.rs | 99 -- library/proptest/src/arbitrary/_alloc/rc.rs | 23 - library/proptest/src/arbitrary/_alloc/str.rs | 51 - library/proptest/src/arbitrary/_alloc/sync.rs | 78 -- library/proptest/src/arbitrary/_core/ascii.rs | 25 - library/proptest/src/arbitrary/_core/cell.rs | 50 - library/proptest/src/arbitrary/_core/cmp.rs | 35 - .../proptest/src/arbitrary/_core/convert.rs | 18 - library/proptest/src/arbitrary/_core/fmt.rs | 20 - library/proptest/src/arbitrary/_core/iter.rs | 175 --- .../proptest/src/arbitrary/_core/marker.rs | 21 - library/proptest/src/arbitrary/_core/mem.rs | 44 - library/proptest/src/arbitrary/_core/mod.rs | 24 - library/proptest/src/arbitrary/_core/num.rs | 57 - .../proptest/src/arbitrary/_core/option.rs | 62 - .../proptest/src/arbitrary/_core/result.rs | 106 -- library/proptest/src/arbitrary/_std/env.rs | 141 --- library/proptest/src/arbitrary/_std/ffi.rs | 102 -- library/proptest/src/arbitrary/_std/fs.rs | 32 - library/proptest/src/arbitrary/_std/io.rs | 166 --- library/proptest/src/arbitrary/_std/mod.rs | 24 - library/proptest/src/arbitrary/_std/net.rs | 119 -- library/proptest/src/arbitrary/_std/panic.rs | 21 - library/proptest/src/arbitrary/_std/path.rs | 25 - library/proptest/src/arbitrary/_std/string.rs | 314 ----- library/proptest/src/arbitrary/_std/sync.rs | 164 --- library/proptest/src/arbitrary/_std/thread.rs | 83 -- library/proptest/src/arbitrary/_std/time.rs | 52 - library/proptest/src/arbitrary/arrays.rs | 40 - library/proptest/src/arbitrary/functor.rs | 216 ---- library/proptest/src/arbitrary/macros.rs | 117 -- library/proptest/src/arbitrary/mod.rs | 69 - library/proptest/src/arbitrary/primitives.rs | 47 - library/proptest/src/arbitrary/sample.rs | 33 - library/proptest/src/arbitrary/traits.rs | 297 ----- library/proptest/src/arbitrary/tuples.rs | 47 - library/proptest/src/bool.rs | 87 -- library/proptest/src/lib.rs | 12 +- library/proptest/src/num.rs | 654 ---------- library/proptest/src/prelude.rs | 52 - library/proptest/src/sugar.rs | 1121 ----------------- library/proptest/src/tuple.rs | 131 -- 49 files changed, 6 insertions(+), 5592 deletions(-) delete mode 100644 library/proptest/src/arbitrary/_alloc/alloc.rs delete mode 100644 library/proptest/src/arbitrary/_alloc/borrow.rs delete mode 100644 library/proptest/src/arbitrary/_alloc/boxed.rs delete mode 100644 library/proptest/src/arbitrary/_alloc/char.rs delete mode 100644 library/proptest/src/arbitrary/_alloc/collections.rs delete mode 100644 library/proptest/src/arbitrary/_alloc/hash.rs delete mode 100644 library/proptest/src/arbitrary/_alloc/mod.rs delete mode 100644 library/proptest/src/arbitrary/_alloc/ops.rs delete mode 100644 library/proptest/src/arbitrary/_alloc/rc.rs delete mode 100644 library/proptest/src/arbitrary/_alloc/str.rs delete mode 100644 library/proptest/src/arbitrary/_alloc/sync.rs delete mode 100644 library/proptest/src/arbitrary/_core/ascii.rs delete mode 100644 library/proptest/src/arbitrary/_core/cell.rs delete mode 100644 library/proptest/src/arbitrary/_core/cmp.rs delete mode 100644 library/proptest/src/arbitrary/_core/convert.rs delete mode 100644 library/proptest/src/arbitrary/_core/fmt.rs delete mode 100644 library/proptest/src/arbitrary/_core/iter.rs delete mode 100644 library/proptest/src/arbitrary/_core/marker.rs delete mode 100644 library/proptest/src/arbitrary/_core/mem.rs delete mode 100644 library/proptest/src/arbitrary/_core/mod.rs delete mode 100644 library/proptest/src/arbitrary/_core/num.rs delete mode 100644 library/proptest/src/arbitrary/_core/option.rs delete mode 100644 library/proptest/src/arbitrary/_core/result.rs delete mode 100644 library/proptest/src/arbitrary/_std/env.rs delete mode 100644 library/proptest/src/arbitrary/_std/ffi.rs delete mode 100644 library/proptest/src/arbitrary/_std/fs.rs delete mode 100644 library/proptest/src/arbitrary/_std/io.rs delete mode 100644 library/proptest/src/arbitrary/_std/mod.rs delete mode 100644 library/proptest/src/arbitrary/_std/net.rs delete mode 100644 library/proptest/src/arbitrary/_std/panic.rs delete mode 100644 library/proptest/src/arbitrary/_std/path.rs delete mode 100644 library/proptest/src/arbitrary/_std/string.rs delete mode 100644 library/proptest/src/arbitrary/_std/sync.rs delete mode 100644 library/proptest/src/arbitrary/_std/thread.rs delete mode 100644 library/proptest/src/arbitrary/_std/time.rs delete mode 100644 library/proptest/src/arbitrary/arrays.rs delete mode 100644 library/proptest/src/arbitrary/functor.rs delete mode 100644 library/proptest/src/arbitrary/macros.rs delete mode 100644 library/proptest/src/arbitrary/mod.rs delete mode 100644 library/proptest/src/arbitrary/primitives.rs delete mode 100644 library/proptest/src/arbitrary/sample.rs delete mode 100644 library/proptest/src/arbitrary/traits.rs delete mode 100644 library/proptest/src/arbitrary/tuples.rs delete mode 100644 library/proptest/src/bool.rs delete mode 100644 library/proptest/src/num.rs delete mode 100644 library/proptest/src/prelude.rs delete mode 100644 library/proptest/src/sugar.rs delete mode 100644 library/proptest/src/tuple.rs diff --git a/library/proptest/src/arbitrary/_alloc/alloc.rs b/library/proptest/src/arbitrary/_alloc/alloc.rs deleted file mode 100644 index 80172cda9975..000000000000 --- a/library/proptest/src/arbitrary/_alloc/alloc.rs +++ /dev/null @@ -1,59 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::hash`. - -use core::cmp; -use core::ops::Range; -use core::usize; - -multiplex_alloc!(::alloc::alloc, ::std::alloc); - -use crate::arbitrary::*; -use crate::strategy::statics::static_map; -use crate::strategy::*; - -arbitrary!(self::alloc::Global; self::alloc::Global); - -// Not Debug. -//lazy_just!(System, || System); - -arbitrary!(self::alloc::Layout, SFnPtrMap<(Range, StrategyFor), Self>; - // 1. align must be a power of two and <= (1 << 31): - // 2. "when rounded up to the nearest multiple of align, must not overflow". - static_map((0u8..32u8, any::()), |(align_power, size)| { - let align = 1usize << align_power; - let max_size = 0usize.wrapping_sub(align); - // Not quite a uniform distribution due to clamping, - // but probably good enough - self::alloc::Layout::from_size_align(cmp::min(max_size, size), align).unwrap() - }) -); - -arbitrary!(self::alloc::AllocError, Just; Just(self::alloc::AllocError)); -/* 2018-07-28 CollectionAllocErr is not currently available outside of using - * the `alloc` crate, which would require a different nightly feature. For now, - * disable. -arbitrary!(alloc::collections::CollectionAllocErr, TupleUnion<(WA>, WA>)>; - prop_oneof![Just(alloc::collections::CollectionAllocErr::AllocErr), - Just(alloc::collections::CollectionAllocErr::CapacityOverflow)]); - */ - -#[cfg(test)] -mod test { - multiplex_alloc!(::alloc::alloc, ::std::alloc); - - no_panic_test!( - layout => self::alloc::Layout, - alloc_err => self::alloc::AllocErr - //collection_alloc_err => alloc::collections::CollectionAllocErr - ); -} diff --git a/library/proptest/src/arbitrary/_alloc/borrow.rs b/library/proptest/src/arbitrary/_alloc/borrow.rs deleted file mode 100644 index 8c3de0aceaa5..000000000000 --- a/library/proptest/src/arbitrary/_alloc/borrow.rs +++ /dev/null @@ -1,29 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for std::borrow. - -use crate::std_facade::fmt; -use crate::std_facade::{Cow, ToOwned}; -use core::borrow::Borrow; - -use crate::arbitrary::{any_with, Arbitrary, SMapped}; -use crate::strategy::statics::static_map; - -arbitrary!( - [A: Arbitrary + Borrow, B: ToOwned + fmt::Debug + ?Sized] - Cow<'static, B>, SMapped, A::Parameters; - args => static_map(any_with::(args), Cow::Owned) -); - -lift1!([Borrow + 'static, B: ToOwned + fmt::Debug + ?Sized] - Cow<'static, B>; base => static_map(base, Cow::Owned) -); diff --git a/library/proptest/src/arbitrary/_alloc/boxed.rs b/library/proptest/src/arbitrary/_alloc/boxed.rs deleted file mode 100644 index 914d7d761444..000000000000 --- a/library/proptest/src/arbitrary/_alloc/boxed.rs +++ /dev/null @@ -1,21 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::boxed`. - -use crate::std_facade::Box; - -wrap_from!(Box); - -#[cfg(test)] -mod test { - no_panic_test!(boxed => Box); -} diff --git a/library/proptest/src/arbitrary/_alloc/char.rs b/library/proptest/src/arbitrary/_alloc/char.rs deleted file mode 100644 index 95607425973f..000000000000 --- a/library/proptest/src/arbitrary/_alloc/char.rs +++ /dev/null @@ -1,91 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::char`. - -use crate::std_facade::Vec; -use core::char::*; -use core::iter::once; -use core::ops::Range; - -use crate::collection::vec; - -multiplex_alloc! { - core::char::DecodeUtf16, std::char::DecodeUtf16, - core::char::DecodeUtf16Error, std::char::DecodeUtf16Error, - core::char::decode_utf16, std::char::decode_utf16 -} - -const VEC_MAX: usize = ::core::u16::MAX as usize; - -use crate::arbitrary::*; -use crate::strategy::statics::static_map; -use crate::strategy::*; - -macro_rules! impl_wrap_char { - ($type: ty, $mapper: expr) => { - arbitrary!($type, SMapped; - static_map(any::(), $mapper)); - }; -} - -impl_wrap_char!(EscapeDebug, char::escape_debug); -impl_wrap_char!(EscapeDefault, char::escape_default); -impl_wrap_char!(EscapeUnicode, char::escape_unicode); -#[cfg(feature = "unstable")] -impl_wrap_char!(ToLowercase, char::to_lowercase); -#[cfg(feature = "unstable")] -impl_wrap_char!(ToUppercase, char::to_uppercase); - -#[cfg(feature = "break-dead-code")] -arbitrary!(DecodeUtf16< as IntoIterator>::IntoIter>, - SMapped, Self>; - static_map(vec(any::(), ..VEC_MAX), decode_utf16) -); - -arbitrary!(ParseCharError, IndFlatten>>; - any::().prop_ind_flat_map(|is_two| - Just((if is_two { "__" } else { "" }).parse::().unwrap_err())) -); - -#[cfg(feature = "unstable")] -arbitrary!(CharTryFromError; { - use core::convert::TryFrom; - char::try_from(0xD800 as u32).unwrap_err() -}); - -arbitrary!(DecodeUtf16Error, SFnPtrMap, Self>; - static_map(0xD800..0xE000, |x| - decode_utf16(once(x)).next().unwrap().unwrap_err()) -); - -#[cfg(test)] -mod test { - no_panic_test!( - escape_debug => EscapeDebug, - escape_default => EscapeDefault, - escape_unicode => EscapeUnicode, - parse_char_error => ParseCharError, - decode_utf16_error => DecodeUtf16Error - ); - - #[cfg(feature = "break-dead-code")] - no_panic_test!( - decode_utf16 => DecodeUtf16< as IntoIterator>::IntoIter> - ); - - #[cfg(feature = "unstable")] - no_panic_test!( - to_lowercase => ToLowercase, - to_uppercase => ToUppercase, - char_try_from_error => CharTryFromError - ); -} diff --git a/library/proptest/src/arbitrary/_alloc/collections.rs b/library/proptest/src/arbitrary/_alloc/collections.rs deleted file mode 100644 index 9c84ed568d1a..000000000000 --- a/library/proptest/src/arbitrary/_alloc/collections.rs +++ /dev/null @@ -1,286 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::collections`. - -//#![cfg_attr(feature="cargo-clippy", allow(implicit_hasher))] - -//============================================================================== -// Imports: -//============================================================================== - -use crate::std_facade::{ - binary_heap, btree_map, btree_set, fmt, linked_list, vec, vec_deque, Arc, BTreeMap, BTreeSet, - BinaryHeap, Box, LinkedList, Rc, Vec, VecDeque, -}; -use core::hash::Hash; -use core::ops::{Bound, RangeInclusive}; - -#[cfg(feature = "std")] -use crate::std_facade::{hash_map, hash_set, HashMap, HashSet}; - -use crate::arbitrary::*; -use crate::collection::*; -use crate::strategy::statics::static_map; -use crate::strategy::*; - -//============================================================================== -// Macros: -//============================================================================== - -/// Parameters for configuring the generation of `StrategyFor<...>`. -type RangedParams1 = product_type![SizeRange, A]; - -/// Parameters for configuring the generation of `StrategyFor<...>`. -type RangedParams2 = product_type![SizeRange, A, B]; - -macro_rules! impl_1 { - ($typ: ident, $strat: ident, $($bound : path),* => $fun: ident) => { - arbitrary!([A: Arbitrary $(+ $bound)*] $typ, - $strat, RangedParams1; - args => { - let product_unpack![range, a] = args; - $fun(any_with::(a), range) - }); - - lift1!([$($bound+)*] $typ, SizeRange; - base, args => $fun(base, args)); - }; -} - -arbitrary!(SizeRange, MapInto>, Self>; - any::>().prop_map_into() -); - -//============================================================================== -// Vec, VecDeque, LinkedList, BTreeSet, BinaryHeap, HashSet, HashMap: -//============================================================================== - -macro_rules! dst_wrapped { - ($($w: ident),*) => { - $(arbitrary!([A: Arbitrary] $w<[A]>, - MapInto>, Self>, - as Arbitrary>::Parameters; - a => any_with::>(a).prop_map_into() - );)* - }; -} - -impl_1!(Vec, VecStrategy, => vec); -dst_wrapped!(Box, Rc, Arc); -impl_1!(VecDeque, VecDequeStrategy, => vec_deque); -impl_1!(LinkedList, LinkedListStrategy, => linked_list); -impl_1!(BTreeSet, BTreeSetStrategy, Ord => btree_set); -impl_1!(BinaryHeap, BinaryHeapStrategy, Ord => binary_heap); -#[cfg(feature = "std")] -impl_1!(HashSet, HashSetStrategy, Hash, Eq => hash_set); - -//============================================================================== -// IntoIterator: -//============================================================================== - -macro_rules! into_iter_1 { - ($module: ident, $type: ident $(, $bound : path)*) => { - arbitrary!([A: Arbitrary $(+ $bound)*] - $module::IntoIter, - SMapped<$type, Self>, - <$type as Arbitrary>::Parameters; - args => static_map(any_with::<$type>(args), $type::into_iter)); - - lift1!(['static + $($bound+)*] $module::IntoIter, SizeRange; - base, args => - $module(base, args).prop_map($type::into_iter)); - }; -} - -into_iter_1!(vec, Vec); -into_iter_1!(vec_deque, VecDeque); -into_iter_1!(linked_list, LinkedList); -into_iter_1!(btree_set, BTreeSet, Ord); -into_iter_1!(binary_heap, BinaryHeap, Ord); -#[cfg(feature = "std")] -into_iter_1!(hash_set, HashSet, Hash, Eq); - -//============================================================================== -// HashMap: -//============================================================================== - -#[cfg(feature = "std")] -arbitrary!([A: Arbitrary + Hash + Eq, B: Arbitrary] HashMap, -HashMapStrategy, -RangedParams2; -args => { - let product_unpack![range, a, b] = args; - hash_map(any_with::(a), any_with::(b), range) -}); - -#[cfg(feature = "std")] -arbitrary!([A: Arbitrary + Hash + Eq, B: Arbitrary] hash_map::IntoIter, - SMapped, Self>, - as Arbitrary>::Parameters; - args => static_map(any_with::>(args), HashMap::into_iter)); - -#[cfg(feature = "std")] -lift1!([, K: Hash + Eq + Arbitrary + 'static] HashMap, - RangedParams1; - base, args => { - let product_unpack![range, k] = args; - hash_map(any_with::(k), base, range) - } -); - -#[cfg(feature = "std")] -lift1!(['static, K: Hash + Eq + Arbitrary + 'static] hash_map::IntoIter, - RangedParams1; - base, args => { - let product_unpack![range, k] = args; - static_map(hash_map(any_with::(k), base, range), HashMap::into_iter) - } -); - -#[cfg(feature = "std")] -impl functor::ArbitraryF2 for HashMap { - type Parameters = SizeRange; - - fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) -> BoxedStrategy - where - AS: Strategy + 'static, - BS: Strategy + 'static, - { - hash_map(fst, snd, args).boxed() - } -} - -#[cfg(feature = "std")] -impl functor::ArbitraryF2 - for hash_map::IntoIter -{ - type Parameters = SizeRange; - - fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) -> BoxedStrategy - where - AS: Strategy + 'static, - BS: Strategy + 'static, - { - static_map(hash_map(fst, snd, args), HashMap::into_iter).boxed() - } -} - -//============================================================================== -// BTreeMap: -//============================================================================== - -arbitrary!([A: Arbitrary + Ord, B: Arbitrary] BTreeMap, -BTreeMapStrategy, -RangedParams2; -args => { - let product_unpack![range, a, b] = args; - btree_map(any_with::(a), any_with::(b), range) -}); - -lift1!([, K: Ord + Arbitrary + 'static] BTreeMap, - RangedParams1; - base, args => { - let product_unpack![range, k] = args; - btree_map(any_with::(k), base, range) - } -); - -impl functor::ArbitraryF2 for BTreeMap { - type Parameters = SizeRange; - fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) -> BoxedStrategy - where - AS: Strategy + 'static, - BS: Strategy + 'static, - { - btree_map(fst, snd, args).boxed() - } -} - -arbitrary!([A: Arbitrary + Ord, B: Arbitrary] btree_map::IntoIter, - SMapped, Self>, - as Arbitrary>::Parameters; - args => static_map(any_with::>(args), BTreeMap::into_iter)); - -impl functor::ArbitraryF2 - for btree_map::IntoIter -{ - type Parameters = SizeRange; - - fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) -> BoxedStrategy - where - AS: Strategy + 'static, - BS: Strategy + 'static, - { - static_map(btree_map(fst, snd, args), BTreeMap::into_iter).boxed() - } -} - -//============================================================================== -// Bound: -//============================================================================== - -arbitrary!([A: Arbitrary] Bound, - TupleUnion<( - WA, Self>>, - WA, Self>>, - WA> - )>, - A::Parameters; - args => { - let base = Arc::new(any_with::(args)); - prop_oneof![ - 2 => static_map(base.clone(), Bound::Included), - 2 => static_map(base, Bound::Excluded), - 1 => LazyJust::new(|| Bound::Unbounded), - ] - } -); - -lift1!(['static] Bound; base => { - let base = Rc::new(base); - prop_oneof![ - 2 => base.clone().prop_map(Bound::Included), - 2 => base.prop_map(Bound::Excluded), - 1 => LazyJustFn::new(|| Bound::Unbounded), - ] -}); - -#[cfg(test)] -mod test { - no_panic_test!( - size_bounds => SizeRange, - vec => Vec, - box_slice => Box<[u8]>, - rc_slice => Rc<[u8]>, - arc_slice => Arc<[u8]>, - vec_deque => VecDeque, - linked_list => LinkedList, - btree_set => BTreeSet, - btree_map => BTreeMap, - bound => Bound, - binary_heap => BinaryHeap, - into_iter_vec => vec::IntoIter, - into_iter_vec_deque => vec_deque::IntoIter, - into_iter_linked_list => linked_list::IntoIter, - into_iter_binary_heap => binary_heap::IntoIter, - into_iter_btree_set => btree_set::IntoIter, - into_iter_btree_map => btree_map::IntoIter - ); - - #[cfg(feature = "std")] - no_panic_test!( - hash_set => HashSet, - hash_map => HashMap, - into_iter_hash_set => hash_set::IntoIter, - into_iter_hash_map => hash_map::IntoIter - ); -} diff --git a/library/proptest/src/arbitrary/_alloc/hash.rs b/library/proptest/src/arbitrary/_alloc/hash.rs deleted file mode 100644 index 6f0cde280ab1..000000000000 --- a/library/proptest/src/arbitrary/_alloc/hash.rs +++ /dev/null @@ -1,34 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::hash`. - -#[cfg(feature = "std")] -use crate::std_facade::hash_map::{DefaultHasher, RandomState}; -use core::hash::{BuildHasherDefault, Hasher}; - -// NOTE: don't impl for std::hash::SipHasher.. since deprecated! - -// over-constrain on purpose! -arbitrary!([H: Default + Hasher] BuildHasherDefault; Default::default()); - -#[cfg(feature = "std")] -lazy_just!(DefaultHasher, Default::default; RandomState, Default::default); - -#[cfg(test)] -mod test { - #[cfg(feature = "std")] - no_panic_test!( - default_hasher => DefaultHasher, - random_state => RandomState, - build_hasher_default => BuildHasherDefault - ); -} diff --git a/library/proptest/src/arbitrary/_alloc/mod.rs b/library/proptest/src/arbitrary/_alloc/mod.rs deleted file mode 100644 index 4abcbba1e538..000000000000 --- a/library/proptest/src/arbitrary/_alloc/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for liballoc. - -#[cfg(feature = "unstable")] -mod alloc; -mod borrow; -mod boxed; -mod char; -mod collections; -mod hash; -mod ops; -mod rc; -mod str; -mod sync; diff --git a/library/proptest/src/arbitrary/_alloc/ops.rs b/library/proptest/src/arbitrary/_alloc/ops.rs deleted file mode 100644 index 1d7469e5450b..000000000000 --- a/library/proptest/src/arbitrary/_alloc/ops.rs +++ /dev/null @@ -1,99 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::ops`. - -use crate::std_facade::Arc; -use core::ops::*; - -use crate::arbitrary::*; -use crate::strategy::statics::static_map; -use crate::strategy::*; - -arbitrary!(RangeFull; ..); -wrap_ctor!(RangeFrom, |a| a..); -wrap_ctor!(RangeTo, |a| ..a); - -wrap_ctor!(RangeToInclusive, |a| ..=a); - -arbitrary!( - [A: PartialOrd + Arbitrary] RangeInclusive, - SMapped<(A, A), Self>, product_type![A::Parameters, A::Parameters]; - args => static_map(any_with::<(A, A)>(args), - |(a, b)| if b < a { b..=a } else { a..=b }) -); - -lift1!([PartialOrd] RangeInclusive; base => { - let base = Arc::new(base); - (base.clone(), base).prop_map(|(a, b)| if b < a { b..=a } else { a..=b }) -}); - -arbitrary!( - [A: PartialOrd + Arbitrary] Range, - SMapped<(A, A), Self>, product_type![A::Parameters, A::Parameters]; - args => static_map(any_with::<(A, A)>(args), - |(a, b)| if b < a { b..a } else { a..b }) -); - -lift1!([PartialOrd] Range; base => { - let base = Arc::new(base); - (base.clone(), base).prop_map(|(a, b)| if b < a { b..a } else { a..b }) -}); - -#[cfg(feature = "unstable")] -arbitrary!( - [Y: Arbitrary, R: Arbitrary] GeneratorState, - TupleUnion<(WA>, WA>)>, - product_type![Y::Parameters, R::Parameters]; - args => { - let product_unpack![y, r] = args; - prop_oneof![ - static_map(any_with::(y), GeneratorState::Yielded), - static_map(any_with::(r), GeneratorState::Complete) - ] - } -); - -#[cfg(feature = "unstable")] -use core::fmt; - -#[cfg(feature = "unstable")] -impl functor::ArbitraryF2 - for GeneratorState -{ - type Parameters = (); - - fn lift2_with(fst: AS, snd: BS, _args: Self::Parameters) -> BoxedStrategy - where - AS: Strategy + 'static, - BS: Strategy + 'static, - { - prop_oneof![fst.prop_map(GeneratorState::Yielded), snd.prop_map(GeneratorState::Complete)] - .boxed() - } -} - -#[cfg(test)] -mod test { - no_panic_test!( - range_full => RangeFull, - range_from => RangeFrom, - range_to => RangeTo, - range => Range, - range_inclusive => RangeInclusive, - range_to_inclusive => RangeToInclusive - ); - - #[cfg(feature = "unstable")] - no_panic_test!( - generator_state => GeneratorState - ); -} diff --git a/library/proptest/src/arbitrary/_alloc/rc.rs b/library/proptest/src/arbitrary/_alloc/rc.rs deleted file mode 100644 index cd426da7dc7c..000000000000 --- a/library/proptest/src/arbitrary/_alloc/rc.rs +++ /dev/null @@ -1,23 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::rc`. - -use crate::std_facade::Rc; - -// Weak would always give None on upgrade since there's no owned Rc. - -wrap_from!(Rc); - -#[cfg(test)] -mod test { - no_panic_test!(rc => Rc); -} diff --git a/library/proptest/src/arbitrary/_alloc/str.rs b/library/proptest/src/arbitrary/_alloc/str.rs deleted file mode 100644 index d3c82fccc9fd..000000000000 --- a/library/proptest/src/arbitrary/_alloc/str.rs +++ /dev/null @@ -1,51 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::str`. - -use crate::std_facade::Vec; -use core::iter::repeat; -use core::str::{from_utf8, ParseBoolError, Utf8Error}; - -use crate::arbitrary::*; -use crate::strategy::statics::static_map; -use crate::strategy::*; - -arbitrary!(ParseBoolError; "".parse::().unwrap_err()); - -type ELSeq = WA>; -type ELSeqs = TupleUnion<(ELSeq, ELSeq, ELSeq, ELSeq)>; - -fn gen_el_seqs() -> ELSeqs { - prop_oneof![ - Just(&[0xC2]), // None - Just(&[0x80]), // Some(1) - Just(&[0xE0, 0xA0, 0x00]), // Some(2) - Just(&[0xF0, 0x90, 0x80, 0x00]) // Some(3) - ] -} - -arbitrary!(Utf8Error, SFnPtrMap<(StrategyFor, ELSeqs), Utf8Error>; - static_map((any::(), gen_el_seqs()), |(vut, elseq)| { - let v = repeat(b'_').take(vut as usize) - .chain(elseq.iter().cloned()) - .collect::>(); - from_utf8(&v).unwrap_err() - }) -); - -#[cfg(test)] -mod test { - no_panic_test!( - parse_bool_errror => ParseBoolError, - utf8_error => Utf8Error - ); -} diff --git a/library/proptest/src/arbitrary/_alloc/sync.rs b/library/proptest/src/arbitrary/_alloc/sync.rs deleted file mode 100644 index 8ff686cb9c74..000000000000 --- a/library/proptest/src/arbitrary/_alloc/sync.rs +++ /dev/null @@ -1,78 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::sync`. - -use crate::std_facade::Arc; -use core::sync::atomic::*; - -use crate::arbitrary::*; -use crate::strategy::statics::static_map; -use crate::strategy::*; - -wrap_from!(Arc); - -macro_rules! atomic { - ($($type: ident, $base: ty);+) => { - $(arbitrary!($type, SMapped<$base, Self>; - static_map(any::<$base>(), $type::new) - );)+ - }; -} - -// impl_wrap_gen!(AtomicPtr); // We don't have impl Arbitrary for *mut T yet. -atomic!(AtomicBool, bool; AtomicIsize, isize; AtomicUsize, usize); - -#[cfg(feature = "unstable")] -atomic!(AtomicI8, i8; AtomicI16, i16; AtomicI32, i32; - AtomicU8, u8; AtomicU16, u16; AtomicU32, u32); - -#[cfg(all(feature = "unstable", feature = "atomic64bit"))] -atomic!(AtomicI64, i64; AtomicU64, u64); - -arbitrary!(Ordering, - TupleUnion<(WA>, WA>, WA>, - WA>, WA>)>; - prop_oneof![ - Just(Ordering::Relaxed), - Just(Ordering::Release), - Just(Ordering::Acquire), - Just(Ordering::AcqRel), - Just(Ordering::SeqCst) - ] -); - -#[cfg(test)] -mod test { - no_panic_test!( - arc => Arc, - atomic_bool => AtomicBool, - atomic_isize => AtomicIsize, - atomic_usize => AtomicUsize, - ordering => Ordering - ); - - #[cfg(feature = "unstable")] - no_panic_test!( - atomic_i8 => AtomicI8, - atomic_i16 => AtomicI16, - atomic_i32 => AtomicI32, - atomic_u8 => AtomicU8, - atomic_u16 => AtomicU16, - atomic_u32 => AtomicU32 - ); - - #[cfg(all(feature = "unstable", feature = "atomic64bit"))] - no_panic_test!( - atomic_i64 => AtomicI64, - atomic_u64 => AtomicU64 - ); -} diff --git a/library/proptest/src/arbitrary/_core/ascii.rs b/library/proptest/src/arbitrary/_core/ascii.rs deleted file mode 100644 index 2fd8093f40f6..000000000000 --- a/library/proptest/src/arbitrary/_core/ascii.rs +++ /dev/null @@ -1,25 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::ascii`. - -use core::ascii::{escape_default, EscapeDefault}; - -use crate::arbitrary::*; -use crate::strategy::statics::static_map; - -arbitrary!(EscapeDefault, SMapped; - static_map(any::(), escape_default)); - -#[cfg(test)] -mod test { - no_panic_test!(escape_default => EscapeDefault); -} diff --git a/library/proptest/src/arbitrary/_core/cell.rs b/library/proptest/src/arbitrary/_core/cell.rs deleted file mode 100644 index b3e2f69875cb..000000000000 --- a/library/proptest/src/arbitrary/_core/cell.rs +++ /dev/null @@ -1,50 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::cell`. - -use core::cell::{BorrowError, BorrowMutError, Cell, RefCell, UnsafeCell}; - -wrap_from!([Copy] Cell); -wrap_from!(RefCell); -wrap_from!(UnsafeCell); - -lazy_just!(BorrowError, || { - // False positive: - #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))] - { - let _rc = RefCell::new(()); - let _bm = _rc.borrow_mut(); - let _tb = _rc.try_borrow(); - let ret = _rc.try_borrow().expect_err("reborrowed RefCell"); - ret - } -}); -lazy_just!(BorrowMutError, || { - // False positive: - #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))] - { - let _rc = RefCell::new(()); - let _bm = _rc.borrow_mut(); - let _tb = _rc.try_borrow(); - let ret = _rc.try_borrow_mut().expect_err("reborrowed RefCell"); - ret - } -}); - -#[cfg(test)] -mod test { - no_panic_test!( - cell => Cell, - ref_cell => RefCell, - unsafe_cell => UnsafeCell - ); -} diff --git a/library/proptest/src/arbitrary/_core/cmp.rs b/library/proptest/src/arbitrary/_core/cmp.rs deleted file mode 100644 index fafe9778919b..000000000000 --- a/library/proptest/src/arbitrary/_core/cmp.rs +++ /dev/null @@ -1,35 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::cmp`. - -use core::cmp::{Ordering, Reverse}; - -use crate::strategy::{Just, TupleUnion, WA}; - -wrap_ctor!(Reverse, Reverse); - -type WAJO = WA>; -arbitrary!(Ordering, TupleUnion<(WAJO, WAJO, WAJO)>; - prop_oneof![ - Just(Ordering::Equal), - Just(Ordering::Less), - Just(Ordering::Greater) - ] -); - -#[cfg(test)] -mod test { - no_panic_test!( - reverse => Reverse, - ordering => Ordering - ); -} diff --git a/library/proptest/src/arbitrary/_core/convert.rs b/library/proptest/src/arbitrary/_core/convert.rs deleted file mode 100644 index 24736c9ce286..000000000000 --- a/library/proptest/src/arbitrary/_core/convert.rs +++ /dev/null @@ -1,18 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::convert`. - -// No sensible Arbitrary impl exists for void-like types like -// std::convert::Infallible. -// -// Auto-deriving should take care to simply not include such -// types in generation instead! diff --git a/library/proptest/src/arbitrary/_core/fmt.rs b/library/proptest/src/arbitrary/_core/fmt.rs deleted file mode 100644 index e2b9dc93bd4c..000000000000 --- a/library/proptest/src/arbitrary/_core/fmt.rs +++ /dev/null @@ -1,20 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::fmt`. - -use core::fmt::Error; -arbitrary!(Error; Error); - -#[cfg(test)] -mod test { - no_panic_test!(error => Error); -} diff --git a/library/proptest/src/arbitrary/_core/iter.rs b/library/proptest/src/arbitrary/_core/iter.rs deleted file mode 100644 index d208de35bfa8..000000000000 --- a/library/proptest/src/arbitrary/_core/iter.rs +++ /dev/null @@ -1,175 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::iter`. - -use core::fmt; -use core::iter::Fuse; -use core::iter::*; - -use crate::arbitrary::*; -use crate::strategy::statics::static_map; -use crate::strategy::*; - -// TODO: Filter, FilterMap, FlatMap, Map, Inspect, Scan, SkipWhile -// Might be possible with CoArbitrary - -wrap_ctor!(Once, once); -wrap_ctor!([Clone] Repeat, repeat); -wrap_ctor!([Iterator + Clone] Cycle, Iterator::cycle); -wrap_ctor!([Iterator] Enumerate, Iterator::enumerate); -wrap_ctor!([Iterator] Fuse, Iterator::fuse); -wrap_ctor!([Iterator, T: fmt::Debug] Peekable, Iterator::peekable); -wrap_ctor!([DoubleEndedIterator] Rev, Iterator::rev); - -arbitrary!(['a, T: 'a + Clone, A: Arbitrary + Iterator] - Cloned, SMapped, A::Parameters; - args => static_map(any_with::(args), Iterator::cloned)); - -impl> - functor::ArbitraryF1 for Cloned -{ - type Parameters = (); - - fn lift1_with(base: S, _args: Self::Parameters) -> BoxedStrategy - where - S: Strategy + 'static, - { - base.prop_map(Iterator::cloned).boxed() - } -} - -arbitrary!([A] Empty; empty()); - -arbitrary!( - [A: Arbitrary + Iterator, B: Arbitrary + Iterator] - Zip, SMapped<(A, B), Self>, - product_type![A::Parameters, B::Parameters]; - args => static_map(any_with::<(A, B)>(args), |(a, b)| a.zip(b)) -); - -lift1!( - [fmt::Debug + 'static + Iterator, B: 'static + Arbitrary + Iterator] - Zip, - B::Parameters; - base, args => - (any_with::(args), base).prop_map(|(b, a)| b.zip(a)).boxed() -); - -impl functor::ArbitraryF2 for Zip { - type Parameters = (); - - fn lift2_with(fst: AS, snd: BS, _args: Self::Parameters) -> BoxedStrategy - where - AS: Strategy + 'static, - BS: Strategy + 'static, - { - (fst, snd).prop_map(|(a, b)| a.zip(b)).boxed() - } -} - -arbitrary!( - [T, - A: Arbitrary + Iterator, - B: Arbitrary + Iterator] - Chain, SMapped<(A, B), Self>, - product_type![A::Parameters, B::Parameters]; - args => static_map(any_with::<(A, B)>(args), |(a, b)| a.chain(b)) -); - -lift1!([fmt::Debug + 'static + Iterator, - B: 'static + Arbitrary + Iterator, - T] - Chain, - B::Parameters; - base, args => - (any_with::(args), base).prop_map(|(b, a)| b.chain(a)).boxed() -); - -impl, B: fmt::Debug + Iterator> - functor::ArbitraryF2 for Chain -{ - type Parameters = (); - - fn lift2_with(fst: AS, snd: BS, _args: Self::Parameters) -> BoxedStrategy - where - AS: Strategy + 'static, - BS: Strategy + 'static, - { - (fst, snd).prop_map(|(a, b)| a.chain(b)).boxed() - } -} - -macro_rules! usize_mod { - ($type: ident, $mapper: ident) => { - arbitrary!([A: Arbitrary + Iterator] $type, - SMapped<(A, usize), Self>, A::Parameters; - a => static_map( - any_with::<(A, usize)>(product_pack![a, ()]), - |(a, b)| a.$mapper(b) - ) - ); - - lift1!([Iterator] $type; - base => (base, any::()).prop_map(|(a, b)| a.$mapper(b)) - ); - }; -} - -usize_mod!(Skip, skip); -usize_mod!(Take, take); - -#[cfg(feature = "unstable")] -usize_mod!(StepBy, step_by); - -#[cfg(test)] -mod test { - use super::*; - - use std::ops::Range; - const DUMMY: &'static [u8] = &[0, 1, 2, 3, 4]; - #[derive(Debug)] - struct Dummy(u8); - arbitrary!(Dummy, SFnPtrMap, Self>; static_map(0..5, Dummy)); - impl Iterator for Dummy { - type Item = &'static u8; - fn next(&mut self) -> Option { - if self.0 < 5 { - let r = &DUMMY[self.0 as usize]; - self.0 += 1; - Some(r) - } else { - None - } - } - } - - no_panic_test!( - empty => Empty, - once => Once, - repeat => Repeat, - cloned => Cloned, - cycle => Cycle>, - enumerate => Enumerate>, - fuse => Fuse>, - peekable => Peekable>, - rev => Rev<::std::vec::IntoIter>, - zip => Zip, Repeat>, - chain => Chain, Once>, - skip => Skip>, - take => Take> - ); - - #[cfg(feature = "unstable")] - no_panic_test!( - step_by => StepBy> - ); -} diff --git a/library/proptest/src/arbitrary/_core/marker.rs b/library/proptest/src/arbitrary/_core/marker.rs deleted file mode 100644 index b51761148a43..000000000000 --- a/library/proptest/src/arbitrary/_core/marker.rs +++ /dev/null @@ -1,21 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::marker`. - -use core::marker::PhantomData; - -arbitrary!([T: ?Sized] PhantomData; PhantomData); - -#[cfg(test)] -mod test { - no_panic_test!(phantom_data => PhantomData); -} diff --git a/library/proptest/src/arbitrary/_core/mem.rs b/library/proptest/src/arbitrary/_core/mem.rs deleted file mode 100644 index bfb13578afb0..000000000000 --- a/library/proptest/src/arbitrary/_core/mem.rs +++ /dev/null @@ -1,44 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::mem`. - -use core::mem::*; - -use crate::arbitrary::*; -use crate::strategy::statics::static_map; - -arbitrary!([A: Arbitrary] Discriminant, - SMapped, A::Parameters; - args => static_map(any_with::(args), |x| discriminant(&x)) -); - -lift1!(['static] Discriminant; - base => static_map(base, |x| discriminant(&x)) -); - -// Not supported at the moment since the user won't be able to call -// https://doc.rust-lang.org/nightly/std/mem/union.ManuallyDrop.html#method.drop -// in any case so the use case is not great for this. -//wrap_ctor!(ManuallyDrop); - -#[cfg(test)] -mod test { - #[derive(Copy, Clone, Debug)] - struct DummyStruct; - arbitrary!(DummyStruct; DummyStruct); - - no_panic_test!( - //manually_drop => ManuallyDrop, // Trivial destructor. - discriminant_struct => Discriminant, - discriminant_enum => Discriminant<::std::num::FpCategory> - ); -} diff --git a/library/proptest/src/arbitrary/_core/mod.rs b/library/proptest/src/arbitrary/_core/mod.rs deleted file mode 100644 index 40c102295198..000000000000 --- a/library/proptest/src/arbitrary/_core/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for libcore. - -mod ascii; -mod cell; -mod cmp; -mod convert; -mod fmt; -mod iter; -mod marker; -mod mem; -mod num; -mod option; -mod result; diff --git a/library/proptest/src/arbitrary/_core/num.rs b/library/proptest/src/arbitrary/_core/num.rs deleted file mode 100644 index bb496d278fbe..000000000000 --- a/library/proptest/src/arbitrary/_core/num.rs +++ /dev/null @@ -1,57 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::num`. - -use core::num::*; - -use crate::strategy::*; - -arbitrary!(ParseFloatError; "".parse::().unwrap_err()); -arbitrary!(ParseIntError; "".parse::().unwrap_err()); - -#[cfg(feature = "unstable")] -arbitrary!(TryFromIntError; { - use core::convert::TryFrom; - u8::try_from(-1).unwrap_err() -}); - -wrap_ctor!(Wrapping, Wrapping); - -arbitrary!(FpCategory, - TupleUnion<(WA>, WA>, WA>, - WA>, WA>)>; - { - use core::num::FpCategory::*; - prop_oneof![ - Just(Nan), - Just(Infinite), - Just(Zero), - Just(Subnormal), - Just(Normal), - ] - } -); - -#[cfg(test)] -mod test { - no_panic_test!( - parse_float_error => ParseFloatError, - parse_int_error => ParseIntError, - wrapping => Wrapping, - fp_category => FpCategory - ); - - #[cfg(feature = "unstable")] - no_panic_test!( - try_from_int_error => TryFromIntError - ); -} diff --git a/library/proptest/src/arbitrary/_core/option.rs b/library/proptest/src/arbitrary/_core/option.rs deleted file mode 100644 index 7bb2832620ee..000000000000 --- a/library/proptest/src/arbitrary/_core/option.rs +++ /dev/null @@ -1,62 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::option`. - -use crate::std_facade::string; -use core::ops::RangeInclusive; -use core::option as opt; - -use crate::arbitrary::*; -use crate::option::{weighted, OptionStrategy, Probability}; -use crate::strategy::statics::static_map; -use crate::strategy::*; - -arbitrary!(Probability, MapInto, Self>; - (0.0..=1.0).prop_map_into() -); - -// These are Option impls: - -arbitrary!(Option; None); -#[cfg(feature = "unstable")] -arbitrary!(Option; None); - -arbitrary!([A: Arbitrary] opt::Option, OptionStrategy, - product_type![Probability, A::Parameters]; - args => { - let product_unpack![prob, a] = args; - weighted(prob, any_with::(a)) - } -); - -lift1!([] Option, Probability; base, prob => weighted(prob, base)); - -arbitrary!([A: Arbitrary] opt::IntoIter, SMapped, Self>, - as Arbitrary>::Parameters; - args => static_map(any_with::>(args), Option::into_iter)); - -lift1!(['static] opt::IntoIter, Probability; - base, prob => weighted(prob, base).prop_map(Option::into_iter) -); - -#[cfg(feature = "unstable")] -arbitrary!(opt::NoneError; opt::NoneError); - -#[cfg(test)] -mod test { - no_panic_test!( - probability => Probability, - option => Option, - option_iter => opt::IntoIter, - option_parse_error => Option - ); -} diff --git a/library/proptest/src/arbitrary/_core/result.rs b/library/proptest/src/arbitrary/_core/result.rs deleted file mode 100644 index 69acf6d35a17..000000000000 --- a/library/proptest/src/arbitrary/_core/result.rs +++ /dev/null @@ -1,106 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::result`. - -use crate::std_facade::string; -use core::fmt; -use core::result::IntoIter; - -use crate::arbitrary::*; -use crate::result::*; -use crate::strategy::statics::static_map; -use crate::strategy::*; - -// These are Result with uninhabited type in some variant: -arbitrary!([A: Arbitrary] Result, - SMapped, A::Parameters; - args => static_map(any_with::(args), Result::Ok) -); -arbitrary!([A: Arbitrary] Result, - SMapped, A::Parameters; - args => static_map(any_with::(args), Result::Err) -); -#[cfg(feature = "unstable")] -arbitrary!([A: Arbitrary] Result, - SMapped, A::Parameters; - args => static_map(any_with::(args), Result::Ok) -); -#[cfg(feature = "unstable")] -arbitrary!([A: Arbitrary] Result, - SMapped, A::Parameters; - args => static_map(any_with::(args), Result::Err) -); - -lift1!([] Result; Result::Ok); -#[cfg(feature = "unstable")] -lift1!([] Result; Result::Ok); - -// We assume that `MaybeOk` is canonical as it's the most likely Strategy -// a user wants. - -arbitrary!([A: Arbitrary, B: Arbitrary] Result, - MaybeOk, - product_type![Probability, A::Parameters, B::Parameters]; - args => { - let product_unpack![prob, a, b] = args; - let (p, a, b) = (prob, any_with::(a), any_with::(b)); - maybe_ok_weighted(p, a, b) - } -); - -impl functor::ArbitraryF1 for Result -where - E::Strategy: 'static, -{ - type Parameters = product_type![Probability, E::Parameters]; - - fn lift1_with(base: AS, args: Self::Parameters) -> BoxedStrategy - where - AS: Strategy + 'static, - { - let product_unpack![prob, e] = args; - let (p, a, e) = (prob, base, any_with::(e)); - maybe_ok_weighted(p, a, e).boxed() - } -} - -impl functor::ArbitraryF2 for Result { - type Parameters = Probability; - - fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) -> BoxedStrategy - where - AS: Strategy + 'static, - BS: Strategy + 'static, - { - maybe_ok_weighted(args, fst, snd).boxed() - } -} - -arbitrary!([A: Arbitrary] IntoIter, - SMapped, Self>, - as Arbitrary>::Parameters; - args => static_map(any_with::>(args), Result::into_iter) -); - -lift1!(['static] IntoIter, Probability; base, args => { - maybe_ok_weighted(args, base, Just(())).prop_map(Result::into_iter) -}); - -#[cfg(test)] -mod test { - no_panic_test!( - result => Result, - into_iter => IntoIter, - result_a_parse_error => Result, - result_parse_error_a => Result<::std::string::ParseError, u8> - ); -} diff --git a/library/proptest/src/arbitrary/_std/env.rs b/library/proptest/src/arbitrary/_std/env.rs deleted file mode 100644 index a11f40a9bb07..000000000000 --- a/library/proptest/src/arbitrary/_std/env.rs +++ /dev/null @@ -1,141 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::env`. - -use std::env::*; -use std::ffi::OsString; -use std::iter::once; - -use crate::arbitrary::*; -use crate::strategy::statics::static_map; -use crate::strategy::*; - -// FIXME: SplitPaths when lifetimes in strategies are possible. - -lazy_just!( - Args, args; - ArgsOs, args_os; - Vars, vars; - VarsOs, vars_os; - JoinPathsError, jpe -); - -#[cfg(not(target_os = "windows"))] -fn jpe() -> JoinPathsError { - join_paths(once(":")).unwrap_err() -} - -#[cfg(target_os = "windows")] -fn jpe() -> JoinPathsError { - join_paths(once("\"")).unwrap_err() -} - -// Algorithm from: https://stackoverflow.com/questions/47749164 -#[cfg(any(target_os = "windows", test))] -fn make_utf16_invalid(buf: &mut [u16], p: usize) { - // Verify that length is non-empty. - // An empty string is always valid UTF-16. - assert!(buf.len() > 0); - - // If first elem or previous entry is not a leading surrogate. - let gen_trail = 0 == p || 0xd800 != (buf[p - 1] & 0xfc00); - // If last element or succeeding entry is not a traililng surrogate. - let gen_lead = p == buf.len() - 1 || 0xdc00 != (buf[p + 1] & 0xfc00); - let (force_bits_mask, force_bits_value) = if gen_trail { - if gen_lead { - // Trailing or leading surrogate. - (0xf800, 0xd800) - } else { - // Trailing surrogate. - (0xfc00, 0xdc00) - } - } else { - // Leading surrogate. - // Note that `gen_lead` and `gen_trail` could both be false here if `p` - // lies exactly between a leading and a trailing surrogate. In this - // case, it doesn't matter what we do because the UTF-16 will be - // invalid regardless, so just always force a leading surrogate. - (0xfc00, 0xd800) - }; - debug_assert_eq!(0, (force_bits_value & !force_bits_mask)); - buf[p] = (buf[p] & !force_bits_mask) | force_bits_value; -} - -#[cfg(not(target_arch = "wasm32"))] -mod var_error { - use super::*; - - /// Generates the set of `WTF-16 \ UTF-16` and makes - /// an `OsString` that is not a valid String from it. - #[cfg(target_os = "windows")] - fn osstring_invalid_string() -> impl Strategy { - use std::os::windows::ffi::OsStringExt; - let size = 1..::std::u16::MAX as usize; - let vec_gen = crate::collection::vec(..::std::u16::MAX, size.clone()); - (size, vec_gen).prop_map(|(p, mut sbuf)| { - // Not quite a uniform distribution due to clamping, - // but probably good enough - let p = ::std::cmp::min(p, sbuf.len() - 1); - make_utf16_invalid(&mut sbuf, p); - OsString::from_wide(sbuf.as_slice()).into_string().unwrap_err() - }) - } - - #[cfg(not(target_os = "windows"))] - fn osstring_invalid_string() -> impl Strategy { - use crate::arbitrary::_std::string::not_utf8_bytes; - use std::os::unix::ffi::OsStringExt; - static_map(not_utf8_bytes(true), OsString::from_vec) - } - - arbitrary!(VarError, - TupleUnion<( - WA>, - WA, Self>> - )>; - prop_oneof![ - Just(VarError::NotPresent), - static_map(osstring_invalid_string().boxed(), VarError::NotUnicode) - ] - ); -} - -#[cfg(test)] -mod test { - use super::*; - use crate::num; - use crate::test_runner::Config; - - no_panic_test!( - args => Args, - args_os => ArgsOs, - vars => Vars, - vars_os => VarsOs, - join_paths_error => JoinPathsError, - var_error => VarError - ); - - proptest! { - #![proptest_config(Config { - cases: 65536, - .. Config::default() - })] - - #[test] - fn make_utf16_invalid_doesnt_panic( - mut buf in [num::u16::ANY; 3], - p in 0usize..3 - ) { - make_utf16_invalid(&mut buf, p); - } - } -} diff --git a/library/proptest/src/arbitrary/_std/ffi.rs b/library/proptest/src/arbitrary/_std/ffi.rs deleted file mode 100644 index 776a8f679d05..000000000000 --- a/library/proptest/src/arbitrary/_std/ffi.rs +++ /dev/null @@ -1,102 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::ffi`. - -use crate::std_facade::{Box, String, Vec}; -use std::ffi::*; -use std::ops::RangeInclusive; - -use crate::arbitrary::*; -use crate::collection::*; -use crate::strategy::statics::static_map; -use crate::strategy::*; - -use super::string::not_utf8_bytes; - -arbitrary!(CString, - SFnPtrMap>, Self>, SizeRange; - args => static_map(vec(1..=::std::u8::MAX, args + 1), |mut vec| { - vec.pop().unwrap(); - // Could use: Self::from_vec_unchecked(vec) safely. - Self::new(vec).unwrap() - }) -); - -arbitrary!(OsString, MapInto, Self>, - ::Parameters; - a => any_with::(a).prop_map_into() -); - -macro_rules! dst_wrapped { - ($($w: ident),*) => { - $(arbitrary!($w, MapInto, Self>, SizeRange; - a => any_with::(a).prop_map_into() - );)* - $(arbitrary!($w, MapInto, Self>, - ::Parameters; - a => any_with::(a).prop_map_into() - );)* - }; -} - -dst_wrapped!(Box); - -#[cfg(feature = "unstable")] -use std::rc::Rc; -#[cfg(feature = "unstable")] -use std::sync::Arc; -#[cfg(feature = "unstable")] -dst_wrapped!(Rc, Arc); - -arbitrary!(FromBytesWithNulError, SMapped, Self>; { - static_map(any::>(), |opt_pos| { - // We make some assumptions about the internal structure of - // FromBytesWithNulError. However, these assumptions do not - // involve any non-public API. - if let Some(pos) = opt_pos { - let pos = pos as usize; - // Allocate pos + 2 so that we never reallocate: - let mut v = Vec::::with_capacity(pos + 2); - v.extend(::std::iter::repeat(1).take(pos)); - v.push(0); - v.push(1); - CStr::from_bytes_with_nul(v.as_slice()).unwrap_err() - } else { - CStr::from_bytes_with_nul(b"").unwrap_err() - } - }) -}); - -arbitrary!(IntoStringError, SFnPtrMap>, Self>; - static_map(not_utf8_bytes(false).boxed(), |bytes| - CString::new(bytes).unwrap().into_string().unwrap_err() - ) -); - -#[cfg(test)] -mod test { - no_panic_test!( - c_string => CString, - os_string => OsString, - box_c_str => Box, - box_os_str => Box, - into_string_error => IntoStringError, - from_bytes_with_nul => FromBytesWithNulError - ); - #[cfg(feature = "unstable")] - no_panic_test!( - rc_c_str => Rc, - rc_os_str => Rc, - arc_c_str => Arc, - arc_os_str => Arc - ); -} diff --git a/library/proptest/src/arbitrary/_std/fs.rs b/library/proptest/src/arbitrary/_std/fs.rs deleted file mode 100644 index 4383fa4093ab..000000000000 --- a/library/proptest/src/arbitrary/_std/fs.rs +++ /dev/null @@ -1,32 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::fs`. - -use std::fs::DirBuilder; - -use crate::arbitrary::{any, SMapped}; -use crate::strategy::statics::static_map; - -// TODO: other parts (figure out workable semantics). - -arbitrary!(DirBuilder, SMapped; { - static_map(any::(), |recursive| { - let mut db = DirBuilder::new(); - db.recursive(recursive); - db - }) -}); - -#[cfg(test)] -mod test { - no_panic_test!(dir_builder => DirBuilder); -} diff --git a/library/proptest/src/arbitrary/_std/io.rs b/library/proptest/src/arbitrary/_std/io.rs deleted file mode 100644 index 768a5b797927..000000000000 --- a/library/proptest/src/arbitrary/_std/io.rs +++ /dev/null @@ -1,166 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::io`. - -use crate::std_facade::String; -#[cfg(test)] -use crate::std_facade::Vec; -use std::io::ErrorKind::*; -use std::io::*; - -use crate::arbitrary::*; -use crate::strategy::statics::static_map; -use crate::strategy::*; - -// TODO: IntoInnerError -// Consider: std::io::Initializer - -macro_rules! buffer { - ($type: ident, $bound: path) => { - arbitrary!( - [A: Arbitrary + $bound] $type, - SMapped<(A, Option), Self>, A::Parameters; - args => static_map( - arbitrary_with(product_pack![args, Default::default()]), - |(inner, cap)| { - if let Some(cap) = cap { - $type::with_capacity(cap as usize, inner) - } else { - $type::new(inner) - } - } - ) - ); - - lift1!([$bound] $type; base => - (base, any::>()).prop_map(|(inner, cap)| { - if let Some(cap) = cap { - $type::with_capacity(cap as usize, inner) - } else { - $type::new(inner) - } - }) - ); - }; -} - -buffer!(BufReader, Read); -buffer!(BufWriter, Write); -buffer!(LineWriter, Write); - -arbitrary!( - [A: Read + Arbitrary, B: Read + Arbitrary] Chain, - SMapped<(A, B), Self>, product_type![A::Parameters, B::Parameters]; - args => static_map(arbitrary_with(args), |(a, b)| a.chain(b)) -); - -wrap_ctor!(Cursor); - -lazy_just!( - Empty, empty - ; Sink, sink - ; Stderr, stderr - ; Stdin, stdin - ; Stdout, stdout -); - -wrap_ctor!([BufRead] Lines, BufRead::lines); - -arbitrary!(Repeat, SMapped; static_map(any::(), repeat)); - -arbitrary!( - [A: BufRead + Arbitrary] Split, SMapped<(A, u8), Self>, A::Parameters; - args => static_map( - arbitrary_with(product_pack![args, Default::default()]), - |(a, b)| a.split(b) - ) -); -lift1!(['static + BufRead] Split; - base => (base, any::()).prop_map(|(a, b)| a.split(b))); - -arbitrary!( - [A: Read + Arbitrary] Take, SMapped<(A, u64), Self>, A::Parameters; - args => static_map( - arbitrary_with(product_pack![args, Default::default()]), - |(a, b)| a.take(b) - ) -); -lift1!(['static + Read] Take; - base => (base, any::()).prop_map(|(a, b)| a.take(b))); - -arbitrary!(ErrorKind, Union>; - Union::new( - [ NotFound - , PermissionDenied - , ConnectionRefused - , ConnectionReset - , ConnectionAborted - , NotConnected - , AddrInUse - , AddrNotAvailable - , BrokenPipe - , AlreadyExists - , WouldBlock - , InvalidInput - , InvalidData - , TimedOut - , WriteZero - , Interrupted - , Other - , UnexpectedEof - // TODO: watch this type for variant-additions. - ].iter().cloned().map(Just)) -); - -arbitrary!( - SeekFrom, - TupleUnion<( - WA>, - WA>, - WA>, - )>; - prop_oneof![ - static_map(any::(), SeekFrom::Start), - static_map(any::(), SeekFrom::End), - static_map(any::(), SeekFrom::Current) - ] -); - -arbitrary!(Error, SMapped<(ErrorKind, Option), Self>; - static_map(arbitrary(), |(k, os)| - if let Some(s) = os { Error::new(k, s) } else { k.into() } - ) -); - -#[cfg(test)] -mod test { - - no_panic_test!( - buf_reader => BufReader, - buf_writer => BufWriter, - line_writer => LineWriter, - chain => Chain>, - cursor => Cursor, - empty => Empty, - sink => Sink, - stderr => Stderr, - stdin => Stdin, - stdout => Stdout, - lines => Lines, - repeat => Repeat, - split => Split>>, - take => Take, - error_kind => ErrorKind, - seek_from => SeekFrom, - error => Error - ); -} diff --git a/library/proptest/src/arbitrary/_std/mod.rs b/library/proptest/src/arbitrary/_std/mod.rs deleted file mode 100644 index d4f07e8d5862..000000000000 --- a/library/proptest/src/arbitrary/_std/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for libstd. - -mod env; -mod ffi; -mod fs; -mod io; -mod net; -mod panic; -mod path; -mod string; -mod sync; -mod thread; -mod time; diff --git a/library/proptest/src/arbitrary/_std/net.rs b/library/proptest/src/arbitrary/_std/net.rs deleted file mode 100644 index 4b4fe4b670e6..000000000000 --- a/library/proptest/src/arbitrary/_std/net.rs +++ /dev/null @@ -1,119 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::net`. - -use std::net::*; - -use crate::arbitrary::*; -use crate::strategy::statics::static_map; -use crate::strategy::*; - -// TODO: Can we design a workable semantic for PBT wrt. actual networking -// connections? - -arbitrary!(AddrParseError; "".parse::().unwrap_err()); - -arbitrary!(Ipv4Addr, - TupleUnion<( - WA>, - WA>, - WA, Self>> - )>; - prop_oneof![ - 1 => Just(Self::new(0, 0, 0, 0)), - 4 => Just(Self::new(127, 0, 0, 1)), - 10 => any::().prop_map_into() - ] -); - -arbitrary!(Ipv6Addr, - TupleUnion<( - WA>, - WA, Self>> - )>; - prop_oneof![ - 2 => static_map(any::(), |ip| ip.to_ipv6_mapped()), - 1 => any::<[u16; 8]>().prop_map_into() - ] -); - -arbitrary!(SocketAddrV4, SMapped<(Ipv4Addr, u16), Self>; - static_map(any::<(Ipv4Addr, u16)>(), |(a, b)| Self::new(a, b)) -); - -arbitrary!(SocketAddrV6, SMapped<(Ipv6Addr, u16, u32, u32), Self>; - static_map(any::<(Ipv6Addr, u16, u32, u32)>(), - |(a, b, c, d)| Self::new(a, b, c, d)) -); - -arbitrary!(IpAddr, - TupleUnion<(WA, Self>>, - WA, Self>>)>; - prop_oneof![ - any::().prop_map_into(), - any::().prop_map_into() - ] -); - -arbitrary!(Shutdown, - TupleUnion<(WA>, WA>, WA>)>; - { - use std::net::Shutdown::*; - prop_oneof![Just(Both), Just(Read), Just(Write)] - } -); -arbitrary!(SocketAddr, - TupleUnion<(WA, Self>>, - WA, Self>>)>; - prop_oneof![ - any::().prop_map_into(), - any::().prop_map_into() - ] -); - -#[cfg(feature = "unstable")] -arbitrary!(Ipv6MulticastScope, - TupleUnion<(WA>, WA>, WA>, - WA>, WA>, WA>, - WA>)>; - { - use std::net::Ipv6MulticastScope::*; - prop_oneof![ - Just(InterfaceLocal), - Just(LinkLocal), - Just(RealmLocal), - Just(AdminLocal), - Just(SiteLocal), - Just(OrganizationLocal), - Just(Global), - ] - } -); - -#[cfg(test)] -mod test { - no_panic_test!( - addr_parse_error => AddrParseError, - ipv4_addr => Ipv4Addr, - ipv6_addr => Ipv6Addr, - socket_addr_v4 => SocketAddrV4, - socket_addr_v6 => SocketAddrV6, - ip_addr => IpAddr, - shutdown => Shutdown, - socket_addr => SocketAddr - ); - - #[cfg(feature = "unstable")] - no_panic_test!( - ipv6_multicast_scope => Ipv6MulticastScope - ); -} diff --git a/library/proptest/src/arbitrary/_std/panic.rs b/library/proptest/src/arbitrary/_std/panic.rs deleted file mode 100644 index b15cc9efb61f..000000000000 --- a/library/proptest/src/arbitrary/_std/panic.rs +++ /dev/null @@ -1,21 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::panic`. - -use std::panic::AssertUnwindSafe; - -wrap_ctor!(AssertUnwindSafe, AssertUnwindSafe); - -#[cfg(test)] -mod test { - no_panic_test!(assert_unwind_safe => AssertUnwindSafe); -} diff --git a/library/proptest/src/arbitrary/_std/path.rs b/library/proptest/src/arbitrary/_std/path.rs deleted file mode 100644 index 766e4eee177b..000000000000 --- a/library/proptest/src/arbitrary/_std/path.rs +++ /dev/null @@ -1,25 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::path`. - -use std::path::*; - -// TODO: Figure out PathBuf and then Box/Rc/Box. - -arbitrary!(StripPrefixError; Path::new("").strip_prefix("a").unwrap_err()); - -#[cfg(test)] -mod test { - no_panic_test!( - strip_prefix_error => StripPrefixError - ); -} diff --git a/library/proptest/src/arbitrary/_std/string.rs b/library/proptest/src/arbitrary/_std/string.rs deleted file mode 100644 index 8c49db3c682f..000000000000 --- a/library/proptest/src/arbitrary/_std/string.rs +++ /dev/null @@ -1,314 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::string`. - -use crate::std_facade::{Box, String, Vec}; -use std::iter; -use std::rc::Rc; -use std::slice; -use std::sync::Arc; - -multiplex_alloc! { - alloc::string::FromUtf8Error, ::std::string::FromUtf8Error, - alloc::string::FromUtf16Error, ::std::string::FromUtf16Error -} - -use crate::arbitrary::*; -use crate::collection; -use crate::strategy::statics::static_map; -use crate::strategy::*; -use crate::string::StringParam; - -impl Arbitrary for String { - type Parameters = StringParam; - type Strategy = &'static str; - - /// ## Panics - /// - /// This implementation panics if the input is not a valid regex proptest - /// can handle. - fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { - args.into() - } -} - -macro_rules! dst_wrapped { - ($($w: ident),*) => { - $(arbitrary!($w, MapInto, Self>, StringParam; - a => any_with::(a).prop_map_into() - );)* - }; -} - -dst_wrapped!(Box, Rc, Arc); - -lazy_just!(FromUtf16Error, || String::from_utf16(&[0xD800]).unwrap_err()); - -// This is a void-like type, it needs to be handled by the user of -// the type by simply never constructing the variant in an enum or for -// structs by inductively not generating the struct. -// The same applies to ! and Infallible. -// generator!(ParseError, || panic!()); - -arbitrary!(FromUtf8Error, SFnPtrMap>, Self>; - static_map(not_utf8_bytes(true).boxed(), - |bs| String::from_utf8(bs).unwrap_err()) -); - -/// This strategy produces sequences of bytes that are guaranteed to be illegal -/// wrt. UTF-8 with the goal of producing a suffix of bytes in the end of -/// an otherwise legal UTF-8 string that causes the string to be illegal. -/// This is used primarily to generate the `Utf8Error` type and similar. -pub(crate) fn not_utf8_bytes(allow_null: bool) -> impl Strategy> { - let prefix = collection::vec(any::(), ..::std::u16::MAX as usize); - let suffix = gen_el_bytes(allow_null); - (prefix, suffix).prop_map(move |(prefix_bytes, el_bytes)| { - let iter = prefix_bytes.iter(); - let string: String = - if allow_null { iter.collect() } else { iter.filter(|&&x| x != '\u{0}').collect() }; - let mut bytes = string.into_bytes(); - bytes.extend(el_bytes.into_iter()); - bytes - }) -} - -/// Stands for "error_length" bytes and contains a suffix of bytes that -/// will cause the whole string to become invalid UTF-8. -/// See `gen_el_bytes` for more details. -#[derive(Debug)] -enum ELBytes { - B1([u8; 1]), - B2([u8; 2]), - B3([u8; 3]), - B4([u8; 4]), -} - -impl<'a> IntoIterator for &'a ELBytes { - type Item = u8; - type IntoIter = iter::Cloned>; - fn into_iter(self) -> Self::IntoIter { - use self::ELBytes::*; - (match *self { - B1(ref a) => a.iter(), - B2(ref a) => a.iter(), - B3(ref a) => a.iter(), - B4(ref a) => a.iter(), - }) - .cloned() - } -} - -// By analysis of run_utf8_validation defined at: -// https://doc.rust-lang.org/nightly/src/core/str/mod.rs.html#1429 -// we know that .error_len() \in {None, Some(1), Some(2), Some(3)}. -// We represent this with the range [0..4) and generate a valid -// sequence from that. -fn gen_el_bytes(allow_null: bool) -> impl Strategy { - fn b1(a: u8) -> ELBytes { - ELBytes::B1([a]) - } - fn b2(a: (u8, u8)) -> ELBytes { - ELBytes::B2([a.0, a.1]) - } - fn b3(a: ((u8, u8), u8)) -> ELBytes { - ELBytes::B3([(a.0).0, (a.0).1, a.1]) - } - fn b4(a: ((u8, u8), u8, u8)) -> ELBytes { - ELBytes::B4([(a.0).0, (a.0).1, a.1, a.2]) - } - - /* - // https://tools.ietf.org/html/rfc3629 - static UTF8_CHAR_WIDTH: [u8; 256] = [ - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x1F - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x3F - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x5F - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, // 0x7F - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0x9F - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, // 0xBF - 0,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, - 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, // 0xDF - 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, // 0xEF - 4,4,4,4,4,0,0,0,0,0,0,0,0,0,0,0, // 0xFF - ]; - - /// Mask of the value bits of a continuation byte. - const CONT_MASK: u8 = 0b0011_1111; - /// Value of the tag bits (tag mask is !CONT_MASK) of a continuation byte. - const TAG_CONT_U8: u8 = 0b1000_0000; - */ - - // Continuation byte: - let succ_byte = 0x80u8..0xC0u8; - - // Do we allow the nul byte or not? - let start_byte = if allow_null { 0x00u8 } else { 0x01u8 }; - - // Invalid continuation byte: - let fail_byte = prop_oneof![start_byte..0x7Fu8, 0xC1u8..]; - - // Matches zero in the UTF8_CHAR_WIDTH table above. - let byte0_w0 = prop_oneof![0x80u8..0xC0u8, 0xF5u8..]; - - // Start of a 3 (width) byte sequence: - // Leads here: https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1479 - let byte0_w2 = 0xC2u8..0xE0u8; - - // Start of a 3 (width) byte sequence: - // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1484 - // See the left column in the match. - let byte0_w3 = 0xE0u8..0xF0u8; - - // Start of a 4 (width) byte sequence: - // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1495 - // See the left column in the match. - let byte0_w4 = 0xF0u8..0xF5u8; - - // The 2 first (valid) bytes of a 3 (width) byte sequence: - // The first byte is byte0_w3. The second is the ones produced on the right. - let byte01_w3 = byte0_w3.clone().prop_flat_map(|x| { - ( - Just(x), - match x { - 0xE0u8 => 0xA0u8..0xC0u8, - 0xE1u8..=0xECu8 => 0x80u8..0xC0u8, - 0xEDu8 => 0x80u8..0xA0u8, - 0xEEu8..=0xEFu8 => 0x80u8..0xA0u8, - _ => panic!(), - }, - ) - }); - - // In a 3 (width) byte sequence, an invalid second byte is chosen such that - // it will yield an error length of Some(1). The second byte is on - // the right of the match arms. - let byte01_w3_e1 = byte0_w3.clone().prop_flat_map(move |x| { - ( - Just(x), - match x { - 0xE0u8 => prop_oneof![start_byte..0xA0u8, 0xC0u8..], - 0xE1u8..=0xECu8 => prop_oneof![start_byte..0x80u8, 0xC0u8..], - 0xEDu8 => prop_oneof![start_byte..0x80u8, 0xA0u8..], - 0xEEu8..=0xEFu8 => prop_oneof![start_byte..0x80u8, 0xA0u8..], - _ => panic!(), - }, - ) - }); - - // In a 4 (width) byte sequence, an invalid second byte is chosen such that - // it will yield an error length of Some(1). The second byte is on - // the right of the match arms. - let byte01_w4_e1 = byte0_w4.clone().prop_flat_map(move |x| { - ( - Just(x), - match x { - 0xF0u8 => prop_oneof![start_byte..0x90u8, 0xA0u8..], - 0xF1u8..=0xF3u8 => prop_oneof![start_byte..0x80u8, 0xA0u8..], - 0xF4u8 => prop_oneof![start_byte..0x80u8, 0x90u8..], - _ => panic!(), - }, - ) - }); - - // The 2 first (valid) bytes of a 4 (width) byte sequence: - // The first byte is byte0_w4. The second is the ones produced on the right. - let byte01_w4 = byte0_w4.clone().prop_flat_map(|x| { - ( - Just(x), - match x { - 0xF0u8 => 0x90u8..0xA0u8, - 0xF1u8..=0xF3u8 => 0x80u8..0xA0u8, - 0xF4u8 => 0x80u8..0x90u8, - _ => panic!(), - }, - ) - }); - - prop_oneof![ - // error_len = None - // These are all happen when next!() fails to provide a byte. - prop_oneof![ - // width = 2 - // lacking 1 bytes: - static_map(byte0_w2.clone(), b1), - // width = 3 - // lacking 2 bytes: - static_map(byte0_w3, b1), - // lacking 1 bytes: - static_map(byte01_w3.clone(), b2), - // width = 4 - // lacking 3 bytes: - static_map(byte0_w4, b1), - // lacking 2 bytes: - static_map(byte01_w4.clone(), b2), - // lacking 1 byte: - static_map((byte01_w4.clone(), succ_byte.clone()), b3), - ], - // error_len = Some(1) - prop_oneof![ - // width = 1 is not represented. - // width = 0 - // path taken: - // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1508 - static_map(byte0_w0, b1), - // width = 2 - // path taken: - // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1480 - static_map((byte0_w2, fail_byte.clone()), b2), - // width = 3 - // path taken: - // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1488 - static_map(byte01_w3_e1, b2), - // width = 4 - // path taken: - // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1499 - static_map(byte01_w4_e1, b2), - ], - // error_len = Some(2) - static_map( - prop_oneof![ - // width = 3 - // path taken: - // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1491 - (byte01_w3, fail_byte.clone()), - // width = 4 - // path taken: - // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1502 - (byte01_w4.clone(), fail_byte.clone()) - ], - b3 - ), - // error_len = Some(3), width = 4 - // path taken: - // https://doc.rust-lang.org/1.23.0/src/core/str/mod.rs.html#1505 - static_map((byte01_w4, succ_byte, fail_byte), b4), - ] - .boxed() -} - -#[cfg(test)] -mod test { - no_panic_test!( - string => String, - str_box => Box, - str_rc => Rc, - str_arc => Arc, - from_utf16_error => FromUtf16Error, - from_utf8_error => FromUtf8Error - ); -} diff --git a/library/proptest/src/arbitrary/_std/sync.rs b/library/proptest/src/arbitrary/_std/sync.rs deleted file mode 100644 index 3a0454e78826..000000000000 --- a/library/proptest/src/arbitrary/_std/sync.rs +++ /dev/null @@ -1,164 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::sync`. - -use std::fmt; -use std::sync::mpsc::*; -use std::sync::*; -use std::thread; -use std::time::Duration; - -use crate::arbitrary::*; -use crate::strategy::statics::static_map; -use crate::strategy::*; - -// OnceState can not escape Once::call_once_force. -// PoisonError depends implicitly on the lifetime on MutexGuard, etc. -// This transitively applies to TryLockError. - -// Not doing Weak because .upgrade() would always return None. - -#[cfg(not(feature = "unstable"))] -wrap_ctor!(Mutex); -#[cfg(feature = "unstable")] -wrap_from!(Mutex); - -#[cfg(not(feature = "unstable"))] -wrap_ctor!(RwLock); -#[cfg(feature = "unstable")] -wrap_from!(RwLock); - -arbitrary!(Barrier, SMapped; // usize would be extreme! - static_map(any::(), |n| Barrier::new(n as usize)) -); - -arbitrary!(BarrierWaitResult, - TupleUnion<(WA>, WA>)>; - prop_oneof![LazyJust::new(bwr_true), LazyJust::new(bwr_false)] -); - -lazy_just!( - Condvar, Default::default; - Once, Once::new -); - -arbitrary!(WaitTimeoutResult, TupleUnion<(WA>, WA>)>; - prop_oneof![Just(wtr_true()), Just(wtr_false())] -); - -fn bwr_true() -> BarrierWaitResult { - Barrier::new(1).wait() -} - -fn bwr_false() -> BarrierWaitResult { - let barrier = Arc::new(Barrier::new(2)); - let b2 = barrier.clone(); - let jh = thread::spawn(move || b2.wait()); - let bwr1 = barrier.wait(); - let bwr2 = jh.join().unwrap(); - if bwr1.is_leader() { bwr2 } else { bwr1 } -} - -fn wtr_false() -> WaitTimeoutResult { - let cvar = Arc::new(Condvar::new()); - let cvar2 = cvar.clone(); - thread::spawn(move || { - cvar2.notify_one(); - }); - let lock = Mutex::new(()); - let wt = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(1)); - let (_, wtr) = wt.unwrap(); - wtr -} - -fn wtr_true() -> WaitTimeoutResult { - let cvar = Condvar::new(); - let lock = Mutex::new(()); - let wt = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(0)); - let (_, wtr) = wt.unwrap(); - wtr -} - -arbitrary!(RecvError; RecvError); - -arbitrary!([T: Arbitrary] SendError, SMapped, T::Parameters; - args => static_map(any_with::(args), SendError) -); - -arbitrary!(RecvTimeoutError, TupleUnion<(WA>, WA>)>; - prop_oneof![ - Just(RecvTimeoutError::Disconnected), - Just(RecvTimeoutError::Timeout) - ] -); - -arbitrary!(TryRecvError, TupleUnion<(WA>, WA>)>; - prop_oneof![ - Just(TryRecvError::Disconnected), - Just(TryRecvError::Empty) - ] -); - -arbitrary!( - [P: Clone + Default, T: Arbitrary] TrySendError, - TupleUnion<(WA>, WA>)>, P; - args => prop_oneof![ - static_map(any_with::(args.clone()), TrySendError::Disconnected), - static_map(any_with::(args), TrySendError::Full), - ] -); - -// If only half of a pair is generated then you will get a hang-up. -// Thus the only meaningful impls are in pairs. -arbitrary!([A] (Sender, Receiver), LazyJustFn; - LazyJust::new(channel) -); - -arbitrary!([A: fmt::Debug] (Sender, IntoIter), LazyJustFn; - LazyJust::new(|| { - let (rx, tx) = channel(); - (rx, tx.into_iter()) - }) -); - -arbitrary!([A] (SyncSender, Receiver), SMapped; - static_map(any::(), |size| sync_channel(size as usize)) -); - -arbitrary!([A: fmt::Debug] (SyncSender, IntoIter), SMapped; - static_map(any::(), |size| { - let (rx, tx) = sync_channel(size as usize); - (rx, tx.into_iter()) - }) -); - -#[cfg(test)] -mod test { - no_panic_test!( - mutex => Mutex, - rw_lock => RwLock, - barrier => Barrier, - barrier_wait_result => BarrierWaitResult, - condvar => Condvar, - once => Once, - wait_timeout_result => WaitTimeoutResult, - recv_error => RecvError, - send_error => SendError, - recv_timeout_error => RecvTimeoutError, - try_recv_error => TryRecvError, - try_send_error => TrySendError, - rx_tx => (Sender, Receiver), - rx_txiter => (Sender, IntoIter), - syncrx_tx => (SyncSender, Receiver), - syncrx_txiter => (SyncSender, IntoIter) - ); -} diff --git a/library/proptest/src/arbitrary/_std/thread.rs b/library/proptest/src/arbitrary/_std/thread.rs deleted file mode 100644 index 87ed046fbd2b..000000000000 --- a/library/proptest/src/arbitrary/_std/thread.rs +++ /dev/null @@ -1,83 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::thread`. - -use crate::std_facade::String; -use std::thread::*; - -use crate::arbitrary::*; -use crate::option::prob; -use crate::strategy::statics::static_map; - -arbitrary!(Builder, SMapped<(Option, Option), Self>; { - let prob = prob(0.7); - let args = product_pack![ - product_pack![prob, Default::default()], - product_pack![prob, Default::default()] - ]; - static_map(arbitrary_with(args), |(os, on)| { - let mut b = Builder::new(); - b = if let Some(size) = os { b.stack_size(size) } else { b }; - if let Some(name) = on { b.name(name) } else { b } - }) -}); - -/* - * The usefulness of this impl is debatable - as are its semantics. - * Perhaps a CoArbitrary-based solution is preferable. - -arbitrary!([A: 'static + Send + Arbitrary<'a>] JoinHandle, - SMapped<'a, (A, Option<()>, u8), Self>, A::Parameters; - args => { - let prob = prob(0.1); - let args2 = product_pack![ - args, - product_pack![prob, default()], - default() - ]; - any_with_smap(args2, |(val, panic, sleep)| thread::spawn(move || { - // Sleep a random amount: - use std::time::Duration; - thread::sleep(Duration::from_millis(sleep as u64)); - - // Randomly panic: - if panic.is_some() { - panic!("Arbitrary for JoinHandle randomly paniced!"); - } - - // Move value into thread and then just return it: - val - })) - } -); -*/ - -#[cfg(test)] -mod test { - no_panic_test!( - builder => Builder - ); - - /* - use super::*; - proptest! { - #[test] - fn join_handle_works(ref jh in any::>()) { - use std::panic::catch_unwind; - catch_unwind(|| { - jh.join(); - () - }) - } - } - */ -} diff --git a/library/proptest/src/arbitrary/_std/time.rs b/library/proptest/src/arbitrary/_std/time.rs deleted file mode 100644 index fe0a537bc037..000000000000 --- a/library/proptest/src/arbitrary/_std/time.rs +++ /dev/null @@ -1,52 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for `std::time`. - -use core::ops::Range; -use std::time::*; - -use crate::arbitrary::*; -use crate::num; -use crate::strategy::statics::{self, static_map}; - -arbitrary!(Duration, SMapped<(u64, u32), Self>; - static_map(any::<(u64, u32)>(), |(a, b)| Duration::new(a, b)) -); - -// Instant::now() "never" returns the same Instant, so no shrinking may occur! -arbitrary!(Instant; Self::now()); - -arbitrary!( - // We can't use `any::()` because the addition to `SystemTime` - // can overflow and panic. To be conservative, we only allow seconds to go - // to i32::MAX since a certain popular OS still uses `i32` to represent the - // seconds counter. - SystemTime, statics::Map<(num::i32::Any, Range), - fn ((i32, u32)) -> SystemTime>; - static_map((num::i32::ANY, 0..1_000_000_000u32), - |(sec, ns)| { - if sec >= 0 { - UNIX_EPOCH + Duration::new(sec as u64, ns) - } else { - UNIX_EPOCH - Duration::new((-(sec as i64)) as u64, ns) - } - }) -); - -#[cfg(test)] -mod test { - no_panic_test!( - duration => Duration, - instant => Instant, - system_time => SystemTime - ); -} diff --git a/library/proptest/src/arbitrary/arrays.rs b/library/proptest/src/arbitrary/arrays.rs deleted file mode 100644 index 72d4f72df8c9..000000000000 --- a/library/proptest/src/arbitrary/arrays.rs +++ /dev/null @@ -1,40 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for arrays. - -use crate::arbitrary::{any_with, Arbitrary}; -use crate::array::UniformArrayStrategy; - -macro_rules! array { - ($($n: expr),*) => { $( - impl Arbitrary for [A; $n] { - type Parameters = A::Parameters; - type Strategy = UniformArrayStrategy; - fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { - let base = any_with::(args); - UniformArrayStrategy::new(base) - } - } - )* }; -} - -array!( - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, - 27, 28, 29, 30, 31, 32 -); - -#[cfg(test)] -mod test { - no_panic_test!( - array_16 => [u8; 16] - ); -} diff --git a/library/proptest/src/arbitrary/functor.rs b/library/proptest/src/arbitrary/functor.rs deleted file mode 100644 index f779595dd8fa..000000000000 --- a/library/proptest/src/arbitrary/functor.rs +++ /dev/null @@ -1,216 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Provides higher order `Arbitrary` traits. -//! This is mainly for use by `proptest_derive`. -//! -//! ## Stability note -//! -//! This trait is mainly defined for `proptest_derive` to simplify the -//! mechanics of deriving recursive types. If you have custom containers -//! and want to support recursive for those, it is a good idea to implement -//! this trait. -//! -//! There are clearer and terser ways that work better with -//! inference such as using `proptest::collection::vec(..)` -//! to achieve the same result. -//! -//! For these reasons, the traits here are deliberately -//! not exported in a convenient way. - -use crate::std_facade::fmt; - -use crate::strategy::{BoxedStrategy, Strategy}; - -/// `ArbitraryF1` lets you lift a [`Strategy`] to unary -/// type constructors such as `Box`, `Vec`, and `Option`. -/// -/// The trait corresponds to -/// [Haskell QuickCheck's `Arbitrary1` type class][HaskellQC]. -/// -/// [HaskellQC]: -/// https://hackage.haskell.org/package/QuickCheck-2.10.1/docs/Test-QuickCheck-Arbitrary.html#t:Arbitrary1 -/// -/// [`Strategy`]: ../proptest/strategy/trait.Strategy.html -pub trait ArbitraryF1: fmt::Debug + Sized { - //========================================================================== - // Implementation note #1 - //========================================================================== - // It might be better to do this with generic associated types by - // having an associated type: - // - // `type Strategy: Strategy;` - // - // But with this setup we will likely loose the ability to add bounds - // such as `Hash + Eq` on `A` which is needed for `HashSet`. We might - // be able to regain this ability with a ConstraintKinds feature. - // - // This alternate formulation will likely work better with type inference. - // - //========================================================================== - // Implementation note #2 - //========================================================================== - // - // Until `-> impl Trait` has been stabilized, `BoxedStrategy` must be - // used. This incurs an unfortunate performance penalty - but since - // we are dealing with testing, it is better to provide slowed down and - // somewhat less general functionality than no functionality at all. - // Implementations should just use `.boxed()` in the end. - //========================================================================== - - /// The type of parameters that [`lift1_with`] accepts for - /// configuration of the lifted and generated [`Strategy`]. Parameters - /// must implement [`Default`]. - /// - /// [`lift1_with`]: - /// trait.ArbitraryF1.html#tymethod.lift1_with - /// - /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html - /// [`Default`]: - /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html - type Parameters: Default; - - /// Lifts a given [`Strategy`] to a new [`Strategy`] for the (presumably) - /// bigger type. This is useful for lifting a `Strategy` for `SomeType` - /// to a container such as `Vec`. - /// - /// Calling this for the type `X` is the equivalent of using - /// [`X::lift1_with(base, Default::default())`]. - /// - /// This method is defined in the trait for optimization for the - /// default if you want to do that. It is a logic error to not - /// preserve the semantics when overriding. - /// - /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html - /// - /// [`X::lift1_with(base, Default::default())`]: - /// trait.ArbitraryF1.html#tymethod.lift1_with - fn lift1(base: AS) -> BoxedStrategy - where - AS: Strategy + 'static, - { - Self::lift1_with(base, Self::Parameters::default()) - } - - /// Lifts a given [`Strategy`] to a new [`Strategy`] for the (presumably) - /// bigger type. This is useful for lifting a `Strategy` for `SomeType` - /// to a container such as `Vec` of `SomeType`. The composite strategy is - /// passed the arguments given in `args`. - /// - /// If you wish to use the [`default()`] arguments, - /// use [`lift1`] instead. - /// - /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html - /// - /// [`lift1`]: trait.ArbitraryF1.html#method.lift1 - /// - /// [`default()`]: - /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html - fn lift1_with(base: AS, args: Self::Parameters) -> BoxedStrategy - where - AS: Strategy + 'static; -} - -/// `ArbitraryF2` lets you lift [`Strategy`] to binary -/// type constructors such as `Result`, `HashMap`. -/// -/// The trait corresponds to -/// [Haskell QuickCheck's `Arbitrary2` type class][HaskellQC]. -/// -/// [HaskellQC]: -/// https://hackage.haskell.org/package/QuickCheck-2.10.1/docs/Test-QuickCheck-Arbitrary.html#t:Arbitrary2 -/// -/// [`Strategy`]: ../proptest/strategy/trait.Strategy.html -pub trait ArbitraryF2: fmt::Debug + Sized { - /// The type of parameters that [`lift2_with`] accepts for - /// configuration of the lifted and generated [`Strategy`]. Parameters - /// must implement [`Default`]. - /// - /// [`lift2_with`]: trait.ArbitraryF2.html#tymethod.lift2_with - /// - /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html - /// - /// [`Default`]: - /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html - type Parameters: Default; - - /// Lifts two given strategies to a new [`Strategy`] for the (presumably) - /// bigger type. This is useful for lifting a `Strategy` for `Type1` - /// and one for `Type2` to a container such as `HashMap`. - /// - /// Calling this for the type `X` is the equivalent of using - /// [`X::lift2_with(base, Default::default())`]. - /// - /// This method is defined in the trait for optimization for the - /// default if you want to do that. It is a logic error to not - /// preserve the semantics when overriding. - /// - /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html - /// - /// [`X::lift2_with(base, Default::default())`]: - /// trait.Arbitrary.html#tymethod.lift2_with - fn lift2(fst: AS, snd: BS) -> BoxedStrategy - where - AS: Strategy + 'static, - BS: Strategy + 'static, - { - Self::lift2_with(fst, snd, Self::Parameters::default()) - } - - /// Lifts two given strategies to a new [`Strategy`] for the (presumably) - /// bigger type. This is useful for lifting a `Strategy` for `Type1` - /// and one for `Type2` to a container such as `HashMap`. - /// The composite strategy is passed the arguments given in `args`. - /// - /// If you wish to use the [`default()`] arguments, - /// use [`lift2`] instead. - /// - /// [`Strategy`]: ../proptest/strategy/trait.Strategy.html - /// - /// [`lift2`]: trait.ArbitraryF2.html#method.lift2 - /// - /// [`default()`]: - /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html - fn lift2_with(fst: AS, snd: BS, args: Self::Parameters) -> BoxedStrategy - where - AS: Strategy + 'static, - BS: Strategy + 'static; -} - -macro_rules! lift1 { - ([$($bounds : tt)*] $typ: ty, $params: ty; - $base: ident, $args: ident => $logic: expr) => { - impl - $crate::arbitrary::functor::ArbitraryF1 - for $typ { - type Parameters = $params; - - fn lift1_with($base: S, $args: Self::Parameters) - -> $crate::strategy::BoxedStrategy - where - S: $crate::strategy::Strategy + 'static - { - $crate::strategy::Strategy::boxed($logic) - } - } - }; - ([$($bounds : tt)*] $typ: ty; $base: ident => $logic: expr) => { - lift1!([$($bounds)*] $typ, (); $base, _args => $logic); - }; - ([$($bounds : tt)*] $typ: ty; $mapper: expr) => { - lift1!(['static + $($bounds)*] $typ; base => - $crate::strategy::Strategy::prop_map(base, $mapper)); - }; - ([$($bounds : tt)*] $typ: ty) => { - lift1!(['static + $($bounds)*] $typ; base => - $crate::strategy::Strategy::prop_map_into(base)); - }; -} diff --git a/library/proptest/src/arbitrary/macros.rs b/library/proptest/src/arbitrary/macros.rs deleted file mode 100644 index 5b373544b5a0..000000000000 --- a/library/proptest/src/arbitrary/macros.rs +++ /dev/null @@ -1,117 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -#![cfg_attr(not(feature = "std"), allow(unused_macros))] - -//============================================================================== -// Macros for quick implementing: -//============================================================================== - -macro_rules! arbitrary { - ([$($bounds : tt)*] $typ: ty, $strat: ty, $params: ty; - $args: ident => $logic: expr) => { - impl<$($bounds)*> $crate::arbitrary::Arbitrary for $typ { - type Parameters = $params; - type Strategy = $strat; - fn arbitrary_with($args: Self::Parameters) -> Self::Strategy { - $logic - } - } - }; - ([$($bounds : tt)*] $typ: ty, $strat: ty; $logic: expr) => { - arbitrary!([$($bounds)*] $typ, $strat, (); _args => $logic); - }; - ([$($bounds : tt)*] $typ: ty; $logic: expr) => { - arbitrary!([$($bounds)*] $typ, - $crate::strategy::Just, (); - _args => $crate::strategy::Just($logic) - ); - }; - ($typ: ty, $strat: ty, $params: ty; $args: ident => $logic: expr) => { - arbitrary!([] $typ, $strat, $params; $args => $logic); - }; - ($typ: ty, $strat: ty; $logic: expr) => { - arbitrary!([] $typ, $strat; $logic); - }; - ($strat: ty; $logic: expr) => { - arbitrary!([] $strat; $logic); - }; - ($($typ: ident),*) => { - $(arbitrary!($typ, $typ::Any; $typ::ANY);)* - }; -} - -macro_rules! wrap_ctor { - ($wrap: ident) => { - wrap_ctor!([] $wrap); - }; - ($wrap: ident, $maker: expr) => { - wrap_ctor!([] $wrap, $maker); - }; - ([$($bound : tt)*] $wrap: ident) => { - wrap_ctor!([$($bound)*] $wrap, $wrap::new); - }; - ([$($bound : tt)*] $wrap: ident, $maker: expr) => { - arbitrary!([A: $crate::arbitrary::Arbitrary + $($bound)*] $wrap, - $crate::arbitrary::SMapped, A::Parameters; - args => $crate::strategy::statics::static_map( - $crate::arbitrary::any_with::(args), $maker)); - - lift1!([$($bound)*] $wrap; $maker); - }; -} - -macro_rules! wrap_from { - ($wrap: ident) => { - wrap_from!([] $wrap); - }; - ([$($bound : tt)*] $wrap: ident) => { - arbitrary!([A: $crate::arbitrary::Arbitrary + $($bound)*] $wrap, - $crate::strategy::MapInto, A::Parameters; - args => $crate::strategy::Strategy::prop_map_into( - $crate::arbitrary::any_with::(args))); - - lift1!([$($bound)*] $wrap); - }; -} - -macro_rules! lazy_just { - ($($self: ty, $fun: expr);+) => { - $( - arbitrary!($self, $crate::strategy::LazyJust Self>; - $crate::strategy::LazyJust::new($fun)); - )+ - }; -} - -//============================================================================== -// Macros for testing: -//============================================================================== - -/// We are mostly interested in ensuring that generating input from our -/// strategies is able to construct a value, therefore ensuring that -/// no panic occurs is mostly sufficient. Shrinking for strategies that -/// use special shrinking methods can be handled separately. -#[cfg(test)] -macro_rules! no_panic_test { - ($($module: ident => $self: ty),+) => { - $( - mod $module { - #[allow(unused_imports)] - use super::super::*; - proptest! { - #[test] - fn no_panic(_ in $crate::arbitrary::any::<$self>()) {} - } - } - )+ - }; -} diff --git a/library/proptest/src/arbitrary/mod.rs b/library/proptest/src/arbitrary/mod.rs deleted file mode 100644 index cd6e0c398e34..000000000000 --- a/library/proptest/src/arbitrary/mod.rs +++ /dev/null @@ -1,69 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Defines the `Arbitrary` trait and related free functions -//! and type aliases. -//! -//! See the [`Arbitrary`] trait for more information. -//! -//! [`Arbitrary`]: trait.Arbitrary.html - -// use crate::strategy::statics; -// use crate::strategy::{Map, Strategy}; - -//============================================================================== -// Trait and impls -//============================================================================== - -mod traits; - -// #[macro_use] -// pub mod functor; - -#[macro_use] -mod macros; - -// mod arrays; -mod primitives; -// mod sample; -// mod tuples; - -// mod _core; - -//#[cfg(any(feature = "std", feature = "alloc"))] -// mod _alloc; - -//#[cfg(feature = "std")] -// mod _std; - -pub use self::traits::*; - -//============================================================================== -// SMapped + Mapped aliases to make documentation clearer. -//============================================================================== - -// pub(crate) type SFnPtrMap = statics::Map::Value) -> O>; - -// /// A static map from a strategy of `I` to `O`. -// /// -// /// # Stability -// /// -// /// This is provided to make documentation more readable. -// /// Do not rely on it existing in your own code. -// pub type SMapped = statics::Map, fn(I) -> O>; - -// /// A normal map from a strategy of `I` to `O`. -// /// -// /// # Stability -// /// -// /// This is provided to make documentation more readable. -// /// Do not rely on it existing in your own code. -// pub type Mapped = Map, fn(I) -> O>; diff --git a/library/proptest/src/arbitrary/primitives.rs b/library/proptest/src/arbitrary/primitives.rs deleted file mode 100644 index bf9b49bad682..000000000000 --- a/library/proptest/src/arbitrary/primitives.rs +++ /dev/null @@ -1,47 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for primitive types. - -use crate::bool; -// use crate::char; -use crate::num::{f32, f64, i16, i32, i64, i8, isize, u16, u32, u64, u8, usize}; -#[cfg(not(target_arch = "wasm32"))] -use crate::num::{i128, u128}; - -arbitrary!(i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, bool); - -#[cfg(not(target_arch = "wasm32"))] -arbitrary!(i128, u128); - -// Note that for floating point types we limit the space since a lot of code -// isn't prepared for (and is not intended to be) things like NaN and infinity. - -arbitrary!(f32, f32::Any; { - f32::POSITIVE | f32::NEGATIVE | f32::ZERO | f32::SUBNORMAL | f32::NORMAL -}); -arbitrary!(f64, f64::Any; { - f64::POSITIVE | f64::NEGATIVE | f64::ZERO | f64::SUBNORMAL | f64::NORMAL -}); - -// arbitrary!(char, char::CharStrategy<'static>; char::any()); - -#[cfg(test)] -mod test { - no_panic_test!( - bool => bool, - char => char, - f32 => f32, f64 => f64, - isize => isize, usize => usize, - i8 => i8, i16 => i16, i32 => i32, i64 => i64, i128 => i128, - u8 => u8, u16 => u16, u32 => u32, u64 => u64, u128 => u128 - ); -} diff --git a/library/proptest/src/arbitrary/sample.rs b/library/proptest/src/arbitrary/sample.rs deleted file mode 100644 index 842fd9f03020..000000000000 --- a/library/proptest/src/arbitrary/sample.rs +++ /dev/null @@ -1,33 +0,0 @@ -//- -// Copyright 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -use crate::arbitrary::Arbitrary; -use crate::sample::{Index, IndexStrategy, Selector, SelectorStrategy}; - -impl Arbitrary for Index { - type Parameters = (); - - type Strategy = IndexStrategy; - - fn arbitrary_with(_: ()) -> IndexStrategy { - IndexStrategy::new() - } -} - -impl Arbitrary for Selector { - type Parameters = (); - - type Strategy = SelectorStrategy; - - fn arbitrary_with(_: ()) -> SelectorStrategy { - SelectorStrategy::new() - } -} diff --git a/library/proptest/src/arbitrary/traits.rs b/library/proptest/src/arbitrary/traits.rs deleted file mode 100644 index e28d50bba87b..000000000000 --- a/library/proptest/src/arbitrary/traits.rs +++ /dev/null @@ -1,297 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -use core::fmt; - -use crate::strategy::Strategy; - -//============================================================================== -// Arbitrary trait -//============================================================================== - -/// Arbitrary determines a canonical [`Strategy`] for the implementing type. -/// -/// It provides the method `arbitrary_with` which generates a `Strategy` for -/// producing arbitrary values of the implementing type *(`Self`)*. In general, -/// these strategies will produce the entire set of values possible for the -/// type, up to some size limitation or constraints set by their parameters. -/// When this is not desired, strategies to produce the desired values can be -/// built by combining [`Strategy`]s as described in the crate documentation. -/// -/// This trait analogous to -/// [Haskell QuickCheck's implementation of `Arbitrary`][HaskellQC]. -/// In this interpretation of `Arbitrary`, `Strategy` is the equivalent of -/// the `Gen` monad. Unlike in QuickCheck, `Arbitrary` is not a core component; -/// types do not need to implement `Arbitrary` unless one wants to use -/// [`any`](fn.any.html) or other free functions in this module. -/// -/// `Arbitrary` currently only works for types which represent owned data as -/// opposed to borrowed data. This is a fundamental restriction of `proptest` -/// which may be lifted in the future as the [generic associated types (GAT)] -/// feature of Rust is implemented and stabilized. -/// -/// [generic associated types (GAT)]: https://github.com/rust-lang/rust/issues/44265 -/// -/// [`Strategy`]: ../strategy/trait.Strategy.html -/// -/// [HaskellQC]: -/// https://hackage.haskell.org/package/QuickCheck/docs/Test-QuickCheck-Arbitrary.html -pub trait Arbitrary: Sized + fmt::Debug { - /// The type of parameters that [`arbitrary_with`] accepts for configuration - /// of the generated [`Strategy`]. Parameters must implement [`Default`]. - /// - /// [`arbitrary_with`]: trait.Arbitrary.html#tymethod.arbitrary_with - /// - /// [`Strategy`]: ../strategy/trait.Strategy.html - /// [`Default`]: - /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html - type Parameters: Default; - - /// Generates a [`Strategy`] for producing arbitrary values - /// of type the implementing type (`Self`). - /// - /// Calling this for the type `X` is the equivalent of using - /// [`X::arbitrary_with(Default::default())`]. - /// - /// This method is defined in the trait for optimization for the - /// default if you want to do that. It is a logic error to not - /// preserve the semantics when overriding. - /// - /// [`Strategy`]: ../strategy/trait.Strategy.html - /// [`X::arbitrary_with(Default::default())`]: - /// trait.Arbitrary.html#tymethod.arbitrary_with - fn arbitrary() -> Self::Strategy { - Self::arbitrary_with(Default::default()) - } - - /// Generates a [`Strategy`] for producing arbitrary values of type the - /// implementing type (`Self`). The strategy is passed the arguments given - /// in args. - /// - /// If you wish to use the [`default()`] arguments, - /// use [`arbitrary`] instead. - /// - /// [`Strategy`]: ../strategy/trait.Strategy.html - /// - /// [`arbitrary`]: trait.Arbitrary.html#method.arbitrary - /// - /// [`default()`]: - /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html - fn arbitrary_with(args: Self::Parameters) -> Self::Strategy; - - /// The type of [`Strategy`] used to generate values of type `Self`. - /// - /// [`Strategy`]: ../strategy/trait.Strategy.html - type Strategy: Strategy; -} - -//============================================================================== -// Type aliases for associated types -//============================================================================== - -/// `StrategyFor` allows you to mention the type of [`Strategy`] for the input -/// type `A` without directly using associated types or without resorting to -/// existential types. This way, if implementation of [`Arbitrary`] changes, -/// your tests should not break. This can be especially beneficial when the -/// type of `Strategy` that you are dealing with is very long in name -/// (the case with generics). -/// -/// [`Arbitrary`]: trait.Arbitrary.html -/// [`Strategy`]: ../strategy/trait.Strategy.html -pub type StrategyFor = ::Strategy; - -/// `ParamsFor` allows you to mention the type of [`Parameters`] for the input -/// type `A` without directly using associated types or without resorting to -/// existential types. This way, if implementation of [`Arbitrary`] changes, -/// your tests should not break. -/// -/// [`Parameters`]: trait.Arbitrary.html#associatedtype.Parameters -/// [`Arbitrary`]: trait.Arbitrary.html -/// [`Strategy`]: ../strategy/trait.Strategy.html -pub type ParamsFor = ::Parameters; - -//============================================================================== -// Free functions that people should use -//============================================================================== - -/// Generates a [`Strategy`] producing [`Arbitrary`][trait Arbitrary] values of -/// `A`. Unlike [`arbitrary`][fn arbitrary], it should be used for being -/// explicit on what `A` is. For clarity, this may be a good idea. -/// -/// Use this version instead of [`arbitrary`][fn arbitrary] if you want to be -/// clear which type you want to generate a `Strategy` for, or if you don't -/// have an anchoring type for type inference to work with. -/// -/// If you want to customize how the strategy is generated, use -/// [`any_with::(args)`] where `args` are any arguments accepted by -/// the `Arbitrary` impl in question. -/// -/// # Example -/// -/// The function can be used as: -/// -/// ```rust -/// use proptest::prelude::*; -/// -/// proptest! { -/// fn reverse_reverse_is_identity(ref vec in any::>()) { -/// let vec2 = vec.iter().cloned().rev().rev().collect::>(); -/// prop_assert_eq!(vec, &vec2); -/// } -/// } -/// -/// fn main() { -/// reverse_reverse_is_identity(); -/// } -/// ``` -/// -/// [`any_with::(args)`]: fn.any_with.html -/// [fn arbitrary]: fn.arbitrary.html -/// [trait Arbitrary]: trait.Arbitrary.html -/// [`Strategy`]: ../strategy/trait.Strategy.html -#[must_use = "strategies do nothing unless used"] -pub fn any() -> StrategyFor { - // ^-- We use a shorter name so that turbofish becomes more ergonomic. - A::arbitrary() -} - -/// Generates a [`Strategy`] producing [`Arbitrary`] values of `A` with the -/// given configuration arguments passed in `args`. Unlike [`arbitrary_with`], -/// it should be used for being explicit on what `A` is. -/// For clarity, this may be a good idea. -/// -/// Use this version instead of [`arbitrary_with`] if you want to be clear which -/// type you want to generate a `Strategy` for, or if you don't have an anchoring -/// type for type inference to work with. -/// -/// If you don't want to specify any arguments and instead use the default -/// behavior, you should use [`any::()`]. -/// -/// # Example -/// -/// The function can be used as: -/// -/// ```rust -/// use proptest::prelude::*; -/// use proptest::collection::size_range; -/// -/// proptest! { -/// fn reverse_reverse_is_identity -/// (ref vec in any_with::>(size_range(1000).lift())) -/// { -/// let vec2 = vec.iter().cloned().rev().rev().collect::>(); -/// prop_assert_eq!(vec, &vec2); -/// } -/// } -/// -/// fn main() { -/// reverse_reverse_is_identity(); -/// } -/// ``` -/// -/// [`any::()`]: fn.any.html -/// [`arbitrary_with`]: fn.arbitrary_with.html -/// [`Arbitrary`]: trait.Arbitrary.html -/// [`Strategy`]: ../strategy/trait.Strategy.html -#[must_use = "strategies do nothing unless used"] -pub fn any_with(args: ParamsFor) -> StrategyFor { - // ^-- We use a shorter name so that turbofish becomes more ergonomic. - A::arbitrary_with(args) -} - -/// Generates a [`Strategy`] producing [`Arbitrary`] values of `A`. -/// Works better with type inference than [`any::()`]. -/// -/// With this version, you shouldn't need to specify any of the (many) type -/// parameters explicitly. This can have a positive effect on type inference. -/// However, if you want specify `A`, you should use [`any::()`] instead. -/// -/// For clarity, it is often a good idea to specify the type generated, and -/// so using [`any::()`] can be a good idea. -/// -/// If you want to customize how the strategy is generated, use -/// [`arbitrary_with(args)`] where `args` is of type -/// `::Parameters`. -/// -/// # Example -/// -/// The function can be used as: -/// -/// ```rust -/// extern crate proptest; -/// use proptest::arbitrary::{arbitrary, StrategyFor}; -/// -/// fn gen_vec_usize() -> StrategyFor> { -/// arbitrary() -/// } -/// -/// # fn main() {} -/// ``` -/// -/// [`arbitrary_with(args)`]: fn.arbitrary_with.html -/// [`any::()`]: fn.any.html -/// [`Arbitrary`]: trait.Arbitrary.html -/// [`Strategy`]: ../strategy/trait.Strategy.html -#[must_use = "strategies do nothing unless used"] -pub fn arbitrary() -> S -where - // The backlinking here cause an injection which helps type inference. - S: Strategy, - A: Arbitrary, -{ - A::arbitrary() -} - -/// Generates a [`Strategy`] producing [`Arbitrary`] values of `A` with the -/// given configuration arguments passed in `args`. -/// Works better with type inference than [`any_with::(args)`]. -/// -/// With this version, you shouldn't need to specify any of the (many) type -/// parameters explicitly. This can have a positive effect on type inference. -/// However, if you want specify `A`, you should use -/// [`any_with::(args)`] instead. -/// -/// For clarity, it is often a good idea to specify the type generated, and -/// so using [`any_with::(args)`] can be a good idea. -/// -/// If you don't want to specify any arguments and instead use the default -/// behavior, you should use [`arbitrary()`]. -/// -/// # Example -/// -/// The function can be used as: -/// -/// ```rust -/// extern crate proptest; -/// use proptest::arbitrary::{arbitrary_with, StrategyFor}; -/// use proptest::collection::size_range; -/// -/// fn gen_vec_10_u32() -> StrategyFor> { -/// arbitrary_with(size_range(10).lift()) -/// } -/// -/// # fn main() {} -/// ``` -/// -/// [`any_with::(args)`]: fn.any_with.html -/// [`arbitrary()`]: fn.arbitrary.html -/// [`Arbitrary`]: trait.Arbitrary.html -/// [`Strategy`]: ../strategy/trait.Strategy.html -#[must_use = "strategies do nothing unless used"] -pub fn arbitrary_with(args: P) -> S -where - P: Default, - // The backlinking here cause an injection which helps type inference. - S: Strategy, - A: Arbitrary, -{ - A::arbitrary_with(args) -} diff --git a/library/proptest/src/arbitrary/tuples.rs b/library/proptest/src/arbitrary/tuples.rs deleted file mode 100644 index db86599304de..000000000000 --- a/library/proptest/src/arbitrary/tuples.rs +++ /dev/null @@ -1,47 +0,0 @@ -//- -// Copyright 2017, 2018 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Arbitrary implementations for tuples. - -use crate::arbitrary::{any_with, Arbitrary}; - -macro_rules! impl_tuple { - ($($typ: ident),*) => { - impl<$($typ : Arbitrary),*> Arbitrary for ($($typ,)*) { - type Parameters = product_type![$($typ::Parameters,)*]; - type Strategy = ($($typ::Strategy,)*); - fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { - #[allow(non_snake_case)] - let product_unpack![$($typ),*] = args; - ($(any_with::<$typ>($typ)),*,) - } - } - }; -} - -arbitrary!((); ()); -impl_tuple!(T0); -impl_tuple!(T0, T1); -impl_tuple!(T0, T1, T2); -impl_tuple!(T0, T1, T2, T3); -impl_tuple!(T0, T1, T2, T3, T4); -impl_tuple!(T0, T1, T2, T3, T4, T5); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8); -impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9); - -#[cfg(test)] -mod test { - no_panic_test!( - tuple_n10 => ((), bool, u8, u16, u32, u64, i8, i16, i32, i64) - ); -} diff --git a/library/proptest/src/bool.rs b/library/proptest/src/bool.rs deleted file mode 100644 index fca7ded985ae..000000000000 --- a/library/proptest/src/bool.rs +++ /dev/null @@ -1,87 +0,0 @@ -//- -// Copyright 2017 Jason Lingle -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Strategies for generating `bool` values. - -use crate::strategy::*; -use crate::test_runner::*; - -/// The type of the `ANY` constant. -#[derive(Clone, Copy, Debug)] -pub struct Any(()); - -/// Generates boolean values by picking `true` or `false` uniformly. -/// -/// Shrinks `true` to `false`. -pub const ANY: Any = Any(()); - -impl Strategy for Any { - type Tree = BoolValueTree; - type Value = bool; - - fn new_tree(&self, _: &mut TestRunner) -> NewTree { - Ok(BoolValueTree::new(kani::any())) - } -} - -/// Generates boolean values by picking `true` with the given `probability` -/// (1.0 = always true, 0.0 = always false). -/// -/// Shrinks `true` to `false`. -pub fn weighted(probability: f64) -> Weighted { - Weighted(probability) -} - -/// The return type from `weighted()`. -#[must_use = "strategies do nothing unless used"] -#[derive(Clone, Copy, Debug)] -pub struct Weighted(f64); - -impl Strategy for Weighted { - type Tree = BoolValueTree; - type Value = bool; - - fn new_tree(&self, _: &mut TestRunner) -> NewTree { - if self.0 >= 1.0 { - Ok(BoolValueTree::new(true)) - } else if self.0 <= 0.0 { - Ok(BoolValueTree::new(false)) - } else { - Ok(BoolValueTree::new(kani::any())) - } - } -} - -/// The `ValueTree` to shrink booleans to false. -#[derive(Clone, Copy, Debug)] -pub struct BoolValueTree { - current: bool, -} - -impl BoolValueTree { - fn new(current: bool) -> Self { - BoolValueTree { current } - } -} - -impl ValueTree for BoolValueTree { - type Value = bool; - - fn current(&self) -> bool { - self.current - } - fn simplify(&mut self) -> bool { - false - } - fn complicate(&mut self) -> bool { - false - } -} diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index cac77d5d86bd..def7921908a9 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -80,18 +80,18 @@ pub mod std_facade; #[doc(hidden)] #[macro_use] -pub mod sugar; +// pub mod sugar; -pub mod arbitrary; +// pub mod arbitrary; // pub mod array; // pub mod bits; -pub mod bool; +// pub mod bool; // pub mod char; // pub mod collection; -pub mod num; +// pub mod num; pub mod strategy; pub mod test_runner; -pub mod tuple; +// pub mod tuple; // pub mod option; // pub mod result; @@ -99,4 +99,4 @@ pub mod tuple; // #[cfg(feature = "std")] // pub mod string; -pub mod prelude; +// pub mod prelude; diff --git a/library/proptest/src/num.rs b/library/proptest/src/num.rs deleted file mode 100644 index 1913586856a1..000000000000 --- a/library/proptest/src/num.rs +++ /dev/null @@ -1,654 +0,0 @@ -//- -// Copyright 2017, 2018 Jason Lingle -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Strategies to generate numeric values (as opposed to integers used as bit -//! fields). -//! -//! All strategies in this module shrink by binary searching towards 0. - -use crate::test_runner::TestRunner; -use core::ops::Range; - -// Below 2 functions are the source of Kani symbolic variables. - -/// Produce an symbolic value from a range. -pub(crate) fn sample_uniform( - _: &mut TestRunner, - range: Range, -) -> X { - let value: X = kani::any(); - kani::assume(range.contains(&value)); - value -} - -/// Produce an symbolic value start and end values. End is inclusive. -pub(crate) fn sample_uniform_incl( - _: &mut TestRunner, - start: X, - end: X, -) -> X { - let value: X = kani::any(); - kani::assume(value <= end); - kani::assume(value >= start); - value -} - -macro_rules! int_any { - ($typ: ident) => { - /// Type of the `ANY` constant. - #[derive(Clone, Copy, Debug)] - #[must_use = "strategies do nothing unless used"] - pub struct Any(()); - /// Generates integers with completely arbitrary values, uniformly - /// distributed over the whole range. - pub const ANY: Any = Any(()); - - impl Strategy for Any { - type Tree = BinarySearch; - type Value = $typ; - - fn new_tree(&self, _: &mut TestRunner) -> NewTree { - Ok(BinarySearch::new(kani::any::<$typ>())) - } - } - }; -} - -macro_rules! numeric_api { - ($typ:ident, $epsilon:expr) => { - impl Strategy for ::core::ops::Range<$typ> { - type Tree = BinarySearch; - type Value = $typ; - - fn new_tree(&self, runner: &mut TestRunner) -> NewTree { - Ok(BinarySearch::new_clamped( - self.start, - $crate::num::sample_uniform(runner, self.clone()), - self.end - $epsilon, - )) - } - } - - impl Strategy for ::core::ops::RangeInclusive<$typ> { - type Tree = BinarySearch; - type Value = $typ; - - fn new_tree(&self, runner: &mut TestRunner) -> NewTree { - Ok(BinarySearch::new_clamped( - *self.start(), - $crate::num::sample_uniform_incl(runner, *self.start(), *self.end()), - *self.end(), - )) - } - } - - impl Strategy for ::core::ops::RangeFrom<$typ> { - type Tree = BinarySearch; - type Value = $typ; - - fn new_tree(&self, runner: &mut TestRunner) -> NewTree { - Ok(BinarySearch::new_clamped( - self.start, - $crate::num::sample_uniform_incl(runner, self.start, ::core::$typ::MAX), - ::core::$typ::MAX, - )) - } - } - - impl Strategy for ::core::ops::RangeTo<$typ> { - type Tree = BinarySearch; - type Value = $typ; - - fn new_tree(&self, runner: &mut TestRunner) -> NewTree { - Ok(BinarySearch::new_clamped( - ::core::$typ::MIN, - $crate::num::sample_uniform(runner, ::core::$typ::MIN..self.end), - self.end, - )) - } - } - - impl Strategy for ::core::ops::RangeToInclusive<$typ> { - type Tree = BinarySearch; - type Value = $typ; - - fn new_tree(&self, runner: &mut TestRunner) -> NewTree { - Ok(BinarySearch::new_clamped( - ::core::$typ::MIN, - $crate::num::sample_uniform_incl(runner, ::core::$typ::MIN, self.end), - self.end, - )) - } - } - }; -} - -macro_rules! signed_integer_bin_search { - ($typ:ident) => { - #[allow(missing_docs)] - pub mod $typ { - - use crate::strategy::*; - use crate::test_runner::TestRunner; - - int_any!($typ); - - /// Shrinks an integer towards 0, using binary search to find - /// boundary points. - #[derive(Clone, Copy, Debug)] - pub struct BinarySearch { - curr: $typ, - } - impl BinarySearch { - /// Creates a new binary searcher starting at the given value. - pub fn new(start: $typ) -> Self { - BinarySearch { curr: start } - } - - /// Creates a new binary searcher which will not produce values - /// on the other side of `lo` or `hi` from `start`. `lo` is - /// inclusive, `hi` is exclusive. - fn new_clamped(_: $typ, start: $typ, _: $typ) -> Self { - BinarySearch { curr: start } - } - } - impl ValueTree for BinarySearch { - type Value = $typ; - - fn current(&self) -> $typ { - self.curr - } - - fn simplify(&mut self) -> bool { - return false; - } - - fn complicate(&mut self) -> bool { - return false; - } - } - - numeric_api!($typ, 1); - } - }; -} - -macro_rules! unsigned_integer_bin_search { - ($typ:ident) => { - #[allow(missing_docs)] - pub mod $typ { - - use crate::strategy::*; - use crate::test_runner::TestRunner; - - int_any!($typ); - - /// Shrinks an integer towards 0, using binary search to find - /// boundary points. - #[derive(Clone, Copy, Debug)] - pub struct BinarySearch { - curr: $typ, - } - impl BinarySearch { - /// Creates a new binary searcher starting at the given value. - pub fn new(start: $typ) -> Self { - BinarySearch { curr: start } - } - - /// Creates a new binary searcher which will not search below - /// the given `lo` value. - fn new_clamped(_: $typ, start: $typ, _: $typ) -> Self { - BinarySearch { curr: start } - } - - /// Creates a new binary searcher which will not search below - /// the given `lo` value. - pub fn new_above(lo: $typ, start: $typ) -> Self { - BinarySearch::new_clamped(lo, start, start) - } - } - impl ValueTree for BinarySearch { - type Value = $typ; - - fn current(&self) -> $typ { - self.curr - } - - fn simplify(&mut self) -> bool { - return false; - } - - fn complicate(&mut self) -> bool { - return false; - } - } - - numeric_api!($typ, 1); - } - }; -} - -signed_integer_bin_search!(i8); -signed_integer_bin_search!(i16); -signed_integer_bin_search!(i32); -signed_integer_bin_search!(i64); -#[cfg(not(target_arch = "wasm32"))] -signed_integer_bin_search!(i128); -signed_integer_bin_search!(isize); -unsigned_integer_bin_search!(u8); -unsigned_integer_bin_search!(u16); -unsigned_integer_bin_search!(u32); -unsigned_integer_bin_search!(u64); -#[cfg(not(target_arch = "wasm32"))] -unsigned_integer_bin_search!(u128); -unsigned_integer_bin_search!(usize); - -#[derive(Clone, Copy, Debug)] -pub(crate) struct FloatTypes(u32); - -impl std::ops::BitOr for FloatTypes { - type Output = Self; - - fn bitor(self, rhs: Self) -> Self { - Self(self.0 | rhs.0) - } -} - -impl std::ops::BitOrAssign for FloatTypes { - fn bitor_assign(&mut self, rhs: Self) { - self.0 |= rhs.0 - } -} - -impl FloatTypes { - const POSITIVE: FloatTypes = FloatTypes(0b0000_0001); - const NEGATIVE: FloatTypes = FloatTypes(0b0000_0010); - const NORMAL: FloatTypes = FloatTypes(0b0000_0100); - const SUBNORMAL: FloatTypes = FloatTypes(0b0000_1000); - const ZERO: FloatTypes = FloatTypes(0b0001_0000); - const INFINITE: FloatTypes = FloatTypes(0b0010_0000); - const QUIET_NAN: FloatTypes = FloatTypes(0b0100_0000); - const SIGNALING_NAN: FloatTypes = FloatTypes(0b1000_0000); - const ANY: FloatTypes = FloatTypes(0b1111_1111); - - fn intersects(&self, other: Self) -> bool { - let intersection = self.0 & other.0; - intersection != 0 - } - - fn contains(&self, other: Self) -> bool { - let intersection = self.0 & other.0; - intersection == other.0 - } - - fn normalise(mut self) -> Self { - if !self.intersects(FloatTypes::POSITIVE | FloatTypes::NEGATIVE) { - self |= FloatTypes::POSITIVE; - } - - if !self.intersects( - FloatTypes::NORMAL - | FloatTypes::SUBNORMAL - | FloatTypes::ZERO - | FloatTypes::INFINITE - | FloatTypes::QUIET_NAN - | FloatTypes::SIGNALING_NAN, - ) { - self |= FloatTypes::NORMAL; - } - self - } -} - -trait FloatLayout { - type Bits: Copy; - - const SIGN_MASK: Self::Bits; - const EXP_MASK: Self::Bits; - const EXP_ZERO: Self::Bits; - const MANTISSA_MASK: Self::Bits; -} - -impl FloatLayout for f32 { - type Bits = u32; - - const SIGN_MASK: u32 = 0x8000_0000; - const EXP_MASK: u32 = 0x7F80_0000; - const EXP_ZERO: u32 = 0x3F80_0000; - const MANTISSA_MASK: u32 = 0x007F_FFFF; -} - -impl FloatLayout for f64 { - type Bits = u64; - - const SIGN_MASK: u64 = 0x8000_0000_0000_0000; - const EXP_MASK: u64 = 0x7FF0_0000_0000_0000; - const EXP_ZERO: u64 = 0x3FF0_0000_0000_0000; - const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF; -} - -macro_rules! float_any { - ($typ:ident) => { - /// Strategies which produce floating-point values from particular - /// classes. See the various `Any`-typed constants in this module. - /// - /// Note that this usage is fairly advanced and primarily useful to - /// implementors of algorithms that need to handle wild values in a - /// particular way. For testing things like graphics processing or game - /// physics, simply using ranges (e.g., `-1.0..2.0`) will often be more - /// practical. - /// - /// `Any` can be OR'ed to combine multiple classes. For example, - /// `POSITIVE | INFINITE` will generate arbitrary positive, non-NaN - /// floats, including positive infinity (but not negative infinity, of - /// course). - /// - /// If neither `POSITIVE` nor `NEGATIVE` has been OR'ed into an `Any` - /// but a type to be generated requires a sign, `POSITIVE` is assumed. - /// If no classes are OR'ed into an `Any` (i.e., only `POSITIVE` and/or - /// `NEGATIVE` are given), `NORMAL` is assumed. - /// - /// The various float classes are assigned fixed weights for generation - /// which are believed to be reasonable for most applications. Roughly: - /// - /// - If `POSITIVE | NEGATIVE`, the sign is evenly distributed between - /// both options. - /// - /// - Classes are weighted as follows, in descending order: - /// `NORMAL` > `ZERO` > `SUBNORMAL` > `INFINITE` > `QUIET_NAN` = - /// `SIGNALING_NAN`. - #[derive(Clone, Copy, Debug)] - #[must_use = "strategies do nothing unless used"] - pub struct Any(FloatTypes); - - impl ops::BitOr for Any { - type Output = Self; - - fn bitor(self, rhs: Self) -> Self { - Any(self.0 | rhs.0) - } - } - - impl ops::BitOrAssign for Any { - fn bitor_assign(&mut self, rhs: Self) { - self.0 |= rhs.0 - } - } - - /// Generates positive floats - /// - /// By itself, implies the `NORMAL` class, unless another class is - /// OR'ed in. That is, using `POSITIVE` as a strategy by itself will - /// generate arbitrary values between the type's `MIN_POSITIVE` and - /// `MAX`, while `POSITIVE | INFINITE` would only allow generating - /// positive infinity. - pub const POSITIVE: Any = Any(FloatTypes::POSITIVE); - /// Generates negative floats. - /// - /// By itself, implies the `NORMAL` class, unless another class is - /// OR'ed in. That is, using `POSITIVE` as a strategy by itself will - /// generate arbitrary values between the type's `MIN` and - /// `-MIN_POSITIVE`, while `NEGATIVE | INFINITE` would only allow - /// generating positive infinity. - pub const NEGATIVE: Any = Any(FloatTypes::NEGATIVE); - /// Generates "normal" floats. - /// - /// These are finite values where the first bit of the mantissa is an - /// implied `1`. When positive, this represents the range - /// `MIN_POSITIVE` through `MAX`, both inclusive. - /// - /// Generated values are uniform over the discrete floating-point - /// space, which means the numeric distribution is an inverse - /// exponential step function. For example, values between 1.0 and 2.0 - /// are generated with the same frequency as values between 2.0 and - /// 4.0, even though the latter covers twice the numeric range. - /// - /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, - /// `POSITIVE` is implied. - pub const NORMAL: Any = Any(FloatTypes::NORMAL); - /// Generates subnormal floats. - /// - /// These are finite non-zero values where the first bit of the - /// mantissa is not an implied zero. When positive, this represents the - /// range `MIN`, inclusive, through `MIN_POSITIVE`, exclusive. - /// - /// Subnormals are generated with a uniform distribution both in terms - /// of discrete floating-point space and numerically. - /// - /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, - /// `POSITIVE` is implied. - pub const SUBNORMAL: Any = Any(FloatTypes::SUBNORMAL); - /// Generates zero-valued floats. - /// - /// Note that IEEE floats support both positive and negative zero, so - /// this class does interact with the sign flags. - /// - /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, - /// `POSITIVE` is implied. - pub const ZERO: Any = Any(FloatTypes::ZERO); - /// Generates infinity floats. - /// - /// If neither `POSITIVE` nor `NEGATIVE` is OR'ed with this constant, - /// `POSITIVE` is implied. - pub const INFINITE: Any = Any(FloatTypes::INFINITE); - /// Generates "Quiet NaN" floats. - /// - /// Operations on quiet NaNs generally simply propagate the NaN rather - /// than invoke any exception mechanism. - /// - /// The payload of the NaN is uniformly distributed over the possible - /// values which safe Rust allows, including the sign bit (as - /// controlled by `POSITIVE` and `NEGATIVE`). - /// - /// Note however that in Rust 1.23.0 and earlier, this constitutes only - /// one particular payload due to apparent issues with particular MIPS - /// and PA-RISC processors which fail to implement IEEE 754-2008 - /// correctly. - /// - /// On Rust 1.24.0 and later, this does produce arbitrary payloads as - /// documented. - /// - /// On platforms where the CPU and the IEEE standard disagree on the - /// format of a quiet NaN, values generated conform to the hardware's - /// expectations. - pub const QUIET_NAN: Any = Any(FloatTypes::QUIET_NAN); - /// Generates "Signaling NaN" floats if allowed by the platform. - /// - /// On most platforms, signalling NaNs by default behave the same as - /// quiet NaNs, but it is possible to configure the OS or CPU to raise - /// an asynchronous exception if an operation is performed on a - /// signalling NaN. - /// - /// In Rust 1.23.0 and earlier, this silently behaves the same as - /// [`QUIET_NAN`](const.QUIET_NAN.html). - /// - /// On platforms where the CPU and the IEEE standard disagree on the - /// format of a quiet NaN, values generated conform to the hardware's - /// expectations. - /// - /// Note that certain platforms — most notably, x86/AMD64 — allow the - /// architecture to turn a signalling NaN into a quiet NaN with the - /// same payload. Whether this happens can depend on what registers the - /// compiler decides to use to pass the value around, what CPU flags - /// are set, and what compiler settings are in use. - pub const SIGNALING_NAN: Any = Any(FloatTypes::SIGNALING_NAN); - - /// Generates literally arbitrary floating-point values, including - /// infinities and quiet NaNs (but not signaling NaNs). - /// - /// Equivalent to `POSITIVE | NEGATIVE | NORMAL | SUBNORMAL | ZERO | - /// INFINITE | QUIET_NAN`. - /// - /// See [`SIGNALING_NAN`](const.SIGNALING_NAN.html) if you also want to - /// generate signalling NaNs. This signalling NaNs are not included by - /// default since in most contexts they either make no difference, or - /// if the process enabled the relevant CPU mode, result in - /// hardware-triggered exceptions that usually just abort the process. - /// - /// Before proptest 0.4.1, this erroneously generated values in the - /// range 0.0..1.0. - pub const ANY: Any = Any(FloatTypes::ANY); - - impl Strategy for Any { - type Tree = BinarySearch; - type Value = $typ; - - fn new_tree(&self, _: &mut TestRunner) -> NewTree { - let flags = self.0.normalise(); - let sign_mask = if flags.contains(FloatTypes::NEGATIVE) { - $typ::SIGN_MASK - } else { - 0 - }; - let sign_or = if flags.contains(FloatTypes::POSITIVE) { - 0 - } else { - $typ::SIGN_MASK - }; - - // A few CPUs disagree with IEEE about the meaning of the - // signalling bit. Assume the `NAN` constant is a quiet NaN as - // interpreted by the hardware and generate values based on - // that. - let quiet_or = ::core::$typ::NAN.to_bits() & - ($typ::EXP_MASK | ($typ::EXP_MASK >> 1)); - let signaling_or = (quiet_or ^ ($typ::EXP_MASK >> 1)) | - $typ::EXP_MASK; - - let (class_mask, class_or, allow_edge_exp, allow_zero_mant) = - || -> (_, _, bool, bool) { - let can_match_after = - flags.contains(FloatTypes::SUBNORMAL) || - flags.contains(FloatTypes::ZERO) || - flags.contains(FloatTypes::INFINITE) || - flags.contains(FloatTypes::QUIET_NAN) || - flags.contains(FloatTypes::SIGNALING_NAN); - if flags.contains(FloatTypes::NORMAL) && (!can_match_after || kani::any()) { - return ($typ::EXP_MASK | $typ::MANTISSA_MASK, 0, false, true); - } - - let can_match_after = - flags.contains(FloatTypes::ZERO) || - flags.contains(FloatTypes::INFINITE) || - flags.contains(FloatTypes::QUIET_NAN) || - flags.contains(FloatTypes::SIGNALING_NAN); - if flags.contains(FloatTypes::SUBNORMAL) && (!can_match_after || kani::any()) { - return ($typ::MANTISSA_MASK, 0, true, false) - } - - let can_match_after = - flags.contains(FloatTypes::INFINITE) || - flags.contains(FloatTypes::QUIET_NAN) || - flags.contains(FloatTypes::SIGNALING_NAN); - if flags.contains(FloatTypes::ZERO) && (!can_match_after || kani::any()) { - return (0, 0, true, true); - } - - let can_match_after = - flags.contains(FloatTypes::QUIET_NAN) || - flags.contains(FloatTypes::SIGNALING_NAN); - if flags.contains(FloatTypes::INFINITE) && (!can_match_after || kani::any()) { - return (0, $typ::EXP_MASK, true, true); - } - - let can_match_after = flags.contains(FloatTypes::SIGNALING_NAN); - if flags.contains(FloatTypes::QUIET_NAN) && (!can_match_after || kani::any()) { - return ($typ::MANTISSA_MASK >> 1, quiet_or, true, false); - } - - if flags.contains(FloatTypes::SIGNALING_NAN) { - return ($typ::MANTISSA_MASK >> 1, signaling_or,true, false); - } - - panic!("This should not be reachable. This is a bug in Kani or Kani's proptest library") - }(); - - let mut generated_value: <$typ as FloatLayout>::Bits = kani::any(); - generated_value &= sign_mask | class_mask; - generated_value |= sign_or | class_or; - let exp = generated_value & $typ::EXP_MASK; - if !allow_edge_exp && (0 == exp || $typ::EXP_MASK == exp) { - generated_value &= !$typ::EXP_MASK; - generated_value |= $typ::EXP_ZERO; - } - if !allow_zero_mant && - 0 == generated_value & $typ::MANTISSA_MASK - { - generated_value |= 1; - } - - Ok(BinarySearch::new_with_types( - $typ::from_bits(generated_value), flags)) - } - } - } -} - -macro_rules! float_bin_search { - ($typ:ident) => { - #[allow(missing_docs)] - pub mod $typ { - use super::{FloatLayout, FloatTypes}; - use crate::strategy::*; - use crate::test_runner::TestRunner; - use core::ops; - - float_any!($typ); - - /// Binary Search Strategy Modified for Kani. It does not - /// perform any random search, but rather returns a - /// symbolic current value. - #[derive(Clone, Copy, Debug)] - pub struct BinarySearch { - curr: $typ, - } - - impl BinarySearch { - /// Creates a new binary searcher starting at the given value. - pub fn new(start: $typ) -> Self { - BinarySearch { curr: start } - } - - fn new_with_types(start: $typ, _: FloatTypes) -> Self { - BinarySearch { curr: start } - } - - /// Creates a new binary searcher which will not produce values - /// on the other side of `lo` or `hi` from `start`. `lo` is - /// inclusive, `hi` is exclusive. - fn new_clamped(_: $typ, start: $typ, _: $typ) -> Self { - BinarySearch { curr: start } - } - } - - impl ValueTree for BinarySearch { - type Value = $typ; - - fn current(&self) -> $typ { - self.curr - } - - fn simplify(&mut self) -> bool { - false - } - - fn complicate(&mut self) -> bool { - false - } - } - - numeric_api!($typ, 0.0); - } - }; -} - -float_bin_search!(f32); -float_bin_search!(f64); diff --git a/library/proptest/src/prelude.rs b/library/proptest/src/prelude.rs deleted file mode 100644 index a218fecb6bc6..000000000000 --- a/library/proptest/src/prelude.rs +++ /dev/null @@ -1,52 +0,0 @@ -//- -// Copyright 2017, 2018, 2019 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Re-exports the most commonly-needed APIs of proptest. -//! -//! This module is intended to be wildcard-imported, i.e., -//! `use proptest::prelude::*;`. Note that it re-exports the whole crate itself -//! under the name `prop`, so you don't need a separate `use proptest;` line. -//! -//! In addition to Proptest's own APIs, this also reexports a small portion of -//! the `rand` crate sufficient to easily use `prop_perturb` and other -//! functionality that exposes random number generators. Please note that this -//! is will always be a direct reexport; using these in preference to using the -//! `rand` crate directly will not provide insulation from the upcoming -//! revision to the `rand` crate. - -pub use crate::arbitrary::{any, any_with, Arbitrary}; -pub use crate::strategy::{BoxedStrategy, Just, SBoxedStrategy, Strategy}; -pub use crate::test_runner::Config as ProptestConfig; -pub use crate::{ - prop_assert, prop_assert_eq, prop_assert_ne, prop_assume, prop_compose, prop_oneof, proptest, -}; - -/// Re-exports the entire public API of proptest so that an import of `prelude` -/// allows simply writing, for example, `prop::num::i32::ANY` rather than -/// `proptest::num::i32::ANY` plus a separate `use proptest;`. -pub mod prop { - pub use crate::arbitrary; - // todo: Implement the missing proptest features. - // pub use crate::array; - // pub use crate::bits; - pub use crate::bool; - // pub use crate::char; - // pub use crate::collection; - pub use crate::num; - // pub use crate::option; - // pub use crate::result; - // pub use crate::sample; - pub use crate::strategy; - #[cfg(feature = "std")] - pub use crate::string; - pub use crate::test_runner; - pub use crate::tuple; -} diff --git a/library/proptest/src/sugar.rs b/library/proptest/src/sugar.rs deleted file mode 100644 index 4f0fb4bc1091..000000000000 --- a/library/proptest/src/sugar.rs +++ /dev/null @@ -1,1121 +0,0 @@ -//- -// Copyright 2017, 2019 The proptest developers -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -// use crate::std_facade::fmt; - -/// Easily define `proptest` tests. -/// -/// Within `proptest!`, define one or more functions without return type -/// normally, except instead of putting `: type` after each parameter, write -/// `in strategy`, where `strategy` is an expression evaluating to some -/// `Strategy`. -/// -/// Each function will be wrapped in a function which sets up a `TestRunner`, -/// and then invokes the function body with inputs generated according to the -/// strategies. -/// -/// ### Example -/// -/// ``` -/// use proptest::prelude::*; -/// -/// proptest! { -/// # /* -/// #[test] -/// # */ -/// fn test_addition(a in 0..10, b in 0..10) { -/// prop_assert!(a + b <= 18); -/// } -/// -/// # /* -/// #[test] -/// # */ -/// fn test_string_concat(a in ".*", b in ".*") { -/// let cat = format!("{}{}", a, b); -/// prop_assert_eq!(a.len() + b.len(), cat.len()); -/// } -/// } -/// # -/// # fn main() { test_addition(); test_string_concat(); } -/// ``` -/// -/// You can also use the normal argument syntax `pattern: type` as in: -/// -/// ```rust -/// use proptest::prelude::*; -/// -/// proptest! { -/// # /* -/// #[test] -/// # */ -/// fn addition_is_commutative(a: u8, b: u8) { -/// prop_assert_eq!(a as u16 + b as u16, b as u16 + a as u16); -/// } -/// -/// # /* -/// #[test] -/// # */ -/// fn test_string_concat(a in ".*", b: String) { -/// let cat = format!("{}{}", a, b); -/// prop_assert_eq!(a.len() + b.len(), cat.len()); -/// } -/// } -/// # -/// # fn main() { addition_is_commutative(); test_string_concat(); } -/// ``` -/// -/// As you can see, you can mix `pattern: type` and `pattern in expr`. -/// Due to limitations in `macro_rules!`, `pattern: type` does not work in -/// all circumstances. In such a case, use `(pattern): type` instead. -/// -/// To override the default configuration, you can start the `proptest!` block -/// with `#![proptest_config(expr)]`, where `expr` is an expression that -/// evaluates to a `proptest::test_runner::Config` (or a reference to one). -/// -/// ``` -/// use proptest::prelude::*; -/// -/// proptest! { -/// #![proptest_config(ProptestConfig { -/// cases: 99, .. ProptestConfig::default() -/// })] -/// # /* -/// #[test] -/// # */ -/// fn test_addition(a in 0..10, b in 0..10) { -/// prop_assert!(a + b <= 18); -/// } -/// } -/// # -/// # fn main() { test_addition(); } -/// ``` -/// -/// ## Closure-Style Invocation -/// -/// As of proptest 0.8.1, an alternative, "closure-style" invocation is -/// supported. In this form, `proptest!` is a function-like macro taking a -/// closure-esque argument. This makes it possible to run multiple tests that -/// require some expensive setup process. Note that the "fork" and "timeout" -/// features are _not_ supported in closure style. -/// -/// To use a custom configuration, pass the `Config` object as a first -/// argument. -/// -/// ### Example -/// -/// ``` -/// use proptest::prelude::*; -/// -/// #[derive(Debug)] -/// struct BigStruct { /* Lots of fields ... */ } -/// -/// fn very_expensive_function() -> BigStruct { -/// // Lots of code... -/// BigStruct { /* fields */ } -/// } -/// -/// # /* -/// #[test] -/// # */ -/// fn my_test() { -/// // We create just one `BigStruct` -/// let big_struct = very_expensive_function(); -/// -/// // But now can run multiple tests without needing to build it every time. -/// // Note the extra parentheses around the arguments are currently -/// // required. -/// proptest!(|(x in 0u32..42u32, y in 1000u32..100000u32)| { -/// // Test stuff -/// }); -/// -/// // `move` closures are also supported -/// proptest!(move |(x in 0u32..42u32)| { -/// // Test other stuff -/// }); -/// -/// // You can pass a custom configuration as the first argument -/// proptest!(ProptestConfig::with_cases(1000), |(x: i32)| { -/// // Test more stuff -/// }); -/// } -/// # -/// # fn main() { my_test(); } -/// ``` -#[macro_export] -macro_rules! proptest { - (#![proptest_config($config:expr)] - $( - $(#[$meta:meta])* - fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block - )*) => { - $( - #[kani::proof] - $(#[$meta])* - fn $test_name() { //rule meta_strategy - // let mut config = $config.clone(); - // config.test_name = Some( - // concat!(module_path!(), "::meta_strategy::", stringify!($test_name))); - $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body); - } - )* - }; - (#![proptest_config($config:expr)] - $( - $(#[$meta:meta])* - fn $test_name:ident($($arg:tt)+) $body:block - )*) => { - $( - #[kani::proof] - $(#[$meta])* - fn $test_name() { //rule meta_type - // let mut config = $config.clone(); - // config.test_name = Some( - // concat!(module_path!(), "::meta_type::", stringify!($test_name))); - $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); - } - )* - }; - - ($( - $(#[$meta:meta])* - fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block - )*) => { $crate::proptest! { - #![proptest_config($crate::test_runner::Config::default())] - $($(#[$meta])* - fn $test_name($($parm in $strategy),+) $body)* - } }; - - ($( - $(#[$meta:meta])* - fn $test_name:ident($($arg:tt)+) $body:block - )*) => { $crate::proptest! { - #![proptest_config($crate::test_runner::Config::default())] - $($(#[$meta])* - fn $test_name($($arg)+) $body)* - } }; - - (|($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { - $crate::proptest!( - $crate::test_runner::Config::default(), - |($($parm in $strategy),+)| $body) - }; - - (move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { - $crate::proptest!( - $crate::test_runner::Config::default(), - move |($($parm in $strategy),+)| $body) - }; - - (|($($arg:tt)+)| $body:expr) => { - $crate::proptest!( - $crate::test_runner::Config::default(), - |($($arg)+)| $body) - }; - - (move |($($arg:tt)+)| $body:expr) => { - $crate::proptest!( - $crate::test_runner::Config::default(), - move |($($arg)+)| $body) - }; - - ($config:expr, |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { { - let mut config = $config.__sugar_to_owned(); - $crate::sugar::force_no_fork(&mut config); - $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body) - } }; - - ($config:expr, move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { { - let mut config = $config.__sugar_to_owned(); - $crate::sugar::force_no_fork(&mut config); - $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [move] $body) - } }; - - ($config:expr, |($($arg:tt)+)| $body:expr) => { { - let mut config = $config.__sugar_to_owned(); - $crate::sugar::force_no_fork(&mut config); - $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); - } }; - - ($config:expr, move |($($arg:tt)+)| $body:expr) => { { - let mut config = $config.__sugar_to_owned(); - $crate::sugar::force_no_fork(&mut config); - $crate::proptest_helper!(@_BODY2 config ($($arg)+) [move] $body); - } }; -} - -/// Rejects the test input if assumptions are not met. -/// -/// Used directly within a function defined with `proptest!` or in any function -/// returning `Result<_, TestCaseError>`. -/// -/// This is invoked as `prop_assume!(condition, format, args...)`. `condition` -/// is evaluated; if it is false, `Err(TestCaseError::Reject)` is returned. The -/// message includes the point of invocation and the format message. `format` -/// and `args` may be omitted to simply use the condition itself as the -/// message. -#[macro_export] -macro_rules! prop_assume { - ($expr:expr) => { - $crate::prop_assume!($expr, "{}", stringify!($expr)) - }; - - ($expr:expr, $fmt:tt $(, $fmt_arg:expr),* $(,)?) => { - if !$expr { - return ::core::result::Result::Err( - $crate::test_runner::TestCaseError::reject( - format!(concat!("{}:{}:{}: ", $fmt), - file!(), line!(), column!() - $(, $fmt_arg)*))); - } - }; -} - -/// Produce a strategy which picks one of the listed choices. -/// -/// This is conceptually equivalent to calling `prop_union` on the first two -/// elements and then chaining `.or()` onto the rest after implicitly boxing -/// all of them. As with `Union`, values shrink across elements on the -/// assumption that earlier ones are "simpler", so they should be listed in -/// order of ascending complexity when possible. -/// -/// The macro invocation has two forms. The first is to simply list the -/// strategies separated by commas; this will cause value generation to pick -/// from the strategies uniformly. The other form is to provide a weight in the -/// form of a `u32` before each strategy, separated from the strategy with -/// `=>`. -/// -/// Note that the exact type returned by the macro varies depending on how many -/// inputs there are. In particular, if given exactly one option, it will -/// return it unmodified. It is not recommended to depend on the particular -/// type produced by this macro. -/// -/// ## Example -/// -/// ```rust,no_run -/// use proptest::prelude::*; -/// -/// #[derive(Clone, Copy, Debug)] -/// enum MyEnum { -/// Big(u64), -/// Medium(u32), -/// Little(i16), -/// } -/// -/// # #[allow(unused_variables)] -/// # fn main() { -/// let my_enum_strategy = prop_oneof![ -/// prop::num::i16::ANY.prop_map(MyEnum::Little), -/// prop::num::u32::ANY.prop_map(MyEnum::Medium), -/// prop::num::u64::ANY.prop_map(MyEnum::Big), -/// ]; -/// -/// let my_weighted_strategy = prop_oneof![ -/// 1 => prop::num::i16::ANY.prop_map(MyEnum::Little), -/// // Chose `Medium` twice as frequently as either `Little` or `Big`; i.e., -/// // around 50% of values will be `Medium`, and 25% for each of `Little` -/// // and `Big`. -/// 2 => prop::num::u32::ANY.prop_map(MyEnum::Medium), -/// 1 => prop::num::u64::ANY.prop_map(MyEnum::Big), -/// ]; -/// # } -/// ``` -#[macro_export] -macro_rules! prop_oneof { - ($($item:expr),+ $(,)?) => { - $crate::prop_oneof![ - $(1 => $item),* - ] - }; - - ($_weight0:expr => $item0:expr $(,)?) => { $item0 }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr, - $weight3:expr => $item3:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)), - ($weight3, $crate::std_facade::Arc::new($item3)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr, - $weight3:expr => $item3:expr, - $weight4:expr => $item4:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)), - ($weight3, $crate::std_facade::Arc::new($item3)), - ($weight4, $crate::std_facade::Arc::new($item4)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr, - $weight3:expr => $item3:expr, - $weight4:expr => $item4:expr, - $weight5:expr => $item5:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)), - ($weight3, $crate::std_facade::Arc::new($item3)), - ($weight4, $crate::std_facade::Arc::new($item4)), - ($weight5, $crate::std_facade::Arc::new($item5)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr, - $weight3:expr => $item3:expr, - $weight4:expr => $item4:expr, - $weight5:expr => $item5:expr, - $weight6:expr => $item6:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)), - ($weight3, $crate::std_facade::Arc::new($item3)), - ($weight4, $crate::std_facade::Arc::new($item4)), - ($weight5, $crate::std_facade::Arc::new($item5)), - ($weight6, $crate::std_facade::Arc::new($item6)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr, - $weight3:expr => $item3:expr, - $weight4:expr => $item4:expr, - $weight5:expr => $item5:expr, - $weight6:expr => $item6:expr, - $weight7:expr => $item7:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)), - ($weight3, $crate::std_facade::Arc::new($item3)), - ($weight4, $crate::std_facade::Arc::new($item4)), - ($weight5, $crate::std_facade::Arc::new($item5)), - ($weight6, $crate::std_facade::Arc::new($item6)), - ($weight7, $crate::std_facade::Arc::new($item7)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr, - $weight3:expr => $item3:expr, - $weight4:expr => $item4:expr, - $weight5:expr => $item5:expr, - $weight6:expr => $item6:expr, - $weight7:expr => $item7:expr, - $weight8:expr => $item8:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)), - ($weight3, $crate::std_facade::Arc::new($item3)), - ($weight4, $crate::std_facade::Arc::new($item4)), - ($weight5, $crate::std_facade::Arc::new($item5)), - ($weight6, $crate::std_facade::Arc::new($item6)), - ($weight7, $crate::std_facade::Arc::new($item7)), - ($weight8, $crate::std_facade::Arc::new($item8)))) - }; - - ($weight0:expr => $item0:expr, - $weight1:expr => $item1:expr, - $weight2:expr => $item2:expr, - $weight3:expr => $item3:expr, - $weight4:expr => $item4:expr, - $weight5:expr => $item5:expr, - $weight6:expr => $item6:expr, - $weight7:expr => $item7:expr, - $weight8:expr => $item8:expr, - $weight9:expr => $item9:expr $(,)?) => { - $crate::strategy::TupleUnion::new( - (($weight0, $crate::std_facade::Arc::new($item0)), - ($weight1, $crate::std_facade::Arc::new($item1)), - ($weight2, $crate::std_facade::Arc::new($item2)), - ($weight3, $crate::std_facade::Arc::new($item3)), - ($weight4, $crate::std_facade::Arc::new($item4)), - ($weight5, $crate::std_facade::Arc::new($item5)), - ($weight6, $crate::std_facade::Arc::new($item6)), - ($weight7, $crate::std_facade::Arc::new($item7)), - ($weight8, $crate::std_facade::Arc::new($item8)), - ($weight9, $crate::std_facade::Arc::new($item9)))) - }; - - ($($weight:expr => $item:expr),+ $(,)?) => { - $crate::strategy::Union::new_weighted(vec![ - $(($weight, $crate::strategy::Strategy::boxed($item))),* - ]) - }; -} - -/// Convenience to define functions which produce new strategies. -/// -/// The macro has two general forms. In the first, you define a function with -/// two argument lists. The first argument list uses the usual syntax and -/// becomes exactly the argument list of the defined function. The second -/// argument list uses the `in strategy` syntax as with `proptest!`, and is -/// used to generate the other inputs for the function. The second argument -/// list has access to all arguments in the first. The return type indicates -/// the type of value being generated; the final return type of the function is -/// `impl Strategy`. -/// -/// ```rust,no_run -/// # #![allow(dead_code)] -/// use proptest::prelude::*; -/// -/// #[derive(Clone, Debug)] -/// struct MyStruct { -/// integer: u32, -/// string: String, -/// } -/// -/// prop_compose! { -/// fn my_struct_strategy(max_integer: u32) -/// (integer in 0..max_integer, string in ".*") -/// -> MyStruct { -/// MyStruct { integer, string } -/// } -/// } -/// # -/// # fn main() { } -/// ``` -/// -/// This form is simply sugar around making a tuple and then calling `prop_map` -/// on it. You can also use `arg: type` as in `proptest! { .. }`: -/// -/// ```rust,no_run -/// # #![allow(dead_code)] -/// # use proptest::prelude::*; -/// # -/// # #[derive(Clone, Debug)] -/// # struct MyStruct { -/// # integer: u32, -/// # string: String, -/// # } -/// -/// prop_compose! { -/// fn my_struct_strategy(max_integer: u32) -/// (integer in 0..max_integer, string: String) -/// -> MyStruct { -/// MyStruct { integer, string } -/// } -/// } -/// # -/// # fn main() { } -/// ``` -/// -/// The second form is mostly the same, except that it takes _three_ argument -/// lists. The third argument list can see all values in both prior, which -/// permits producing strategies based on other strategies. -/// -/// ```rust,no_run -/// # #![allow(dead_code)] -/// use proptest::prelude::*; -/// -/// prop_compose! { -/// fn nearby_numbers()(centre in -1000..1000) -/// (a in centre-10..centre+10, -/// b in centre-10..centre+10) -/// -> (i32, i32) { -/// (a, b) -/// } -/// } -/// # -/// # fn main() { } -/// ``` -/// -/// However, the body of the function does _not_ have access to the second -/// argument list. If the body needs access to those values, they must be -/// passed through explicitly. -/// -/// ```rust,no_run -/// # #![allow(dead_code)] -/// use proptest::prelude::*; -/// -/// prop_compose! { -/// fn vec_and_index -/// (max_length: usize) -/// (vec in prop::collection::vec(1..10, 1..max_length)) -/// (index in 0..vec.len(), vec in Just(vec)) -/// -> (Vec, usize) -/// { -/// (vec, index) -/// } -/// } -/// # fn main() { } -/// ``` -/// -/// The second form is sugar around making a strategy tuple, calling -/// `prop_flat_map()`, then `prop_map()`. -/// -/// To give the function any modifier which isn't a visibility modifier, put it -/// in brackets before the `fn` token but after any visibility modifier. -/// -/// ```rust,no_run -/// # #![allow(dead_code)] -/// use proptest::prelude::*; -/// -/// prop_compose! { -/// pub(crate) [unsafe] fn pointer()(v in prop::num::usize::ANY) -/// -> *const () { -/// v as *const () -/// } -/// } -/// # fn main() { } -/// ``` -/// -/// ## Comparison with Hypothesis' `@composite` -/// -/// `prop_compose!` makes it easy to do a lot of things you can do with -/// [Hypothesis' `@composite`](https://hypothesis.readthedocs.io/en/latest/data.html#composite-strategies), -/// but not everything. -/// -/// - You can't filter via this macro. For filtering, you need to make the -/// strategy the "normal" way and use `prop_filter()`. -/// -/// - More than two layers of strategies or arbitrary logic between the two -/// layers. If you need either of these, you can achieve them by calling -/// `prop_flat_map()` by hand. -#[macro_export] -macro_rules! prop_compose { - ($(#[$meta:meta])* - $vis:vis - $([$($modi:tt)*])? fn $name:ident $params:tt - ($($var:pat in $strategy:expr),+ $(,)?) - -> $return_type:ty $body:block) => - { - #[must_use = "strategies do nothing unless used"] - $(#[$meta])* - $vis - $($($modi)*)? fn $name $params - -> impl $crate::strategy::Strategy { - let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); - $crate::strategy::Strategy::prop_map(strat, - move |$crate::proptest_helper!(@_WRAPPAT ($($var),*))| $body) - } - }; - - ($(#[$meta:meta])* - $vis:vis - $([$($modi:tt)*])? fn $name:ident $params:tt - ($($var:pat in $strategy:expr),+ $(,)?) - ($($var2:pat in $strategy2:expr),+ $(,)?) - -> $return_type:ty $body:block) => - { - #[must_use = "strategies do nothing unless used"] - $(#[$meta])* - $vis - $($($modi)*)? fn $name $params - -> impl $crate::strategy::Strategy { - let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); - let strat = $crate::strategy::Strategy::prop_flat_map( - strat, - move |$crate::proptest_helper!(@_WRAPPAT ($($var),*))| - $crate::proptest_helper!(@_WRAP ($($strategy2)*))); - $crate::strategy::Strategy::prop_map(strat, - move |$crate::proptest_helper!(@_WRAPPAT ($($var2),*))| $body) - } - }; - - ($(#[$meta:meta])* - $vis:vis - $([$($modi:tt)*])? fn $name:ident $params:tt - ($($arg:tt)+) - -> $return_type:ty $body:block) => - { - #[must_use = "strategies do nothing unless used"] - $(#[$meta])* - $vis - $($($modi)*)? fn $name $params - -> impl $crate::strategy::Strategy { - let strat = $crate::proptest_helper!(@_EXT _STRAT ($($arg)+)); - $crate::strategy::Strategy::prop_map(strat, - move |$crate::proptest_helper!(@_EXT _PAT ($($arg)+))| $body) - } - }; - - ($(#[$meta:meta])* - $vis:vis - $([$($modi:tt)*])? fn $name:ident $params:tt - ($($arg:tt)+ $(,)?) - ($($arg2:tt)+ $(,)?) - -> $return_type:ty $body:block) => - { - #[must_use = "strategies do nothing unless used"] - $(#[$meta])* - $vis - $($($modi)*)? fn $name $params - -> impl $crate::strategy::Strategy { - let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); - let strat = $crate::strategy::Strategy::prop_flat_map( - strat, - move |$crate::proptest_helper!(@_EXT _PAT ($($arg)+))| - $crate::proptest_helper!(@_EXT _STRAT ($($arg2)*))); - $crate::strategy::Strategy::prop_map(strat, - move |$crate::proptest_helper!(@_EXT _PAT ($($arg2)*))| $body) - } - }; -} - -/// Similar to `assert!` from std, but returns a test failure instead of -/// panicking if the condition fails. -/// -/// This can be used in any function that returns a `Result<_, TestCaseError>`, -/// including the top-level function inside `proptest!`. -/// -/// Both panicking via `assert!` and returning a test case failure have the -/// same effect as far as proptest is concerned; however, the Rust runtime -/// implicitly prints every panic to stderr by default (including a backtrace -/// if enabled), which can make test failures unnecessarily noisy. By using -/// `prop_assert!` instead, the only output on a failing test case is the final -/// panic including the minimal test case. -/// -/// ## Example -/// -/// ``` -/// use proptest::prelude::*; -/// -/// proptest! { -/// # /* -/// #[test] -/// # */ -/// fn triangle_inequality(a in 0.0f64..10.0, b in 0.0f64..10.0) { -/// // Called with just a condition will print the condition on failure -/// prop_assert!((a*a + b*b).sqrt() <= a + b); -/// // You can also provide a custom failure message -/// prop_assert!((a*a + b*b).sqrt() <= a + b, -/// "Triangle inequality didn't hold for ({}, {})", a, b); -/// // If calling another function that can return failure, don't forget -/// // the `?` to propagate the failure. -/// assert_from_other_function(a, b)?; -/// } -/// } -/// -/// // The macro can be used from another function provided it has a compatible -/// // return type. -/// fn assert_from_other_function(a: f64, b: f64) -> Result<(), TestCaseError> { -/// prop_assert!((a*a + b*b).sqrt() <= a + b); -/// Ok(()) -/// } -/// # -/// # fn main() { triangle_inequality(); } -/// ``` -#[macro_export] -macro_rules! prop_assert { - ($cond:expr) => { - $crate::prop_assert!($cond, concat!("assertion failed: ", stringify!($cond))) - }; - - ($cond:expr, $($fmt:tt)*) => { - if !$cond { - let message = format!($($fmt)*); - let message = format!("{} at {}:{}", message, file!(), line!()); - return ::core::result::Result::Err( - $crate::test_runner::TestCaseError::fail(message)); - } - }; -} - -/// Similar to `assert_eq!` from std, but returns a test failure instead of -/// panicking if the condition fails. -/// -/// See `prop_assert!` for a more in-depth discussion. -/// -/// ## Example -/// -/// ``` -/// use proptest::prelude::*; -/// -/// proptest! { -/// # /* -/// #[test] -/// # */ -/// fn concat_string_length(ref a in ".*", ref b in ".*") { -/// let cat = format!("{}{}", a, b); -/// // Use with default message -/// prop_assert_eq!(a.len() + b.len(), cat.len()); -/// // Can also provide custom message (added after the normal -/// // assertion message) -/// prop_assert_eq!(a.len() + b.len(), cat.len(), -/// "a = {:?}, b = {:?}", a, b); -/// } -/// } -/// # -/// # fn main() { concat_string_length(); } -/// ``` -#[macro_export] -macro_rules! prop_assert_eq { - ($left:expr, $right:expr) => {{ - let left = $left; - let right = $right; - $crate::prop_assert!( - left == right, - "assertion failed: `(left == right)` \ - \n left: `{:?}`,\n right: `{:?}`", - left, right); - }}; - - ($left:expr, $right:expr, $fmt:tt $($args:tt)*) => {{ - let left = $left; - let right = $right; - $crate::prop_assert!( - left == right, - concat!( - "assertion failed: `(left == right)` \ - \n left: `{:?}`, \n right: `{:?}`: ", $fmt), - left, right $($args)*); - }}; -} - -/// Similar to `assert_ne!` from std, but returns a test failure instead of -/// panicking if the condition fails. -/// -/// See `prop_assert!` for a more in-depth discussion. -/// -/// ## Example -/// -/// ``` -/// use proptest::prelude::*; -/// -/// proptest! { -/// # /* -/// #[test] -/// # */ -/// fn test_addition(a in 0i32..100i32, b in 1i32..100i32) { -/// // Use with default message -/// prop_assert_ne!(a, a + b); -/// // Can also provide custom message added after the common message -/// prop_assert_ne!(a, a + b, "a = {}, b = {}", a, b); -/// } -/// } -/// # -/// # fn main() { test_addition(); } -/// ``` -#[macro_export] -macro_rules! prop_assert_ne { - ($left:expr, $right:expr) => {{ - let left = $left; - let right = $right; - prop_assert!( - left != right, - "assertion failed: `(left != right)`\ - \n left: `{:?}`,\n right: `{:?}`", - left, right); - }}; - - ($left:expr, $right:expr, $fmt:tt $($args:tt)*) => {{ - let left = $left; - let right = $right; - prop_assert!(left != right, concat!( - "assertion failed: `(left != right)`\ - \n left: `{:?}`,\n right: `{:?}`: ", $fmt), - left, right $($args)*); - }}; -} - -#[doc(hidden)] -#[macro_export] -macro_rules! proptest_helper { - (@_WRAP ($a:tt)) => { $a }; - (@_WRAP ($a0:tt $a1:tt)) => { ($a0, $a1) }; - (@_WRAP ($a0:tt $a1:tt $a2:tt)) => { ($a0, $a1, $a2) }; - (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt)) => { ($a0, $a1, $a2, $a3) }; - (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt)) => { - ($a0, $a1, $a2, $a3, $a4) - }; - (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt $a5:tt)) => { - ($a0, $a1, $a2, $a3, $a4, $a5) - }; - (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt $a5:tt $a6:tt)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6) - }; - (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt - $a4:tt $a5:tt $a6:tt $a7:tt)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7) - }; - (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt - $a5:tt $a6:tt $a7:tt $a8:tt)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8) - }; - (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt - $a5:tt $a6:tt $a7:tt $a8:tt $a9:tt)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9) - }; - (@_WRAP ($a:tt $($rest:tt)*)) => { - ($a, $crate::proptest_helper!(@_WRAP ($($rest)*))) - }; - (@_WRAPPAT ($item:pat)) => { $item }; - (@_WRAPPAT ($a0:pat, $a1:pat)) => { ($a0, $a1) }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat)) => { ($a0, $a1, $a2) }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat)) => { - ($a0, $a1, $a2, $a3) - }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat)) => { - ($a0, $a1, $a2, $a3, $a4) - }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, $a5:pat)) => { - ($a0, $a1, $a2, $a3, $a4, $a5) - }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, - $a4:pat, $a5:pat, $a6:pat)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6) - }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, - $a4:pat, $a5:pat, $a6:pat, $a7:pat)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7) - }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, - $a5:pat, $a6:pat, $a7:pat, $a8:pat)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8) - }; - (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, - $a5:pat, $a6:pat, $a7:pat, $a8:pat, $a9:pat)) => { - ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9) - }; - (@_WRAPPAT ($a:pat, $($rest:pat),*)) => { - ($a, $crate::proptest_helper!(@_WRAPPAT ($($rest),*))) - }; - (@_WRAPSTR ($item:pat)) => { stringify!($item) }; - (@_WRAPSTR ($a0:pat, $a1:pat)) => { (stringify!($a0), stringify!($a1)) }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2)) - }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3)) - }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2), - stringify!($a3), stringify!($a4)) - }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, $a5:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), - stringify!($a4), stringify!($a5)) - }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, - $a4:pat, $a5:pat, $a6:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), - stringify!($a4), stringify!($a5), stringify!($a6)) - }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, - $a4:pat, $a5:pat, $a6:pat, $a7:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), - stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7)) - }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, - $a5:pat, $a6:pat, $a7:pat, $a8:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), - stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7), - stringify!($a8)) - }; - (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, - $a5:pat, $a6:pat, $a7:pat, $a8:pat, $a9:pat)) => { - (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), - stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7), - stringify!($a8), stringify!($a9)) - }; - (@_WRAPSTR ($a:pat, $($rest:pat),*)) => { - (stringify!($a), $crate::proptest_helper!(@_WRAPSTR ($($rest),*))) - }; - // build a property testing block that when executed, executes the full property test. - (@_BODY $config:ident ($($parm:pat in $strategy:expr),+) [$($mod:tt)*] $body:expr) => {{ - $config.source_file = Some(file!()); - let mut runner = $crate::test_runner::TestRunner::new($config); - let names = $crate::proptest_helper!(@_WRAPSTR ($($parm),*)); - match runner.run( - &$crate::strategy::Strategy::prop_map( - $crate::proptest_helper!(@_WRAP ($($strategy)*)), - |values| $crate::sugar::NamedArguments(names, values)), - $($mod)* |$crate::sugar::NamedArguments( - _, $crate::proptest_helper!(@_WRAPPAT ($($parm),*)))| - { - let _: () = $body; - Ok(()) - }) - { - Ok(_) => (), - Err(e) => panic!("{}\n{}", e, runner), - } - }}; - // build a property testing block that when executed, executes the full property test. - (@_BODY2 $config:ident ($($arg:tt)+) [$($mod:tt)*] $body:expr) => {{ - // $config.source_file = Some(file!()); - // let mut runner2 = $crate::test_runner::TestRunner::new($config); - // let names2 = $crate::proptest_helper!(@_EXT _STR ($($arg)*)); - // match runner2.run( - // &$crate::strategy::Strategy::prop_map( - // $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), - // |values| $crate::sugar::NamedArguments(names2, values)), - // $($mod)* |$crate::sugar::NamedArguments( - // _, $crate::proptest_helper!(@_EXT _PAT ($($arg)*)))| - // { - // let _: () = $body; - // Ok(()) - // }) - // { - // Ok(_) => (), - // Err(e) => panic!("{}\n{}", e, runner2), - // } - $crate::test_runner::TestRunner::run_kani( - $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), - |$crate::proptest_helper!(@_EXT _PAT ($($arg)*))| { - $body - } - ); - }}; - - // The logic below helps support `pat: type` in the proptest! macro. - - // These matchers define the actual logic: - (@_STRAT [$s:ty] [$p:pat]) => { $crate::arbitrary::any::<$s>() }; - (@_PAT [$s:ty] [$p:pat]) => { $p }; - (@_STR [$s:ty] [$p:pat]) => { stringify!($p) }; - (@_STRAT in [$s:expr] [$p:pat]) => { $s }; - (@_PAT in [$s:expr] [$p:pat]) => { $p }; - (@_STR in [$s:expr] [$p:pat]) => { stringify!($p) }; - - // These matchers rewrite into the above extractors. - // We have to do this because `:` can't FOLLOW(pat). - // Note that this is not the full `pat` grammar... - // See https://docs.rs/syn/0.14.2/syn/enum.Pat.html for that. - (@_EXT $cmd:ident ($p:pat in $s:expr $(,)?)) => { - $crate::proptest_helper!(@$cmd in [$s] [$p]) - }; - (@_EXT $cmd:ident (($p:pat) : $s:ty $(,)?)) => { - // Users can wrap in parens as a last resort. - $crate::proptest_helper!(@$cmd [$s] [$p]) - }; - (@_EXT $cmd:ident (_ : $s:ty $(,)?)) => { - $crate::proptest_helper!(@$cmd [$s] [_]) - }; - (@_EXT $cmd:ident (ref mut $p:ident : $s:ty $(,)?)) => { - $crate::proptest_helper!(@$cmd [$s] [ref mut $p]) - }; - (@_EXT $cmd:ident (ref $p:ident : $s:ty $(,)?)) => { - $crate::proptest_helper!(@$cmd [$s] [ref $p]) - }; - (@_EXT $cmd:ident (mut $p:ident : $s:ty $(,)?)) => { - $crate::proptest_helper!(@$cmd [$s] [mut $p]) - }; - (@_EXT $cmd:ident ($p:ident : $s:ty $(,)?)) => { - $crate::proptest_helper!(@$cmd [$s] [$p]) - }; - (@_EXT $cmd:ident ([$($p:tt)*] : $s:ty $(,)?)) => { - $crate::proptest_helper!(@$cmd [$s] [[$($p)*]]) - }; - - // Rewrite, Inductive case: - (@_EXT $cmd:ident ($p:pat in $s:expr, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd in [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; - (@_EXT $cmd:ident (($p:pat) : $s:ty, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; - (@_EXT $cmd:ident (_ : $s:ty, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd [$s] [_]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; - (@_EXT $cmd:ident (ref mut $p:ident : $s:ty, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd [$s] [ref mut $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; - (@_EXT $cmd:ident (ref $p:ident : $s:ty, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd [$s] [ref $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; - (@_EXT $cmd:ident (mut $p:ident : $s:ty, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd [$s] [mut $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; - (@_EXT $cmd:ident ($p:ident : $s:ty, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; - (@_EXT $cmd:ident ([$($p:tt)*] : $s:ty, $($r:tt)*)) => { - ($crate::proptest_helper!(@$cmd [$s] [[$($p)*]]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) - }; -} - -// macro_rules! named_arguments_tuple { -// ($($ix:tt $argn:ident $argv:ident)*) => { -// impl<'a, $($argn : Copy),*, $($argv),*> fmt::Debug -// for NamedArguments<($($argn,)*),&'a ($($argv,)*)> -// where $(NamedArguments<$argn, &'a $argv> : fmt::Debug),*, -// $($argv : 'a),* -// { -// #[allow(unused_assignments)] -// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -// let mut first = true; -// $( -// if !first { -// write!(f, ", ")?; -// } -// first = false; -// fmt::Debug::fmt( -// &NamedArguments((self.0).$ix, &(self.1).$ix), f)?; -// )* -// Ok(()) -// } -// } - -// impl<$($argn : Copy),*, $($argv),*> fmt::Debug -// for NamedArguments<($($argn,)*), ($($argv,)*)> -// where $(for<'a> NamedArguments<$argn, &'a $argv> : fmt::Debug),* -// { -// #[allow(unused_assignments)] -// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -// let mut first = true; -// $( -// if !first { -// write!(f, ", ")?; -// } -// first = false; -// fmt::Debug::fmt( -// &NamedArguments((self.0).$ix, &(self.1).$ix), f)?; -// )* -// Ok(()) -// } -// } -// } -// } - -// named_arguments_tuple!(0 AN AV); -// named_arguments_tuple!(0 AN AV 1 BN BV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV -// 5 FN FV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV -// 5 FN FV 6 GN GV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV -// 5 FN FV 6 GN GV 7 HN HV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV -// 5 FN FV 6 GN GV 7 HN HV 8 IN IV); -// named_arguments_tuple!(0 AN AV 1 BN BV 2 CN CV 3 DN DV 4 EN EV -// 5 FN FV 6 GN GV 7 HN HV 8 IN IV 9 JN JV); diff --git a/library/proptest/src/tuple.rs b/library/proptest/src/tuple.rs deleted file mode 100644 index 8a972e29a55d..000000000000 --- a/library/proptest/src/tuple.rs +++ /dev/null @@ -1,131 +0,0 @@ -//- -// Copyright 2017 Jason Lingle -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. -// Modifications Copyright Kani Contributors -// See GitHub history for details - -//! Support for combining strategies into tuples. -//! -//! There is no explicit "tuple strategy"; simply make a tuple containing the -//! strategy and that tuple is itself a strategy. - -use crate::strategy::*; -use crate::test_runner::*; - -/// Common `ValueTree` implementation for all tuple strategies. -#[derive(Clone, Copy, Debug)] -pub struct TupleValueTree { - tree: T, -} - -impl TupleValueTree { - /// Create a new `TupleValueTree` wrapping `inner`. - /// - /// It only makes sense for `inner` to be a tuple of an arity for which the - /// type implements `ValueTree`. - pub fn new(inner: T) -> Self { - TupleValueTree { tree: inner } - } -} - -macro_rules! tuple { - ($($fld:tt : $typ:ident),*) => { - impl<$($typ : Strategy),*> Strategy for ($($typ,)*) { - type Tree = TupleValueTree<($($typ::Tree,)*)>; - type Value = ($($typ::Value,)*); - - fn new_tree(&self, runner: &mut TestRunner) -> NewTree { - let values = ($(self.$fld.new_tree(runner)?,)*); - Ok(TupleValueTree::new(values)) - } - } - - impl<$($typ : ValueTree),*> ValueTree - for TupleValueTree<($($typ,)*)> { - type Value = ($($typ::Value,)*); - - fn current(&self) -> Self::Value { - ($(self.tree.$fld.current(),)*) - } - - fn simplify(&mut self) -> bool { - false - } - - fn complicate(&mut self) -> bool { - false - } - } - } -} - -tuple!(0: A); -tuple!(0: A, 1: B); -tuple!(0: A, 1: B, 2: C); -tuple!(0: A, 1: B, 2: C, 3: D); -tuple!(0: A, 1: B, 2: C, 3: D, 4: E); -tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F); -tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G); -tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H); -tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I); -tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J); -tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K); -tuple!(0: A, 1: B, 2: C, 3: D, 4: E, 5: F, 6: G, 7: H, 8: I, 9: J, 10: K, 11: L); - -#[cfg(test)] -mod test { - use crate::strategy::*; - - use super::*; - - #[test] - fn shrinks_fully_ltr() { - fn pass(a: (i32, i32)) -> bool { - a.0 * a.1 <= 9 - } - - let input = (0..32, 0..32); - let mut runner = TestRunner::default(); - - let mut cases_tested = 0; - for _ in 0..256 { - // Find a failing test case - let mut case = input.new_tree(&mut runner).unwrap(); - if pass(case.current()) { - continue; - } - - loop { - if pass(case.current()) { - if !case.complicate() { - break; - } - } else { - if !case.simplify() { - break; - } - } - } - - let last = case.current(); - assert!(!pass(last)); - // Maximally shrunken - assert!(pass((last.0 - 1, last.1))); - assert!(pass((last.0, last.1 - 1))); - - cases_tested += 1; - } - - assert!(cases_tested > 32, "Didn't find enough test cases"); - } - - #[test] - fn test_sanity() { - check_strategy_sanity((0i32..100, 0i32..1000, 0i32..10000), None); - } -} From decdc711c7a5087a02cff64219d98766e3cf30e0 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 15:36:02 -0400 Subject: [PATCH 49/80] Adjust license tag. --- library/proptest/src/lib.rs | 10 ++++++++-- library/proptest/src/std_facade.rs | 5 ++++- library/proptest/src/strategy/just.rs | 5 ++++- library/proptest/src/strategy/mod.rs | 5 ++++- library/proptest/src/strategy/traits.rs | 7 ++++++- library/proptest/src/test_runner/config.rs | 5 ++++- library/proptest/src/test_runner/mod.rs | 17 +++++++++++++---- library/proptest/src/test_runner/reason.rs | 5 ++++- library/proptest/src/test_runner/runner.rs | 5 ++++- 9 files changed, 51 insertions(+), 13 deletions(-) diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index def7921908a9..f6661bdc2363 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -6,8 +6,11 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + +// SPDX-License-Identifier: Apache-2.0 OR MIT +// // Modifications Copyright Kani Contributors -// See GitHub history for details +// See GitHub history for details. //! # Proptest Reference Documentation //! @@ -32,7 +35,10 @@ #![cfg_attr(all(feature = "std", feature = "unstable"), feature(ip))] #![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(core_intrinsics))] -// // std_facade is used in a few macros, so it needs to be public. +// TODO: Implement support for more features. They are commented out +// for now. + +// std_facade is used in a few macros, so it needs to be public. // #[macro_use] // #[doc(hidden)] pub mod std_facade; diff --git a/library/proptest/src/std_facade.rs b/library/proptest/src/std_facade.rs index 427008183480..fcfc674a5538 100644 --- a/library/proptest/src/std_facade.rs +++ b/library/proptest/src/std_facade.rs @@ -6,8 +6,11 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + +// SPDX-License-Identifier: Apache-2.0 OR MIT +// // Modifications Copyright Kani Contributors -// See GitHub history for details +// See GitHub history for details. //! This module provides #[cfg(..)]ed type aliases over features. diff --git a/library/proptest/src/strategy/just.rs b/library/proptest/src/strategy/just.rs index 45633e52d339..83af8557ba5e 100644 --- a/library/proptest/src/strategy/just.rs +++ b/library/proptest/src/strategy/just.rs @@ -6,8 +6,11 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + +// SPDX-License-Identifier: Apache-2.0 OR MIT +// // Modifications Copyright Kani Contributors -// See GitHub history for details +// See GitHub history for details. use crate::std_facade::fmt; diff --git a/library/proptest/src/strategy/mod.rs b/library/proptest/src/strategy/mod.rs index 711fd2312457..5dc351541a80 100644 --- a/library/proptest/src/strategy/mod.rs +++ b/library/proptest/src/strategy/mod.rs @@ -6,8 +6,11 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + +// SPDX-License-Identifier: Apache-2.0 OR MIT +// // Modifications Copyright Kani Contributors -// See GitHub history for details +// See GitHub history for details. //! Defines the core traits used by Proptest. diff --git a/library/proptest/src/strategy/traits.rs b/library/proptest/src/strategy/traits.rs index 4e3262f796f6..3a34834ae2e5 100644 --- a/library/proptest/src/strategy/traits.rs +++ b/library/proptest/src/strategy/traits.rs @@ -6,8 +6,11 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + +// SPDX-License-Identifier: Apache-2.0 OR MIT +// // Modifications Copyright Kani Contributors -// See GitHub history for details +// See GitHub history for details. //! This file defines the strategy trait, which replaces //! proptest::strategy::Strategy @@ -65,6 +68,8 @@ pub trait Strategy: fmt::Debug { /// generate the test case. fn new_tree(&self, runner: &mut TestRunner) -> NewTree; + // TODO: Implement more complex strategy compositions. + // /// Returns a strategy which produces values transformed by the function // /// `fun`. // /// diff --git a/library/proptest/src/test_runner/config.rs b/library/proptest/src/test_runner/config.rs index 802be998e06c..08168d581926 100644 --- a/library/proptest/src/test_runner/config.rs +++ b/library/proptest/src/test_runner/config.rs @@ -6,8 +6,11 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + +// SPDX-License-Identifier: Apache-2.0 OR MIT +// // Modifications Copyright Kani Contributors -// See GitHub history for details +// See GitHub history for details. // use crate::std_facade::Box; use core::u32; diff --git a/library/proptest/src/test_runner/mod.rs b/library/proptest/src/test_runner/mod.rs index 67cc40aa5f56..043af101edd1 100644 --- a/library/proptest/src/test_runner/mod.rs +++ b/library/proptest/src/test_runner/mod.rs @@ -1,14 +1,23 @@ -// Copyright Kani Contributors +//- +// Copyright 2017, 2018 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + // SPDX-License-Identifier: Apache-2.0 OR MIT +// +// Modifications Copyright Kani Contributors +// See GitHub history for details. //! Module for test runner. Significantly scaled back compared to //! original. +mod config; mod reason; mod runner; -// Modifications Copyright Kani Contributors -// See GitHub history for details -mod config; pub use config::*; pub use reason::*; diff --git a/library/proptest/src/test_runner/reason.rs b/library/proptest/src/test_runner/reason.rs index d907ca7a1e39..dec142810f07 100644 --- a/library/proptest/src/test_runner/reason.rs +++ b/library/proptest/src/test_runner/reason.rs @@ -6,8 +6,11 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + +// SPDX-License-Identifier: Apache-2.0 OR MIT +// // Modifications Copyright Kani Contributors -// See GitHub history for details +// See GitHub history for details. use crate::std_facade::{fmt, Box, Cow, String}; diff --git a/library/proptest/src/test_runner/runner.rs b/library/proptest/src/test_runner/runner.rs index 78931d643f5c..fa3e8a8eb05a 100644 --- a/library/proptest/src/test_runner/runner.rs +++ b/library/proptest/src/test_runner/runner.rs @@ -6,8 +6,11 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + +// SPDX-License-Identifier: Apache-2.0 OR MIT +// // Modifications Copyright Kani Contributors -// See GitHub history for details +// See GitHub history for details. //! This file implements a Kani-specific test runner that mirrors the //! one in proptest. In contrast to the original, this test runner From 0309b5ec092d0a4b3cfbdbbccb516abcb6ad904f Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 15:36:33 -0400 Subject: [PATCH 50/80] Purged unused code. --- library/proptest/src/std_facade.rs | 83 ++++------- library/proptest/src/test_runner/config.rs | 158 --------------------- 2 files changed, 24 insertions(+), 217 deletions(-) diff --git a/library/proptest/src/std_facade.rs b/library/proptest/src/std_facade.rs index fcfc674a5538..5eefeddc7f76 100644 --- a/library/proptest/src/std_facade.rs +++ b/library/proptest/src/std_facade.rs @@ -14,66 +14,31 @@ //! This module provides #[cfg(..)]ed type aliases over features. -macro_rules! multiplex_alloc { - ($($alloc: path, $std: path),*) => { - $( - // #[cfg(all(feature = "alloc", not(feature = "std")))] - // pub use $alloc; - // #[cfg(feature = "std")] - pub use $std; - )* - }; -} +pub use ::std::borrow::Cow; +pub use ::std::borrow::ToOwned; +pub use ::std::boxed::Box; +pub use ::std::collections::binary_heap; +pub use ::std::collections::btree_map; +pub use ::std::collections::btree_set; +pub use ::std::collections::linked_list; +pub use ::std::collections::vec_deque; +pub use ::std::collections::BTreeMap; +pub use ::std::collections::BTreeSet; +pub use ::std::collections::BinaryHeap; +pub use ::std::collections::LinkedList; +pub use ::std::collections::VecDeque; +pub use ::std::rc::Rc; +pub use ::std::string; +pub use ::std::string::String; +pub use ::std::sync::Arc; +pub use ::std::vec; +pub use ::std::vec::Vec; + +pub use ::std::collections::HashMap; +pub use ::std::collections::HashSet; -macro_rules! multiplex_core { - ($($core: path, $std: path),*) => { - $( - // #[cfg(not(feature = "std"))] - // pub use $core; - // #[cfg(feature = "std")] - pub use $std; - )* - }; -} - -multiplex_alloc! { - alloc::borrow::Cow, ::std::borrow::Cow, - alloc::borrow::ToOwned, ::std::borrow::ToOwned, - alloc::boxed::Box, ::std::boxed::Box, - alloc::string::String, ::std::string::String, - alloc::string, ::std::string, - alloc::sync::Arc, ::std::sync::Arc, - alloc::rc::Rc, ::std::rc::Rc, - alloc::vec::Vec, ::std::vec::Vec, - alloc::vec, ::std::vec, - alloc::collections::VecDeque, std::collections::VecDeque, - alloc::collections::vec_deque, std::collections::vec_deque, - alloc::collections::BinaryHeap, ::std::collections::BinaryHeap, - alloc::collections::binary_heap, ::std::collections::binary_heap, - alloc::collections::LinkedList, ::std::collections::LinkedList, - alloc::collections::linked_list, ::std::collections::linked_list, - alloc::collections::BTreeSet, ::std::collections::BTreeSet, - alloc::collections::BTreeMap, ::std::collections::BTreeMap, - alloc::collections::btree_map, ::std::collections::btree_map, - alloc::collections::btree_set, ::std::collections::btree_set -} - -#[cfg(feature = "std")] -multiplex_alloc! { - hashmap_core::HashMap, ::std::collections::HashMap, - hashmap_core::HashSet, ::std::collections::HashSet -} - -//#[cfg(not(feature = "std"))] -//pub(crate) use hashmap_core::map as hash_map; -#[cfg(feature = "std")] pub use ::std::collections::hash_map; -//#[cfg(not(feature = "std"))] -//pub(crate) use hashmap_core::set as hash_set; -#[cfg(feature = "std")] pub use ::std::collections::hash_set; -multiplex_core! { - core::fmt, ::std::fmt, - core::cell::Cell, ::std::cell::Cell -} +pub use ::std::cell::Cell; +pub use ::std::fmt; diff --git a/library/proptest/src/test_runner/config.rs b/library/proptest/src/test_runner/config.rs index 08168d581926..589b6551387c 100644 --- a/library/proptest/src/test_runner/config.rs +++ b/library/proptest/src/test_runner/config.rs @@ -12,134 +12,23 @@ // Modifications Copyright Kani Contributors // See GitHub history for details. -// use crate::std_facade::Box; use core::u32; -#[cfg(feature = "std")] -use std::env; -#[cfg(feature = "std")] -use std::ffi::OsString; -#[cfg(feature = "std")] -use std::fmt; -#[cfg(feature = "std")] -use std::str::FromStr; - -// use crate::test_runner::result_cache::{noop_result_cache, ResultCache}; -// use crate::test_runner::rng::RngAlgorithm; -// use crate::test_runner::FailurePersistence; -#[cfg(feature = "std")] -use crate::test_runner::FileFailurePersistence; - -#[cfg(feature = "std")] -const CASES: &str = "PROPTEST_CASES"; -#[cfg(feature = "std")] -const MAX_LOCAL_REJECTS: &str = "PROPTEST_MAX_LOCAL_REJECTS"; -#[cfg(feature = "std")] -const MAX_GLOBAL_REJECTS: &str = "PROPTEST_MAX_GLOBAL_REJECTS"; -#[cfg(feature = "std")] -const MAX_FLAT_MAP_REGENS: &str = "PROPTEST_MAX_FLAT_MAP_REGENS"; -#[cfg(feature = "std")] -const MAX_SHRINK_TIME: &str = "PROPTEST_MAX_SHRINK_TIME"; -#[cfg(feature = "std")] -const MAX_SHRINK_ITERS: &str = "PROPTEST_MAX_SHRINK_ITERS"; -#[cfg(feature = "fork")] -const FORK: &str = "PROPTEST_FORK"; -#[cfg(feature = "timeout")] -const TIMEOUT: &str = "PROPTEST_TIMEOUT"; -#[cfg(feature = "std")] -const VERBOSE: &str = "PROPTEST_VERBOSE"; - -#[cfg(feature = "std")] -fn contextualize_config(mut result: Config) -> Config { - fn parse_or_warn(src: &OsString, dst: &mut T, typ: &str, var: &str) { - if let Some(src) = src.to_str() { - if let Ok(value) = src.parse() { - *dst = value; - } else { - eprintln!( - "proptest: The env-var {}={} can't be parsed as {}, \ - using default of {}.", - var, src, typ, *dst - ); - } - } else { - eprintln!( - "proptest: The env-var {} is not valid, using \ - default of {}.", - var, *dst - ); - } - } - - result.failure_persistence = Some(Box::new(FileFailurePersistence::default())); - for (var, value) in env::vars_os().filter_map(|(k, v)| k.into_string().ok().map(|k| (k, v))) { - match var.as_str() { - CASES => parse_or_warn(&value, &mut result.cases, "u32", CASES), - MAX_LOCAL_REJECTS => { - parse_or_warn(&value, &mut result.max_local_rejects, "u32", MAX_LOCAL_REJECTS) - } - MAX_GLOBAL_REJECTS => { - parse_or_warn(&value, &mut result.max_global_rejects, "u32", MAX_GLOBAL_REJECTS) - } - MAX_FLAT_MAP_REGENS => { - parse_or_warn(&value, &mut result.max_flat_map_regens, "u32", MAX_FLAT_MAP_REGENS) - } - #[cfg(feature = "fork")] - FORK => parse_or_warn(&value, &mut result.fork, "bool", FORK), - #[cfg(feature = "timeout")] - TIMEOUT => parse_or_warn(&value, &mut result.timeout, "timeout", TIMEOUT), - MAX_SHRINK_TIME => { - parse_or_warn(&value, &mut result.max_shrink_time, "u32", MAX_SHRINK_TIME) - } - MAX_SHRINK_ITERS => { - parse_or_warn(&value, &mut result.max_shrink_iters, "u32", MAX_SHRINK_ITERS) - } - VERBOSE => parse_or_warn(&value, &mut result.verbose, "u32", VERBOSE), - RNG_ALGORITHM => { - parse_or_warn(&value, &mut result.rng_algorithm, "RngAlgorithm", RNG_ALGORITHM) - } - - _ => { - if var.starts_with("PROPTEST_") { - eprintln!("proptest: Ignoring unknown env-var {}.", var); - } - } - } - } - - result -} - fn default_default_config() -> Config { Config { cases: 256, max_local_rejects: 65_536, max_global_rejects: 1024, max_flat_map_regens: 1_000_000, - // failure_persistence: None, source_file: None, test_name: None, - #[cfg(feature = "fork")] - fork: false, - #[cfg(feature = "timeout")] - timeout: 0, - #[cfg(feature = "std")] - max_shrink_time: 0, max_shrink_iters: u32::MAX, - // result_cache: noop_result_cache, - #[cfg(feature = "std")] - verbose: 0, - // rng_algorithm: RngAlgorithm::default(), _non_exhaustive: (), } } // The default config, computed by combining environment variables and // defaults. -#[cfg(feature = "std")] -lazy_static! { - static ref DEFAULT_CONFIG: Config = contextualize_config(default_default_config()); -} /// Configuration for how a proptest test should be run. #[derive(Clone, Debug, PartialEq)] @@ -175,19 +64,6 @@ pub struct Config { /// `PROPTEST_MAX_FLAT_MAP_REGENS` environment variable. pub max_flat_map_regens: u32, - /// Indicates whether and how to persist failed test results. - /// - /// When compiling with "std" feature (i.e. the standard library is available), the default - /// is `Some(Box::new(FileFailurePersistence::SourceParallel("proptest-regressions")))`. - /// - /// Without the standard library, the default is `None`, and no persistence occurs. - /// - /// See the docs of [`FileFailurePersistence`](enum.FileFailurePersistence.html) - /// and [`MapFailurePersistence`](struct.MapFailurePersistence.html) for more information. - /// - /// The default cannot currently be overridden by an environment variable. - // pub failure_persistence: Option>, - /// File location of the current test, relevant for persistence /// and debugging. /// @@ -271,23 +147,6 @@ pub struct Config { /// `PROPTEST_MAX_SHRINK_ITERS` environment variable. pub max_shrink_iters: u32, - // A function to create new result caches. - - // The default is to do no caching. The easiest way to enable caching is - // to set this field to `basic_result_cache` (though that is currently - // only available with the `std` feature). - - // This is useful for strategies which have a tendency to produce - // duplicate values, or for tests where shrinking can take a very long - // time due to exploring the same output multiple times. - - // When caching is enabled, generated values themselves are not stored, so - // this does not pose a risk of memory exhaustion for large test inputs - // unless using extraordinarily large test case counts. - - // Caching incurs its own overhead, and may very well make your test run - // more slowly. - // pub result_cache: fn() -> Box, /// Set to non-zero values to cause proptest to emit human-targeted /// messages to stderr as it runs. /// @@ -306,15 +165,6 @@ pub struct Config { #[cfg(feature = "std")] pub verbose: u32, - // The RNG algorithm to use when not using a user-provided RNG. - - // The default is `RngAlgorithm::default()`, which can be overridden by - // setting the `PROPTEST_RNG_ALGORITHM` environment variable to one of the following: - - // - `xs` — `RngAlgorithm::XorShift` - // - `cc` — `RngAlgorithm::ChaCha` - // pub rng_algorithm: RngAlgorithm, - // Needs to be public so FRU syntax can be used. #[doc(hidden)] pub _non_exhaustive: (), @@ -436,14 +286,6 @@ impl Config { } } -#[cfg(feature = "std")] -impl Default for Config { - fn default() -> Self { - DEFAULT_CONFIG.clone() - } -} - -#[cfg(not(feature = "std"))] impl Default for Config { fn default() -> Self { default_default_config() From f7064a0ccfd47583eafbf4537a3f491087ea0e0d Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 15:50:04 -0400 Subject: [PATCH 51/80] Added todo message. --- library/proptest/src/strategy/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/proptest/src/strategy/mod.rs b/library/proptest/src/strategy/mod.rs index 5dc351541a80..01f356ac34ef 100644 --- a/library/proptest/src/strategy/mod.rs +++ b/library/proptest/src/strategy/mod.rs @@ -14,6 +14,8 @@ //! Defines the core traits used by Proptest. +// TODO: support more strategy operations. + // mod filter; // mod filter_map; // mod flatten; From e6d1f4613c36137b09639964687481e211b83b02 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 16:15:43 -0400 Subject: [PATCH 52/80] Reverted invariant.rs. --- library/kani/src/invariant.rs | 97 ++++++++++++++++++++++++++--------- 1 file changed, 72 insertions(+), 25 deletions(-) diff --git a/library/kani/src/invariant.rs b/library/kani/src/invariant.rs index 4a74ce996eb3..e7a2c9ef357e 100644 --- a/library/kani/src/invariant.rs +++ b/library/kani/src/invariant.rs @@ -1,9 +1,8 @@ // Copyright Kani Contributors // SPDX-License-Identifier: Apache-2.0 OR MIT -//! This module introduces the Invariant trait. - -use crate::Arbitrary; +//! This module introduces the Invariant trait as well as implementation for commonly used types. +use std::num::*; /// Types that implement a check to ensure its value is valid and safe to be used. See /// for examples of valid values. @@ -15,36 +14,84 @@ use crate::Arbitrary; /// /// This trait is unsafe since &self might represent an invalid value. The `is_valid()` function /// must return `true` if and only if the invariant of its type is held. -/// -/// # Deprecation -/// -/// We have decided to deprecate this trait in favor of using `Arbitrary` for now. The main -/// benefit of using Invariant was to avoid calling `kani::any_raw()` followed by `kani::assume()`. -/// However, `kani::any_raw()` today cannot guarantee the rust type validity invariants, which -/// could lead to UB in our analysis. -#[deprecated( - since = "0.8.0", - note = "With `kani::Invariant`, Kani cannot guarantee that the type respects the language \ - type invariants which may trigger UB. Use `kani::Arbitrary` instead." -)] pub unsafe trait Invariant { /// Check if `&self` holds a valid value that respect the type invariant. /// This function must return `true` if and only if `&self` is valid. fn is_valid(&self) -> bool; } -// We cannot apply #[deprecated] to trait impl so add this to ignore the deprecation warnings. -#[allow(deprecated)] -impl Arbitrary for T -where - T: Invariant, -{ - default fn any() -> Self { - let value = unsafe { crate::any_raw_internal::() }; - crate::assume(value.is_valid()); - value +macro_rules! empty_invariant { + ( $type: ty ) => { + unsafe impl Invariant for $type { + #[inline(always)] + fn is_valid(&self) -> bool { + true + } + } + }; +} + +empty_invariant!(u8); +empty_invariant!(u16); +empty_invariant!(u32); +empty_invariant!(u64); +empty_invariant!(u128); +empty_invariant!(usize); + +empty_invariant!(i8); +empty_invariant!(i16); +empty_invariant!(i32); +empty_invariant!(i64); +empty_invariant!(i128); +empty_invariant!(isize); + +// We do not constraint floating points values per type spec. Users must add assumptions to their +// verification code if they want to eliminate NaN, infinite, or subnormal. +empty_invariant!(f32); +empty_invariant!(f64); + +empty_invariant!(()); + +unsafe impl Invariant for bool { + #[inline(always)] + fn is_valid(&self) -> bool { + let byte = u8::from(*self); + byte == 0 || byte == 1 + } +} + +/// Validate that a char is not outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] +/// Ref: +unsafe impl Invariant for char { + #[inline(always)] + fn is_valid(&self) -> bool { + // Kani translates char into i32. + let val = *self as i32; + val <= 0xD7FF || (0xE000..=0x10FFFF).contains(&val) } } +macro_rules! nonzero_invariant { + ( $type: ty ) => { + unsafe impl Invariant for $type { + #[inline(always)] + fn is_valid(&self) -> bool { + self.get() != 0 + } + } + }; +} +nonzero_invariant!(NonZeroU8); +nonzero_invariant!(NonZeroU16); +nonzero_invariant!(NonZeroU32); +nonzero_invariant!(NonZeroU64); +nonzero_invariant!(NonZeroU128); +nonzero_invariant!(NonZeroUsize); +nonzero_invariant!(NonZeroI8); +nonzero_invariant!(NonZeroI16); +nonzero_invariant!(NonZeroI32); +nonzero_invariant!(NonZeroI64); +nonzero_invariant!(NonZeroI128); +nonzero_invariant!(NonZeroIsize); From 5674243608a7642f4b537143e084c5cd09b33f3e Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 17:13:22 -0400 Subject: [PATCH 53/80] Added basic test case. --- tests/cargo-kani/proptest/Cargo.toml | 9 +++++++++ tests/cargo-kani/proptest/src/lib.rs | 18 ++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 tests/cargo-kani/proptest/Cargo.toml create mode 100644 tests/cargo-kani/proptest/src/lib.rs diff --git a/tests/cargo-kani/proptest/Cargo.toml b/tests/cargo-kani/proptest/Cargo.toml new file mode 100644 index 000000000000..e3e7668fe291 --- /dev/null +++ b/tests/cargo-kani/proptest/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "proptest-test-cases" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +#[target.'cfg(not(kani))'.dependencies] +#proptest = '1.0.0' diff --git a/tests/cargo-kani/proptest/src/lib.rs b/tests/cargo-kani/proptest/src/lib.rs new file mode 100644 index 000000000000..c4a90a496127 --- /dev/null +++ b/tests/cargo-kani/proptest/src/lib.rs @@ -0,0 +1,18 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT + +//! cargo-kani test crate for proptest. + +use proptest::test_runner::Config; + +// check if the proptest library is linked and macro is working. +proptest::proptest!{ + fn successfully_linked_proptest(_ in proptest::strategy::Just(()) ) { + let config = Config::default(); + assert_eq!( + config.cases, + 256, + "Default .cases should be 256. Check library/proptest/src/test_runner/config.rs" + ); + } +} From 952013ea55cfbbd83847249fc8f79c65c0e39ec7 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 17:13:41 -0400 Subject: [PATCH 54/80] Added proptest syntax sugar macros. --- library/proptest/src/lib.rs | 2 +- library/proptest/src/sugar.rs | 1051 +++++++++++++++++++++++++++++++++ 2 files changed, 1052 insertions(+), 1 deletion(-) create mode 100644 library/proptest/src/sugar.rs diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index f6661bdc2363..3ea1fd14313a 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -86,7 +86,7 @@ pub mod std_facade; #[doc(hidden)] #[macro_use] -// pub mod sugar; +pub mod sugar; // pub mod arbitrary; // pub mod array; diff --git a/library/proptest/src/sugar.rs b/library/proptest/src/sugar.rs new file mode 100644 index 000000000000..86649c42f483 --- /dev/null +++ b/library/proptest/src/sugar.rs @@ -0,0 +1,1051 @@ +//- +// Copyright 2017, 2019 The proptest developers +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// Modifications Copyright Kani Contributors +// See GitHub history for details + +// use crate::std_facade::fmt; + +/// Easily define `proptest` tests. +/// +/// Within `proptest!`, define one or more functions without return type +/// normally, except instead of putting `: type` after each parameter, write +/// `in strategy`, where `strategy` is an expression evaluating to some +/// `Strategy`. +/// +/// Each function will be wrapped in a function which sets up a `TestRunner`, +/// and then invokes the function body with inputs generated according to the +/// strategies. +/// +/// ### Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn test_addition(a in 0..10, b in 0..10) { +/// prop_assert!(a + b <= 18); +/// } +/// +/// # /* +/// #[test] +/// # */ +/// fn test_string_concat(a in ".*", b in ".*") { +/// let cat = format!("{}{}", a, b); +/// prop_assert_eq!(a.len() + b.len(), cat.len()); +/// } +/// } +/// # +/// # fn main() { test_addition(); test_string_concat(); } +/// ``` +/// +/// You can also use the normal argument syntax `pattern: type` as in: +/// +/// ```rust +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn addition_is_commutative(a: u8, b: u8) { +/// prop_assert_eq!(a as u16 + b as u16, b as u16 + a as u16); +/// } +/// +/// # /* +/// #[test] +/// # */ +/// fn test_string_concat(a in ".*", b: String) { +/// let cat = format!("{}{}", a, b); +/// prop_assert_eq!(a.len() + b.len(), cat.len()); +/// } +/// } +/// # +/// # fn main() { addition_is_commutative(); test_string_concat(); } +/// ``` +/// +/// As you can see, you can mix `pattern: type` and `pattern in expr`. +/// Due to limitations in `macro_rules!`, `pattern: type` does not work in +/// all circumstances. In such a case, use `(pattern): type` instead. +/// +/// To override the default configuration, you can start the `proptest!` block +/// with `#![proptest_config(expr)]`, where `expr` is an expression that +/// evaluates to a `proptest::test_runner::Config` (or a reference to one). +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// #![proptest_config(ProptestConfig { +/// cases: 99, .. ProptestConfig::default() +/// })] +/// # /* +/// #[test] +/// # */ +/// fn test_addition(a in 0..10, b in 0..10) { +/// prop_assert!(a + b <= 18); +/// } +/// } +/// # +/// # fn main() { test_addition(); } +/// ``` +/// +/// ## Closure-Style Invocation +/// +/// As of proptest 0.8.1, an alternative, "closure-style" invocation is +/// supported. In this form, `proptest!` is a function-like macro taking a +/// closure-esque argument. This makes it possible to run multiple tests that +/// require some expensive setup process. Note that the "fork" and "timeout" +/// features are _not_ supported in closure style. +/// +/// To use a custom configuration, pass the `Config` object as a first +/// argument. +/// +/// ### Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// #[derive(Debug)] +/// struct BigStruct { /* Lots of fields ... */ } +/// +/// fn very_expensive_function() -> BigStruct { +/// // Lots of code... +/// BigStruct { /* fields */ } +/// } +/// +/// # /* +/// #[test] +/// # */ +/// fn my_test() { +/// // We create just one `BigStruct` +/// let big_struct = very_expensive_function(); +/// +/// // But now can run multiple tests without needing to build it every time. +/// // Note the extra parentheses around the arguments are currently +/// // required. +/// proptest!(|(x in 0u32..42u32, y in 1000u32..100000u32)| { +/// // Test stuff +/// }); +/// +/// // `move` closures are also supported +/// proptest!(move |(x in 0u32..42u32)| { +/// // Test other stuff +/// }); +/// +/// // You can pass a custom configuration as the first argument +/// proptest!(ProptestConfig::with_cases(1000), |(x: i32)| { +/// // Test more stuff +/// }); +/// } +/// # +/// # fn main() { my_test(); } +/// ``` +#[macro_export] +macro_rules! proptest { + (#![proptest_config($config:expr)] + $( + $(#[$meta:meta])* + fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block + )*) => { + $( + #[kani::proof] + $(#[$meta])* + fn $test_name() { //rule meta_strategy + // let mut config = $config.clone(); + // config.test_name = Some( + // concat!(module_path!(), "::meta_strategy::", stringify!($test_name))); + $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body); + } + )* + }; + (#![proptest_config($config:expr)] + $( + $(#[$meta:meta])* + fn $test_name:ident($($arg:tt)+) $body:block + )*) => { + $( + #[kani::proof] + $(#[$meta])* + fn $test_name() { //rule meta_type + // let mut config = $config.clone(); + // config.test_name = Some( + // concat!(module_path!(), "::meta_type::", stringify!($test_name))); + $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); + } + )* + }; + + ($( + $(#[$meta:meta])* + fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block + )*) => { $crate::proptest! { + #![proptest_config($crate::test_runner::Config::default())] + $($(#[$meta])* + fn $test_name($($parm in $strategy),+) $body)* + } }; + + ($( + $(#[$meta:meta])* + fn $test_name:ident($($arg:tt)+) $body:block + )*) => { $crate::proptest! { + #![proptest_config($crate::test_runner::Config::default())] + $($(#[$meta])* + fn $test_name($($arg)+) $body)* + } }; + + (|($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + |($($parm in $strategy),+)| $body) + }; + + (move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + move |($($parm in $strategy),+)| $body) + }; + + (|($($arg:tt)+)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + |($($arg)+)| $body) + }; + + (move |($($arg:tt)+)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + move |($($arg)+)| $body) + }; + + ($config:expr, |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body) + } }; + + ($config:expr, move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [move] $body) + } }; + + ($config:expr, |($($arg:tt)+)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); + } }; + + ($config:expr, move |($($arg:tt)+)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY2 config ($($arg)+) [move] $body); + } }; +} + +/// Rejects the test input if assumptions are not met. +/// +/// Used directly within a function defined with `proptest!` or in any function +/// returning `Result<_, TestCaseError>`. +/// +/// This is invoked as `prop_assume!(condition, format, args...)`. `condition` +/// is evaluated; if it is false, `Err(TestCaseError::Reject)` is returned. The +/// message includes the point of invocation and the format message. `format` +/// and `args` may be omitted to simply use the condition itself as the +/// message. +#[macro_export] +macro_rules! prop_assume { + ($expr:expr) => { + $crate::prop_assume!($expr, "{}", stringify!($expr)) + }; + + ($expr:expr, $fmt:tt $(, $fmt_arg:expr),* $(,)?) => { + if !$expr { + return ::core::result::Result::Err( + $crate::test_runner::TestCaseError::reject( + format!(concat!("{}:{}:{}: ", $fmt), + file!(), line!(), column!() + $(, $fmt_arg)*))); + } + }; +} + +/// Produce a strategy which picks one of the listed choices. +/// +/// This is conceptually equivalent to calling `prop_union` on the first two +/// elements and then chaining `.or()` onto the rest after implicitly boxing +/// all of them. As with `Union`, values shrink across elements on the +/// assumption that earlier ones are "simpler", so they should be listed in +/// order of ascending complexity when possible. +/// +/// The macro invocation has two forms. The first is to simply list the +/// strategies separated by commas; this will cause value generation to pick +/// from the strategies uniformly. The other form is to provide a weight in the +/// form of a `u32` before each strategy, separated from the strategy with +/// `=>`. +/// +/// Note that the exact type returned by the macro varies depending on how many +/// inputs there are. In particular, if given exactly one option, it will +/// return it unmodified. It is not recommended to depend on the particular +/// type produced by this macro. +/// +/// ## Example +/// +/// ```rust,no_run +/// use proptest::prelude::*; +/// +/// #[derive(Clone, Copy, Debug)] +/// enum MyEnum { +/// Big(u64), +/// Medium(u32), +/// Little(i16), +/// } +/// +/// # #[allow(unused_variables)] +/// # fn main() { +/// let my_enum_strategy = prop_oneof![ +/// prop::num::i16::ANY.prop_map(MyEnum::Little), +/// prop::num::u32::ANY.prop_map(MyEnum::Medium), +/// prop::num::u64::ANY.prop_map(MyEnum::Big), +/// ]; +/// +/// let my_weighted_strategy = prop_oneof![ +/// 1 => prop::num::i16::ANY.prop_map(MyEnum::Little), +/// // Chose `Medium` twice as frequently as either `Little` or `Big`; i.e., +/// // around 50% of values will be `Medium`, and 25% for each of `Little` +/// // and `Big`. +/// 2 => prop::num::u32::ANY.prop_map(MyEnum::Medium), +/// 1 => prop::num::u64::ANY.prop_map(MyEnum::Big), +/// ]; +/// # } +/// ``` +#[macro_export] +macro_rules! prop_oneof { + ($($item:expr),+ $(,)?) => { + $crate::prop_oneof![ + $(1 => $item),* + ] + }; + + ($_weight0:expr => $item0:expr $(,)?) => { $item0 }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)), + ($weight7, $crate::std_facade::Arc::new($item7)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr, + $weight8:expr => $item8:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)), + ($weight7, $crate::std_facade::Arc::new($item7)), + ($weight8, $crate::std_facade::Arc::new($item8)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr, + $weight8:expr => $item8:expr, + $weight9:expr => $item9:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)), + ($weight7, $crate::std_facade::Arc::new($item7)), + ($weight8, $crate::std_facade::Arc::new($item8)), + ($weight9, $crate::std_facade::Arc::new($item9)))) + }; + + ($($weight:expr => $item:expr),+ $(,)?) => { + $crate::strategy::Union::new_weighted(vec![ + $(($weight, $crate::strategy::Strategy::boxed($item))),* + ]) + }; +} + +/// Convenience to define functions which produce new strategies. +/// +/// The macro has two general forms. In the first, you define a function with +/// two argument lists. The first argument list uses the usual syntax and +/// becomes exactly the argument list of the defined function. The second +/// argument list uses the `in strategy` syntax as with `proptest!`, and is +/// used to generate the other inputs for the function. The second argument +/// list has access to all arguments in the first. The return type indicates +/// the type of value being generated; the final return type of the function is +/// `impl Strategy`. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// use proptest::prelude::*; +/// +/// #[derive(Clone, Debug)] +/// struct MyStruct { +/// integer: u32, +/// string: String, +/// } +/// +/// prop_compose! { +/// fn my_struct_strategy(max_integer: u32) +/// (integer in 0..max_integer, string in ".*") +/// -> MyStruct { +/// MyStruct { integer, string } +/// } +/// } +/// # +/// # fn main() { } +/// ``` +/// +/// This form is simply sugar around making a tuple and then calling `prop_map` +/// on it. You can also use `arg: type` as in `proptest! { .. }`: +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// # use proptest::prelude::*; +/// # +/// # #[derive(Clone, Debug)] +/// # struct MyStruct { +/// # integer: u32, +/// # string: String, +/// # } +/// +/// prop_compose! { +/// fn my_struct_strategy(max_integer: u32) +/// (integer in 0..max_integer, string: String) +/// -> MyStruct { +/// MyStruct { integer, string } +/// } +/// } +/// # +/// # fn main() { } +/// ``` +/// +/// The second form is mostly the same, except that it takes _three_ argument +/// lists. The third argument list can see all values in both prior, which +/// permits producing strategies based on other strategies. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// use proptest::prelude::*; +/// +/// prop_compose! { +/// fn nearby_numbers()(centre in -1000..1000) +/// (a in centre-10..centre+10, +/// b in centre-10..centre+10) +/// -> (i32, i32) { +/// (a, b) +/// } +/// } +/// # +/// # fn main() { } +/// ``` +/// +/// However, the body of the function does _not_ have access to the second +/// argument list. If the body needs access to those values, they must be +/// passed through explicitly. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// use proptest::prelude::*; +/// +/// prop_compose! { +/// fn vec_and_index +/// (max_length: usize) +/// (vec in prop::collection::vec(1..10, 1..max_length)) +/// (index in 0..vec.len(), vec in Just(vec)) +/// -> (Vec, usize) +/// { +/// (vec, index) +/// } +/// } +/// # fn main() { } +/// ``` +/// +/// The second form is sugar around making a strategy tuple, calling +/// `prop_flat_map()`, then `prop_map()`. +/// +/// To give the function any modifier which isn't a visibility modifier, put it +/// in brackets before the `fn` token but after any visibility modifier. +/// +/// ```rust,no_run +/// # #![allow(dead_code)] +/// use proptest::prelude::*; +/// +/// prop_compose! { +/// pub(crate) [unsafe] fn pointer()(v in prop::num::usize::ANY) +/// -> *const () { +/// v as *const () +/// } +/// } +/// # fn main() { } +/// ``` +/// +/// ## Comparison with Hypothesis' `@composite` +/// +/// `prop_compose!` makes it easy to do a lot of things you can do with +/// [Hypothesis' `@composite`](https://hypothesis.readthedocs.io/en/latest/data.html#composite-strategies), +/// but not everything. +/// +/// - You can't filter via this macro. For filtering, you need to make the +/// strategy the "normal" way and use `prop_filter()`. +/// +/// - More than two layers of strategies or arbitrary logic between the two +/// layers. If you need either of these, you can achieve them by calling +/// `prop_flat_map()` by hand. +#[macro_export] +macro_rules! prop_compose { + ($(#[$meta:meta])* + $vis:vis + $([$($modi:tt)*])? fn $name:ident $params:tt + ($($var:pat in $strategy:expr),+ $(,)?) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $vis + $($($modi)*)? fn $name $params + -> impl $crate::strategy::Strategy { + let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); + $crate::strategy::Strategy::prop_map(strat, + move |$crate::proptest_helper!(@_WRAPPAT ($($var),*))| $body) + } + }; + + ($(#[$meta:meta])* + $vis:vis + $([$($modi:tt)*])? fn $name:ident $params:tt + ($($var:pat in $strategy:expr),+ $(,)?) + ($($var2:pat in $strategy2:expr),+ $(,)?) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $vis + $($($modi)*)? fn $name $params + -> impl $crate::strategy::Strategy { + let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); + let strat = $crate::strategy::Strategy::prop_flat_map( + strat, + move |$crate::proptest_helper!(@_WRAPPAT ($($var),*))| + $crate::proptest_helper!(@_WRAP ($($strategy2)*))); + $crate::strategy::Strategy::prop_map(strat, + move |$crate::proptest_helper!(@_WRAPPAT ($($var2),*))| $body) + } + }; + + ($(#[$meta:meta])* + $vis:vis + $([$($modi:tt)*])? fn $name:ident $params:tt + ($($arg:tt)+) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $vis + $($($modi)*)? fn $name $params + -> impl $crate::strategy::Strategy { + let strat = $crate::proptest_helper!(@_EXT _STRAT ($($arg)+)); + $crate::strategy::Strategy::prop_map(strat, + move |$crate::proptest_helper!(@_EXT _PAT ($($arg)+))| $body) + } + }; + + ($(#[$meta:meta])* + $vis:vis + $([$($modi:tt)*])? fn $name:ident $params:tt + ($($arg:tt)+ $(,)?) + ($($arg2:tt)+ $(,)?) + -> $return_type:ty $body:block) => + { + #[must_use = "strategies do nothing unless used"] + $(#[$meta])* + $vis + $($($modi)*)? fn $name $params + -> impl $crate::strategy::Strategy { + let strat = $crate::proptest_helper!(@_WRAP ($($strategy)*)); + let strat = $crate::strategy::Strategy::prop_flat_map( + strat, + move |$crate::proptest_helper!(@_EXT _PAT ($($arg)+))| + $crate::proptest_helper!(@_EXT _STRAT ($($arg2)*))); + $crate::strategy::Strategy::prop_map(strat, + move |$crate::proptest_helper!(@_EXT _PAT ($($arg2)*))| $body) + } + }; +} + +/// Similar to `assert!` from std, but returns a test failure instead of +/// panicking if the condition fails. +/// +/// This can be used in any function that returns a `Result<_, TestCaseError>`, +/// including the top-level function inside `proptest!`. +/// +/// Both panicking via `assert!` and returning a test case failure have the +/// same effect as far as proptest is concerned; however, the Rust runtime +/// implicitly prints every panic to stderr by default (including a backtrace +/// if enabled), which can make test failures unnecessarily noisy. By using +/// `prop_assert!` instead, the only output on a failing test case is the final +/// panic including the minimal test case. +/// +/// ## Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn triangle_inequality(a in 0.0f64..10.0, b in 0.0f64..10.0) { +/// // Called with just a condition will print the condition on failure +/// prop_assert!((a*a + b*b).sqrt() <= a + b); +/// // You can also provide a custom failure message +/// prop_assert!((a*a + b*b).sqrt() <= a + b, +/// "Triangle inequality didn't hold for ({}, {})", a, b); +/// // If calling another function that can return failure, don't forget +/// // the `?` to propagate the failure. +/// assert_from_other_function(a, b)?; +/// } +/// } +/// +/// // The macro can be used from another function provided it has a compatible +/// // return type. +/// fn assert_from_other_function(a: f64, b: f64) -> Result<(), TestCaseError> { +/// prop_assert!((a*a + b*b).sqrt() <= a + b); +/// Ok(()) +/// } +/// # +/// # fn main() { triangle_inequality(); } +/// ``` +#[macro_export] +macro_rules! prop_assert { + ($cond:expr) => { + $crate::prop_assert!($cond, concat!("assertion failed: ", stringify!($cond))) + }; + + ($cond:expr, $($fmt:tt)*) => { + if !$cond { + let message = format!($($fmt)*); + let message = format!("{} at {}:{}", message, file!(), line!()); + return ::core::result::Result::Err( + $crate::test_runner::TestCaseError::fail(message)); + } + }; +} + +/// Similar to `assert_eq!` from std, but returns a test failure instead of +/// panicking if the condition fails. +/// +/// See `prop_assert!` for a more in-depth discussion. +/// +/// ## Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn concat_string_length(ref a in ".*", ref b in ".*") { +/// let cat = format!("{}{}", a, b); +/// // Use with default message +/// prop_assert_eq!(a.len() + b.len(), cat.len()); +/// // Can also provide custom message (added after the normal +/// // assertion message) +/// prop_assert_eq!(a.len() + b.len(), cat.len(), +/// "a = {:?}, b = {:?}", a, b); +/// } +/// } +/// # +/// # fn main() { concat_string_length(); } +/// ``` +#[macro_export] +macro_rules! prop_assert_eq { + ($left:expr, $right:expr) => {{ + let left = $left; + let right = $right; + $crate::prop_assert!( + left == right, + "assertion failed: `(left == right)` \ + \n left: `{:?}`,\n right: `{:?}`", + left, right); + }}; + + ($left:expr, $right:expr, $fmt:tt $($args:tt)*) => {{ + let left = $left; + let right = $right; + $crate::prop_assert!( + left == right, + concat!( + "assertion failed: `(left == right)` \ + \n left: `{:?}`, \n right: `{:?}`: ", $fmt), + left, right $($args)*); + }}; +} + +/// Similar to `assert_ne!` from std, but returns a test failure instead of +/// panicking if the condition fails. +/// +/// See `prop_assert!` for a more in-depth discussion. +/// +/// ## Example +/// +/// ``` +/// use proptest::prelude::*; +/// +/// proptest! { +/// # /* +/// #[test] +/// # */ +/// fn test_addition(a in 0i32..100i32, b in 1i32..100i32) { +/// // Use with default message +/// prop_assert_ne!(a, a + b); +/// // Can also provide custom message added after the common message +/// prop_assert_ne!(a, a + b, "a = {}, b = {}", a, b); +/// } +/// } +/// # +/// # fn main() { test_addition(); } +/// ``` +#[macro_export] +macro_rules! prop_assert_ne { + ($left:expr, $right:expr) => {{ + let left = $left; + let right = $right; + prop_assert!( + left != right, + "assertion failed: `(left != right)`\ + \n left: `{:?}`,\n right: `{:?}`", + left, right); + }}; + + ($left:expr, $right:expr, $fmt:tt $($args:tt)*) => {{ + let left = $left; + let right = $right; + prop_assert!(left != right, concat!( + "assertion failed: `(left != right)`\ + \n left: `{:?}`,\n right: `{:?}`: ", $fmt), + left, right $($args)*); + }}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! proptest_helper { + (@_WRAP ($a:tt)) => { $a }; + (@_WRAP ($a0:tt $a1:tt)) => { ($a0, $a1) }; + (@_WRAP ($a0:tt $a1:tt $a2:tt)) => { ($a0, $a1, $a2) }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt)) => { ($a0, $a1, $a2, $a3) }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt)) => { + ($a0, $a1, $a2, $a3, $a4) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt $a5:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt $a5:tt $a6:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt + $a4:tt $a5:tt $a6:tt $a7:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt + $a5:tt $a6:tt $a7:tt $a8:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8) + }; + (@_WRAP ($a0:tt $a1:tt $a2:tt $a3:tt $a4:tt + $a5:tt $a6:tt $a7:tt $a8:tt $a9:tt)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9) + }; + (@_WRAP ($a:tt $($rest:tt)*)) => { + ($a, $crate::proptest_helper!(@_WRAP ($($rest)*))) + }; + (@_WRAPPAT ($item:pat)) => { $item }; + (@_WRAPPAT ($a0:pat, $a1:pat)) => { ($a0, $a1) }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat)) => { ($a0, $a1, $a2) }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat)) => { + ($a0, $a1, $a2, $a3) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat)) => { + ($a0, $a1, $a2, $a3, $a4) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, $a5:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat, $a7:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8) + }; + (@_WRAPPAT ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat, $a9:pat)) => { + ($a0, $a1, $a2, $a3, $a4, $a5, $a6, $a7, $a8, $a9) + }; + (@_WRAPPAT ($a:pat, $($rest:pat),*)) => { + ($a, $crate::proptest_helper!(@_WRAPPAT ($($rest),*))) + }; + (@_WRAPSTR ($item:pat)) => { stringify!($item) }; + (@_WRAPSTR ($a0:pat, $a1:pat)) => { (stringify!($a0), stringify!($a1)) }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), + stringify!($a3), stringify!($a4)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, $a5:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, + $a4:pat, $a5:pat, $a6:pat, $a7:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7), + stringify!($a8)) + }; + (@_WRAPSTR ($a0:pat, $a1:pat, $a2:pat, $a3:pat, $a4:pat, + $a5:pat, $a6:pat, $a7:pat, $a8:pat, $a9:pat)) => { + (stringify!($a0), stringify!($a1), stringify!($a2), stringify!($a3), + stringify!($a4), stringify!($a5), stringify!($a6), stringify!($a7), + stringify!($a8), stringify!($a9)) + }; + (@_WRAPSTR ($a:pat, $($rest:pat),*)) => { + (stringify!($a), $crate::proptest_helper!(@_WRAPSTR ($($rest),*))) + }; + // build a property testing block that when executed, executes the full property test. + (@_BODY $config:ident ($($parm:pat in $strategy:expr),+) [$($mod:tt)*] $body:expr) => {{ + // $config.source_file = Some(file!()); + // let mut runner = $crate::test_runner::TestRunner::new($config); + // let names = $crate::proptest_helper!(@_WRAPSTR ($($parm),*)); + // match runner.run( + // &$crate::strategy::Strategy::prop_map( + // $crate::proptest_helper!(@_WRAP ($($strategy)*)), + // |values| $crate::sugar::NamedArguments(names, values)), + // $($mod)* |$crate::sugar::NamedArguments( + // _, $crate::proptest_helper!(@_WRAPPAT ($($parm),*)))| + // { + // let _: () = $body; + // Ok(()) + // }) + // { + // Ok(_) => (), + // Err(e) => panic!("{}BODY\n{}", e, runner), + // } + $crate::test_runner::TestRunner::run_kani( + $crate::proptest_helper!(@_WRAP ($($strategy)*)), + |$crate::proptest_helper!(@_WRAPPAT ($($parm),*))| { + $body + } + ); + }}; + // build a property testing block that when executed, executes the full property test. + (@_BODY2 $config:ident ($($arg:tt)+) [$($mod:tt)*] $body:expr) => {{ + $crate::test_runner::TestRunner::run_kani( + $crate::proptest_helper!(@_EXT _STRAT ($($arg)*)), + |$crate::proptest_helper!(@_EXT _PAT ($($arg)*))| { + $body + } + ); + }}; + + // The logic below helps support `pat: type` in the proptest! macro. + + // These matchers define the actual logic: + (@_STRAT [$s:ty] [$p:pat]) => { $crate::arbitrary::any::<$s>() }; + (@_PAT [$s:ty] [$p:pat]) => { $p }; + (@_STR [$s:ty] [$p:pat]) => { stringify!($p) }; + (@_STRAT in [$s:expr] [$p:pat]) => { $s }; + (@_PAT in [$s:expr] [$p:pat]) => { $p }; + (@_STR in [$s:expr] [$p:pat]) => { stringify!($p) }; + + // These matchers rewrite into the above extractors. + // We have to do this because `:` can't FOLLOW(pat). + // Note that this is not the full `pat` grammar... + // See https://docs.rs/syn/0.14.2/syn/enum.Pat.html for that. + (@_EXT $cmd:ident ($p:pat in $s:expr $(,)?)) => { + $crate::proptest_helper!(@$cmd in [$s] [$p]) + }; + (@_EXT $cmd:ident (($p:pat) : $s:ty $(,)?)) => { + // Users can wrap in parens as a last resort. + $crate::proptest_helper!(@$cmd [$s] [$p]) + }; + (@_EXT $cmd:ident (_ : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [_]) + }; + (@_EXT $cmd:ident (ref mut $p:ident : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [ref mut $p]) + }; + (@_EXT $cmd:ident (ref $p:ident : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [ref $p]) + }; + (@_EXT $cmd:ident (mut $p:ident : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [mut $p]) + }; + (@_EXT $cmd:ident ($p:ident : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [$p]) + }; + (@_EXT $cmd:ident ([$($p:tt)*] : $s:ty $(,)?)) => { + $crate::proptest_helper!(@$cmd [$s] [[$($p)*]]) + }; + + // Rewrite, Inductive case: + (@_EXT $cmd:ident ($p:pat in $s:expr, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd in [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (($p:pat) : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (_ : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [_]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (ref mut $p:ident : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [ref mut $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (ref $p:ident : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [ref $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident (mut $p:ident : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [mut $p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident ($p:ident : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [$p]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; + (@_EXT $cmd:ident ([$($p:tt)*] : $s:ty, $($r:tt)*)) => { + ($crate::proptest_helper!(@$cmd [$s] [[$($p)*]]), $crate::proptest_helper!(@_EXT $cmd ($($r)*))) + }; +} From 8a0335e5f86174f3d779d50f5750f1a04df5ca45 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 18:04:30 -0400 Subject: [PATCH 55/80] Reverted Cargo.toml of proptest testcase. The old one works. --- tests/cargo-kani/proptest/Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/cargo-kani/proptest/Cargo.toml b/tests/cargo-kani/proptest/Cargo.toml index e3e7668fe291..364be5429361 100644 --- a/tests/cargo-kani/proptest/Cargo.toml +++ b/tests/cargo-kani/proptest/Cargo.toml @@ -5,5 +5,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html -#[target.'cfg(not(kani))'.dependencies] -#proptest = '1.0.0' +[target.'cfg(not(kani))'.dependencies] +proptest = '1.0.0' From c09133622b77985ea13955b2eacdaa8f46b6c1d1 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 18:55:38 -0400 Subject: [PATCH 56/80] Rustfmt. --- tests/cargo-kani/proptest/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cargo-kani/proptest/src/lib.rs b/tests/cargo-kani/proptest/src/lib.rs index c4a90a496127..2ebf97e58312 100644 --- a/tests/cargo-kani/proptest/src/lib.rs +++ b/tests/cargo-kani/proptest/src/lib.rs @@ -6,7 +6,7 @@ use proptest::test_runner::Config; // check if the proptest library is linked and macro is working. -proptest::proptest!{ +proptest::proptest! { fn successfully_linked_proptest(_ in proptest::strategy::Just(()) ) { let config = Config::default(); assert_eq!( From 4a680ace87151c9815d8fff6f42013ba1c330bf4 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 18:55:54 -0400 Subject: [PATCH 57/80] Supressed warnings caused by kani-specific panic! macro. --- library/proptest/src/strategy/traits.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/proptest/src/strategy/traits.rs b/library/proptest/src/strategy/traits.rs index 3a34834ae2e5..55f552fc8815 100644 --- a/library/proptest/src/strategy/traits.rs +++ b/library/proptest/src/strategy/traits.rs @@ -818,6 +818,10 @@ impl Default for CheckStrategySanityOptions { /// /// This can work with fallible strategies, but limits how many times it will /// retry failures. +/// +/// We allow unused variables because we need to compile with this with +/// kani. Kani's library hacks cause unused variables around panic! +#[allow(unused_variables)] pub fn check_strategy_sanity(strategy: S, options: Option) where S::Tree: Clone + fmt::Debug, From 81b7601f49bea01d00e02a44a73e21ec8f903136 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 20:43:55 -0400 Subject: [PATCH 58/80] Reverted invariant. --- library/kani/src/invariant.rs | 100 +++++++++------------------------- 1 file changed, 25 insertions(+), 75 deletions(-) diff --git a/library/kani/src/invariant.rs b/library/kani/src/invariant.rs index e7a2c9ef357e..08e5ace8e89b 100644 --- a/library/kani/src/invariant.rs +++ b/library/kani/src/invariant.rs @@ -1,8 +1,9 @@ // Copyright Kani Contributors // SPDX-License-Identifier: Apache-2.0 OR MIT -//! This module introduces the Invariant trait as well as implementation for commonly used types. -use std::num::*; +//! This module introduces the Invariant trait. + +use crate::Arbitrary; /// Types that implement a check to ensure its value is valid and safe to be used. See /// for examples of valid values. @@ -14,84 +15,33 @@ use std::num::*; /// /// This trait is unsafe since &self might represent an invalid value. The `is_valid()` function /// must return `true` if and only if the invariant of its type is held. +/// +/// # Deprecation +/// +/// We have decided to deprecate this trait in favor of using `Arbitrary` for now. The main +/// benefit of using Invariant was to avoid calling `kani::any_raw()` followed by `kani::assume()`. +/// However, `kani::any_raw()` today cannot guarantee the rust type validity invariants, which +/// could lead to UB in our analysis. +#[deprecated( + since = "0.8.0", + note = "With `kani::Invariant`, Kani cannot guarantee that the type respects the language \ + type invariants which may trigger UB. Use `kani::Arbitrary` instead." +)] pub unsafe trait Invariant { /// Check if `&self` holds a valid value that respect the type invariant. /// This function must return `true` if and only if `&self` is valid. fn is_valid(&self) -> bool; } -macro_rules! empty_invariant { - ( $type: ty ) => { - unsafe impl Invariant for $type { - #[inline(always)] - fn is_valid(&self) -> bool { - true - } - } - }; -} - -empty_invariant!(u8); -empty_invariant!(u16); -empty_invariant!(u32); -empty_invariant!(u64); -empty_invariant!(u128); -empty_invariant!(usize); - -empty_invariant!(i8); -empty_invariant!(i16); -empty_invariant!(i32); -empty_invariant!(i64); -empty_invariant!(i128); -empty_invariant!(isize); - -// We do not constraint floating points values per type spec. Users must add assumptions to their -// verification code if they want to eliminate NaN, infinite, or subnormal. -empty_invariant!(f32); -empty_invariant!(f64); - -empty_invariant!(()); - -unsafe impl Invariant for bool { - #[inline(always)] - fn is_valid(&self) -> bool { - let byte = u8::from(*self); - byte == 0 || byte == 1 - } -} - -/// Validate that a char is not outside the ranges [0x0, 0xD7FF] and [0xE000, 0x10FFFF] -/// Ref: -unsafe impl Invariant for char { - #[inline(always)] - fn is_valid(&self) -> bool { - // Kani translates char into i32. - let val = *self as i32; - val <= 0xD7FF || (0xE000..=0x10FFFF).contains(&val) +// We cannot apply #[deprecated] to trait impl so add this to ignore the deprecation warnings. +#[allow(deprecated)] +impl Arbitrary for T +where + T: Invariant, +{ + default fn any() -> Self { + let value = unsafe { crate::any_raw_internal::() }; + crate::assume(value.is_valid()); + value } } - -macro_rules! nonzero_invariant { - ( $type: ty ) => { - unsafe impl Invariant for $type { - #[inline(always)] - fn is_valid(&self) -> bool { - self.get() != 0 - } - } - }; -} - -nonzero_invariant!(NonZeroU8); -nonzero_invariant!(NonZeroU16); -nonzero_invariant!(NonZeroU32); -nonzero_invariant!(NonZeroU64); -nonzero_invariant!(NonZeroU128); -nonzero_invariant!(NonZeroUsize); - -nonzero_invariant!(NonZeroI8); -nonzero_invariant!(NonZeroI16); -nonzero_invariant!(NonZeroI32); -nonzero_invariant!(NonZeroI64); -nonzero_invariant!(NonZeroI128); -nonzero_invariant!(NonZeroIsize); From 5aac1edd064a881611977a9afcc3f8e8e58fa4af Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 20:45:20 -0400 Subject: [PATCH 59/80] Temporarily removed refresh script. --- scripts/cargo-kani | 2 +- scripts/kani | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/cargo-kani b/scripts/cargo-kani index c3452c85ece4..3f1fa775dae3 100755 --- a/scripts/cargo-kani +++ b/scripts/cargo-kani @@ -21,7 +21,7 @@ KANI_PATH=${KANI_CANDIDATES[0]} if [ -z "${CARGO_KANI_IS_CHILD+x}" ]; then # avoid infinite recursion as below script also calls `cargo kani` - $SCRIPT_DIR/refresh-kani-proptest.sh + true # $SCRIPT_DIR/refresh-kani-proptest.sh fi CARGO_TOML_SAVE_FILE='.save-cargo.toml' diff --git a/scripts/kani b/scripts/kani index 03a5b7968a48..1ed225b2cb8d 100755 --- a/scripts/kani +++ b/scripts/kani @@ -19,6 +19,4 @@ then fi KANI_PATH=${KANI_CANDIDATES[0]} -$SCRIPT_DIR/refresh-kani-proptest.sh - exec -a kani "${KANI_PATH}" "$@" From 49bd73eb1847c4832625e5ff17834e1a53b11830 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 22:41:43 -0400 Subject: [PATCH 60/80] Cleaner path to root workspace. --- .cargo/config.toml | 7 +++++++ kani-driver/build.rs | 12 +++++++----- kani-driver/src/call_cargo.rs | 4 ++-- scripts/cargo-kani | 26 ++++++++++++-------------- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 52976cfaa9c3..f3bf2376d901 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -20,3 +20,10 @@ rustflags = [ # Global lints/warnings. Need to use underscore instead of -. "-Aclippy::too_many_arguments", "-Aclippy::type_complexity", ] + +[env] +# This is a hack to get the root of the workspace. TODO: This should be +# removed when cargo implements this. See +# https://github.com/rust-lang/cargo/issues/3946#issuecomment-973132993 +# for details. +CARGO_WORKSPACE_DIR = { value = "", relative = true } diff --git a/kani-driver/build.rs b/kani-driver/build.rs index 621e33d02c70..f327aead308e 100644 --- a/kani-driver/build.rs +++ b/kani-driver/build.rs @@ -9,9 +9,11 @@ fn main() { // https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates // https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-build-scripts // So "repeat" the info from build script (here) to our crate's build environment. - - let target = var("TARGET").unwrap(); - let out_dir = var("OUT_DIR").unwrap(); - println!("cargo:rustc-env=KANI_EXTERN_DIR={}/../../../../{}/debug/deps", out_dir, target); - println!("cargo:rustc-env=TARGET={}", target); + let target_arch = var("TARGET").unwrap(); + let workspace_root = var("CARGO_WORKSPACE_DIR").unwrap(); + println!( + "cargo:rustc-env=KANI_EXTERN_OUT_DIR={}/target/{}/debug/deps", + workspace_root, &target_arch + ); + println!("cargo:rustc-env=TARGET={}", &target_arch); } diff --git a/kani-driver/src/call_cargo.rs b/kani-driver/src/call_cargo.rs index 1910809609fe..01dd3c6c4531 100644 --- a/kani-driver/src/call_cargo.rs +++ b/kani-driver/src/call_cargo.rs @@ -34,11 +34,11 @@ fn find_target_dir() -> PathBuf { impl KaniSession { /// Calls `cargo_build` to generate `*.symtab.json` files in `target_dir` pub fn cargo_build(&self) -> Result { - let build_target = env!("TARGET"); // see build.rs + let build_target = env!("TARGET"); // target architecture, see build.rs let target_dir = self.args.target_dir.as_ref().unwrap_or(&find_target_dir()).clone(); let outdir = target_dir.join(build_target).join("debug/deps"); - let kani_extern_lib_path = PathBuf::from(std::env!("KANI_EXTERN_DIR")); + let kani_extern_lib_path = PathBuf::from(std::env!("KANI_EXTERN_OUT_DIR")); let flag_env = { let rustc_args = self.kani_rustc_flags(); diff --git a/scripts/cargo-kani b/scripts/cargo-kani index 3f1fa775dae3..152c0d64551f 100755 --- a/scripts/cargo-kani +++ b/scripts/cargo-kani @@ -19,21 +19,19 @@ then fi KANI_PATH=${KANI_CANDIDATES[0]} -if [ -z "${CARGO_KANI_IS_CHILD+x}" ]; then - # avoid infinite recursion as below script also calls `cargo kani` - true # $SCRIPT_DIR/refresh-kani-proptest.sh -fi - -CARGO_TOML_SAVE_FILE='.save-cargo.toml' -if [[ "${PROPTEST+x}" == "1" ]]; then - cp Cargo.toml $CARGO_TOML_SAVE_FILE - cat Cargo.toml | sed 's/^\s*proptest.*$//g' | tee Cargo.toml 1>/dev/null - +# if the crate uses proptest, get ready to run that. Make sure local +# proptest import and kani's proptest does not clash. +if grep '^proptest\s*=' Cargo.toml > /dev/null; then + if grep -F "[target.'cfg(not(kani))'.dependencies]" Cargo.toml > /dev/null \ + && [ -z "${CARGO_KANI_IS_CHILD+x}" ]; then + $SCRIPT_DIR/refresh-kani-proptest.sh + export IS_KANI_PROPTEST=1 + else + echo "Clashing import of proptest. Stopping cargo kani." + echo "Please put your proptest import under [target.'cfg(not(kani))'.dependencies]" + exit 1 + fi fi exec -a cargo-kani "${KANI_PATH}" "$@" EXIT_CODE="$?" - -# todo! Somehow, this is not running. Exits fro cargo kani error. -cat $CARGO_TOML_SAVE_FILE > Cargo.toml -exit $EXIT_CODE From a488a1854438c046057a9bf3d598382a82e1cef4 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 22:44:20 -0400 Subject: [PATCH 61/80] Made extended linking paths dependent on env being set for proptest. --- kani-driver/src/call_cargo.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/kani-driver/src/call_cargo.rs b/kani-driver/src/call_cargo.rs index 01dd3c6c4531..de94d57df9c0 100644 --- a/kani-driver/src/call_cargo.rs +++ b/kani-driver/src/call_cargo.rs @@ -82,17 +82,19 @@ impl KaniSession { }); } + let mut symtabs = glob(&outdir.join("*.symtab.json"))?; + let mut metadata = glob(&outdir.join("*.kani-metadata.json"))?; + if std::env::var("IS_KANI_PROPTEST").is_ok() { + // if the "proptests is precent" flag is enabled by cargo-kani + symtabs.extend(glob(&kani_extern_lib_path.join("*.symtab.json"))?); + metadata.extend(glob(&outdir.join("*.kani-metadata.json"))?); + } + Ok(CargoOutputs { outdir: outdir.clone(), - symtabs: glob(&outdir.join("*.symtab.json"))? - .into_iter() - .chain(glob(&kani_extern_lib_path.join("*.symtab.json"))?) - .collect(), - metadata: glob(&outdir.join("*.kani-metadata.json"))? - .into_iter() - .chain(glob(&kani_extern_lib_path.join("*.kani-metadata.json"))?) - .collect(), - restrictions: self.args.restrict_vtable().then(|| outdir), + symtabs, + metadata, + restrictions: self.args.restrict_vtable().then_some(outdir), }) } } From 5de4c25ab81d0e98bd7aea1de1d536225c2781d2 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 22:45:30 -0400 Subject: [PATCH 62/80] Fixed proptest refresh taht was occuring too frequently. --- scripts/kani-regression.sh | 1 + scripts/refresh-kani-proptest.sh | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/kani-regression.sh b/scripts/kani-regression.sh index f9c5a6b9f707..c9486b401702 100755 --- a/scripts/kani-regression.sh +++ b/scripts/kani-regression.sh @@ -30,6 +30,7 @@ PYTHONPATH=${SCRIPT_DIR} python3 -m unittest ${SCRIPT_DIR}/test_cbmc_json_parser # Build all packages in the workspace cargo build --workspace +${SCRIPT_DIR}/refresh-kani-proptest.sh # Unit tests cargo test -p cprover_bindings diff --git a/scripts/refresh-kani-proptest.sh b/scripts/refresh-kani-proptest.sh index 99e7f8e4f87e..5f0786f9aef2 100755 --- a/scripts/refresh-kani-proptest.sh +++ b/scripts/refresh-kani-proptest.sh @@ -12,9 +12,9 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) KANI_REPO_ROOT="$SCRIPT_DIR/.." PROPTEST_SYMTAB_PATH="$(find $KANI_REPO_ROOT/target -name '*symtab.json' | head -1)" -KANI_TARGET="$KANI_REPO_ROOT/target/debug/libproptest.d" +PROPTEST_RLIB_PATH="$KANI_REPO_ROOT/target/debug/libproptest.rlib" -if [ ! -f "$PROPTEST_SYMTAB_PATH" ] || [[ "$PROPTEST_SYMTAB_PATH" -ot "$KANI_TARGET" ]]; then +if [ ! -f "$PROPTEST_SYMTAB_PATH" ] || [[ "$PROPTEST_SYMTAB_PATH" -ot "$PROPTEST_RLIB_PATH" ]]; then echo 'Proptest symtab not found or too old. (Re)compiling proptest..' ( cd $KANI_REPO_ROOT/library/proptest; From 02a94da787a88821758513a737118fa27b1ad48f Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 22:45:51 -0400 Subject: [PATCH 63/80] Remove proptest import. They break since only strategies are loaded. --- tests/cargo-kani/rectangle-example/Cargo.toml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/cargo-kani/rectangle-example/Cargo.toml b/tests/cargo-kani/rectangle-example/Cargo.toml index 7f26c7256dca..0d939f44c30f 100644 --- a/tests/cargo-kani/rectangle-example/Cargo.toml +++ b/tests/cargo-kani/rectangle-example/Cargo.toml @@ -8,5 +8,7 @@ edition = "2018" [dependencies] -[dev-dependencies] -proptest = "1.0.0" +# Turned off while proptest integration is merging. The first PR will +# not support any integers, which crashes this test case. +# [dev-dependencies] +# proptest = "1.0.0" From a1f23c8c1ff1489830a219051f6cf42ac55c10e6 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 22:52:30 -0400 Subject: [PATCH 64/80] Purged tests not needed at this sub-PR. --- tests/proptest/primitive/fixme-multi-arg.rs | 39 ------- tests/proptest/primitive/fixme-single-arg.rs | 104 ------------------ .../primitive/fixme-single-strategy.rs | 103 ----------------- 3 files changed, 246 deletions(-) delete mode 100644 tests/proptest/primitive/fixme-multi-arg.rs delete mode 100644 tests/proptest/primitive/fixme-single-arg.rs delete mode 100644 tests/proptest/primitive/fixme-single-strategy.rs diff --git a/tests/proptest/primitive/fixme-multi-arg.rs b/tests/proptest/primitive/fixme-multi-arg.rs deleted file mode 100644 index 8f415445c35c..000000000000 --- a/tests/proptest/primitive/fixme-multi-arg.rs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright Kani Contributors -// SPDX-License-Identifier: Apache-2.0 OR MIT - -//! Proptests with a single primitive input. This repetition should be -//! done with macros, but since we have already 2 nested macros, I -//! pre-expanded for clarity during development. - -kani::translate_from_proptest!{ -proptest! { - #[kani::proof] - fn proptest_two_types(input_1 : u8, input_2 : i32) { - let derived = input_2 << input_1; - assert!(derived + derived >= 0); - assert_eq!(derived - derived, 0); - } - - #[kani::proof] - fn proptest_two_strategies(input_1 : proptest::arbitrary::any, input_2 : proptest::arbitrary::any) { - let derived = input_2 << input_1; - assert!(derived + derived >= 0); - assert_eq!(derived - derived, 0); - } - - #[kani::proof] - fn proptest_two_mixed_type_first(input_1 : u8, input_2 : proptest::arbitrary::any) { - let derived = input_2 << input_1; - assert!(derived + derived >= 0); - assert_eq!(derived - derived, 0); - } - - #[kani::proof] - fn proptest_two_mixed_type_first(input_1 : proptest::arbitrary::any, input_2 : i32) { - let derived = input_2 << input_1; - assert!(derived + derived >= 0); - assert_eq!(derived - derived, 0); - } -} -} - diff --git a/tests/proptest/primitive/fixme-single-arg.rs b/tests/proptest/primitive/fixme-single-arg.rs deleted file mode 100644 index 880a7c9dc427..000000000000 --- a/tests/proptest/primitive/fixme-single-arg.rs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright Kani Contributors -// SPDX-License-Identifier: Apache-2.0 OR MIT - -//! Proptests with a single primitive input. This repetition should be -//! done with macros, but since we have already 2 nested macros, I -//! pre-expanded for clarity. - -kani::translate_from_proptest!{ -proptest! { - #[kani::proof] - fn proptest_u8 (input_1 : u8) { - assert!(input_1 + input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_u16 (input_1 : u16) { - assert!(input_1 + input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_u32 (input_1 : u32) { - assert!(input_1 + input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_u64 (input_1 : u64) { - assert!(input_1 + input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_u128 (input_1 : u128) { - assert!(input_1 + input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_usize (input_1 : usize) { - assert!(input_1 + input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_i8 (input_1 : i8) { - assert!(input_1 * input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_i16 (input_1 : i16) { - assert!(input_1 * input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_i32 (input_1 : i32) { - assert!(input_1 * input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_i64 (input_1 : i64) { - assert!(input_1 * input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_i128 (input_1 : i128) { - assert!(input_1 * input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_isize (input_1 : isize) { - assert!(input_1 * input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} -} diff --git a/tests/proptest/primitive/fixme-single-strategy.rs b/tests/proptest/primitive/fixme-single-strategy.rs deleted file mode 100644 index 57146f841013..000000000000 --- a/tests/proptest/primitive/fixme-single-strategy.rs +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright Kani Contributors -// SPDX-License-Identifier: Apache-2.0 OR MIT - -//! Proptests with a single primitive strategy. Also expanded for -//! clarity during testing. - -kani::translate_from_proptest!{ -proptest! { - #[kani::proof] - fn proptest_u8 (input_1 in proptest::arbitrary::any) { - assert!(input_1 + input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_u16 (input_1 in proptest::arbitrary::any) { - assert!(input_1 + input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_u32 (input_1 in proptest::arbitrary::any) { - assert!(input_1 + input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_u64 (input_1 in proptest::arbitrary::any) { - assert!(input_1 + input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_u128 (input_1 in proptest::arbitrary::any) { - assert!(input_1 + input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_usize (input_1 in proptest::arbitrary::any) { - assert!(input_1 + input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_i8 (input_1 in proptest::arbitrary::any) { - assert!(input_1 * input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_i16 (input_1 in proptest::arbitrary::any) { - assert!(input_1 * input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_i32 (input_1 in proptest::arbitrary::any) { - assert!(input_1 * input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_i64 (input_1 in proptest::arbitrary::any) { - assert!(input_1 * input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_i128 (input_1 in proptest::arbitrary::any) { - assert!(input_1 * input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} - -proptest! { - #[kani::proof] - fn proptest_isize (input_1 in proptest::arbitrary::any) { - assert!(input_1 * input_1 >= 0); - assert_eq!(input_1 - input_1, 0); - } -} -} From 9ddd844c554ce872e1ed83ae30ef1dd0ebc61b15 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 23:08:31 -0400 Subject: [PATCH 65/80] Cleaned up paths. --- kani-compiler/build.rs | 8 +++++++- kani-compiler/src/main.rs | 5 +---- kani-driver/src/call_cargo.rs | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/kani-compiler/build.rs b/kani-compiler/build.rs index 8a96a81cbb9c..4cdef48c5c4f 100644 --- a/kani-compiler/build.rs +++ b/kani-compiler/build.rs @@ -62,9 +62,15 @@ pub fn main() { // Compile kani library and export KANI_LIB_PATH variable with its relative location. let out_dir = env::var("OUT_DIR").unwrap(); let lib_out = path_str!([&out_dir, "lib"]); + let target = env::var("TARGET").unwrap(); setup_lib(&out_dir, &lib_out, "kani"); setup_lib(&out_dir, &lib_out, "kani_macros"); setup_lib(&out_dir, &lib_out, "std"); println!("cargo:rustc-env=KANI_LIB_PATH={}", lib_out); - println!("cargo:rustc-env=TARGET={}", env::var("TARGET").unwrap()); + println!("cargo:rustc-env=TARGET={}", target); + println!( + "cargo:rustc-env=KANI_EXTERN_OUT_DIR={}/target/{}/debug/deps", + env::var("CARGO_WORKSPACE_DIR").unwrap(), + target + ); } diff --git a/kani-compiler/src/main.rs b/kani-compiler/src/main.rs index d15ddd57c9ba..cb0ce40ee72d 100644 --- a/kani-compiler/src/main.rs +++ b/kani-compiler/src/main.rs @@ -47,10 +47,7 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { // for more details. let kani_std_rlib = PathBuf::from(lib_path).join("libstd.rlib"); let kani_std_wrapper = format!("noprelude:std={}", kani_std_rlib.to_str().unwrap()); - - let build_target = env!("TARGET"); // see build.rs - let kani_extern_lib_path = - PathBuf::from(lib_path).join(format!("../../../../../{}/debug/deps", build_target)); + let kani_extern_lib_path = PathBuf::from(env!("KANI_EXTERN_OUT_DIR")); let args = vec![ "-C", diff --git a/kani-driver/src/call_cargo.rs b/kani-driver/src/call_cargo.rs index de94d57df9c0..0f125e0832c4 100644 --- a/kani-driver/src/call_cargo.rs +++ b/kani-driver/src/call_cargo.rs @@ -38,7 +38,7 @@ impl KaniSession { let target_dir = self.args.target_dir.as_ref().unwrap_or(&find_target_dir()).clone(); let outdir = target_dir.join(build_target).join("debug/deps"); - let kani_extern_lib_path = PathBuf::from(std::env!("KANI_EXTERN_OUT_DIR")); + let kani_extern_lib_path = PathBuf::from(env!("KANI_EXTERN_OUT_DIR")); let flag_env = { let rustc_args = self.kani_rustc_flags(); From a66a89c5beac3f8657be02d961073083c7b2e094 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 23:11:55 -0400 Subject: [PATCH 66/80] Purged debug comment on macro expansion. --- kani-compiler/src/main.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/kani-compiler/src/main.rs b/kani-compiler/src/main.rs index cb0ce40ee72d..592537daaa32 100644 --- a/kani-compiler/src/main.rs +++ b/kani-compiler/src/main.rs @@ -67,9 +67,6 @@ fn rustc_gotoc_flags(lib_path: &str) -> Vec { "crate-attr=feature(register_tool)", "-Z", "crate-attr=register_tool(kanitool)", - // Prints expanded macro. For proptest devops only, remove after done - // "-Z", - // "unpretty=expanded", "-L", lib_path, "--extern", From f744b7c56f457445e3a08cb486c6b0a5333ff3ef Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 23:15:35 -0400 Subject: [PATCH 67/80] Fixed license. --- library/proptest/src/sugar.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/library/proptest/src/sugar.rs b/library/proptest/src/sugar.rs index 86649c42f483..37950657c53a 100644 --- a/library/proptest/src/sugar.rs +++ b/library/proptest/src/sugar.rs @@ -6,8 +6,11 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. + +// SPDX-License-Identifier: Apache-2.0 OR MIT +// // Modifications Copyright Kani Contributors -// See GitHub history for details +// See GitHub history for details. // use crate::std_facade::fmt; From 933751a15e7adaf812e349a544800553821d27f3 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Wed, 3 Aug 2022 23:19:00 -0400 Subject: [PATCH 68/80] Fixed license for new test case. --- tests/cargo-kani/proptest/Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/cargo-kani/proptest/Cargo.toml b/tests/cargo-kani/proptest/Cargo.toml index 364be5429361..8775cbd99bc7 100644 --- a/tests/cargo-kani/proptest/Cargo.toml +++ b/tests/cargo-kani/proptest/Cargo.toml @@ -1,3 +1,6 @@ +# Copyright Kani Contributors +# SPDX-License-Identifier: Apache-2.0 OR MIT + [package] name = "proptest-test-cases" version = "0.1.0" From 3262c1edface29f241a00855b98182d547567555 Mon Sep 17 00:00:00 2001 From: YoshikiTakashima Date: Thu, 4 Aug 2022 14:49:36 +0000 Subject: [PATCH 69/80] More temporary disabling of proptest --- docs/src/tutorial/first-steps-v1/Cargo.toml | 6 ++++-- docs/src/tutorial/first-steps-v2/Cargo.toml | 6 ++++-- docs/src/tutorial/kinds-of-failure/Cargo.toml | 6 ++++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/docs/src/tutorial/first-steps-v1/Cargo.toml b/docs/src/tutorial/first-steps-v1/Cargo.toml index a034b3ea3411..5cdeac3f462d 100644 --- a/docs/src/tutorial/first-steps-v1/Cargo.toml +++ b/docs/src/tutorial/first-steps-v1/Cargo.toml @@ -7,7 +7,9 @@ edition = "2018" [dependencies] -[dev-dependencies] -proptest = "1.0.0" +# Turned off while proptest integration is merging. The first PR will +# not support any integers, which crashes this test case. +# [dev-dependencies] +# proptest = "1.0.0" [workspace] diff --git a/docs/src/tutorial/first-steps-v2/Cargo.toml b/docs/src/tutorial/first-steps-v2/Cargo.toml index 5524ce6aeb90..accfe4b42ee6 100644 --- a/docs/src/tutorial/first-steps-v2/Cargo.toml +++ b/docs/src/tutorial/first-steps-v2/Cargo.toml @@ -7,7 +7,9 @@ edition = "2018" [dependencies] -[dev-dependencies] -proptest = "1.0.0" +# Turned off while proptest integration is merging. The first PR will +# not support any integers, which crashes this test case. +# [dev-dependencies] +# proptest = "1.0.0" [workspace] diff --git a/docs/src/tutorial/kinds-of-failure/Cargo.toml b/docs/src/tutorial/kinds-of-failure/Cargo.toml index 4dc1ae87565e..baf009dee087 100644 --- a/docs/src/tutorial/kinds-of-failure/Cargo.toml +++ b/docs/src/tutorial/kinds-of-failure/Cargo.toml @@ -7,7 +7,9 @@ edition = "2018" [dependencies] -[dev-dependencies] -proptest = "1.0.0" +# Turned off while proptest integration is merging. The first PR will +# not support any integers, which crashes this test case. +# [dev-dependencies] +# proptest = "1.0.0" [workspace] From 9ebad12a4a3594c96769cbfcfadd9a402435e568 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 8 Aug 2022 16:21:36 -0400 Subject: [PATCH 70/80] Changed comment to point to kani tracking issue. --- .cargo/config.toml | 7 +++---- docs/src/tutorial/first-steps-v1/Cargo.toml | 3 ++- docs/src/tutorial/first-steps-v2/Cargo.toml | 3 ++- library/proptest/src/lib.rs | 3 ++- library/proptest/src/strategy/just.rs | 2 -- library/proptest/src/strategy/mod.rs | 4 +++- library/proptest/src/strategy/traits.rs | 4 +++- tests/cargo-kani/rectangle-example/Cargo.toml | 3 ++- 8 files changed, 17 insertions(+), 12 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index f3bf2376d901..ae53166d4992 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -22,8 +22,7 @@ rustflags = [ # Global lints/warnings. Need to use underscore instead of -. ] [env] -# This is a hack to get the root of the workspace. TODO: This should be -# removed when cargo implements this. See -# https://github.com/rust-lang/cargo/issues/3946#issuecomment-973132993 -# for details. +# This is a hack to get the root of the workspace. TODO: This should +# be removed when cargo implements this. See Kani-side tracking issue +# is https://github.com/model-checking/kani/issues/1472 for details. CARGO_WORKSPACE_DIR = { value = "", relative = true } diff --git a/docs/src/tutorial/first-steps-v1/Cargo.toml b/docs/src/tutorial/first-steps-v1/Cargo.toml index 5cdeac3f462d..812eec5b2bb0 100644 --- a/docs/src/tutorial/first-steps-v1/Cargo.toml +++ b/docs/src/tutorial/first-steps-v1/Cargo.toml @@ -8,7 +8,8 @@ edition = "2018" [dependencies] # Turned off while proptest integration is merging. The first PR will -# not support any integers, which crashes this test case. +# not support any integers, which crashes this test case. See +# https://github.com/model-checking/kani/issues/1473 for details. # [dev-dependencies] # proptest = "1.0.0" diff --git a/docs/src/tutorial/first-steps-v2/Cargo.toml b/docs/src/tutorial/first-steps-v2/Cargo.toml index accfe4b42ee6..3837ced9aa7b 100644 --- a/docs/src/tutorial/first-steps-v2/Cargo.toml +++ b/docs/src/tutorial/first-steps-v2/Cargo.toml @@ -8,7 +8,8 @@ edition = "2018" [dependencies] # Turned off while proptest integration is merging. The first PR will -# not support any integers, which crashes this test case. +# not support any integers, which crashes this test case. See +# https://github.com/model-checking/kani/issues/1473 for details. # [dev-dependencies] # proptest = "1.0.0" diff --git a/library/proptest/src/lib.rs b/library/proptest/src/lib.rs index 3ea1fd14313a..0ad5cff45ca3 100644 --- a/library/proptest/src/lib.rs +++ b/library/proptest/src/lib.rs @@ -36,7 +36,8 @@ #![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(core_intrinsics))] // TODO: Implement support for more features. They are commented out -// for now. +// for now. See https://github.com/model-checking/kani/issues/1473 for +// more details. // std_facade is used in a few macros, so it needs to be public. // #[macro_use] diff --git a/library/proptest/src/strategy/just.rs b/library/proptest/src/strategy/just.rs index 83af8557ba5e..a2dac4baa00f 100644 --- a/library/proptest/src/strategy/just.rs +++ b/library/proptest/src/strategy/just.rs @@ -126,8 +126,6 @@ impl T> fmt::Debug for LazyJust { // Any `fn () -> T` is a Strategy //============================================================================== -// TODO: try 'F: Fn () -> T' instead when we've got specialization. - impl Strategy for fn() -> T { type Tree = Self; type Value = T; diff --git a/library/proptest/src/strategy/mod.rs b/library/proptest/src/strategy/mod.rs index 01f356ac34ef..400dc2461383 100644 --- a/library/proptest/src/strategy/mod.rs +++ b/library/proptest/src/strategy/mod.rs @@ -14,7 +14,9 @@ //! Defines the core traits used by Proptest. -// TODO: support more strategy operations. +// TODO: support more strategy operations. See +// https://github.com/model-checking/kani/issues/1473 for more +// details. // mod filter; // mod filter_map; diff --git a/library/proptest/src/strategy/traits.rs b/library/proptest/src/strategy/traits.rs index 55f552fc8815..77b85ae2b466 100644 --- a/library/proptest/src/strategy/traits.rs +++ b/library/proptest/src/strategy/traits.rs @@ -68,7 +68,9 @@ pub trait Strategy: fmt::Debug { /// generate the test case. fn new_tree(&self, runner: &mut TestRunner) -> NewTree; - // TODO: Implement more complex strategy compositions. + // TODO: Implement more complex strategy compositions. See + // https://github.com/model-checking/kani/issues/1473 for more + // details. // /// Returns a strategy which produces values transformed by the function // /// `fun`. diff --git a/tests/cargo-kani/rectangle-example/Cargo.toml b/tests/cargo-kani/rectangle-example/Cargo.toml index 0d939f44c30f..df05e35fe90c 100644 --- a/tests/cargo-kani/rectangle-example/Cargo.toml +++ b/tests/cargo-kani/rectangle-example/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] # Turned off while proptest integration is merging. The first PR will -# not support any integers, which crashes this test case. +# not support any integers, which crashes this test case. See +# https://github.com/model-checking/kani/issues/1473 for details. # [dev-dependencies] # proptest = "1.0.0" From b835517aef9230827e606e92ac6d0e4929141d89 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 8 Aug 2022 16:52:47 -0400 Subject: [PATCH 71/80] Moved to using paths rather than string concat. --- kani-compiler/build.rs | 11 ++++++++--- kani-driver/build.rs | 17 +++++++++++++++-- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/kani-compiler/build.rs b/kani-compiler/build.rs index 4cdef48c5c4f..6b96b4d467a4 100644 --- a/kani-compiler/build.rs +++ b/kani-compiler/build.rs @@ -69,8 +69,13 @@ pub fn main() { println!("cargo:rustc-env=KANI_LIB_PATH={}", lib_out); println!("cargo:rustc-env=TARGET={}", target); println!( - "cargo:rustc-env=KANI_EXTERN_OUT_DIR={}/target/{}/debug/deps", - env::var("CARGO_WORKSPACE_DIR").unwrap(), - target + "cargo:rustc-env=KANI_EXTERN_OUT_DIR={}", + path_str!([ + env::var("CARGO_WORKSPACE_DIR").unwrap().as_ref(), + "target", + target.as_ref(), + "debug", + "deps" + ]), ); } diff --git a/kani-driver/build.rs b/kani-driver/build.rs index f327aead308e..edae285497bd 100644 --- a/kani-driver/build.rs +++ b/kani-driver/build.rs @@ -2,6 +2,19 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT use std::env::var; +use std::path::PathBuf; + +macro_rules! path_str { + ($input:expr) => { + String::from( + $input + .iter() + .collect::() + .to_str() + .unwrap_or_else(|| panic!("Invalid path {}", stringify!($input))), + ) + }; +} fn main() { // We want to know what target triple we were built with, but this isn't normally provided to us. @@ -12,8 +25,8 @@ fn main() { let target_arch = var("TARGET").unwrap(); let workspace_root = var("CARGO_WORKSPACE_DIR").unwrap(); println!( - "cargo:rustc-env=KANI_EXTERN_OUT_DIR={}/target/{}/debug/deps", - workspace_root, &target_arch + "cargo:rustc-env=KANI_EXTERN_OUT_DIR={}", + path_str!([workspace_root.as_ref(), "target", target_arch.as_ref(), "debug", "deps"]), ); println!("cargo:rustc-env=TARGET={}", &target_arch); } From dbcbd2ab5736692b6446cfad65cb82d820166953 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 8 Aug 2022 19:29:31 -0400 Subject: [PATCH 72/80] Made search for symtab more specific. --- scripts/refresh-kani-proptest.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/refresh-kani-proptest.sh b/scripts/refresh-kani-proptest.sh index 5f0786f9aef2..736457d6d2f4 100755 --- a/scripts/refresh-kani-proptest.sh +++ b/scripts/refresh-kani-proptest.sh @@ -11,7 +11,7 @@ SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) KANI_REPO_ROOT="$SCRIPT_DIR/.." -PROPTEST_SYMTAB_PATH="$(find $KANI_REPO_ROOT/target -name '*symtab.json' | head -1)" +PROPTEST_SYMTAB_PATH="$(find $KANI_REPO_ROOT/target -name 'proptest-*symtab.json' | head -1)" PROPTEST_RLIB_PATH="$KANI_REPO_ROOT/target/debug/libproptest.rlib" if [ ! -f "$PROPTEST_SYMTAB_PATH" ] || [[ "$PROPTEST_SYMTAB_PATH" -ot "$PROPTEST_RLIB_PATH" ]]; then From 3b0f4751eb7f9b3a45c0327c8c0ac6fd971fb0aa Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 8 Aug 2022 20:11:05 -0400 Subject: [PATCH 73/80] Set `-eu` like other scripts. --- scripts/refresh-kani-proptest.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/refresh-kani-proptest.sh b/scripts/refresh-kani-proptest.sh index 736457d6d2f4..63e5129773e9 100755 --- a/scripts/refresh-kani-proptest.sh +++ b/scripts/refresh-kani-proptest.sh @@ -8,6 +8,8 @@ # to called manually, but rather from `scripts/kani` and # `scripts/cargo-kani`. +set -eu + SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) KANI_REPO_ROOT="$SCRIPT_DIR/.." @@ -18,7 +20,7 @@ if [ ! -f "$PROPTEST_SYMTAB_PATH" ] || [[ "$PROPTEST_SYMTAB_PATH" -ot "$PROPTEST echo 'Proptest symtab not found or too old. (Re)compiling proptest..' ( cd $KANI_REPO_ROOT/library/proptest; - export CARGO_KANI_IS_CHILD=1 + export CARGO_KANI_IS_CHILD=1; cargo kani --only-codegen; ) fi From bcebad63024b63760975399dbf02bf46cdbaa82f Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 8 Aug 2022 20:17:02 -0400 Subject: [PATCH 74/80] Moved to using `tomlq` wrapper around jq. Both installed. --- .github/workflows/format-check.yml | 4 ---- scripts/cargo-kani | 13 ++++++------- scripts/setup/macos/install_deps.sh | 2 ++ scripts/setup/ubuntu/install_deps.sh | 2 ++ 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/.github/workflows/format-check.yml b/.github/workflows/format-check.yml index e3f0d9ff5515..beaeb5bbf6dd 100644 --- a/.github/workflows/format-check.yml +++ b/.github/workflows/format-check.yml @@ -32,10 +32,6 @@ jobs: with: os: ubuntu-20.04 - - name: "Install jq for parsing." - run: | - sudo apt-get install -y jq - - name: "Run Clippy" run: | cargo clippy --all -- -D warnings diff --git a/scripts/cargo-kani b/scripts/cargo-kani index 152c0d64551f..fabec97afa0c 100755 --- a/scripts/cargo-kani +++ b/scripts/cargo-kani @@ -21,16 +21,15 @@ KANI_PATH=${KANI_CANDIDATES[0]} # if the crate uses proptest, get ready to run that. Make sure local # proptest import and kani's proptest does not clash. -if grep '^proptest\s*=' Cargo.toml > /dev/null; then - if grep -F "[target.'cfg(not(kani))'.dependencies]" Cargo.toml > /dev/null \ - && [ -z "${CARGO_KANI_IS_CHILD+x}" ]; then +if tomlq '.target."cfg(not(kani))".dependencies.proptest' Cargo.toml > /dev/null; then + if [ -z "${CARGO_KANI_IS_CHILD+x}" ]; then $SCRIPT_DIR/refresh-kani-proptest.sh export IS_KANI_PROPTEST=1 - else - echo "Clashing import of proptest. Stopping cargo kani." - echo "Please put your proptest import under [target.'cfg(not(kani))'.dependencies]" - exit 1 fi +else + echo "Clashing import of proptest. Stopping cargo kani." + echo "Please put your proptest import under [target.'cfg(not(kani))'.dependencies]" + exit 1 fi exec -a cargo-kani "${KANI_PATH}" "$@" diff --git a/scripts/setup/macos/install_deps.sh b/scripts/setup/macos/install_deps.sh index 0484b83e1db8..9bedc446e544 100755 --- a/scripts/setup/macos/install_deps.sh +++ b/scripts/setup/macos/install_deps.sh @@ -16,6 +16,8 @@ brew install universal-ctags wget PYTHON_DEPS=( autopep8 colorama # Used for introducing colors into terminal output + tomlq # used by the proptest feature for detecting Cargo.toml structure + jq # needs jq as dependency ) python3 -m pip install "${PYTHON_DEPS[@]}" diff --git a/scripts/setup/ubuntu/install_deps.sh b/scripts/setup/ubuntu/install_deps.sh index 7a6269aecdfa..3a8a1c6acb0d 100755 --- a/scripts/setup/ubuntu/install_deps.sh +++ b/scripts/setup/ubuntu/install_deps.sh @@ -26,6 +26,8 @@ DEPS=( wget zlib1g zlib1g-dev + tomlq # used by the proptest feature for detecting Cargo.toml structure + jq # needs jq as dependency ) # Version specific dependencies. From 4e4b0e5926277516110b5c1f9cea66d794336add Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 8 Aug 2022 20:30:36 -0400 Subject: [PATCH 75/80] Fixed typo. --- kani-driver/src/call_cargo.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kani-driver/src/call_cargo.rs b/kani-driver/src/call_cargo.rs index 0f125e0832c4..5113664770aa 100644 --- a/kani-driver/src/call_cargo.rs +++ b/kani-driver/src/call_cargo.rs @@ -85,7 +85,7 @@ impl KaniSession { let mut symtabs = glob(&outdir.join("*.symtab.json"))?; let mut metadata = glob(&outdir.join("*.kani-metadata.json"))?; if std::env::var("IS_KANI_PROPTEST").is_ok() { - // if the "proptests is precent" flag is enabled by cargo-kani + // if the "proptests is present" flag is enabled by cargo-kani symtabs.extend(glob(&kani_extern_lib_path.join("*.symtab.json"))?); metadata.extend(glob(&outdir.join("*.kani-metadata.json"))?); } From 1a549a4859ce6fa5bf53b5ea81c3e36a9a655b72 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 8 Aug 2022 20:50:59 -0400 Subject: [PATCH 76/80] Added docs. --- docs/src/dev-documentation.md | 1 + docs/src/proptest.md | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 docs/src/proptest.md diff --git a/docs/src/dev-documentation.md b/docs/src/dev-documentation.md index d480c4340d19..25e684f490dc 100644 --- a/docs/src/dev-documentation.md +++ b/docs/src/dev-documentation.md @@ -13,6 +13,7 @@ developers (including external contributors): 2. [Useful command-line instructions for Kani/CBMC/Git](./cheat-sheets.md). 3. [Development setup recommendations for working with `rustc`](./rustc-hacks.md). 4. [Guide for testing in Kani](./testing.md). + 5. [(Experimental) Running Proptests with Kani](./proptest.md). > **NOTE**: The developer documentation is intended for Kani developers and not users. At present, the project is under heavy development and some items diff --git a/docs/src/proptest.md b/docs/src/proptest.md new file mode 100644 index 000000000000..2ad1087973b7 --- /dev/null +++ b/docs/src/proptest.md @@ -0,0 +1,25 @@ +# (Experimental) Running Proptests with Kani + +**NOTE** This feature is purely experimental, and we do not guarentee +any support. Furthermore, many features that are implemented in +`proptest` are missing and your proptests may not compile. + +An experimental feature allows Kani to run Property-Based Tests +written using the [proptest](https://crates.io/crates/proptest) +crate. This feature is supported only for `cargo kani`. + +No special annotations are required, but you do need to adjust +`Cargo.toml` so that the proptest import does not conflict with the +one provided by kani. The easiest way to do this will be to put the +proptest import under `[target.'cfg(not(kani))'.dependencies]`. + +### Under the Hood: How Kani's `proptest` feature works. + +Under the hood, the `proptest` feature works hijacking the import of +the proptest library. This is achieved by with 2 components +1. Proptest proptest import `[target.'cfg(not(kani))'.dependencies]` + makes the original import invisible to Kani, which runs the + configuration parameter `kani`. +2. Add in our custom proptest through `-L` and `--extern` while making + sure to link `proptest` symtabs by adding them to the glob in + `kani-driver/src/call_cargo.rs` From ab9922d11997c073ab685212a658b773e2bb4da3 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 8 Aug 2022 20:55:24 -0400 Subject: [PATCH 77/80] Fixed dependency install after ci broke. --- scripts/setup/ubuntu/install_deps.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/setup/ubuntu/install_deps.sh b/scripts/setup/ubuntu/install_deps.sh index 3a8a1c6acb0d..3dbf8ec909ee 100755 --- a/scripts/setup/ubuntu/install_deps.sh +++ b/scripts/setup/ubuntu/install_deps.sh @@ -26,8 +26,6 @@ DEPS=( wget zlib1g zlib1g-dev - tomlq # used by the proptest feature for detecting Cargo.toml structure - jq # needs jq as dependency ) # Version specific dependencies. @@ -52,6 +50,8 @@ sudo DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends --ye PYTHON_DEPS=( autopep8 colorama # Used for introducing colors into terminal output + tomlq # used by the proptest feature for detecting Cargo.toml structure + jq # needs jq as dependency ) python3 -m pip install "${PYTHON_DEPS[@]}" From fa80a275343bd8323c91f64bcc6585061ddfe4d0 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 8 Aug 2022 22:41:21 -0400 Subject: [PATCH 78/80] Fixed cargo kani misclassifying proptest cases. --- scripts/cargo-kani | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/scripts/cargo-kani b/scripts/cargo-kani index fabec97afa0c..219fb57235e0 100755 --- a/scripts/cargo-kani +++ b/scripts/cargo-kani @@ -21,12 +21,20 @@ KANI_PATH=${KANI_CANDIDATES[0]} # if the crate uses proptest, get ready to run that. Make sure local # proptest import and kani's proptest does not clash. -if tomlq '.target."cfg(not(kani))".dependencies.proptest' Cargo.toml > /dev/null; then +function has-direct-proptest-import() { + (tomlq -e '.dev-dependencies.proptest' Cargo.toml || + tomlq -e '.dependencies.proptest' Cargo.toml) &> /dev/null +} +function has-kani-escaped-proptest-import() { + (tomlq -e '.target."cfg(not(kani))".dev-dependencies.proptest' Cargo.toml || + tomlq -e '.target."cfg(not(kani))".dependencies.proptest' Cargo.toml) &> /dev/null +} +if has-kani-escaped-proptest-import; then if [ -z "${CARGO_KANI_IS_CHILD+x}" ]; then $SCRIPT_DIR/refresh-kani-proptest.sh export IS_KANI_PROPTEST=1 fi -else +elif has-direct-proptest-import; then echo "Clashing import of proptest. Stopping cargo kani." echo "Please put your proptest import under [target.'cfg(not(kani))'.dependencies]" exit 1 From 44a40742a9b13887ef14666a41a6e7269048127f Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Mon, 8 Aug 2022 23:01:10 -0400 Subject: [PATCH 79/80] Purged unneeded refresh. --- scripts/kani-regression.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/kani-regression.sh b/scripts/kani-regression.sh index dcd8d901b92a..90c0e84858d1 100755 --- a/scripts/kani-regression.sh +++ b/scripts/kani-regression.sh @@ -30,7 +30,6 @@ PYTHONPATH=${SCRIPT_DIR} python3 -m unittest ${SCRIPT_DIR}/test_cbmc_json_parser # Build all packages in the workspace cargo build --workspace -${SCRIPT_DIR}/refresh-kani-proptest.sh # Unit tests cargo test -p cprover_bindings From 526538cd38b663695fdb3f7d35341792904a8d92 Mon Sep 17 00:00:00 2001 From: Yoshi Takashima Date: Tue, 9 Aug 2022 08:36:05 -0400 Subject: [PATCH 80/80] Fixed clippy warning regarding derived traits. --- library/proptest/src/test_runner/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/proptest/src/test_runner/config.rs b/library/proptest/src/test_runner/config.rs index 589b6551387c..ea634c323ddc 100644 --- a/library/proptest/src/test_runner/config.rs +++ b/library/proptest/src/test_runner/config.rs @@ -31,7 +31,7 @@ fn default_default_config() -> Config { // defaults. /// Configuration for how a proptest test should be run. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Config { /// The number of successful test cases that must execute for the test as a /// whole to pass.