proptest-1.6.0/.cargo_vcs_info.json0000644000000001460000000000100127210ustar { "git": { "sha1": "e5b6c65be5cefc830cb92f48d94382f36b704284" }, "path_in_vcs": "proptest" }proptest-1.6.0/CHANGELOG.md000064400000000000000000001075251046102023000133330ustar 00000000000000## Unreleased ## 1.6.0 ### New Features - Added `handle-panics` feature which enables catching panics raised in tests and turning them into failures. ([\#525](https://github.com/proptest-rs/proptest/pull/525)) - Exit early if shrink disabled. ([\#520](https://github.com/proptest-rs/proptest/pull/520)) - Add `Config::with_failure_persistence`. A convenience constructor making use of a generic parameter over `FailurePersistence` impls and hiding the `Some(Box::new(...))`. ([\#508](https://github.com/proptest-rs/proptest/pull/508)) - Add From's for SizeRange and Probability. ([\#498]([https://github.com/proptest-rs/proptest/pull/498)) - When running persisted regressions, the most recently added regression is now run first. ([\#496](https://github.com/proptest-rs/proptest/pull/496])) ### Bug Fixes - Fix WebAssembly support. Hides a few paths, that fail at runtime on wasm32-unknown-unknown, under conditional compilation. \([#519](https://github.com/proptest-rs/proptest/pull/519)) - Fix incorrectly reading environment configuration. Previously controlling proptest configuration via env vars was not properly applied. This caused vars like `PROPTEST_MAX_DEFAULT_SIZE_RANGE` to be not be properly applied, leading to unexpected behavior. ([\#457](https://github.com/proptest-rs/proptest/pull/457)) - Allow trailing comma in prop_assert_eq/ne like std. ([\#510](https://github.com/proptest-rs/proptest/pull/510)) ### Other Notes - Add `no_std` to `alloc` contexts. `no_std` must be used explicitly with `alloc`. Updated CI and documentation to reflect this. ([\#528](https://github.com/proptest-rs/proptest/pull/528)) - Make `libm` optional in a `std` environment. ([\#524](https://github.com/proptest-rs/proptest/pull/524)) - Update `bit-set` and `bit-vec` to `0.8.0`. ([\#501](https://github.com/proptest-rs/proptest/pull/501)) - Removed unused `frunk` feature. ([\#498](https://github.com/proptest-rs/proptest/pull/498)) ## 1.5.0 ### New Features - Setting `PROPTEST_MAX_DEFAULT_SIZE_RANGE` now customizes the default `SizeRange` used by the default strategies for collections (like `Vec`). The default remains 100. - Empty ranges panic during tree creation instead of during sampling. ### Documentation - Reference the derive macro in Arbitrary's documentation - Fix broken links in the book ### Bug Fixes - Fixed issue where config contextualization would clobber existing failure persistence config ## 1.4.0 ### Breaking Changes - The minimum supported Rust version has been increased to 1.65.0. ### Other Notes - `regex-syntax` updated from 0.7 to 0.8 - Fixed new clippies - Fixed nightly build where Generator was renamed to Coroutine ## 1.3.1 ### Other Notes - `bit-set` updated from 0.5.0 to 0.5.2 to ensure minimum compatible version with bit-vec 0.6 ## 1.3.0 ### Breaking Changes - The minimum supported Rust version has been increased to 1.64.0. ### New Features - Adds Arbitrary impl for PathBuf - Permit use of (?-u) in byte-regex strategies, allowing non-utf-8 bytes to be generated ### Book - Various small fixes -- typos, formatting - Removal of custom theme - Add book page for Tips and Best Practices ### Other Notes - `regex-syntax` version 0.7 is now used. - Print a seed to stderr for a failed test even when a regressions file is already present. - Fixed a performance issue with `VarBitSet::saturated` that can slow down `VecStrategy` - Remove use of rust feature `core_intrinsics` - Remove no longer needed "break-dead-code" feature - Disable `clippy::arc_with_non_send_sync` - Remove dependency on `byteorder` ## 1.2.0 ### Breaking Changes - `PROPTEST_` environment variables now take precedence over tests' non-default configuration. ### Bug Fixes - Don't implement Arbitrary for NonZeroU128 and NonZeroI128 on wasm targets where u128 and i128 Arbitrary impls don't exist ### New Features ### Other Notes - Minimal failing input is now printed using debug pretty-printing - Made public `VarBitSet`, `SizeRange` read-only methods and num sampling functions in preparation for release of a `proptest-state-machine` crate. - Removed dependency on `quick_error` - Start publishing MSRV ## 1.1.0 ### Bug Fixes - Sampling from large ranges of floats such as `(0f32)..` no longer panics with newer versions of the `rand` crate - [dependencies.x86] was bumped to latest current version. x86 crate does was on a very old version 0.33.0 which used a removed macro from rust. - The calculation for the arbitrary impl of Layout was using a max_size that was too large and overflowing Layout. This has been fixed. - Test for arbitrary AllocError was referring to AllocErr which does not exist, this was fixed. - NoneError has been removed from rust so it was subsequently removed from proptest. It was blocking compilation. evidence: https://github.com/rust-lang/rust/issues/85614 - `try_reserve` is stable so removed from unstable features - `try_trait` has been changed to `try_trait_v2` so that was adjusted in `Cargo.toml`. - `prop_assert_ne!` now uses fully qualified `prop_assert_eq!` - Persisted tests are not counted against the number of cases to run ### New Features - Add `Arbitrary` impls for arrays of all sizes using const generics - Add `Arbitrary` impls for `core::num::NonZero*` - Adds ability to disable failure persistence via env var `PROPTEST_DISABLE_FAILURE_PERSISTENCE` ### Other Notes - `proptest` no longer depends on the `quick-error` crate. ## 1.0.0 ### Breaking Changes - The minimum supported Rust version has been increased to 1.50.0. - The version of the `rand` crate has been increased to 0.8. - Due to changes in the `getrandom` crate, if you wish to use proptest on the `wasm32-unknown-unknown` target, you must manually add a dependency on that crate and enable a feature that will allow it to work. Refer to the `getrandom` crate documentation for more information. ### Bug Fixes - `prop_shuffle()` can now produce all permutations. ### New Features - Tuple strategies up to 12 elements are now supported, for parity with the blanket implementations that `std` provides. ## 0.10.1 ### New Features - Added `RngAlgorithm::Recorder` and supporting APIs which allow capturing random data generated as part of generating a value or running a test. ## 0.10.0 ### Breaking Changes - The version of the `rand` crate has been increased to 0.7. - The `proptest!` macro no longer accepts function bodies which implicitly return a value (which would then be discarded). - The `TupleUnion` implementation in `proptest` 0.9 has been removed and replaced with `LazyTupleUnion`. `prop_oneof!` is unaffected and continues to be the recommended way to build a union of strategies. ### New Features - Enabling the `hardware-rng` optional dependency (disabled by default) allows obtaining non-deterministic random seeds even in `no_std` environments provided the architecture is x86 or AMD64. - Added missing `?Sized` bound to `B` on the implementation of `Arbitrary` for `std::borrow::Cow<'_, B>`. ### Bug Fixes - `prop_assert!` and `prop_assume!` should now be usable in `no_std` environments. ### Other Notes - `rusty_fork` has been bumped to 0.3.0, which adds support for a number of [new test flags](https://github.com/AltSysrq/rusty-fork/blob/master/CHANGELOG.md#improvements) when running forked tests. - The `PassThrough` RNG algorithm now returns 0 instead of panicking when it runs out of entropy. ## 0.9.6 ### Bug Fixes - Fixed [#186](https://github.com/proptest-rs/proptest/issues/186), a Rust future-compatibility issue. ## 0.9.5 ### Bug Fixes - Fixed a Rust future-compatibility issue (https://github.com/rust-lang/rust/pull/65819). ### New Additions ## 0.9.4 ### Bug Fixes - The `unstable` feature one again works against the latest nightly. ### Performance Improvements - Unions and the `prop_oneof!` combinator now generate value trees lazily. In previous versions of `proptest`, if a value tree for a union variant was generated, so would value trees for earlier variants -- as a result, union value tree generation was linear in the number of variants. In `proptest` 0.9.4 and above, value trees are only generated for union variants that are picked. Union value tree generation is now independent of the number of variants. ### Deprecations - `TupleUnion` has been deprecated, and its implementation will be replaced by `LazyTupleUnion`'s in 0.10.0. ### Other Notes - The return type of `prop_oneof!` has changed from `TupleUnion` to `LazyTupleUnion`. `prop_oneof!`'s return type is documented to not be stable, and that continues to be the case. - Shrinking is now limited to four times as many iterations as configured number of test cases by default. - `prop_assert_eq!` and `prop_assert_ne!` produce output more similar to the `assert_eq!` and `assert_ne!` macros. This should also make it easier to visually parse out the source location in the resulting messages. ## 0.9.3 This is a minor release to correct some packaging errors. The license files are now included in the files published to crates.io, and some unneeded files are now excluded. ## 0.9.2 ### New Additions - Closures generated by `prop_compose!` are now `move`. This is not expected to cause any breakage since there is no way to successfully use a borrowing closure with that macro. - There is now **highly experimental** support for building on Web Assembly. Refer to [the Proptest book](https://altsysrq.github.io/proptest-book/proptest/wasm.html) for build instructions. ### Other Notes - Using proptest with the default `std` feature enabled, the `spin` crate is no longer brought in as a dependency. - Using proptest with the `std` feature disabled, neither `spin` nor `lazy_static` are brought in as dependencies. ## 0.9.1 ### New RNG Algorithm Starting in this version, the default RNG algorithm has been changed from XorShift to ChaCha since it produces higher-quality randomness. This may make test case generation a bit slower but it avoids certain pathological cases that the old generator had. The old algorithm is still supported, and is used automatically when reading old failure persistence files. Note that this change also affects the internal representation of RNG seeds, which affects the `FailurePersistence` trait which previously only supported the seed representation for XorShift. This release maintains source compatibility with 0.9.0 by providing defaults for the new methods which delegate (when possible) to the old ones, but be aware that custom failure persistence implementations using the old API will not function when using an RNG other than XorShift. To keep using the old algorithm, you can set the environment variable `PROPTEST_RNG_ALGORITHM` to `xs` or set `Config.rng_algorithm` to `RngAlgorithm::XorShift` in code. Besides ChaCha, this version also adds a `PassThrough` RNG "algorithm" which makes it possible to use an external source of entropy with Proptest. ### New Additions - `TestRng` instances can be created with the `from_seed` function. - `TestRunner` instances can be created with user-provided `TestRng`s. - `TestRunner` now has a `deterministic()` constructor which uses the same RNG every time, to facilitate doing statistical tests on strategy outputs. - There is now a work-around for a [compiler bug](https://github.com/rust-lang/rust/issues/52478) which prevents building with `-C link-dead-code`. Please see this issue for details: https://github.com/proptest-rs/proptest/issues/124 ### Deprecations - The `load_persisted_failures` and `save_persisted_failure` methods on the `FailurePersistence` trait have been deprecated and will be removed in 0.10.0. ## 0.9.0 ### Breaking Changes - The minimum Rust version has been increased to 1.32.0. - The version of the `rand` crate has been increased to 0.6. - The `ValueFor` type alias (deprecated in 0.8.0) has been removed. Replace `ValueFor` with `S::Value` or `::Value` as necessary. - `From` implementations converting a `SizeRange` back to various std types have been removed since they were of limited utility and had unclear or incorrect conversion properties. - Many optional elements (such as trailing commas or function visibility modifiers) in certain macros could be specified more than once. The macros now accept at most one occurrence. - Visibility modifiers inside `prop_compose` must no longer be enclosed in brackets. Unless other modifiers (e.g., `unsafe`) are also in use, simply removing the brackets is sufficient. ### New Additions - Rust 2018 style macro imports are now supported. - In a Rust 2018 crate, all the macros can be brought into scope with `import proptest::prelude::*;`. - The proptest macros now accept trailing commas in more locations. - Visibility modifiers can now be passed to `prop_compose!` without enclosing them in brackets. Unfortunately, the old way could not continue to be supported due to the way the `vis` macro matcher works. ### Nightly-only breakage - The `nightly` feature, which was formerly required for using proptest with `#[no_std]`, has been removed. References to the feature can simply be deleted. - When using the `unstable` feature and setting `default-features = false`, the `AtomicI64` and `AtomicU64` types are not supported unless the `atomic64bit` feature is enabled. This supports `no_std` usage on platforms which do not support atomic 64-bit operations. ### Other Notes - Generated strings are now much more likely to contain right-to-left override characters. - Most of the crate-level documentation has been relocated to the [Proptest Book](https://altsysrq.github.io/proptest-book/proptest/index.html). ## 0.8.7 ### New Additions - Add `max_shrink_iters` and `max_shrink_time` options to test configuration to allow capping the resources expended on shrinking test cases. - Add `verbose` option to make proptest give details about what is happening as the test executes. - When a failure is saved to the persistence file, the message now also includes the seed that was saved so that it can manually be added to the appropriate file should the test have run somewhere where the updated file is not accessible (for example, on a CI system). ### Bug Fixes - `any::()` now generates random values centred on the UNIX epoch rather than always producing the current time. ### Other Notes - When using forking, proptest will now detect conditions which cause the child process to crash without running any tests, and will fail quickly instead of respawning child processes. ## 0.8.6 ### New Additions - `Vec where S: Strategy` is now itself a `Strategy` for producing fixed-size `Vec`s whose values are derived from the respective strategies. - It is now possible to configure the test runner to cache test results to avoid spending time running identical tests. See `Config.result_cache`. - Add `sample::Index`, a type for generating indices into runtime-sized slices and vectors. - Add `sample::Selector`, a type for picking items out of dynamically-created iterables. ### Bug Fixes - Fix panic when using `sample::subsequence` with an empty vector. - Fix panic when using `sample::subsequence` with a size equal to the size of the input vector. - Fix sampled bitset strategies on integers not allowing to generate exactly the same number of bits as the integer is wide. ### Other Notes - Passing empty size ranges to functions requiring a non-empty size range now panic with an explicit message immediately rather than causing an arithmetic error when generating input values. - There were a few cases where proptest would accept a `SizeRange` with an inclusive maximum value of `usize::MAX`. Size ranges are now always clamped to `usize::MAX - 1`. ## 0.8.5 ### Bug Fixes - Fix build when nightly features are enabled. ## 0.8.4 ### Bug Fixes - Nightly and no_std support work against latest nightly once again. ### New Additions - Added `bits::bool_vec` for generating `Vec` as a bit set. ### Nightly-only breakage - `impl Arbitrary for CollectionAllocErr` is temporarily removed pending it being available outside the `alloc` crate again. - `bits::bitset` is no longer available without the `bit-set` feature (enabled by default), which is [not compatible with `#[no_std]` environments](https://github.com/contain-rs/bit-vec/pull/51). ## 0.8.3 ### Bug Fixes - Fix that regex-based string generation could transpose the order of a literal and a non-literal component. ## 0.8.2 ### New Additions - Macros which previously accepted `pattern in strategy` syntax to specify arguments now also accept `pattern: type` syntax as shorthand for `pattern in any::()`. - Closure-style `proptest!` invocation no longer requires the body to use block syntax. - Closure-style `proptest!` invocation now accepts custom configurations. ## 0.8.1 ### New Additions - `proptest!` now has form that accepts a closure. See the documentation for the macro for more details. ### Bug Fixes - Fix spurious warning about corrupt regression files. The files were not corrupt but the parser was failing to handle the blank line at the end. - The `multiplex_alloc!` and `multiplex_core!` macros which were unintentionally exported in 0.8.0 are no longer exported. This is not considered a breaking change since they were not supposed to be accessible, and in any case would not have expanded into valid code in most other crates. ## 0.8.0 ### New Additions - A combinator `.prop_filter_map` has been added to `Strategy`. It is similar to `.filter_map` for `Iterator` in that it is the combination of `.prop_filter` and `.prop_map`. - `i128` and `u128` are now supported without any feature flags and on stable. - More implementations of `Arbitrary` are supported for `alloc` + `no_std` users. - `size_range` now accepts inclusive ranges of form `low..=high` and `..=high`. Thus, you can construct a `vec` strategy as: `vec(elt_strategy, low..=high)` and `vec(elt_strategy, ..=high)`. This also applies to other functions accepting `Into`. - `..= high` is now a valid strategy. Please note that `..= 1` will naturally include numbers lower than `0` for sized types. - `low..=high` is also a valid strategy. - `Arbitrary` is implemented for `RangeInclusive`, `RangeToInclusive`, and `DecodeUtf16` on stable. - Bitset strategies and `subsequence` now accept all range syntaxes. ### Bug Fixes - Fix a race condition where a test failing due to running ever so slightly over the set timeout could cause the test harness to converge to the incorrect failing value, a non-failing value, or panic. ### Deprecations - The type alias `ValueFor` is now deprecated and will be removed in version 0.9. You should just use `S::Value` instead. ### Breaking changes - A minimum version of 1.27 of Rust is now required. - `regex-syntax` version 0.6 is now used. - `rand` version 0.5 is now used. - As a consequence, the `FailurePersistence` trait will now use `[u8; 16]` seeds instead of `[u32; 4]`. However, the stored failure persistence files using the default `FileFailurePersistence` will still use `[u32; 4]` so your old failure persistence files should still work. - The RNG used by proptest has been changed to a PRNG `TestRng` which proptest exposes. This is currently a simple new-type wrapper around `XorShiftRng`. In the future, this will give us more freedom to make changes without breakage. - The feature flag `i128_support` has been removed. The features it added are now always supported. - The associated type `Value` of `Strategy` has been renamed to `Tree`. A new associated type `Value` has been added to `Strategy` which always refers to the same type as `::Value` for some strategy `S`. This change allows you to write `-> impl Strategy` for functions returning a `Strategy` generating `T`s. This is more ergonomic to use than `-> impl Strategy>`. - The method `new_value` in `Strategy` has been renamed to `new_tree` to mirror the renaming of `Value` to `Tree`. - As a consequence change, the associated type `ValueTree` has been removed from `Arbitrary`. - The methods `run` and `run_one` on `TestRunner` now takes a function-under-test that accepts the generated type by value instead of by reference instead. This means that you don't need to write `ref value in my_strategy` and can write `value in my_strategy` instead even if `typeof(value)` doesn't implement `Copy`. This is also a step in the direction of allowing strategies to generate references when generic associated types (GATs) land. However, `ref value in my_strategy` will still be accepted, so not a lot of breakage should come of this if you've used `proptest! { .. }`. - `prop_compose!` no longer applies `.boxed()` to the strategy produced. Therefore, `-> BoxedStrategy` is no longer the correct type. The new return type is `-> impl Strategy`. If you want the old behaviour, you can use `.boxed()` yourself. - `Arbitrary` for `SizeRange` changed its associated type to use `RangeInclusive`. Same applies for `CString`. - Many APIs now use `impl Trait` in argument position, which could affect code using turbofishes to specify types explicitly. - `char` APIs which formerly represented a range as `(start, end)` now require `start..=end`. ### Nightly-only breakage - As `std::io::{Chars, CharsError}` have been deprecated on nightly, their `Arbitrary` implementations have been removed. ## 0.7.2 ### Bug Fixes - Fix that `bool` would not shrink correctly, leading to hangs when tests taking `bool` parameters would fail in certain circumstances. ## 0.7.1 ### New Additions - It is now possible to run test cases in sub-processes. This allows using proptest to test functions which may cause the test process to terminate abruptly, such as by calling `abort()` or even suffering a segmentation fault. This requires the "fork" feature, enabled by default. - Added support for setting a timeout which applies on a per-test-case (i.e., single input rather than the whole test) basis. This allows using proptest to find inputs which cause code to get stuck in infinite loops or exhibit other pathological performance behaviour. This requires the "timeout" feature (and transitively, the "fork" feature), enabled by default. See also [the documentation](README.md#forking-and-timeouts) for these features. ### Bug Fixes - Fix that failure persistence file would be written to the incorrect location in projects using workspaces. See [#24](https://github.com/proptest-rs/proptest/issues/24) for more details and instructions on how to migrate any persistence files that had been written to the wrong location. - Fix a case where `any::()` or `any::()` could panic on Windows. ### Nightly-only breakage - Support for the `hashmap_core` crate is removed pending https://github.com/Amanieu/hashmap_core/issues/3. ## 0.7.0 ### Potential Breaking Changes - The persistence system has been refactored to allow for non-file-system based persistence. `FailurePersistence` is now a trait, and the prior file-based enum which fulfilled that purpose is now called `FileFailurePersistence` and implements the generic trait. The default behavior has not changed. - Reflecting the change to persistence, `Config.failure_persistence` is now of type `Option>`. - The `source_file` used as an optional reference point to the location of the calling test is now tracked on the `Config` struct rather than the `TestRunner`. ### New Additions - Experimental support on nightly for working in `#![no_std]` environments has been added. To use it, one must disable the default-features for proptest and use the new "alloc" and "nightly" features. Currently access to a heap allocator is still required. ## 0.6.0 ### Potential Breaking Changes - There is a small change of breakage if you've relied on `Recursive` using an `Arc>` as `Recursive` now internally uses `BoxedStrategy` instead as well as expecting a `Fn(BoxedStrategy) -> R` instead of `Fn(Arc>) -> R`. In addition, the type of recursive strategies has changed from `Recursive, F>` to just `Recursive`. ### Minor changes - Reduced indirections and heap allocations inside `Recursive` somewhat. - `BoxedStrategy` and `SBoxedStrategy` now use `Arc` internally instead of using `Box`. While this has marginal overhead, it also reduces the overhead in `Recursive`. The upside to this change is also that you can very cheaply clone strategies. - `Filter` is marginally faster. ### Bug Fixes - Removed `impl Arbitrary for LocalKeyState` since `LocalKeyState` no longer exists in the nightly compiler. - Unstable features compile on latest nightly again. ## 0.5.1 ### New Additions - `proptest::strategy::Union` and `proptest::strategy::TupleUnion` now work with weighted strategies even if the sum of the weights overflows a `u32`. - Added `SIGNALING_NAN` strategy to generate signalling NaNs if supported by the platform. Note that this is _not_ included in `ANY`. ### Bug Fixes - Fixed values produced via `prop_recursive()` not shrinking from the recursive to the non-recursive case. - Fix that `QUIET_NAN` would generate signalling NaNs on most platforms on Rust 1.24.0 and later. ## 0.5.0 ### Potential Breaking Changes - There is a small chance of breakage if you've relied on the constraints put on type inference by the closure in `leaf.prop_recursive(..)` having a fixed output type. The output type is now any strategy that generates the same type as `leaf`. This change is intended to make working with recursive types a bit easier as you no longer have to use `.boxed()` inside the closure you pass to `.prop_recursive(..)`. - There is a small chance of breakage wrt. type inference due to the introduction of `SizeRange`. - There is a small chance of breakage wrt. type inference due to the introduction of `Probability`. - `BoxedStrategy` and `SBoxedStrategy` are now newtypes instead of being type aliases. You will only experience breaking changes if you've directly used `.boxed()` and not `(S)BoxedStrategy` but rather `Box>>>`. The probability of breakage is very small, but still possible. The benefit of this change is that calling `.boxed()` or `.sboxed()` twice only boxes once. This can happen in situations where you have functions `Strategy -> BoxedStrategy` or with code generation. - `proptest::char::ANY` has been removed. Any remaining uses must be replaced by `proptest::char::any()`. - `proptest::strategy::Singleton` has been removed. Any remaining uses must be replaced by `proptest::strategy::Just`. ### New Additions - Proptest now has an `Arbitrary` trait in `proptest::arbitrary` and re-exported in the `proptest::prelude`. `Arbitrary` has also been `impl`emented for most of the standard library. The trait provides a mechanism to define a canonical `Strategy` for a given type just like `Arbitrary` in Haskell's QuickCheck. Deriving for this trait will also be provided soon in the crate `proptest_derive`. To use the canonical strategy for a certain type `T`, you can simply use `any::()`. This is the major new addition of this release. - The `any_with`, `arbitrary`, `arbitrary_with` free functions in the module `proptest::arbitrary`. - The `ArbitraryF1` and `ArbitraryF2` traits in `proptest::arbitrary::functor`. These are "higher order" `Arbitrary` traits that correspond to the `Arbitrary1` and `Arbitrary2` type classes in Haskell's QuickCheck. They are mainly provided to support a common set of container-like types in custom deriving self-recursive types in `proptest_derive`. More on this later releases. - The strategies in `proptest::option` and `proptest::result` now accept a type `Probability` which is a wrapper around `f64`. Conversions from types such as `f64` are provided to make the interface ergonomic to use. Users may also use the `proptest::option::prob` function to explicitly construct the type. - The strategies in `proptest::collections` now accept a type `SizeRange` which is a wrapper around `Range`. Conversions from types such as `usize` and `Range` are provided to make the interface ergonomic to use. Users may also use the `proptest::collections::size_bounds` function to explicitly construct the type. - A `.prop_map_into()` operation on all strategies that map using `Into`. This is a clearer and cheaper operation than using `.prop_map(OutputType::from)`. - A nonshrinking `LazyJust` strategy that can be used instead of `Just` when you have non-`Clone` types. - Anything that can be coerced to `fn() -> T` where `T: Debug` is a `Strategy` where `ValueFor T> == T`. This is intended to make it easier to reuse proptest for unit tests with manual input space partition where `fn() -> T` provides fixtures. ### Minor changes - Relaxed the constraints of `btree_map` removing `'static`. - Reduced the heap allocation inside `Recursive` somewhat. ## 0.4.2 ### Bug Fixes - The `unstable` feature now works again. ## 0.4.1 ### New Additions - The `proptest::num::f32` and `proptest::num::f64` modules now have additional constants (e.g., `POSITIVE`, `SUBNORMAL`, `INFINITE`) which can be used to generate subsets of the floating-point domain by class and sign. ### Bug Fixes - `proptest::num::f32::ANY` and `proptest::num::f64::ANY` now actually produce arbitrary values. Previously, they had the same effect as `0.0..1.0`. While this fix is a very substantial change in behaviour, it was not considered a breaking change since (a) the new behaviour is consistent with the documentation and expectations, (b) it's quite unlikely anyone was depending on the old behaviour since anyone who wanted that range would have written it out, and (c) Proptest isn't generally a transitive dependency so the chance of this update happening "by surprise" is low. ## 0.4.0 ### Deprecations and Potential Breaking Changes - `proptest::char::ANY` replaced with `proptest::char::any()`. `proptest::char::ANY` is present but deprecated, and will be removed in proptest 0.5.0. - Instead of returning `-> Result`, strategies are expected to return `-> Result` instead. `Reason` reduces the amount of heap allocations, especially for `.prop_filter(..)` where you may now also pass in `&'static str`. You will only experience breaks if you've written your own strategy types or if you've used `TestCaseError::Reject` or `TestCaseError::Fail` explicitly. - Update of externally-visible crate `rand` to `0.4.2`. ### New Additions - Added `proptest::test_runner::Reason` which allows you to avoid heap allocation in some places and may be used to make the API richer in the future without incurring more breaking changes. - Added a type alias `proptest::strategy::NewTree` where `S: Strategy` defined as: `type NewTree = Result<::Value, Rejection>`. ## 0.3.4 ### Bug Fixes - Cases where `file!()` returns a relative path, such as on Windows, are now handled more reasonably. See [#24](https://github.com/proptest-rs/proptest/issues/24) for more details and instructions on how to migrate any persistence files that had been written to the wrong location. ## 0.3.3 Boxing Day Special ### New Additions - Added support for `i128` and `u128`. Since this is an unstable feature in Rust, this is hidden behind the feature `unstable` which you have to explicitly opt into in your `Cargo.toml` file. - Failing case persistence. By default, when a test fails, Proptest will now save the seed for the failing test to a file, and later runs will test the persisted failing cases before generating new ones. - Added `UniformArrayStrategy` and helper functions to simplify generating homogeneous arrays with non-`Copy` inner strategies. - Trait `rand::Rng` and struct `rand::XorShiftRng` are now included in `proptest::prelude`. ### Bug Fixes - Fix a case where certain combinations of strategies, like two `prop_shuffle()`s in close proximity, could result in low-quality randomness. ## 0.3.2 ### New Additions - Added `SampledBitSetStrategy` to generate bit sets based on size distribution. - Added `Strategy::sboxed()` and `SBoxedStrategy` to make `Send + Sync` boxed strategies. - `RegexGeneratorStrategy` is now `Send` and `Sync`. - Added a type alias `ValueFor` where `S: Strategy`. This is a shorter way to refer to: `<::Value as ValueTree>::Value`. - Added a type alias `type W = (u32, T)` for a weighted strategy `T` in the context of union strategies. - `TestRunner` now implements `Default`. - Added `Config::with_cases(number_of_cases: u32) -> Config` for simpler construction of a `Config` that only differs by the number of test cases. - All default fields of `Config` can now be overridden by setting environment variables. See the docs of that struct for more details. - Bumped dependency `rand = "0.3.18"`. - Added `proptest::sample::subsequence` which returns a strategy generating subsequences, of the source `Vec`, with a size within the given `Range`. - Added `proptest::sample::select` which returns a strategy selecting exactly one value from another collection. - Added `prop_perturb` strategy combinator. - Added `strategy::check_strategy_sanity()` function to do sanity checks on the shrinking implementation of a strategy. - Added `prop_shuffle` strategy combinator. - Added `strategy::Fuse` adaptor. ### Bug Fixes - Fix bug where `Vec`, array and tuple shrinking could corrupt the state of their inner values, for example leading to out-of-range integers. - Fix bug where `Flatten` (a.k.a. the `prop_flat_map` combinator) could fail to converge to a failing test case during shrinking. - Fix `TupleUnion` sometimes panicking during shrinking if there were more than two choices. ## 0.3.1 ### New Additions - Added `CharStrategy::new_borrowed`. ## 0.3.0 ### New Additions - `Union` now supports weighting via `Union::new_weighted`. Corresponding syntax to specify weights is also available in `prop_oneof!`. - Added `TupleUnion`, which works like `Union` but permits doing static dispatch even with heterogeneous delegate strategies. - `prop_oneof!` is smarter about how it combines the input strategies. - Added `option` module to generate weighted or unweighted `Option` types. - Added `result` module to generate weighted or unweighted `Result` types. - All `bits` submodules now have a `masked` function to create a strategy for generating subsets of an arbitrary bitmask. ### Potential Breaking Changes - `Union::new` now has a generic argument type which could impact type inference. - The concrete types produced by `prop_oneof!` have changed. - API functions which used to return `BoxedStrategy` now return a specific type. - `BitSetStrategy` is no longer `Copy` for non-`Copy` types `T` nor `Debug` for non-`Debug` types `T`. - `BitSetLike::max` has been renamed to `BitSetLike::len`. ## 0.2.1 ### New Additions - Added `prop_assert!` macro family to assert without panicking, for quieter test failure modes. - New `prelude` module for easier importing of important things. - Renamed `Singleton` to `Just`. (The old name is still available.) - Failure messages produced by `proptest!` are now much more readable. - Added in-depth tutorial. ## 0.2.0 ### Breaking Changes - `Strategy` now requires `std::fmt::Debug`. ### New Additions - `Strategy` now has a family of `prop_flat_map()` combinators for producing dynamic and higher-order strategies. - `Strategy` has a `prop_recursive()` combinator which allows generating recursive structures. - Added `proptest::bool::weighted()` to pull booleans from a weighted distribution. - New `prop_oneof!` macro makes it easier to select from one of several strategies. - New `prop_compose!` macro to simplify writing most types of custom strategies. ## 0.1.1 ### New Additions Add `strategy::NoShrink`, `Strategy::no_shrink()`. proptest-1.6.0/Cargo.lock0000644000000354410000000000100107020ustar # This file is automatically @generated by Cargo. # It is not intended for manual editing. version = 3 [[package]] name = "aho-corasick" version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" dependencies = [ "memchr", ] [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "bit-set" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bit_field" version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61" [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "convert_case" version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" dependencies = [ "unicode-segmentation", ] [[package]] name = "errno" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" dependencies = [ "libc", "windows-sys", ] [[package]] name = "fastrand" version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "getrandom" version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe9006bed769170c11f845cf00c7c1e9092aeb3f268e007c3e760ac68008070f" dependencies = [ "cfg-if", "libc", "wasi", ] [[package]] name = "glob" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" [[package]] name = "itoa" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" [[package]] name = "libm" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "linux-raw-sys" version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4cd1a83af159aa67994778be9070f0ae1bd732942279cabb14f86f986a21456" [[package]] name = "memchr" version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" [[package]] name = "num-traits" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" dependencies = [ "autocfg", "libm", ] [[package]] name = "ppv-lite86" version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro2" version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" version = "1.6.0" dependencies = [ "bit-set", "bit-vec", "bitflags 2.4.1", "lazy_static", "num-traits", "proptest-macro", "rand", "rand_chacha", "rand_xorshift", "regex", "regex-syntax", "rusty-fork", "tempfile", "trybuild", "unarray", "x86", ] [[package]] name = "proptest-macro" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37f29eb7ffe1011ed152b761e866c717244d37c10032f8cbdc08388d733a31b7" dependencies = [ "convert_case", "proc-macro2", "quote", "syn", ] [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] [[package]] name = "rand" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", ] [[package]] name = "rand_chacha" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", ] [[package]] name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", ] [[package]] name = "rand_xorshift" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ "rand_core", ] [[package]] name = "raw-cpuid" version = "10.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "redox_syscall" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ "bitflags 1.3.2", ] [[package]] name = "regex" version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", "regex-automata", "regex-syntax", ] [[package]] name = "regex-automata" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] [[package]] name = "regex-syntax" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "rustix" version = "0.38.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72e572a5e8ca657d7366229cdde4bd14c4eb5499a9573d4d366fe1b599daa316" dependencies = [ "bitflags 2.4.1", "errno", "libc", "linux-raw-sys", "windows-sys", ] [[package]] name = "rusty-fork" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" dependencies = [ "fnv", "quick-error", "tempfile", "wait-timeout", ] [[package]] name = "ryu" version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" [[package]] name = "serde" version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b9781016e935a97e8beecf0c933758c97a5520d32930e460142b4cd80c6338e" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.216" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46f859dbbf73865c6627ed570e78961cd3ac92407a2d117204c49232485da55e" dependencies = [ "proc-macro2", "quote", "syn", ] [[package]] name = "serde_json" version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", "ryu", "serde", ] [[package]] name = "syn" version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] [[package]] name = "tempfile" version = "3.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" dependencies = [ "cfg-if", "fastrand", "redox_syscall", "rustix", "windows-sys", ] [[package]] name = "termcolor" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] [[package]] name = "toml" version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" dependencies = [ "serde", ] [[package]] name = "trybuild" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef41de35c6f33f6aaa082e4dd00ac71b564497c0e295e6228b405dd9a8538ffa" dependencies = [ "glob", "lazy_static", "serde", "serde_json", "termcolor", "toml", ] [[package]] name = "unarray" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-segmentation" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "wait-timeout" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" dependencies = [ "libc", ] [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" dependencies = [ "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ "windows-targets", ] [[package]] name = "windows-targets" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", "windows_x86_64_msvc", ] [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "x86" version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385" dependencies = [ "bit_field", "bitflags 1.3.2", "raw-cpuid", ] proptest-1.6.0/Cargo.toml0000644000000063040000000000100107210ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" rust-version = "1.65" name = "proptest" version = "1.6.0" authors = ["Jason Lingle"] build = false exclude = [ "/gen-*.sh", "/readme-*.md", ] autolib = false autobins = false autoexamples = false autotests = false autobenches = false description = """ Hypothesis-like property-based testing and shrinking. """ homepage = "https://proptest-rs.github.io/proptest/proptest/index.html" documentation = "https://docs.rs/proptest/latest/proptest/" readme = "README.md" keywords = [ "property", "testing", "quickcheck", "fuzz", "hypothesis", ] categories = ["development-tools::testing"] license = "MIT OR Apache-2.0" repository = "https://github.com/proptest-rs/proptest" [package.metadata.docs.rs] all-features = true rustdoc-args = [ "--cfg", "docsrs", ] [lib] name = "proptest" path = "src/lib.rs" [[example]] name = "config-defaults" path = "examples/config-defaults.rs" [[example]] name = "dateparser_v1" path = "examples/dateparser_v1.rs" [[example]] name = "dateparser_v2" path = "examples/dateparser_v2.rs" [[example]] name = "fib" path = "examples/fib.rs" [[example]] name = "tutorial-simplify-play" path = "examples/tutorial-simplify-play.rs" [[example]] name = "tutorial-strategy-play" path = "examples/tutorial-strategy-play.rs" [dependencies.bit-set] version = "0.8.0" optional = true [dependencies.bit-vec] version = "0.8.0" optional = true [dependencies.bitflags] version = "2" [dependencies.lazy_static] version = "1.2" optional = true [dependencies.num-traits] version = "0.2.15" default-features = false [dependencies.proptest-macro] version = "0.1" optional = true [dependencies.rand] version = "0.8" features = ["alloc"] default-features = false [dependencies.rand_chacha] version = "0.3" default-features = false [dependencies.rand_xorshift] version = "0.3" [dependencies.regex-syntax] version = "0.8" optional = true [dependencies.rusty-fork] version = "0.3.0" optional = true default-features = false [dependencies.tempfile] version = "3.0" optional = true [dependencies.unarray] version = "0.1.4" [dependencies.x86] version = "0.52.0" optional = true [dev-dependencies.regex] version = "1.0" [dev-dependencies.trybuild] version = "=1.0.0" [features] alloc = [] atomic64bit = [] attr-macro = ["proptest-macro"] bit-set = [ "dep:bit-set", "dep:bit-vec", ] default = [ "std", "fork", "timeout", "bit-set", ] default-code-coverage = [ "std", "fork", "timeout", "bit-set", ] fork = [ "std", "rusty-fork", "tempfile", ] handle-panics = ["std"] hardware-rng = ["x86"] no_std = ["num-traits/libm"] std = [ "rand/std", "lazy_static", "regex-syntax", "num-traits/std", ] timeout = [ "fork", "rusty-fork/timeout", ] unstable = [] proptest-1.6.0/Cargo.toml.orig000064400000000000000000000056351046102023000144100ustar 00000000000000[package] name = "proptest" version = "1.6.0" authors = ["Jason Lingle"] license = "MIT OR Apache-2.0" readme = "README.md" repository = "https://github.com/proptest-rs/proptest" homepage = "https://proptest-rs.github.io/proptest/proptest/index.html" documentation = "https://docs.rs/proptest/latest/proptest/" keywords = ["property", "testing", "quickcheck", "fuzz", "hypothesis"] categories = ["development-tools::testing"] edition = "2018" rust-version = "1.65" exclude = ["/gen-*.sh", "/readme-*.md"] description = """ Hypothesis-like property-based testing and shrinking. """ [features] default = ["std", "fork", "timeout", "bit-set"] # Everything in `default` that doesn't break code coverage builds default-code-coverage = ["std", "fork", "timeout", "bit-set"] attr-macro = ["proptest-macro"] # Enables unstable features of Rust. unstable = [] # Enables the use of standard-library dependent features std = ["rand/std", "lazy_static", "regex-syntax", "num-traits/std"] # std or libm required for mul_add. no_std = ["num-traits/libm"] # For use in no_std environments with access to an allocator #alloc = ["hashmap_core"] alloc = [] # Use a hardware random number generator (instead of static seed) for x86 no_std targets hardware-rng = ["x86"] # Enables use of the "fork" feature. # # Requires std. fork = ["std", "rusty-fork", "tempfile"] # Enables use of the "timeout" feature. # # Requires the "fork" feature. timeout = ["fork", "rusty-fork/timeout"] # Enables support for 64-bit atomic integers. # This is enabled by default. Some no_std environments do not support it and # need it excluded, however. atomic64bit = [] bit-set = ["dep:bit-set", "dep:bit-vec"] # Enables proper handling of panics # In particular, hides all intermediate panics flowing into stderr during shrink phase handle-panics = ["std"] [dependencies] bitflags = "2" unarray = "0.1.4" proptest-macro = { version = "0.1", optional = true } # [dependencies.hashmap_core] # version = "0.1.5" # optional = true [dependencies.lazy_static] version = "1.2" optional = true [dependencies.num-traits] version = "0.2.15" default-features = false [dependencies.regex-syntax] # If you change this, make sure to also bump the `regex` dependency to a # version that also uses this version of regex-syntax. version = "0.8" optional = true [dependencies.bit-set] version = "0.8.0" optional = true [dependencies.bit-vec] version = "0.8.0" optional = true [dependencies.rand] version = "0.8" default-features = false features = ["alloc"] [dependencies.rand_xorshift] version = "0.3" [dependencies.rand_chacha] version = "0.3" default-features = false [dependencies.rusty-fork] version = "0.3.0" optional = true default-features = false [dependencies.tempfile] version = "3.0" optional = true [dependencies.x86] version = "0.52.0" optional = true [package.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] [dev-dependencies] regex = "1.0" trybuild = "=1.0.0" proptest-1.6.0/LICENSE-APACHE000064400000000000000000000251371046102023000134440ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. proptest-1.6.0/LICENSE-MIT000064400000000000000000000020441046102023000131440ustar 00000000000000Copyright (c) 2016 FullContact, Inc Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. proptest-1.6.0/README.md000064400000000000000000000357351046102023000130040ustar 00000000000000# Proptest [![Build Status](https://github.com/proptest-rs/proptest/workflows/Rust/badge.svg?branch=master)](https://github.com/proptest-rs/proptest/actions) [![](https://img.shields.io/crates/v/proptest.svg)](https://crates.io/crates/proptest) [![](https://img.shields.io/website/https/proptest-rs.github.io/proptest.svg)][book] [![](https://docs.rs/proptest/badge.svg)][api-docs] [book]: https://proptest-rs.github.io/proptest/intro.html [api-docs]: https://docs.rs/proptest/latest/proptest/ ## Book A detailed introduction to proptest can be found in the [book](https://proptest-rs.github.io/proptest/) ## Introduction Proptest is a property testing framework (i.e., the QuickCheck family) inspired by the [Hypothesis](https://hypothesis.works/) framework for Python. It allows to test that certain properties of your code hold for arbitrary inputs, and if a failure is found, automatically finds the minimal test case to reproduce the problem. Unlike QuickCheck, generation and shrinking is defined on a per-value basis instead of per-type, which makes it more flexible and simplifies composition. ### Status of this crate The crate is fairly close to being feature-complete and has not seen substantial architectural changes in quite some time. At this point, it mainly sees passive maintenance. See the [changelog](https://github.com/proptest-rs/proptest/blob/master/proptest/CHANGELOG.md) for a full list of substantial historical changes, breaking and otherwise. ### MSRV The current MSRV of this crate is 1.64. The MSRV is guaranteed to not exceed ` - 7`, though in practice it may be lower than this - your mileage may vary. If we change this policy in a backwards incompatible way (e.g. changing it to ` - 1`), this constitutes a breaking change, and would be a major version bump (e.g. 1.1 -> 2.0). ### What is property testing? _Property testing_ is a system of testing code by checking that certain properties of its output or behaviour are fulfilled for all inputs. These inputs are generated automatically, and, critically, when a failing input is found, the input is automatically reduced to a _minimal_ test case. Property testing is best used to complement traditional unit testing (i.e., using specific inputs chosen by hand). Traditional tests can test specific known edge cases, simple inputs, and inputs that were known in the past to reveal bugs, whereas property tests will search for more complicated inputs that cause problems. ## Getting Started Let's say we want to make a function that parses dates of the form `YYYY-MM-DD`. We're not going to worry about _validating_ the date, any triple of integers is fine. So let's bang something out real quick. ```rust,no_run fn parse_date(s: &str) -> Option<(u32, u32, u32)> { if 10 != s.len() { return None; } if "-" != &s[4..5] || "-" != &s[7..8] { return None; } let year = &s[0..4]; let month = &s[6..7]; let day = &s[8..10]; year.parse::().ok().and_then( |y| month.parse::().ok().and_then( |m| day.parse::().ok().map( |d| (y, m, d)))) } ``` It compiles, that means it works, right? Maybe not, let's add some tests. ```rust,ignore #[test] fn test_parse_date() { assert_eq!(None, parse_date("2017-06-1")); assert_eq!(None, parse_date("2017-06-170")); assert_eq!(None, parse_date("2017006-17")); assert_eq!(None, parse_date("2017-06017")); assert_eq!(Some((2017, 06, 17)), parse_date("2017-06-17")); } ``` Tests pass, deploy to production! But now your application starts crashing, and people are upset that you moved Christmas to February. Maybe we need to be a bit more thorough. In `Cargo.toml`, add ```toml [dev-dependencies] proptest = "1.0.0" ``` Now we can add some property tests to our date parser. But how do we test the date parser for arbitrary inputs, without making another date parser in the test to validate it? We won't need to as long as we choose our inputs and properties correctly. But before correctness, there's actually an even simpler property to test: _The function should not crash._ Let's start there. ```rust,ignore // Bring the macros and other important things into scope. use proptest::prelude::*; proptest! { #[test] fn doesnt_crash(s in "\\PC*") { parse_date(&s); } } ``` What this does is take a literally random `&String` (ignore `\\PC*` for the moment, we'll get back to that — if you've already figured it out, contain your excitement for a bit) and give it to `parse_date()` and then throw the output away. When we run this, we get a bunch of scary-looking output, eventually ending with ```text thread 'main' panicked at 'Test failed: byte index 4 is not a char boundary; it is inside 'ௗ' (bytes 2..5) of `aAௗ0㌀0`; minimal failing input: s = "aAௗ0㌀0" successes: 102 local rejects: 0 global rejects: 0 ' ``` If we look at the top directory after the test fails, we'll see a new `proptest-regressions` directory, which contains some files corresponding to source files containing failing test cases. These are [_failure persistence_](https://proptest-rs.github.io/proptest/proptest/failure-persistence.html) files. The first thing we should do is add these to source control. ```text $ git add proptest-regressions ``` The next thing we should do is copy the failing case to a traditional unit test since it has exposed a bug not similar to what we've tested in the past. ```rust,ignore #[test] fn test_unicode_gibberish() { assert_eq!(None, parse_date("aAௗ0㌀0")); } ``` Now, let's see what happened... we forgot about UTF-8! You can't just blindly slice strings since you could split a character, in this case that Tamil diacritic placed atop other characters in the string. In the interest of making the code changes as small as possible, we'll just check that the string is ASCII and reject anything that isn't. ```rust,no_run fn parse_date(s: &str) -> Option<(u32, u32, u32)> { if 10 != s.len() { return None; } // NEW: Ignore non-ASCII strings so we don't need to deal with Unicode. if !s.is_ascii() { return None; } if "-" != &s[4..5] || "-" != &s[7..8] { return None; } let year = &s[0..4]; let month = &s[6..7]; let day = &s[8..10]; year.parse::().ok().and_then( |y| month.parse::().ok().and_then( |m| day.parse::().ok().map( |d| (y, m, d)))) } ``` The tests pass now! But we know there are still more problems, so let's test more properties. Another property we want from our code is that it parses every valid date. We can add another test to the `proptest!` section: ```rust,ignore proptest! { // snip... #[test] fn parses_all_valid_dates(s in "[0-9]{4}-[0-9]{2}-[0-9]{2}") { parse_date(&s).unwrap(); } } ``` The thing to the right-hand side of `in` is actually a *regular expression*, and `s` is chosen from strings which match it. So in our previous test, `"\\PC*"` was generating arbitrary strings composed of arbitrary non-control characters. Now, we generate things in the YYYY-MM-DD format. The new test passes, so let's move on to something else. The final property we want to check is that the dates are actually parsed _correctly_. Now, we can't do this by generating strings — we'd end up just reimplementing the date parser in the test! Instead, we start from the expected output, generate the string, and check that it gets parsed back. ```rust,ignore proptest! { // snip... #[test] fn parses_date_back_to_original(y in 0u32..10000, m in 1u32..13, d in 1u32..32) { let (y2, m2, d2) = parse_date( &format!("{:04}-{:02}-{:02}", y, m, d)).unwrap(); // prop_assert_eq! is basically the same as assert_eq!, but doesn't // cause a bunch of panic messages to be printed on intermediate // test failures. Which one to use is largely a matter of taste. prop_assert_eq!((y, m, d), (y2, m2, d2)); } } ``` Here, we see that besides regexes, we can use any expression which is a `proptest::strategy::Strategy`, in this case, integer ranges. The test fails when we run it. Though there's not much output this time. ```text thread 'main' panicked at 'Test failed: assertion failed: `(left == right)` (left: `(0, 10, 1)`, right: `(0, 0, 1)`) at examples/dateparser_v2.rs:46; minimal failing input: y = 0, m = 10, d = 1 successes: 2 local rejects: 0 global rejects: 0 ', examples/dateparser_v2.rs:33 note: Run with `RUST_BACKTRACE=1` for a backtrace. ``` The failing input is `(y, m, d) = (0, 10, 1)`, which is a rather specific output. Before thinking about why this breaks the code, let's look at what proptest did to arrive at this value. At the start of our test function, insert ```rust,ignore println!("y = {}, m = {}, d = {}", y, m, d); ``` Running the test again, we get something like this: ```text y = 2497, m = 8, d = 27 y = 9641, m = 8, d = 18 y = 7360, m = 12, d = 20 y = 3680, m = 12, d = 20 y = 1840, m = 12, d = 20 y = 920, m = 12, d = 20 y = 460, m = 12, d = 20 y = 230, m = 12, d = 20 y = 115, m = 12, d = 20 y = 57, m = 12, d = 20 y = 28, m = 12, d = 20 y = 14, m = 12, d = 20 y = 7, m = 12, d = 20 y = 3, m = 12, d = 20 y = 1, m = 12, d = 20 y = 0, m = 12, d = 20 y = 0, m = 6, d = 20 y = 0, m = 9, d = 20 y = 0, m = 11, d = 20 y = 0, m = 10, d = 20 y = 0, m = 10, d = 10 y = 0, m = 10, d = 5 y = 0, m = 10, d = 3 y = 0, m = 10, d = 2 y = 0, m = 10, d = 1 ``` The test failure message said there were two successful cases; we see these at the very top, `2497-08-27` and `9641-08-18`. The next case, `7360-12-20`, failed. There's nothing immediately obviously special about this date. Fortunately, proptest reduced it to a much simpler case. First, it rapidly reduced the `y` input to `0` at the beginning, and similarly reduced the `d` input to the minimum allowable value of `1` at the end. Between those two, though, we see something different: it tried to shrink `12` to `6`, but then ended up raising it back up to `10`. This is because the `0000-06-20` and `0000-09-20` test cases _passed_. In the end, we get the date `0000-10-01`, which apparently gets parsed as `0000-00-01`. Again, this failing case was added to the failure persistence file, and we should add this as its own unit test: ```text $ git add proptest-regressions ``` ```rust,ignore #[test] fn test_october_first() { assert_eq!(Some((0, 10, 1)), parse_date("0000-10-01")); } ``` Now to figure out what's broken in the code. Even without the intermediate input, we can say with reasonable confidence that the year and day parts don't come into the picture since both were reduced to the minimum allowable input. The month input was _not_, but was reduced to `10`. This means we can infer that there's something special about `10` that doesn't hold for `9`. In this case, that "special something" is being two digits wide. In our code: ```rust,ignore let month = &s[6..7]; ``` We were off by one, and need to use the range `5..7`. After fixing this, the test passes. The `proptest!` macro has some additional syntax, including for setting configuration for things like the number of test cases to generate. See its [documentation](https://docs.rs/proptest/latest/proptest/macro.proptest.html) for more details. ## Differences between QuickCheck and Proptest QuickCheck and Proptest are similar in many ways: both generate random inputs for a function to check certain properties, and automatically shrink inputs to minimal failing cases. The one big difference is that QuickCheck generates and shrinks values based on type alone, whereas Proptest uses explicit `Strategy` objects. The QuickCheck approach has a lot of disadvantages in comparison: - QuickCheck can only define one generator and shrinker per type. If you need a custom generation strategy, you need to wrap it in a newtype and implement traits on that by hand. In Proptest, you can define arbitrarily many different strategies for the same type, and there are plenty built-in. - For the same reason, QuickCheck has a single "size" configuration that tries to define the range of values generated. If you need an integer between 0 and 100 and another between 0 and 1000, you probably need to do another newtype. In Proptest, you can directly just express that you want a `0..100` integer and a `0..1000` integer. - Types in QuickCheck are not easily composable. Defining `Arbitrary` and `Shrink` for a new struct which is simply produced by the composition of its fields requires implementing both by hand, including a bidirectional mapping between the struct and a tuple of its fields. In Proptest, you can make a tuple of the desired components and then `prop_map` it into the desired form. Shrinking happens automatically in terms of the input types. - Because constraints on values cannot be expressed in QuickCheck, generation and shrinking may lead to a lot of input rejections. Strategies in Proptest are aware of simple constraints and do not generate or shrink to values that violate them. The author of Hypothesis also has an [article on this topic](https://hypothesis.works/articles/integrated-shrinking/). Of course, there's also some relative downsides that fall out of what Proptest does differently: - Generating complex values in Proptest can be up to an order of magnitude slower than in QuickCheck. This is because QuickCheck performs stateless shrinking based on the output value, whereas Proptest must hold on to all the intermediate states and relationships in order for its richer shrinking model to work. ## Limitations of Property Testing Given infinite time, property testing will eventually explore the whole input space to a test. However, time is not infinite, so only a randomly sampled portion of the input space can be explored. This means that property testing is extremely unlikely to find single-value edge cases in a large space. For example, the following test will virtually always pass: ```rust use proptest::prelude::*; proptest! { #[test] fn i64_abs_is_never_negative(a: i64) { // This actually fails if a == i64::MIN, but randomly picking one // specific value out of 2⁶⁴ is overwhelmingly unlikely. assert!(a.abs() >= 0); } } ``` Because of this, traditional unit testing with intelligently selected cases is still necessary for many kinds of problems. Similarly, in some cases it can be hard or impossible to define a strategy which actually produces useful inputs. A strategy of `.{1,4096}` may be great to fuzz a C parser, but is highly unlikely to produce anything that makes it to a code generator. # Acknowledgements This crate wouldn't have come into existence had it not been for the [Rust port of QuickCheck](https://github.com/BurntSushi/quickcheck) and the [`regex_generate`](https://github.com/CryptArchy/regex_generate) crate which gave wonderful examples of what is possible. ## Contribution Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions. proptest-1.6.0/examples/config-defaults.rs000064400000000000000000000006761046102023000167570ustar 00000000000000//- // 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. use proptest::test_runner::Config; fn main() { println!("Default config: {:?}", Config::default()); } proptest-1.6.0/examples/dateparser_v1.rs000064400000000000000000000023511046102023000164350ustar 00000000000000//- // 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. use proptest::prelude::*; fn parse_date(s: &str) -> Option<(u32, u32, u32)> { if 10 != s.len() { return None; } // ! if "-" != &s[4..5] || "-" != &s[7..8] { return None; } let year = &s[0..4]; let month = &s[6..7]; // ! let day = &s[8..10]; year.parse::().ok().and_then(|y| { month .parse::() .ok() .and_then(|m| day.parse::().ok().map(|d| (y, m, d))) }) } // NB We omit #[test] on these functions so that main() can call them. proptest! { fn doesnt_crash(s in "\\PC*") { parse_date(&s); } } fn main() { assert_eq!(None, parse_date("2017-06-1")); assert_eq!(None, parse_date("2017-06-170")); assert_eq!(None, parse_date("2017006-17")); assert_eq!(None, parse_date("2017-06017")); assert_eq!(Some((2017, 6, 17)), parse_date("2017-06-17")); doesnt_crash(); } proptest-1.6.0/examples/dateparser_v2.rs000064400000000000000000000034461046102023000164440ustar 00000000000000//- // 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. use proptest::prelude::*; fn parse_date(s: &str) -> Option<(u32, u32, u32)> { if 10 != s.len() { return None; } // NEW: Ignore non-ASCII strings so we don't need to deal with Unicode. if !s.is_ascii() { return None; } if "-" != &s[4..5] || "-" != &s[7..8] { return None; } let year = &s[0..4]; let month = &s[6..7]; // ! let day = &s[8..10]; year.parse::().ok().and_then(|y| { month .parse::() .ok() .and_then(|m| day.parse::().ok().map(|d| (y, m, d))) }) } // NB We omit #[test] on these functions so that main() can call them. proptest! { fn doesnt_crash(s in "\\PC*") { parse_date(&s); } fn parses_all_valid_dates(s in "[0-9]{4}-[0-9]{2}-[0-9]{2}") { parse_date(&s).unwrap(); } fn parses_date_back_to_original(y in 0u32..10_000, m in 1u32..13, d in 1u32..32) { let (y2, m2, d2) = parse_date( &format!("{:04}-{:02}-{:02}", y, m, d)).unwrap(); prop_assert_eq!((y, m, d), (y2, m2, d2)); } } fn main() { assert_eq!(None, parse_date("2017-06-1")); assert_eq!(None, parse_date("2017-06-170")); assert_eq!(None, parse_date("2017006-17")); assert_eq!(None, parse_date("2017-06017")); assert_eq!(Some((2017, 6, 17)), parse_date("2017-06-17")); doesnt_crash(); parses_all_valid_dates(); parses_date_back_to_original(); } proptest-1.6.0/examples/fib.rs000064400000000000000000000030031046102023000144300ustar 00000000000000//- // Copyright 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. // This #[cfg] is only here so that CI can test building proptest with the // timeout feature disabled. You do not need it in your code. #[cfg(feature = "timeout")] mod fib { use proptest::prelude::*; // The worst possible way to calculate Fibonacci numbers fn fib(n: u64) -> u64 { if n <= 1 { n } else { fib(n - 1) + fib(n - 2) } } proptest! { #![proptest_config(ProptestConfig { // Setting both fork and timeout is redundant since timeout implies // fork, but both are shown for clarity. fork: true, timeout: 1000, .. ProptestConfig::default() })] // NB We omit #[test] on the test function so that main() can call it. fn test_fib(n in prop::num::u64::ANY) { // For large n, this will variously run for an extremely long time, // overflow the stack, or panic due to integer overflow. assert!(fib(n) >= n); } } // This is just here so that main can call it pub fn do_test_fib() { test_fib(); } } fn main() { #[cfg(feature = "timeout")] fib::do_test_fib(); } proptest-1.6.0/examples/tutorial-simplify-play.rs000064400000000000000000000016231046102023000203360ustar 00000000000000//- // 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. // Shows how to pick values from a strategy and simplify them. // // This is *not* how proptest is normally used; it is simply used to play // around with value generation. use proptest::strategy::{Strategy, ValueTree}; use proptest::test_runner::TestRunner; fn main() { let mut runner = TestRunner::default(); let mut str_val = "[a-z]{1,4}\\p{Cyrillic}{1,4}\\p{Greek}{1,4}" .new_tree(&mut runner) .unwrap(); println!("str_val = {}", str_val.current()); while str_val.simplify() { println!(" = {}", str_val.current()); } } proptest-1.6.0/examples/tutorial-strategy-play.rs000064400000000000000000000016401046102023000203430ustar 00000000000000//- // 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. // Shows how to pick values from a strategy. // // This is *not* how proptest is normally used; it is simply used to play // around with value generation. use proptest::strategy::{Strategy, ValueTree}; use proptest::test_runner::TestRunner; fn main() { let mut runner = TestRunner::default(); let int_val = (0..100i32).new_tree(&mut runner).unwrap(); let str_val = "[a-z]{1,4}\\p{Cyrillic}{1,4}\\p{Greek}{1,4}" .new_tree(&mut runner) .unwrap(); println!( "int_val = {}, str_val = {}", int_val.current(), str_val.current() ); } proptest-1.6.0/proptest-regressions/.gitignore000064400000000000000000000000701046102023000177160ustar 00000000000000# Produced by a test that deliberately fails. sugar.txt proptest-1.6.0/proptest-regressions/arbitrary/_std/env.txt000064400000000000000000000006051046102023000222130ustar 00000000000000# Seeds for failure cases proptest has generated in the past. It is # automatically read and these particular cases re-run before any # novel cases are generated. # # It is recommended to check this file in to source control so that # everyone who runs the test benefits from these saved cases. xs 1820944860 846518628 1859875405 4214131038 # shrinks to mut buf = [55296, 0, 56320], p = 1 proptest-1.6.0/proptest-regressions/test_runner/rng.txt000064400000000000000000000232251046102023000216340ustar 00000000000000# Seeds for failure cases proptest has generated in the past. It is # automatically read and these particular cases re-run before any # novel cases are generated. # # It is recommended to check this file in to source control so that # everyone who runs the test benefits from these saved cases. cc c07e85d05e65b51ff76176b8f3fb2ef318b8590d6e39cc1013d36c32a8f4589c # shrinks to seed = PassThrough(None, [4, 236, 242, 152, 113, 207, 60, 224, 102, 251, 83, 252, 39, 193, 248, 85, 34, 142, 244, 163, 10, 16, 16, 192, 82, 17, 210, 144, 251, 173, 175, 190, 94, 56, 129, 205, 214, 88, 168, 187, 100, 86, 98, 190, 160, 60, 58, 9, 194, 66, 118, 50, 208, 64, 157, 161, 246, 106, 14, 132, 132, 230, 125, 27, 216, 105, 121, 193, 171, 131, 10, 150, 189, 175, 177, 32, 34, 49, 77, 66, 36, 161, 178, 39, 171, 250, 156, 163, 160, 99, 200, 159, 134, 242, 43, 88, 68, 4, 156, 123, 104, 6, 74, 167, 60, 215, 9, 203, 60, 6, 45, 186, 252, 196, 64, 61, 135, 132, 144, 191, 162, 134, 157, 159, 78, 218, 161, 28, 100, 69, 23, 82, 115, 252, 183, 2, 217, 137, 145, 224, 73, 161, 28, 230, 88, 226, 209, 34, 86, 183, 152, 36, 233, 174, 24, 169, 151, 14, 106, 246, 27, 10, 200, 151, 179, 142, 37, 239, 75, 159, 167, 78, 110, 14, 241, 163, 48, 79, 194, 33, 166, 173, 46, 22, 251, 62, 115, 194, 146, 154, 35, 59, 20, 242, 161, 101, 33, 216, 83, 55, 52, 209, 249, 51, 24, 187, 58, 154, 166, 152, 1, 55, 149, 11, 158, 239, 3, 198, 142, 105, 139, 247, 245, 37, 193, 163, 180, 254, 64, 133, 177, 110, 26, 173, 72, 237, 19, 223, 69, 120, 8, 55, 85, 216, 84, 21, 197, 30, 109, 126, 144, 76, 215, 98, 204, 33, 84, 103, 33, 7, 172, 179, 119, 247, 197, 153, 191, 136, 245, 249, 27, 184, 29, 189, 60, 28, 77, 193, 144, 10, 71, 18, 68, 130, 218, 29, 188, 4, 233, 16, 143, 215, 52, 56, 71, 70, 146, 2, 130, 119, 179, 150, 79, 109, 139, 138, 3, 57, 109, 144, 160, 179, 117, 208, 53, 241, 226, 52, 141, 116, 6, 47, 248, 76, 10, 209, 255, 205, 145, 127, 215, 201, 43, 28, 51, 166, 177, 193, 232, 6, 241, 205, 53, 104, 133, 202, 1, 203, 146, 151, 154, 168, 248, 63, 139, 186, 211, 142, 206, 122, 222, 63, 134, 227, 12, 84, 197, 45, 41, 155, 211, 165, 118, 10, 255, 117, 238, 57, 133, 157, 121, 240, 67, 255, 103, 116, 94, 28, 4, 224, 24, 120, 161, 59, 83, 103, 182, 227, 176, 89, 194, 131, 22, 251, 59, 131, 117, 243, 123, 141, 3, 181, 191, 214, 31, 41, 227, 27, 169, 168, 132, 207, 167, 169, 1, 201, 191, 186, 249, 16, 32, 237, 199, 122, 153, 151, 1, 254, 69, 169, 137, 244, 84, 214, 31, 217, 26, 20, 197, 15, 179, 74, 149, 219, 45, 145, 245, 239, 215, 172, 249, 144, 79, 76, 10, 27, 21, 168, 160, 248, 178, 22, 251, 204, 12, 18, 197, 226, 11, 26, 2, 128, 86, 85, 92, 164, 59, 253, 75, 84, 122, 229, 45, 130, 39, 162, 35, 84, 126, 250, 164, 21, 55, 73, 149, 82, 83, 26, 81, 147, 231, 19, 244, 159, 23, 51, 215, 81, 93, 171, 27, 246, 234, 230, 107, 47, 47, 201, 23, 161, 194, 213, 146, 164, 91, 174, 151, 148, 113, 147, 148, 206, 224, 17, 167, 139, 70, 240, 60, 37, 102, 17, 176, 60, 213, 42, 22, 123, 50, 44, 87, 244, 193, 141, 53, 212, 228, 239, 212, 55, 146, 192, 157, 250, 248, 46, 73, 98, 173, 145, 249, 51, 10, 154, 154, 179, 95, 140, 184, 96, 162, 96, 35, 147, 243, 187, 255, 5, 191, 185, 182, 216, 69, 24, 45, 45, 160, 232, 83, 180, 185, 103, 10, 140, 86, 206, 104, 99, 70, 200, 201, 13, 235, 54, 136, 23, 142, 220, 16, 231, 158, 243, 54, 167, 45, 125, 51, 116, 210, 246, 216, 89, 30, 218, 108, 214, 29, 85, 95, 0, 226, 11, 90, 196, 186, 48, 188, 9, 8, 212, 213, 35, 231, 182, 78, 105, 239, 231, 22, 191, 166, 210, 227, 134, 79, 144, 17, 154, 60, 179, 135, 211, 104, 109, 75, 213, 109, 182, 55, 82, 172, 20, 249, 73, 0, 169, 162, 37, 1, 92, 25, 141, 25, 140, 118, 77, 221, 54, 7, 224, 224, 115, 107, 41, 20, 37, 35, 102, 243, 206, 200, 98, 176, 118, 140, 23, 159, 127, 90, 82, 174, 21, 34, 72, 25, 236, 241, 68, 65, 116, 41, 67, 153, 211, 73, 120, 113, 189, 125, 158, 72, 201, 200, 201, 207, 253, 75, 246, 120, 146, 187, 9, 24, 164, 57, 160, 127, 178, 147, 239, 155, 188, 160, 179, 191, 241, 245, 31, 245, 57, 18, 64, 246, 44, 150, 32, 99, 79, 124, 188, 147, 122, 104, 30, 71, 4, 232, 91, 224, 94, 230, 207, 165, 227, 85, 166, 82, 25, 149, 95, 168, 100, 58, 104, 173, 157, 245, 254, 33, 187, 7, 174, 61, 216, 80, 64, 119, 245, 123, 231, 208, 248, 184, 224, 196, 3, 18, 37, 101, 88, 224, 209, 42, 122, 55, 251, 240, 253, 210, 191, 243, 109, 151, 228, 109, 79, 66, 182, 48, 169, 163, 109, 206, 52, 90, 137, 254, 111, 225, 58, 141, 118, 247, 50, 141, 98, 87, 123, 213, 242, 23, 177, 128, 100, 144, 167, 156, 96, 59, 0, 0, 241, 53, 94, 45, 2, 252, 145, 17, 35, 16, 10, 146, 94, 180, 207, 67, 23, 213, 31, 121, 169, 196, 16, 211, 189, 153, 199, 47, 150, 109, 17, 55, 228, 237, 117, 59, 153, 175, 130, 73, 241, 85, 41, 165, 225, 83, 223, 69, 213, 183, 118, 41, 239, 172, 31, 169, 222, 211, 181, 87, 183, 34, 34, 171, 97, 115, 180, 177, 249, 126, 56, 213, 205, 241, 250, 136, 43, 84, 211, 214, 33, 185, 5, 177, 30, 152, 135, 35, 232, 194, 34, 252, 93, 192, 233, 181, 42, 239, 113, 58, 67, 132, 197, 160, 179, 202, 51, 146, 240, 194, 201, 34, 174, 251, 155, 59, 219, 89, 74, 3, 164, 175, 88, 40, 191, 11, 149, 16, 35, 16, 147, 53, 127, 5, 158, 248, 45, 24, 127, 235, 73, 29, 244, 65, 131, 217, 157, 88, 115, 152, 217, 58, 209, 135, 36, 203, 20, 211, 123, 156, 114, 110, 71, 0, 38, 123, 34, 179, 135, 6, 50, 44, 165, 162, 209, 77, 10, 32, 75, 185, 134, 220, 195, 164, 212, 70, 209, 241, 188, 67, 168, 245, 198, 243, 79, 3, 246, 218, 43, 35, 249, 217, 181, 128, 165, 86, 101, 82, 241, 230, 250, 246, 170, 76, 245, 126, 91, 116, 92, 240, 42, 40, 42, 190, 71, 158, 155, 199, 209, 223, 138, 195, 87, 175, 145, 78, 83, 160, 206, 165, 188, 64, 22, 86, 219, 50, 230, 180, 132, 233, 111, 251, 101, 141, 228, 218, 101, 72, 187, 172, 59, 126, 115, 175, 239, 135, 188, 137, 8, 152, 199, 23, 125, 164, 0, 24, 252, 158, 102, 229, 9, 207, 37, 235, 167, 122, 48, 175, 153, 98, 235, 26, 96, 66, 217, 180, 136, 30, 78, 138, 47, 13, 5, 12, 82, 151, 224, 20, 106, 57, 104, 243, 175, 37, 231, 111, 74, 51, 176, 236, 236, 128, 12, 134, 196, 18, 9, 79, 2, 146, 235, 238, 72, 165, 164, 201, 190, 212, 53, 240, 131, 39, 178, 229, 59, 10, 171, 229, 245, 222, 197, 237, 233, 132, 161, 116, 39, 193, 207, 222, 211, 209, 232, 46, 202, 55, 196, 7, 202, 67, 105, 211, 84, 138, 118, 145, 194, 132, 107, 217, 116, 136, 147, 190, 39, 243, 81, 104, 162, 78, 123, 174, 73, 181, 220, 166, 40, 133, 189, 64, 202, 129, 83, 251, 4, 13, 122, 250, 172, 152, 175, 13, 214, 253, 175, 36, 160, 171, 239, 58, 38, 66, 216, 250, 227, 0, 159, 45, 72, 82, 204, 30, 4, 18, 76, 253, 11, 170, 26, 56, 212, 101, 84, 127, 179, 197, 170, 217, 14, 63, 0, 162, 223, 215, 171, 159, 30, 82, 221, 24, 43, 60, 204, 50, 52, 1, 187, 65, 83, 206, 122, 104, 44, 126, 224, 42, 192, 211, 48, 205, 112, 70, 181, 131, 41, 76, 2, 8, 213, 127, 48, 63, 115, 243, 125, 118, 83, 97, 167, 25, 253, 61, 233, 0, 219, 244, 231, 154, 69, 135, 161, 132, 138, 2, 62, 49, 3, 162, 123, 26, 179, 222, 247, 48, 44, 196, 183, 114, 74, 159, 224, 133, 140, 86, 111, 156, 39, 225, 40, 24, 16, 215, 143, 102, 131, 59, 5, 49, 185, 202, 157, 103, 90, 49, 72, 42, 251, 183, 162, 140, 15, 40, 213, 169, 230, 236, 19, 41, 229, 79, 163, 91, 196, 176, 130, 53, 197, 182, 133, 161, 231, 57, 23, 138, 163, 46, 85, 177, 86, 45, 40, 29, 89, 72, 241, 151, 28, 109, 117, 18, 178, 52, 237, 200, 152, 255, 85, 223, 150, 167, 1, 253, 62, 153, 146, 104, 48, 45, 131, 89, 239, 204, 89, 152, 91, 32, 26, 174, 97, 82, 88, 113, 8, 208, 8, 124, 120, 236, 0, 72, 43, 252, 125, 227, 232, 13, 17, 208, 82, 242, 223, 161, 63, 33, 49, 20, 105, 38, 210, 31, 170, 37, 185, 142, 233, 23, 213, 118, 161, 128, 60, 182, 91, 247, 234, 251, 90, 58, 72, 103, 19, 158, 194, 108, 146, 225, 243, 107, 190, 19, 93, 62, 144, 128, 226, 26, 49, 4, 175, 142, 131, 212, 182, 71, 120, 160, 178, 30, 115, 190, 0, 30, 21, 165, 118, 180, 236, 11, 68, 243, 92, 38, 218, 96, 180, 41, 27, 160, 237, 101, 181, 127, 127, 144, 209, 133, 179, 121, 85, 229, 171, 19, 176, 227, 85, 131, 179, 102, 78, 203, 168, 126, 189, 217, 188, 133, 81, 195, 177, 248, 232, 201, 206, 32, 68, 4, 139, 136, 92, 29, 44, 235, 134, 246, 94, 97, 140, 245, 59, 45, 198, 41, 181, 255, 124, 254, 57, 210, 198, 166, 141, 119, 85, 114, 246, 182, 69, 44, 209, 237, 255, 8, 49, 91, 60, 24, 195, 237, 102, 178, 154, 60, 4, 11, 35, 125, 38, 243, 168, 226, 231, 113, 173, 148, 212, 124, 162, 167, 213, 168, 22, 141, 124, 72, 5, 195, 160, 249, 3, 156, 239, 104, 10, 248, 52, 118, 3, 73, 165, 160, 35, 141, 67, 31, 185, 178, 212, 94, 1, 210, 62, 77, 102, 36, 8, 106, 39, 228, 132, 208, 187, 68, 62, 209, 116, 103, 83, 71, 160, 218, 189, 117, 222, 207, 95, 130, 174, 143, 188, 102, 199, 210, 134, 192, 138, 160, 46, 116, 55, 220, 109, 36, 9, 156, 148, 226, 72, 113, 16, 173, 156, 176, 209, 29, 185, 234, 59, 50, 248, 250, 88, 197, 23, 193, 218, 119, 113, 50, 165, 190, 123, 177, 41, 92, 53, 28, 147, 170, 12, 4, 93, 85, 119, 255, 17, 59, 90, 153, 68, 25, 152, 6, 52, 165, 175, 189, 100, 56, 73, 146, 50, 203, 206, 174, 209, 104, 156, 214, 126, 224, 4, 191, 147, 182, 52, 1, 189, 105, 250, 19, 43, 7, 154, 186, 70, 114, 115, 225, 250, 171, 157, 61, 166, 59, 183, 89, 147, 6, 166, 91, 127, 182, 243, 0, 95, 156, 187, 48, 157, 188, 211, 169, 85, 253, 60, 158, 9, 95, 245, 173, 20, 35, 11, 13, 49, 0, 8, 30, 234, 175, 89, 183, 153, 186, 171, 200, 107, 237, 14, 128, 142, 223, 69, 36, 237, 161, 60, 159, 7, 5, 221, 13, 232, 155, 78, 146, 213, 223, 14, 232, 253, 65, 210, 23, 26, 230, 123, 163, 228, 54, 222, 198, 191, 13, 10, 68, 12, 222, 17, 81, 202, 106, 62, 82, 98, 180, 118, 37, 61, 240, 214, 185, 142, 220, 132, 75, 187, 32, 36, 244, 121, 161, 180, 231, 216, 254, 120, 83, 212, 255, 88, 224, 63, 103, 77, 117, 144, 20, 46, 120, 115, 140, 147, 78, 228, 62, 222, 238, 172, 107, 18, 73, 3, 118, 251, 127, 246, 10, 88, 91, 63, 246, 43, 17, 144, 238, 67, 102, 120, 173, 89, 94, 209, 15, 201, 70, 185]) cc ea20181bc161c5c2b5a2a9f4a684a8afc64b7c4e78242355f117f4bd2d387a3f # shrinks to seed = PassThrough(None, []) proptest-1.6.0/src/arbitrary/_alloc/alloc.rs000064400000000000000000000043031046102023000171670ustar 00000000000000//- // 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; // TODO: This may only work on 64 bit processors, but previously it was broken // even on 64 bit so still an improvement. 63 -> uint size - 1. let max_size = (1usize << 63) - (1 << usize::from(align_power)); // 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::AllocError //collection_alloc_err => alloc::collections::CollectionAllocErr ); } proptest-1.6.0/src/arbitrary/_alloc/borrow.rs000064400000000000000000000016441046102023000174140ustar 00000000000000//- // 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) ); proptest-1.6.0/src/arbitrary/_alloc/boxed.rs000064400000000000000000000010041046102023000171710ustar 00000000000000//- // 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); } proptest-1.6.0/src/arbitrary/_alloc/char.rs000064400000000000000000000047571046102023000170270ustar 00000000000000//- // 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); 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 ); 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 ); } proptest-1.6.0/src/arbitrary/_alloc/collections.rs000064400000000000000000000230231046102023000204130ustar 00000000000000//- // 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(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 ); } proptest-1.6.0/src/arbitrary/_alloc/hash.rs000064400000000000000000000020161046102023000170170ustar 00000000000000//- // 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 ); } proptest-1.6.0/src/arbitrary/_alloc/mod.rs000064400000000000000000000010311046102023000166470ustar 00000000000000//- // 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; proptest-1.6.0/src/arbitrary/_alloc/ops.rs000064400000000000000000000055361046102023000167070ustar 00000000000000//- // 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] CoroutineState, TupleUnion<(WA>, WA>)>, product_type![Y::Parameters, R::Parameters]; args => { let product_unpack![y, r] = args; prop_oneof![ static_map(any_with::(y), CoroutineState::Yielded), static_map(any_with::(r), CoroutineState::Complete) ] } ); #[cfg(feature = "unstable")] use core::fmt; #[cfg(feature = "unstable")] impl functor::ArbitraryF2 for CoroutineState { 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(CoroutineState::Yielded), snd.prop_map(CoroutineState::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 => CoroutineState ); } proptest-1.6.0/src/arbitrary/_alloc/rc.rs000064400000000000000000000011011046102023000164720ustar 00000000000000//- // 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); } proptest-1.6.0/src/arbitrary/_alloc/str.rs000064400000000000000000000027001046102023000167040ustar 00000000000000//- // 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 ); } proptest-1.6.0/src/arbitrary/_alloc/sync.rs000064400000000000000000000040551046102023000170550ustar 00000000000000//- // 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 ); } proptest-1.6.0/src/arbitrary/_core/ascii.rs000064400000000000000000000012671046102023000170310ustar 00000000000000//- // 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); } proptest-1.6.0/src/arbitrary/_core/cell.rs000064400000000000000000000024441046102023000166560ustar 00000000000000//- // 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(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(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 ); } proptest-1.6.0/src/arbitrary/_core/cmp.rs000064400000000000000000000015041046102023000165120ustar 00000000000000//- // 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 ); } proptest-1.6.0/src/arbitrary/_core/convert.rs000064400000000000000000000011221046102023000174070ustar 00000000000000//- // 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! proptest-1.6.0/src/arbitrary/_core/fmt.rs000064400000000000000000000010021046102023000165120ustar 00000000000000//- // 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); } proptest-1.6.0/src/arbitrary/_core/iter.rs000064400000000000000000000121331046102023000166760ustar 00000000000000//- // 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< T: 'static + Clone, A: fmt::Debug + 'static + Iterator, > 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< T, A: fmt::Debug + Iterator, 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> ); } proptest-1.6.0/src/arbitrary/_core/marker.rs000064400000000000000000000010731046102023000172150ustar 00000000000000//- // 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); } proptest-1.6.0/src/arbitrary/_core/mem.rs000064400000000000000000000024521046102023000165140ustar 00000000000000//- // 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> ); } proptest-1.6.0/src/arbitrary/_core/mod.rs000064400000000000000000000010221046102023000165050ustar 00000000000000//- // 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 non_zero; mod num; mod option; mod result; proptest-1.6.0/src/arbitrary/_core/non_zero.rs000064400000000000000000000042721046102023000175710ustar 00000000000000//- // 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 core::convert::TryFrom; #[cfg(not(target_arch = "wasm32"))] use core::num::{NonZeroI128, NonZeroU128}; use core::num::{ NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, }; use crate::arbitrary::{any, Arbitrary, StrategyFor}; use crate::strategy::{FilterMap, Strategy}; macro_rules! non_zero_impl { ($nz:ty, $prim:ty) => { impl Arbitrary for $nz { type Parameters = (); type Strategy = FilterMap, fn($prim) -> Option>; fn arbitrary_with((): Self::Parameters) -> Self::Strategy { any::<$prim>().prop_filter_map("must be non zero", |i| { Self::try_from(i).ok() }) } } }; } non_zero_impl!(NonZeroU8, u8); non_zero_impl!(NonZeroU16, u16); non_zero_impl!(NonZeroU32, u32); non_zero_impl!(NonZeroU64, u64); #[cfg(not(target_arch = "wasm32"))] non_zero_impl!(NonZeroU128, u128); non_zero_impl!(NonZeroUsize, usize); non_zero_impl!(NonZeroI8, i8); non_zero_impl!(NonZeroI16, i16); non_zero_impl!(NonZeroI32, i32); non_zero_impl!(NonZeroI64, i64); #[cfg(not(target_arch = "wasm32"))] non_zero_impl!(NonZeroI128, i128); non_zero_impl!(NonZeroIsize, isize); #[cfg(test)] mod test { no_panic_test!( u8 => core::num::NonZeroU8, u16 => core::num::NonZeroU16, u32 => core::num::NonZeroU32, u64 => core::num::NonZeroU64, usize => core::num::NonZeroUsize, i8 => core::num::NonZeroI8, i16 => core::num::NonZeroI16, i32 => core::num::NonZeroI32, i64 => core::num::NonZeroI64, isize => core::num::NonZeroIsize ); #[cfg(not(target_arch = "wasm32"))] no_panic_test!( u128 => core::num::NonZeroU128, i128 => core::num::NonZeroI128 ); } proptest-1.6.0/src/arbitrary/_core/num.rs000064400000000000000000000025671046102023000165440ustar 00000000000000//- // 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 ); } proptest-1.6.0/src/arbitrary/_core/option.rs000064400000000000000000000032721046102023000172470ustar 00000000000000//- // 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(test)] mod test { no_panic_test!( probability => Probability, option => Option, option_iter => opt::IntoIter, option_parse_error => Option ); } proptest-1.6.0/src/arbitrary/_core/result.rs000064400000000000000000000063471046102023000172630ustar 00000000000000//- // 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> ); } proptest-1.6.0/src/arbitrary/_std/env.rs000064400000000000000000000103311046102023000163630ustar 00000000000000//- // 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); } } } proptest-1.6.0/src/arbitrary/_std/ffi.rs000064400000000000000000000057541046102023000163540ustar 00000000000000//- // 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 ); } proptest-1.6.0/src/arbitrary/_std/fs.rs000064400000000000000000000014671046102023000162150ustar 00000000000000//- // 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); } proptest-1.6.0/src/arbitrary/_std/io.rs000064400000000000000000000105001046102023000162000ustar 00000000000000//- // 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 ); } proptest-1.6.0/src/arbitrary/_std/mod.rs000064400000000000000000000007731046102023000163630ustar 00000000000000//- // 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; proptest-1.6.0/src/arbitrary/_std/net.rs000064400000000000000000000062251046102023000163700ustar 00000000000000//- // 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 ); } proptest-1.6.0/src/arbitrary/_std/panic.rs000064400000000000000000000011031046102023000166620ustar 00000000000000//- // 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); } proptest-1.6.0/src/arbitrary/_std/path.rs000064400000000000000000000105601046102023000165330ustar 00000000000000//- // 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::*; use crate::{ arbitrary::{SMapped, StrategyFor}, path::PathParams, prelude::{any, any_with, Arbitrary, Strategy}, std_facade::{string::ToString, Arc, Box, Rc, String, Vec}, strategy::{statics::static_map, MapInto}, }; arbitrary!(StripPrefixError; Path::new("").strip_prefix("a").unwrap_err()); /// A private type (not actually pub) representing the output of [`PathParams`] that can't be /// referred to by API users. /// /// The goal of this type is to encapsulate the output of `PathParams`. If this layer weren't /// present, the type of `::Strategy` would be `SMapped<(bool, Vec), /// Self>`. This is a problem because it exposes the internal representation of `PathParams` as an /// API. For example, if an additional parameter of randomness (e.g. another bool) were added, the /// type of `Strategy` would change. /// /// With `PathParamsOutput`, the type of `Strategy` is `SMapped`, which is a /// type that can't be named directly---only via `::Strategy`. The internal /// representation of `PathParams` can be changed without affecting the API. #[derive(Debug)] pub struct PathParamsOutput { is_absolute: bool, components: Vec, } impl Arbitrary for PathParamsOutput { type Parameters = PathParams; type Strategy = SMapped<(bool, Vec), Self>; fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { static_map( ( any::(), any_with::>(( args.components(), args.component_regex(), )), ), |(is_absolute, components)| Self { is_absolute, components, }, ) } } /// This implementation accepts as its argument a [`PathParams`] struct. It generates either a /// relative or an absolute path with equal probability. /// /// Currently, this implementation does not generate: /// /// * Paths that are not valid UTF-8 (this is unlikely to change) /// * Paths with a [`PrefixComponent`](std::path::PrefixComponent) on Windows, e.g. `C:\` (this may /// change in the future) impl Arbitrary for PathBuf { type Parameters = PathParams; type Strategy = SMapped; fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { static_map( any_with::(args), |PathParamsOutput { is_absolute, components, }| { let mut out = PathBuf::new(); if is_absolute { out.push(&MAIN_SEPARATOR.to_string()); } for component in components { // If a component has an embedded / (or \ on Windows), remove it from the // string. let component = component .chars() .filter(|&c| !std::path::is_separator(c)) .collect::(); out.push(&component); } out }, ) } } macro_rules! dst_wrapped { ($($w: ident),*) => { $( /// This implementation is identical to [the `Arbitrary` implementation for /// `PathBuf`](trait.Arbitrary.html#impl-Arbitrary-for-PathBuf). impl Arbitrary for $w { type Parameters = PathParams; type Strategy = MapInto, Self>; fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { any_with::(args).prop_map_into() } } )* } } dst_wrapped!(Box, Rc, Arc); #[cfg(test)] mod test { no_panic_test!( strip_prefix_error => StripPrefixError, path_buf => PathBuf, box_path => Box, rc_path => Rc, arc_path => Arc ); } proptest-1.6.0/src/arbitrary/_std/string.rs000064400000000000000000000247211046102023000171110ustar 00000000000000//- // 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 ); } proptest-1.6.0/src/arbitrary/_std/sync.rs000064400000000000000000000111541046102023000165530ustar 00000000000000//- // 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 (_unused, 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 (_unused, 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) ); } proptest-1.6.0/src/arbitrary/_std/thread.rs000064400000000000000000000043231046102023000170460ustar 00000000000000//- // 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(); () }) } } */ } proptest-1.6.0/src/arbitrary/_std/time.rs000064400000000000000000000031531046102023000165350ustar 00000000000000//- // 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 ); } proptest-1.6.0/src/arbitrary/arrays.rs000064400000000000000000000016561046102023000161550ustar 00000000000000//- // 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; 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) } } #[cfg(test)] mod test { no_panic_test!( array_16 => [u8; 16] ); no_panic_test!( array_1024 => [u8; 1024] ); } proptest-1.6.0/src/arbitrary/functor.rs000064400000000000000000000210421046102023000163230ustar 00000000000000//- // 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)); }; } proptest-1.6.0/src/arbitrary/macros.rs000064400000000000000000000075461046102023000161440ustar 00000000000000//- // 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>()) {} } } )+ }; } proptest-1.6.0/src/arbitrary/mod.rs000064400000000000000000000034641046102023000154320ustar 00000000000000//- // 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>; proptest-1.6.0/src/arbitrary/primitives.rs000064400000000000000000000025261046102023000170440ustar 00000000000000//- // 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::{ f32, f64, i128, i16, i32, i64, i8, isize, u128, u16, u32, u64, u8, usize, }; arbitrary!(bool, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize, 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 ); } proptest-1.6.0/src/arbitrary/sample.rs000064400000000000000000000014621046102023000161300ustar 00000000000000//- // 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() } } proptest-1.6.0/src/arbitrary/traits.rs000064400000000000000000000262071046102023000161610ustar 00000000000000//- // 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. /// /// If you do not have unique constraints on how to generate the data for your /// custom types, consider using [the derive macro] to implement Arbitrary /// /// [generic associated types (GAT)]: https://github.com/rust-lang/rust/issues/44265 /// /// [`Strategy`]: ../strategy/trait.Strategy.html /// /// [the derive macro]: https://docs.rs/proptest-derive/latest/proptest_derive/ /// /// [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) } proptest-1.6.0/src/arbitrary/tuples.rs000064400000000000000000000026231046102023000161630ustar 00000000000000//- // 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) ); } proptest-1.6.0/src/array.rs000064400000000000000000000166161046102023000137750ustar 00000000000000//- // 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 strategies producing fixed-length arrays. //! //! An array of strategies (but only length 1 to 32 for now) is itself a //! strategy which generates arrays of that size drawing elements from the //! corresponding input strategies. //! //! See also [`UniformArrayStrategy`](struct.UniformArrayStrategy.html) for //! easily making a strategy for an array drawn from one strategy. //! //! General implementations are available for sizes 1 through 32. use core::marker::PhantomData; use crate::strategy::*; use crate::test_runner::*; /// A `Strategy` which generates fixed-size arrays containing values drawn from /// an inner strategy. /// /// `T` must be an array type of length 1 to 32 whose values are produced by /// strategy `S`. Instances of this type are normally created by the various /// `uniformXX` functions in this module. /// /// This is mainly useful when the inner strategy is not `Copy`, precluding /// expressing the strategy as `[myStrategy; 32]`, for example. /// /// ## Example /// /// ``` /// use proptest::prelude::*; /// /// proptest! { /// #[test] /// fn test_something(a in prop::array::uniform32(1u32..)) { /// let unexpected = [0u32;32]; /// // `a` is also a [u32;32], so we can compare them directly /// assert_ne!(unexpected, a); /// } /// } /// # fn main() { } /// ``` #[must_use = "strategies do nothing unless used"] #[derive(Clone, Copy, Debug)] pub struct UniformArrayStrategy { strategy: S, _marker: PhantomData, } impl UniformArrayStrategy { /// Directly create a `UniformArrayStrategy`. /// /// This is only intended for advanced use, since the only way to specify /// the array size is with the turbofish operator and explicitly naming the /// type of the values in the array and the strategy itself. /// /// Prefer the `uniformXX` functions at module-level unless something /// precludes their use. pub fn new(strategy: S) -> Self { UniformArrayStrategy { strategy, _marker: PhantomData, } } } /// A `ValueTree` operating over a fixed-size array. #[derive(Clone, Copy, Debug)] pub struct ArrayValueTree { tree: T, shrinker: usize, last_shrinker: Option, } /// Create a strategy to generate fixed-length arrays. /// /// All values within the new strategy are generated using the given /// strategy. /// /// See [`UniformArrayStrategy`](struct.UniformArrayStrategy.html) for /// example usage. pub fn uniform( strategy: S, ) -> UniformArrayStrategy { UniformArrayStrategy { strategy, _marker: PhantomData, } } macro_rules! small_array { ($n:tt $uni:ident) => { /// Create a strategy to generate fixed-length arrays. /// /// All values within the new strategy are generated using the given /// strategy. The length of the array corresponds to the suffix of the /// name of this function. /// /// See [`UniformArrayStrategy`](struct.UniformArrayStrategy.html) for /// example usage. pub fn $uni( strategy: S, ) -> UniformArrayStrategy { UniformArrayStrategy { strategy, _marker: PhantomData, } } }; } impl Strategy for [S; N] { type Tree = ArrayValueTree<[S::Tree; N]>; type Value = [S::Value; N]; fn new_tree(&self, runner: &mut TestRunner) -> NewTree { Ok(ArrayValueTree { tree: unarray::build_array_result(|i| self[i].new_tree(runner))?, shrinker: 0, last_shrinker: None, }) } } impl Strategy for UniformArrayStrategy { type Tree = ArrayValueTree<[S::Tree; N]>; type Value = [S::Value; N]; fn new_tree(&self, runner: &mut TestRunner) -> NewTree { Ok(ArrayValueTree { tree: unarray::build_array_result(|_| { self.strategy.new_tree(runner) })?, shrinker: 0, last_shrinker: None, }) } } impl ValueTree for ArrayValueTree<[T; N]> { type Value = [T::Value; N]; fn current(&self) -> [T::Value; N] { core::array::from_fn(|i| self.tree[i].current()) } fn simplify(&mut self) -> bool { while self.shrinker < N { if self.tree[self.shrinker].simplify() { self.last_shrinker = Some(self.shrinker); return true; } else { self.shrinker += 1; } } false } fn complicate(&mut self) -> bool { if let Some(shrinker) = self.last_shrinker { self.shrinker = shrinker; if self.tree[shrinker].complicate() { true } else { self.last_shrinker = None; false } } else { false } } } small_array!(1 uniform1); small_array!(2 uniform2); small_array!(3 uniform3); small_array!(4 uniform4); small_array!(5 uniform5); small_array!(6 uniform6); small_array!(7 uniform7); small_array!(8 uniform8); small_array!(9 uniform9); small_array!(10 uniform10); small_array!(11 uniform11); small_array!(12 uniform12); small_array!(13 uniform13); small_array!(14 uniform14); small_array!(15 uniform15); small_array!(16 uniform16); small_array!(17 uniform17); small_array!(18 uniform18); small_array!(19 uniform19); small_array!(20 uniform20); small_array!(21 uniform21); small_array!(22 uniform22); small_array!(23 uniform23); small_array!(24 uniform24); small_array!(25 uniform25); small_array!(26 uniform26); small_array!(27 uniform27); small_array!(28 uniform28); small_array!(29 uniform29); small_array!(30 uniform30); small_array!(31 uniform31); small_array!(32 uniform32); #[cfg(test)] mod test { use super::*; #[test] fn shrinks_fully_ltr() { fn pass(a: [i32; 2]) -> bool { a[0] * a[1] <= 9 } let input = [0..32, 0..32]; let mut runner = TestRunner::deterministic(); 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..1000), (1i32..1000)], None); } } proptest-1.6.0/src/bits.rs000064400000000000000000000461071046102023000136160ustar 00000000000000//- // 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. //! Strategies for working with bit sets. //! //! Besides `BitSet` itself, this also defines strategies for all the primitive //! integer types. These strategies are appropriate for integers which are used //! as bit flags, etc; e.g., where the most reasonable simplification of `64` //! is `0` (clearing one bit) and not `63` (clearing one bit but setting 6 //! others). For integers treated as numeric values, see the corresponding //! modules of the `num` module instead. use crate::std_facade::{fmt, Vec}; use core::marker::PhantomData; use core::mem; #[cfg(feature = "bit-set")] use bit_set::BitSet; #[cfg(feature = "bit-set")] use bit_vec::BitVec; use rand::{self, seq::IteratorRandom, Rng}; use crate::collection::SizeRange; use crate::num::sample_uniform_incl; use crate::strategy::*; use crate::test_runner::*; /// Trait for types which can be handled with `BitSetStrategy`. #[cfg_attr(clippy, allow(len_without_is_empty))] pub trait BitSetLike: Clone + fmt::Debug { /// Create a new value of `Self` with space for up to `max` bits, all /// initialised to zero. fn new_bitset(max: usize) -> Self; /// Return an upper bound on the greatest bit set _plus one_. fn len(&self) -> usize; /// Test whether the given bit is set. fn test(&self, ix: usize) -> bool; /// Set the given bit. fn set(&mut self, ix: usize); /// Clear the given bit. fn clear(&mut self, ix: usize); /// Return the number of bits set. /// /// This has a default for backwards compatibility, which simply does a /// linear scan through the bits. Implementations are strongly encouraged /// to override this. fn count(&self) -> usize { let mut n = 0; for i in 0..self.len() { if self.test(i) { n += 1; } } n } } macro_rules! int_bitset { ($typ:ty) => { impl BitSetLike for $typ { fn new_bitset(_: usize) -> Self { 0 } fn len(&self) -> usize { mem::size_of::<$typ>() * 8 } fn test(&self, ix: usize) -> bool { 0 != (*self & ((1 as $typ) << ix)) } fn set(&mut self, ix: usize) { *self |= (1 as $typ) << ix; } fn clear(&mut self, ix: usize) { *self &= !((1 as $typ) << ix); } fn count(&self) -> usize { self.count_ones() as usize } } }; } int_bitset!(u8); int_bitset!(u16); int_bitset!(u32); int_bitset!(u64); int_bitset!(usize); int_bitset!(i8); int_bitset!(i16); int_bitset!(i32); int_bitset!(i64); int_bitset!(isize); #[cfg(feature = "bit-set")] #[cfg_attr(docsrs, doc(cfg(feature = "bit-set")))] impl BitSetLike for BitSet { fn new_bitset(max: usize) -> Self { BitSet::with_capacity(max) } fn len(&self) -> usize { self.capacity() } fn test(&self, bit: usize) -> bool { self.contains(bit) } fn set(&mut self, bit: usize) { self.insert(bit); } fn clear(&mut self, bit: usize) { self.remove(bit); } fn count(&self) -> usize { self.len() } } impl BitSetLike for Vec { fn new_bitset(max: usize) -> Self { vec![false; max] } fn len(&self) -> usize { self.len() } fn test(&self, bit: usize) -> bool { if bit >= self.len() { false } else { self[bit] } } fn set(&mut self, bit: usize) { if bit >= self.len() { self.resize(bit + 1, false); } self[bit] = true; } fn clear(&mut self, bit: usize) { if bit < self.len() { self[bit] = false; } } fn count(&self) -> usize { self.iter().filter(|&&b| b).count() } } /// Generates values as a set of bits between the two bounds. /// /// Values are generated by uniformly setting individual bits to 0 /// or 1 between the bounds. Shrinking iteratively clears bits. #[must_use = "strategies do nothing unless used"] #[derive(Clone, Copy, Debug)] pub struct BitSetStrategy { min: usize, max: usize, mask: Option, } impl BitSetStrategy { /// Create a strategy which generates values where bits between `min` /// (inclusive) and `max` (exclusive) may be set. /// /// Due to the generics, the functions in the typed submodules are usually /// preferable to calling this directly. pub fn new(min: usize, max: usize) -> Self { BitSetStrategy { min, max, mask: None, } } /// Create a strategy which generates values where any bits set (and only /// those bits) in `mask` may be set. pub fn masked(mask: T) -> Self { BitSetStrategy { min: 0, max: mask.len(), mask: Some(mask), } } } impl Strategy for BitSetStrategy { type Tree = BitSetValueTree; type Value = T; fn new_tree(&self, runner: &mut TestRunner) -> NewTree { let mut inner = T::new_bitset(self.max); for bit in self.min..self.max { if self.mask.as_ref().map_or(true, |mask| mask.test(bit)) && runner.rng().gen() { inner.set(bit); } } Ok(BitSetValueTree { inner, shrink: self.min, prev_shrink: None, min_count: 0, }) } } /// Generates bit sets with a particular number of bits set. /// /// Specifically, this strategy is given both a size range and a bit range. To /// produce a new value, it selects a size, then uniformly selects that many /// bits from within the bit range. /// /// Shrinking happens as with [`BitSetStrategy`](struct.BitSetStrategy.html). #[derive(Clone, Debug)] #[must_use = "strategies do nothing unless used"] pub struct SampledBitSetStrategy { size: SizeRange, bits: SizeRange, _marker: PhantomData, } impl SampledBitSetStrategy { /// Create a strategy which generates values where bits within the bounds /// given by `bits` may be set. The number of bits that are set is chosen /// to be in the range given by `size`. /// /// Due to the generics, the functions in the typed submodules are usually /// preferable to calling this directly. /// /// ## Panics /// /// Panics if `size` includes a value that is greater than the number of /// bits in `bits`. pub fn new(size: impl Into, bits: impl Into) -> Self { let size = size.into(); let bits = bits.into(); size.assert_nonempty(); let available_bits = bits.end_excl() - bits.start(); assert!( size.end_excl() <= available_bits + 1, "Illegal SampledBitSetStrategy: have {} bits available, \ but requested size is {}..{}", available_bits, size.start(), size.end_excl() ); SampledBitSetStrategy { size, bits, _marker: PhantomData, } } } impl Strategy for SampledBitSetStrategy { type Tree = BitSetValueTree; type Value = T; fn new_tree(&self, runner: &mut TestRunner) -> NewTree { let mut bits = T::new_bitset(self.bits.end_excl()); let count = sample_uniform_incl( runner, self.size.start(), self.size.end_incl(), ); if bits.len() < count { panic!("not enough bits to sample"); } for bit in self.bits.iter().choose_multiple(runner.rng(), count) { bits.set(bit); } Ok(BitSetValueTree { inner: bits, shrink: self.bits.start(), prev_shrink: None, min_count: self.size.start(), }) } } /// Value tree produced by `BitSetStrategy` and `SampledBitSetStrategy`. #[derive(Clone, Copy, Debug)] pub struct BitSetValueTree { inner: T, shrink: usize, prev_shrink: Option, min_count: usize, } impl ValueTree for BitSetValueTree { type Value = T; fn current(&self) -> T { self.inner.clone() } fn simplify(&mut self) -> bool { if self.inner.count() <= self.min_count { return false; } while self.shrink < self.inner.len() && !self.inner.test(self.shrink) { self.shrink += 1; } if self.shrink >= self.inner.len() { self.prev_shrink = None; false } else { self.prev_shrink = Some(self.shrink); self.inner.clear(self.shrink); self.shrink += 1; true } } fn complicate(&mut self) -> bool { if let Some(bit) = self.prev_shrink.take() { self.inner.set(bit); true } else { false } } } macro_rules! int_api { ($typ:ident, $max:expr) => { #[allow(missing_docs)] pub mod $typ { use super::*; /// Generates integers where all bits may be set. pub const ANY: BitSetStrategy<$typ> = BitSetStrategy { min: 0, max: $max, mask: None, }; /// Generates values where bits between the given bounds may be /// set. pub fn between(min: usize, max: usize) -> BitSetStrategy<$typ> { BitSetStrategy::new(min, max) } /// Generates values where any bits set in `mask` (and no others) /// may be set. pub fn masked(mask: $typ) -> BitSetStrategy<$typ> { BitSetStrategy::masked(mask) } /// Create a strategy which generates values where bits within the /// bounds given by `bits` may be set. The number of bits that are /// set is chosen to be in the range given by `size`. /// /// ## Panics /// /// Panics if `size` includes a value that is greater than the /// number of bits in `bits`. pub fn sampled( size: impl Into, bits: impl Into, ) -> SampledBitSetStrategy<$typ> { SampledBitSetStrategy::new(size, bits) } } }; } int_api!(u8, 8); int_api!(u16, 16); int_api!(u32, 32); int_api!(u64, 64); int_api!(i8, 8); int_api!(i16, 16); int_api!(i32, 32); int_api!(i64, 64); macro_rules! minimal_api { ($md:ident, $typ:ty) => { #[allow(missing_docs)] pub mod $md { use super::*; /// Generates values where bits between the given bounds may be /// set. pub fn between(min: usize, max: usize) -> BitSetStrategy<$typ> { BitSetStrategy::new(min, max) } /// Generates values where any bits set in `mask` (and no others) /// may be set. pub fn masked(mask: $typ) -> BitSetStrategy<$typ> { BitSetStrategy::masked(mask) } /// Create a strategy which generates values where bits within the /// bounds given by `bits` may be set. The number of bits that are /// set is chosen to be in the range given by `size`. /// /// ## Panics /// /// Panics if `size` includes a value that is greater than the /// number of bits in `bits`. pub fn sampled( size: impl Into, bits: impl Into, ) -> SampledBitSetStrategy<$typ> { SampledBitSetStrategy::new(size, bits) } } }; } minimal_api!(usize, usize); minimal_api!(isize, isize); #[cfg(feature = "bit-set")] #[cfg_attr(docsrs, doc(cfg(feature = "bit-set")))] minimal_api!(bitset, BitSet); minimal_api!(bool_vec, Vec); pub(crate) mod varsize { use super::*; use core::iter::FromIterator; #[cfg(feature = "bit-set")] type Inner = BitSet; #[cfg(not(feature = "bit-set"))] type Inner = Vec; /// A bit set is a set of bit flags. #[derive(Debug, Clone)] pub struct VarBitSet(Inner); impl VarBitSet { /// Create a bit set of `len` set values. #[cfg(not(feature = "bit-set"))] pub fn saturated(len: usize) -> Self { Self(vec![true; len]) } /// Create a bit set of `len` set values. #[cfg(feature = "bit-set")] pub fn saturated(len: usize) -> Self { Self(BitSet::from_bit_vec(BitVec::from_elem(len, true))) } #[cfg(not(feature = "bit-set"))] pub(crate) fn iter<'a>(&'a self) -> impl Iterator + 'a { (0..self.len()).into_iter().filter(move |&ix| self.test(ix)) } #[cfg(feature = "bit-set")] pub(crate) fn iter<'a>(&'a self) -> impl Iterator + 'a { self.0.iter() } } impl BitSetLike for VarBitSet { fn new_bitset(max: usize) -> Self { VarBitSet(Inner::new_bitset(max)) } fn len(&self) -> usize { BitSetLike::len(&self.0) } fn test(&self, bit: usize) -> bool { BitSetLike::test(&self.0, bit) } fn set(&mut self, bit: usize) { BitSetLike::set(&mut self.0, bit); } fn clear(&mut self, bit: usize) { BitSetLike::clear(&mut self.0, bit); } fn count(&self) -> usize { BitSetLike::count(&self.0) } } impl FromIterator for VarBitSet { fn from_iter>(into_iter: T) -> Self { let iter = into_iter.into_iter(); let lower_bound = iter.size_hint().0; let mut bits = VarBitSet::new_bitset(lower_bound); for bit in iter { bits.set(bit); } bits } } /* pub(crate) fn between(min: usize, max: usize) -> BitSetStrategy { BitSetStrategy::new(min, max) } pub(crate) fn masked(mask: VarBitSet) -> BitSetStrategy { BitSetStrategy::masked(mask) } */ pub(crate) fn sampled( size: impl Into, bits: impl Into, ) -> SampledBitSetStrategy { SampledBitSetStrategy::new(size, bits) } } pub use self::varsize::VarBitSet; #[cfg(test)] mod test { use super::*; #[test] fn generates_values_in_range() { let input = u32::between(4, 8); let mut runner = TestRunner::default(); for _ in 0..256 { let value = input.new_tree(&mut runner).unwrap().current(); assert!(0 == value & !0xF0u32, "Generate value {}", value); } } #[test] fn generates_values_in_mask() { let mut accum = 0; let mut runner = TestRunner::deterministic(); let input = u32::masked(0xdeadbeef); for _ in 0..1024 { accum |= input.new_tree(&mut runner).unwrap().current(); } assert_eq!(0xdeadbeef, accum); } #[cfg(feature = "bit-set")] #[test] fn mask_bounds_for_bitset_correct() { let mut seen_0 = false; let mut seen_2 = false; let mut mask = BitSet::new(); mask.insert(0); mask.insert(2); let mut runner = TestRunner::deterministic(); let input = bitset::masked(mask); for _ in 0..32 { let v = input.new_tree(&mut runner).unwrap().current(); seen_0 |= v.contains(0); seen_2 |= v.contains(2); } assert!(seen_0); assert!(seen_2); } #[test] fn mask_bounds_for_vecbool_correct() { let mut seen_0 = false; let mut seen_2 = false; let mask = vec![true, false, true, false]; let mut runner = TestRunner::deterministic(); let input = bool_vec::masked(mask); for _ in 0..32 { let v = input.new_tree(&mut runner).unwrap().current(); assert_eq!(4, v.len()); seen_0 |= v[0]; seen_2 |= v[2]; } assert!(seen_0); assert!(seen_2); } #[test] fn shrinks_to_zero() { let input = u32::between(4, 24); let mut runner = TestRunner::default(); for _ in 0..256 { let mut value = input.new_tree(&mut runner).unwrap(); let mut prev = value.current(); while value.simplify() { let v = value.current(); assert!( 1 == (prev & !v).count_ones(), "Shrank from {} to {}", prev, v ); prev = v; } assert_eq!(0, value.current()); } } #[test] fn complicates_to_previous() { let input = u32::between(4, 24); let mut runner = TestRunner::default(); for _ in 0..256 { let mut value = input.new_tree(&mut runner).unwrap(); let orig = value.current(); if value.simplify() { assert!(value.complicate()); assert_eq!(orig, value.current()); } } } #[test] fn sampled_selects_correct_sizes_and_bits() { let input = u32::sampled(4..8, 10..20); let mut seen_counts = [0; 32]; let mut seen_bits = [0; 32]; let mut runner = TestRunner::deterministic(); for _ in 0..2048 { let value = input.new_tree(&mut runner).unwrap().current(); let count = value.count_ones() as usize; assert!(count >= 4 && count < 8); seen_counts[count] += 1; for bit in 0..32 { if 0 != value & (1 << bit) { assert!(bit >= 10 && bit < 20); seen_bits[bit] += value; } } } for i in 4..8 { assert!(seen_counts[i] >= 256 && seen_counts[i] < 1024); } let least_seen_bit_count = seen_bits[10..20].iter().cloned().min().unwrap(); let most_seen_bit_count = seen_bits[10..20].iter().cloned().max().unwrap(); assert_eq!(1, most_seen_bit_count / least_seen_bit_count); } #[test] fn sampled_doesnt_shrink_below_min_size() { let input = u32::sampled(4..8, 10..20); let mut runner = TestRunner::default(); for _ in 0..256 { let mut value = input.new_tree(&mut runner).unwrap(); while value.simplify() {} assert_eq!(4, value.current().count_ones()); } } #[test] fn test_sanity() { check_strategy_sanity(u32::masked(0xdeadbeef), None); } } proptest-1.6.0/src/bool.rs000064400000000000000000000067451046102023000136140ustar 00000000000000//- // 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::*; use rand::Rng; /// 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, runner: &mut TestRunner) -> NewTree { Ok(BoolValueTree::new(runner.rng().gen())) } } /// 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, runner: &mut TestRunner) -> NewTree { Ok(BoolValueTree::new(runner.rng().gen_bool(self.0))) } } /// The `ValueTree` to shrink booleans to false. #[derive(Clone, Copy, Debug)] pub struct BoolValueTree { current: bool, state: ShrinkState, } #[derive(Clone, Copy, Debug, PartialEq)] enum ShrinkState { Untouched, Simplified, Final, } impl BoolValueTree { fn new(current: bool) -> Self { BoolValueTree { current, state: ShrinkState::Untouched, } } } impl ValueTree for BoolValueTree { type Value = bool; fn current(&self) -> bool { self.current } fn simplify(&mut self) -> bool { match self.state { ShrinkState::Untouched if self.current => { self.current = false; self.state = ShrinkState::Simplified; true } ShrinkState::Untouched | ShrinkState::Simplified | ShrinkState::Final => { self.state = ShrinkState::Final; false } } } fn complicate(&mut self) -> bool { match self.state { ShrinkState::Untouched | ShrinkState::Final => { self.state = ShrinkState::Final; false } ShrinkState::Simplified => { self.current = true; self.state = ShrinkState::Final; true } } } } #[cfg(test)] mod test { use super::*; #[test] fn test_sanity() { check_strategy_sanity(ANY, None); } #[test] fn shrinks_properly() { let mut tree = BoolValueTree::new(true); assert!(tree.simplify()); assert!(!tree.current()); assert!(!tree.clone().simplify()); assert!(tree.complicate()); assert!(!tree.clone().complicate()); assert!(tree.current()); assert!(!tree.simplify()); assert!(tree.current()); tree = BoolValueTree::new(false); assert!(!tree.clone().simplify()); assert!(!tree.clone().complicate()); assert!(!tree.current()); } } proptest-1.6.0/src/char.rs000064400000000000000000000322201046102023000135610ustar 00000000000000//- // 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 `char` values. //! //! Unlike most strategies in Proptest, character generation is by default //! biased to particular values known to be difficult to handle in various //! circumstances. //! //! The main things of interest are `any()` to generate truly arbitrary //! characters, and `range()` and `ranges()` to select characters from //! inclusive ranges. use crate::std_facade::Cow; use core::ops::RangeInclusive; use rand::Rng; use crate::num; use crate::strategy::*; use crate::test_runner::*; /// An inclusive char range from fst to snd. type CharRange = RangeInclusive; /// A default set of characters to consider as "special" during character /// generation. /// /// Most of the characters here were chosen specifically because they are /// difficult to handle in particular contexts. pub const DEFAULT_SPECIAL_CHARS: &[char] = &[ // Things to give shell scripts and filesystem logic difficulties '/', '\\', '$', '.', '*', '{', '\'', '"', '`', ':', // Characters with special significance in URLs and elsewhere '?', '%', '=', '&', '<', // Interesting ASCII control characters // NUL, HT, CR, LF, VT ESC DEL '\x00', '\t', '\r', '\n', '\x0B', '\x1B', '\x7F', // ¥ both to test simple Unicode handling and because it has interesting // properties on MS Shift-JIS systems. '¥', // No non-Unicode encoding has both ¥ and Ѩ 'Ѩ', // In UTF-8, Ⱥ increases in length from 2 to 3 bytes when lowercased 'Ⱥ', // More Unicode edge-cases: BOM, replacement character, RTL override, and non-BMP '\u{FEFF}', '\u{FFFD}', '\u{202E}', '🕴', ]; /// A default sequence of ranges used preferentially when generating random /// characters. pub const DEFAULT_PREFERRED_RANGES: &[CharRange] = &[ // ASCII printable ' '..='~', ' '..='~', ' '..='~', ' '..='~', ' '..='~', // Latin-1 '\u{0040}'..='\u{00ff}', ]; /// Selects a random character the way `CharStrategy` does. /// /// If `special` is non-empty, there is a 50% chance that a character from this /// array is chosen randomly, and will be returned if that character falls /// within `ranges`. /// /// If `preferred` is non-empty, there is a 50% chance that any generation /// which gets past the `special` step picks a random element from this list, /// then a random character from within that range (both endpoints inclusive). /// That character will be returned if it falls within `ranges`. /// /// In all other cases, an element is picked randomly from `ranges` and a /// random character within the range (both endpoints inclusive) is chosen and /// returned. /// /// Notice that in all cases, `ranges` completely defines the set of characters /// that can possibly be defined. /// /// It is legal for ranges in all cases to contain non-characters. /// /// Both `preferred` and `ranges` bias selection towards characters in smaller /// ranges. This is deliberate. `preferred` is usually tuned to select /// particular characters anyway. `ranges` is usually derived from some /// external property, and the fact that a range is small often means it is /// more interesting. pub fn select_char( rnd: &mut impl Rng, special: &[char], preferred: &[CharRange], ranges: &[CharRange], ) -> char { let (base, offset) = select_range_index(rnd, special, preferred, ranges); ::core::char::from_u32(base + offset).expect("bad character selected") } fn select_range_index( rnd: &mut impl Rng, special: &[char], preferred: &[CharRange], ranges: &[CharRange], ) -> (u32, u32) { fn in_range(ranges: &[CharRange], ch: char) -> Option<(u32, u32)> { ranges .iter() .find(|r| ch >= *r.start() && ch <= *r.end()) .map(|r| (*r.start() as u32, ch as u32 - *r.start() as u32)) } if !special.is_empty() && rnd.gen() { let s = special[rnd.gen_range(0..special.len())]; if let Some(ret) = in_range(ranges, s) { return ret; } } if !preferred.is_empty() && rnd.gen() { let range = preferred[rnd.gen_range(0..preferred.len())].clone(); if let Some(ch) = ::core::char::from_u32( rnd.gen_range(*range.start() as u32..*range.end() as u32 + 1), ) { if let Some(ret) = in_range(ranges, ch) { return ret; } } } for _ in 0..65_536 { let range = ranges[rnd.gen_range(0..ranges.len())].clone(); if let Some(ch) = ::core::char::from_u32( rnd.gen_range(*range.start() as u32..*range.end() as u32 + 1), ) { return (*range.start() as u32, ch as u32 - *range.start() as u32); } } // Give up and return a character we at least know is valid. (*ranges[0].start() as u32, 0) } /// Strategy for generating `char`s. /// /// Character selection is more sophisticated than integer selection. Naïve /// selection (particularly in the larger context of generating strings) would /// result in starting inputs like `ꂡ螧轎ቶᢹ糦狥芹ᘆ㶏曊ᒀ踔虙ჲ` and "simplified" /// inputs consisting mostly of control characters. It also has difficulty /// locating edge cases, since the vast majority of code points (such as the /// enormous CJK regions) don't cause problems for anything with even basic /// Unicode support. /// /// Instead, character selection is always based on explicit ranges, and is /// designed to bias to specifically chosen characters and character ranges to /// produce inputs that are both more useful and easier for humans to /// understand. There are also hard-wired simplification targets based on ASCII /// instead of simply simplifying towards NUL to avoid problematic inputs being /// reduced to a bunch of NUL characters. /// /// Shrinking never crosses ranges. If you have a complex range like `[A-Za-z]` /// and the starting point `x` is chosen, it will not shrink to the first `A-Z` /// group, but rather simply to `a`. /// /// The usual way to get instances of this class is with the module-level `ANY` /// constant or `range` function. Directly constructing a `CharStrategy` is /// only necessary for complex ranges or to override the default biases. #[derive(Debug, Clone)] #[must_use = "strategies do nothing unless used"] pub struct CharStrategy<'a> { special: Cow<'a, [char]>, preferred: Cow<'a, [CharRange]>, ranges: Cow<'a, [CharRange]>, } impl<'a> CharStrategy<'a> { /// Construct a new `CharStrategy` with the parameters it will pass to the /// function underlying `select_char()`. /// /// All arguments as per `select_char()`. pub fn new( special: Cow<'a, [char]>, preferred: Cow<'a, [CharRange]>, ranges: Cow<'a, [CharRange]>, ) -> Self { CharStrategy { special, preferred, ranges, } } /// Same as `CharStrategy::new()` but using `Cow::Borrowed` for all parts. pub fn new_borrowed( special: &'a [char], preferred: &'a [CharRange], ranges: &'a [CharRange], ) -> Self { CharStrategy::new( Cow::Borrowed(special), Cow::Borrowed(preferred), Cow::Borrowed(ranges), ) } } const WHOLE_RANGE: &[CharRange] = &['\x00'..=::core::char::MAX]; /// Creates a `CharStrategy` which picks from literally any character, with the /// default biases. pub fn any() -> CharStrategy<'static> { CharStrategy { special: Cow::Borrowed(DEFAULT_SPECIAL_CHARS), preferred: Cow::Borrowed(DEFAULT_PREFERRED_RANGES), ranges: Cow::Borrowed(WHOLE_RANGE), } } /// Creates a `CharStrategy` which selects characters within the given /// endpoints, inclusive, using the default biases. pub fn range(start: char, end: char) -> CharStrategy<'static> { CharStrategy { special: Cow::Borrowed(DEFAULT_SPECIAL_CHARS), preferred: Cow::Borrowed(DEFAULT_PREFERRED_RANGES), ranges: Cow::Owned(vec![start..=end]), } } /// Creates a `CharStrategy` which selects characters within the given ranges, /// all inclusive, using the default biases. pub fn ranges(ranges: Cow<[CharRange]>) -> CharStrategy { CharStrategy { special: Cow::Borrowed(DEFAULT_SPECIAL_CHARS), preferred: Cow::Borrowed(DEFAULT_PREFERRED_RANGES), ranges, } } /// The `ValueTree` corresponding to `CharStrategy`. #[derive(Debug, Clone, Copy)] pub struct CharValueTree { value: num::u32::BinarySearch, } impl<'a> Strategy for CharStrategy<'a> { type Tree = CharValueTree; type Value = char; fn new_tree(&self, runner: &mut TestRunner) -> NewTree { let (base, offset) = select_range_index( runner.rng(), &self.special, &self.preferred, &self.ranges, ); // Select a minimum point more convenient than 0 let start = base + offset; let bottom = if start >= '¡' as u32 && base < '¡' as u32 { '¡' as u32 } else if start >= 'a' as u32 && base < 'a' as u32 { 'a' as u32 } else if start >= 'A' as u32 && base < 'A' as u32 { 'A' as u32 } else if start >= '0' as u32 && base < '0' as u32 { '0' as u32 } else if start >= ' ' as u32 && base < ' ' as u32 { ' ' as u32 } else { base }; Ok(CharValueTree { value: num::u32::BinarySearch::new_above(bottom, start), }) } } impl CharValueTree { fn reposition(&mut self) { while ::core::char::from_u32(self.value.current()).is_none() { if !self.value.complicate() { panic!("Converged to non-char value"); } } } } impl ValueTree for CharValueTree { type Value = char; fn current(&self) -> char { ::core::char::from_u32(self.value.current()) .expect("Generated non-char value") } fn simplify(&mut self) -> bool { if self.value.simplify() { self.reposition(); true } else { false } } fn complicate(&mut self) -> bool { if self.value.complicate() { self.reposition(); true } else { false } } } #[cfg(test)] mod test { use std::cmp::{max, min}; use std::vec::Vec; use super::*; use crate::collection; proptest! { #[test] fn stays_in_range(input_ranges in collection::vec( (0..::std::char::MAX as u32, 0..::std::char::MAX as u32), 1..5)) { let input = ranges(Cow::Owned(input_ranges.iter().map( |&(lo, hi)| ::std::char::from_u32(lo).and_then( |lo| ::std::char::from_u32(hi).map( |hi| min(lo, hi) ..= max(lo, hi))) .ok_or_else(|| TestCaseError::reject("non-char"))) .collect::,_>>()?)); let mut runner = TestRunner::default(); for _ in 0..256 { let mut value = input.new_tree(&mut runner).unwrap(); loop { let ch = value.current() as u32; assert!(input_ranges.iter().any( |&(lo, hi)| ch >= min(lo, hi) && ch <= max(lo, hi))); if !value.simplify() { break; } } } } } #[test] fn applies_desired_bias() { let mut men_in_business_suits_levitating = 0; let mut ascii_printable = 0; let mut runner = TestRunner::deterministic(); for _ in 0..1024 { let ch = any().new_tree(&mut runner).unwrap().current(); if '🕴' == ch { men_in_business_suits_levitating += 1; } else if ch >= ' ' && ch <= '~' { ascii_printable += 1; } } assert!(ascii_printable >= 256); assert!(men_in_business_suits_levitating >= 1); } #[test] fn doesnt_shrink_to_ascii_control() { let mut accepted = 0; let mut runner = TestRunner::deterministic(); for _ in 0..256 { let mut value = any().new_tree(&mut runner).unwrap(); if value.current() <= ' ' { continue; } while value.simplify() {} assert!(value.current() >= ' '); accepted += 1; } assert!(accepted >= 200); } #[test] fn test_sanity() { check_strategy_sanity( any(), Some(CheckStrategySanityOptions { // `simplify()` can itself `complicate()` back to the starting // position, so the overly strict complicate-after-simplify check // must be disabled. strict_complicate_after_simplify: false, ..CheckStrategySanityOptions::default() }), ); } } proptest-1.6.0/src/collection.rs000064400000000000000000000606761046102023000150170ustar 00000000000000//- // 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. //! Strategies for generating `std::collections` of values. use core::cmp::Ord; use core::hash::Hash; use core::ops::{Add, Range, RangeInclusive, RangeTo, RangeToInclusive}; use core::usize; use crate::std_facade::{ fmt, BTreeMap, BTreeSet, BinaryHeap, LinkedList, Vec, VecDeque, }; #[cfg(feature = "std")] use crate::std_facade::{HashMap, HashSet}; use crate::bits::{BitSetLike, VarBitSet}; use crate::num::sample_uniform_incl; use crate::strategy::*; use crate::test_runner::*; use crate::tuple::TupleValueTree; //============================================================================== // SizeRange //============================================================================== /// The minimum and maximum range/bounds on the size of a collection. /// The interval must form a subset of `[0, std::usize::MAX)`. /// /// A value like `0..=std::usize::MAX` will still be accepted but will silently /// truncate the maximum to `std::usize::MAX - 1`. /// /// The `Default` is `0..PROPTEST_MAX_DEFAULT_SIZE_RANGE`. The max can be set with /// the `PROPTEST_MAX_DEFAULT_SIZE_RANGE` env var, which defaults to `100`. #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct SizeRange(Range); /// Creates a `SizeRange` from some value that is convertible into it. pub fn size_range(from: impl Into) -> SizeRange { from.into() } impl Default for SizeRange { /// Constructs a `SizeRange` equivalent to `size_range(0..PROPTEST_MAX_DEFAULT_SIZE_RANGE)`. /// The max can be set with the `PROPTEST_MAX_DEFAULT_SIZE_RANGE` env var, which defaults to `100`. fn default() -> Self { size_range(0..Config::default().max_default_size_range) } } impl SizeRange { /// Creates a `SizeBounds` from a `RangeInclusive`. pub fn new(range: RangeInclusive) -> Self { range.into() } // Don't rely on these existing internally: /// Merges self together with some other argument producing a product /// type expected by some implementations of `A: Arbitrary` in /// `A::Parameters`. This can be more ergonomic to work with and may /// help type inference. pub fn with(self, and: X) -> product_type![Self, X] { product_pack![self, and] } /// Merges self together with some other argument generated with a /// default value producing a product type expected by some /// implementations of `A: Arbitrary` in `A::Parameters`. /// This can be more ergonomic to work with and may help type inference. pub fn lift(self) -> product_type![Self, X] { self.with(Default::default()) } /// The lower bound of the range (inclusive). pub fn start(&self) -> usize { self.0.start } /// Extract the ends `[low, high]` of a `SizeRange`. pub fn start_end_incl(&self) -> (usize, usize) { (self.start(), self.end_incl()) } /// The upper bound of the range (inclusive). pub fn end_incl(&self) -> usize { self.0.end - 1 } /// The upper bound of the range (exclusive). pub fn end_excl(&self) -> usize { self.0.end } pub(crate) fn iter(&self) -> impl Iterator { self.0.clone().into_iter() } pub(crate) fn is_empty(&self) -> bool { self.start() == self.end_excl() } pub(crate) fn assert_nonempty(&self) { if self.is_empty() { panic!( "Invalid use of empty size range. (hint: did you \ accidentally write {}..{} where you meant {}..={} \ somewhere?)", self.start(), self.end_excl(), self.start(), self.end_excl() ); } } } /// Given `(low: usize, high: usize)`, /// then a size range of `[low..high)` is the result. impl From<(usize, usize)> for SizeRange { fn from((low, high): (usize, usize)) -> Self { size_range(low..high) } } /// Given `exact`, then a size range of `[exact, exact]` is the result. impl From for SizeRange { fn from(exact: usize) -> Self { size_range(exact..=exact) } } /// Given `..high`, then a size range `[0, high)` is the result. impl From> for SizeRange { fn from(high: RangeTo) -> Self { size_range(0..high.end) } } /// Given `low .. high`, then a size range `[low, high)` is the result. impl From> for SizeRange { fn from(r: Range) -> Self { SizeRange(r) } } /// Given `low ..= high`, then a size range `[low, high]` is the result. impl From> for SizeRange { fn from(r: RangeInclusive) -> Self { size_range(*r.start()..r.end().saturating_add(1)) } } /// Given `..=high`, then a size range `[0, high]` is the result. impl From> for SizeRange { fn from(high: RangeToInclusive) -> Self { size_range(0..=high.end) } } impl From for Range { fn from(size_range: SizeRange) -> Self { size_range.0 } } /// Adds `usize` to both start and end of the bounds. /// /// Panics if adding to either end overflows `usize`. impl Add for SizeRange { type Output = SizeRange; fn add(self, rhs: usize) -> Self::Output { let (start, end) = self.start_end_incl(); size_range((start + rhs)..=(end + rhs)) } } //============================================================================== // Strategies //============================================================================== /// Strategy to create `Vec`s with a length in a certain range. /// /// Created by the `vec()` function in the same module. #[must_use = "strategies do nothing unless used"] #[derive(Clone, Debug)] pub struct VecStrategy { element: T, size: SizeRange, } /// Create a strategy to generate `Vec`s containing elements drawn from /// `element` and with a size range given by `size`. /// /// To make a `Vec` with a fixed number of elements, each with its own /// strategy, you can instead make a `Vec` of strategies (boxed if necessary). pub fn vec( element: T, size: impl Into, ) -> VecStrategy { let size = size.into(); size.assert_nonempty(); VecStrategy { element, size } } mapfn! { [] fn VecToDeque[](vec: Vec) -> VecDeque { vec.into() } } opaque_strategy_wrapper! { /// Strategy to create `VecDeque`s with a length in a certain range. /// /// Created by the `vec_deque()` function in the same module. #[derive(Clone, Debug)] pub struct VecDequeStrategy[][where T : Strategy]( statics::Map, VecToDeque>) -> VecDequeValueTree; /// `ValueTree` corresponding to `VecDequeStrategy`. #[derive(Clone, Debug)] pub struct VecDequeValueTree[][where T : ValueTree]( statics::Map, VecToDeque>) -> VecDeque; } /// Create a strategy to generate `VecDeque`s containing elements drawn from /// `element` and with a size range given by `size`. pub fn vec_deque( element: T, size: impl Into, ) -> VecDequeStrategy { VecDequeStrategy(statics::Map::new(vec(element, size), VecToDeque)) } mapfn! { [] fn VecToLl[](vec: Vec) -> LinkedList { vec.into_iter().collect() } } opaque_strategy_wrapper! { /// Strategy to create `LinkedList`s with a length in a certain range. /// /// Created by the `linkedlist()` function in the same module. #[derive(Clone, Debug)] pub struct LinkedListStrategy[][where T : Strategy]( statics::Map, VecToLl>) -> LinkedListValueTree; /// `ValueTree` corresponding to `LinkedListStrategy`. #[derive(Clone, Debug)] pub struct LinkedListValueTree[][where T : ValueTree]( statics::Map, VecToLl>) -> LinkedList; } /// Create a strategy to generate `LinkedList`s containing elements drawn from /// `element` and with a size range given by `size`. pub fn linked_list( element: T, size: impl Into, ) -> LinkedListStrategy { LinkedListStrategy(statics::Map::new(vec(element, size), VecToLl)) } mapfn! { [] fn VecToBinHeap[](vec: Vec) -> BinaryHeap { vec.into() } } opaque_strategy_wrapper! { /// Strategy to create `BinaryHeap`s with a length in a certain range. /// /// Created by the `binary_heap()` function in the same module. #[derive(Clone, Debug)] pub struct BinaryHeapStrategy[][where T : Strategy, T::Value : Ord]( statics::Map, VecToBinHeap>) -> BinaryHeapValueTree; /// `ValueTree` corresponding to `BinaryHeapStrategy`. #[derive(Clone, Debug)] pub struct BinaryHeapValueTree[][where T : ValueTree, T::Value : Ord]( statics::Map, VecToBinHeap>) -> BinaryHeap; } /// Create a strategy to generate `BinaryHeap`s containing elements drawn from /// `element` and with a size range given by `size`. pub fn binary_heap( element: T, size: impl Into, ) -> BinaryHeapStrategy where T::Value: Ord, { BinaryHeapStrategy(statics::Map::new(vec(element, size), VecToBinHeap)) } mapfn! { {#[cfg(feature = "std")]} [] fn VecToHashSet[](vec: Vec) -> HashSet { vec.into_iter().collect() } } #[derive(Debug, Clone, Copy)] struct MinSize(usize); #[cfg(feature = "std")] impl statics::FilterFn> for MinSize { fn apply(&self, set: &HashSet) -> bool { set.len() >= self.0 } } opaque_strategy_wrapper! { {#[cfg(feature = "std")]} {#[cfg_attr(docsrs, doc(cfg(feature = "std")))]} /// Strategy to create `HashSet`s with a length in a certain range. /// /// Created by the `hash_set()` function in the same module. #[derive(Clone, Debug)] pub struct HashSetStrategy[][where T : Strategy, T::Value : Hash + Eq]( statics::Filter, VecToHashSet>, MinSize>) -> HashSetValueTree; /// `ValueTree` corresponding to `HashSetStrategy`. #[derive(Clone, Debug)] pub struct HashSetValueTree[][where T : ValueTree, T::Value : Hash + Eq]( statics::Filter, VecToHashSet>, MinSize>) -> HashSet; } /// Create a strategy to generate `HashSet`s containing elements drawn from /// `element` and with a size range given by `size`. /// /// This strategy will implicitly do local rejects to ensure that the `HashSet` /// has at least the minimum number of elements, in case `element` should /// produce duplicate values. #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub fn hash_set( element: T, size: impl Into, ) -> HashSetStrategy where T::Value: Hash + Eq, { let size = size.into(); HashSetStrategy(statics::Filter::new( statics::Map::new(vec(element, size.clone()), VecToHashSet), "HashSet minimum size".into(), MinSize(size.start()), )) } mapfn! { [] fn VecToBTreeSet[](vec: Vec) -> BTreeSet { vec.into_iter().collect() } } impl statics::FilterFn> for MinSize { fn apply(&self, set: &BTreeSet) -> bool { set.len() >= self.0 } } opaque_strategy_wrapper! { /// Strategy to create `BTreeSet`s with a length in a certain range. /// /// Created by the `btree_set()` function in the same module. #[derive(Clone, Debug)] pub struct BTreeSetStrategy[][where T : Strategy, T::Value : Ord]( statics::Filter, VecToBTreeSet>, MinSize>) -> BTreeSetValueTree; /// `ValueTree` corresponding to `BTreeSetStrategy`. #[derive(Clone, Debug)] pub struct BTreeSetValueTree[][where T : ValueTree, T::Value : Ord]( statics::Filter, VecToBTreeSet>, MinSize>) -> BTreeSet; } /// Create a strategy to generate `BTreeSet`s containing elements drawn from /// `element` and with a size range given by `size`. /// /// This strategy will implicitly do local rejects to ensure that the /// `BTreeSet` has at least the minimum number of elements, in case `element` /// should produce duplicate values. pub fn btree_set( element: T, size: impl Into, ) -> BTreeSetStrategy where T::Value: Ord, { let size = size.into(); BTreeSetStrategy(statics::Filter::new( statics::Map::new(vec(element, size.clone()), VecToBTreeSet), "BTreeSet minimum size".into(), MinSize(size.start()), )) } mapfn! { {#[cfg(feature = "std")]} [] fn VecToHashMap[] (vec: Vec<(K, V)>) -> HashMap { vec.into_iter().collect() } } #[cfg(feature = "std")] impl statics::FilterFn> for MinSize { fn apply(&self, map: &HashMap) -> bool { map.len() >= self.0 } } opaque_strategy_wrapper! { {#[cfg(feature = "std")]} {#[cfg_attr(docsrs, doc(cfg(feature = "std")))]} /// Strategy to create `HashMap`s with a length in a certain range. /// /// Created by the `hash_map()` function in the same module. #[derive(Clone, Debug)] pub struct HashMapStrategy[] [where K : Strategy, V : Strategy, K::Value : Hash + Eq]( statics::Filter, VecToHashMap>, MinSize>) -> HashMapValueTree; /// `ValueTree` corresponding to `HashMapStrategy`. #[derive(Clone, Debug)] pub struct HashMapValueTree[] [where K : ValueTree, V : ValueTree, K::Value : Hash + Eq]( statics::Filter>, VecToHashMap>, MinSize>) -> HashMap; } /// Create a strategy to generate `HashMap`s containing keys and values drawn /// from `key` and `value` respectively, and with a size within the given /// range. /// /// This strategy will implicitly do local rejects to ensure that the `HashMap` /// has at least the minimum number of elements, in case `key` should produce /// duplicate values. #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub fn hash_map( key: K, value: V, size: impl Into, ) -> HashMapStrategy where K::Value: Hash + Eq, { let size = size.into(); HashMapStrategy(statics::Filter::new( statics::Map::new(vec((key, value), size.clone()), VecToHashMap), "HashMap minimum size".into(), MinSize(size.start()), )) } mapfn! { [] fn VecToBTreeMap[] (vec: Vec<(K, V)>) -> BTreeMap { vec.into_iter().collect() } } impl statics::FilterFn> for MinSize { fn apply(&self, map: &BTreeMap) -> bool { map.len() >= self.0 } } opaque_strategy_wrapper! { /// Strategy to create `BTreeMap`s with a length in a certain range. /// /// Created by the `btree_map()` function in the same module. #[derive(Clone, Debug)] pub struct BTreeMapStrategy[] [where K : Strategy, V : Strategy, K::Value : Ord]( statics::Filter, VecToBTreeMap>, MinSize>) -> BTreeMapValueTree; /// `ValueTree` corresponding to `BTreeMapStrategy`. #[derive(Clone, Debug)] pub struct BTreeMapValueTree[] [where K : ValueTree, V : ValueTree, K::Value : Ord]( statics::Filter>, VecToBTreeMap>, MinSize>) -> BTreeMap; } /// Create a strategy to generate `BTreeMap`s containing keys and values drawn /// from `key` and `value` respectively, and with a size within the given /// range. /// /// This strategy will implicitly do local rejects to ensure that the /// `BTreeMap` has at least the minimum number of elements, in case `key` /// should produce duplicate values. pub fn btree_map( key: K, value: V, size: impl Into, ) -> BTreeMapStrategy where K::Value: Ord, { let size = size.into(); BTreeMapStrategy(statics::Filter::new( statics::Map::new(vec((key, value), size.clone()), VecToBTreeMap), "BTreeMap minimum size".into(), MinSize(size.start()), )) } #[derive(Clone, Copy, Debug)] enum Shrink { DeleteElement(usize), ShrinkElement(usize), } /// `ValueTree` corresponding to `VecStrategy`. #[derive(Clone, Debug)] pub struct VecValueTree { elements: Vec, included_elements: VarBitSet, min_size: usize, shrink: Shrink, prev_shrink: Option, } impl Strategy for VecStrategy { type Tree = VecValueTree; type Value = Vec; fn new_tree(&self, runner: &mut TestRunner) -> NewTree { let (start, end) = self.size.start_end_incl(); let max_size = sample_uniform_incl(runner, start, end); let mut elements = Vec::with_capacity(max_size); while elements.len() < max_size { elements.push(self.element.new_tree(runner)?); } Ok(VecValueTree { elements, included_elements: VarBitSet::saturated(max_size), min_size: start, shrink: Shrink::DeleteElement(0), prev_shrink: None, }) } } impl Strategy for Vec { type Tree = VecValueTree; type Value = Vec; fn new_tree(&self, runner: &mut TestRunner) -> NewTree { let len = self.len(); let elements = self .iter() .map(|t| t.new_tree(runner)) .collect::, Reason>>()?; Ok(VecValueTree { elements, included_elements: VarBitSet::saturated(len), min_size: len, shrink: Shrink::ShrinkElement(0), prev_shrink: None, }) } } impl ValueTree for VecValueTree { type Value = Vec; fn current(&self) -> Vec { self.elements .iter() .enumerate() .filter(|&(ix, _)| self.included_elements.test(ix)) .map(|(_, element)| element.current()) .collect() } fn simplify(&mut self) -> bool { // The overall strategy here is to iteratively delete elements from the // list until we can do so no further, then to shrink each remaining // element in sequence. // // For `complicate()`, we simply undo the last shrink operation, if // there was any. if let Shrink::DeleteElement(ix) = self.shrink { // Can't delete an element if beyond the end of the vec or if it // would put us under the minimum length. if ix >= self.elements.len() || self.included_elements.count() == self.min_size { self.shrink = Shrink::ShrinkElement(0); } else { self.included_elements.clear(ix); self.prev_shrink = Some(self.shrink); self.shrink = Shrink::DeleteElement(ix + 1); return true; } } while let Shrink::ShrinkElement(ix) = self.shrink { if ix >= self.elements.len() { // Nothing more we can do return false; } if !self.included_elements.test(ix) { // No use shrinking something we're not including. self.shrink = Shrink::ShrinkElement(ix + 1); continue; } if !self.elements[ix].simplify() { // Move on to the next element self.shrink = Shrink::ShrinkElement(ix + 1); } else { self.prev_shrink = Some(self.shrink); return true; } } panic!("Unexpected shrink state"); } fn complicate(&mut self) -> bool { match self.prev_shrink { None => false, Some(Shrink::DeleteElement(ix)) => { // Undo the last item we deleted. Can't complicate any further, // so unset prev_shrink. self.included_elements.set(ix); self.prev_shrink = None; true } Some(Shrink::ShrinkElement(ix)) => { if self.elements[ix].complicate() { // Don't unset prev_shrink; we may be able to complicate // again. true } else { // Can't complicate the last element any further. self.prev_shrink = None; false } } } } } //============================================================================== // Tests //============================================================================== #[cfg(test)] mod test { use super::*; use crate::bits; #[test] fn test_vec() { let input = vec(1usize..20usize, 5..20); let mut num_successes = 0; let mut runner = TestRunner::deterministic(); for _ in 0..256 { let case = input.new_tree(&mut runner).unwrap(); let start = case.current(); // Has correct length assert!(start.len() >= 5 && start.len() < 20); // Has at least 2 distinct values assert!(start.iter().map(|&v| v).collect::().len() >= 2); let result = runner.run_one(case, |v| { prop_assert!( v.iter().map(|&v| v).sum::() < 9, "greater than 8" ); Ok(()) }); match result { Ok(true) => num_successes += 1, Err(TestError::Fail(_, value)) => { // The minimal case always has between 5 (due to min // length) and 9 (min element value = 1) elements, and // always sums to exactly 9. assert!( value.len() >= 5 && value.len() <= 9 && value.iter().map(|&v| v).sum::() == 9, "Unexpected minimal value: {:?}", value ); } e => panic!("Unexpected result: {:?}", e), } } assert!(num_successes < 256); } #[test] fn test_vec_sanity() { check_strategy_sanity(vec(0i32..1000, 5..10), None); } #[test] fn test_parallel_vec() { let input = vec![(1u32..10).boxed(), bits::u32::masked(0xF0u32).boxed()]; for _ in 0..256 { let mut runner = TestRunner::default(); let mut case = input.new_tree(&mut runner).unwrap(); loop { let current = case.current(); assert_eq!(2, current.len()); assert!(current[0] >= 1 && current[0] <= 10); assert_eq!(0, (current[1] & !0xF0)); if !case.simplify() { break; } } } } #[cfg(feature = "std")] #[test] fn test_map() { // Only 8 possible keys let input = hash_map("[ab]{3}", "a", 2..3); let mut runner = TestRunner::deterministic(); for _ in 0..256 { let v = input.new_tree(&mut runner).unwrap().current(); assert_eq!(2, v.len()); } } #[cfg(feature = "std")] #[test] fn test_set() { // Only 8 possible values let input = hash_set("[ab]{3}", 2..3); let mut runner = TestRunner::deterministic(); for _ in 0..256 { let v = input.new_tree(&mut runner).unwrap().current(); assert_eq!(2, v.len()); } } } proptest-1.6.0/src/file-preamble000064400000000000000000000005051046102023000147260ustar 00000000000000//- // Copyright 2017 // // 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. proptest-1.6.0/src/lib.rs000064400000000000000000000043511046102023000134160ustar 00000000000000//- // 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. //! # 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://proptest-rs.github.io/proptest/intro.html). #![forbid(future_incompatible)] #![deny(missing_docs, bare_trait_objects)] #![no_std] #![cfg_attr(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_v2, coroutine_trait, never_type) )] #![cfg_attr(all(feature = "std", feature = "unstable"), feature(ip))] #![cfg_attr(docsrs, feature(doc_cfg))] // 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; #[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; #[cfg(feature = "fork")] #[macro_use] extern crate rusty_fork; #[macro_use] mod macros; #[doc(hidden)] #[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; #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub mod path; pub mod result; pub mod sample; #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub mod string; pub mod prelude; #[cfg(feature = "attr-macro")] pub use proptest_macro::property_test; #[cfg(feature = "attr-macro")] #[test] fn compile_tests() { let t = trybuild::TestCases::new(); t.pass("tests/pass/*.rs"); } proptest-1.6.0/src/macros.rs000064400000000000000000000051011046102023000141260ustar 00000000000000//- // 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. //! Macros for internal use to reduce boilerplate. // Pervasive internal sugar macro_rules! mapfn { ($({#[$allmeta:meta]})* $(#[$meta:meta])* [$($vis:tt)*] fn $name:ident[$($gen:tt)*]($parm:ident: $input:ty) -> $output:ty { $($body:tt)* }) => { $(#[$allmeta])* $(#[$meta])* #[derive(Clone, Copy, Debug)] $($vis)* struct $name; $(#[$allmeta])* impl $($gen)* $crate::strategy::statics::MapFn<$input> for $name { type Output = $output; fn apply(&self, $parm: $input) -> $output { $($body)* } } } } macro_rules! delegate_vt_0 { () => { fn current(&self) -> Self::Value { self.0.current() } fn simplify(&mut self) -> bool { self.0.simplify() } fn complicate(&mut self) -> bool { self.0.complicate() } }; } macro_rules! opaque_strategy_wrapper { ($({#[$allmeta:meta]})* $(#[$smeta:meta])* pub struct $stratname:ident [$($sgen:tt)*][$($swhere:tt)*] ($innerstrat:ty) -> $stratvtty:ty; $(#[$vmeta:meta])* pub struct $vtname:ident [$($vgen:tt)*][$($vwhere:tt)*] ($innervt:ty) -> $actualty:ty; ) => { $(#[$allmeta])* $(#[$smeta])* #[must_use = "strategies do nothing unless used"] pub struct $stratname $($sgen)* ($innerstrat) $($swhere)*; $(#[$allmeta])* $(#[$vmeta])* pub struct $vtname $($vgen)* ($innervt) $($vwhere)*; $(#[$allmeta])* impl $($sgen)* Strategy for $stratname $($sgen)* $($swhere)* { type Tree = $stratvtty; type Value = $actualty; fn new_tree(&self, runner: &mut TestRunner) -> NewTree { self.0.new_tree(runner).map($vtname) } } $(#[$allmeta])* impl $($vgen)* ValueTree for $vtname $($vgen)* $($vwhere)* { type Value = $actualty; delegate_vt_0!(); } } } // Example: unwrap_or!(result, err => handle_err(err)); macro_rules! unwrap_or { ($unwrap: expr, $err: ident => $on_err: expr) => { match $unwrap { Ok(ok) => ok, Err($err) => $on_err, } }; } proptest-1.6.0/src/num/float_samplers.rs000064400000000000000000000446061046102023000164710ustar 00000000000000//- // Copyright 2022 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. //! Alternative uniform float samplers. //! These samplers are used over the ones from `rand` because the ones provided by the //! rand crate are prone to overflow. In addition, these are 'high precision' samplers //! that are more appropriate for test data. //! The samplers work by splitting the range into equally sized intervals and selecting //! an iterval at random. That interval is then itself split and a new interval is //! selected at random. The process repeats until the interval only contains two //! floating point values at the bounds. At that stage, one is selected at random and //! returned. pub(crate) use self::f32::F32U; pub(crate) use self::f64::F64U; macro_rules! float_sampler { ($typ: ident, $int_typ: ident, $wrapper: ident) => { pub mod $typ { use rand::prelude::*; use rand::distributions::uniform::{ SampleBorrow, SampleUniform, UniformSampler, }; #[cfg(not(feature = "std"))] use num_traits::float::Float; #[must_use] // Returns the previous float value. In other words the greatest value representable // as a float such that `next_down(a) < a`. `-0.` is treated as `0.`. fn next_down(a: $typ) -> $typ { debug_assert!(a.is_finite() && a > $typ::MIN, "`next_down` invalid input: {}", a); if a == (0.) { -$typ::from_bits(1) } else if a < 0. { $typ::from_bits(a.to_bits() + 1) } else { $typ::from_bits(a.to_bits() - 1) } } #[must_use] // Returns the unit in last place using the definition by John Harrison. // This is the distance between `a` and the next closest float. Note that // `ulp(1) = $typ::EPSILON/2`. fn ulp(a: $typ) -> $typ { debug_assert!(a.is_finite() && a > $typ::MIN, "`ulp` invalid input: {}", a); a.abs() - next_down(a.abs()) } #[derive(Copy, Clone, Debug)] pub(crate) struct $wrapper($typ); impl From<$typ> for $wrapper { fn from(x: $typ) -> Self { $wrapper(x) } } impl From<$wrapper> for $typ { fn from(x: $wrapper) -> Self { x.0 } } #[derive(Clone, Copy, Debug)] pub(crate) struct FloatUniform { low: $typ, high: $typ, intervals: IntervalCollection, inclusive: bool, } impl UniformSampler for FloatUniform { type X = $wrapper; fn new(low: B1, high: B2) -> Self where B1: SampleBorrow + Sized, B2: SampleBorrow + Sized, { let low = low.borrow().0; let high = high.borrow().0; FloatUniform { low, high, intervals: split_interval([low, high]), inclusive: false, } } fn new_inclusive(low: B1, high: B2) -> Self where B1: SampleBorrow + Sized, B2: SampleBorrow + Sized, { let low = low.borrow().0; let high = high.borrow().0; FloatUniform { low, high, intervals: split_interval([low, high]), inclusive: true, } } fn sample(&self, rng: &mut R) -> Self::X { let mut intervals = self.intervals; while intervals.count > 1 { let new_interval = intervals.get(rng.gen_range(0..intervals.count)); intervals = split_interval(new_interval); } let last = intervals.get(0); let result = *last.choose(rng).expect("Slice is not empty"); // These results could happen because the first split might // overshoot one of the bounds. We could resample in this // case but for testing data this is not a problem. let clamped_result = if result < self.low { debug_assert!(self.low - result < self.intervals.step); self.low } else if result > self.high{ debug_assert!(result - self.high < self.intervals.step); self.high } else { result }; if !self.inclusive && clamped_result == self.high { return $wrapper(next_down(self.high)); }; $wrapper(clamped_result) } } impl SampleUniform for $wrapper { type Sampler = FloatUniform; } // Divides the range [low, high] into intervals of size epsilon * max(abs(low, high)); // Note that the one interval may extend out of the range. #[derive(Clone, Copy, Debug)] struct IntervalCollection { start: $typ, step: $typ, count: $int_typ, } fn split_interval([low, high]: [$typ; 2]) -> IntervalCollection { assert!(low.is_finite(), "low finite"); assert!(high.is_finite(), "high finite"); assert!(high - low > 0., "invalid range"); let min_abs = $typ::min(low.abs(), high.abs()); let max_abs = $typ::max(low.abs(), high.abs()); let gap = ulp(max_abs); let (start, step) = if low.abs() < high.abs() { (high, -gap) } else { (low, gap) }; let min_gaps = min_abs / gap; let max_gaps = max_abs / gap; debug_assert!( max_gaps.floor() == max_gaps, "max_gaps is an integer" ); let count = if low.signum() == high.signum() { max_gaps as $int_typ - min_gaps.floor() as $int_typ } else { // `step` is a power of two so `min_gaps` won't be rounded // except possibly to 0. if min_gaps == 0. && min_abs > 0. { max_gaps as $int_typ + 1 } else { max_gaps as $int_typ + min_gaps.ceil() as $int_typ } }; debug_assert!(count - 1 <= 2 * MAX_PRECISE_INT); IntervalCollection { start, step, count, } } impl IntervalCollection { fn get(&self, index: $int_typ) -> [$typ; 2] { assert!(index < self.count, "index out of bounds"); // `index` might be greater that `MAX_PERCISE_INT` // which means `MAX_PRECIST_INT as $typ` would round // to a different number. Fortunately, `index` will // never be larger than `2 * MAX_PRECISE_INT` (as // asserted above). let x = ((index / 2) as $typ).mul_add( 2. * self.step, (index % 2) as $typ * self.step + self.start, ); let y = x + self.step; if self.step > 0. { [x, y] } else { [y, x] } } } // Values greater than MAX_PRECISE_INT may be rounded when converted to float. const MAX_PRECISE_INT: $int_typ = (2 as $int_typ).pow($typ::MANTISSA_DIGITS); #[cfg(test)] mod test { use super::*; use crate::prelude::*; fn sort((left, right): ($typ, $typ)) -> ($typ, $typ) { if left < right { (left, right) } else { (right, left) } } fn finite() -> impl Strategy { prop::num::$typ::NEGATIVE | prop::num::$typ::POSITIVE | prop::num::$typ::NORMAL | prop::num::$typ::SUBNORMAL | prop::num::$typ::ZERO } fn bounds() -> impl Strategy { (finite(), finite()) .prop_filter("Bounds can't be equal", |(a, b)| a != b) .prop_map(sort) } #[test] fn range_test() { use crate::test_runner::{RngAlgorithm, TestRng}; let mut test_rng = TestRng::deterministic_rng(RngAlgorithm::default()); let (low, high) = (-1., 10.); let uniform = FloatUniform::new($wrapper(low), $wrapper(high)); let samples = (0..100) .map(|_| $typ::from(uniform.sample(&mut test_rng))); for s in samples { assert!(low <= s && s < high); } } #[test] fn range_end_bound_test() { use crate::test_runner::{RngAlgorithm, TestRng}; let mut test_rng = TestRng::deterministic_rng(RngAlgorithm::default()); let (low, high) = (1., 1. + $typ::EPSILON); let uniform = FloatUniform::new($wrapper(low), $wrapper(high)); let mut samples = (0..100) .map(|_| $typ::from(uniform.sample(&mut test_rng))); assert!(samples.all(|x| x == 1.)); } #[test] fn inclusive_range_test() { use crate::test_runner::{RngAlgorithm, TestRng}; let mut test_rng = TestRng::deterministic_rng(RngAlgorithm::default()); let (low, high) = (-1., 10.); let uniform = FloatUniform::new_inclusive($wrapper(low), $wrapper(high)); let samples = (0..100) .map(|_| $typ::from(uniform.sample(&mut test_rng))); for s in samples { assert!(low <= s && s <= high); } } #[test] fn inclusive_range_end_bound_test() { use crate::test_runner::{RngAlgorithm, TestRng}; let mut test_rng = TestRng::deterministic_rng(RngAlgorithm::default()); let (low, high) = (1., 1. + $typ::EPSILON); let uniform = FloatUniform::new_inclusive($wrapper(low), $wrapper(high)); let mut samples = (0..100) .map(|_| $typ::from(uniform.sample(&mut test_rng))); assert!(samples.any(|x| x == 1. + $typ::EPSILON)); } #[test] fn all_floats_in_range_are_possible_1() { use crate::test_runner::{RngAlgorithm, TestRng}; let mut test_rng = TestRng::deterministic_rng(RngAlgorithm::default()); let (low, high) = (1. - $typ::EPSILON, 1. + $typ::EPSILON); let uniform = FloatUniform::new_inclusive($wrapper(low), $wrapper(high)); let mut samples = (0..100) .map(|_| $typ::from(uniform.sample(&mut test_rng))); assert!(samples.any(|x| x == 1. - $typ::EPSILON / 2.)); } #[test] fn all_floats_in_range_are_possible_2() { use crate::test_runner::{RngAlgorithm, TestRng}; let mut test_rng = TestRng::deterministic_rng(RngAlgorithm::default()); let (low, high) = (0., MAX_PRECISE_INT as $typ); let uniform = FloatUniform::new_inclusive($wrapper(low), $wrapper(high)); let mut samples = (0..100) .map(|_| $typ::from(uniform.sample(&mut test_rng))) .map(|x| x.fract()); assert!(samples.any(|x| x != 0.)); } #[test] fn max_precise_int_plus_one_is_rounded_down() { assert_eq!(((MAX_PRECISE_INT + 1) as $typ) as $int_typ, MAX_PRECISE_INT); } proptest! { #[test] fn next_down_less_than_float(val in finite()) { prop_assume!(val > $typ::MIN); prop_assert!(next_down(val) < val); } #[test] fn no_value_between_float_and_next_down(val in finite()) { prop_assume!(val > $typ::MIN); let prev = next_down(val); let avg = prev / 2. + val / 2.; prop_assert!(avg == prev || avg == val); } #[test] fn values_less_than_or_equal_to_max_precise_int_are_not_rounded(i in 0..=MAX_PRECISE_INT) { prop_assert_eq!((i as $typ) as $int_typ, i); } #[test] fn indivisible_intervals_are_split_to_self(val in finite()) { prop_assume!(val > $typ::MIN); let prev = next_down(val); let intervals = split_interval([prev, val]); prop_assert_eq!(intervals.count, 1); } #[test] fn split_intervals_are_the_same_size( (low, high) in bounds(), indices: [prop::sample::Index; 32]) { let intervals = split_interval([low, high]); let size = (intervals.count - 1) as usize; prop_assume!(size > 0); let mut it = indices.iter() .map(|i| i.index(size) as $int_typ) .map(|i| intervals.get(i)) .map(|[low, high]| high - low); let interval_size = it.next().unwrap(); let all_equal = it.all(|g| g == interval_size); prop_assert!(all_equal); } #[test] fn split_intervals_are_consecutive( (low, high) in bounds(), indices: [prop::sample::Index; 32]) { let intervals = split_interval([low, high]); let size = (intervals.count - 1) as usize; prop_assume!(size > 1); let mut it = indices.iter() .map(|i| i.index(size - 1) as $int_typ) .map(|i| (intervals.get(i), intervals.get(i + 1))); let ascending = it.all(|([_, h1], [l2, _])| h1 == l2); let descending = it.all(|([l1, _], [_, h2])| l1 == h2); prop_assert!(ascending || descending); } #[test] fn first_split_might_slightly_overshoot_one_bound((low, high) in bounds()) { let intervals = split_interval([low, high]); let start = intervals.get(0); let end = intervals.get(intervals.count - 1); let (low_interval, high_interval) = if start[0] < end[0] { (start, end) } else { (end, start) }; prop_assert!( low == low_interval[0] && high_interval[0] < high && high <= high_interval[1] || low_interval[0] <= low && low < low_interval[1] && high == high_interval[1]); } #[test] fn subsequent_splits_always_match_bounds( (low, high) in bounds(), index: prop::sample::Index) { // This property is true because the distances of split intervals of // are powers of two so the smaller one always divides the larger. let intervals = split_interval([low, high]); let size = (intervals.count - 1) as usize; let interval = intervals.get(index.index(size) as $int_typ); let small_intervals = split_interval(interval); let start = small_intervals.get(0); let end = small_intervals.get(small_intervals.count - 1); let (low_interval, high_interval) = if start[0] < end[0] { (start, end) } else { (end, start) }; prop_assert!( interval[0] == low_interval[0] && interval[1] == high_interval[1]); } } } } }; } float_sampler!(f32, u32, F32U); float_sampler!(f64, u64, F64U); proptest-1.6.0/src/num.rs000064400000000000000000001447711046102023000134620ustar 00000000000000//- // 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. mod float_samplers; use crate::test_runner::TestRunner; use rand::distributions::uniform::{SampleUniform, Uniform}; use rand::distributions::{Distribution, Standard}; /// Generate a random value of `X`, sampled uniformly from the half /// open range `[low, high)` (excluding `high`). Panics if `low >= high`. pub(crate) fn sample_uniform( run: &mut TestRunner, start: X, end: X, ) -> X { Uniform::new(start, end).sample(run.rng()) } /// Generate a random value of `X`, sampled uniformly from the closed /// range `[low, high]` (inclusive). Panics if `low > high`. pub fn sample_uniform_incl( run: &mut TestRunner, start: X, end: X, ) -> X { Uniform::new_inclusive(start, end).sample(run.rng()) } 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(runner.rng().gen())) } } }; } macro_rules! numeric_api { ($typ:ident, $epsilon:expr) => { numeric_api!($typ, $typ, $epsilon); }; ($typ:ident, $sample_typ:ty, $epsilon:expr) => { impl Strategy for ::core::ops::Range<$typ> { type Tree = BinarySearch; type Value = $typ; fn new_tree(&self, runner: &mut TestRunner) -> NewTree { if self.is_empty() { panic!( "Invalid use of empty range {}..{}.", self.start, self.end ); } Ok(BinarySearch::new_clamped( self.start, $crate::num::sample_uniform::<$sample_typ>( runner, self.start.into(), self.end.into(), ) .into(), self.end - $epsilon, )) } } impl Strategy for ::core::ops::RangeInclusive<$typ> { type Tree = BinarySearch; type Value = $typ; fn new_tree(&self, runner: &mut TestRunner) -> NewTree { if self.is_empty() { panic!( "Invalid use of empty range {}..={}.", self.start(), self.end() ); } Ok(BinarySearch::new_clamped( *self.start(), $crate::num::sample_uniform_incl::<$sample_typ>( runner, (*self.start()).into(), (*self.end()).into(), ) .into(), *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::<$sample_typ>( runner, self.start.into(), ::core::$typ::MAX.into(), ) .into(), ::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::<$sample_typ>( runner, ::core::$typ::MIN.into(), self.end.into(), ) .into(), 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::<$sample_typ>( runner, ::core::$typ::MIN.into(), self.end.into(), ) .into(), self.end, )) } } }; } macro_rules! signed_integer_bin_search { ($typ:ident) => { #[allow(missing_docs)] pub mod $typ { use rand::Rng; 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, curr: $typ, hi: $typ, } 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, } } fn reposition(&mut self) -> bool { // Won't ever overflow since lo starts at 0 and advances // towards hi. let interval = self.hi - self.lo; let new_mid = self.lo + interval / 2; if new_mid == self.curr { false } else { self.curr = new_mid; true } } fn magnitude_greater(lhs: $typ, rhs: $typ) -> bool { if 0 == lhs { false } else if lhs < 0 { lhs < rhs } else { lhs > rhs } } } impl ValueTree for BinarySearch { type Value = $typ; fn current(&self) -> $typ { self.curr } fn simplify(&mut self) -> bool { if !BinarySearch::magnitude_greater(self.hi, self.lo) { return false; } self.hi = self.curr; self.reposition() } fn complicate(&mut self) -> bool { if !BinarySearch::magnitude_greater(self.hi, self.lo) { return false; } self.lo = self.curr + if self.hi < 0 { -1 } else { 1 }; self.reposition() } } numeric_api!($typ, 1); } }; } macro_rules! unsigned_integer_bin_search { ($typ:ident) => { #[allow(missing_docs)] pub mod $typ { use rand::Rng; 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, curr: $typ, hi: $typ, } 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) } fn reposition(&mut self) -> bool { let interval = self.hi - self.lo; let new_mid = self.lo + interval / 2; if new_mid == self.curr { false } else { self.curr = new_mid; true } } } impl ValueTree for BinarySearch { type Value = $typ; fn current(&self) -> $typ { self.curr } fn simplify(&mut self) -> bool { if self.hi <= self.lo { return false; } self.hi = self.curr; self.reposition() } fn complicate(&mut self) -> bool { if self.hi <= self.lo { return false; } self.lo = self.curr + 1; self.reposition() } } numeric_api!($typ, 1); } }; } signed_integer_bin_search!(i8); signed_integer_bin_search!(i16); signed_integer_bin_search!(i32); signed_integer_bin_search!(i64); 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); unsigned_integer_bin_search!(u128); unsigned_integer_bin_search!(usize); bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 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, $sample_typ:ident) => { #[allow(missing_docs)] pub mod $typ { use super::float_samplers::$sample_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, $sample_typ, 0.0); } }; } float_bin_search!(f32, F32U); float_bin_search!(f64, F64U); #[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 FORTY_TWO: $t = 42 as $t; const FIFTY_SIX: $t = 56 as $t; #[test] fn range() { check_strategy_sanity(FORTY_TWO..FIFTY_SIX, None); } #[test] fn range_inclusive() { check_strategy_sanity(FORTY_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(FORTY_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() })); } } mod panic_on_empty { macro_rules! panic_on_empty { ($t:tt) => { mod $t { use crate::strategy::Strategy; use crate::test_runner::TestRunner; use std::panic; use std::string::String; const ZERO: $t = 0 as $t; const ONE: $t = 1 as $t; #[test] fn range() { assert_eq!( panic::catch_unwind(|| { let mut runner = TestRunner::deterministic(); let _ = (ZERO..ZERO).new_tree(&mut runner); }) .err() .and_then(|a| a .downcast_ref::() .map(|s| { s == "Invalid use of empty range 0..0." })), Some(true) ); } #[test] fn range_inclusive() { assert_eq!( panic::catch_unwind(|| { let mut runner = TestRunner::deterministic(); let _ = (ONE..=ZERO).new_tree(&mut runner); }) .err() .and_then(|a| a .downcast_ref::() .map(|s| { s == "Invalid use of empty range 1..=0." })), Some(true) ); } } }; } panic_on_empty!(u8); panic_on_empty!(i8); panic_on_empty!(u16); panic_on_empty!(i16); panic_on_empty!(u32); panic_on_empty!(i32); panic_on_empty!(u64); panic_on_empty!(i64); panic_on_empty!(usize); panic_on_empty!(isize); panic_on_empty!(f32); panic_on_empty!(f64); } } proptest-1.6.0/src/option.rs000064400000000000000000000157401046102023000141640ustar 00000000000000//- // 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 `std::Option` values. #![cfg_attr(clippy, allow(expl_impl_clone_on_copy))] use core::fmt; use core::marker::PhantomData; use crate::std_facade::Arc; use crate::strategy::*; use crate::test_runner::*; //============================================================================== // Probability //============================================================================== /// Creates a `Probability` from some value that is convertible into it. /// /// # Panics /// /// Panics if the converted to probability would lie /// outside interval `[0.0, 1.0]`. Consult the `Into` (or `From`) /// implementations for more details. pub fn prob(from: impl Into) -> Probability { from.into() } impl Default for Probability { /// The default probability is 0.5, or 50% chance. fn default() -> Self { prob(0.5) } } impl Probability { /// Creates a `Probability` from a `f64`. /// /// # Panics /// /// Panics if the probability is outside interval `[0.0, 1.0]`. pub fn new(prob: f64) -> Self { assert!(prob >= 0.0 && prob <= 1.0); Probability(prob) } // Don't rely on these existing internally: /// Merges self together with some other argument producing a product /// type expected by some implementations of `A: Arbitrary` in /// `A::Parameters`. This can be more ergonomic to work with and may /// help type inference. pub fn with(self, and: X) -> product_type![Self, X] { product_pack![self, and] } /// Merges self together with some other argument generated with a /// default value producing a product type expected by some /// implementations of `A: Arbitrary` in `A::Parameters`. /// This can be more ergonomic to work with and may help type inference. pub fn lift(self) -> product_type![Self, X] { self.with(Default::default()) } } impl From for Probability { /// Creates a `Probability` from a `f64`. /// /// # Panics /// /// Panics if the probability is outside interval `[0.0, 1.0]`. fn from(prob: f64) -> Self { Probability::new(prob) } } impl From for f64 { fn from(p: Probability) -> Self { p.0 } } /// A probability in the range `[0.0, 1.0]` with a default of `0.5`. #[derive(Clone, Copy, PartialEq, Debug)] pub struct Probability(f64); //============================================================================== // Strategies for Option //============================================================================== mapfn! { [] fn WrapSome[](t: T) -> Option { Some(t) } } #[must_use = "strategies do nothing unless used"] struct NoneStrategy(PhantomData); impl Clone for NoneStrategy { fn clone(&self) -> Self { *self } } impl Copy for NoneStrategy {} impl fmt::Debug for NoneStrategy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "NoneStrategy") } } impl Strategy for NoneStrategy { type Tree = Self; type Value = Option; fn new_tree(&self, _: &mut TestRunner) -> NewTree { Ok(*self) } } impl ValueTree for NoneStrategy { type Value = Option; fn current(&self) -> Option { None } fn simplify(&mut self) -> bool { false } fn complicate(&mut self) -> bool { false } } opaque_strategy_wrapper! { /// Strategy which generates `Option` values whose inner `Some` values are /// generated by another strategy. /// /// Constructed by other functions in this module. #[derive(Clone)] pub struct OptionStrategy[][where T : Strategy] (TupleUnion<(WA>, WA>)>) -> OptionValueTree; /// `ValueTree` type corresponding to `OptionStrategy`. pub struct OptionValueTree[][where T : Strategy] (TupleUnionValueTree<( LazyValueTree>, Option>>, )>) -> Option; } // XXX Unclear why this is necessary; #[derive(Debug)] *should* generate // exactly this, but for some reason it adds a `T::Value : Debug` constraint as // well. impl fmt::Debug for OptionStrategy { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "OptionStrategy({:?})", self.0) } } impl Clone for OptionValueTree where T::Tree: Clone, { fn clone(&self) -> Self { OptionValueTree(self.0.clone()) } } impl fmt::Debug for OptionValueTree where T::Tree: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "OptionValueTree({:?})", self.0) } } /// Return a strategy producing `Optional` values wrapping values from the /// given delegate strategy. /// /// `Some` values shrink to `None`. /// /// `Some` and `None` are each chosen with 50% probability. pub fn of(t: T) -> OptionStrategy { weighted(Probability::default(), t) } /// Return a strategy producing `Optional` values wrapping values from the /// given delegate strategy. /// /// `Some` values shrink to `None`. /// /// `Some` is chosen with a probability given by `probability_of_some`, which /// must be between 0.0 and 1.0, both exclusive. pub fn weighted( probability_of_some: impl Into, t: T, ) -> OptionStrategy { let prob = probability_of_some.into().into(); let (weight_some, weight_none) = float_to_weight(prob); OptionStrategy(TupleUnion::new(( (weight_none, Arc::new(NoneStrategy(PhantomData))), (weight_some, Arc::new(statics::Map::new(t, WrapSome))), ))) } #[cfg(test)] mod test { use super::*; fn count_some_of_1000(s: OptionStrategy>) -> u32 { let mut runner = TestRunner::deterministic(); let mut count = 0; for _ in 0..1000 { count += s.new_tree(&mut runner).unwrap().current().is_some() as u32; } count } #[test] fn probability_defaults_to_0p5() { let count = count_some_of_1000(of(Just(42i32))); assert!(count > 450 && count < 550); } #[test] fn probability_handled_correctly() { let count = count_some_of_1000(weighted(0.9, Just(42i32))); assert!(count > 800 && count < 950); let count = count_some_of_1000(weighted(0.1, Just(42i32))); assert!(count > 50 && count < 150); } #[test] fn test_sanity() { check_strategy_sanity(of(0i32..1000i32), None); } } proptest-1.6.0/src/path.rs000064400000000000000000000033111046102023000135770ustar 00000000000000//! Strategies for generating [`PathBuf`] and related path types. //! //! [`PathParams`] in this module is used as the argument to the //! [`Arbitrary`](crate::arbitrary::Arbitrary) implementation for [`PathBuf`]. use crate::{collection::SizeRange, string::StringParam}; /// Parameters for the [`Arbitrary`] implementation for [`PathBuf`]. /// /// By default, this generates paths with 0 to 8 components uniformly at random, each of which is a /// default [`StringParam`]. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct PathParams { /// The number of components in the path. components: SizeRange, /// The regular expression to generate individual components. component_regex: StringParam, } impl PathParams { /// Gets the number of components in the path. pub fn components(&self) -> SizeRange { self.components.clone() } /// Sets the number of components in the path. pub fn with_components(mut self, components: impl Into) -> Self { self.components = components.into(); self } /// Gets the regular expression to generate individual components. pub fn component_regex(&self) -> StringParam { self.component_regex } /// Sets the regular expression to generate individual components. pub fn with_component_regex( mut self, component_regex: impl Into, ) -> Self { self.component_regex = component_regex.into(); self } } impl Default for PathParams { fn default() -> Self { Self { components: (0..8).into(), // This is the default regex for `any::()`. component_regex: StringParam::default(), } } } proptest-1.6.0/src/prelude.rs000064400000000000000000000040431046102023000143060ustar 00000000000000//- // 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::test_runner::TestCaseError; pub use crate::{ prop_assert, prop_assert_eq, prop_assert_ne, prop_assume, prop_compose, prop_oneof, proptest, }; pub use rand::{Rng, RngCore}; /// 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; 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; } proptest-1.6.0/src/product_tuple.rs000064400000000000000000000021161046102023000155360ustar 00000000000000//- // 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 macros for product type creation, extraction, and the type signature //! itself. This version uses tuples. macro_rules! product_type { ($factor: ty) => { ($factor,) }; ($($factor: ty),*) => { ( $( $factor, )* ) }; ($($factor: ty),*,) => { ( $( $factor, )* ) }; } macro_rules! product_pack { ($factor: expr) => { ($factor,) }; ($($factor: expr),*) => { ( $( $factor ),* ) }; ($($factor: expr),*,) => { ( $( $factor ),* ) }; } macro_rules! product_unpack { ($factor: pat) => { ($factor,) }; ($($factor: pat),*) => { ( $( $factor ),* ) }; ($($factor: pat),*,) => { ( $( $factor ),* ) }; } proptest-1.6.0/src/regex-contrib/README.md000064400000000000000000000002721046102023000163270ustar 00000000000000Files in this directory are copied verbatim from the https://github.com/rust-lang/regex repository and are used for generating test data. They do not become part of the proptest binary. proptest-1.6.0/src/regex-contrib/crates_regex.rs000064400000000000000000003661331046102023000201040ustar 00000000000000// Copyright 2018 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // 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. // DO NOT EDIT. Automatically generated by 'scripts/scrape_crates_io.py' // on 2018-06-20 09:56:32.820354. // autoshutdown-0.1.0: r"\s*(\d+)(\w)\s*" consistent!(autoshutdown_0, r"\s*(\d+)(\w)\s*"); // epub-1.1.1: r"/" consistent!(epub_0, r"/"); // rpi-info-0.2.0: "^Revision\t+: ([0-9a-fA-F]+)" consistent!(rpi_info_0, "^Revision\t+: ([0-9a-fA-F]+)"); // rpi-info-0.2.0: "Serial\t+: ([0-9a-fA-F]+)" consistent!(rpi_info_1, "Serial\t+: ([0-9a-fA-F]+)"); // pnet_macros-0.21.0: r"^u([0-9]+)(be|le|he)?$" consistent!(pnet_macros_0, r"^u([0-9]+)(be|le|he)?$"); // iban_validate-1.0.3: r"^[A-Z]{2}\d{2}[A-Z\d]{1,30}$" consistent!(iban_validate_0, r"^[A-Z]{2}\d{2}[A-Z\d]{1,30}$"); // markifier-0.1.0: r".*\[(?P.+)%.*\].*" consistent!(markifier_0, r".*\[(?P.+)%.*\].*"); // mallumo-0.3.0: r"(#include) (\S*)(.*)" consistent!(mallumo_0, r"(#include) (\S*)(.*)"); // mallumo-0.3.0: r"(ERROR: \d+:)(\d+)(: )(.+)" consistent!(mallumo_1, r"(ERROR: \d+:)(\d+)(: )(.+)"); // mallumo-0.3.0: r"(\d+\()(\d+)(?:\) : )(.+)" consistent!(mallumo_2, r"(\d+\()(\d+)(?:\) : )(.+)"); // magnet_more-0.0.1: r"(.+?)(\[.*?\])?" consistent!(magnet_more_0, r"(.+?)(\[.*?\])?"); // magnet_app-0.0.1: r":(?P[a-zA-Z_]+)" consistent!(magnet_app_0, r":(?P[a-zA-Z_]+)"); // yubibomb-0.2.0: r"^\d{6}(?:\s*,\s*\d{6})*$" consistent!(yubibomb_0, r"^\d{6}(?:\s*,\s*\d{6})*$"); // multirust-rs-0.0.4: r"[\\/]([^\\/?]+)(\?.*)?$" consistent!(multirust_rs_0, r"[\\/]([^\\/?]+)(\?.*)?$"); // hueclient-0.3.2: "\"[a-z]*\":null" consistent!(hueclient_0, "\"[a-z]*\":null"); // hueclient-0.3.2: ",+" consistent!(hueclient_1, ",+"); // hueclient-0.3.2: ",\\}" consistent!(hueclient_2, ",\\}"); // hueclient-0.3.2: "\\{," consistent!(hueclient_3, "\\{,"); // aerial-0.1.0: r"[a-zA-Z_\$][a-zA-Z_0-9]*" consistent!(aerial_0, r"[a-zA-Z_\$][a-zA-Z_0-9]*"); // aerial-0.1.0: r"thi[sng]+" consistent!(aerial_1, r"thi[sng]+"); // rvue-0.1.0: r"(.+)\s+\((.+?)\)" consistent!(rvue_0, r"(.+)\s+\((.+?)\)"); // rvue-0.1.0: r"([\d\.]+)\s*out\s*of\s*([\d\.]+)" consistent!(rvue_1, r"([\d\.]+)\s*out\s*of\s*([\d\.]+)"); // rvue-0.1.0: r"^([\d\.]+)\s*(?:\(\))?$" consistent!(rvue_2, r"^([\d\.]+)\s*(?:\(\))?$"); // rvue-0.1.0: r"([\d\.]+)\s*Points\s*Possible" consistent!(rvue_3, r"([\d\.]+)\s*Points\s*Possible"); // rvue-0.1.0: r"([\d\.]+)\s*/\s*([\d\.]+)" consistent!(rvue_4, r"([\d\.]+)\s*/\s*([\d\.]+)"); // rvsim-0.1.0: r"_?([_a-z0-9]+)\s*:\s*([_a-z0-9]+)\s*[,)]" consistent!(rvsim_0, r"_?([_a-z0-9]+)\s*:\s*([_a-z0-9]+)\s*[,)]"); // nereon-0.1.4: "(.*[^\\\\])\\{\\}(.*)" consistent!(nereon_0, "(.*[^\\\\])\\{\\}(.*)"); // next_episode-0.3.0: r"((?i)^(.+).s(\d+)e(\d+).*)$" consistent!(next_episode_0, r"((?i)^(.+).s(\d+)e(\d+).*)$"); // migrant_lib-0.19.2: r"[^a-z0-9-]+" consistent!(migrant_lib_0, r"[^a-z0-9-]+"); // migrant_lib-0.19.2: r"[0-9]{14}_[a-z0-9-]+" consistent!(migrant_lib_1, r"[0-9]{14}_[a-z0-9-]+"); // migrant_lib-0.19.2: r"([0-9]{14}_)?[a-z0-9-]+" consistent!(migrant_lib_2, r"([0-9]{14}_)?[a-z0-9-]+"); // minipre-0.2.0: "$_" consistent!(minipre_0, "$_"); // minifier-0.0.13: r">\s+<" consistent!(minifier_0, r">\s+<"); // minifier-0.0.13: r"\s{2,}|[\r\n]" consistent!(minifier_1, r"\s{2,}|[\r\n]"); // minifier-0.0.13: r"<(style|script)[\w|\s].*?>" consistent!(minifier_2, r"<(style|script)[\w|\s].*?>"); // minifier-0.0.13: "" consistent!(minifier_3, ""); // minifier-0.0.13: r"<\w.*?>" consistent!(minifier_4, r"<\w.*?>"); // minifier-0.0.13: r" \s+|\s +" consistent!(minifier_5, r" \s+|\s +"); // minifier-0.0.13: r"\w\s+\w" consistent!(minifier_6, r"\w\s+\w"); // minifier-0.0.13: r"'\s+>" consistent!(minifier_7, r"'\s+>"); // minifier-0.0.13: r"\d\s+>" consistent!(minifier_8, r"\d\s+>"); // ggp-rs-0.1.2: r"(?P\([^)]+\))|(?P[a-zA-Z0-9_]+)" consistent!(ggp_rs_0, r"(?P\([^)]+\))|(?P[a-zA-Z0-9_]+)"); // ggp-rs-0.1.2: r"\((.*)\)." consistent!(ggp_rs_1, r"\((.*)\)."); // poe-superfilter-0.2.0: "[A-Za-z0-9_]" consistent!(poe_superfilter_0, "[A-Za-z0-9_]"); // poke-a-mango-0.5.0: r"(\d+)x(\d+)" consistent!(poke_a_mango_0, r"(\d+)x(\d+)"); // pop3-rs-0.1.0: r"(?P\d+) (?P\d+)" consistent!(pop3_rs_0, r"(?P\d+) (?P\d+)"); // pop3-rs-0.1.0: r"(?P\d+) (?P[\x21-\x7E]{1,70})" consistent!(pop3_rs_1, r"(?P\d+) (?P[\x21-\x7E]{1,70})"); // pop3-rs-0.1.0: r"(<.*>)\r\n$" consistent!(pop3_rs_2, r"(<.*>)\r\n$"); // pop3-rs-0.1.0: r"^(?P\+OK|-ERR) (?P.*)" consistent!(pop3_rs_3, r"^(?P\+OK|-ERR) (?P.*)"); // pop3-1.0.6: r"^\.\r\n$" consistent!(pop3_0, r"^\.\r\n$"); // pop3-1.0.6: r"\+OK(.*)" consistent!(pop3_1, r"\+OK(.*)"); // pop3-1.0.6: r"-ERR(.*)" consistent!(pop3_2, r"-ERR(.*)"); // pop3-1.0.6: r"\+OK (\d+) (\d+)\r\n" consistent!(pop3_3, r"\+OK (\d+) (\d+)\r\n"); // pop3-1.0.6: r"(\d+) ([\x21-\x7e]+)\r\n" consistent!(pop3_4, r"(\d+) ([\x21-\x7e]+)\r\n"); // pop3-1.0.6: r"\+OK (\d+) ([\x21-\x7e]+)\r\n" consistent!(pop3_5, r"\+OK (\d+) ([\x21-\x7e]+)\r\n"); // pop3-1.0.6: r"(\d+) (\d+)\r\n" consistent!(pop3_6, r"(\d+) (\d+)\r\n"); // pop3-1.0.6: r"\+OK (\d+) (\d+)\r\n" consistent!(pop3_7, r"\+OK (\d+) (\d+)\r\n"); // polk-1.1.3: "github:(\\w+)/?(\\w+)?" consistent!(polk_0, "github:(\\w+)/?(\\w+)?"); // geochunk-0.1.5: "^[0-9]{5}" consistent!(geochunk_0, "^[0-9]{5}"); // generic-dns-update-1.1.4: r"((?:(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?)\.){3}(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?))" consistent!(generic_dns_update_0, r"((?:(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?)\.){3}(?:0|1[\d]{0,2}|2(?:[0-4]\d?|5[0-5]?|[6-9])?|[3-9]\d?))"); // generic-dns-update-1.1.4: r"((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|(([0-9A-Fa-f]{1,4}:){0,5}:((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|(::([0-9A-Fa-f]{1,4}:){0,5}((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))" consistent!(generic_dns_update_1, r"((([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}:[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){5}:([0-9A-Fa-f]{1,4}:)?[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){4}:([0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){3}:([0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){2}:([0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){6}((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|(([0-9A-Fa-f]{1,4}:){0,5}:((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|(::([0-9A-Fa-f]{1,4}:){0,5}((\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d)\.){3}(\d((25[0-5])|(1\d{2})|(2[0-4]\d)|(\d{1,2}))\d))|([0-9A-Fa-f]{1,4}::([0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})|(::([0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})|(([0-9A-Fa-f]{1,4}:){1,7}:))"); // generic-dns-update-1.1.4: r"([0-9.]*)" consistent!(generic_dns_update_2, r"([0-9.]*)"); // generic-dns-update-1.1.4: r"([0-9]+)" consistent!(generic_dns_update_3, r"([0-9]+)"); // generic-dns-update-1.1.4: r"([0-9]+)" consistent!(generic_dns_update_4, r"([0-9]+)"); // generic-dns-update-1.1.4: r"([0-1]*)" consistent!(generic_dns_update_5, r"([0-1]*)"); // generate-nix-pkg-0.3.0: r"(\d*)\.(\d*)\.(\d*)(-(\S*))?" consistent!(generate_nix_pkg_0, r"(\d*)\.(\d*)\.(\d*)(-(\S*))?"); // generate-nix-pkg-0.3.0: r"^(\S*) (\d*)\.(\d*)\.(\d*)(-(\S*))?" consistent!(generate_nix_pkg_1, r"^(\S*) (\d*)\.(\d*)\.(\d*)(-(\S*))?"); // genact-0.6.0: r"arch/([a-z0-9_])+/" consistent!(genact_0, r"arch/([a-z0-9_])+/"); // genact-0.6.0: r"arch/([a-z0-9_])+/" consistent!(genact_1, r"arch/([a-z0-9_])+/"); // cron_rs-0.1.6: r"^\s*((\*(/\d+)?)|[0-9-,/]+)(\s+((\*(/\d+)?)|[0-9-,/]+)){4,5}\s*$" consistent!(cron_rs_0, r"^\s*((\*(/\d+)?)|[0-9-,/]+)(\s+((\*(/\d+)?)|[0-9-,/]+)){4,5}\s*$"); // systemfd-0.3.0: r"^([a-zA-Z]+)::(.+)$" consistent!(systemfd_0, r"^([a-zA-Z]+)::(.+)$"); // symbolic-debuginfo-5.0.2: "__?hidden#\\d+_" consistent!(symbolic_debuginfo_0, "__?hidden#\\d+_"); // symbolic-minidump-5.0.2: r"^Linux ([^ ]+) (.*) \w+(?: GNU/Linux)?$" consistent!(symbolic_minidump_0, r"^Linux ([^ ]+) (.*) \w+(?: GNU/Linux)?$"); // graphql-idl-parser-0.1.1: "^(?u:\\#)(?u:[\t-\r - \u{85}-\u{85}\u{a0}-\u{a0}\u{1680}-\u{1680}\u{2000}-\u{200a}\u{2028}-\u{2029}\u{202f}-\u{202f}\u{205f}-\u{205f}\u{3000}-\u{3000}])*(?u:.)+" consistent!(graphql_idl_parser_0, "^(?u:\\#)(?u:[\t-\r - \u{85}-\u{85}\u{a0}-\u{a0}\u{1680}-\u{1680}\u{2000}-\u{200a}\u{2028}-\u{2029}\u{202f}-\u{202f}\u{205f}-\u{205f}\u{3000}-\u{3000}])*(?u:.)+"); // graphql-idl-parser-0.1.1: "^(?u:=)(?u:[\t-\r - \u{85}-\u{85}\u{a0}-\u{a0}\u{1680}-\u{1680}\u{2000}-\u{200a}\u{2028}-\u{2029}\u{202f}-\u{202f}\u{205f}-\u{205f}\u{3000}-\u{3000}])*(?u:.)+" consistent!(graphql_idl_parser_1, "^(?u:=)(?u:[\t-\r - \u{85}-\u{85}\u{a0}-\u{a0}\u{1680}-\u{1680}\u{2000}-\u{200a}\u{2028}-\u{2029}\u{202f}-\u{202f}\u{205f}-\u{205f}\u{3000}-\u{3000}])*(?u:.)+"); // graphql-idl-parser-0.1.1: "^(?u:[A-Z_-_a-z])(?u:[0-9A-Z_-_a-z])*" consistent!(graphql_idl_parser_2, "^(?u:[A-Z_-_a-z])(?u:[0-9A-Z_-_a-z])*"); // graphql-idl-parser-0.1.1: "^(?u:!)" consistent!(graphql_idl_parser_3, "^(?u:!)"); // graphql-idl-parser-0.1.1: "^(?u:\\()" consistent!(graphql_idl_parser_4, "^(?u:\\()"); // graphql-idl-parser-0.1.1: "^(?u:\\))" consistent!(graphql_idl_parser_5, "^(?u:\\))"); // graphql-idl-parser-0.1.1: "^(?u:,)" consistent!(graphql_idl_parser_6, "^(?u:,)"); // graphql-idl-parser-0.1.1: "^(?u::)" consistent!(graphql_idl_parser_7, "^(?u::)"); // graphql-idl-parser-0.1.1: "^(?u:@)" consistent!(graphql_idl_parser_8, "^(?u:@)"); // graphql-idl-parser-0.1.1: "^(?u:\\[)" consistent!(graphql_idl_parser_9, "^(?u:\\[)"); // graphql-idl-parser-0.1.1: "^(?u:\\])" consistent!(graphql_idl_parser_10, "^(?u:\\])"); // graphql-idl-parser-0.1.1: "^(?u:enum)" consistent!(graphql_idl_parser_11, "^(?u:enum)"); // graphql-idl-parser-0.1.1: "^(?u:implements)" consistent!(graphql_idl_parser_12, "^(?u:implements)"); // graphql-idl-parser-0.1.1: "^(?u:input)" consistent!(graphql_idl_parser_13, "^(?u:input)"); // graphql-idl-parser-0.1.1: "^(?u:interface)" consistent!(graphql_idl_parser_14, "^(?u:interface)"); // graphql-idl-parser-0.1.1: "^(?u:scalar)" consistent!(graphql_idl_parser_15, "^(?u:scalar)"); // graphql-idl-parser-0.1.1: "^(?u:type)" consistent!(graphql_idl_parser_16, "^(?u:type)"); // graphql-idl-parser-0.1.1: "^(?u:union)" consistent!(graphql_idl_parser_17, "^(?u:union)"); // graphql-idl-parser-0.1.1: "^(?u:\\{)" consistent!(graphql_idl_parser_18, "^(?u:\\{)"); // graphql-idl-parser-0.1.1: "^(?u:\\})" consistent!(graphql_idl_parser_19, "^(?u:\\})"); // grimoire-0.1.0: r"(?s)/\*(?P.*?)\*/" consistent!(grimoire_0, r"(?s)/\*(?P.*?)\*/"); // phonenumber-0.2.0+8.9.0: r"[\d]+(?:[~\x{2053}\x{223C}\x{FF5E}][\d]+)?" consistent!(phonenumber_0, r"[\d]+(?:[~\x{2053}\x{223C}\x{FF5E}][\d]+)?"); // phonenumber-0.2.0+8.9.0: r"[, \[\]]" consistent!(phonenumber_1, r"[, \[\]]"); // phonenumber-0.2.0+8.9.0: r"[\\/] *x" consistent!(phonenumber_2, r"[\\/] *x"); // phonenumber-0.2.0+8.9.0: r"[[\P{N}&&\P{L}]&&[^#]]+$" consistent!(phonenumber_3, r"[[\P{N}&&\P{L}]&&[^#]]+$"); // phonenumber-0.2.0+8.9.0: r"(?:.*?[A-Za-z]){3}.*" consistent!(phonenumber_4, r"(?:.*?[A-Za-z]){3}.*"); // phonenumber-0.2.0+8.9.0: r"(\D+)" consistent!(phonenumber_5, r"(\D+)"); // phonenumber-0.2.0+8.9.0: r"(\$\d)" consistent!(phonenumber_6, r"(\$\d)"); // phonenumber-0.2.0+8.9.0: r"\(?\$1\)?" consistent!(phonenumber_7, r"\(?\$1\)?"); // phone_number-0.1.0: r"\D" consistent!(phone_number_0, r"\D"); // phone_number-0.1.0: r"^0+" consistent!(phone_number_1, r"^0+"); // phone_number-0.1.0: r"^89" consistent!(phone_number_2, r"^89"); // phone_number-0.1.0: r"^8+" consistent!(phone_number_3, r"^8+"); // phile-0.1.4: r"^ *(\^_*\^) *$" consistent!(phile_0, r"^ *(\^_*\^) *$"); // phile-0.1.4: r"^[_\p{XID_Start}]$" consistent!(phile_1, r"^[_\p{XID_Start}]$"); // phile-0.1.4: r"^\p{XID_Continue}$" consistent!(phile_2, r"^\p{XID_Continue}$"); // uritemplate-0.1.2: "%25(?P[0-9a-fA-F][0-9a-fA-F])" consistent!(uritemplate_0, "%25(?P[0-9a-fA-F][0-9a-fA-F])"); // urdf-rs-0.4.2: "^package://(\\w+)/" consistent!(urdf_rs_0, "^package://(\\w+)/"); // url-match-0.1.7: r"(?P[?&.])" consistent!(url_match_0, r"(?P[?&.])"); // url-match-0.1.7: r":(?P[a-zA-Z0-9_-]+)" consistent!(url_match_1, r":(?P[a-zA-Z0-9_-]+)"); // tsm-sys-0.1.0: r"hello world" consistent!(tsm_sys_0, r"hello world"); // deb-version-0.1.0: "^(?:(?:(?:\\d+:).+)|(?:[^:]+))$" consistent!(deb_version_0, "^(?:(?:(?:\\d+:).+)|(?:[^:]+))$"); // debcargo-2.1.0: r"^(?i)(a|an|the)\s+" consistent!(debcargo_0, r"^(?i)(a|an|the)\s+"); // debcargo-2.1.0: r"^(?i)(rust\s+)?(implementation|library|tool|crate)\s+(of|to|for)\s+" consistent!(debcargo_1, r"^(?i)(rust\s+)?(implementation|library|tool|crate)\s+(of|to|for)\s+"); // feaders-0.2.0: r"^.*\.h$" consistent!(feaders_0, r"^.*\.h$"); // feaders-0.2.0: r"^.*\.c$" consistent!(feaders_1, r"^.*\.c$"); // feaders-0.2.0: r"^.*\.hpp$" consistent!(feaders_2, r"^.*\.hpp$"); // feaders-0.2.0: r"^.*\.cc$" consistent!(feaders_3, r"^.*\.cc$"); // feaders-0.2.0: r"^.*\.cpp$" consistent!(feaders_4, r"^.*\.cpp$"); // hyperscan-0.1.6: r"CPtr\(\w+\)" consistent!(hyperscan_0, r"CPtr\(\w+\)"); // hyperscan-0.1.6: r"^Version:\s(\d\.\d\.\d)\sFeatures:\s+(\w+)?\sMode:\s(\w+)$" consistent!(hyperscan_1, r"^Version:\s(\d\.\d\.\d)\sFeatures:\s+(\w+)?\sMode:\s(\w+)$"); // hyperscan-0.1.6: r"RawDatabase\{db: \w+\}" consistent!(hyperscan_2, r"RawDatabase\{db: \w+\}"); // hyperscan-0.1.6: r"RawSerializedDatabase\{p: \w+, len: \d+\}" consistent!(hyperscan_3, r"RawSerializedDatabase\{p: \w+, len: \d+\}"); // ucd-parse-0.1.1: r"[0-9A-F]+" consistent!(ucd_parse_0, r"[0-9A-F]+"); // afsort-0.2.0: r".*" consistent!(afsort_0, r".*"); // afsort-0.2.0: r".*" consistent!(afsort_1, r".*"); // afsort-0.2.0: r".*" consistent!(afsort_2, r".*"); // afsort-0.2.0: r".*" consistent!(afsort_3, r".*"); // afsort-0.2.0: r".*" consistent!(afsort_4, r".*"); // afsort-0.2.0: r".*" consistent!(afsort_5, r".*"); // afsort-0.2.0: r"^[a-z]+$" consistent!(afsort_6, r"^[a-z]+$"); // afsort-0.2.0: r"^[a-z]+$" consistent!(afsort_7, r"^[a-z]+$"); // tin-summer-1.21.4: r"(\.git|\.pijul|_darcs|\.hg)$" consistent!(tin_summer_0, r"(\.git|\.pijul|_darcs|\.hg)$"); // tin-drummer-1.0.1: r".*?\.(a|la|lo|o|ll|keter|bc|dyn_o|d|rlib|crate|min\.js|hi|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$" consistent!(tin_drummer_0, r".*?\.(a|la|lo|o|ll|keter|bc|dyn_o|d|rlib|crate|min\.js|hi|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$"); // tin-drummer-1.0.1: r".*?\.(stats|conf|h|out|cache.*|dat|pc|info|\.js)$" consistent!(tin_drummer_1, r".*?\.(stats|conf|h|out|cache.*|dat|pc|info|\.js)$"); // tin-drummer-1.0.1: r".*?\.(exe|a|la|o|ll|keter|bc|dyn_o|d|rlib|crate|min\.js|hi|dyn_hi|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$" consistent!(tin_drummer_2, r".*?\.(exe|a|la|o|ll|keter|bc|dyn_o|d|rlib|crate|min\.js|hi|dyn_hi|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$"); // tin-drummer-1.0.1: r".*?\.(stats|conf|h|out|cache.*|\.js)$" consistent!(tin_drummer_3, r".*?\.(stats|conf|h|out|cache.*|\.js)$"); // tin-drummer-1.0.1: r"(\.git|\.pijul|_darcs|\.hg)$" consistent!(tin_drummer_4, r"(\.git|\.pijul|_darcs|\.hg)$"); // tin-drummer-1.0.1: r".*?\.(dyn_o|out|d|hi|dyn_hi|dump-.*|p_hi|p_o|prof|tix)$" consistent!(tin_drummer_5, r".*?\.(dyn_o|out|d|hi|dyn_hi|dump-.*|p_hi|p_o|prof|tix)$"); // tin-drummer-1.0.1: r".*?\.(ibc)$" consistent!(tin_drummer_6, r".*?\.(ibc)$"); // tin-drummer-1.0.1: r"\.stack-work|dist-newstyle" consistent!(tin_drummer_7, r"\.stack-work|dist-newstyle"); // timmy-0.3.0: r"_NET_WM_PID\(CARDINAL\) = (\d+)" consistent!(timmy_0, r"_NET_WM_PID\(CARDINAL\) = (\d+)"); // timmy-0.3.0: r"today|yesterday|now" consistent!(timmy_1, r"today|yesterday|now"); // timmy-0.3.0: r"(?P\d{1,2})/(?P\d{1,2})(/(?P\d{4}|\d{2}))?" consistent!(timmy_2, r"(?P\d{1,2})/(?P\d{1,2})(/(?P\d{4}|\d{2}))?"); // timmy-0.3.0: r"(?P\d+) (days?|ds?)(?P( ago)?)" consistent!(timmy_3, r"(?P\d+) (days?|ds?)(?P( ago)?)"); // timmy-0.3.0: r"(?P
\d{2}):(?P\d{2})" consistent!(timmy_4, r"(?P
\d{2}):(?P\d{2})"); // tinfo-0.5.0: r"^(\d+): \d+ windows \(.*\) \[\d+x\d+\]( \(attached\))?" consistent!(tinfo_0, r"^(\d+): \d+ windows \(.*\) \[\d+x\d+\]( \(attached\))?"); // tinfo-0.5.0: r"^(\d+):(\d+): (.*) \((\d+) panes\) \[(\d+)x(\d+)\]" consistent!(tinfo_1, r"^(\d+):(\d+): (.*) \((\d+) panes\) \[(\d+)x(\d+)\]"); // timespan-0.0.4: r"(?:\\\{start\\\}|\\\{end\\\})" consistent!(timespan_0, r"(?:\\\{start\\\}|\\\{end\\\})"); // timespan-0.0.4: r"(.*)\s+-\s+(.*)" consistent!(timespan_1, r"(.*)\s+-\s+(.*)"); // timespan-0.0.4: r"(.*)\s+(\w+)$" consistent!(timespan_2, r"(.*)\s+(\w+)$"); // timespan-0.0.4: r"(.*)\s+(\w+)$" consistent!(timespan_3, r"(.*)\s+(\w+)$"); // timespan-0.0.4: r"(.*)\s+-\s+(.*)" consistent!(timespan_4, r"(.*)\s+-\s+(.*)"); // titlecase-0.10.0: r"[[:lower:]]" consistent!(titlecase_0, r"[[:lower:]]"); // tight-0.1.3: r"^\d+ (day|week|month|year)s?$" consistent!(tight_0, r"^\d+ (day|week|month|year)s?$"); // tight-0.1.3: r"^\d+ (day|week|month|year)s?$" consistent!(tight_1, r"^\d+ (day|week|month|year)s?$"); // yaml-0.2.1: r"^[-+]?(0|[1-9][0-9_]*)$" consistent!(yaml_0, r"^[-+]?(0|[1-9][0-9_]*)$"); // yaml-0.2.1: r"^([-+]?)0o?([0-7_]+)$" consistent!(yaml_1, r"^([-+]?)0o?([0-7_]+)$"); // yaml-0.2.1: r"^([-+]?)0x([0-9a-fA-F_]+)$" consistent!(yaml_2, r"^([-+]?)0x([0-9a-fA-F_]+)$"); // yaml-0.2.1: r"^([-+]?)0b([0-1_]+)$" consistent!(yaml_3, r"^([-+]?)0b([0-1_]+)$"); // yaml-0.2.1: r"^([-+]?)(\.[0-9]+|[0-9]+(\.[0-9]*)?([eE][-+]?[0-9]+)?)$" consistent!(yaml_4, r"^([-+]?)(\.[0-9]+|[0-9]+(\.[0-9]*)?([eE][-+]?[0-9]+)?)$"); // yaml-0.2.1: r"^[+]?(\.inf|\.Inf|\.INF)$" consistent!(yaml_5, r"^[+]?(\.inf|\.Inf|\.INF)$"); // yaml-0.2.1: r"^-(\.inf|\.Inf|\.INF)$" consistent!(yaml_6, r"^-(\.inf|\.Inf|\.INF)$"); // yaml-0.2.1: r"^(\.nan|\.NaN|\.NAN)$" consistent!(yaml_7, r"^(\.nan|\.NaN|\.NAN)$"); // yaml-0.2.1: r"^(null|Null|NULL|~)$" consistent!(yaml_8, r"^(null|Null|NULL|~)$"); // yaml-0.2.1: r"^(true|True|TRUE|yes|Yes|YES)$" consistent!(yaml_9, r"^(true|True|TRUE|yes|Yes|YES)$"); // yaml-0.2.1: r"^(false|False|FALSE|no|No|NO)$" consistent!(yaml_10, r"^(false|False|FALSE|no|No|NO)$"); // kefia-0.1.0: r"(?m)^(\S+)/(\S+) (\S+)(?: \((.*)\))?$" consistent!(kefia_0, r"(?m)^(\S+)/(\S+) (\S+)(?: \((.*)\))?$"); // risp-0.7.0: "^(\\s+|;.*?(\n|$))+" consistent!(risp_0, "^(\\s+|;.*?(\n|$))+"); // risp-0.7.0: "^\".*?\"" consistent!(risp_1, "^\".*?\""); // risp-0.7.0: r"^[^\s\{\}()\[\]]+" consistent!(risp_2, r"^[^\s\{\}()\[\]]+"); // risp-0.7.0: r"^-?\d+" consistent!(risp_3, r"^-?\d+"); // ripgrep-0.8.1: "^([0-9]+)([KMG])?$" consistent!(ripgrep_0, "^([0-9]+)([KMG])?$"); // riquid-0.0.1: r"^\w+" consistent!(riquid_0, r"^\w+"); // riquid-0.0.1: r"^\d+" consistent!(riquid_1, r"^\d+"); // recursive_disassembler-2.1.2: r"\A(0x)?([a-fA-F0-9]+)\z" consistent!(recursive_disassembler_0, r"\A(0x)?([a-fA-F0-9]+)\z"); // remake-0.1.0: r"^[a-zA-Z_][a-zA-Z0-9_]*" consistent!(remake_0, r"^[a-zA-Z_][a-zA-Z0-9_]*"); // regex-decode-0.1.0: r"'(?P[^']+)'\s+\((?P<year>\d{4})\)" consistent!(regex_decode_0, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); // regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" consistent!(regex_decode_1, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); // regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" consistent!(regex_decode_2, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); // regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" consistent!(regex_decode_3, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); // regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" consistent!(regex_decode_4, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); // regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" consistent!(regex_decode_5, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); // regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{2})\)" consistent!(regex_decode_6, r"'(?P<title>[^']+)'\s+\((?P<year>\d{2})\)"); // regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" consistent!(regex_decode_7, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); // regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)" consistent!(regex_decode_8, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})\)"); // regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" consistent!(regex_decode_9, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); // regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" consistent!(regex_decode_10, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); // regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" consistent!(regex_decode_11, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); // regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" consistent!(regex_decode_12, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); // regex-decode-0.1.0: r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)" consistent!(regex_decode_13, r"'(?P<title>[^']+)'\s+\((?P<year>\d{4})?\)"); // regex-cache-0.2.0: "[0-9]{3}-[0-9]{3}-[0-9]{4}" consistent!(regex_cache_0, "[0-9]{3}-[0-9]{3}-[0-9]{4}"); // regex-cache-0.2.0: r"^\d+$" consistent!(regex_cache_1, r"^\d+$"); // regex-cache-0.2.0: r"^[a-z]+$" consistent!(regex_cache_2, r"^[a-z]+$"); // regex-cache-0.2.0: r"^\d+$" consistent!(regex_cache_3, r"^\d+$"); // regex-cache-0.2.0: r"^\d+$" consistent!(regex_cache_4, r"^\d+$"); // regex_dfa-0.5.0: r"\d{4}-\d{2}-\d{2}" consistent!(regex_dfa_0, r"\d{4}-\d{2}-\d{2}"); // reaper-2.0.0: r"^[0-9\p{L} _\\.]{3,16}$" consistent!(reaper_0, r"^[0-9\p{L} _\\.]{3,16}$"); // retdec-0.1.0: r"^attachment; filename=(.+)$" consistent!(retdec_0, r"^attachment; filename=(.+)$"); // renvsubst-0.1.2: r"(\\)(?P<head>\$[0-9A-Za-z_{])" consistent!(renvsubst_0, r"(\\)(?P<head>\$[0-9A-Za-z_{])"); // renvsubst-0.1.2: r"\$([[:word:]]+)" consistent!(renvsubst_1, r"\$([[:word:]]+)"); // renvsubst-0.1.2: r"\$\{([[:word:]]+)\}" consistent!(renvsubst_2, r"\$\{([[:word:]]+)\}"); // rexpect-0.3.0: r"'[a-z]+'" consistent!(rexpect_0, r"'[a-z]+'"); // rexpect-0.3.0: r"^\d{4}-\d{2}-\d{2}$" consistent!(rexpect_1, r"^\d{4}-\d{2}-\d{2}$"); // rexpect-0.3.0: r"-\d{2}-" consistent!(rexpect_2, r"-\d{2}-"); // luther-0.1.0: "^a(b|c)c*$" consistent!(luther_0, "^a(b|c)c*$"); // little_boxes-1.6.0: r"(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]" consistent!(little_boxes_0, r"(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]"); // libimagentrytag-0.8.0: "^[a-zA-Z]([a-zA-Z0-9_-]*)$" consistent!(libimagentrytag_0, "^[a-zA-Z]([a-zA-Z0-9_-]*)$"); // libimaginteraction-0.8.0: r"^[Yy](\n?)$" consistent!(libimaginteraction_0, r"^[Yy](\n?)$"); // libimaginteraction-0.8.0: r"^[Nn](\n?)$" consistent!(libimaginteraction_1, r"^[Nn](\n?)$"); // libimagutil-0.8.0: "^(?P<KEY>([^=]*))=(.*)$" consistent!(libimagutil_0, "^(?P<KEY>([^=]*))=(.*)$"); // libimagutil-0.8.0: "(.*)=(\"(?P<QVALUE>([^\"]*))\"|(?P<VALUE>(.*)))$" consistent!(libimagutil_1, "(.*)=(\"(?P<QVALUE>([^\"]*))\"|(?P<VALUE>(.*)))$"); // linux_ip-0.1.0: r"\s+" consistent!(linux_ip_0, r"\s+"); // linux_ip-0.1.0: r"\s*[\n\r]+\s*" consistent!(linux_ip_1, r"\s*[\n\r]+\s*"); // linux_ip-0.1.0: r"^([0-9a-fA-F\.:/]+)\s+dev\s+([a-z0-9\.]+)\s*(.*)$" consistent!(linux_ip_2, r"^([0-9a-fA-F\.:/]+)\s+dev\s+([a-z0-9\.]+)\s*(.*)$"); // linux_ip-0.1.0: r"^([0-9a-fA-F\.:/]+|default)\s+via\s+([a-z0-9\.:]+)\s+dev\s+([a-z0-9\.]+)\s*(.*)$" consistent!(linux_ip_3, r"^([0-9a-fA-F\.:/]+|default)\s+via\s+([a-z0-9\.:]+)\s+dev\s+([a-z0-9\.]+)\s*(.*)$"); // linux_ip-0.1.0: r"^(blackhole)\s+([0-9a-fA-F\.:/]+)$" consistent!(linux_ip_4, r"^(blackhole)\s+([0-9a-fA-F\.:/]+)$"); // linux_ip-0.1.0: r"^(unreachable)\s+([0-9a-fA-F\.:/]+)\s+dev\s+([a-z0-9\.]+)\s+(.*)$" consistent!(linux_ip_5, r"^(unreachable)\s+([0-9a-fA-F\.:/]+)\s+dev\s+([a-z0-9\.]+)\s+(.*)$"); // linux_ip-0.1.0: r"\s*[\n\r]+\s*" consistent!(linux_ip_6, r"\s*[\n\r]+\s*"); // linux_ip-0.1.0: r"^\d+:\s+([a-zA-Z0-9\.-]+)(@\S+)*:\s+(.*)$" consistent!(linux_ip_7, r"^\d+:\s+([a-zA-Z0-9\.-]+)(@\S+)*:\s+(.*)$"); // linux_ip-0.1.0: r"\s*link/ether\s+([a-f0-9:]+)\s+.*" consistent!(linux_ip_8, r"\s*link/ether\s+([a-f0-9:]+)\s+.*"); // linux_ip-0.1.0: r"\s*inet[6]*\s+([0-9a-f:\./]+)\s+.*" consistent!(linux_ip_9, r"\s*inet[6]*\s+([0-9a-f:\./]+)\s+.*"); // linky-0.1.4: r"[^\w -]" consistent!(linky_0, r"[^\w -]"); // linky-0.1.4: r"^(.*):(\d+): [^ ]* ([^ ]*)$" consistent!(linky_1, r"^(.*):(\d+): [^ ]* ([^ ]*)$"); // limonite-0.2.1: r"^(\d{4}-\d{2}-\d{2})-(\d{3})-(.+)$" consistent!(limonite_0, r"^(\d{4}-\d{2}-\d{2})-(\d{3})-(.+)$"); // process-queue-0.1.1: r"^[a-zA-Z]+$" consistent!(process_queue_0, r"^[a-zA-Z]+$"); // pronghorn-0.1.2: r"^\{([a-zA-Z_]+)\}$" consistent!(pronghorn_0, r"^\{([a-zA-Z_]+)\}$"); // protocol-ftp-client-0.1.1: "(?m:^(\\d{3}) (.+)\r$)" consistent!(protocol_ftp_client_0, "(?m:^(\\d{3}) (.+)\r$)"); // protocol-ftp-client-0.1.1: "\"(.+)\"" consistent!(protocol_ftp_client_1, "\"(.+)\""); // protocol-ftp-client-0.1.1: "(\\w+) [Tt]ype: (\\w+)" consistent!(protocol_ftp_client_2, "(\\w+) [Tt]ype: (\\w+)"); // protocol-ftp-client-0.1.1: "(?m:^(\\d{3})-.+\r$)" consistent!(protocol_ftp_client_3, "(?m:^(\\d{3})-.+\r$)"); // protocol-ftp-client-0.1.1: "Entering Passive Mode \\((\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)\\)" consistent!(protocol_ftp_client_4, "Entering Passive Mode \\((\\d+),(\\d+),(\\d+),(\\d+),(\\d+),(\\d+)\\)"); // protocol-ftp-client-0.1.1: "(?m:^(.+)\r$)" consistent!(protocol_ftp_client_5, "(?m:^(.+)\r$)"); // protocol-ftp-client-0.1.1: "^([d-])(?:[rwx-]{3}){3} +\\d+ +\\w+ +\\w+ +(\\d+) +(.+) +(.+)$" consistent!(protocol_ftp_client_6, "^([d-])(?:[rwx-]{3}){3} +\\d+ +\\w+ +\\w+ +(\\d+) +(.+) +(.+)$"); // article-date-extractor-0.1.1: r"([\./\-_]{0,1}(19|20)\d{2})[\./\-_]{0,1}(([0-3]{0,1}[0-9][\./\-_])|(\w{3,5}[\./\-_]))([0-3]{0,1}[0-9][\./\-]{0,1})" consistent!(article_date_extractor_0, r"([\./\-_]{0,1}(19|20)\d{2})[\./\-_]{0,1}(([0-3]{0,1}[0-9][\./\-_])|(\w{3,5}[\./\-_]))([0-3]{0,1}[0-9][\./\-]{0,1})"); // article-date-extractor-0.1.1: r"(?i)publishdate|pubdate|timestamp|article_date|articledate|date" consistent!(article_date_extractor_1, r"(?i)publishdate|pubdate|timestamp|article_date|articledate|date"); // arthas_plugin-0.1.1: r"type\((.*)\)" consistent!(arthas_plugin_0, r"type\((.*)\)"); // arthas_plugin-0.1.1: r"Vec<(.*)>" consistent!(arthas_plugin_1, r"Vec<(.*)>"); // arthas_plugin-0.1.1: r"Option<(.*)>" consistent!(arthas_plugin_2, r"Option<(.*)>"); // arthas_plugin-0.1.1: r"HashMap<[a-z0-9A-Z]+, *(.*)>" consistent!(arthas_plugin_3, r"HashMap<[a-z0-9A-Z]+, *(.*)>"); // arthas_derive-0.1.0: "Vec *< *(.*) *>" consistent!(arthas_derive_0, "Vec *< *(.*) *>"); // arthas_derive-0.1.0: r"Option *< *(.*) *>" consistent!(arthas_derive_1, r"Option *< *(.*) *>"); // arthas_derive-0.1.0: r"HashMap *< *[a-z0-9A-Z]+ *, *(.*) *>" consistent!(arthas_derive_2, r"HashMap *< *[a-z0-9A-Z]+ *, *(.*) *>"); // arpabet-0.2.0: r"^([\w\-\(\)\.']+)\s+([^\s].*)\s*$" consistent!(arpabet_0, r"^([\w\-\(\)\.']+)\s+([^\s].*)\s*$"); // arpabet-0.2.0: r"^;;;\s+" consistent!(arpabet_1, r"^;;;\s+"); // glossy_codegen-0.2.0: r"/\*.*?\*/|//.*" consistent!(glossy_codegen_0, r"/\*.*?\*/|//.*"); // glossy_codegen-0.2.0: "^\\s*#\\s*include\\s+<([:print:]+)>\\s*$" consistent!(glossy_codegen_1, "^\\s*#\\s*include\\s+<([:print:]+)>\\s*$"); // glossy_codegen-0.2.0: "^\\s*#\\s*include\\s+\"([:print:]+)\"\\s*$" consistent!(glossy_codegen_2, "^\\s*#\\s*include\\s+\"([:print:]+)\"\\s*$"); // glossy_codegen-0.2.0: r"^\s*#\s*version\s+(\d+)" consistent!(glossy_codegen_3, r"^\s*#\s*version\s+(\d+)"); // glossy_codegen-0.2.0: r"^\s*$" consistent!(glossy_codegen_4, r"^\s*$"); // gluster-1.0.1: r"(?P<addr>via \S+)" consistent!(gluster_0, r"(?P<addr>via \S+)"); // gluster-1.0.1: r"(?P<src>src \S+)" consistent!(gluster_1, r"(?P<src>src \S+)"); // gl_helpers-0.1.7: r"(.*)\[\d+\]" consistent!(gl_helpers_0, r"(.*)\[\d+\]"); // gl_helpers-0.1.7: r"(\d+).(\d+)" consistent!(gl_helpers_1, r"(\d+).(\d+)"); // glr-parser-0.0.1: r"(?P<c>[\\\.\+\*\?\(\)\|\[\]\{\}\^\$])" consistent!(glr_parser_0, r"(?P<c>[\\\.\+\*\?\(\)\|\[\]\{\}\^\$])"); // glr-parser-0.0.1: r"^\w+$" consistent!(glr_parser_1, r"^\w+$"); // glr-parser-0.0.1: "'[^']+'" consistent!(glr_parser_2, "'[^']+'"); // hoodlum-0.5.0: r"(?m)//.*" consistent!(hoodlum_0, r"(?m)//.*"); // form-checker-0.2.2: r"^1\d{10}$" consistent!(form_checker_0, r"^1\d{10}$"); // form-checker-0.2.2: r"(?i)^[\w.%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$" consistent!(form_checker_1, r"(?i)^[\w.%+-]+@(?:[A-Z0-9-]+\.)+[A-Z]{2,4}$"); // wikibase-0.2.0: r"(?P<user_agent>[a-zA-Z0-9-_]+/[0-9\.]+)" consistent!(wikibase_0, r"(?P<user_agent>[a-zA-Z0-9-_]+/[0-9\.]+)"); // wifiscanner-0.3.6: r"Cell [0-9]{2,} - Address:" consistent!(wifiscanner_0, r"Cell [0-9]{2,} - Address:"); // wifiscanner-0.3.6: r"([0-9a-zA-Z]{1}[0-9a-zA-Z]{1}[:]{1}){5}[0-9a-zA-Z]{1}[0-9a-zA-Z]{1}" consistent!(wifiscanner_1, r"([0-9a-zA-Z]{1}[0-9a-zA-Z]{1}[:]{1}){5}[0-9a-zA-Z]{1}[0-9a-zA-Z]{1}"); // wifiscanner-0.3.6: r"Signal level=(\d+)/100" consistent!(wifiscanner_2, r"Signal level=(\d+)/100"); // bbcode-1.0.2: r"(?s)\[b\](.*?)\[/b\]" consistent!(bbcode_0, r"(?s)\[b\](.*?)\[/b\]"); // bbcode-1.0.2: r"(?s)\[i\](.*?)\[/i\]" consistent!(bbcode_1, r"(?s)\[i\](.*?)\[/i\]"); // bbcode-1.0.2: r"(?s)\[u\](.*?)\[/u\]" consistent!(bbcode_2, r"(?s)\[u\](.*?)\[/u\]"); // bbcode-1.0.2: r"(?s)\[s\](.*?)\[/s\]" consistent!(bbcode_3, r"(?s)\[s\](.*?)\[/s\]"); // bbcode-1.0.2: r"(?s)\[size=(\d+)](.*?)\[/size\]" consistent!(bbcode_4, r"(?s)\[size=(\d+)](.*?)\[/size\]"); // bbcode-1.0.2: r"(?s)\[color=(.+)](.*?)\[/color\]" consistent!(bbcode_5, r"(?s)\[color=(.+)](.*?)\[/color\]"); // bbcode-1.0.2: r"(?s)\[center\](.*?)\[/center\]" consistent!(bbcode_6, r"(?s)\[center\](.*?)\[/center\]"); // bbcode-1.0.2: r"(?s)\[left\](.*?)\[/left\]" consistent!(bbcode_7, r"(?s)\[left\](.*?)\[/left\]"); // bbcode-1.0.2: r"(?s)\[right\](.*?)\[/right\]" consistent!(bbcode_8, r"(?s)\[right\](.*?)\[/right\]"); // bbcode-1.0.2: r"(?s)\[table\](.*?)\[/table\]" consistent!(bbcode_9, r"(?s)\[table\](.*?)\[/table\]"); // bbcode-1.0.2: r"(?s)\[td\](.*?)\[/td\]" consistent!(bbcode_10, r"(?s)\[td\](.*?)\[/td\]"); // bbcode-1.0.2: r"(?s)\[tr\](.*?)\[/tr\]" consistent!(bbcode_11, r"(?s)\[tr\](.*?)\[/tr\]"); // bbcode-1.0.2: r"(?s)\[th\](.*?)\[/th\]" consistent!(bbcode_12, r"(?s)\[th\](.*?)\[/th\]"); // bbcode-1.0.2: r"(?s)\[url\](.*?)\[/url\]" consistent!(bbcode_13, r"(?s)\[url\](.*?)\[/url\]"); // bbcode-1.0.2: r"(?s)\[url=(.+)\](.*?)\[/url\]" consistent!(bbcode_14, r"(?s)\[url=(.+)\](.*?)\[/url\]"); // bbcode-1.0.2: r"(?s)\[quote\](.*?)\[/quote\]" consistent!(bbcode_15, r"(?s)\[quote\](.*?)\[/quote\]"); // bbcode-1.0.2: r"(?s)\[quote=(.+)\](.*?)\[/quote\]" consistent!(bbcode_16, r"(?s)\[quote=(.+)\](.*?)\[/quote\]"); // bbcode-1.0.2: r"(?s)\[img=(\d+)x(\d+)(\b.*)?\](.*?)\[/img\]" consistent!(bbcode_17, r"(?s)\[img=(\d+)x(\d+)(\b.*)?\](.*?)\[/img\]"); // bbcode-1.0.2: r"(?s)\[img=(.+)(\b.*)?\](.*?)\[/img\]" consistent!(bbcode_18, r"(?s)\[img=(.+)(\b.*)?\](.*?)\[/img\]"); // bbcode-1.0.2: r"(?s)\[img(\b.*)?\](.*?)\[/img\]" consistent!(bbcode_19, r"(?s)\[img(\b.*)?\](.*?)\[/img\]"); // bbcode-1.0.2: r"(?s)\[ol\](.*?)\[/ol\]" consistent!(bbcode_20, r"(?s)\[ol\](.*?)\[/ol\]"); // bbcode-1.0.2: r"(?s)\[ul\](.*?)\[/ul\]" consistent!(bbcode_21, r"(?s)\[ul\](.*?)\[/ul\]"); // bbcode-1.0.2: r"(?s)\[list\](.*?)\[/list\]" consistent!(bbcode_22, r"(?s)\[list\](.*?)\[/list\]"); // bbcode-1.0.2: r"(?s)\[youtube\](.*?)\[/youtube\]" consistent!(bbcode_23, r"(?s)\[youtube\](.*?)\[/youtube\]"); // bbcode-1.0.2: r"(?s)\[youtube=(\d+)x(\d+)\](.*?)\[/youtube\]" consistent!(bbcode_24, r"(?s)\[youtube=(\d+)x(\d+)\](.*?)\[/youtube\]"); // bbcode-1.0.2: r"(?s)\[li\](.*?)\[/li\]" consistent!(bbcode_25, r"(?s)\[li\](.*?)\[/li\]"); // block-utils-0.5.0: r"loop\d+" consistent!(block_utils_0, r"loop\d+"); // block-utils-0.5.0: r"ram\d+" consistent!(block_utils_1, r"ram\d+"); // block-utils-0.5.0: r"md\d+" consistent!(block_utils_2, r"md\d+"); // kvvliveapi-0.1.0: r"^([1-9]) min$" consistent!(kvvliveapi_0, r"^([1-9]) min$"); // rfc822_sanitizer-0.3.3: r"(\d{2}):(\d{2}):(\d{2})" consistent!(rfc822_sanitizer_0, r"(\d{2}):(\d{2}):(\d{2})"); // rfc822_sanitizer-0.3.3: r"(\d{1,2}):(\d{1,2}):(\d{1,2})" consistent!(rfc822_sanitizer_1, r"(\d{1,2}):(\d{1,2}):(\d{1,2})"); // faker-0.0.4: r"[2-9]" consistent!(faker_0, r"[2-9]"); // faker-0.0.4: r"[1-9]" consistent!(faker_1, r"[1-9]"); // faker-0.0.4: r"[0-9]" consistent!(faker_2, r"[0-9]"); // faker-0.0.4: r"\d{10}" consistent!(faker_3, r"\d{10}"); // faker-0.0.4: r"\d{1}" consistent!(faker_4, r"\d{1}"); // faker-0.0.4: r"^\w+" consistent!(faker_5, r"^\w+"); // faker-0.0.4: r"^\w+" consistent!(faker_6, r"^\w+"); // faker-0.0.4: r"^(\w+\.? ?){2,3}$" consistent!(faker_7, r"^(\w+\.? ?){2,3}$"); // faker-0.0.4: r"^[A-Z][a-z]+\.?$" consistent!(faker_8, r"^[A-Z][a-z]+\.?$"); // faker-0.0.4: r"^[A-Z][A-Za-z]*\.?$" consistent!(faker_9, r"^[A-Z][A-Za-z]*\.?$"); // faker-0.0.4: r"http://lorempixel.com/100/100/\w+" consistent!(faker_10, r"http://lorempixel.com/100/100/\w+"); // faker-0.0.4: r"http://lorempixel.com/100/100/cats" consistent!(faker_11, r"http://lorempixel.com/100/100/cats"); // fancy-regex-0.1.0: "(?i:ß)" consistent!(fancy_regex_0, "(?i:ß)"); // fancy-regex-0.1.0: "(?i:\\x{0587})" consistent!(fancy_regex_1, "(?i:\\x{0587})"); // fancy-regex-0.1.0: "^\\\\([!-/:-@\\[-`\\{-~aftnrv]|[0-7]{1,3}|x[0-9a-fA-F]{2}|x\\{[0-9a-fA-F]{1,6}\\})" consistent!(fancy_regex_2, "^\\\\([!-/:-@\\[-`\\{-~aftnrv]|[0-7]{1,3}|x[0-9a-fA-F]{2}|x\\{[0-9a-fA-F]{1,6}\\})"); // fancy-prompt-0.1.5: r"/([^/])[^/]+/" consistent!(fancy_prompt_0, r"/([^/])[^/]+/"); // fancy-prompt-0.1.5: r"^([^:]+):.*?(?::([^:]+))?$" consistent!(fancy_prompt_1, r"^([^:]+):.*?(?::([^:]+))?$"); // fanta-0.2.0: r"^(/?__\w+__)/(.*)" consistent!(fanta_0, r"^(/?__\w+__)/(.*)"); // fanta-cli-0.1.1: r"(.)([A-Z])" consistent!(fanta_cli_0, r"(.)([A-Z])"); // fanta-cli-0.1.1: "\\{:[^\\s]+\\}" consistent!(fanta_cli_1, "\\{:[^\\s]+\\}"); // amethyst_tools-0.7.1: "(?P<last>[^\r])\n" consistent!(amethyst_tools_0, "(?P<last>[^\r])\n"); // amigo-0.3.1: r"^-?\d+(\.\d)?" consistent!(amigo_0, r"^-?\d+(\.\d)?"); // amigo-0.3.1: r"^[a-zA-Z_]+[\w-]*[!?_]?" consistent!(amigo_1, r"^[a-zA-Z_]+[\w-]*[!?_]?"); // amigo-0.3.1: r"^\(" consistent!(amigo_2, r"^\("); // amigo-0.3.1: r"^\)" consistent!(amigo_3, r"^\)"); // amigo-0.3.1: r"^\s+" consistent!(amigo_4, r"^\s+"); // ethcore-logger-1.12.0: "\x1b\\[[^m]+m" consistent!(ethcore_logger_0, "\x1b\\[[^m]+m"); // dash2html-1.0.1: r"__.*?__" consistent!(dash2html_0, r"__.*?__"); // dash2html-1.0.1: r"(?i)@(?:time|clipboard|cursor|date)" consistent!(dash2html_1, r"(?i)@(?:time|clipboard|cursor|date)"); // os_type-2.0.0: r"^Microsoft Windows \[Version\s(\d+\.\d+\.\d+)\]$" consistent!(os_type_0, r"^Microsoft Windows \[Version\s(\d+\.\d+\.\d+)\]$"); // os_type-2.0.0: r"ProductName:\s([\w\s]+)\n" consistent!(os_type_1, r"ProductName:\s([\w\s]+)\n"); // os_type-2.0.0: r"ProductVersion:\s(\w+\.\w+\.\w+)" consistent!(os_type_2, r"ProductVersion:\s(\w+\.\w+\.\w+)"); // os_type-2.0.0: r"BuildVersion:\s(\w+)" consistent!(os_type_3, r"BuildVersion:\s(\w+)"); // os_type-2.0.0: r"(\w+) Linux release" consistent!(os_type_4, r"(\w+) Linux release"); // os_type-2.0.0: r"release\s([\w\.]+)" consistent!(os_type_5, r"release\s([\w\.]+)"); // os_type-2.0.0: r"Distributor ID:\s(\w+)" consistent!(os_type_6, r"Distributor ID:\s(\w+)"); // os_type-2.0.0: r"Release:\s([\w\.]+)" consistent!(os_type_7, r"Release:\s([\w\.]+)"); // bindgen-0.37.0: r"typename type\-parameter\-\d+\-\d+::.+" consistent!(bindgen_0, r"typename type\-parameter\-\d+\-\d+::.+"); // imap-0.8.1: "^+(.*)\r\n" consistent!(imap_0, "^+(.*)\r\n"); // image-base64-0.1.0: r"^ffd8ffe0" consistent!(image_base64_0, r"^ffd8ffe0"); // image-base64-0.1.0: r"^89504e47" consistent!(image_base64_1, r"^89504e47"); // image-base64-0.1.0: r"^47494638" consistent!(image_base64_2, r"^47494638"); // json-pointer-0.3.2: "^(/([^/~]|~[01])*)*$" consistent!(json_pointer_0, "^(/([^/~]|~[01])*)*$"); // json-pointer-0.3.2: "^#(/([^/~%]|~[01]|%[0-9a-fA-F]{2})*)*$" consistent!(json_pointer_1, "^#(/([^/~%]|~[01]|%[0-9a-fA-F]{2})*)*$"); // mysql_common-0.7.0: r"^5.5.5-(\d{1,2})\.(\d{1,2})\.(\d{1,3})-MariaDB" consistent!(mysql_common_0, r"^5.5.5-(\d{1,2})\.(\d{1,2})\.(\d{1,3})-MariaDB"); // mysql_common-0.7.0: r"^(\d{1,2})\.(\d{1,2})\.(\d{1,3})(.*)" consistent!(mysql_common_1, r"^(\d{1,2})\.(\d{1,2})\.(\d{1,3})(.*)"); // government_id-0.1.0: r"^[0-9]{4}[0-9A-Z]{2}[0-9]{3}$" consistent!(government_id_0, r"^[0-9]{4}[0-9A-Z]{2}[0-9]{3}$"); // ohmers-0.1.1: r"UniqueIndexViolation: (\w+)" consistent!(ohmers_0, r"UniqueIndexViolation: (\w+)"); // eliza-1.0.0: r"(.*) you are (.*)" consistent!(eliza_0, r"(.*) you are (.*)"); // eliza-1.0.0: r"(.*) you are (.*)" consistent!(eliza_1, r"(.*) you are (.*)"); // eliza-1.0.0: r"(.*) you are (.*)" consistent!(eliza_2, r"(.*) you are (.*)"); // chema-0.0.5: "^\\s*\\*" consistent!(chema_0, "^\\s*\\*"); // chema-0.0.5: "^\\s*@(\\w+)\\s+(.*)" consistent!(chema_1, "^\\s*@(\\w+)\\s+(.*)"); // chord3-0.3.0: r"^\s*#" consistent!(chord3_0, r"^\s*#"); // chord3-0.3.0: r"\{(?P<cmd>\w+)(?::?\s*(?P<arg>.*))?\}" consistent!(chord3_1, r"\{(?P<cmd>\w+)(?::?\s*(?P<arg>.*))?\}"); // chord3-0.3.0: r"\{(eot|end_of_tab):?\s*" consistent!(chord3_2, r"\{(eot|end_of_tab):?\s*"); // chord3-0.3.0: r"([^\[]*)(?:\[([^\]]*)\])?" consistent!(chord3_3, r"([^\[]*)(?:\[([^\]]*)\])?"); // checkmail-0.1.1: "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$" consistent!(checkmail_0, "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"); // cntk-0.2.1: r"\b\w\w+\b" consistent!(cntk_0, r"\b\w\w+\b"); // cntk-0.2.1: r"\b\w\w+\b" consistent!(cntk_1, r"\b\w\w+\b"); // cniguru-0.1.0: r"\(id: (\d+)\)" consistent!(cniguru_0, r"\(id: (\d+)\)"); // upm_lib-0.3.0: r"^(\d+)\.(\d+)\.(\d+)(?:-([\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*))?(?:\+([\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*))?$" consistent!(upm_lib_0, r"^(\d+)\.(\d+)\.(\d+)(?:-([\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*))?(?:\+([\dA-Za-z-]+(?:\.[\dA-Za-z-]+)*))?$"); // avro-0.2.1: r"^\s*(\*+(\s+))?" consistent!(avro_0, r"^\s*(\*+(\s+))?"); // avro-0.2.1: r"^\s*(\*+)?" consistent!(avro_1, r"^\s*(\*+)?"); // nomi-0.0.2: "[0-9]+" consistent!(nomi_0, "[0-9]+"); // nodes-0.1.0: "([0-9]+)@(?:nodes|n)?:([^@]+)?" consistent!(nodes_0, "([0-9]+)@(?:nodes|n)?:([^@]+)?"); // not-stakkr-1.0.0: r"(?i)in (\d+) (second|minute|hour|day|week)s?" consistent!(not_stakkr_0, r"(?i)in (\d+) (second|minute|hour|day|week)s?"); // notetxt-0.0.1: "^([A-Za-z0-9 -_:]+)\n-+\n" consistent!(notetxt_0, "^([A-Za-z0-9 -_:]+)\n-+\n"); // nail-0.1.0-pre.0: r"^-?[0-9]+(\.[0-9]+)?([eE]-?[0-9]+)?$" consistent!(nail_0, r"^-?[0-9]+(\.[0-9]+)?([eE]-?[0-9]+)?$"); // nail-0.1.0-pre.0: r"^-?[0-9]+$" consistent!(nail_1, r"^-?[0-9]+$"); // askalono-0.2.0: r"[^\w\s\pP]+" consistent!(askalono_0, r"[^\w\s\pP]+"); // askalono-0.2.0: r"(?x)[ \t\p{Zs} \\ / \| \x2044 ]+" consistent!(askalono_1, r"(?x)[ \t\p{Zs} \\ / \| \x2044 ]+"); // askalono-0.2.0: r"\p{Pd}+" consistent!(askalono_2, r"\p{Pd}+"); // askalono-0.2.0: r"\p{Ps}+" consistent!(askalono_3, r"\p{Ps}+"); // askalono-0.2.0: r"\p{Pe}+" consistent!(askalono_4, r"\p{Pe}+"); // askalono-0.2.0: r"\p{Pc}+" consistent!(askalono_5, r"\p{Pc}+"); // askalono-0.2.0: r"[©Ⓒⓒ]" consistent!(askalono_6, r"[©Ⓒⓒ]"); // askalono-0.2.0: r"[\r\n\v\f]" consistent!(askalono_7, r"[\r\n\v\f]"); // askalono-0.2.0: r"\n{3,}" consistent!(askalono_8, r"\n{3,}"); // askalono-0.2.0: r"[^\w\s]+" consistent!(askalono_9, r"[^\w\s]+"); // askalono-0.2.0: r"\s+" consistent!(askalono_10, r"\s+"); // assembunny_plus-0.0.3: r"[^0-9a-zA-Z_]" consistent!(assembunny_plus_0, r"[^0-9a-zA-Z_]"); // assembunny_plus-0.0.3: r"[0-9]" consistent!(assembunny_plus_1, r"[0-9]"); // salt-compressor-0.4.0: r"(?m)^Minion (\S*) did not respond\. No job will be sent\.$" consistent!(salt_compressor_0, r"(?m)^Minion (\S*) did not respond\. No job will be sent\.$"); // sabisabi-0.4.1: r"</?[^>]+?>" consistent!(sabisabi_0, r"</?[^>]+?>"); // sabisabi-0.4.1: r"\([^)]*\)" consistent!(sabisabi_1, r"\([^)]*\)"); // sassers-0.13.5-h28: "@import \"([^\"]*)\";" consistent!(sassers_0, "@import \"([^\"]*)\";"); // shadowsocks-0.6.2: r"[A-Za-z\d-]{1,63}$" consistent!(shadowsocks_0, r"[A-Za-z\d-]{1,63}$"); // shkeleton-0.1.5: "[abc]+" consistent!(shkeleton_0, "[abc]+"); // shellwords-0.1.0: r"([^A-Za-z0-9_\-.,:/@\n])" consistent!(shellwords_0, r"([^A-Za-z0-9_\-.,:/@\n])"); // shellwords-0.1.0: r"\n" consistent!(shellwords_1, r"\n"); // shush-0.1.5: "(?P<num>[0-9]+)(?P<units>[dhms])" consistent!(shush_0, "(?P<num>[0-9]+)(?P<units>[dhms])"); // woothee-0.8.0: r"(?:Chrome|CrMo|CriOS)/([.0-9]+)" consistent!(woothee_0, r"(?:Chrome|CrMo|CriOS)/([.0-9]+)"); // woothee-0.8.0: r"Vivaldi/([.0-9]+)" consistent!(woothee_1, r"Vivaldi/([.0-9]+)"); // woothee-0.8.0: r"Firefox/([.0-9]+)" consistent!(woothee_2, r"Firefox/([.0-9]+)"); // woothee-0.8.0: r"^Mozilla/[.0-9]+ \((?:Mobile|Tablet);(?:.*;)? rv:([.0-9]+)\) Gecko/[.0-9]+ Firefox/[.0-9]+$" consistent!(woothee_3, r"^Mozilla/[.0-9]+ \((?:Mobile|Tablet);(?:.*;)? rv:([.0-9]+)\) Gecko/[.0-9]+ Firefox/[.0-9]+$"); // woothee-0.8.0: r"FxiOS/([.0-9]+)" consistent!(woothee_4, r"FxiOS/([.0-9]+)"); // woothee-0.8.0: r"\(([^;)]+);FOMA;" consistent!(woothee_5, r"\(([^;)]+);FOMA;"); // woothee-0.8.0: r"jig browser[^;]+; ([^);]+)" consistent!(woothee_6, r"jig browser[^;]+; ([^);]+)"); // woothee-0.8.0: r"(?i)rss(?:reader|bar|[-_ /;()]|[ +]*/)" consistent!(woothee_7, r"(?i)rss(?:reader|bar|[-_ /;()]|[ +]*/)"); // woothee-0.8.0: r"(?i)(?:bot|crawler|spider)(?:[-_ ./;@()]|$)" consistent!(woothee_8, r"(?i)(?:bot|crawler|spider)(?:[-_ ./;@()]|$)"); // woothee-0.8.0: r"(?i)(?:feed|web) ?parser" consistent!(woothee_9, r"(?i)(?:feed|web) ?parser"); // woothee-0.8.0: r"(?i)watch ?dog" consistent!(woothee_10, r"(?i)watch ?dog"); // woothee-0.8.0: r"Edge/([.0-9]+)" consistent!(woothee_11, r"Edge/([.0-9]+)"); // woothee-0.8.0: r"MSIE ([.0-9]+);" consistent!(woothee_12, r"MSIE ([.0-9]+);"); // woothee-0.8.0: r"Version/([.0-9]+)" consistent!(woothee_13, r"Version/([.0-9]+)"); // woothee-0.8.0: r"Opera[/ ]([.0-9]+)" consistent!(woothee_14, r"Opera[/ ]([.0-9]+)"); // woothee-0.8.0: r"OPR/([.0-9]+)" consistent!(woothee_15, r"OPR/([.0-9]+)"); // woothee-0.8.0: r"Version/([.0-9]+)" consistent!(woothee_16, r"Version/([.0-9]+)"); // woothee-0.8.0: r"(?:SoftBank|Vodafone|J-PHONE)/[.0-9]+/([^ /;()]+)" consistent!(woothee_17, r"(?:SoftBank|Vodafone|J-PHONE)/[.0-9]+/([^ /;()]+)"); // woothee-0.8.0: r"Trident/([.0-9]+);" consistent!(woothee_18, r"Trident/([.0-9]+);"); // woothee-0.8.0: r" rv:([.0-9]+)" consistent!(woothee_19, r" rv:([.0-9]+)"); // woothee-0.8.0: r"IEMobile/([.0-9]+);" consistent!(woothee_20, r"IEMobile/([.0-9]+);"); // woothee-0.8.0: r"(?:WILLCOM|DDIPOCKET);[^/]+/([^ /;()]+)" consistent!(woothee_21, r"(?:WILLCOM|DDIPOCKET);[^/]+/([^ /;()]+)"); // woothee-0.8.0: r"Windows ([ .a-zA-Z0-9]+)[;\\)]" consistent!(woothee_22, r"Windows ([ .a-zA-Z0-9]+)[;\\)]"); // woothee-0.8.0: r"^Phone(?: OS)? ([.0-9]+)" consistent!(woothee_23, r"^Phone(?: OS)? ([.0-9]+)"); // woothee-0.8.0: r"iP(hone;|ad;|od) .*like Mac OS X" consistent!(woothee_24, r"iP(hone;|ad;|od) .*like Mac OS X"); // woothee-0.8.0: r"Version/([.0-9]+)" consistent!(woothee_25, r"Version/([.0-9]+)"); // woothee-0.8.0: r"rv:(\d+\.\d+\.\d+)" consistent!(woothee_26, r"rv:(\d+\.\d+\.\d+)"); // woothee-0.8.0: r"FreeBSD ([^;\)]+);" consistent!(woothee_27, r"FreeBSD ([^;\)]+);"); // woothee-0.8.0: r"CrOS ([^\)]+)\)" consistent!(woothee_28, r"CrOS ([^\)]+)\)"); // woothee-0.8.0: r"Android[- ](\d+\.\d+(?:\.\d+)?)" consistent!(woothee_29, r"Android[- ](\d+\.\d+(?:\.\d+)?)"); // woothee-0.8.0: r"PSP \(PlayStation Portable\); ([.0-9]+)\)" consistent!(woothee_30, r"PSP \(PlayStation Portable\); ([.0-9]+)\)"); // woothee-0.8.0: r"PLAYSTATION 3;? ([.0-9]+)\)" consistent!(woothee_31, r"PLAYSTATION 3;? ([.0-9]+)\)"); // woothee-0.8.0: r"PlayStation Vita ([.0-9]+)\)" consistent!(woothee_32, r"PlayStation Vita ([.0-9]+)\)"); // woothee-0.8.0: r"PlayStation 4 ([.0-9]+)\)" consistent!(woothee_33, r"PlayStation 4 ([.0-9]+)\)"); // woothee-0.8.0: r"BB10(?:.+)Version/([.0-9]+) " consistent!(woothee_34, r"BB10(?:.+)Version/([.0-9]+) "); // woothee-0.8.0: r"BlackBerry(?:\d+)/([.0-9]+) " consistent!(woothee_35, r"BlackBerry(?:\d+)/([.0-9]+) "); // woothee-0.8.0: r"; CPU(?: iPhone)? OS (\d+_\d+(?:_\d+)?) like Mac OS X" consistent!(woothee_36, r"; CPU(?: iPhone)? OS (\d+_\d+(?:_\d+)?) like Mac OS X"); // woothee-0.8.0: r"Mac OS X (10[._]\d+(?:[._]\d+)?)(?:\)|;)" consistent!(woothee_37, r"Mac OS X (10[._]\d+(?:[._]\d+)?)(?:\)|;)"); // woothee-0.8.0: r"^(?:Apache-HttpClient/|Jakarta Commons-HttpClient/|Java/)" consistent!(woothee_38, r"^(?:Apache-HttpClient/|Jakarta Commons-HttpClient/|Java/)"); // woothee-0.8.0: r"[- ]HttpClient(/|$)" consistent!(woothee_39, r"[- ]HttpClient(/|$)"); // woothee-0.8.0: r"^(?:PHP|WordPress|CakePHP|PukiWiki|PECL::HTTP)(?:/| |$)" consistent!(woothee_40, r"^(?:PHP|WordPress|CakePHP|PukiWiki|PECL::HTTP)(?:/| |$)"); // woothee-0.8.0: r"(?:PEAR HTTP_Request|HTTP_Request)(?: class|2)" consistent!(woothee_41, r"(?:PEAR HTTP_Request|HTTP_Request)(?: class|2)"); // woothee-0.8.0: r"(?:Rome Client |UnwindFetchor/|ia_archiver |Summify |PostRank/)" consistent!(woothee_42, r"(?:Rome Client |UnwindFetchor/|ia_archiver |Summify |PostRank/)"); // woothee-0.8.0: r"Sleipnir/([.0-9]+)" consistent!(woothee_43, r"Sleipnir/([.0-9]+)"); // word_replace-0.0.3: r"@@[a-z|A-Z|\d]+@@" consistent!(word_replace_0, r"@@[a-z|A-Z|\d]+@@"); // wordcount-0.1.0: r"\w+" consistent!(wordcount_0, r"\w+"); // just-0.3.12: "^([^=]+)=(.*)$" consistent!(just_0, "^([^=]+)=(.*)$"); // emote-0.1.0: r":[a-zA-Z_]+?:" consistent!(emote_0, r":[a-zA-Z_]+?:"); // emojicons-1.0.1: r":([a-zA-Z0-9_+-]+):" consistent!(emojicons_0, r":([a-zA-Z0-9_+-]+):"); // git2_codecommit-0.1.2: r"git-codecommit\.([a-z0-9-]+)\.amazonaws\.com" consistent!(git2_codecommit_0, r"git-codecommit\.([a-z0-9-]+)\.amazonaws\.com"); // git-workarea-3.1.2: r"^submodule\.(?P<name>.*)\.(?P<key>[^=]*)=(?P<value>.*)$" consistent!(git_workarea_0, r"^submodule\.(?P<name>.*)\.(?P<key>[^=]*)=(?P<value>.*)$"); // git-shell-enforce-directory-1.0.0: r"^(?P<command>git-(?:receive|upload)-pack) '(?P<path>.+)'$" consistent!(git_shell_enforce_directory_0, r"^(?P<command>git-(?:receive|upload)-pack) '(?P<path>.+)'$"); // git-journal-1.6.3: r"[ \n]:(.*?):" consistent!(git_journal_0, r"[ \n]:(.*?):"); // git-find-0.3.2: r"^git@(?P<host>[[:alnum:]\._-]+):(?P<path>[[:alnum:]\._\-/]+).git$" consistent!(git_find_0, r"^git@(?P<host>[[:alnum:]\._-]+):(?P<path>[[:alnum:]\._\-/]+).git$"); // gitlab-api-0.6.0: r"private_token=\w{20}" consistent!(gitlab_api_0, r"private_token=\w{20}"); // td-client-0.7.0: "^(http://|https://)" consistent!(td_client_0, "^(http://|https://)"); // karaconv-0.3.0: r"--(?P<type>[a-zA-Z]+)-- (?P<contents>.*)" consistent!(karaconv_0, r"--(?P<type>[a-zA-Z]+)-- (?P<contents>.*)"); // katana-1.0.2: r"(?P<comp>et al\.)(?:\.)" consistent!(katana_0, r"(?P<comp>et al\.)(?:\.)"); // katana-1.0.2: r"\.{3}" consistent!(katana_1, r"\.{3}"); // katana-1.0.2: r"(?P<number>[0-9]+)\.(?P<decimal>[0-9]+)" consistent!(katana_2, r"(?P<number>[0-9]+)\.(?P<decimal>[0-9]+)"); // katana-1.0.2: r"\s\.(?P<nums>[0-9]+)" consistent!(katana_3, r"\s\.(?P<nums>[0-9]+)"); // katana-1.0.2: r"(?:[A-Za-z]\.){2,}" consistent!(katana_4, r"(?:[A-Za-z]\.){2,}"); // katana-1.0.2: r"(?P<init>[A-Z])(?P<point>\.)" consistent!(katana_5, r"(?P<init>[A-Z])(?P<point>\.)"); // katana-1.0.2: r"(?P<title>[A-Z][a-z]{1,3})(\.)" consistent!(katana_6, r"(?P<title>[A-Z][a-z]{1,3})(\.)"); // katana-1.0.2: r"&==&(?P<p>[.!?])" consistent!(katana_7, r"&==&(?P<p>[.!?])"); // katana-1.0.2: r"&\^&(?P<p>[.!?])" consistent!(katana_8, r"&\^&(?P<p>[.!?])"); // katana-1.0.2: r"&\*\*&(?P<p>[.!?])" consistent!(katana_9, r"&\*\*&(?P<p>[.!?])"); // katana-1.0.2: r"&=&(?P<p>[.!?])" consistent!(katana_10, r"&=&(?P<p>[.!?])"); // katana-1.0.2: r"&##&(?P<p>[.!?])" consistent!(katana_11, r"&##&(?P<p>[.!?])"); // katana-1.0.2: r"&\$&(?P<p>[.!?])" consistent!(katana_12, r"&\$&(?P<p>[.!?])"); // kailua_syntax-1.1.0: r"@(?:_|\d+(?:/\d+(?:-\d+)?)?)" consistent!(kailua_syntax_0, r"@(?:_|\d+(?:/\d+(?:-\d+)?)?)"); // kailua_syntax-1.1.0: r"<(\d+)>" consistent!(kailua_syntax_1, r"<(\d+)>"); // ftp-3.0.1: r"\((\d+),(\d+),(\d+),(\d+),(\d+),(\d+)\)" consistent!(ftp_0, r"\((\d+),(\d+),(\d+),(\d+),(\d+),(\d+)\)"); // ftp-3.0.1: r"\b(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\b" consistent!(ftp_1, r"\b(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})\b"); // ftp-3.0.1: r"\s+(\d+)\s*$" consistent!(ftp_2, r"\s+(\d+)\s*$"); // vat-0.1.0: r"<countryCode>(.*?)</countryCode>" consistent!(vat_0, r"<countryCode>(.*?)</countryCode>"); // vat-0.1.0: r"<vatNumber>(.*?)</vatNumber>" consistent!(vat_1, r"<vatNumber>(.*?)</vatNumber>"); // vat-0.1.0: r"<name>(.*?)</name>" consistent!(vat_2, r"<name>(.*?)</name>"); // vat-0.1.0: r"<address>(?s)(.*?)(?-s)</address>" consistent!(vat_3, r"<address>(?s)(.*?)(?-s)</address>"); // vat-0.1.0: r"<valid>(true|false)</valid>" consistent!(vat_4, r"<valid>(true|false)</valid>"); // vat-0.1.0: r"^ATU\d{8}$" consistent!(vat_5, r"^ATU\d{8}$"); // vat-0.1.0: r"^BE0?\d{9, 10}$" consistent!(vat_6, r"^BE0?\d{9, 10}$"); // vat-0.1.0: r"^BG\d{9,10}$" consistent!(vat_7, r"^BG\d{9,10}$"); // vat-0.1.0: r"^HR\d{11}$" consistent!(vat_8, r"^HR\d{11}$"); // vat-0.1.0: r"^CY\d{8}[A-Z]$" consistent!(vat_9, r"^CY\d{8}[A-Z]$"); // vat-0.1.0: r"^CZ\d{8,10}$" consistent!(vat_10, r"^CZ\d{8,10}$"); // vat-0.1.0: r"^DK\d{8}$" consistent!(vat_11, r"^DK\d{8}$"); // vat-0.1.0: r"^EE\d{9}$" consistent!(vat_12, r"^EE\d{9}$"); // vat-0.1.0: r"^FI\d{8}$" consistent!(vat_13, r"^FI\d{8}$"); // vat-0.1.0: r"^FR[A-HJ-NP-Z0-9][A-HJ-NP-Z0-9]\d{9}$" consistent!(vat_14, r"^FR[A-HJ-NP-Z0-9][A-HJ-NP-Z0-9]\d{9}$"); // vat-0.1.0: r"^DE\d{9}$" consistent!(vat_15, r"^DE\d{9}$"); // vat-0.1.0: r"^EL\d{9}$" consistent!(vat_16, r"^EL\d{9}$"); // vat-0.1.0: r"^HU\d{8}$" consistent!(vat_17, r"^HU\d{8}$"); // vat-0.1.0: r"^IE\d[A-Z0-9\+\*]\d{5}[A-Z]{1,2}$" consistent!(vat_18, r"^IE\d[A-Z0-9\+\*]\d{5}[A-Z]{1,2}$"); // vat-0.1.0: r"^IT\d{11}$" consistent!(vat_19, r"^IT\d{11}$"); // vat-0.1.0: r"^LV\d{11}$" consistent!(vat_20, r"^LV\d{11}$"); // vat-0.1.0: r"^LT(\d{9}|\d{12})$" consistent!(vat_21, r"^LT(\d{9}|\d{12})$"); // vat-0.1.0: r"^LU\d{8}$" consistent!(vat_22, r"^LU\d{8}$"); // vat-0.1.0: r"^MT\d{8}$" consistent!(vat_23, r"^MT\d{8}$"); // vat-0.1.0: r"^NL\d{9}B\d{2}$" consistent!(vat_24, r"^NL\d{9}B\d{2}$"); // vat-0.1.0: r"^PL\d{10}$" consistent!(vat_25, r"^PL\d{10}$"); // vat-0.1.0: r"^PT\d{9}$" consistent!(vat_26, r"^PT\d{9}$"); // vat-0.1.0: r"^RO\d{2,10}$" consistent!(vat_27, r"^RO\d{2,10}$"); // vat-0.1.0: r"^SK\d{10}$" consistent!(vat_28, r"^SK\d{10}$"); // vat-0.1.0: r"^SI\d{8}$" consistent!(vat_29, r"^SI\d{8}$"); // vat-0.1.0: r"^ES[A-Z0-9]\d{7}[A-Z0-9]$" consistent!(vat_30, r"^ES[A-Z0-9]\d{7}[A-Z0-9]$"); // vat-0.1.0: r"^SE\d{10}01$" consistent!(vat_31, r"^SE\d{10}01$"); // vat-0.1.0: r"^(GB(GD|HA)\d{3}|GB\d{9}|GB\d{12})$" consistent!(vat_32, r"^(GB(GD|HA)\d{3}|GB\d{9}|GB\d{12})$"); // eve-0.1.1: r"\{\{(.*)\}\}" consistent!(eve_0, r"\{\{(.*)\}\}"); // egc-0.1.2: "^mio" consistent!(egc_0, "^mio"); // pew-0.2.3: "" consistent!(pew_0, ""); // pew-0.2.3: "" consistent!(pew_1, ""); // mob-0.4.3: "y" consistent!(mob_0, "y"); // lit-0.2.8: "@([a-z]+)" consistent!(lit_0, "@([a-z]+)"); // lit-0.2.8: "([A-Z-]+):(.*)" consistent!(lit_1, "([A-Z-]+):(.*)"); // lit-0.2.8: "^[a-zA-Z_][a-zA-Z0-9_]*$" consistent!(lit_2, "^[a-zA-Z_][a-zA-Z0-9_]*$"); // avm-1.0.1: r"\d+\.\d+\.\d+" consistent!(avm_0, r"\d+\.\d+\.\d+"); // avm-1.0.1: r"\d+\.\d+\.\d+" consistent!(avm_1, r"\d+\.\d+\.\d+"); // orm-0.2.0: r"^Vec<(.+)>$" consistent!(orm_0, r"^Vec<(.+)>$"); // sgf-0.1.5: r"\\(\r\n|\n\r|\n|\r)" consistent!(sgf_0, r"\\(\r\n|\n\r|\n|\r)"); // sgf-0.1.5: r"\\(.)" consistent!(sgf_1, r"\\(.)"); // sgf-0.1.5: r"\r\n|\n\r|\n|\r" consistent!(sgf_2, r"\r\n|\n\r|\n|\r"); // sgf-0.1.5: r"([\]\\:])" consistent!(sgf_3, r"([\]\\:])"); // dok-0.2.0: "^Bearer realm=\"(.+?)\",service=\"(.+?)\",scope=\"(.+?)\"$" consistent!(dok_0, "^Bearer realm=\"(.+?)\",service=\"(.+?)\",scope=\"(.+?)\"$"); // d20-0.1.0: r"([+-]?\s*\d+[dD]\d+|[+-]?\s*\d+)" consistent!(d20_0, r"([+-]?\s*\d+[dD]\d+|[+-]?\s*\d+)"); // dvb-0.3.0: "E" consistent!(dvb_0, "E"); // dvb-0.3.0: "^F" consistent!(dvb_1, "^F"); // dvb-0.3.0: "^S" consistent!(dvb_2, "^S"); // ger-0.2.0: r"Change-Id: (I[a-f0-9]{40})$" consistent!(ger_0, r"Change-Id: (I[a-f0-9]{40})$"); // ger-0.2.0: r"(refs|ref|fix|fixes|close|closes)\s+([A-Z]{2,5}-[0-9]{1,5})$" consistent!(ger_1, r"(refs|ref|fix|fixes|close|closes)\s+([A-Z]{2,5}-[0-9]{1,5})$"); // n5-0.2.1: r"(\d+)(\.(\d+))?(\.(\d+))?(.*)" consistent!(n5_0, r"(\d+)(\.(\d+))?(\.(\d+))?(.*)"); // po-0.1.4: r"[A-Za-z0-9]" consistent!(po_0, r"[A-Za-z0-9]"); // carnix-0.8.5: "path is (‘|')?([^’'\n]*)(’|')?" consistent!(carnix_0, "path is (‘|')?([^’'\n]*)(’|')?"); // carnix-0.8.5: r"^(\S*) (\d*)\.(\d*)\.(\d*)(-(\S*))?(.*)?" consistent!(carnix_1, r"^(\S*) (\d*)\.(\d*)\.(\d*)(-(\S*))?(.*)?"); // carnix-0.8.5: r"(\d*)\.(\d*)\.(\d*)(-(\S*))?" consistent!(carnix_2, r"(\d*)\.(\d*)\.(\d*)(-(\S*))?"); // carnix-0.8.5: r"(\S*)-(\d*)\.(\d*)\.(\d*)(-(\S*))?" consistent!(carnix_3, r"(\S*)-(\d*)\.(\d*)\.(\d*)(-(\S*))?"); // caseless-0.2.1: r"^# CaseFolding-(\d+)\.(\d+)\.(\d+).txt$" consistent!(caseless_0, r"^# CaseFolding-(\d+)\.(\d+)\.(\d+).txt$"); // caseless-0.2.1: r"^([0-9A-F]+); [CF]; ([0-9A-F ]+);" consistent!(caseless_1, r"^([0-9A-F]+); [CF]; ([0-9A-F ]+);"); // cabot-0.2.0: "\r?\n\r?\n" consistent!(cabot_0, "\r?\n\r?\n"); // cabot-0.2.0: "\r?\n" consistent!(cabot_1, "\r?\n"); // card-validate-2.2.1: r"^600" consistent!(card_validate_0, r"^600"); // card-validate-2.2.1: r"^5019" consistent!(card_validate_1, r"^5019"); // card-validate-2.2.1: r"^4" consistent!(card_validate_2, r"^4"); // card-validate-2.2.1: r"^(5[1-5]|2[2-7])" consistent!(card_validate_3, r"^(5[1-5]|2[2-7])"); // card-validate-2.2.1: r"^3[47]" consistent!(card_validate_4, r"^3[47]"); // card-validate-2.2.1: r"^3[0689]" consistent!(card_validate_5, r"^3[0689]"); // card-validate-2.2.1: r"^6([045]|22)" consistent!(card_validate_6, r"^6([045]|22)"); // card-validate-2.2.1: r"^(62|88)" consistent!(card_validate_7, r"^(62|88)"); // card-validate-2.2.1: r"^35" consistent!(card_validate_8, r"^35"); // card-validate-2.2.1: r"^[0-9]+$" consistent!(card_validate_9, r"^[0-9]+$"); // cargo-testify-0.3.0: r"\d{1,} passed.*filtered out" consistent!(cargo_testify_0, r"\d{1,} passed.*filtered out"); // cargo-testify-0.3.0: r"error(:|\[).*" consistent!(cargo_testify_1, r"error(:|\[).*"); // cargo-wix-0.0.5: r"<(.*?)>" consistent!(cargo_wix_0, r"<(.*?)>"); // cargo-wix-0.0.5: r"<(.*?)>" consistent!(cargo_wix_1, r"<(.*?)>"); // cargo-wix-0.0.5: r"<(.*?)>" consistent!(cargo_wix_2, r"<(.*?)>"); // cargo-wix-0.0.5: r"<(.*?)>" consistent!(cargo_wix_3, r"<(.*?)>"); // cargo-incremental-0.1.23: r"(?m)^incremental: re-using (\d+) out of (\d+) modules$" consistent!(cargo_incremental_0, r"(?m)^incremental: re-using (\d+) out of (\d+) modules$"); // cargo-incremental-0.1.23: "(?m)(warning|error): (.*)\n --> ([^:]:\\d+:\\d+)$" consistent!(cargo_incremental_1, "(?m)(warning|error): (.*)\n --> ([^:]:\\d+:\\d+)$"); // cargo-incremental-0.1.23: r"(?m)^test (.*) \.\.\. (\w+)" consistent!(cargo_incremental_2, r"(?m)^test (.*) \.\.\. (\w+)"); // cargo-incremental-0.1.23: r"(?m)(\d+) passed; (\d+) failed; (\d+) ignored; \d+ measured" consistent!(cargo_incremental_3, r"(?m)(\d+) passed; (\d+) failed; (\d+) ignored; \d+ measured"); // cargo-testjs-0.1.2: r"^[^-]+-[0-9a-f]+\.js$" consistent!(cargo_testjs_0, r"^[^-]+-[0-9a-f]+\.js$"); // cargo-tarpaulin-0.6.2: r"\s*//" consistent!(cargo_tarpaulin_0, r"\s*//"); // cargo-tarpaulin-0.6.2: r"/\*" consistent!(cargo_tarpaulin_1, r"/\*"); // cargo-tarpaulin-0.6.2: r"\*/" consistent!(cargo_tarpaulin_2, r"\*/"); // cargo-culture-kit-0.1.0: r"^fo" consistent!(cargo_culture_kit_0, r"^fo"); // cargo-screeps-0.1.3: "\\s+" consistent!(cargo_screeps_0, "\\s+"); // cargo-brew-0.1.4: r"`(\S+) v([0-9.]+)" consistent!(cargo_brew_0, r"`(\S+) v([0-9.]+)"); // cargo-release-0.10.2: "^\\[.+\\]" consistent!(cargo_release_0, "^\\[.+\\]"); // cargo-release-0.10.2: "^\\[\\[.+\\]\\]" consistent!(cargo_release_1, "^\\[\\[.+\\]\\]"); // cargo-edit-0.3.0-beta.1: r"^https://github.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$" consistent!(cargo_edit_0, r"^https://github.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$"); // cargo-edit-0.3.0-beta.1: r"^https://gitlab.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$" consistent!(cargo_edit_1, r"^https://gitlab.com/([-_0-9a-zA-Z]+)/([-_0-9a-zA-Z]+)(/|.git)?$"); // cargo-disassemble-0.1.1: ".*" consistent!(cargo_disassemble_0, ".*"); // cargo-demangle-0.1.2: r"(?m)(?P<symbol>_ZN[0-9]+.*E)" consistent!(cargo_demangle_0, r"(?m)(?P<symbol>_ZN[0-9]+.*E)"); // cargo-coverage-annotations-0.1.5: r"^\s*\}(?:\)*;?|\s*else\s*\{)$" consistent!(cargo_coverage_annotations_0, r"^\s*\}(?:\)*;?|\s*else\s*\{)$"); // cargo-urlcrate-1.0.1: "[\u{001b}\u{009b}][\\[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]" consistent!(cargo_urlcrate_0, "[\u{001b}\u{009b}][\\[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-PRZcf-nqry=><]"); // cargo-script-0.2.8: r"^\s*\*( |$)" consistent!(cargo_script_0, r"^\s*\*( |$)"); // cargo-script-0.2.8: r"^(\s+)" consistent!(cargo_script_1, r"^(\s+)"); // cargo-script-0.2.8: r"/\*|\*/" consistent!(cargo_script_2, r"/\*|\*/"); // cargo-script-0.2.8: r"^\s*//!" consistent!(cargo_script_3, r"^\s*//!"); // cargo-script-0.2.8: r"^#![^\[].*?(\r\n|\n)" consistent!(cargo_script_4, r"^#![^\[].*?(\r\n|\n)"); // cargo-update-1.5.2: r"cargo-install-update\.exe-v.+" consistent!(cargo_update_0, r"cargo-install-update\.exe-v.+"); // canteen-0.4.1: r"^<(?:(int|uint|str|float|path):)?([\w_][a-zA-Z0-9_]*)>$" consistent!(canteen_0, r"^<(?:(int|uint|str|float|path):)?([\w_][a-zA-Z0-9_]*)>$"); // thruster-cli-0.1.3: r"(.)([A-Z])" consistent!(thruster_cli_0, r"(.)([A-Z])"); // thieves-cant-0.1.0: "([Z]+)$" consistent!(thieves_cant_0, "([Z]+)$"); // codeowners-0.1.3: r"^@\S+/\S+" consistent!(codeowners_0, r"^@\S+/\S+"); // codeowners-0.1.3: r"^@\S+" consistent!(codeowners_1, r"^@\S+"); // codeowners-0.1.3: r"^\S+@\S+" consistent!(codeowners_2, r"^\S+@\S+"); // conserve-0.4.2: r"^b0000 {21} complete 20[-0-9T:+]+\s +\d+s\n$" consistent!(conserve_0, r"^b0000 {21} complete 20[-0-9T:+]+\s +\d+s\n$"); // commodore-0.3.0: r"(?P<greeting>\S+?) (?P<name>\S+?)$" consistent!(commodore_0, r"(?P<greeting>\S+?) (?P<name>\S+?)$"); // corollary-0.3.0: r"([ \t]*)```haskell([\s\S]*?)```" consistent!(corollary_0, r"([ \t]*)```haskell([\s\S]*?)```"); // corollary-0.3.0: r"\b((?:a|b|t)\d*)\b" consistent!(corollary_1, r"\b((?:a|b|t)\d*)\b"); // colorizex-0.1.3: "NB" consistent!(colorizex_0, "NB"); // colorstring-0.0.1: r"(?i)\[[a-z0-9_-]+\]" consistent!(colorstring_0, r"(?i)\[[a-z0-9_-]+\]"); // colorstring-0.0.1: r"^(?i)(\[[a-z0-9_-]+\])+" consistent!(colorstring_1, r"^(?i)(\[[a-z0-9_-]+\])+"); // cosmogony-0.3.0: "name:(.+)" consistent!(cosmogony_0, "name:(.+)"); // cobalt-bin-0.12.1: r"(?m:^ {0,3}\[[^\]]+\]:.+$)" consistent!(cobalt_bin_0, r"(?m:^ {0,3}\[[^\]]+\]:.+$)"); // comrak-0.2.12: r"[^\p{L}\p{M}\p{N}\p{Pc} -]" consistent!(comrak_0, r"[^\p{L}\p{M}\p{N}\p{Pc} -]"); // content-blocker-0.2.3: "" consistent!(content_blocker_0, ""); // content-blocker-0.2.3: "(?i)hi" consistent!(content_blocker_1, "(?i)hi"); // content-blocker-0.2.3: "http[s]?://domain.org" consistent!(content_blocker_2, "http[s]?://domain.org"); // content-blocker-0.2.3: "(?i)http[s]?://domain.org" consistent!(content_blocker_3, "(?i)http[s]?://domain.org"); // content-blocker-0.2.3: "http://domain.org" consistent!(content_blocker_4, "http://domain.org"); // content-blocker-0.2.3: "http://domain.org" consistent!(content_blocker_5, "http://domain.org"); // content-blocker-0.2.3: "ad.html" consistent!(content_blocker_6, "ad.html"); // content-blocker-0.2.3: "ad.html" consistent!(content_blocker_7, "ad.html"); // content-blocker-0.2.3: "http://domain.org" consistent!(content_blocker_8, "http://domain.org"); // content-blocker-0.2.3: "http://domain.org/nocookies.sjs" consistent!(content_blocker_9, "http://domain.org/nocookies.sjs"); // content-blocker-0.2.3: "http://domain.org/nocookies.sjs" consistent!(content_blocker_10, "http://domain.org/nocookies.sjs"); // content-blocker-0.2.3: "http://domain.org/hideme.jpg" consistent!(content_blocker_11, "http://domain.org/hideme.jpg"); // content-blocker-0.2.3: "http://domain.org/ok.html" consistent!(content_blocker_12, "http://domain.org/ok.html"); // content-blocker-0.2.3: "http://domain.org/ok.html\\?except_this=1" consistent!(content_blocker_13, "http://domain.org/ok.html\\?except_this=1"); // victoria-dom-0.1.2: "[A-Za-z0-9=]" consistent!(victoria_dom_0, "[A-Za-z0-9=]"); // numbat-1.0.0: r"^nsq://" consistent!(numbat_0, r"^nsq://"); // airkorea-0.1.2: r"[\s\t\r\n]" consistent!(airkorea_0, r"[\s\t\r\n]"); // airkorea-0.1.2: r"([\{\[,])|([\}\]])" consistent!(airkorea_1, r"([\{\[,])|([\}\]])"); // airkorea-0.1.2: r"[^.\d]+$" consistent!(airkorea_2, r"[^.\d]+$"); // rofl-0.0.1: r"\b" // consistent!(rofl_0, r"\b"); // rogcat-0.2.15: r"--------- beginning of.*" consistent!(rogcat_0, r"--------- beginning of.*"); // rogcat-0.2.15: r"a|e|i|o|u" consistent!(rogcat_1, r"a|e|i|o|u"); // rogcat-0.2.15: r"^(\d+)([kMG])$" consistent!(rogcat_2, r"^(\d+)([kMG])$"); // media_filename-0.1.4: "\\.([A-Za-z0-9]{2,4})$" consistent!(media_filename_0, "\\.([A-Za-z0-9]{2,4})$"); // media_filename-0.1.4: "([0-9]{3,4}p|[0-9]{3,4}x[0-9]{3,4})" consistent!(media_filename_1, "([0-9]{3,4}p|[0-9]{3,4}x[0-9]{3,4})"); // media_filename-0.1.4: "(?:^\\[([^]]+)\\]|- ?([^-]+)$)" consistent!(media_filename_2, "(?:^\\[([^]]+)\\]|- ?([^-]+)$)"); // media_filename-0.1.4: "(?:[eE]([0-9]{2,3})|[^0-9A-Za-z]([0-9]{2,3})(?:v[0-9])?[^0-9A-Za-z])" consistent!(media_filename_3, "(?:[eE]([0-9]{2,3})|[^0-9A-Za-z]([0-9]{2,3})(?:v[0-9])?[^0-9A-Za-z])"); // media_filename-0.1.4: "[sS]([0-9]{1,2})" consistent!(media_filename_4, "[sS]([0-9]{1,2})"); // media_filename-0.1.4: "((?i)(?:PPV.)?[HP]DTV|(?:HD)?CAM|BRRIP|[^a-z]TS[^a-z]|(?:PPV )?WEB.?DL(?: DVDRip)?|HDRip|DVDRip|CamRip|W[EB]BRip|BluRay|BD|DVD|DvDScr|hdtv)" consistent!(media_filename_5, "((?i)(?:PPV.)?[HP]DTV|(?:HD)?CAM|BRRIP|[^a-z]TS[^a-z]|(?:PPV )?WEB.?DL(?: DVDRip)?|HDRip|DVDRip|CamRip|W[EB]BRip|BluRay|BD|DVD|DvDScr|hdtv)"); // media_filename-0.1.4: "((19[0-9]|20[01])[0-9])" consistent!(media_filename_6, "((19[0-9]|20[01])[0-9])"); // media_filename-0.1.4: "((?i)xvid|x264|h\\.?264)" consistent!(media_filename_7, "((?i)xvid|x264|h\\.?264)"); // media_filename-0.1.4: "((?i)MP3|DD5\\.?1|Dual[- ]Audio|LiNE|DTS|AAC(?:\\.?2\\.0)?|AC3(?:\\.5\\.1)?)" consistent!(media_filename_8, "((?i)MP3|DD5\\.?1|Dual[- ]Audio|LiNE|DTS|AAC(?:\\.?2\\.0)?|AC3(?:\\.5\\.1)?)"); // media_filename-0.1.4: "\\[([0-9A-F]{8})\\]" consistent!(media_filename_9, "\\[([0-9A-F]{8})\\]"); // termimage-0.3.2: r"(\d+)[xX](\d+)" consistent!(termimage_0, r"(\d+)[xX](\d+)"); // teensy-0.1.0: r".*(\d{4}-\d{2}-\d{2}).*" consistent!(teensy_0, r".*(\d{4}-\d{2}-\d{2}).*"); // telescreen-0.1.3: r"<@(.+)>" consistent!(telescreen_0, r"<@(.+)>"); // tempus_fugit-0.4.4: r"^(\d+)" consistent!(tempus_fugit_0, r"^(\d+)"); // fselect-0.4.1: "(\\?|\\.|\\*|\\[|\\]|\\(|\\)|\\^|\\$)" consistent!(fselect_0, "(\\?|\\.|\\*|\\[|\\]|\\(|\\)|\\^|\\$)"); // fselect-0.4.1: "(%|_|\\?|\\.|\\*|\\[|\\]|\\(|\\)|\\^|\\$)" consistent!(fselect_1, "(%|_|\\?|\\.|\\*|\\[|\\]|\\(|\\)|\\^|\\$)"); // fs_eventbridge-0.1.0: r"^([A-Z]+)(?:\s(.+))?\s*" consistent!(fs_eventbridge_0, r"^([A-Z]+)(?:\s(.+))?\s*"); // joseki-0.0.1: r"(\w{1,2})\[(.+?)\]" consistent!(joseki_0, r"(\w{1,2})\[(.+?)\]"); // tweetr-0.2.1: r"(?i)in (\d+) (second|minute|hour|day|week)s?" consistent!(tweetr_0, r"(?i)in (\d+) (second|minute|hour|day|week)s?"); // bullet_core-0.1.1: "^(?u:[0-9])+" consistent!(bullet_core_0, "^(?u:[0-9])+"); // bullet_core-0.1.1: "^(?u:[0-9])+(?u:\\.)(?u:[0-9])+" consistent!(bullet_core_1, "^(?u:[0-9])+(?u:\\.)(?u:[0-9])+"); // bullet_core-0.1.1: "^(?u:[A-Za-zª-ªµ-µº-ºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬ-ˬˮ-ˮͰ-ʹͶ-ͷͺ-ͽͿ-ͿΆ-ΆΈ-ΊΌ-ΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙ-ՙա-ևא-תװ-ײؠ-يٮ-ٯٱ-ۓە-ەۥ-ۦۮ-ۯۺ-ۼۿ-ۿܐ-ܐܒ-ܯݍ-ޥޱ-ޱߊ-ߪߴ-ߵߺ-ߺࠀ-ࠕࠚ-ࠚࠤ-ࠤࠨ-ࠨࡀ-ࡘࢠ-ࢴऄ-हऽ-ऽॐ-ॐक़-ॡॱ-ঀঅ-ঌএ-ঐও-নপ-রল-লশ-হঽ-ঽৎ-ৎড়-ঢ়য়-ৡৰ-ৱਅ-ਊਏ-ਐਓ-ਨਪ-ਰਲ-ਲ਼ਵ-ਸ਼ਸ-ਹਖ਼-ੜਫ਼-ਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલ-ળવ-હઽ-ઽૐ-ૐૠ-ૡૹ-ૹଅ-ଌଏ-ଐଓ-ନପ-ରଲ-ଳଵ-ହଽ-ଽଡ଼-ଢ଼ୟ-ୡୱ-ୱஃ-ஃஅ-ஊஎ-ஐஒ-கங-சஜ-ஜஞ-டண-தந-பம-ஹௐ-ௐఅ-ఌఎ-ఐఒ-నప-హఽ-ఽౘ-ౚౠ-ౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽ-ಽೞ-ೞೠ-ೡೱ-ೲഅ-ഌഎ-ഐഒ-ഺഽ-ഽൎ-ൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රල-ලව-ෆก-ะา-ำเ-ๆກ-ຂຄ-ຄງ-ຈຊ-ຊຍ-ຍດ-ທນ-ຟມ-ຣລ-ລວ-ວສ-ຫອ-ະາ-ຳຽ-ຽເ-ໄໆ-ໆໜ-ໟༀ-ༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿ-ဿၐ-ၕၚ-ၝၡ-ၡၥ-ၦၮ-ၰၵ-ႁႎ-ႎႠ-ჅჇ-ჇჍ-Ⴭა-ჺჼ-ቈቊ-ቍቐ-ቖቘ-ቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀ-ዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗ-ៗៜ-ៜᠠ-ᡷᢀ-ᢨᢪ-ᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧ-ᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮ-ᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵ-ᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙ-ὙὛ-ὛὝ-ὝὟ-ώᾀ-ᾴᾶ-ᾼι-ιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱ-ⁱⁿ-ⁿₐ-ₜℂ-ℂℇ-ℇℊ-ℓℕ-ℕℙ-ℝℤ-ℤΩ-Ωℨ-ℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎ-ⅎↃ-ↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲ-ⳳⴀ-ⴥⴧ-ⴧⴭ-ⴭⴰ-ⵧⵯ-ⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ-ⸯ々-〆〱-〵〻-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪ-ꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻ-ꣻꣽ-ꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏ-ꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺ-ꩺꩾ-ꪯꪱ-ꪱꪵ-ꪶꪹ-ꪽꫀ-ꫀꫂ-ꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִ-יִײַ-ﬨשׁ-זּטּ-לּמּ-מּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ𐀀-𐀋𐀍-𐀦𐀨-𐀺𐀼-𐀽𐀿-𐁍𐁐-𐁝𐂀-𐃺𐊀-𐊜𐊠-𐋐𐌀-𐌟𐌰-𐍀𐍂-𐍉𐍐-𐍵𐎀-𐎝𐎠-𐏃𐏈-𐏏𐐀-𐒝𐔀-𐔧𐔰-𐕣𐘀-𐜶𐝀-𐝕𐝠-𐝧𐠀-𐠅𐠈-𐠈𐠊-𐠵𐠷-𐠸𐠼-𐠼𐠿-𐡕𐡠-𐡶𐢀-𐢞𐣠-𐣲𐣴-𐣵𐤀-𐤕𐤠-𐤹𐦀-𐦷𐦾-𐦿𐨀-𐨀𐨐-𐨓𐨕-𐨗𐨙-𐨳𐩠-𐩼𐪀-𐪜𐫀-𐫇𐫉-𐫤𐬀-𐬵𐭀-𐭕𐭠-𐭲𐮀-𐮑𐰀-𐱈𐲀-𐲲𐳀-𐳲𑀃-𑀷𑂃-𑂯𑃐-𑃨𑄃-𑄦𑅐-𑅲𑅶-𑅶𑆃-𑆲𑇁-𑇄𑇚-𑇚𑇜-𑇜𑈀-𑈑𑈓-𑈫𑊀-𑊆𑊈-𑊈𑊊-𑊍𑊏-𑊝𑊟-𑊨𑊰-𑋞𑌅-𑌌𑌏-𑌐𑌓-𑌨𑌪-𑌰𑌲-𑌳𑌵-𑌹𑌽-𑌽𑍐-𑍐𑍝-𑍡𑒀-𑒯𑓄-𑓅𑓇-𑓇𑖀-𑖮𑗘-𑗛𑘀-𑘯𑙄-𑙄𑚀-𑚪𑜀-𑜙𑢠-𑣟𑣿-𑣿𑫀-𑫸𒀀-𒎙𒒀-𒕃𓀀-𓐮𔐀-𔙆𖠀-𖨸𖩀-𖩞𖫐-𖫭𖬀-𖬯𖭀-𖭃𖭣-𖭷𖭽-𖮏𖼀-𖽄𖽐-𖽐𖾓-𖾟𛀀-𛀁𛰀-𛱪𛱰-𛱼𛲀-𛲈𛲐-𛲙𝐀-𝑔𝑖-𝒜𝒞-𝒟𝒢-𝒢𝒥-𝒦𝒩-𝒬𝒮-𝒹𝒻-𝒻𝒽-𝓃𝓅-𝔅𝔇-𝔊𝔍-𝔔𝔖-𝔜𝔞-𝔹𝔻-𝔾𝕀-𝕄𝕆-𝕆𝕊-𝕐𝕒-𝚥𝚨-𝛀𝛂-𝛚𝛜-𝛺𝛼-𝜔𝜖-𝜴𝜶-𝝎𝝐-𝝮𝝰-𝞈𝞊-𝞨𝞪-𝟂𝟄-𝟋𞠀-𞣄𞸀-𞸃𞸅-𞸟𞸡-𞸢𞸤-𞸤𞸧-𞸧𞸩-𞸲𞸴-𞸷𞸹-𞸹𞸻-𞸻𞹂-𞹂𞹇-𞹇𞹉-𞹉𞹋-𞹋𞹍-𞹏𞹑-𞹒𞹔-𞹔𞹗-𞹗𞹙-𞹙𞹛-𞹛𞹝-𞹝𞹟-𞹟𞹡-𞹢𞹤-𞹤𞹧-𞹪𞹬-𞹲𞹴-𞹷𞹹-𞹼𞹾-𞹾𞺀-𞺉𞺋-𞺛𞺡-𞺣𞺥-𞺩𞺫-𞺻𠀀-𪛖𪜀-𫜴𫝀-𫠝𫠠-𬺡丽-𪘀])+" consistent!(bullet_core_2, "^(?u:[A-Za-zª-ªµ-µº-ºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬ-ˬˮ-ˮͰ-ʹͶ-ͷͺ-ͽͿ-ͿΆ-ΆΈ-ΊΌ-ΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙ-ՙա-ևא-תװ-ײؠ-يٮ-ٯٱ-ۓە-ەۥ-ۦۮ-ۯۺ-ۼۿ-ۿܐ-ܐܒ-ܯݍ-ޥޱ-ޱߊ-ߪߴ-ߵߺ-ߺࠀ-ࠕࠚ-ࠚࠤ-ࠤࠨ-ࠨࡀ-ࡘࢠ-ࢴऄ-हऽ-ऽॐ-ॐक़-ॡॱ-ঀঅ-ঌএ-ঐও-নপ-রল-লশ-হঽ-ঽৎ-ৎড়-ঢ়য়-ৡৰ-ৱਅ-ਊਏ-ਐਓ-ਨਪ-ਰਲ-ਲ਼ਵ-ਸ਼ਸ-ਹਖ਼-ੜਫ਼-ਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલ-ળવ-હઽ-ઽૐ-ૐૠ-ૡૹ-ૹଅ-ଌଏ-ଐଓ-ନପ-ରଲ-ଳଵ-ହଽ-ଽଡ଼-ଢ଼ୟ-ୡୱ-ୱஃ-ஃஅ-ஊஎ-ஐஒ-கங-சஜ-ஜஞ-டண-தந-பம-ஹௐ-ௐఅ-ఌఎ-ఐఒ-నప-హఽ-ఽౘ-ౚౠ-ౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽ-ಽೞ-ೞೠ-ೡೱ-ೲഅ-ഌഎ-ഐഒ-ഺഽ-ഽൎ-ൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රල-ලව-ෆก-ะา-ำเ-ๆກ-ຂຄ-ຄງ-ຈຊ-ຊຍ-ຍດ-ທນ-ຟມ-ຣລ-ລວ-ວສ-ຫອ-ະາ-ຳຽ-ຽເ-ໄໆ-ໆໜ-ໟༀ-ༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿ-ဿၐ-ၕၚ-ၝၡ-ၡၥ-ၦၮ-ၰၵ-ႁႎ-ႎႠ-ჅჇ-ჇჍ-Ⴭა-ჺჼ-ቈቊ-ቍቐ-ቖቘ-ቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀ-ዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗ-ៗៜ-ៜᠠ-ᡷᢀ-ᢨᢪ-ᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧ-ᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮ-ᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵ-ᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙ-ὙὛ-ὛὝ-ὝὟ-ώᾀ-ᾴᾶ-ᾼι-ιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱ-ⁱⁿ-ⁿₐ-ₜℂ-ℂℇ-ℇℊ-ℓℕ-ℕℙ-ℝℤ-ℤΩ-Ωℨ-ℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎ-ⅎↃ-ↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲ-ⳳⴀ-ⴥⴧ-ⴧⴭ-ⴭⴰ-ⵧⵯ-ⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ-ⸯ々-〆〱-〵〻-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪ-ꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻ-ꣻꣽ-ꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏ-ꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺ-ꩺꩾ-ꪯꪱ-ꪱꪵ-ꪶꪹ-ꪽꫀ-ꫀꫂ-ꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִ-יִײַ-ﬨשׁ-זּטּ-לּמּ-מּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ𐀀-𐀋𐀍-𐀦𐀨-𐀺𐀼-𐀽𐀿-𐁍𐁐-𐁝𐂀-𐃺𐊀-𐊜𐊠-𐋐𐌀-𐌟𐌰-𐍀𐍂-𐍉𐍐-𐍵𐎀-𐎝𐎠-𐏃𐏈-𐏏𐐀-𐒝𐔀-𐔧𐔰-𐕣𐘀-𐜶𐝀-𐝕𐝠-𐝧𐠀-𐠅𐠈-𐠈𐠊-𐠵𐠷-𐠸𐠼-𐠼𐠿-𐡕𐡠-𐡶𐢀-𐢞𐣠-𐣲𐣴-𐣵𐤀-𐤕𐤠-𐤹𐦀-𐦷𐦾-𐦿𐨀-𐨀𐨐-𐨓𐨕-𐨗𐨙-𐨳𐩠-𐩼𐪀-𐪜𐫀-𐫇𐫉-𐫤𐬀-𐬵𐭀-𐭕𐭠-𐭲𐮀-𐮑𐰀-𐱈𐲀-𐲲𐳀-𐳲𑀃-𑀷𑂃-𑂯𑃐-𑃨𑄃-𑄦𑅐-𑅲𑅶-𑅶𑆃-𑆲𑇁-𑇄𑇚-𑇚𑇜-𑇜𑈀-𑈑𑈓-𑈫𑊀-𑊆𑊈-𑊈𑊊-𑊍𑊏-𑊝𑊟-𑊨𑊰-𑋞𑌅-𑌌𑌏-𑌐𑌓-𑌨𑌪-𑌰𑌲-𑌳𑌵-𑌹𑌽-𑌽𑍐-𑍐𑍝-𑍡𑒀-𑒯𑓄-𑓅𑓇-𑓇𑖀-𑖮𑗘-𑗛𑘀-𑘯𑙄-𑙄𑚀-𑚪𑜀-𑜙𑢠-𑣟𑣿-𑣿𑫀-𑫸𒀀-𒎙𒒀-𒕃𓀀-𓐮𔐀-𔙆𖠀-𖨸𖩀-𖩞𖫐-𖫭𖬀-𖬯𖭀-𖭃𖭣-𖭷𖭽-𖮏𖼀-𖽄𖽐-𖽐𖾓-𖾟𛀀-𛀁𛰀-𛱪𛱰-𛱼𛲀-𛲈𛲐-𛲙𝐀-𝑔𝑖-𝒜𝒞-𝒟𝒢-𝒢𝒥-𝒦𝒩-𝒬𝒮-𝒹𝒻-𝒻𝒽-𝓃𝓅-𝔅𝔇-𝔊𝔍-𝔔𝔖-𝔜𝔞-𝔹𝔻-𝔾𝕀-𝕄𝕆-𝕆𝕊-𝕐𝕒-𝚥𝚨-𝛀𝛂-𝛚𝛜-𝛺𝛼-𝜔𝜖-𝜴𝜶-𝝎𝝐-𝝮𝝰-𝞈𝞊-𝞨𝞪-𝟂𝟄-𝟋𞠀-𞣄𞸀-𞸃𞸅-𞸟𞸡-𞸢𞸤-𞸤𞸧-𞸧𞸩-𞸲𞸴-𞸷𞸹-𞸹𞸻-𞸻𞹂-𞹂𞹇-𞹇𞹉-𞹉𞹋-𞹋𞹍-𞹏𞹑-𞹒𞹔-𞹔𞹗-𞹗𞹙-𞹙𞹛-𞹛𞹝-𞹝𞹟-𞹟𞹡-𞹢𞹤-𞹤𞹧-𞹪𞹬-𞹲𞹴-𞹷𞹹-𞹼𞹾-𞹾𞺀-𞺉𞺋-𞺛𞺡-𞺣𞺥-𞺩𞺫-𞺻𠀀-𪛖𪜀-𫜴𫝀-𫠝𫠠-𬺡丽-𪘀])+"); // bullet_core-0.1.1: "^(?u:d/d)((?u:[A-Za-zª-ªµ-µº-ºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬ-ˬˮ-ˮͰ-ʹͶ-ͷͺ-ͽͿ-ͿΆ-ΆΈ-ΊΌ-ΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙ-ՙա-ևא-תװ-ײؠ-يٮ-ٯٱ-ۓە-ەۥ-ۦۮ-ۯۺ-ۼۿ-ۿܐ-ܐܒ-ܯݍ-ޥޱ-ޱߊ-ߪߴ-ߵߺ-ߺࠀ-ࠕࠚ-ࠚࠤ-ࠤࠨ-ࠨࡀ-ࡘࢠ-ࢴऄ-हऽ-ऽॐ-ॐक़-ॡॱ-ঀঅ-ঌএ-ঐও-নপ-রল-লশ-হঽ-ঽৎ-ৎড়-ঢ়য়-ৡৰ-ৱਅ-ਊਏ-ਐਓ-ਨਪ-ਰਲ-ਲ਼ਵ-ਸ਼ਸ-ਹਖ਼-ੜਫ਼-ਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલ-ળવ-હઽ-ઽૐ-ૐૠ-ૡૹ-ૹଅ-ଌଏ-ଐଓ-ନପ-ରଲ-ଳଵ-ହଽ-ଽଡ଼-ଢ଼ୟ-ୡୱ-ୱஃ-ஃஅ-ஊஎ-ஐஒ-கங-சஜ-ஜஞ-டண-தந-பம-ஹௐ-ௐఅ-ఌఎ-ఐఒ-నప-హఽ-ఽౘ-ౚౠ-ౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽ-ಽೞ-ೞೠ-ೡೱ-ೲഅ-ഌഎ-ഐഒ-ഺഽ-ഽൎ-ൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රල-ලව-ෆก-ะา-ำเ-ๆກ-ຂຄ-ຄງ-ຈຊ-ຊຍ-ຍດ-ທນ-ຟມ-ຣລ-ລວ-ວສ-ຫອ-ະາ-ຳຽ-ຽເ-ໄໆ-ໆໜ-ໟༀ-ༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿ-ဿၐ-ၕၚ-ၝၡ-ၡၥ-ၦၮ-ၰၵ-ႁႎ-ႎႠ-ჅჇ-ჇჍ-Ⴭა-ჺჼ-ቈቊ-ቍቐ-ቖቘ-ቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀ-ዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗ-ៗៜ-ៜᠠ-ᡷᢀ-ᢨᢪ-ᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧ-ᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮ-ᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵ-ᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙ-ὙὛ-ὛὝ-ὝὟ-ώᾀ-ᾴᾶ-ᾼι-ιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱ-ⁱⁿ-ⁿₐ-ₜℂ-ℂℇ-ℇℊ-ℓℕ-ℕℙ-ℝℤ-ℤΩ-Ωℨ-ℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎ-ⅎↃ-ↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲ-ⳳⴀ-ⴥⴧ-ⴧⴭ-ⴭⴰ-ⵧⵯ-ⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ-ⸯ々-〆〱-〵〻-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪ-ꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻ-ꣻꣽ-ꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏ-ꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺ-ꩺꩾ-ꪯꪱ-ꪱꪵ-ꪶꪹ-ꪽꫀ-ꫀꫂ-ꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִ-יִײַ-ﬨשׁ-זּטּ-לּמּ-מּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ𐀀-𐀋𐀍-𐀦𐀨-𐀺𐀼-𐀽𐀿-𐁍𐁐-𐁝𐂀-𐃺𐊀-𐊜𐊠-𐋐𐌀-𐌟𐌰-𐍀𐍂-𐍉𐍐-𐍵𐎀-𐎝𐎠-𐏃𐏈-𐏏𐐀-𐒝𐔀-𐔧𐔰-𐕣𐘀-𐜶𐝀-𐝕𐝠-𐝧𐠀-𐠅𐠈-𐠈𐠊-𐠵𐠷-𐠸𐠼-𐠼𐠿-𐡕𐡠-𐡶𐢀-𐢞𐣠-𐣲𐣴-𐣵𐤀-𐤕𐤠-𐤹𐦀-𐦷𐦾-𐦿𐨀-𐨀𐨐-𐨓𐨕-𐨗𐨙-𐨳𐩠-𐩼𐪀-𐪜𐫀-𐫇𐫉-𐫤𐬀-𐬵𐭀-𐭕𐭠-𐭲𐮀-𐮑𐰀-𐱈𐲀-𐲲𐳀-𐳲𑀃-𑀷𑂃-𑂯𑃐-𑃨𑄃-𑄦𑅐-𑅲𑅶-𑅶𑆃-𑆲𑇁-𑇄𑇚-𑇚𑇜-𑇜𑈀-𑈑𑈓-𑈫𑊀-𑊆𑊈-𑊈𑊊-𑊍𑊏-𑊝𑊟-𑊨𑊰-𑋞𑌅-𑌌𑌏-𑌐𑌓-𑌨𑌪-𑌰𑌲-𑌳𑌵-𑌹𑌽-𑌽𑍐-𑍐𑍝-𑍡𑒀-𑒯𑓄-𑓅𑓇-𑓇𑖀-𑖮𑗘-𑗛𑘀-𑘯𑙄-𑙄𑚀-𑚪𑜀-𑜙𑢠-𑣟𑣿-𑣿𑫀-𑫸𒀀-𒎙𒒀-𒕃𓀀-𓐮𔐀-𔙆𖠀-𖨸𖩀-𖩞𖫐-𖫭𖬀-𖬯𖭀-𖭃𖭣-𖭷𖭽-𖮏𖼀-𖽄𖽐-𖽐𖾓-𖾟𛀀-𛀁𛰀-𛱪𛱰-𛱼𛲀-𛲈𛲐-𛲙𝐀-𝑔𝑖-𝒜𝒞-𝒟𝒢-𝒢𝒥-𝒦𝒩-𝒬𝒮-𝒹𝒻-𝒻𝒽-𝓃𝓅-𝔅𝔇-𝔊𝔍-𝔔𝔖-𝔜𝔞-𝔹𝔻-𝔾𝕀-𝕄𝕆-𝕆𝕊-𝕐𝕒-𝚥𝚨-𝛀𝛂-𝛚𝛜-𝛺𝛼-𝜔𝜖-𝜴𝜶-𝝎𝝐-𝝮𝝰-𝞈𝞊-𝞨𝞪-𝟂𝟄-𝟋𞠀-𞣄𞸀-𞸃𞸅-𞸟𞸡-𞸢𞸤-𞸤𞸧-𞸧𞸩-𞸲𞸴-𞸷𞸹-𞸹𞸻-𞸻𞹂-𞹂𞹇-𞹇𞹉-𞹉𞹋-𞹋𞹍-𞹏𞹑-𞹒𞹔-𞹔𞹗-𞹗𞹙-𞹙𞹛-𞹛𞹝-𞹝𞹟-𞹟𞹡-𞹢𞹤-𞹤𞹧-𞹪𞹬-𞹲𞹴-𞹷𞹹-𞹼𞹾-𞹾𞺀-𞺉𞺋-𞺛𞺡-𞺣𞺥-𞺩𞺫-𞺻𠀀-𪛖𪜀-𫜴𫝀-𫠝𫠠-𬺡丽-𪘀])+)" consistent!(bullet_core_3, "^(?u:d/d)((?u:[A-Za-zª-ªµ-µº-ºÀ-ÖØ-öø-ˁˆ-ˑˠ-ˤˬ-ˬˮ-ˮͰ-ʹͶ-ͷͺ-ͽͿ-ͿΆ-ΆΈ-ΊΌ-ΌΎ-ΡΣ-ϵϷ-ҁҊ-ԯԱ-Ֆՙ-ՙա-ևא-תװ-ײؠ-يٮ-ٯٱ-ۓە-ەۥ-ۦۮ-ۯۺ-ۼۿ-ۿܐ-ܐܒ-ܯݍ-ޥޱ-ޱߊ-ߪߴ-ߵߺ-ߺࠀ-ࠕࠚ-ࠚࠤ-ࠤࠨ-ࠨࡀ-ࡘࢠ-ࢴऄ-हऽ-ऽॐ-ॐक़-ॡॱ-ঀঅ-ঌএ-ঐও-নপ-রল-লশ-হঽ-ঽৎ-ৎড়-ঢ়য়-ৡৰ-ৱਅ-ਊਏ-ਐਓ-ਨਪ-ਰਲ-ਲ਼ਵ-ਸ਼ਸ-ਹਖ਼-ੜਫ਼-ਫ਼ੲ-ੴઅ-ઍએ-ઑઓ-નપ-રલ-ળવ-હઽ-ઽૐ-ૐૠ-ૡૹ-ૹଅ-ଌଏ-ଐଓ-ନପ-ରଲ-ଳଵ-ହଽ-ଽଡ଼-ଢ଼ୟ-ୡୱ-ୱஃ-ஃஅ-ஊஎ-ஐஒ-கங-சஜ-ஜஞ-டண-தந-பம-ஹௐ-ௐఅ-ఌఎ-ఐఒ-నప-హఽ-ఽౘ-ౚౠ-ౡಅ-ಌಎ-ಐಒ-ನಪ-ಳವ-ಹಽ-ಽೞ-ೞೠ-ೡೱ-ೲഅ-ഌഎ-ഐഒ-ഺഽ-ഽൎ-ൎൟ-ൡൺ-ൿඅ-ඖක-නඳ-රල-ලව-ෆก-ะา-ำเ-ๆກ-ຂຄ-ຄງ-ຈຊ-ຊຍ-ຍດ-ທນ-ຟມ-ຣລ-ລວ-ວສ-ຫອ-ະາ-ຳຽ-ຽເ-ໄໆ-ໆໜ-ໟༀ-ༀཀ-ཇཉ-ཬྈ-ྌက-ဪဿ-ဿၐ-ၕၚ-ၝၡ-ၡၥ-ၦၮ-ၰၵ-ႁႎ-ႎႠ-ჅჇ-ჇჍ-Ⴭა-ჺჼ-ቈቊ-ቍቐ-ቖቘ-ቘቚ-ቝበ-ኈኊ-ኍነ-ኰኲ-ኵኸ-ኾዀ-ዀዂ-ዅወ-ዖዘ-ጐጒ-ጕጘ-ፚᎀ-ᎏᎠ-Ᏽᏸ-ᏽᐁ-ᙬᙯ-ᙿᚁ-ᚚᚠ-ᛪᛱ-ᛸᜀ-ᜌᜎ-ᜑᜠ-ᜱᝀ-ᝑᝠ-ᝬᝮ-ᝰក-ឳៗ-ៗៜ-ៜᠠ-ᡷᢀ-ᢨᢪ-ᢪᢰ-ᣵᤀ-ᤞᥐ-ᥭᥰ-ᥴᦀ-ᦫᦰ-ᧉᨀ-ᨖᨠ-ᩔᪧ-ᪧᬅ-ᬳᭅ-ᭋᮃ-ᮠᮮ-ᮯᮺ-ᯥᰀ-ᰣᱍ-ᱏᱚ-ᱽᳩ-ᳬᳮ-ᳱᳵ-ᳶᴀ-ᶿḀ-ἕἘ-Ἕἠ-ὅὈ-Ὅὐ-ὗὙ-ὙὛ-ὛὝ-ὝὟ-ώᾀ-ᾴᾶ-ᾼι-ιῂ-ῄῆ-ῌῐ-ΐῖ-Ίῠ-Ῥῲ-ῴῶ-ῼⁱ-ⁱⁿ-ⁿₐ-ₜℂ-ℂℇ-ℇℊ-ℓℕ-ℕℙ-ℝℤ-ℤΩ-Ωℨ-ℨK-ℭℯ-ℹℼ-ℿⅅ-ⅉⅎ-ⅎↃ-ↄⰀ-Ⱞⰰ-ⱞⱠ-ⳤⳫ-ⳮⳲ-ⳳⴀ-ⴥⴧ-ⴧⴭ-ⴭⴰ-ⵧⵯ-ⵯⶀ-ⶖⶠ-ⶦⶨ-ⶮⶰ-ⶶⶸ-ⶾⷀ-ⷆⷈ-ⷎⷐ-ⷖⷘ-ⷞⸯ-ⸯ々-〆〱-〵〻-〼ぁ-ゖゝ-ゟァ-ヺー-ヿㄅ-ㄭㄱ-ㆎㆠ-ㆺㇰ-ㇿ㐀-䶵一-鿕ꀀ-ꒌꓐ-ꓽꔀ-ꘌꘐ-ꘟꘪ-ꘫꙀ-ꙮꙿ-ꚝꚠ-ꛥꜗ-ꜟꜢ-ꞈꞋ-ꞭꞰ-ꞷꟷ-ꠁꠃ-ꠅꠇ-ꠊꠌ-ꠢꡀ-ꡳꢂ-ꢳꣲ-ꣷꣻ-ꣻꣽ-ꣽꤊ-ꤥꤰ-ꥆꥠ-ꥼꦄ-ꦲꧏ-ꧏꧠ-ꧤꧦ-ꧯꧺ-ꧾꨀ-ꨨꩀ-ꩂꩄ-ꩋꩠ-ꩶꩺ-ꩺꩾ-ꪯꪱ-ꪱꪵ-ꪶꪹ-ꪽꫀ-ꫀꫂ-ꫂꫛ-ꫝꫠ-ꫪꫲ-ꫴꬁ-ꬆꬉ-ꬎꬑ-ꬖꬠ-ꬦꬨ-ꬮꬰ-ꭚꭜ-ꭥꭰ-ꯢ가-힣ힰ-ퟆퟋ-ퟻ豈-舘並-龎ff-stﬓ-ﬗיִ-יִײַ-ﬨשׁ-זּטּ-לּמּ-מּנּ-סּףּ-פּצּ-ﮱﯓ-ﴽﵐ-ﶏﶒ-ﷇﷰ-ﷻﹰ-ﹴﹶ-ﻼA-Za-zヲ-하-ᅦᅧ-ᅬᅭ-ᅲᅳ-ᅵ𐀀-𐀋𐀍-𐀦𐀨-𐀺𐀼-𐀽𐀿-𐁍𐁐-𐁝𐂀-𐃺𐊀-𐊜𐊠-𐋐𐌀-𐌟𐌰-𐍀𐍂-𐍉𐍐-𐍵𐎀-𐎝𐎠-𐏃𐏈-𐏏𐐀-𐒝𐔀-𐔧𐔰-𐕣𐘀-𐜶𐝀-𐝕𐝠-𐝧𐠀-𐠅𐠈-𐠈𐠊-𐠵𐠷-𐠸𐠼-𐠼𐠿-𐡕𐡠-𐡶𐢀-𐢞𐣠-𐣲𐣴-𐣵𐤀-𐤕𐤠-𐤹𐦀-𐦷𐦾-𐦿𐨀-𐨀𐨐-𐨓𐨕-𐨗𐨙-𐨳𐩠-𐩼𐪀-𐪜𐫀-𐫇𐫉-𐫤𐬀-𐬵𐭀-𐭕𐭠-𐭲𐮀-𐮑𐰀-𐱈𐲀-𐲲𐳀-𐳲𑀃-𑀷𑂃-𑂯𑃐-𑃨𑄃-𑄦𑅐-𑅲𑅶-𑅶𑆃-𑆲𑇁-𑇄𑇚-𑇚𑇜-𑇜𑈀-𑈑𑈓-𑈫𑊀-𑊆𑊈-𑊈𑊊-𑊍𑊏-𑊝𑊟-𑊨𑊰-𑋞𑌅-𑌌𑌏-𑌐𑌓-𑌨𑌪-𑌰𑌲-𑌳𑌵-𑌹𑌽-𑌽𑍐-𑍐𑍝-𑍡𑒀-𑒯𑓄-𑓅𑓇-𑓇𑖀-𑖮𑗘-𑗛𑘀-𑘯𑙄-𑙄𑚀-𑚪𑜀-𑜙𑢠-𑣟𑣿-𑣿𑫀-𑫸𒀀-𒎙𒒀-𒕃𓀀-𓐮𔐀-𔙆𖠀-𖨸𖩀-𖩞𖫐-𖫭𖬀-𖬯𖭀-𖭃𖭣-𖭷𖭽-𖮏𖼀-𖽄𖽐-𖽐𖾓-𖾟𛀀-𛀁𛰀-𛱪𛱰-𛱼𛲀-𛲈𛲐-𛲙𝐀-𝑔𝑖-𝒜𝒞-𝒟𝒢-𝒢𝒥-𝒦𝒩-𝒬𝒮-𝒹𝒻-𝒻𝒽-𝓃𝓅-𝔅𝔇-𝔊𝔍-𝔔𝔖-𝔜𝔞-𝔹𝔻-𝔾𝕀-𝕄𝕆-𝕆𝕊-𝕐𝕒-𝚥𝚨-𝛀𝛂-𝛚𝛜-𝛺𝛼-𝜔𝜖-𝜴𝜶-𝝎𝝐-𝝮𝝰-𝞈𝞊-𝞨𝞪-𝟂𝟄-𝟋𞠀-𞣄𞸀-𞸃𞸅-𞸟𞸡-𞸢𞸤-𞸤𞸧-𞸧𞸩-𞸲𞸴-𞸷𞸹-𞸹𞸻-𞸻𞹂-𞹂𞹇-𞹇𞹉-𞹉𞹋-𞹋𞹍-𞹏𞹑-𞹒𞹔-𞹔𞹗-𞹗𞹙-𞹙𞹛-𞹛𞹝-𞹝𞹟-𞹟𞹡-𞹢𞹤-𞹤𞹧-𞹪𞹬-𞹲𞹴-𞹷𞹹-𞹼𞹾-𞹾𞺀-𞺉𞺋-𞺛𞺡-𞺣𞺥-𞺩𞺫-𞺻𠀀-𪛖𪜀-𫜴𫝀-𫠝𫠠-𬺡丽-𪘀])+)"); // bullet_core-0.1.1: "^(?u:\\()" consistent!(bullet_core_4, "^(?u:\\()"); // bullet_core-0.1.1: "^(?u:\\))" consistent!(bullet_core_5, "^(?u:\\))"); // bullet_core-0.1.1: "^(?u:\\*)" consistent!(bullet_core_6, "^(?u:\\*)"); // bullet_core-0.1.1: "^(?u:\\+)" consistent!(bullet_core_7, "^(?u:\\+)"); // bullet_core-0.1.1: "^(?u:,)" consistent!(bullet_core_8, "^(?u:,)"); // bullet_core-0.1.1: "^(?u:\\-)" consistent!(bullet_core_9, "^(?u:\\-)"); // bullet_core-0.1.1: "^(?u:/)" consistent!(bullet_core_10, "^(?u:/)"); // bullet_core-0.1.1: "^(?u:\\[)" consistent!(bullet_core_11, "^(?u:\\[)"); // bullet_core-0.1.1: "^(?u:\\])" consistent!(bullet_core_12, "^(?u:\\])"); // bullet_core-0.1.1: "^(?u:\\^)" consistent!(bullet_core_13, "^(?u:\\^)"); // bullet_core-0.1.1: "^(?u:·)" consistent!(bullet_core_14, "^(?u:·)"); // actix-web-0.6.13: "//+" consistent!(actix_web_0, "//+"); // actix-web-0.6.13: "//+" consistent!(actix_web_1, "//+"); // althea_kernel_interface-0.1.0: r"(\S*) .* (\S*) (REACHABLE|STALE|DELAY)" consistent!(althea_kernel_interface_0, r"(\S*) .* (\S*) (REACHABLE|STALE|DELAY)"); // althea_kernel_interface-0.1.0: r"-s (.*) --ip6-dst (.*)/.* bcnt = (.*)" consistent!(althea_kernel_interface_1, r"-s (.*) --ip6-dst (.*)/.* bcnt = (.*)"); // alcibiades-0.3.0: r"\buci(?:\s|$)" consistent!(alcibiades_0, r"\buci(?:\s|$)"); // ruma-identifiers-0.11.0: r"\A[a-z0-9._=-]+\z" consistent!(ruma_identifiers_0, r"\A[a-z0-9._=-]+\z"); // rusqbin-0.2.3: r"/rusqbins/((?i)[A-F0-9]{8}\-[A-F0-9]{4}\-4[A-F0-9]{3}\-[89AB][A-F0-9]{3}\-[A-F0-9]{12})$" consistent!(rusqbin_0, r"/rusqbins/((?i)[A-F0-9]{8}\-[A-F0-9]{4}\-4[A-F0-9]{3}\-[89AB][A-F0-9]{3}\-[A-F0-9]{12})$"); // rusqbin-0.2.3: r"/rusqbins/((?i)[A-F0-9]{8}\-[A-F0-9]{4}\-4[A-F0-9]{3}\-[89AB][A-F0-9]{3}\-[A-F0-9]{12})/requests/?$" consistent!(rusqbin_1, r"/rusqbins/((?i)[A-F0-9]{8}\-[A-F0-9]{4}\-4[A-F0-9]{3}\-[89AB][A-F0-9]{3}\-[A-F0-9]{12})/requests/?$"); // rust-install-0.0.4: r"^(nightly|beta|stable)(?:-(\d{4}-\d{2}-\d{2}))?$" consistent!(rust_install_0, r"^(nightly|beta|stable)(?:-(\d{4}-\d{2}-\d{2}))?$"); // rust_inbox-0.0.5: "^+(.*)\r\n" consistent!(rust_inbox_0, "^+(.*)\r\n"); // rust_inbox-0.0.5: r"^\* CAPABILITY (.*)\r\n" consistent!(rust_inbox_1, r"^\* CAPABILITY (.*)\r\n"); // rust_inbox-0.0.5: r"^([a-zA-Z0-9]+) (OK|NO|BAD)(.*)" consistent!(rust_inbox_2, r"^([a-zA-Z0-9]+) (OK|NO|BAD)(.*)"); // rust_inbox-0.0.5: r"^\* (\d+) EXISTS\r\n" consistent!(rust_inbox_3, r"^\* (\d+) EXISTS\r\n"); // rust_inbox-0.0.5: r"^\* (\d+) RECENT\r\n" consistent!(rust_inbox_4, r"^\* (\d+) RECENT\r\n"); // rust_inbox-0.0.5: r"^\* FLAGS (.+)\r\n" consistent!(rust_inbox_5, r"^\* FLAGS (.+)\r\n"); // rust_inbox-0.0.5: r"^\* OK \[UNSEEN (\d+)\](.*)\r\n" consistent!(rust_inbox_6, r"^\* OK \[UNSEEN (\d+)\](.*)\r\n"); // rust_inbox-0.0.5: r"^\* OK \[UIDVALIDITY (\d+)\](.*)\r\n" consistent!(rust_inbox_7, r"^\* OK \[UIDVALIDITY (\d+)\](.*)\r\n"); // rust_inbox-0.0.5: r"^\* OK \[UIDNEXT (\d+)\](.*)\r\n" consistent!(rust_inbox_8, r"^\* OK \[UIDNEXT (\d+)\](.*)\r\n"); // rust_inbox-0.0.5: r"^\* OK \[PERMANENTFLAGS (.+)\](.*)\r\n" consistent!(rust_inbox_9, r"^\* OK \[PERMANENTFLAGS (.+)\](.*)\r\n"); // rustml-0.0.7: r"^[a-z]+ (\d+)$" consistent!(rustml_0, r"^[a-z]+ (\d+)$"); // rustml-0.0.7: r"^[a-z]+ (\d+)$" consistent!(rustml_1, r"^[a-z]+ (\d+)$"); // rustml-0.0.7: r"^[a-z]+ (\d+)$" consistent!(rustml_2, r"^[a-z]+ (\d+)$"); // rustfmt-0.10.0: r"([^\\](\\\\)*)\\[\n\r][[:space:]]*" consistent!(rustfmt_0, r"([^\\](\\\\)*)\\[\n\r][[:space:]]*"); // rustfmt-core-0.4.0: r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)" consistent!(rustfmt_core_0, r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)"); // rustfmt-core-0.4.0: r"^## `([^`]+)`" consistent!(rustfmt_core_1, r"^## `([^`]+)`"); // rustfmt-core-0.4.0: r"([^\\](\\\\)*)\\[\n\r][[:space:]]*" consistent!(rustfmt_core_2, r"([^\\](\\\\)*)\\[\n\r][[:space:]]*"); // rustfmt-core-0.4.0: r"\s;" consistent!(rustfmt_core_3, r"\s;"); // rust-enum-derive-0.4.0: r"^(0x)?([:digit:]+)$" consistent!(rust_enum_derive_0, r"^(0x)?([:digit:]+)$"); // rust-enum-derive-0.4.0: r"^([:digit:]+)[:space:]*<<[:space:]*([:digit:]+)$" consistent!(rust_enum_derive_1, r"^([:digit:]+)[:space:]*<<[:space:]*([:digit:]+)$"); // rust-enum-derive-0.4.0: r"^[:space:]*([[:alnum:]_]+)([:space:]*=[:space:]*([:graph:]+))?[:space:]*," consistent!(rust_enum_derive_2, r"^[:space:]*([[:alnum:]_]+)([:space:]*=[:space:]*([:graph:]+))?[:space:]*,"); // rust-enum-derive-0.4.0: r"^#define[:space:]+([:graph:]+)[:space:]+([:graph:]+)" consistent!(rust_enum_derive_3, r"^#define[:space:]+([:graph:]+)[:space:]+([:graph:]+)"); // rustsourcebundler-0.2.0: r"^\s*pub mod (.+);$" consistent!(rustsourcebundler_0, r"^\s*pub mod (.+);$"); // rustsourcebundler-0.2.0: r"^\s*pub mod (.+);$" consistent!(rustsourcebundler_1, r"^\s*pub mod (.+);$"); // rustfmt-nightly-0.8.2: r"([^\\](\\\\)*)\\[\n\r][[:space:]]*" consistent!(rustfmt_nightly_0, r"([^\\](\\\\)*)\\[\n\r][[:space:]]*"); // rustfmt-nightly-0.8.2: r"\s;" consistent!(rustfmt_nightly_1, r"\s;"); // rustache-0.1.0: r"(?s)(.*?)([ \t\r\n]*)(\{\{(\{?\S?\s*?[\w\.\s]*.*?\s*?\}?)\}\})([ \t\r\n]*)" consistent!(rustache_0, r"(?s)(.*?)([ \t\r\n]*)(\{\{(\{?\S?\s*?[\w\.\s]*.*?\s*?\}?)\}\})([ \t\r\n]*)"); // rustfilt-0.2.0: r"_ZN[\$\._[:alnum:]]*" consistent!(rustfilt_0, r"_ZN[\$\._[:alnum:]]*"); // rustache-lists-0.1.2: r"(?s)(.*?)([ \t\r\n]*)(\{\{(\{?\S?\s*?[\w\.\s]*.*?\s*?\}?)\}\})([ \t\r\n]*)" consistent!(rustache_lists_0, r"(?s)(.*?)([ \t\r\n]*)(\{\{(\{?\S?\s*?[\w\.\s]*.*?\s*?\}?)\}\})([ \t\r\n]*)"); // rural-0.7.3: "(.+)=(.+)" consistent!(rural_0, "(.+)=(.+)"); // rural-0.7.3: "(.*):(.+)" consistent!(rural_1, "(.*):(.+)"); // rural-0.7.3: "(.+):=(.+)" consistent!(rural_2, "(.+):=(.+)"); // rural-0.7.3: "(.*)==(.+)" consistent!(rural_3, "(.*)==(.+)"); // rusoto_credential-0.11.0: r"^\[([^\]]+)\]$" consistent!(rusoto_credential_0, r"^\[([^\]]+)\]$"); // rumblebars-0.3.0: "([:blank:]*)$" consistent!(rumblebars_0, "([:blank:]*)$"); // rumblebars-0.3.0: "(\r?\n)[:blank:]*(\\{\\{~?[#!/](?:\\}?[^}])*\\}\\})[:blank:]*(:?\r?\n)?\\z" consistent!(rumblebars_1, "(\r?\n)[:blank:]*(\\{\\{~?[#!/](?:\\}?[^}])*\\}\\})[:blank:]*(:?\r?\n)?\\z"); // rumblebars-0.3.0: "(\r?\n[:blank:]*)(\\{\\{~?>(?:\\}?[^}])*\\}\\})[:blank:]*(:?\r?\n)?\\z" consistent!(rumblebars_2, "(\r?\n[:blank:]*)(\\{\\{~?>(?:\\}?[^}])*\\}\\})[:blank:]*(:?\r?\n)?\\z"); // rumblebars-0.3.0: "((?:[:blank:]|\r?\n)*)(\r?\n)[:blank:]*$" consistent!(rumblebars_3, "((?:[:blank:]|\r?\n)*)(\r?\n)[:blank:]*$"); // rumblebars-0.3.0: "^([:blank:]*\r?\n)(.*)" consistent!(rumblebars_4, "^([:blank:]*\r?\n)(.*)"); // diesel_cli-1.3.1: r"(?P<stamp>[\d-]*)_hello" consistent!(diesel_cli_0, r"(?P<stamp>[\d-]*)_hello"); // dishub-0.1.1: r"(\d+)s" consistent!(dishub_0, r"(\d+)s"); // spreadsheet_textconv-0.1.0: r"\n" consistent!(spreadsheet_textconv_0, r"\n"); // spreadsheet_textconv-0.1.0: r"\r" consistent!(spreadsheet_textconv_1, r"\r"); // spreadsheet_textconv-0.1.0: r"\t" consistent!(spreadsheet_textconv_2, r"\t"); // split_aud-0.1.0: r"DELAY (-?\d+)ms" consistent!(split_aud_0, r"DELAY (-?\d+)ms"); // split_aud-0.1.0: r"Trim\((\d+), ?(\d+)\)" consistent!(split_aud_1, r"Trim\((\d+), ?(\d+)\)"); // spotrust-0.0.5: r"spotify:[a-z]+:[a-zA-Z0-9]+" consistent!(spotrust_0, r"spotify:[a-z]+:[a-zA-Z0-9]+"); // spaceslugs-0.1.0: r"[^\x00-\x7F]" consistent!(spaceslugs_0, r"[^\x00-\x7F]"); // spaceslugs-0.1.0: r"[']+" consistent!(spaceslugs_1, r"[']+"); // spaceslugs-0.1.0: r"\W+" consistent!(spaceslugs_2, r"\W+"); // spaceslugs-0.1.0: r"[ ]+" consistent!(spaceslugs_3, r"[ ]+"); // space_email_api-0.1.1: "PHPSESSID=([0-9a-f]+)" consistent!(space_email_api_0, "PHPSESSID=([0-9a-f]+)"); // lorikeet-0.7.0: "[^0-9.,]" consistent!(lorikeet_0, "[^0-9.,]"); // claude-0.3.0: r"^(?:\b|(-)?)(\p{Currency_Symbol})?((?:(?:\d{1,3}[\.,])+\d{3})|\d+)(?:[\.,](\d{2}))?\b$" consistent!(claude_0, r"^(?:\b|(-)?)(\p{Currency_Symbol})?((?:(?:\d{1,3}[\.,])+\d{3})|\d+)(?:[\.,](\d{2}))?\b$"); // clam-0.1.6: r"<%=\s*(.+?)\s*%>" consistent!(clam_0, r"<%=\s*(.+?)\s*%>"); // classifier-0.0.3: r"(\s)" consistent!(classifier_0, r"(\s)"); // click-0.3.2: r"(-----BEGIN .*-----\n)((?:(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)*\n)+)(-----END .*-----)" consistent!(click_0, r"(-----BEGIN .*-----\n)((?:(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)*\n)+)(-----END .*-----)"); // click-0.3.2: r"-----BEGIN PRIVATE KEY-----" consistent!(click_1, r"-----BEGIN PRIVATE KEY-----"); // ultrastar-txt-0.1.2: r"#([A-Z3a-z]*):(.*)" consistent!(ultrastar_txt_0, r"#([A-Z3a-z]*):(.*)"); // ultrastar-txt-0.1.2: "^-\\s?(-?[0-9]+)\\s*$" consistent!(ultrastar_txt_1, "^-\\s?(-?[0-9]+)\\s*$"); // ultrastar-txt-0.1.2: "^-\\s?(-?[0-9]+)\\s+(-?[0-9]+)" consistent!(ultrastar_txt_2, "^-\\s?(-?[0-9]+)\\s+(-?[0-9]+)"); // ultrastar-txt-0.1.2: "^(.)\\s*(-?[0-9]+)\\s+(-?[0-9]+)\\s+(-?[0-9]+)\\s?(.*)" consistent!(ultrastar_txt_3, "^(.)\\s*(-?[0-9]+)\\s+(-?[0-9]+)\\s+(-?[0-9]+)\\s?(.*)"); // ultrastar-txt-0.1.2: "^P\\s?(-?[0-9]+)" consistent!(ultrastar_txt_4, "^P\\s?(-?[0-9]+)"); // db-accelerate-2.0.0: r"^template\.add($|\..+$)" consistent!(db_accelerate_0, r"^template\.add($|\..+$)"); // db-accelerate-2.0.0: r"^template\.sub($|\..+$)" consistent!(db_accelerate_1, r"^template\.sub($|\..+$)"); // sterling-0.3.0: r"(\d+)([cegps])" consistent!(sterling_0, r"(\d+)([cegps])"); // stache-0.2.0: r"[^\w]" consistent!(stache_0, r"[^\w]"); // strukt-0.1.0: "\"([<>]?)([xcbB\\?hHiIlLqQfdspP]*)\"" consistent!(strukt_0, "\"([<>]?)([xcbB\\?hHiIlLqQfdspP]*)\""); // steamid-ng-0.3.1: r"^STEAM_([0-4]):([0-1]):([0-9]{1,10})$" consistent!(steamid_ng_0, r"^STEAM_([0-4]):([0-1]):([0-9]{1,10})$"); // steamid-ng-0.3.1: r"^\[([AGMPCgcLTIUai]):([0-4]):([0-9]{1,10})(:([0-9]+))?\]$" consistent!(steamid_ng_1, r"^\[([AGMPCgcLTIUai]):([0-4]):([0-9]{1,10})(:([0-9]+))?\]$"); // strscan-0.1.1: r"^\w+" consistent!(strscan_0, r"^\w+"); // strscan-0.1.1: r"^\s+" consistent!(strscan_1, r"^\s+"); // strscan-0.1.1: r"^\w+" consistent!(strscan_2, r"^\w+"); // strscan-0.1.1: r"^\s+" consistent!(strscan_3, r"^\s+"); // strscan-0.1.1: r"^(\w+)\s+" consistent!(strscan_4, r"^(\w+)\s+"); // tk-carbon-0.2.0: r"^([a-zA-Z0-9\.-]+)(?:\s+(\d+))$" consistent!(tk_carbon_0, r"^([a-zA-Z0-9\.-]+)(?:\s+(\d+))$"); // tk-carbon-0.2.0: r"^([a-zA-Z0-9\.-]+)(?:\s+(\d+))$" consistent!(tk_carbon_1, r"^([a-zA-Z0-9\.-]+)(?:\s+(\d+))$"); // evalrs-0.0.10: r"extern\s+crate\s+([a-z0-9_]+)\s*;(\s*//(.+))?" consistent!(evalrs_0, r"extern\s+crate\s+([a-z0-9_]+)\s*;(\s*//(.+))?"); // evalrs-0.0.10: r"(?m)^# " consistent!(evalrs_1, r"(?m)^# "); // evalrs-0.0.10: r"(?m)^\s*fn +main *\( *\)" consistent!(evalrs_2, r"(?m)^\s*fn +main *\( *\)"); // evalrs-0.0.10: r"(extern\s+crate\s+[a-z0-9_]+\s*;)" consistent!(evalrs_3, r"(extern\s+crate\s+[a-z0-9_]+\s*;)"); // gate_build-0.5.0: "(.*)_t([0-9]+)" consistent!(gate_build_0, "(.*)_t([0-9]+)"); // rake-0.1.1: r"[^\P{P}-]|\s+-\s+" consistent!(rake_0, r"[^\P{P}-]|\s+-\s+"); // rafy-0.2.1: r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*" consistent!(rafy_0, r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*"); // raven-0.2.1: r"^(?P<protocol>.*?)://(?P<public_key>.*?):(?P<secret_key>.*?)@(?P<host>.*?)/(?P<path>.*/)?(?P<project_id>.*)$" consistent!(raven_0, r"^(?P<protocol>.*?)://(?P<public_key>.*?):(?P<secret_key>.*?)@(?P<host>.*?)/(?P<path>.*/)?(?P<project_id>.*)$"); // rargs-0.2.0: r"\{[[:space:]]*[^{}]*[[:space:]]*\}" consistent!(rargs_0, r"\{[[:space:]]*[^{}]*[[:space:]]*\}"); // rargs-0.2.0: r"^\{[[:space:]]*(?P<name>[[:word:]]*)[[:space:]]*\}$" consistent!(rargs_1, r"^\{[[:space:]]*(?P<name>[[:word:]]*)[[:space:]]*\}$"); // rargs-0.2.0: r"^\{[[:space:]]*(?P<num>-?\d+)[[:space:]]*\}$" consistent!(rargs_2, r"^\{[[:space:]]*(?P<num>-?\d+)[[:space:]]*\}$"); // rargs-0.2.0: r"^\{(?P<left>-?\d*)?\.\.(?P<right>-?\d*)?(?::(?P<sep>.*))?\}$" consistent!(rargs_3, r"^\{(?P<left>-?\d*)?\.\.(?P<right>-?\d*)?(?::(?P<sep>.*))?\}$"); // rargs-0.2.0: r"(.*?)[[:space:]]+|(.*?)$" consistent!(rargs_4, r"(.*?)[[:space:]]+|(.*?)$"); // indradb-lib-0.15.0: r"[a-zA-Z0-9]{8}" consistent!(indradb_lib_0, r"[a-zA-Z0-9]{8}"); // fungi-lang-0.1.50: r"::" consistent!(fungi_lang_0, r"::"); // nickel-0.10.1: "/hello/(?P<name>[a-zA-Z]+)" consistent!(nickel_0, "/hello/(?P<name>[a-zA-Z]+)"); // nickel-0.10.1: "/hello/(?P<name>[a-zA-Z]+)" consistent!(nickel_1, "/hello/(?P<name>[a-zA-Z]+)"); // pact_verifier-0.4.0: r"\{(\w+)\}" consistent!(pact_verifier_0, r"\{(\w+)\}"); // pact_matching-0.4.1: "application/.*json" consistent!(pact_matching_0, "application/.*json"); // pact_matching-0.4.1: "application/json.*" consistent!(pact_matching_1, "application/json.*"); // pact_matching-0.4.1: "application/.*xml" consistent!(pact_matching_2, "application/.*xml"); // pangu-0.2.0: "([\"'\\(\\[\\{{<\u{201c}])(\\s*)(.+?)(\\s*)([\"'\\)\\]\\}}>\u{201d}])" consistent!(pangu_0, "([\"'\\(\\[\\{{<\u{201c}])(\\s*)(.+?)(\\s*)([\"'\\)\\]\\}}>\u{201d}])"); // pangu-0.2.0: "([\\(\\[\\{{<\u{201c}]+)(\\s*)(.+?)(\\s*)([\\)\\]\\}}>\u{201d}]+)" consistent!(pangu_1, "([\\(\\[\\{{<\u{201c}]+)(\\s*)(.+?)(\\s*)([\\)\\]\\}}>\u{201d}]+)"); // parser-haskell-0.2.0: r"\{-[\s\S]*?-\}" consistent!(parser_haskell_0, r"\{-[\s\S]*?-\}"); // parser-haskell-0.2.0: r"(?m);+\s*$" consistent!(parser_haskell_1, r"(?m);+\s*$"); // parser-haskell-0.2.0: r"(?m)^#(if|ifn?def|endif|else|include|elif).*" consistent!(parser_haskell_2, r"(?m)^#(if|ifn?def|endif|else|include|elif).*"); // parser-haskell-0.2.0: r"'([^'\\]|\\[A-Z]{1,3}|\\.)'" consistent!(parser_haskell_3, r"'([^'\\]|\\[A-Z]{1,3}|\\.)'"); // parser-haskell-0.2.0: r"forall\s+(.*?)\." consistent!(parser_haskell_4, r"forall\s+(.*?)\."); // html2md-0.2.1: "\\s{2,}" consistent!(html2md_0, "\\s{2,}"); // html2md-0.2.1: "\\n{2,}" consistent!(html2md_1, "\\n{2,}"); // html2md-0.2.1: "(?m)(\\S) $" consistent!(html2md_2, "(?m)(\\S) $"); // html2md-0.2.1: "(?m)^[-*] " consistent!(html2md_3, "(?m)^[-*] "); // ovpnfile-0.1.2: r"#.*$" consistent!(ovpnfile_0, r"#.*$"); // ovpnfile-0.1.2: r"^<(\S+)>" consistent!(ovpnfile_1, r"^<(\S+)>"); // ovpnfile-0.1.2: r"^</(\S+)>" consistent!(ovpnfile_2, r"^</(\S+)>"); // screenruster-saver-fractal-0.1.1: r"#([:xdigit:]{2})([:xdigit:]{2})([:xdigit:]{2})" consistent!(screenruster_saver_fractal_0, r"#([:xdigit:]{2})([:xdigit:]{2})([:xdigit:]{2})"); // scarlet-0.2.2: r"rgb\((?: *(\d{1,3}),)(?: *(\d{1,3}),)(?: *(\d{1,3}))\)" consistent!(scarlet_0, r"rgb\((?: *(\d{1,3}),)(?: *(\d{1,3}),)(?: *(\d{1,3}))\)"); // cpp_to_rust_generator-0.2.0: r"^([\w:]+)<(.+)>$" consistent!(cpp_to_rust_generator_0, r"^([\w:]+)<(.+)>$"); // cpp_to_rust_generator-0.2.0: r"^type-parameter-(\d+)-(\d+)$" consistent!(cpp_to_rust_generator_1, r"^type-parameter-(\d+)-(\d+)$"); // cpp_to_rust_generator-0.2.0: r"^([\w~]+)<[^<>]+>$" consistent!(cpp_to_rust_generator_2, r"^([\w~]+)<[^<>]+>$"); // cpp_to_rust_generator-0.2.0: r"(signals|Q_SIGNALS)\s*:" consistent!(cpp_to_rust_generator_3, r"(signals|Q_SIGNALS)\s*:"); // cpp_to_rust_generator-0.2.0: r"(slots|Q_SLOTS)\s*:" consistent!(cpp_to_rust_generator_4, r"(slots|Q_SLOTS)\s*:"); // cpp_to_rust_generator-0.2.0: r"(public|protected|private)\s*:" consistent!(cpp_to_rust_generator_5, r"(public|protected|private)\s*:"); // cpp_to_rust-0.5.3: r"^([\w:]+)<(.+)>$" consistent!(cpp_to_rust_0, r"^([\w:]+)<(.+)>$"); // cpp_to_rust-0.5.3: r"^type-parameter-(\d+)-(\d+)$" consistent!(cpp_to_rust_1, r"^type-parameter-(\d+)-(\d+)$"); // cpp_to_rust-0.5.3: r"^([\w~]+)<[^<>]+>$" consistent!(cpp_to_rust_2, r"^([\w~]+)<[^<>]+>$"); // cpp_to_rust-0.5.3: r"(signals|Q_SIGNALS)\s*:" consistent!(cpp_to_rust_3, r"(signals|Q_SIGNALS)\s*:"); // cpp_to_rust-0.5.3: r"(slots|Q_SLOTS)\s*:" consistent!(cpp_to_rust_4, r"(slots|Q_SLOTS)\s*:"); // cpp_to_rust-0.5.3: r"(public|protected|private)\s*:" consistent!(cpp_to_rust_5, r"(public|protected|private)\s*:"); // fritzbox_logs-0.2.0: "(\\d{2}\\.\\d{2}\\.\\d{2}) (\\d{2}:\\d{2}:\\d{2}) (.*)" consistent!(fritzbox_logs_0, "(\\d{2}\\.\\d{2}\\.\\d{2}) (\\d{2}:\\d{2}:\\d{2}) (.*)"); // fractal-matrix-api-3.29.0: r"mxc://(?P<server>[^/]+)/(?P<media>.+)" consistent!(fractal_matrix_api_0, r"mxc://(?P<server>[^/]+)/(?P<media>.+)"); // smtp2go-0.1.4: r"^api-[a-zA-Z0-9]{32}$" consistent!(smtp2go_0, r"^api-[a-zA-Z0-9]{32}$"); // pusher-0.3.1: r"^[-a-zA-Z0-9_=@,.;]+$" consistent!(pusher_0, r"^[-a-zA-Z0-9_=@,.;]+$"); // pusher-0.3.1: r"\A\d+\.\d+\z" consistent!(pusher_1, r"\A\d+\.\d+\z"); // bakervm-0.9.0: r"^\.(.+?) +?(.+)$" consistent!(bakervm_0, r"^\.(.+?) +?(.+)$"); // bakervm-0.9.0: r"^\.([^\s]+)$" consistent!(bakervm_1, r"^\.([^\s]+)$"); // bakervm-0.9.0: r"^include! +([^\s]+)$" consistent!(bakervm_2, r"^include! +([^\s]+)$"); // bakervm-0.9.0: r"^@(\d+)$" consistent!(bakervm_3, r"^@(\d+)$"); // bakervm-0.9.0: r"^true|false$" consistent!(bakervm_4, r"^true|false$"); // bakervm-0.9.0: r"^(-?\d+)?\.[0-9]+$" consistent!(bakervm_5, r"^(-?\d+)?\.[0-9]+$"); // bakervm-0.9.0: r"^(-?\d+)?$" consistent!(bakervm_6, r"^(-?\d+)?$"); // bakervm-0.9.0: r"^#([0-9abcdefABCDEF]{6})$" consistent!(bakervm_7, r"^#([0-9abcdefABCDEF]{6})$"); // bakervm-0.9.0: r"^'(.)'$" consistent!(bakervm_8, r"^'(.)'$"); // bakervm-0.9.0: r"^\$vi\((\d+)\)$" consistent!(bakervm_9, r"^\$vi\((\d+)\)$"); // bakervm-0.9.0: r"^\$key\((\d+)\)$" consistent!(bakervm_10, r"^\$key\((\d+)\)$"); // banana-0.0.2: "(?P<type>[A-Z^']+) (?P<route>[^']+) HTTP/(?P<http>[^']+)" consistent!(banana_0, "(?P<type>[A-Z^']+) (?P<route>[^']+) HTTP/(?P<http>[^']+)"); // serial-key-2.0.0: r"[A-F0-9]{8}" consistent!(serial_key_0, r"[A-F0-9]{8}"); // serde-hjson-0.8.1: "[\\\\\"\x00-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]" consistent!(serde_hjson_0, "[\\\\\"\x00-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]"); // serde-hjson-0.8.1: "[\x00-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]" consistent!(serde_hjson_1, "[\x00-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]"); // serde-hjson-0.8.1: "'''|[\x00-\x09\x0b\x0c\x0e-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]" consistent!(serde_hjson_2, "'''|[\x00-\x09\x0b\x0c\x0e-\x1f\x7f-\u{9f}\u{00ad}\u{0600}-\u{0604}\u{070f}\u{17b4}\u{17b5}\u{200c}-\u{200f}\u{2028}-\u{202f}\u{2060}-\u{206f}\u{feff}\u{fff0}-\u{ffff}]"); // serde-odbc-0.1.0: r"/todos/(?P<id>\d+)" consistent!(serde_odbc_0, r"/todos/(?P<id>\d+)"); // sentry-0.6.0: r"^(?:_<)?([a-zA-Z0-9_]+?)(?:\.\.|::)" consistent!(sentry_0, r"^(?:_<)?([a-zA-Z0-9_]+?)(?:\.\.|::)"); // sentiment-0.1.1: r"[^a-zA-Z0 -]+" consistent!(sentiment_0, r"[^a-zA-Z0 -]+"); // sentiment-0.1.1: r" {2,}" consistent!(sentiment_1, r" {2,}"); // verilog-0.0.1: r"(?m)//.*" consistent!(verilog_0, r"(?m)//.*"); // verex-0.2.2: "(?P<robot>C3PO)" consistent!(verex_0, "(?P<robot>C3PO)"); // handlebars-0.32.4: ">|<|\"|&" consistent!(handlebars_0, ">|<|\"|&"); // haikunator-0.1.2: r"^\w+-\w+-[0123456789]{4}$" consistent!(haikunator_0, r"^\w+-\w+-[0123456789]{4}$"); // haikunator-0.1.2: r"^\w+@\w+@[0123456789]{4}$" consistent!(haikunator_1, r"^\w+@\w+@[0123456789]{4}$"); // haikunator-0.1.2: r"^\w+-\w+-[0123456789abcdef]{4}$" consistent!(haikunator_2, r"^\w+-\w+-[0123456789abcdef]{4}$"); // haikunator-0.1.2: r"^\w+-\w+-[0123456789忠犬ハチ公]{10}$" consistent!(haikunator_3, r"^\w+-\w+-[0123456789忠犬ハチ公]{10}$"); // haikunator-0.1.2: r"^\w+-\w+$" consistent!(haikunator_4, r"^\w+-\w+$"); // haikunator-0.1.2: r"^\w+-\w+-[foo]{4}$" consistent!(haikunator_5, r"^\w+-\w+-[foo]{4}$"); // haikunator-0.1.2: r"^\w+-\w+-[0123456789忠犬ハチ公]{5}$" consistent!(haikunator_6, r"^\w+-\w+-[0123456789忠犬ハチ公]{5}$"); // bobbin-cli-0.8.3: r"(.*)" consistent!(bobbin_cli_0, r"(.*)"); // bobbin-cli-0.8.3: r"rustc (.*)" consistent!(bobbin_cli_1, r"rustc (.*)"); // bobbin-cli-0.8.3: r"cargo (.*)" consistent!(bobbin_cli_2, r"cargo (.*)"); // bobbin-cli-0.8.3: r"xargo (.*)\n" consistent!(bobbin_cli_3, r"xargo (.*)\n"); // bobbin-cli-0.8.3: r"Open On-Chip Debugger (.*)" consistent!(bobbin_cli_4, r"Open On-Chip Debugger (.*)"); // bobbin-cli-0.8.3: r"arm-none-eabi-gcc \(GNU Tools for ARM Embedded Processors[^\)]*\) (.*)" consistent!(bobbin_cli_5, r"arm-none-eabi-gcc \(GNU Tools for ARM Embedded Processors[^\)]*\) (.*)"); // bobbin-cli-0.8.3: r"(?m).*\nBasic Open Source SAM-BA Application \(BOSSA\) Version (.*)\n" consistent!(bobbin_cli_6, r"(?m).*\nBasic Open Source SAM-BA Application \(BOSSA\) Version (.*)\n"); // bobbin-cli-0.8.3: r"(?m)SEGGER J-Link Commander (.*)\n" consistent!(bobbin_cli_7, r"(?m)SEGGER J-Link Commander (.*)\n"); // bobbin-cli-0.8.3: r"(?m)Teensy Loader, Command Line, Version (.*)\n" consistent!(bobbin_cli_8, r"(?m)Teensy Loader, Command Line, Version (.*)\n"); // bobbin-cli-0.8.3: r"dfu-util (.*)\n" consistent!(bobbin_cli_9, r"dfu-util (.*)\n"); // borsholder-0.9.1: r"^/static/[\w.]+$" consistent!(borsholder_0, r"^/static/[\w.]+$"); // borsholder-0.9.1: r"^/timeline/([0-9]+)$" consistent!(borsholder_1, r"^/timeline/([0-9]+)$"); // fblog-1.0.1: "\u{001B}\\[[\\d;]*[^\\d;]" consistent!(fblog_0, "\u{001B}\\[[\\d;]*[^\\d;]"); // fblog-1.0.1: "\u{001B}\\[[\\d;]*[^\\d;]" consistent!(fblog_1, "\u{001B}\\[[\\d;]*[^\\d;]"); // toml-query-0.6.0: r"^\[\d+\]$" consistent!(toml_query_0, r"^\[\d+\]$"); // todo-txt-1.1.0: r" (?P<key>[^\s]+):(?P<value>[^\s^/]+)" consistent!(todo_txt_0, r" (?P<key>[^\s]+):(?P<value>[^\s^/]+)"); // findr-0.1.5: r"\band\b" consistent!(findr_0, r"\band\b"); // findr-0.1.5: r"\bor\b" consistent!(findr_1, r"\bor\b"); // findr-0.1.5: r"\bnot\b" consistent!(findr_2, r"\bnot\b"); // file-sniffer-3.0.1: r".*?\.(a|la|lo|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$" consistent!(file_sniffer_0, r".*?\.(a|la|lo|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|S|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$"); // file-sniffer-3.0.1: r".*?\.(stats|conf|h|cache.*|dat|pc|info)$" consistent!(file_sniffer_1, r".*?\.(stats|conf|h|cache.*|dat|pc|info)$"); // file-sniffer-3.0.1: r".*?\.(exe|a|la|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$" consistent!(file_sniffer_2, r".*?\.(exe|a|la|o|ll|keter|bc|dyn_o|out|d|rlib|crate|min\.js|hi|dyn_hi|jsexe|webapp|js\.externs|ibc|toc|aux|fdb_latexmk|fls|egg-info|whl|js_a|js_hi|jld|ji|js_o|so.*|dump-.*|vmb|crx|orig|elmo|elmi|pyc|mod|p_hi|p_o|prof|tix)$"); // file-sniffer-3.0.1: r".*?\.(stats|conf|h|cache.*)$" consistent!(file_sniffer_3, r".*?\.(stats|conf|h|cache.*)$"); // file-sniffer-3.0.1: r"(\.git|\.pijul|_darcs|\.hg)$" consistent!(file_sniffer_4, r"(\.git|\.pijul|_darcs|\.hg)$"); // file_logger-0.1.0: "test" consistent!(file_logger_0, "test"); // file_scanner-0.2.0: r"foo" consistent!(file_scanner_0, r"foo"); // file_scanner-0.2.0: r"a+b" consistent!(file_scanner_1, r"a+b"); // file_scanner-0.2.0: r"a[ab]*b" consistent!(file_scanner_2, r"a[ab]*b"); // file_scanner-0.2.0: r"\s+" consistent!(file_scanner_3, r"\s+"); // file_scanner-0.2.0: r"\s+" consistent!(file_scanner_4, r"\s+"); // cellsplit-0.2.1: r"^\s*([^\s]+) %cellsplit<\d+>$" consistent!(cellsplit_0, r"^\s*([^\s]+) %cellsplit<\d+>$"); // cellsplit-0.2.1: r"^\s*([^\s]+) %cellsplit<\d+>$" consistent!(cellsplit_1, r"^\s*([^\s]+) %cellsplit<\d+>$"); // aterm-0.20.0: r"^[+\-]?[0-9]+" consistent!(aterm_0, r"^[+\-]?[0-9]+"); // aterm-0.20.0: r"^[+\-]?[0-9]+\.[0-9]*([eE][+\-]?[0-9]+)?" consistent!(aterm_1, r"^[+\-]?[0-9]+\.[0-9]*([eE][+\-]?[0-9]+)?"); // atarashii_imap-0.3.0: r"^[*] OK" consistent!(atarashii_imap_0, r"^[*] OK"); // atarashii_imap-0.3.0: r"FLAGS\s\((.+)\)" consistent!(atarashii_imap_1, r"FLAGS\s\((.+)\)"); // atarashii_imap-0.3.0: r"\[PERMANENTFLAGS\s\((.+)\)\]" consistent!(atarashii_imap_2, r"\[PERMANENTFLAGS\s\((.+)\)\]"); // atarashii_imap-0.3.0: r"\[UIDVALIDITY\s(\d+)\]" consistent!(atarashii_imap_3, r"\[UIDVALIDITY\s(\d+)\]"); // atarashii_imap-0.3.0: r"(\d+)\sEXISTS" consistent!(atarashii_imap_4, r"(\d+)\sEXISTS"); // atarashii_imap-0.3.0: r"(\d+)\sRECENT" consistent!(atarashii_imap_5, r"(\d+)\sRECENT"); // atarashii_imap-0.3.0: r"\[UNSEEN\s(\d+)\]" consistent!(atarashii_imap_6, r"\[UNSEEN\s(\d+)\]"); // atarashii_imap-0.3.0: r"\[UIDNEXT\s(\d+)\]" consistent!(atarashii_imap_7, r"\[UIDNEXT\s(\d+)\]"); // editorconfig-1.0.0: r"\\(\{|\})" consistent!(editorconfig_0, r"\\(\{|\})"); // editorconfig-1.0.0: r"(^|[^\\])\\\|" consistent!(editorconfig_1, r"(^|[^\\])\\\|"); // editorconfig-1.0.0: r"\[([^\]]*)$" consistent!(editorconfig_2, r"\[([^\]]*)$"); // editorconfig-1.0.0: r"\[(.*/.*)\]" consistent!(editorconfig_3, r"\[(.*/.*)\]"); // editorconfig-1.0.0: r"\{(-?\d+\\\.\\\.-?\d+)\}" consistent!(editorconfig_4, r"\{(-?\d+\\\.\\\.-?\d+)\}"); // editorconfig-1.0.0: r"\{([^,]+)\}" consistent!(editorconfig_5, r"\{([^,]+)\}"); // editorconfig-1.0.0: r"\{(([^\}].*)?(,|\|)(.*[^\\])?)\}" consistent!(editorconfig_6, r"\{(([^\}].*)?(,|\|)(.*[^\\])?)\}"); // editorconfig-1.0.0: r"^/" consistent!(editorconfig_7, r"^/"); // editorconfig-1.0.0: r"(^|[^\\])(\{|\})" consistent!(editorconfig_8, r"(^|[^\\])(\{|\})"); // edmunge-1.0.0: "^#!.*\n" consistent!(edmunge_0, "^#!.*\n"); // unicode_names2_macros-0.2.0: r"\\N\{(.*?)(?:\}|$)" consistent!(unicode_names2_macros_0, r"\\N\{(.*?)(?:\}|$)"); // unidiff-0.2.1: r"^--- (?P<filename>[^\t\n]+)(?:\t(?P<timestamp>[^\n]+))?" consistent!(unidiff_0, r"^--- (?P<filename>[^\t\n]+)(?:\t(?P<timestamp>[^\n]+))?"); // unidiff-0.2.1: r"^\+\+\+ (?P<filename>[^\t\n]+)(?:\t(?P<timestamp>[^\n]+))?" consistent!(unidiff_1, r"^\+\+\+ (?P<filename>[^\t\n]+)(?:\t(?P<timestamp>[^\n]+))?"); // unidiff-0.2.1: r"^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@[ ]?(.*)" consistent!(unidiff_2, r"^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@[ ]?(.*)"); // unidiff-0.2.1: r"^(?P<line_type>[- \n\+\\]?)(?P<value>.*)" consistent!(unidiff_3, r"^(?P<line_type>[- \n\+\\]?)(?P<value>.*)"); // slippy-map-tiles-0.13.1: "/?(?P<zoom>[0-9]?[0-9])/(?P<x>[0-9]{1,10})/(?P<y>[0-9]{1,10})(\\.[a-zA-Z]{3,4})?$" consistent!(slippy_map_tiles_0, "/?(?P<zoom>[0-9]?[0-9])/(?P<x>[0-9]{1,10})/(?P<y>[0-9]{1,10})(\\.[a-zA-Z]{3,4})?$"); // slippy-map-tiles-0.13.1: r"^(?P<minlon>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<minlat>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<maxlon>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<maxlat>-?[0-9]{1,3}(\.[0-9]{1,10})?)$" consistent!(slippy_map_tiles_1, r"^(?P<minlon>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<minlat>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<maxlon>-?[0-9]{1,3}(\.[0-9]{1,10})?) (?P<maxlat>-?[0-9]{1,3}(\.[0-9]{1,10})?)$"); // slippy-map-tiles-0.13.1: r"^(?P<minlon>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<minlat>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<maxlon>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<maxlat>-?[0-9]{1,3}(\.[0-9]{1,10})?)$" consistent!(slippy_map_tiles_2, r"^(?P<minlon>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<minlat>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<maxlon>-?[0-9]{1,3}(\.[0-9]{1,10})?),(?P<maxlat>-?[0-9]{1,3}(\.[0-9]{1,10})?)$"); // sonos-0.1.2: r"^https?://(.+?):1400/xml" consistent!(sonos_0, r"^https?://(.+?):1400/xml"); // validator_derive-0.7.0: r"^[a-z]{2}$" consistent!(validator_derive_0, r"^[a-z]{2}$"); // validator_derive-0.7.0: r"[a-z]{2}" consistent!(validator_derive_1, r"[a-z]{2}"); // validator_derive-0.7.0: r"[a-z]{2}" consistent!(validator_derive_2, r"[a-z]{2}"); // nginx-config-0.8.0: r"one of \d+ options" consistent!(nginx_config_0, r"one of \d+ options"); // waltz-0.4.0: r"[\s,]" consistent!(waltz_0, r"[\s,]"); // warheadhateus-0.2.1: r"^aws_access_key_id = (.*)" consistent!(warheadhateus_0, r"^aws_access_key_id = (.*)"); // warheadhateus-0.2.1: r"^aws_secret_access_key = (.*)" consistent!(warheadhateus_1, r"^aws_secret_access_key = (.*)"); // warheadhateus-0.2.1: r"^aws_access_key_id = (.*)" consistent!(warheadhateus_2, r"^aws_access_key_id = (.*)"); // warheadhateus-0.2.1: r"^aws_secret_access_key = (.*)" consistent!(warheadhateus_3, r"^aws_secret_access_key = (.*)"); // jieba-rs-0.2.2: r"([\u{4E00}-\u{9FD5}a-zA-Z0-9+#&\._%]+)" consistent!(jieba_rs_0, r"([\u{4E00}-\u{9FD5}a-zA-Z0-9+#&\._%]+)"); // jieba-rs-0.2.2: r"(\r\n|\s)" consistent!(jieba_rs_1, r"(\r\n|\s)"); // jieba-rs-0.2.2: "([\u{4E00}-\u{9FD5}]+)" consistent!(jieba_rs_2, "([\u{4E00}-\u{9FD5}]+)"); // jieba-rs-0.2.2: r"[^a-zA-Z0-9+#\n]" consistent!(jieba_rs_3, r"[^a-zA-Z0-9+#\n]"); // jieba-rs-0.2.2: r"([\u{4E00}-\u{9FD5}]+)" consistent!(jieba_rs_4, r"([\u{4E00}-\u{9FD5}]+)"); // jieba-rs-0.2.2: r"([a-zA-Z0-9]+(?:.\d+)?%?)" consistent!(jieba_rs_5, r"([a-zA-Z0-9]+(?:.\d+)?%?)"); // lalrpop-0.15.2: r"Span\([0-9 ,]*\)" consistent!(lalrpop_0, r"Span\([0-9 ,]*\)"); // lalrpop-snap-0.15.2: r"Span\([0-9 ,]*\)" consistent!(lalrpop_snap_0, r"Span\([0-9 ,]*\)"); // nlp-tokenize-0.1.0: r"[\S]+" consistent!(nlp_tokenize_0, r"[\S]+"); // kbgpg-0.1.2: "[[:xdigit:]][70]" consistent!(kbgpg_0, "[[:xdigit:]][70]"); // cdbd-0.1.1: r"^((?P<address>.*):)?(?P<port>\d+)$" consistent!(cdbd_0, r"^((?P<address>.*):)?(?P<port>\d+)$"); // mbutiles-0.1.1: r"[\w\s=+-/]+\((\{(.|\n)*\})\);?" consistent!(mbutiles_0, r"[\w\s=+-/]+\((\{(.|\n)*\})\);?"); // extrahop-0.2.5: r"^-\d+(?:ms|s|m|h|d|w|y)?$" consistent!(extrahop_0, r"^-\d+(?:ms|s|m|h|d|w|y)?$"); // pippin-0.1.0: "^((?:.*)-)?ss(0|[1-9][0-9]*)\\.pip$" consistent!(pippin_0, "^((?:.*)-)?ss(0|[1-9][0-9]*)\\.pip$"); // pippin-0.1.0: "^((?:.*)-)?ss(0|[1-9][0-9]*)-cl(0|[1-9][0-9]*)\\.piplog$" consistent!(pippin_1, "^((?:.*)-)?ss(0|[1-9][0-9]*)-cl(0|[1-9][0-9]*)\\.piplog$"); // pippin-0.1.0: "^((?:.*)-)?ss(0|[1-9][0-9]*)\\.pip$" consistent!(pippin_2, "^((?:.*)-)?ss(0|[1-9][0-9]*)\\.pip$"); // pippin-0.1.0: "^((?:.*)-)?ss(0|[1-9][0-9]*)-cl(0|[1-9][0-9]*)\\.piplog$" consistent!(pippin_3, "^((?:.*)-)?ss(0|[1-9][0-9]*)-cl(0|[1-9][0-9]*)\\.piplog$"); // pippin-0.1.0: "^.*pn(0|[1-9][0-9]*)(-ss(0|[1-9][0-9]*)(\\.pip|-cl(0|[1-9][0-9]*)\\.piplog))?$" consistent!(pippin_4, "^.*pn(0|[1-9][0-9]*)(-ss(0|[1-9][0-9]*)(\\.pip|-cl(0|[1-9][0-9]*)\\.piplog))?$"); // pippin-0.1.0: "^(.*)-ss(?:0|[1-9][0-9]*)(?:\\.pip|-cl(?:0|[1-9][0-9]*)\\.piplog)$" consistent!(pippin_5, "^(.*)-ss(?:0|[1-9][0-9]*)(?:\\.pip|-cl(?:0|[1-9][0-9]*)\\.piplog)$"); // pinyin-0.3.0: r"(?i)[āáǎàēéěèōóǒòīíǐìūúǔùüǘǚǜńň]" consistent!(pinyin_0, r"(?i)[āáǎàēéěèōóǒòīíǐìūúǔùüǘǚǜńň]"); // pinyin-0.3.0: r"([aeoiuvnm])([0-4])$" consistent!(pinyin_1, r"([aeoiuvnm])([0-4])$"); // duration-parser-0.2.0: r"(?P<value>\d+)(?P<units>[a-z])" consistent!(duration_parser_0, r"(?P<value>\d+)(?P<units>[a-z])"); // dutree-0.2.7: r"^\d+\D?$" consistent!(dutree_0, r"^\d+\D?$"); // djangohashers-0.3.0: r"^[A-Za-z0-9]*$" consistent!(djangohashers_0, r"^[A-Za-z0-9]*$"); // rtag-0.3.5: r"^[A-Z][A-Z0-9]{2,}$" consistent!(rtag_0, r"^[A-Z][A-Z0-9]{2,}$"); // rtag-0.3.5: r"^http://www\.emusic\.com" consistent!(rtag_1, r"^http://www\.emusic\.com"); // rtag-0.3.5: r"^[A-Z][A-Z0-9]{2,}" consistent!(rtag_2, r"^[A-Z][A-Z0-9]{2,}"); // rtag-0.3.5: r"(^[\x{0}|\x{feff}|\x{fffe}]*|[\x{0}|\x{feff}|\x{fffe}]*$)" consistent!(rtag_3, r"(^[\x{0}|\x{feff}|\x{fffe}]*|[\x{0}|\x{feff}|\x{fffe}]*$)"); // rtow-0.1.0: r"(\d+)[xX](\d+)" consistent!(rtow_0, r"(\d+)[xX](\d+)"); // pleingres-sql-plugin-0.1.0: r"\$([a-zA-Z0-9_]+)" consistent!(pleingres_sql_plugin_0, r"\$([a-zA-Z0-9_]+)"); // dono-2.0.0: "[\\n]+" consistent!(dono_0, "[\\n]+"); // dono-2.0.0: "(?m)^\\n" consistent!(dono_1, "(?m)^\\n"); // dono-2.0.0: "(?m)^\\n" consistent!(dono_2, "(?m)^\\n"); // ssb-common-0.3.0: r"^[0-9A-Za-z\+/]{43}=\.ed25519$" consistent!(ssb_common_0, r"^[0-9A-Za-z\+/]{43}=\.ed25519$"); // ssb-common-0.3.0: r"^[0-9A-Za-z\+/]{86}==\.ed25519$" consistent!(ssb_common_1, r"^[0-9A-Za-z\+/]{86}==\.ed25519$"); // ssb-common-0.3.0: r"^[0-9A-Za-z\+/]{43}=\.sha256$" consistent!(ssb_common_2, r"^[0-9A-Za-z\+/]{43}=\.sha256$"); // mozversion-0.1.3: r"^(?P<major>\d+)\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?(?:(?P<pre0>[a-z]+)(?P<pre1>\d*))?$" consistent!(mozversion_0, r"^(?P<major>\d+)\.(?P<minor>\d+)(?:\.(?P<patch>\d+))?(?:(?P<pre0>[a-z]+)(?P<pre1>\d*))?$"); // monger-0.5.6: r"^(\d+)\.(\d+)$" consistent!(monger_0, r"^(\d+)\.(\d+)$"); // mongo_rub-0.0.2: r"^[rv]2\.6" consistent!(mongo_rub_0, r"^[rv]2\.6"); // flow-0.3.5: "body value" consistent!(flow_0, "body value"); // flow-0.3.5: "start marker" consistent!(flow_1, "start marker"); // flow-0.3.5: "end marker" consistent!(flow_2, "end marker"); // flow-0.3.5: "body value" consistent!(flow_3, "body value"); // vobsub-0.2.3: "^([A-Za-z/ ]+): (.*)" consistent!(vobsub_0, "^([A-Za-z/ ]+): (.*)"); // voidmap-1.1.2: r"#([^\s=]+)*" consistent!(voidmap_0, r"#([^\s=]+)*"); // voidmap-1.1.2: r"#(\S+)*" consistent!(voidmap_1, r"#(\S+)*"); // voidmap-1.1.2: r"#prio=(\d+)" consistent!(voidmap_2, r"#prio=(\d+)"); // voidmap-1.1.2: r"\[(\S+)\]" consistent!(voidmap_3, r"\[(\S+)\]"); // voidmap-1.1.2: r"#limit=(\d+)" consistent!(voidmap_4, r"#limit=(\d+)"); // voidmap-1.1.2: r"#tagged=(\S+)" consistent!(voidmap_5, r"#tagged=(\S+)"); // voidmap-1.1.2: r"#rev\b" consistent!(voidmap_6, r"#rev\b"); // voidmap-1.1.2: r"#done\b" consistent!(voidmap_7, r"#done\b"); // voidmap-1.1.2: r"#open\b" consistent!(voidmap_8, r"#open\b"); // voidmap-1.1.2: r"#since=(\S+)" consistent!(voidmap_9, r"#since=(\S+)"); // voidmap-1.1.2: r"#until=(\S+)" consistent!(voidmap_10, r"#until=(\S+)"); // voidmap-1.1.2: r"#plot=(\S+)" consistent!(voidmap_11, r"#plot=(\S+)"); // voidmap-1.1.2: r"#n=(\d+)" consistent!(voidmap_12, r"#n=(\d+)"); // voidmap-1.1.2: r"(\S+)" consistent!(voidmap_13, r"(\S+)"); // voidmap-1.1.2: r"(?P<y>\d+)y" consistent!(voidmap_14, r"(?P<y>\d+)y"); // voidmap-1.1.2: r"(?P<m>\d+)m" consistent!(voidmap_15, r"(?P<m>\d+)m"); // voidmap-1.1.2: r"(?P<w>\d+)w" consistent!(voidmap_16, r"(?P<w>\d+)w"); // voidmap-1.1.2: r"(?P<d>\d+)d" consistent!(voidmap_17, r"(?P<d>\d+)d"); // voidmap-1.1.2: r"(?P<h>\d+)h" consistent!(voidmap_18, r"(?P<h>\d+)h"); // voidmap-1.1.2: r"C-(.)" consistent!(voidmap_19, r"C-(.)"); // qt_generator-0.2.0: r"^\.\./qt[^/]+/" consistent!(qt_generator_0, r"^\.\./qt[^/]+/"); // qt_generator-0.2.0: "(href|src)=\"([^\"]*)\"" consistent!(qt_generator_1, "(href|src)=\"([^\"]*)\""); // kryptos-0.6.1: r"[01]{5}" consistent!(kryptos_0, r"[01]{5}"); // cifar_10_loader-0.2.0: "data_batch_[1-5].bin" consistent!(cifar_10_loader_0, "data_batch_[1-5].bin"); // cifar_10_loader-0.2.0: "test_batch.bin" consistent!(cifar_10_loader_1, "test_batch.bin"); // circadian-0.6.0: r"^\d+.\d+s$" consistent!(circadian_0, r"^\d+.\d+s$"); // circadian-0.6.0: r"^\d+:\d+$" consistent!(circadian_1, r"^\d+:\d+$"); // circadian-0.6.0: r"^\d+:\d+m$" consistent!(circadian_2, r"^\d+:\d+m$"); // cicada-0.8.1: r"!!" consistent!(cicada_0, r"!!"); // cicada-0.8.1: r"^([^`]*)`([^`]+)`(.*)$" consistent!(cicada_1, r"^([^`]*)`([^`]+)`(.*)$"); // cicada-0.8.1: r"\*+" consistent!(cicada_2, r"\*+"); // cicada-0.8.1: r"([^\$]*)\$\{?([A-Za-z0-9\?\$_]+)\}?(.*)" consistent!(cicada_3, r"([^\$]*)\$\{?([A-Za-z0-9\?\$_]+)\}?(.*)"); // cicada-0.8.1: r"^ *alias +([a-zA-Z0-9_\.-]+)=(.*)$" consistent!(cicada_4, r"^ *alias +([a-zA-Z0-9_\.-]+)=(.*)$"); // vterm-sys-0.1.0: r"hi" consistent!(vterm_sys_0, r"hi"); // skim-0.5.0: r".*?\t" consistent!(skim_0, r".*?\t"); // skim-0.5.0: r".*?[\t ]" consistent!(skim_1, r".*?[\t ]"); // skim-0.5.0: r"(\{-?[0-9.,q]*?})" consistent!(skim_2, r"(\{-?[0-9.,q]*?})"); // skim-0.5.0: r"[ \t\n]+" consistent!(skim_3, r"[ \t\n]+"); // skim-0.5.0: r"[ \t\n]+" consistent!(skim_4, r"[ \t\n]+"); // skim-0.5.0: r"([^ |]+( +\| +[^ |]*)+)|( +)" consistent!(skim_5, r"([^ |]+( +\| +[^ |]*)+)|( +)"); // skim-0.5.0: r" +\| +" consistent!(skim_6, r" +\| +"); // skim-0.5.0: r"^(?P<left>-?\d+)?(?P<sep>\.\.)?(?P<right>-?\d+)?$" consistent!(skim_7, r"^(?P<left>-?\d+)?(?P<sep>\.\.)?(?P<right>-?\d+)?$"); // skim-0.5.0: "," consistent!(skim_8, ","); // skim-0.5.0: ".*?," consistent!(skim_9, ".*?,"); // skim-0.5.0: ".*?," consistent!(skim_10, ".*?,"); // skim-0.5.0: "," consistent!(skim_11, ","); // skim-0.5.0: r"\x1B\[(?:([0-9]+;[0-9]+[Hf])|([0-9]+[ABCD])|(s|u|2J|K)|([0-9;]*m)|(=[0-9]+[hI]))" consistent!(skim_12, r"\x1B\[(?:([0-9]+;[0-9]+[Hf])|([0-9]+[ABCD])|(s|u|2J|K)|([0-9;]*m)|(=[0-9]+[hI]))"); // egg-mode-text-1.14.7: r"[-_./]\z" consistent!(egg_mode_text_0, r"[-_./]\z"); // java-properties-1.1.1: "^[ \t\r\n\x0c]*[#!]" consistent!(java_properties_0, "^[ \t\r\n\x0c]*[#!]"); // java-properties-1.1.1: r"^[ \t\x0c]*[#!][^\r\n]*$" consistent!(java_properties_1, r"^[ \t\x0c]*[#!][^\r\n]*$"); // java-properties-1.1.1: r"^([ \t\x0c]*[:=][ \t\x0c]*|[ \t\x0c]+)$" consistent!(java_properties_2, r"^([ \t\x0c]*[:=][ \t\x0c]*|[ \t\x0c]+)$"); // ipaddress-0.1.2: r":.+\." consistent!(ipaddress_0, r":.+\."); // ipaddress-0.1.2: r"\." consistent!(ipaddress_1, r"\."); // ipaddress-0.1.2: r":" consistent!(ipaddress_2, r":"); // iptables-0.2.2: r"v(\d+)\.(\d+)\.(\d+)" consistent!(iptables_0, r"v(\d+)\.(\d+)\.(\d+)"); // rsure-0.8.1: r"^([^-]+)-(.*)\.dat\.gz$" consistent!(rsure_0, r"^([^-]+)-(.*)\.dat\.gz$"); // rs-jsonpath-0.1.0: "^(.*?)(<=|<|==|>=|>)(.*?)$" consistent!(rs_jsonpath_0, "^(.*?)(<=|<|==|>=|>)(.*?)$"); // oatie-0.3.0: r"(\n|^)(\w+):([\n\w\W]+?)(\n(?:\w)|(\n\]))" consistent!(oatie_0, r"(\n|^)(\w+):([\n\w\W]+?)(\n(?:\w)|(\n\]))"); // weld-0.2.0: "#.*$" consistent!(weld_0, "#.*$"); // weld-0.2.0: r"^[A-Za-z$_][A-Za-z0-9$_]*$" consistent!(weld_1, r"^[A-Za-z$_][A-Za-z0-9$_]*$"); // weld-0.2.0: r"^[0-9]+[cC]$" consistent!(weld_2, r"^[0-9]+[cC]$"); // weld-0.2.0: r"^0b[0-1]+[cC]$" consistent!(weld_3, r"^0b[0-1]+[cC]$"); // weld-0.2.0: r"^0x[0-9a-fA-F]+[cC]$" consistent!(weld_4, r"^0x[0-9a-fA-F]+[cC]$"); // weld-0.2.0: r"^[0-9]+$" consistent!(weld_5, r"^[0-9]+$"); // weld-0.2.0: r"^0b[0-1]+$" consistent!(weld_6, r"^0b[0-1]+$"); // weld-0.2.0: r"^0x[0-9a-fA-F]+$" consistent!(weld_7, r"^0x[0-9a-fA-F]+$"); // weld-0.2.0: r"^[0-9]+[lL]$" consistent!(weld_8, r"^[0-9]+[lL]$"); // weld-0.2.0: r"^0b[0-1]+[lL]$" consistent!(weld_9, r"^0b[0-1]+[lL]$"); // weld-0.2.0: r"^0x[0-9a-fA-F]+[lL]$" consistent!(weld_10, r"^0x[0-9a-fA-F]+[lL]$"); // webgl_generator-0.1.0: "([(, ])enum\\b" consistent!(webgl_generator_0, "([(, ])enum\\b"); // webgl_generator-0.1.0: "\\bAcquireResourcesCallback\\b" consistent!(webgl_generator_1, "\\bAcquireResourcesCallback\\b"); // weave-0.2.0: r"^(\d+)(,(\d+))?([acd]).*$" consistent!(weave_0, r"^(\d+)(,(\d+))?([acd]).*$"); // wemo-0.0.12: r"<BinaryState>(\d)(\|-?\d+)*</BinaryState>" consistent!(wemo_0, r"<BinaryState>(\d)(\|-?\d+)*</BinaryState>"); // webscale-0.9.4: r"(http[s]?://[^\s]+)" consistent!(webscale_0, r"(http[s]?://[^\s]+)"); // svgrep-1.1.0: r"^\d+.*$" consistent!(svgrep_0, r"^\d+.*$"); // ignore-0.4.2: r"^[\pL\pN]+$" consistent!(ignore_0, r"^[\pL\pN]+$"); // ommui_string_patterns-0.1.2: r"^([A-Za-z][0-9A-Za-z_]*)?$" consistent!(ommui_string_patterns_0, r"^([A-Za-z][0-9A-Za-z_]*)?$"); // ommui_string_patterns-0.1.2: r"^(\S+(?:.*\S)?)?$" consistent!(ommui_string_patterns_1, r"^(\S+(?:.*\S)?)?$"); // opcua-types-0.3.0: "^(?P<min>[0-9]{1,10})(:(?P<max>[0-9]{1,10}))?$" consistent!(opcua_types_0, "^(?P<min>[0-9]{1,10})(:(?P<max>[0-9]{1,10}))?$"); // opcua-types-0.3.0: r"^(ns=(?P<ns>[0-9]+);)?(?P<t>[isgb])=(?P<v>.+)$" consistent!(opcua_types_1, r"^(ns=(?P<ns>[0-9]+);)?(?P<t>[isgb])=(?P<v>.+)$"); // open_read_later-1.1.1: r"^(.+?)\s*:\s*(.+)$" consistent!(open_read_later_0, r"^(.+?)\s*:\s*(.+)$"); // youtube-downloader-0.1.0: r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*" consistent!(youtube_downloader_0, r"^.*(?:(?:youtu\.be/|v/|vi/|u/w/|embed/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*"); // yobot-0.1.1: "." consistent!(yobot_0, "."); // yobot-0.1.1: r"." consistent!(yobot_1, r"."); // yobot-0.1.1: r".+" consistent!(yobot_2, r".+"); // yobot-0.1.1: r"." consistent!(yobot_3, r"."); // ubiquity-0.1.5: r"foo" consistent!(ubiquity_0, r"foo"); // ubiquity-0.1.5: r"/target/" consistent!(ubiquity_1, r"/target/"); // ubiquity-0.1.5: r".DS_Store" consistent!(ubiquity_2, r".DS_Store"); // qasm-1.0.0: r"//.*" consistent!(qasm_0, r"//.*"); // drill-0.3.5: r"\{\{ *([a-z\._]+) *\}\}" consistent!(drill_0, r"\{\{ *([a-z\._]+) *\}\}"); // queryst-2.0.0: r"^([^\]\[]+)" consistent!(queryst_0, r"^([^\]\[]+)"); // queryst-2.0.0: r"(\[[^\]\[]*\])" consistent!(queryst_1, r"(\[[^\]\[]*\])"); // qui-vive-0.1.0: r"^/(\w+)$" consistent!(qui_vive_0, r"^/(\w+)$"); // qui-vive-0.1.0: r"^/key$" consistent!(qui_vive_1, r"^/key$"); // qui-vive-0.1.0: r"^/key/(\w+)$" consistent!(qui_vive_2, r"^/key/(\w+)$"); // qui-vive-0.1.0: r"^/url$" consistent!(qui_vive_3, r"^/url$"); // qui-vive-0.1.0: r"^/url/(\w+)$" consistent!(qui_vive_4, r"^/url/(\w+)$"); // qui-vive-0.1.0: r"^/inv$" consistent!(qui_vive_5, r"^/inv$"); // qui-vive-0.1.0: r"^/inv/(\w+)$" consistent!(qui_vive_6, r"^/inv/(\w+)$"); // subdiff-0.1.0: r"\b" // consistent!(subdiff_0, r"\b"); // substudy-0.4.5: r"^(\d+)/(\d+)$" consistent!(substudy_0, r"^(\d+)/(\d+)$"); // substudy-0.4.5: r"\s+" consistent!(substudy_1, r"\s+"); // substudy-0.4.5: r"<[a-z/][^>]*>" consistent!(substudy_2, r"<[a-z/][^>]*>"); // substudy-0.4.5: r"(\([^)]*\)|♪[^♪]*♪|[A-Z]{2,} ?:)" consistent!(substudy_3, r"(\([^)]*\)|♪[^♪]*♪|[A-Z]{2,} ?:)"); // substudy-0.4.5: r"\s+" consistent!(substudy_4, r"\s+"); // isbnid-0.1.3: r"^(\d(-| )?){9}(x|X|\d|(\d(-| )?){3}\d)$" consistent!(isbnid_0, r"^(\d(-| )?){9}(x|X|\d|(\d(-| )?){3}\d)$"); // isbnid-0.1.3: r"[^0-9X]" consistent!(isbnid_1, r"[^0-9X]"); // ispc-0.3.5: r"Intel\(r\) SPMD Program Compiler \(ispc\), (\d+\.\d+\.\d+)" consistent!(ispc_0, r"Intel\(r\) SPMD Program Compiler \(ispc\), (\d+\.\d+\.\d+)"); �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/result.rs������������������������������������������������������������������������0000644�0000000�0000000�00000024274�10461020230�0014174�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017 Jason Lingle // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Strategies for combining delegate strategies into `std::Result`s. //! //! That is, the strategies here are for producing `Ok` _and_ `Err` cases. To //! simply adapt a strategy producing `T` into `Result<T, something>` which is //! always `Ok`, you can do something like `base_strategy.prop_map(Ok)` to //! simply wrap the generated values. //! //! Note that there are two nearly identical APIs for doing this, termed "maybe //! ok" and "maybe err". The difference between the two is in how they shrink; //! "maybe ok" treats `Ok` as the special case and shrinks to `Err`; //! conversely, "maybe err" treats `Err` as the special case and shrinks to //! `Ok`. Which to use largely depends on the code being tested; if the code //! typically handles errors by immediately bailing out and doing nothing else, //! "maybe ok" is likely more suitable, as shrinking will cause the code to //! take simpler paths. On the other hand, functions that need to make a //! complicated or fragile "back out" process on error are better tested with //! "maybe err" since the success case results in an easier to understand code //! path. #![cfg_attr(clippy, allow(expl_impl_clone_on_copy))] use core::fmt; use core::marker::PhantomData; use crate::std_facade::Arc; use crate::strategy::*; use crate::test_runner::*; // Re-export the type for easier usage. pub use crate::option::{prob, Probability}; struct WrapOk<T, E>(PhantomData<T>, PhantomData<E>); impl<T, E> Clone for WrapOk<T, E> { fn clone(&self) -> Self { *self } } impl<T, E> Copy for WrapOk<T, E> {} impl<T, E> fmt::Debug for WrapOk<T, E> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "WrapOk") } } impl<T: fmt::Debug, E: fmt::Debug> statics::MapFn<T> for WrapOk<T, E> { type Output = Result<T, E>; fn apply(&self, t: T) -> Result<T, E> { Ok(t) } } struct WrapErr<T, E>(PhantomData<T>, PhantomData<E>); impl<T, E> Clone for WrapErr<T, E> { fn clone(&self) -> Self { *self } } impl<T, E> Copy for WrapErr<T, E> {} impl<T, E> fmt::Debug for WrapErr<T, E> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "WrapErr") } } impl<T: fmt::Debug, E: fmt::Debug> statics::MapFn<E> for WrapErr<T, E> { type Output = Result<T, E>; fn apply(&self, e: E) -> Result<T, E> { Err(e) } } type MapErr<T, E> = statics::Map<E, WrapErr<<T as Strategy>::Value, <E as Strategy>::Value>>; type MapOk<T, E> = statics::Map<T, WrapOk<<T as Strategy>::Value, <E as Strategy>::Value>>; opaque_strategy_wrapper! { /// Strategy which generates `Result`s using `Ok` and `Err` values from two /// delegate strategies. /// /// Shrinks to `Err`. #[derive(Clone)] pub struct MaybeOk[<T, E>][where T : Strategy, E : Strategy] (TupleUnion<(WA<MapErr<T, E>>, WA<MapOk<T, E>>)>) -> MaybeOkValueTree<T, E>; /// `ValueTree` type corresponding to `MaybeOk`. pub struct MaybeOkValueTree[<T, E>][where T : Strategy, E : Strategy] (TupleUnionValueTree<( LazyValueTree<statics::Map<E, WrapErr<T::Value, E::Value>>>, Option<LazyValueTree<statics::Map<T, WrapOk<T::Value, E::Value>>>>, )>) -> Result<T::Value, E::Value>; } opaque_strategy_wrapper! { /// Strategy which generates `Result`s using `Ok` and `Err` values from two /// delegate strategies. /// /// Shrinks to `Ok`. #[derive(Clone)] pub struct MaybeErr[<T, E>][where T : Strategy, E : Strategy] (TupleUnion<(WA<MapOk<T, E>>, WA<MapErr<T, E>>)>) -> MaybeErrValueTree<T, E>; /// `ValueTree` type corresponding to `MaybeErr`. pub struct MaybeErrValueTree[<T, E>][where T : Strategy, E : Strategy] (TupleUnionValueTree<( LazyValueTree<statics::Map<T, WrapOk<T::Value, E::Value>>>, Option<LazyValueTree<statics::Map<E, WrapErr<T::Value, E::Value>>>>, )>) -> Result<T::Value, E::Value>; } // These need to exist for the same reason as the one on `OptionStrategy` impl<T: Strategy + fmt::Debug, E: Strategy + fmt::Debug> fmt::Debug for MaybeOk<T, E> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "MaybeOk({:?})", self.0) } } impl<T: Strategy + fmt::Debug, E: Strategy + fmt::Debug> fmt::Debug for MaybeErr<T, E> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "MaybeErr({:?})", self.0) } } impl<T: Strategy, E: Strategy> Clone for MaybeOkValueTree<T, E> where T::Tree: Clone, E::Tree: Clone, { fn clone(&self) -> Self { MaybeOkValueTree(self.0.clone()) } } impl<T: Strategy, E: Strategy> fmt::Debug for MaybeOkValueTree<T, E> where T::Tree: fmt::Debug, E::Tree: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "MaybeOkValueTree({:?})", self.0) } } impl<T: Strategy, E: Strategy> Clone for MaybeErrValueTree<T, E> where T::Tree: Clone, E::Tree: Clone, { fn clone(&self) -> Self { MaybeErrValueTree(self.0.clone()) } } impl<T: Strategy, E: Strategy> fmt::Debug for MaybeErrValueTree<T, E> where T::Tree: fmt::Debug, E::Tree: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "MaybeErrValueTree({:?})", self.0) } } /// Create a strategy for `Result`s where `Ok` values are taken from `t` and /// `Err` values are taken from `e`. /// /// `Ok` and `Err` are chosen with equal probability. /// /// Generated values shrink to `Err`. pub fn maybe_ok<T: Strategy, E: Strategy>(t: T, e: E) -> MaybeOk<T, E> { maybe_ok_weighted(0.5, t, e) } /// Create a strategy for `Result`s where `Ok` values are taken from `t` and /// `Err` values are taken from `e`. /// /// `probability_of_ok` is the probability (between 0.0 and 1.0, exclusive) /// that `Ok` is initially chosen. /// /// Generated values shrink to `Err`. pub fn maybe_ok_weighted<T: Strategy, E: Strategy>( probability_of_ok: impl Into<Probability>, t: T, e: E, ) -> MaybeOk<T, E> { let prob = probability_of_ok.into().into(); let (ok_weight, err_weight) = float_to_weight(prob); MaybeOk(TupleUnion::new(( ( err_weight, Arc::new(statics::Map::new(e, WrapErr(PhantomData, PhantomData))), ), ( ok_weight, Arc::new(statics::Map::new(t, WrapOk(PhantomData, PhantomData))), ), ))) } /// Create a strategy for `Result`s where `Ok` values are taken from `t` and /// `Err` values are taken from `e`. /// /// `Ok` and `Err` are chosen with equal probability. /// /// Generated values shrink to `Ok`. pub fn maybe_err<T: Strategy, E: Strategy>(t: T, e: E) -> MaybeErr<T, E> { maybe_err_weighted(0.5, t, e) } /// Create a strategy for `Result`s where `Ok` values are taken from `t` and /// `Err` values are taken from `e`. /// /// `probability_of_ok` is the probability (between 0.0 and 1.0, exclusive) /// that `Err` is initially chosen. /// /// Generated values shrink to `Ok`. pub fn maybe_err_weighted<T: Strategy, E: Strategy>( probability_of_err: impl Into<Probability>, t: T, e: E, ) -> MaybeErr<T, E> { let prob = probability_of_err.into().into(); let (err_weight, ok_weight) = float_to_weight(prob); MaybeErr(TupleUnion::new(( ( ok_weight, Arc::new(statics::Map::new(t, WrapOk(PhantomData, PhantomData))), ), ( err_weight, Arc::new(statics::Map::new(e, WrapErr(PhantomData, PhantomData))), ), ))) } #[cfg(test)] mod test { use super::*; fn count_ok_of_1000(s: impl Strategy<Value = Result<(), ()>>) -> u32 { let mut runner = TestRunner::deterministic(); let mut count = 0; for _ in 0..1000 { count += s.new_tree(&mut runner).unwrap().current().is_ok() as u32; } count } #[test] fn probability_defaults_to_0p5() { let count = count_ok_of_1000(maybe_err(Just(()), Just(()))); assert!(count > 400 && count < 600); let count = count_ok_of_1000(maybe_ok(Just(()), Just(()))); assert!(count > 400 && count < 600); } #[test] fn probability_handled_correctly() { let count = count_ok_of_1000(maybe_err_weighted(0.1, Just(()), Just(()))); assert!(count > 800 && count < 950); let count = count_ok_of_1000(maybe_err_weighted(0.9, Just(()), Just(()))); assert!(count > 50 && count < 150); let count = count_ok_of_1000(maybe_ok_weighted(0.9, Just(()), Just(()))); assert!(count > 800 && count < 950); let count = count_ok_of_1000(maybe_ok_weighted(0.1, Just(()), Just(()))); assert!(count > 50 && count < 150); } #[test] fn shrink_to_correct_case() { let mut runner = TestRunner::default(); { let input = maybe_err(Just(()), Just(())); for _ in 0..64 { let mut val = input.new_tree(&mut runner).unwrap(); if val.current().is_ok() { assert!(!val.simplify()); assert!(val.current().is_ok()); } else { assert!(val.simplify()); assert!(val.current().is_ok()); } } } { let input = maybe_ok(Just(()), Just(())); for _ in 0..64 { let mut val = input.new_tree(&mut runner).unwrap(); if val.current().is_err() { assert!(!val.simplify()); assert!(val.current().is_err()); } else { assert!(val.simplify()); assert!(val.current().is_err()); } } } } #[test] fn test_sanity() { check_strategy_sanity(maybe_ok(0i32..100i32, 0i32..100i32), None); check_strategy_sanity(maybe_err(0i32..100i32, 0i32..100i32), None); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/sample.rs������������������������������������������������������������������������0000644�0000000�0000000�00000041043�10461020230�0014130�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018 Jason Lingle // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Strategies for generating values by taking samples of collections. //! //! Note that the strategies in this module are not native combinators; that //! is, the input collection is not itself a strategy, but is rather fixed when //! the strategy is created. use crate::std_facade::{Arc, Cow, Vec}; use core::fmt; use core::mem; use core::ops::Range; use core::u64; use rand::Rng; use crate::bits::{self, BitSetValueTree, SampledBitSetStrategy, VarBitSet}; use crate::num; use crate::strategy::*; use crate::test_runner::*; /// Re-exported to make usage more ergonomic. pub use crate::collection::{size_range, SizeRange}; /// Sample subsequences whose size are within `size` from the given collection /// `values`. /// /// A subsequence is a subset of the elements in a collection in the order they /// occur in that collection. The elements are not chosen to be contiguous. /// /// This is roughly analogous to `rand::sample`, except that it guarantees that /// the order is preserved. /// /// `values` may be a static slice or a `Vec`. /// /// ## Panics /// /// Panics if the maximum size implied by `size` is larger than the size of /// `values`. /// /// Panics if `size` is a zero-length range. pub fn subsequence<T: Clone + 'static>( values: impl Into<Cow<'static, [T]>>, size: impl Into<SizeRange>, ) -> Subsequence<T> { let values = values.into(); let len = values.len(); let size = size.into(); size.assert_nonempty(); assert!( size.end_incl() <= len, "Maximum size of subsequence {} exceeds length of input {}", size.end_incl(), len ); Subsequence { values: Arc::new(values), bit_strategy: bits::varsize::sampled(size, 0..len), } } /// Strategy to generate `Vec`s by sampling a subsequence from another /// collection. /// /// This is created by the `subsequence` function in the same module. #[derive(Debug, Clone)] #[must_use = "strategies do nothing unless used"] pub struct Subsequence<T: Clone + 'static> { values: Arc<Cow<'static, [T]>>, bit_strategy: SampledBitSetStrategy<VarBitSet>, } impl<T: fmt::Debug + Clone + 'static> Strategy for Subsequence<T> { type Tree = SubsequenceValueTree<T>; type Value = Vec<T>; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { Ok(SubsequenceValueTree { values: Arc::clone(&self.values), inner: self.bit_strategy.new_tree(runner)?, }) } } /// `ValueTree` type for `Subsequence`. #[derive(Debug, Clone)] pub struct SubsequenceValueTree<T: Clone + 'static> { values: Arc<Cow<'static, [T]>>, inner: BitSetValueTree<VarBitSet>, } impl<T: fmt::Debug + Clone + 'static> ValueTree for SubsequenceValueTree<T> { type Value = Vec<T>; fn current(&self) -> Self::Value { let inner = self.inner.current(); let ret = inner.iter().map(|ix| self.values[ix].clone()).collect(); ret } fn simplify(&mut self) -> bool { self.inner.simplify() } fn complicate(&mut self) -> bool { self.inner.complicate() } } #[derive(Debug, Clone)] struct SelectMapFn<T: Clone + 'static>(Arc<Cow<'static, [T]>>); impl<T: fmt::Debug + Clone + 'static> statics::MapFn<usize> for SelectMapFn<T> { type Output = T; fn apply(&self, ix: usize) -> T { self.0[ix].clone() } } opaque_strategy_wrapper! { /// Strategy to produce one value from a fixed collection of options. /// /// Created by the `select()` in the same module. #[derive(Clone, Debug)] pub struct Select[<T>][where T : Clone + fmt::Debug + 'static]( statics::Map<Range<usize>, SelectMapFn<T>>) -> SelectValueTree<T>; /// `ValueTree` corresponding to `Select`. #[derive(Clone, Debug)] pub struct SelectValueTree[<T>][where T : Clone + fmt::Debug + 'static]( statics::Map<num::usize::BinarySearch, SelectMapFn<T>>) -> T; } /// Create a strategy which uniformly selects one value from `values`. /// /// `values` should be a `&'static [T]` or a `Vec<T>`, or potentially another /// type that can be coerced to `Cow<'static,[T]>`. /// /// This is largely equivalent to making a `Union` of a bunch of `Just` /// strategies, but is substantially more efficient and shrinks by binary /// search. /// /// If `values` is also to be generated by a strategy, see /// [`Index`](struct.Index.html) for a more efficient way to select values than /// using `prop_flat_map()`. pub fn select<T: Clone + fmt::Debug + 'static>( values: impl Into<Cow<'static, [T]>>, ) -> Select<T> { let cow = values.into(); Select(statics::Map::new(0..cow.len(), SelectMapFn(Arc::new(cow)))) } /// A stand-in for an index into a slice or similar collection or conceptually /// similar things. /// /// At the lowest level, `Index` is a mechanism for generating `usize` values /// in the range [0..N), for some N whose value is not known until it is /// needed. (Contrast with using `0..N` itself as a strategy, where you need to /// know N when you define the strategy.) /// /// For any upper bound, the actual index produced by an `Index` is the same no /// matter how many times it is used. Different upper bounds will produce /// different but not independent values. /// /// Shrinking will cause the index to binary search through the underlying /// collection(s) it is used to sample. /// /// Note that `Index` _cannot_ currently be used as a slice index (e.g., /// `slice[index]`) due to the trait coherence rules. /// /// ## Example /// /// If the collection itself being indexed is itself generated by a strategy, /// you can make separately define that strategy and a strategy generating one /// or more `Index`es and then join the two after input generation, avoiding a /// call to `prop_flat_map()`. /// /// ``` /// use proptest::prelude::*; /// /// proptest! { /// # /* /// #[test] /// # */ /// fn my_test( /// names in prop::collection::vec("[a-z]+", 10..20), /// indices in prop::collection::vec(any::<prop::sample::Index>(), 5..10) /// ) { /// // We now have Vec<String> of ten to twenty names, and a Vec<Index> /// // of five to ten indices and can combine them however we like. /// for index in &indices { /// println!("Accessing item by index: {}", names[index.index(names.len())]); /// println!("Accessing item by convenience method: {}", index.get(&names)); /// } /// // Test stuff... /// } /// } /// # /// # fn main() { my_test(); } /// ``` #[derive(Clone, Copy, Debug)] pub struct Index(usize); impl Index { /// Return the real index that would be used to index a collection of size `size`. /// /// ## Panics /// /// Panics if `size == 0`. pub fn index(&self, size: usize) -> usize { assert!(size > 0, "Attempt to use `Index` with 0-size collection"); // No platforms currently have `usize` wider than 64 bits, so `u128` is // sufficient to hold the result of a full multiply, letting us do a // simple fixed-point multiply. ((size as u128) * (self.0 as u128) >> (mem::size_of::<usize>() * 8)) as usize } /// Return a reference to the element in `slice` that this `Index` refers to. /// /// A shortcut for `&slice[index.index(slice.len())]`. pub fn get<'a, T>(&self, slice: &'a [T]) -> &'a T { &slice[self.index(slice.len())] } /// Return a mutable reference to the element in `slice` that this `Index` /// refers to. /// /// A shortcut for `&mut slice[index.index(slice.len())]`. pub fn get_mut<'a, T>(&self, slice: &'a mut [T]) -> &'a mut T { let ix = self.index(slice.len()); &mut slice[ix] } } // This impl is handy for generic code over any type that exposes an internal `Index` -- with it, // a plain `Index` can be passed in as well. impl AsRef<Index> for Index { fn as_ref(&self) -> &Index { self } } mapfn! { [] fn UsizeToIndex[](raw: usize) -> Index { Index(raw) } } opaque_strategy_wrapper! { /// Strategy to create `Index`es. /// /// Created via `any::<Index>()`. #[derive(Clone, Debug)] pub struct IndexStrategy[][]( statics::Map<num::usize::Any, UsizeToIndex>) -> IndexValueTree; /// `ValueTree` corresponding to `IndexStrategy`. #[derive(Clone, Debug)] pub struct IndexValueTree[][]( statics::Map<num::usize::BinarySearch,UsizeToIndex>) -> Index; } impl IndexStrategy { pub(crate) fn new() -> Self { IndexStrategy(statics::Map::new(num::usize::ANY, UsizeToIndex)) } } /// A value for picking random values out of iterators. /// /// This is, in a sense, a more flexible variant of /// [`Index`](struct.Index.html) in that it can operate on arbitrary /// `IntoIterator` values. /// /// Initially, the selection is roughly uniform, with a very slight bias /// towards items earlier in the iterator. /// /// Shrinking causes the selection to move toward items earlier in the /// iterator, ultimately settling on the very first, but this currently happens /// in a very haphazard way that may fail to find the earliest failing input. /// /// ## Example /// /// Generate a non-indexable collection and a value to pick out of it. /// /// ``` /// use proptest::prelude::*; /// /// proptest! { /// # /* /// #[test] /// # */ /// fn my_test( /// names in prop::collection::hash_set("[a-z]+", 10..20), /// selector in any::<prop::sample::Selector>() /// ) { /// println!("Selected name: {}", selector.select(&names)); /// // Test stuff... /// } /// } /// # /// # fn main() { my_test(); } /// ``` #[derive(Clone, Debug)] pub struct Selector { rng: TestRng, bias_increment: u64, } /// Strategy to create `Selector`s. /// /// Created via `any::<Selector>()`. #[derive(Debug)] pub struct SelectorStrategy { _nonexhaustive: (), } /// `ValueTree` corresponding to `SelectorStrategy`. #[derive(Debug)] pub struct SelectorValueTree { rng: TestRng, reverse_bias_increment: num::u64::BinarySearch, } impl SelectorStrategy { pub(crate) fn new() -> Self { SelectorStrategy { _nonexhaustive: () } } } impl Strategy for SelectorStrategy { type Tree = SelectorValueTree; type Value = Selector; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { Ok(SelectorValueTree { rng: runner.new_rng(), reverse_bias_increment: num::u64::BinarySearch::new(u64::MAX), }) } } impl ValueTree for SelectorValueTree { type Value = Selector; fn current(&self) -> Selector { Selector { rng: self.rng.clone(), bias_increment: u64::MAX - self.reverse_bias_increment.current(), } } fn simplify(&mut self) -> bool { self.reverse_bias_increment.simplify() } fn complicate(&mut self) -> bool { self.reverse_bias_increment.complicate() } } impl Selector { /// Pick a random element from iterable `it`. /// /// The selection is unaffected by the elements themselves, and is /// dependent only on the actual length of `it`. /// /// `it` is always iterated completely. /// /// ## Panics /// /// Panics if `it` has no elements. pub fn select<T: IntoIterator>(&self, it: T) -> T::Item { self.try_select(it).expect("select from empty iterator") } /// Pick a random element from iterable `it`. /// /// Returns `None` if `it` is empty. /// /// The selection is unaffected by the elements themselves, and is /// dependent only on the actual length of `it`. /// /// `it` is always iterated completely. pub fn try_select<T: IntoIterator>(&self, it: T) -> Option<T::Item> { let mut bias = 0u64; let mut min_score = 0; let mut best = None; let mut rng = self.rng.clone(); for item in it { let score = bias.saturating_add(rng.gen()); if best.is_none() || score < min_score { best = Some(item); min_score = score; } bias = bias.saturating_add(self.bias_increment); } best } } #[cfg(test)] mod test { use crate::std_facade::BTreeSet; use super::*; use crate::arbitrary::any; #[test] fn sample_slice() { static VALUES: &[usize] = &[0, 1, 2, 3, 4, 5, 6, 7]; let mut size_counts = [0; 8]; let mut value_counts = [0; 8]; let mut runner = TestRunner::deterministic(); let input = subsequence(VALUES, 3..7); for _ in 0..2048 { let value = input.new_tree(&mut runner).unwrap().current(); // Generated the correct number of items assert!(value.len() >= 3 && value.len() < 7); // Chose distinct items assert_eq!( value.len(), value.iter().cloned().collect::<BTreeSet<_>>().len() ); // Values are in correct order let mut sorted = value.clone(); sorted.sort(); assert_eq!(sorted, value); size_counts[value.len()] += 1; for value in value { value_counts[value] += 1; } } for i in 3..7 { assert!( size_counts[i] >= 256 && size_counts[i] < 1024, "size {} was chosen {} times", i, size_counts[i] ); } for (ix, &v) in value_counts.iter().enumerate() { assert!( v >= 1024 && v < 1500, "Value {} was chosen {} times", ix, v ); } } #[test] fn sample_vec() { // Just test that the types work out let values = vec![0, 1, 2, 3, 4]; let mut runner = TestRunner::deterministic(); let input = subsequence(values, 1..3); let _ = input.new_tree(&mut runner).unwrap().current(); } #[test] fn test_select() { let values = vec![0, 1, 2, 3, 4, 5, 6, 7]; let mut counts = [0; 8]; let mut runner = TestRunner::deterministic(); let input = select(values); for _ in 0..1024 { counts[input.new_tree(&mut runner).unwrap().current()] += 1; } for (ix, &count) in counts.iter().enumerate() { assert!( count >= 64 && count < 256, "Generated value {} {} times", ix, count ); } } #[test] fn test_sample_sanity() { check_strategy_sanity(subsequence(vec![0, 1, 2, 3, 4], 1..3), None); } #[test] fn test_select_sanity() { check_strategy_sanity(select(vec![0, 1, 2, 3, 4]), None); } #[test] fn subseq_empty_vec_works() { let mut runner = TestRunner::deterministic(); let input = subsequence(Vec::<()>::new(), 0..1); assert_eq!( Vec::<()>::new(), input.new_tree(&mut runner).unwrap().current() ); } #[test] fn subseq_full_vec_works() { let v = vec![1u32, 2u32, 3u32]; let mut runner = TestRunner::deterministic(); let input = subsequence(v.clone(), 3); assert_eq!(v, input.new_tree(&mut runner).unwrap().current()); } #[test] fn index_works() { let mut runner = TestRunner::deterministic(); let input = any::<Index>(); let col = vec!["foo", "bar", "baz"]; let mut seen = BTreeSet::new(); for _ in 0..16 { let mut tree = input.new_tree(&mut runner).unwrap(); seen.insert(*tree.current().get(&col)); while tree.simplify() {} assert_eq!("foo", *tree.current().get(&col)); } assert_eq!(col.into_iter().collect::<BTreeSet<_>>(), seen); } #[test] fn selector_works() { let mut runner = TestRunner::deterministic(); let input = any::<Selector>(); let col: BTreeSet<&str> = vec!["foo", "bar", "baz"].into_iter().collect(); let mut seen = BTreeSet::new(); for _ in 0..16 { let mut tree = input.new_tree(&mut runner).unwrap(); seen.insert(*tree.current().select(&col)); while tree.simplify() {} assert_eq!("bar", *tree.current().select(&col)); } assert_eq!(col, seen); } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/std_facade.rs��������������������������������������������������������������������0000644�0000000�0000000�00000004666�10461020230�0014736�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 } ��������������������������������������������������������������������������proptest-1.6.0/src/strategy/filter.rs���������������������������������������������������������������0000644�0000000�0000000�00000007506�10461020230�0016004�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017 Jason Lingle // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::{fmt, Arc}; use crate::strategy::traits::*; use crate::test_runner::*; /// `Strategy` and `ValueTree` filter adaptor. /// /// See `Strategy::prop_filter()`. #[must_use = "strategies do nothing unless used"] pub struct Filter<S, F> { pub(super) source: S, pub(super) whence: Reason, pub(super) fun: Arc<F>, } impl<S, F> Filter<S, F> { pub(super) fn new(source: S, whence: Reason, fun: F) -> Self { Self { source, whence, fun: Arc::new(fun), } } } impl<S: fmt::Debug, F> fmt::Debug for Filter<S, F> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Filter") .field("source", &self.source) .field("whence", &self.whence) .field("fun", &"<function>") .finish() } } impl<S: Clone, F> Clone for Filter<S, F> { fn clone(&self) -> Self { Filter { source: self.source.clone(), whence: "unused".into(), fun: Arc::clone(&self.fun), } } } impl<S: Strategy, F: Fn(&S::Value) -> bool> Strategy for Filter<S, F> { type Tree = Filter<S::Tree, F>; type Value = S::Value; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { loop { let val = self.source.new_tree(runner)?; if !(self.fun)(&val.current()) { runner.reject_local(self.whence.clone())?; } else { return Ok(Filter { source: val, whence: self.whence.clone(), fun: Arc::clone(&self.fun), }); } } } } impl<S: ValueTree, F: Fn(&S::Value) -> bool> Filter<S, F> { fn ensure_acceptable(&mut self) { while !(self.fun)(&self.source.current()) { if !self.source.complicate() { panic!( "Unable to complicate filtered strategy \ back into acceptable value" ); } } } } impl<S: ValueTree, F: Fn(&S::Value) -> bool> ValueTree for Filter<S, F> { type Value = S::Value; fn current(&self) -> S::Value { self.source.current() } fn simplify(&mut self) -> bool { if self.source.simplify() { self.ensure_acceptable(); true } else { false } } fn complicate(&mut self) -> bool { if self.source.complicate() { self.ensure_acceptable(); true } else { false } } } #[cfg(test)] mod test { use super::*; #[test] fn test_filter() { let input = (0..256).prop_filter("%3", |&v| 0 == v % 3); for _ in 0..256 { let mut runner = TestRunner::default(); let mut case = input.new_tree(&mut runner).unwrap(); assert!(0 == case.current() % 3); while case.simplify() { assert!(0 == case.current() % 3); } assert!(0 == case.current() % 3); } } #[test] fn test_filter_sanity() { check_strategy_sanity( (0..256).prop_filter("!%5", |&v| 0 != v % 5), Some(CheckStrategySanityOptions { // Due to internal rejection sampling, `simplify()` can // converge back to what `complicate()` would do. strict_complicate_after_simplify: false, ..CheckStrategySanityOptions::default() }), ); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/strategy/filter_map.rs�����������������������������������������������������������0000644�0000000�0000000�00000013064�10461020230�0016635�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017 Jason Lingle // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::{fmt, Arc, Cell}; use crate::strategy::traits::*; use crate::test_runner::*; /// `Strategy` and `ValueTree` filter_map adaptor. /// /// See `Strategy::prop_filter_map()`. #[must_use = "strategies do nothing unless used"] pub struct FilterMap<S, F> { pub(super) source: S, pub(super) whence: Reason, pub(super) fun: Arc<F>, } impl<S, F> FilterMap<S, F> { pub(super) fn new(source: S, whence: Reason, fun: F) -> Self { Self { source, whence, fun: Arc::new(fun), } } } impl<S: fmt::Debug, F> fmt::Debug for FilterMap<S, F> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("FilterMap") .field("source", &self.source) .field("whence", &self.whence) .field("fun", &"<function>") .finish() } } impl<S: Clone, F> Clone for FilterMap<S, F> { fn clone(&self) -> Self { Self { source: self.source.clone(), whence: self.whence.clone(), fun: Arc::clone(&self.fun), } } } impl<S: Strategy, F: Fn(S::Value) -> Option<O>, O: fmt::Debug> Strategy for FilterMap<S, F> { type Tree = FilterMapValueTree<S::Tree, F, O>; type Value = O; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { loop { let val = self.source.new_tree(runner)?; if let Some(current) = (self.fun)(val.current()) { return Ok(FilterMapValueTree::new(val, &self.fun, current)); } else { runner.reject_local(self.whence.clone())?; } } } } /// `ValueTree` corresponding to `FilterMap`. pub struct FilterMapValueTree<V, F, O> { source: V, current: Cell<Option<O>>, fun: Arc<F>, } impl<V: Clone + ValueTree, F: Fn(V::Value) -> Option<O>, O> Clone for FilterMapValueTree<V, F, O> { fn clone(&self) -> Self { Self::new(self.source.clone(), &self.fun, self.fresh_current()) } } impl<V: fmt::Debug, F, O> fmt::Debug for FilterMapValueTree<V, F, O> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("FilterMapValueTree") .field("source", &self.source) .field("current", &"<current>") .field("fun", &"<function>") .finish() } } impl<V: ValueTree, F: Fn(V::Value) -> Option<O>, O> FilterMapValueTree<V, F, O> { fn new(source: V, fun: &Arc<F>, current: O) -> Self { Self { source, current: Cell::new(Some(current)), fun: Arc::clone(fun), } } fn fresh_current(&self) -> O { (self.fun)(self.source.current()) .expect("internal logic error; this is a bug!") } fn ensure_acceptable(&mut self) { loop { if let Some(current) = (self.fun)(self.source.current()) { // Found an acceptable element! self.current = Cell::new(Some(current)); break; } else if !self.source.complicate() { panic!( "Unable to complicate filtered strategy \ back into acceptable value" ); } } } } impl<V: ValueTree, F: Fn(V::Value) -> Option<O>, O: fmt::Debug> ValueTree for FilterMapValueTree<V, F, O> { type Value = O; fn current(&self) -> O { // Optimization: we avoid the else branch in most success cases // thereby avoiding to call the closure and the source tree. if let Some(current) = self.current.replace(None) { current } else { self.fresh_current() } } fn simplify(&mut self) -> bool { if self.source.simplify() { self.ensure_acceptable(); true } else { false } } fn complicate(&mut self) -> bool { if self.source.complicate() { self.ensure_acceptable(); true } else { false } } } #[cfg(test)] mod test { use super::*; #[test] fn test_filter_map() { let input = (0..256).prop_filter_map("%3 + 1", |v| { if 0 == v % 3 { Some(v + 1) } else { None } }); for _ in 0..256 { let mut runner = TestRunner::default(); let mut case = input.new_tree(&mut runner).unwrap(); assert_eq!(0, (case.current() - 1) % 3); while case.simplify() { assert_eq!(0, (case.current() - 1) % 3); } assert_eq!(0, (case.current() - 1) % 3); } } #[test] fn test_filter_map_sanity() { check_strategy_sanity( (0..256).prop_filter_map("!%5 * 2", |v| { if 0 != v % 5 { Some(v * 2) } else { None } }), Some(CheckStrategySanityOptions { // Due to internal rejection sampling, `simplify()` can // converge back to what `complicate()` would do. strict_complicate_after_simplify: false, ..CheckStrategySanityOptions::default() }), ); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/strategy/flatten.rs��������������������������������������������������������������0000644�0000000�0000000�00000026016�10461020230�0016151�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017 Jason Lingle // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::{fmt, Arc}; use core::mem; use crate::strategy::fuse::Fuse; use crate::strategy::traits::*; use crate::test_runner::*; /// Adaptor that flattens a `Strategy` which produces other `Strategy`s into a /// `Strategy` that picks one of those strategies and then picks values from /// it. #[derive(Debug, Clone, Copy)] #[must_use = "strategies do nothing unless used"] pub struct Flatten<S> { source: S, } impl<S: Strategy> Flatten<S> { /// Wrap `source` to flatten it. pub fn new(source: S) -> Self { Flatten { source } } } impl<S: Strategy> Strategy for Flatten<S> where S::Value: Strategy, { type Tree = FlattenValueTree<S::Tree>; type Value = <S::Value as Strategy>::Value; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { let meta = self.source.new_tree(runner)?; FlattenValueTree::new(runner, meta) } } /// The `ValueTree` produced by `Flatten`. pub struct FlattenValueTree<S: ValueTree> where S::Value: Strategy, { meta: Fuse<S>, current: Fuse<<S::Value as Strategy>::Tree>, // The final value to produce after successive calls to complicate() on the // underlying objects return false. final_complication: Option<Fuse<<S::Value as Strategy>::Tree>>, // When `simplify()` or `complicate()` causes a new `Strategy` to be // chosen, we need to find a new failing input for that case. To do this, // we implement `complicate()` by regenerating values up to a number of // times corresponding to the maximum number of test cases. A `simplify()` // which does not cause a new strategy to be chosen always resets // `complicate_regen_remaining` to 0. // // This does unfortunately depart from the direct interpretation of // simplify/complicate as binary search, but is still easier to think about // than other implementations of higher-order strategies. runner: TestRunner, complicate_regen_remaining: u32, } impl<S: ValueTree> Clone for FlattenValueTree<S> where S::Value: Strategy + Clone, S: Clone, <S::Value as Strategy>::Tree: Clone, { fn clone(&self) -> Self { FlattenValueTree { meta: self.meta.clone(), current: self.current.clone(), final_complication: self.final_complication.clone(), runner: self.runner.clone(), complicate_regen_remaining: self.complicate_regen_remaining, } } } impl<S: ValueTree> fmt::Debug for FlattenValueTree<S> where S::Value: Strategy, S: fmt::Debug, <S::Value as Strategy>::Tree: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("FlattenValueTree") .field("meta", &self.meta) .field("current", &self.current) .field("final_complication", &self.final_complication) .field( "complicate_regen_remaining", &self.complicate_regen_remaining, ) .finish() } } impl<S: ValueTree> FlattenValueTree<S> where S::Value: Strategy, { fn new(runner: &mut TestRunner, meta: S) -> Result<Self, Reason> { let current = meta.current().new_tree(runner)?; Ok(FlattenValueTree { meta: Fuse::new(meta), current: Fuse::new(current), final_complication: None, runner: runner.partial_clone(), complicate_regen_remaining: 0, }) } } impl<S: ValueTree> ValueTree for FlattenValueTree<S> where S::Value: Strategy, { type Value = <S::Value as Strategy>::Value; fn current(&self) -> Self::Value { self.current.current() } fn simplify(&mut self) -> bool { self.complicate_regen_remaining = 0; if self.current.simplify() { // Now that we've simplified the derivative value, we can't // re-complicate the meta value unless it gets simplified again. // We also mustn't complicate back to whatever's in // `final_complication` since the new state of `self.current` is // the most complicated state. self.meta.disallow_complicate(); self.final_complication = None; true } else if !self.meta.simplify() { false } else if let Ok(v) = self.meta.current().new_tree(&mut self.runner) { // Shift current into final_complication and `v` into // `current`. We also need to prevent that value from // complicating beyond the current point in the future // since we're going to return `true` from `simplify()` // ourselves. self.current.disallow_complicate(); self.final_complication = Some(Fuse::new(v)); mem::swap( self.final_complication.as_mut().unwrap(), &mut self.current, ); // Initially complicate by regenerating the chosen value. self.complicate_regen_remaining = self.runner.config().cases; true } else { false } } fn complicate(&mut self) -> bool { if self.complicate_regen_remaining > 0 { if self.runner.flat_map_regen() { self.complicate_regen_remaining -= 1; if let Ok(v) = self.meta.current().new_tree(&mut self.runner) { self.current = Fuse::new(v); return true; } } else { self.complicate_regen_remaining = 0; } } if self.current.complicate() { return true; } else if self.meta.complicate() { if let Ok(v) = self.meta.current().new_tree(&mut self.runner) { self.complicate_regen_remaining = self.runner.config().cases; self.current = Fuse::new(v); return true; } } if let Some(v) = self.final_complication.take() { self.current = v; true } else { false } } } /// Similar to `Flatten`, but does not shrink the input strategy. /// /// See `Strategy::prop_ind_flat_map()` fore more details. #[derive(Clone, Copy, Debug)] pub struct IndFlatten<S>(pub(super) S); impl<S: Strategy> Strategy for IndFlatten<S> where S::Value: Strategy, { type Tree = <S::Value as Strategy>::Tree; type Value = <S::Value as Strategy>::Value; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { let inner = self.0.new_tree(runner)?; inner.current().new_tree(runner) } } /// Similar to `Map` plus `Flatten`, but does not shrink the input strategy and /// passes the original input through. /// /// See `Strategy::prop_ind_flat_map2()` for more details. pub struct IndFlattenMap<S, F> { pub(super) source: S, pub(super) fun: Arc<F>, } impl<S: fmt::Debug, F> fmt::Debug for IndFlattenMap<S, F> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("IndFlattenMap") .field("source", &self.source) .field("fun", &"<function>") .finish() } } impl<S: Clone, F> Clone for IndFlattenMap<S, F> { fn clone(&self) -> Self { IndFlattenMap { source: self.source.clone(), fun: Arc::clone(&self.fun), } } } impl<S: Strategy, R: Strategy, F: Fn(S::Value) -> R> Strategy for IndFlattenMap<S, F> { type Tree = crate::tuple::TupleValueTree<(S::Tree, R::Tree)>; type Value = (S::Value, R::Value); fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { let left = self.source.new_tree(runner)?; let right_source = (self.fun)(left.current()); let right = right_source.new_tree(runner)?; Ok(crate::tuple::TupleValueTree::new((left, right))) } } #[cfg(test)] mod test { use super::*; use std::u32; use crate::strategy::just::Just; use crate::test_runner::Config; #[test] fn test_flat_map() { // Pick random integer A, then random integer B which is ±5 of A and // assert that B <= A if A > 10000. Shrinking should always converge to // A=10001, B=10002. let input = (0..65536).prop_flat_map(|a| (Just(a), (a - 5..a + 5))); let mut failures = 0; let mut runner = TestRunner::new_with_rng( Config { max_shrink_iters: u32::MAX - 1, ..Config::default() }, TestRng::deterministic_rng(RngAlgorithm::default()), ); for _ in 0..1000 { let case = input.new_tree(&mut runner).unwrap(); let result = runner.run_one(case, |(a, b)| { if a <= 10000 || b <= a { Ok(()) } else { Err(TestCaseError::fail("fail")) } }); match result { Ok(_) => {} Err(TestError::Fail(_, v)) => { failures += 1; assert_eq!((10001, 10002), v); } result => panic!("Unexpected result: {:?}", result), } } assert!(failures > 250); } #[test] fn test_flat_map_sanity() { check_strategy_sanity( (0..65536).prop_flat_map(|a| (Just(a), (a - 5..a + 5))), None, ); } #[test] fn flat_map_respects_regen_limit() { use std::sync::atomic::{AtomicBool, Ordering}; let input = (0..65536) .prop_flat_map(|_| 0..65536) .prop_flat_map(|_| 0..65536) .prop_flat_map(|_| 0..65536) .prop_flat_map(|_| 0..65536) .prop_flat_map(|_| 0..65536); // Arteficially make the first case fail and all others pass, so that // the regeneration logic futilely searches for another failing // example and eventually gives up. Unfortunately, the test is sort of // semi-decidable; if the limit *doesn't* work, the test just runs // almost forever. let pass = AtomicBool::new(false); let mut runner = TestRunner::new(Config { max_flat_map_regens: 1000, ..Config::default() }); let case = input.new_tree(&mut runner).unwrap(); let _ = runner.run_one(case, |_| { // Only the first run fails, all others succeed prop_assert!(pass.fetch_or(true, Ordering::SeqCst)); Ok(()) }); } #[test] fn test_ind_flat_map_sanity() { check_strategy_sanity( (0..65536).prop_ind_flat_map(|a| (Just(a), (a - 5..a + 5))), None, ); } #[test] fn test_ind_flat_map2_sanity() { check_strategy_sanity( (0..65536).prop_ind_flat_map2(|a| a - 5..a + 5), None, ); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/strategy/fuse.rs�����������������������������������������������������������������0000644�0000000�0000000�00000014571�10461020230�0015461�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017 Jason Lingle // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::strategy::*; use crate::test_runner::*; /// Adaptor for `Strategy` and `ValueTree` which guards `simplify()` and /// `complicate()` to avoid contract violations. /// /// This can be used as an intermediate when the caller would otherwise need /// its own separate state tracking, or as a workaround for a broken /// `ValueTree` implementation. /// /// This wrapper specifically has the following effects: /// /// - Calling `complicate()` before `simplify()` was ever called does nothing /// and returns `false`. /// /// - Calling `simplify()` after it has returned `false` and no calls to /// `complicate()` returned `true` does nothing and returns `false`. /// /// - Calling `complicate()` after it has returned `false` and no calls to /// `simplify()` returned `true` does nothing and returns `false`. /// /// There is also limited functionality to alter the internal state to assist /// in its usage as a state tracker. /// /// Wrapping a `Strategy` in `Fuse` simply causes its `ValueTree` to also be /// wrapped in `Fuse`. /// /// While this is similar to `std::iter::Fuse`, it is not exposed as a method /// on `Strategy` since the vast majority of proptest should never need this /// functionality; it mainly concerns implementors of strategies. #[derive(Debug, Clone, Copy)] #[must_use = "strategies do nothing unless used"] pub struct Fuse<T> { inner: T, may_simplify: bool, may_complicate: bool, } impl<T> Fuse<T> { /// Wrap the given `T` in `Fuse`. pub fn new(inner: T) -> Self { Fuse { inner, may_simplify: true, may_complicate: false, } } } impl<T: Strategy> Strategy for Fuse<T> { type Tree = Fuse<T::Tree>; type Value = T::Value; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { self.inner.new_tree(runner).map(Fuse::new) } } impl<T: ValueTree> Fuse<T> { /// Return whether a call to `simplify()` may be productive. /// /// Formally, this is true if one of the following holds: /// /// - `simplify()` has never been called. /// - The most recent call to `simplify()` returned `true`. /// - `complicate()` has been called more recently than `simplify()` and /// the last call returned `true`. pub fn may_simplify(&self) -> bool { self.may_simplify } /// Disallow any further calls to `simplify()` until a call to /// `complicate()` returns `true`. pub fn disallow_simplify(&mut self) { self.may_simplify = false; } /// Return whether a call to `complicate()` may be productive. /// /// Formally, this is true if one of the following holds: /// /// - The most recent call to `complicate()` returned `true`. /// - `simplify()` has been called more recently than `complicate()` and /// the last call returned `true`. pub fn may_complicate(&self) -> bool { self.may_complicate } /// Disallow any further calls to `complicate()` until a call to /// `simplify()` returns `true`. pub fn disallow_complicate(&mut self) { self.may_complicate = false; } /// Prevent any further shrinking operations from occurring. pub fn freeze(&mut self) { self.disallow_simplify(); self.disallow_complicate(); } } impl<T: ValueTree> ValueTree for Fuse<T> { type Value = T::Value; fn current(&self) -> T::Value { self.inner.current() } fn simplify(&mut self) -> bool { if self.may_simplify { if self.inner.simplify() { self.may_complicate = true; true } else { self.may_simplify = false; false } } else { false } } fn complicate(&mut self) -> bool { if self.may_complicate { if self.inner.complicate() { self.may_simplify = true; true } else { self.may_complicate = false; false } } else { false } } } #[cfg(test)] mod test { use super::*; struct StrictValueTree { min: u32, curr: u32, max: u32, ready: bool, } impl StrictValueTree { fn new(start: u32) -> Self { StrictValueTree { min: 0, curr: start, max: start, ready: false, } } } impl ValueTree for StrictValueTree { type Value = u32; fn current(&self) -> u32 { self.curr } fn simplify(&mut self) -> bool { assert!(self.min <= self.curr); if self.curr > self.min { self.max = self.curr; self.curr -= 1; self.ready = true; true } else { self.min += 1; false } } fn complicate(&mut self) -> bool { assert!(self.max >= self.curr); assert!(self.ready); if self.curr < self.max { self.curr += 1; true } else { self.max -= 1; false } } } #[test] fn test_sanity() { check_strategy_sanity(Fuse::new(0i32..100i32), None); } #[test] fn guards_bad_transitions() { let mut vt = Fuse::new(StrictValueTree::new(5)); assert!(!vt.complicate()); assert_eq!(5, vt.current()); assert!(vt.simplify()); // 0, 4, 5 assert!(vt.simplify()); // 0, 3, 4 assert!(vt.simplify()); // 0, 2, 3 assert!(vt.simplify()); // 0, 1, 2 assert!(vt.simplify()); // 0, 0, 1 assert_eq!(0, vt.current()); assert!(!vt.simplify()); // 1, 0, 1 assert!(!vt.simplify()); // 1, 0, 1 assert_eq!(0, vt.current()); assert!(vt.complicate()); // 1, 1, 1 assert_eq!(1, vt.current()); assert!(!vt.complicate()); // 1, 1, 0 assert!(!vt.complicate()); // 1, 1, 0 assert_eq!(1, vt.current()); } } ���������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/strategy/just.rs�����������������������������������������������������������������0000644�0000000�0000000�00000007760�10461020230�0015506�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T: Clone + fmt::Debug>( /// The value produced by this strategy. pub T, ); impl<T: Clone + fmt::Debug> Strategy for Just<T> { type Tree = Self; type Value = T; fn new_tree(&self, _: &mut TestRunner) -> NewTree<Self> { Ok(self.clone()) } } impl<T: Clone + fmt::Debug> ValueTree for Just<T> { type Value = T; noshrink!(); fn current(&self) -> T { self.0.clone() } } //============================================================================== // 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, F: Fn() -> T> { /// The function executed in `.current()`. function: F, } /// Shorthand for `LazyJust<T, fn () -> T>`. pub type LazyJustFn<V> = LazyJust<V, fn() -> V>; impl<T, F: Fn() -> T> LazyJust<T, F> { /// 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 } } } impl<T: fmt::Debug, F: Clone + Fn() -> T> Strategy for LazyJust<T, F> { type Tree = Self; type Value = T; fn new_tree(&self, _: &mut TestRunner) -> NewTree<Self> { Ok(self.clone()) } } impl<T: fmt::Debug, F: Fn() -> T> ValueTree for LazyJust<T, F> { type Value = T; noshrink!(); fn current(&self) -> Self::Value { (self.function)() } } impl<T, F: Copy + Fn() -> T> Copy for LazyJust<T, F> {} impl<T, F: Clone + Fn() -> T> Clone for LazyJust<T, F> { fn clone(&self) -> Self { Self { function: self.function.clone(), } } } impl<T, F: Fn() -> T> fmt::Debug for LazyJust<T, F> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt.debug_struct("LazyJust") .field("function", &"<function>") .finish() } } //============================================================================== // Any `fn () -> T` is a Strategy //============================================================================== // TODO: try 'F: Fn () -> T' instead when we've got specialization. impl<T: fmt::Debug> Strategy for fn() -> T { type Tree = Self; type Value = T; fn new_tree(&self, _: &mut TestRunner) -> NewTree<Self> { Ok(*self) } } impl<T: fmt::Debug> ValueTree for fn() -> T { type Value = T; noshrink!(); fn current(&self) -> Self::Value { self() } } ����������������proptest-1.6.0/src/strategy/lazy.rs�����������������������������������������������������������������0000644�0000000�0000000�00000012343�10461020230�0015471�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2019 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::{fmt, Arc}; use core::mem; use crate::strategy::traits::*; use crate::test_runner::*; /// Represents a value tree that is initialized on the first call to any /// methods. /// /// This is used to defer potentially expensive generation to shrinking time. It /// is public only to allow APIs to expose it as an intermediate value. pub struct LazyValueTree<S: Strategy> { state: LazyValueTreeState<S>, } enum LazyValueTreeState<S: Strategy> { Initialized(S::Tree), Uninitialized { strategy: Arc<S>, runner: TestRunner, }, Failed, } impl<S: Strategy> LazyValueTree<S> { /// Create a new value tree where initial generation is deferred until /// `maybe_init` is called. pub(crate) fn new(strategy: Arc<S>, runner: &mut TestRunner) -> Self { let runner = runner.partial_clone(); Self { state: LazyValueTreeState::Uninitialized { strategy, runner }, } } /// Create a new value tree that has already been initialized. pub(crate) fn new_initialized(value_tree: S::Tree) -> Self { Self { state: LazyValueTreeState::Initialized(value_tree), } } /// Returns a reference to the inner value tree if initialized. pub(crate) fn as_inner(&self) -> Option<&S::Tree> { match &self.state { LazyValueTreeState::Initialized(v) => Some(v), LazyValueTreeState::Uninitialized { .. } | LazyValueTreeState::Failed => None, } } /// Returns a mutable reference to the inner value tree if uninitialized. pub(crate) fn as_inner_mut(&mut self) -> Option<&mut S::Tree> { match &mut self.state { LazyValueTreeState::Initialized(v) => Some(v), LazyValueTreeState::Uninitialized { .. } | LazyValueTreeState::Failed => None, } } /// Try initializing the value tree. pub(crate) fn maybe_init(&mut self) { if !self.is_uninitialized() { return; } let state = mem::replace(&mut self.state, LazyValueTreeState::Failed); match state { LazyValueTreeState::Uninitialized { strategy, mut runner, } => { match strategy.new_tree(&mut runner) { Ok(v) => { let _ = mem::replace( &mut self.state, LazyValueTreeState::Initialized(v), ); } Err(_) => { // self.state is set to Failed above. Keep it that way. } } } LazyValueTreeState::Initialized(_) | LazyValueTreeState::Failed => { unreachable!("can only reach here if uninitialized") } } } /// Whether this value tree still needs to be initialized. pub(crate) fn is_uninitialized(&self) -> bool { match &self.state { LazyValueTreeState::Uninitialized { .. } => true, LazyValueTreeState::Initialized(_) | LazyValueTreeState::Failed => { false } } } /// Whether the value tree was successfully initialized. pub(crate) fn is_initialized(&self) -> bool { match &self.state { LazyValueTreeState::Initialized(_) => true, LazyValueTreeState::Uninitialized { .. } | LazyValueTreeState::Failed => false, } } } impl<S: Strategy> Clone for LazyValueTree<S> where S::Tree: Clone, { fn clone(&self) -> Self { Self { state: self.state.clone(), } } } impl<S: Strategy> fmt::Debug for LazyValueTree<S> where S::Tree: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("LazyValueTree") .field("state", &self.state) .finish() } } impl<S: Strategy> Clone for LazyValueTreeState<S> where S::Tree: Clone, { fn clone(&self) -> Self { use LazyValueTreeState::*; match self { Initialized(v) => Initialized(v.clone()), Uninitialized { strategy, runner } => Uninitialized { strategy: Arc::clone(strategy), runner: runner.clone(), }, Failed => Failed, } } } impl<S: Strategy> fmt::Debug for LazyValueTreeState<S> where S::Tree: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { LazyValueTreeState::Initialized(value_tree) => { f.debug_tuple("Initialized").field(value_tree).finish() } LazyValueTreeState::Uninitialized { strategy, .. } => f .debug_struct("Uninitialized") .field("strategy", strategy) .finish(), LazyValueTreeState::Failed => write!(f, "Failed"), } } } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/strategy/map.rs������������������������������������������������������������������0000644�0000000�0000000�00000016572�10461020230�0015277�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017 Jason Lingle // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::Arc; use core::fmt; use core::marker::PhantomData; use crate::strategy::traits::*; use crate::test_runner::*; //============================================================================== // Map //============================================================================== /// `Strategy` and `ValueTree` map adaptor. /// /// See `Strategy::prop_map()`. #[must_use = "strategies do nothing unless used"] pub struct Map<S, F> { pub(super) source: S, pub(super) fun: Arc<F>, } impl<S: fmt::Debug, F> fmt::Debug for Map<S, F> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Map") .field("source", &self.source) .field("fun", &"<function>") .finish() } } impl<S: Clone, F> Clone for Map<S, F> { fn clone(&self) -> Self { Map { source: self.source.clone(), fun: Arc::clone(&self.fun), } } } impl<S: Strategy, O: fmt::Debug, F: Fn(S::Value) -> O> Strategy for Map<S, F> { type Tree = Map<S::Tree, F>; type Value = O; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { self.source.new_tree(runner).map(|v| Map { source: v, fun: Arc::clone(&self.fun), }) } } impl<S: ValueTree, O: fmt::Debug, F: Fn(S::Value) -> O> ValueTree for Map<S, F> { type Value = O; fn current(&self) -> O { (self.fun)(self.source.current()) } fn simplify(&mut self) -> bool { self.source.simplify() } fn complicate(&mut self) -> bool { self.source.complicate() } } //============================================================================== // MapInto //============================================================================== // NOTE: Since this is external stable API, // we avoid relying on the Map in `statics`. /// `Strategy` and `ValueTree` map into adaptor. /// /// See `Strategy::prop_map_into()`. #[must_use = "strategies do nothing unless used"] pub struct MapInto<S, O> { pub(super) source: S, pub(super) output: PhantomData<O>, } impl<S, O> MapInto<S, O> { /// Construct a `MapInto` mapper from an `S` strategy into a strategy /// producing `O`s. pub(super) fn new(source: S) -> Self { Self { source, output: PhantomData, } } } impl<S: fmt::Debug, O> fmt::Debug for MapInto<S, O> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("MapInto") .field("source", &self.source) .finish() } } impl<S: Clone, O> Clone for MapInto<S, O> { fn clone(&self) -> Self { Self::new(self.source.clone()) } } impl<S: Strategy, O: fmt::Debug> Strategy for MapInto<S, O> where S::Value: Into<O>, { type Tree = MapInto<S::Tree, O>; type Value = O; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { self.source.new_tree(runner).map(MapInto::new) } } impl<S: ValueTree, O: fmt::Debug> ValueTree for MapInto<S, O> where S::Value: Into<O>, { type Value = O; fn current(&self) -> O { self.source.current().into() } fn simplify(&mut self) -> bool { self.source.simplify() } fn complicate(&mut self) -> bool { self.source.complicate() } } //============================================================================== // Perturb //============================================================================== /// `Strategy` perturbation adaptor. /// /// See `Strategy::prop_perturb()`. #[must_use = "strategies do nothing unless used"] pub struct Perturb<S, F> { pub(super) source: S, pub(super) fun: Arc<F>, } impl<S: fmt::Debug, F> fmt::Debug for Perturb<S, F> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Perturb") .field("source", &self.source) .field("fun", &"<function>") .finish() } } impl<S: Clone, F> Clone for Perturb<S, F> { fn clone(&self) -> Self { Perturb { source: self.source.clone(), fun: Arc::clone(&self.fun), } } } impl<S: Strategy, O: fmt::Debug, F: Fn(S::Value, TestRng) -> O> Strategy for Perturb<S, F> { type Tree = PerturbValueTree<S::Tree, F>; type Value = O; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { let rng = runner.new_rng(); self.source.new_tree(runner).map(|source| PerturbValueTree { source, rng, fun: Arc::clone(&self.fun), }) } } /// `ValueTree` perturbation adaptor. /// /// See `Strategy::prop_perturb()`. pub struct PerturbValueTree<S, F> { source: S, fun: Arc<F>, rng: TestRng, } impl<S: fmt::Debug, F> fmt::Debug for PerturbValueTree<S, F> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("PerturbValueTree") .field("source", &self.source) .field("fun", &"<function>") .field("rng", &self.rng) .finish() } } impl<S: Clone, F> Clone for PerturbValueTree<S, F> { fn clone(&self) -> Self { PerturbValueTree { source: self.source.clone(), fun: Arc::clone(&self.fun), rng: self.rng.clone(), } } } impl<S: ValueTree, O: fmt::Debug, F: Fn(S::Value, TestRng) -> O> ValueTree for PerturbValueTree<S, F> { type Value = O; fn current(&self) -> O { (self.fun)(self.source.current(), self.rng.clone()) } fn simplify(&mut self) -> bool { self.source.simplify() } fn complicate(&mut self) -> bool { self.source.complicate() } } //============================================================================== // Tests //============================================================================== #[cfg(test)] mod test { use std::collections::HashSet; use rand::RngCore; use super::*; use crate::strategy::just::Just; #[test] fn test_map() { TestRunner::default() .run(&(0..10).prop_map(|v| v * 2), |v| { assert!(0 == v % 2); Ok(()) }) .unwrap(); } #[test] fn test_map_into() { TestRunner::default() .run(&(0..10u8).prop_map_into::<usize>(), |v| { assert!(v < 10); Ok(()) }) .unwrap(); } #[test] fn perturb_uses_same_rng_every_time() { let mut runner = TestRunner::default(); let input = Just(1).prop_perturb(|v, mut rng| v + rng.next_u32()); for _ in 0..16 { let value = input.new_tree(&mut runner).unwrap(); assert_eq!(value.current(), value.current()); } } #[test] fn perturb_uses_varying_random_seeds() { let mut runner = TestRunner::default(); let input = Just(1).prop_perturb(|v, mut rng| v + rng.next_u32()); let mut seen = HashSet::new(); for _ in 0..64 { seen.insert(input.new_tree(&mut runner).unwrap().current()); } assert_eq!(64, seen.len()); } } ��������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/strategy/mod.rs������������������������������������������������������������������0000644�0000000�0000000�00000001475�10461020230�0015275�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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::map::*; pub use self::recursive::*; pub use self::shuffle::*; pub use self::traits::*; pub use self::unions::*; pub mod statics; ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/strategy/recursive.rs������������������������������������������������������������0000644�0000000�0000000�00000016054�10461020230�0016524�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017 Jason Lingle // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::{fmt, Arc, Box, Vec}; use crate::strategy::traits::*; use crate::strategy::unions::float_to_weight; use crate::test_runner::*; /// Return type from `Strategy::prop_recursive()`. #[must_use = "strategies do nothing unless used"] pub struct Recursive<T, F> { base: BoxedStrategy<T>, recurse: Arc<F>, depth: u32, desired_size: u32, expected_branch_size: u32, } impl<T: fmt::Debug, F> fmt::Debug for Recursive<T, F> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Recursive") .field("base", &self.base) .field("recurse", &"<function>") .field("depth", &self.depth) .field("desired_size", &self.desired_size) .field("expected_branch_size", &self.expected_branch_size) .finish() } } impl<T, F> Clone for Recursive<T, F> { fn clone(&self) -> Self { Recursive { base: self.base.clone(), recurse: Arc::clone(&self.recurse), depth: self.depth, desired_size: self.desired_size, expected_branch_size: self.expected_branch_size, } } } impl< T: fmt::Debug + 'static, R: Strategy<Value = T> + 'static, F: Fn(BoxedStrategy<T>) -> R, > Recursive<T, F> { pub(super) fn new( base: impl Strategy<Value = T> + 'static, depth: u32, desired_size: u32, expected_branch_size: u32, recurse: F, ) -> Self { Self { base: base.boxed(), recurse: Arc::new(recurse), depth, desired_size, expected_branch_size, } } } impl< T: fmt::Debug + 'static, R: Strategy<Value = T> + 'static, F: Fn(BoxedStrategy<T>) -> R, > Strategy for Recursive<T, F> { type Tree = Box<dyn ValueTree<Value = T>>; type Value = T; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { // Since the generator is stateless, we can't implement any "absolutely // X many items" rule. We _can_, however, with extremely high // probability, obtain a value near what we want by using decaying // probabilities of branching as we go down the tree. // // We are given a target size S and a branch size K (branch size = // expected number of items immediately below each branch). We select // some probability P for each level. // // A single level l is thus expected to hold PlK branches. Each of // those will have P(l+1)K child branches of their own, so there are // PlP(l+1)K² second-level branches. The total branches in the tree is // thus (Σ PlK^l) for l from 0 to infinity. Each level is expected to // hold K items, so the total number of items is simply K times the // number of branches, or (K Σ PlK^l). So we want to find a P sequence // such that (lim (K Σ PlK^l) = S), or more simply, // (lim Σ PlK^l = S/K). // // Let Q be a second probability sequence such that Pl = Ql/K^l. This // changes the formulation to (lim Σ Ql = S/K). The series Σ0.5^(l+1) // converges on 1.0, so we can let Ql = S/K * 0.5^(l+1), and so // Pl = S/K^(l+1) * 0.5^(l+1) = S / (2K) ^ (l+1) // // We don't actually have infinite levels here since we _can_ easily // cap to a fixed max depth, so this will be a minor underestimate. We // also clamp all probabilities to 0.9 to ensure that we can't end up // with levels which are always pure branches, which further // underestimates size. let mut branch_probabilities = Vec::new(); let mut k2 = u64::from(self.expected_branch_size) * 2; for _ in 0..self.depth { branch_probabilities.push(f64::from(self.desired_size) / k2 as f64); k2 = k2.saturating_mul(u64::from(self.expected_branch_size) * 2); } let mut strat = self.base.clone(); while let Some(branch_probability) = branch_probabilities.pop() { let recursed = (self.recurse)(strat.clone()); let recursive_choice = recursed.boxed(); let non_recursive_choice = strat; // Clamp the maximum branch probability to 0.9 to ensure we can // generate non-recursive cases reasonably often. let branch_probability = branch_probability.min(0.9); let (weight_branch, weight_leaf) = float_to_weight(branch_probability); let branch = prop_oneof![ weight_leaf => non_recursive_choice, weight_branch => recursive_choice, ]; strat = branch.boxed(); } strat.new_tree(runner) } } #[cfg(test)] mod test { use std::cmp::max; use super::*; use crate::strategy::just::Just; #[derive(Clone, Debug, PartialEq)] enum Tree { Leaf, Branch(Vec<Tree>), } impl Tree { fn stats(&self) -> (u32, u32) { match *self { Tree::Leaf => (0, 1), Tree::Branch(ref children) => { let mut depth = 0; let mut count = 0; for child in children { let (d, c) = child.stats(); depth = max(d, depth); count += c; } (depth + 1, count + 1) } } } } #[test] fn test_recursive() { let mut max_depth = 0; let mut max_count = 0; let strat = Just(Tree::Leaf).prop_recursive(4, 64, 16, |element| { crate::collection::vec(element, 8..16).prop_map(Tree::Branch) }); let mut runner = TestRunner::deterministic(); for _ in 0..65536 { let tree = strat.new_tree(&mut runner).unwrap().current(); let (depth, count) = tree.stats(); assert!(depth <= 4, "Got depth {}", depth); assert!(count <= 128, "Got count {}", count); max_depth = max(depth, max_depth); max_count = max(count, max_count); } assert!(max_depth >= 3, "Only got max depth {}", max_depth); assert!(max_count > 48, "Only got max count {}", max_count); } #[test] fn simplifies_to_non_recursive() { let strat = Just(Tree::Leaf).prop_recursive(4, 64, 16, |element| { crate::collection::vec(element, 8..16).prop_map(Tree::Branch) }); let mut runner = TestRunner::deterministic(); for _ in 0..256 { let mut value = strat.new_tree(&mut runner).unwrap(); while value.simplify() {} assert_eq!(Tree::Leaf, value.current()); } } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/strategy/shuffle.rs��������������������������������������������������������������0000644�0000000�0000000�00000017730�10461020230�0016153�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017 Jason Lingle // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::{Cell, Vec, VecDeque}; use rand::Rng; use crate::num; use crate::strategy::traits::*; use crate::test_runner::*; /// `Strategy` shuffle adaptor. /// /// See `Strategy::prop_shuffle()`. #[derive(Clone, Debug)] #[must_use = "strategies do nothing unless used"] pub struct Shuffle<S>(pub(super) S); /// A value which can be used with the `prop_shuffle` combinator. /// /// This is not a general-purpose trait. Its methods are prefixed with /// `shuffle_` to avoid the compiler suggesting them or this trait as /// corrections in errors. pub trait Shuffleable { /// Return the length of this collection. fn shuffle_len(&self) -> usize; /// Swap the elements at the given indices. fn shuffle_swap(&mut self, a: usize, b: usize); } macro_rules! shuffleable { ($($t:tt)*) => { impl<T> Shuffleable for $($t)* { fn shuffle_len(&self) -> usize { self.len() } fn shuffle_swap(&mut self, a: usize, b: usize) { self.swap(a, b); } } } } shuffleable!([T]); shuffleable!(Vec<T>); shuffleable!(VecDeque<T>); // Zero- and 1-length arrays aren't usefully shuffleable, but are included to // simplify external macros that may try to use them anyway. shuffleable!([T; 0]); shuffleable!([T; 1]); shuffleable!([T; 2]); shuffleable!([T; 3]); shuffleable!([T; 4]); shuffleable!([T; 5]); shuffleable!([T; 6]); shuffleable!([T; 7]); shuffleable!([T; 8]); shuffleable!([T; 9]); shuffleable!([T; 10]); shuffleable!([T; 11]); shuffleable!([T; 12]); shuffleable!([T; 13]); shuffleable!([T; 14]); shuffleable!([T; 15]); shuffleable!([T; 16]); shuffleable!([T; 17]); shuffleable!([T; 18]); shuffleable!([T; 19]); shuffleable!([T; 20]); shuffleable!([T; 21]); shuffleable!([T; 22]); shuffleable!([T; 23]); shuffleable!([T; 24]); shuffleable!([T; 25]); shuffleable!([T; 26]); shuffleable!([T; 27]); shuffleable!([T; 28]); shuffleable!([T; 29]); shuffleable!([T; 30]); shuffleable!([T; 31]); shuffleable!([T; 32]); impl<S: Strategy> Strategy for Shuffle<S> where S::Value: Shuffleable, { type Tree = ShuffleValueTree<S::Tree>; type Value = S::Value; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { let rng = runner.new_rng(); self.0.new_tree(runner).map(|inner| ShuffleValueTree { inner, rng, dist: Cell::new(None), simplifying_inner: false, }) } } /// `ValueTree` shuffling adaptor. /// /// See `Strategy::prop_shuffle()`. #[derive(Clone, Debug)] pub struct ShuffleValueTree<V> { inner: V, rng: TestRng, /// The maximum amount to move any one element during shuffling. /// /// This is `Cell` since we can't determine the bounds of the value until /// the first call to `current()`. (We technically _could_ by generating a /// value in `new_tree` and checking its length, but that would be a 100% /// slowdown.) dist: Cell<Option<num::usize::BinarySearch>>, /// Whether we've started simplifying `inner`. After this point, we can no /// longer simplify or complicate `dist`. simplifying_inner: bool, } impl<V: ValueTree> ShuffleValueTree<V> where V::Value: Shuffleable, { fn init_dist(&self, dflt: usize) -> usize { if self.dist.get().is_none() { self.dist.set(Some(num::usize::BinarySearch::new(dflt))); } self.dist.get().unwrap().current() } fn force_init_dist(&self) { if self.dist.get().is_none() { self.init_dist(self.current().shuffle_len()); } } } impl<V: ValueTree> ValueTree for ShuffleValueTree<V> where V::Value: Shuffleable, { type Value = V::Value; fn current(&self) -> V::Value { let mut value = self.inner.current(); let len = value.shuffle_len(); // The maximum distance to swap elements. This could be larger than // `value` if `value` has reduced size during shrinking; that's OK, // since we only use this to filter swaps. let max_swap = self.init_dist(len); // If empty collection or all swaps will be filtered out, there's // nothing to shuffle. if 0 == len || 0 == max_swap { return value; } let mut rng = self.rng.clone(); for start_index in 0..len - 1 { // Determine the other index to be swapped, then skip the swap if // it is too far. This ordering is critical, as it ensures that we // generate the same sequence of random numbers every time. let end_index = rng.gen_range(start_index..len); if end_index - start_index <= max_swap { value.shuffle_swap(start_index, end_index); } } value } fn simplify(&mut self) -> bool { if self.simplifying_inner { self.inner.simplify() } else { // Ensure that we've initialised `dist` to *something* to give // consistent non-panicking behaviour even if called in an // unexpected sequence. self.force_init_dist(); if self.dist.get_mut().as_mut().unwrap().simplify() { true } else { self.simplifying_inner = true; self.inner.simplify() } } } fn complicate(&mut self) -> bool { if self.simplifying_inner { self.inner.complicate() } else { self.force_init_dist(); self.dist.get_mut().as_mut().unwrap().complicate() } } } #[cfg(test)] mod test { use std::borrow::ToOwned; use std::collections::HashSet; use std::i32; use super::*; use crate::collection; use crate::strategy::just::Just; static VALUES: &'static [i32] = &[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ]; #[test] fn generates_different_permutations() { let mut runner = TestRunner::default(); let mut seen = HashSet::<Vec<i32>>::new(); let input = Just(VALUES.to_owned()).prop_shuffle(); for _ in 0..1024 { let mut value = input.new_tree(&mut runner).unwrap().current(); assert!( seen.insert(value.clone()), "Value {:?} generated more than once", value ); value.sort(); assert_eq!(VALUES, &value[..]); } } #[test] fn simplify_reduces_shuffle_amount() { let mut runner = TestRunner::default(); let input = Just(VALUES.to_owned()).prop_shuffle(); for _ in 0..1024 { let mut value = input.new_tree(&mut runner).unwrap(); let mut prev_dist = i32::MAX; loop { let v = value.current(); // Compute the "shuffle distance" by summing the absolute // distance of each element's displacement. let mut dist = 0; for (ix, &nominal) in v.iter().enumerate() { dist += (nominal - ix as i32).abs(); } assert!( dist <= prev_dist, "dist = {}, prev_dist = {}", dist, prev_dist ); prev_dist = dist; if !value.simplify() { break; } } // When fully simplified, the result is in the original order. assert_eq!(0, prev_dist); } } #[test] fn simplify_complicate_contract_upheld() { check_strategy_sanity( collection::vec(0i32..1000, 5..10).prop_shuffle(), None, ); } } ����������������������������������������proptest-1.6.0/src/strategy/statics.rs��������������������������������������������������������������0000644�0000000�0000000�00000016232�10461020230�0016165�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017 Jason Lingle // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Modified versions of the normal strategy combinators which take specialised //! traits instead of normal functions. //! //! This entire module is strictly a workaround until //! <https://github.com/rust-lang/rfcs/pull/1522> and //! <https://github.com/rust-lang/rfcs/pull/2071> are available in stable. It //! allows naming types built on the combinators without resorting to dynamic //! dispatch or causing `Arc` to allocate space for a function pointer. //! //! External code is discouraged from using this module directly. It is //! deliberately not exposed in a convenient way (i.e., via the `Strategy` //! trait itself), but is nonetheless exposed since external trait implementors //! may face the same issues. //! //! **This module is subject to removal at some point after the language //! features linked above become stable.** use crate::std_facade::fmt; use crate::strategy::traits::*; use crate::test_runner::*; //============================================================================== // Filter //============================================================================== /// Essentially `Fn (&T) -> bool`. pub trait FilterFn<T> { /// Test whether `t` passes the filter. fn apply(&self, t: &T) -> bool; } /// Static version of `strategy::Filter`. #[derive(Clone)] #[must_use = "strategies do nothing unless used"] pub struct Filter<S, F> { source: S, whence: Reason, fun: F, } impl<S, F> Filter<S, F> { /// Adapt strategy `source` to reject values which do not pass `filter`, /// using `whence` as the reported reason/location. pub fn new(source: S, whence: Reason, filter: F) -> Self { // NOTE: We don't use universal quantification R: Into<Reason> // since the module is not conveniently exposed. Filter { source, whence, fun: filter, } } } impl<S: fmt::Debug, F> fmt::Debug for Filter<S, F> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Filter") .field("source", &self.source) .field("whence", &self.whence) .field("fun", &"<function>") .finish() } } impl<S: Strategy, F: FilterFn<S::Value> + Clone> Strategy for Filter<S, F> { type Tree = Filter<S::Tree, F>; type Value = S::Value; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { loop { let val = self.source.new_tree(runner)?; if !self.fun.apply(&val.current()) { runner.reject_local(self.whence.clone())?; } else { return Ok(Filter { source: val, whence: "unused".into(), fun: self.fun.clone(), }); } } } } impl<S: ValueTree, F: FilterFn<S::Value>> Filter<S, F> { fn ensure_acceptable(&mut self) { while !self.fun.apply(&self.source.current()) { if !self.source.complicate() { panic!( "Unable to complicate filtered strategy \ back into acceptable value" ); } } } } impl<S: ValueTree, F: FilterFn<S::Value>> ValueTree for Filter<S, F> { type Value = S::Value; fn current(&self) -> S::Value { self.source.current() } fn simplify(&mut self) -> bool { if self.source.simplify() { self.ensure_acceptable(); true } else { false } } fn complicate(&mut self) -> bool { if self.source.complicate() { self.ensure_acceptable(); true } else { false } } } //============================================================================== // Map //============================================================================== /// Essentially `Fn (T) -> Output`. pub trait MapFn<T> { #[allow(missing_docs)] type Output: fmt::Debug; /// Map `T` to `Output`. fn apply(&self, t: T) -> Self::Output; } /// Static version of `strategy::Map`. #[derive(Clone)] #[must_use = "strategies do nothing unless used"] pub struct Map<S, F> { source: S, fun: F, } impl<S, F> Map<S, F> { /// Adapt strategy `source` by applying `fun` to values it produces. pub fn new(source: S, fun: F) -> Self { Map { source, fun } } } impl<S: fmt::Debug, F> fmt::Debug for Map<S, F> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Map") .field("source", &self.source) .field("fun", &"<function>") .finish() } } impl<S: Strategy, F: Clone + MapFn<S::Value>> Strategy for Map<S, F> { type Tree = Map<S::Tree, F>; type Value = F::Output; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { self.source.new_tree(runner).map(|v| Map { source: v, fun: self.fun.clone(), }) } } impl<S: ValueTree, F: MapFn<S::Value>> ValueTree for Map<S, F> { type Value = F::Output; fn current(&self) -> F::Output { self.fun.apply(self.source.current()) } fn simplify(&mut self) -> bool { self.source.simplify() } fn complicate(&mut self) -> bool { self.source.complicate() } } impl<I, O: fmt::Debug> MapFn<I> for fn(I) -> O { type Output = O; fn apply(&self, x: I) -> Self::Output { self(x) } } pub(crate) fn static_map<S: Strategy, O: fmt::Debug>( strat: S, fun: fn(S::Value) -> O, ) -> Map<S, fn(S::Value) -> O> { Map::new(strat, fun) } //============================================================================== // Tests //============================================================================== #[cfg(test)] mod test { use super::*; #[test] fn test_static_filter() { #[derive(Clone, Copy, Debug)] struct MyFilter; impl FilterFn<i32> for MyFilter { fn apply(&self, &v: &i32) -> bool { 0 == v % 3 } } let input = Filter::new(0..256, "%3".into(), MyFilter); for _ in 0..256 { let mut runner = TestRunner::default(); let mut case = input.new_tree(&mut runner).unwrap(); assert!(0 == case.current() % 3); while case.simplify() { assert!(0 == case.current() % 3); } assert!(0 == case.current() % 3); } } #[test] fn test_static_map() { #[derive(Clone, Copy, Debug)] struct MyMap; impl MapFn<i32> for MyMap { type Output = i32; fn apply(&self, v: i32) -> i32 { v * 2 } } let input = Map::new(0..10, MyMap); TestRunner::default() .run(&input, |v| { assert!(0 == v % 2); Ok(()) }) .unwrap(); } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/strategy/traits.rs���������������������������������������������������������������0000644�0000000�0000000�00000114150�10461020230�0016017�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. 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<S> = Result<<S as Strategy>::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<Value = Self::Value>; /// 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<Value = MyType>`. 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<Self>; /// 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: fmt::Debug, F: Fn(Self::Value) -> O>( self, fun: F, ) -> Map<Self, F> where Self: Sized, { Map { source: self, fun: Arc::new(fun), } } /// Returns a strategy which produces values of type `O` by transforming /// `Self` with `Into<O>`. /// /// 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<O: fmt::Debug>(self) -> MapInto<Self, O> where Self: Sized, Self::Value: Into<O>, { 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: fmt::Debug, F: Fn(Self::Value, TestRng) -> O>( self, fun: F, ) -> Perturb<Self, F> 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: Strategy, F: Fn(Self::Value) -> S>( self, fun: F, ) -> Flatten<Map<Self, F>> 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: Strategy, F: Fn(Self::Value) -> S>( self, fun: F, ) -> IndFlatten<Map<Self, F>> 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. fn prop_ind_flat_map2<S: Strategy, F: Fn(Self::Value) -> S>( self, fun: F, ) -> IndFlattenMap<Self, F> 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<R: Into<Reason>, F: Fn(&Self::Value) -> bool>( self, whence: R, fun: F, ) -> Filter<Self, F> 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<F: Fn(Self::Value) -> Option<O>, O: fmt::Debug>( self, whence: impl Into<Reason>, fun: F, ) -> FilterMap<Self, F> 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<Self> 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<JsonNode>), /// Map(HashMap<String, JsonNode>), /// } /// /// # 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<Value = Self::Value> + 'static, F: Fn(BoxedStrategy<Self::Value>) -> R, >( self, depth: u32, desired_size: u32, expected_branch_size: u32, recurse: F, ) -> Recursive<Self::Value, F> 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<u32>) -> 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<Self> 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<Self::Value> 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<Self::Value> 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<Self> 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>(T); impl<T: Strategy> Strategy for NoShrink<T> { type Tree = NoShrink<T::Tree>; type Value = T::Value; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { self.0.new_tree(runner).map(NoShrink) } } impl<T: ValueTree> ValueTree for NoShrink<T> { 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> { (**self).new_tree(runner) } } }; } proxy_strategy!(Box<S>); proxy_strategy!(&'a S, 'a); proxy_strategy!(&'a mut S, 'a); proxy_strategy!(Rc<S>); proxy_strategy!(Arc<S>); impl<T: ValueTree + ?Sized> ValueTree for Box<T> { 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<T> = Box<dyn ValueTree<Value = T>>; /// 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<T>(Arc<dyn Strategy<Value = T, Tree = BoxedVT<T>>>); /// 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<T>( Arc<dyn Strategy<Value = T, Tree = BoxedVT<T>> + Sync + Send>, ); impl<T> Clone for BoxedStrategy<T> { fn clone(&self) -> Self { BoxedStrategy(Arc::clone(&self.0)) } } impl<T> Clone for SBoxedStrategy<T> { fn clone(&self) -> Self { SBoxedStrategy(Arc::clone(&self.0)) } } impl<T: fmt::Debug> Strategy for BoxedStrategy<T> { type Tree = BoxedVT<T>; type Value = T; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { self.0.new_tree(runner) } // Optimization: Don't rebox the strategy. fn boxed(self) -> BoxedStrategy<Self::Value> where Self: Sized + 'static, { self } } impl<T: fmt::Debug> Strategy for SBoxedStrategy<T> { type Tree = BoxedVT<T>; type Value = T; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { self.0.new_tree(runner) } // Optimization: Don't rebox the strategy. fn sboxed(self) -> SBoxedStrategy<Self::Value> where Self: Sized + Send + Sync + 'static, { self } fn boxed(self) -> BoxedStrategy<Self::Value> where Self: Sized + 'static, { BoxedStrategy(self.0) } } #[derive(Debug)] struct BoxedStrategyWrapper<T>(T); impl<T: Strategy> Strategy for BoxedStrategyWrapper<T> where T::Tree: 'static, { type Tree = Box<dyn ValueTree<Value = T::Value>>; type Value = T::Value; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { 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<S: Strategy>( strategy: S, options: Option<CheckStrategySanityOptions>, ) 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 ); } } } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/strategy/unions.rs���������������������������������������������������������������0000644�0000000�0000000�00000055011�10461020230�0016024�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017 Jason Lingle // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::{fmt, Arc, Vec}; use core::cmp::{max, min}; use core::u32; #[cfg(not(feature = "std"))] use num_traits::float::FloatCore; use crate::num::sample_uniform; use crate::strategy::{lazy::LazyValueTree, traits::*}; use crate::test_runner::*; /// A **relative** `weight` of a particular `Strategy` corresponding to `T` /// coupled with `T` itself. The weight is currently given in `u32`. pub type W<T> = (u32, T); /// A **relative** `weight` of a particular `Strategy` corresponding to `T` /// coupled with `Arc<T>`. The weight is currently given in `u32`. pub type WA<T> = (u32, Arc<T>); /// A `Strategy` which picks from one of several delegate `Strategy`s. /// /// See `Strategy::prop_union()`. #[derive(Clone, Debug)] #[must_use = "strategies do nothing unless used"] pub struct Union<T: Strategy> { // In principle T could be any `Strategy + Clone`, but that isn't possible // for BC reasons with the 0.9 series. options: Vec<WA<T>>, } impl<T: Strategy> Union<T> { /// Create a strategy which selects uniformly from the given delegate /// strategies. /// /// When shrinking, after maximal simplification of the chosen element, the /// strategy will move to earlier options and continue simplification with /// those. /// /// ## Panics /// /// Panics if `options` is empty. pub fn new(options: impl IntoIterator<Item = T>) -> Self { let options: Vec<WA<T>> = options.into_iter().map(|v| (1, Arc::new(v))).collect(); assert!(!options.is_empty()); Self { options } } pub(crate) fn try_new<E>( it: impl Iterator<Item = Result<T, E>>, ) -> Result<Self, E> { let options: Vec<WA<T>> = it .map(|r| r.map(|v| (1, Arc::new(v)))) .collect::<Result<_, _>>()?; assert!(!options.is_empty()); Ok(Self { options }) } /// Create a strategy which selects from the given delegate strategies. /// /// Each strategy is assigned a non-zero weight which determines how /// frequently that strategy is chosen. For example, a strategy with a /// weight of 2 will be chosen twice as frequently as one with a weight of /// 1\. /// /// ## Panics /// /// Panics if `options` is empty or any element has a weight of 0. /// /// Panics if the sum of the weights overflows a `u32`. pub fn new_weighted(options: Vec<W<T>>) -> Self { assert!(!options.is_empty()); assert!( !options.iter().any(|&(w, _)| 0 == w), "Union option has a weight of 0" ); assert!( options.iter().map(|&(w, _)| u64::from(w)).sum::<u64>() <= u64::from(u32::MAX), "Union weights overflow u32" ); let options = options.into_iter().map(|(w, v)| (w, Arc::new(v))).collect(); Self { options } } /// Add `other` as an additional alternate strategy with weight 1. pub fn or(mut self, other: T) -> Self { self.options.push((1, Arc::new(other))); self } } fn pick_weighted<I: Iterator<Item = u32>>( runner: &mut TestRunner, weights1: I, weights2: I, ) -> usize { let sum = weights1.map(u64::from).sum(); let weighted_pick = sample_uniform(runner, 0, sum); weights2 .scan(0u64, |state, w| { *state += u64::from(w); Some(*state) }) .filter(|&v| v <= weighted_pick) .count() } impl<T: Strategy> Strategy for Union<T> { type Tree = UnionValueTree<T>; type Value = T::Value; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { fn extract_weight<V>(&(w, _): &WA<V>) -> u32 { w } let pick = pick_weighted( runner, self.options.iter().map(extract_weight::<T>), self.options.iter().map(extract_weight::<T>), ); let mut options = Vec::with_capacity(pick); // Delay initialization for all options less than pick. for option in &self.options[0..pick] { options.push(LazyValueTree::new(Arc::clone(&option.1), runner)); } // Initialize the tree at pick so at least one value is available. Note // that if generation for the value at pick fails, the entire strategy // will fail. This seems like the right call. options.push(LazyValueTree::new_initialized( self.options[pick].1.new_tree(runner)?, )); Ok(UnionValueTree { options, pick, min_pick: 0, prev_pick: None, }) } } macro_rules! access_vec { ([$($muta:tt)*] $dst:ident = $this:expr, $ix:expr, $body:block) => {{ let $dst = &$($muta)* $this.options[$ix]; $body }} } /// `ValueTree` corresponding to `Union`. pub struct UnionValueTree<T: Strategy> { options: Vec<LazyValueTree<T>>, // This struct maintains the invariant that between function calls, // `pick` and `prev_pick` (if Some) always point to initialized // trees. pick: usize, min_pick: usize, prev_pick: Option<usize>, } macro_rules! lazy_union_value_tree_body { ($typ:ty, $access:ident) => { type Value = $typ; fn current(&self) -> Self::Value { $access!([] opt = self, self.pick, { opt.as_inner().unwrap_or_else(|| panic!( "value tree at self.pick = {} must be initialized", self.pick, ) ).current() }) } fn simplify(&mut self) -> bool { let orig_pick = self.pick; if $access!([mut] opt = self, orig_pick, { opt.as_inner_mut().unwrap_or_else(|| panic!( "value tree at self.pick = {} must be initialized", orig_pick, ) ).simplify() }) { self.prev_pick = None; return true; } assert!( self.pick >= self.min_pick, "self.pick = {} should never go below self.min_pick = {}", self.pick, self.min_pick, ); if self.pick == self.min_pick { // No more simplification to be done. return false; } // self.prev_pick is always a valid pick. self.prev_pick = Some(self.pick); let mut next_pick = self.pick; while next_pick > self.min_pick { next_pick -= 1; let initialized = $access!([mut] opt = self, next_pick, { opt.maybe_init(); opt.is_initialized() }); if initialized { // next_pick was correctly initialized above. self.pick = next_pick; return true; } } false } fn complicate(&mut self) -> bool { if let Some(pick) = self.prev_pick { // simplify() ensures that the previous pick was initialized. self.pick = pick; self.min_pick = pick; self.prev_pick = None; true } else { let pick = self.pick; $access!([mut] opt = self, pick, { opt.as_inner_mut().unwrap_or_else(|| panic!( "value tree at self.pick = {} must be initialized", pick, ) ).complicate() }) } } } } impl<T: Strategy> ValueTree for UnionValueTree<T> { lazy_union_value_tree_body!(T::Value, access_vec); } impl<T: Strategy> Clone for UnionValueTree<T> where T::Tree: Clone, { fn clone(&self) -> Self { Self { options: self.options.clone(), pick: self.pick, min_pick: self.min_pick, prev_pick: self.prev_pick, } } } impl<T: Strategy> fmt::Debug for UnionValueTree<T> where T::Tree: fmt::Debug, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("UnionValueTree") .field("options", &self.options) .field("pick", &self.pick) .field("min_pick", &self.min_pick) .field("prev_pick", &self.prev_pick) .finish() } } macro_rules! def_access_tuple { ($b:tt $name:ident, $($n:tt)*) => { macro_rules! $name { ([$b($b muta:tt)*] $b dst:ident = $b this:expr, $b ix:expr, $b body:block) => { match $b ix { 0 => { let $b dst = &$b($b muta)* $b this.options.0; $b body }, $( $n => { if let Some(ref $b($b muta)* $b dst) = $b this.options.$n { $b body } else { panic!("TupleUnion tried to access \ uninitialised slot {}", $n) } }, )* _ => panic!("TupleUnion tried to access out-of-range \ slot {}", $b ix), } } } } } def_access_tuple!($ access_tuple2, 1); def_access_tuple!($ access_tuple3, 1 2); def_access_tuple!($ access_tuple4, 1 2 3); def_access_tuple!($ access_tuple5, 1 2 3 4); def_access_tuple!($ access_tuple6, 1 2 3 4 5); def_access_tuple!($ access_tuple7, 1 2 3 4 5 6); def_access_tuple!($ access_tuple8, 1 2 3 4 5 6 7); def_access_tuple!($ access_tuple9, 1 2 3 4 5 6 7 8); def_access_tuple!($ access_tupleA, 1 2 3 4 5 6 7 8 9); /// Similar to `Union`, but internally uses a tuple to hold the strategies. /// /// This allows better performance than vanilla `Union` since one does not need /// to resort to boxing and dynamic dispatch to handle heterogeneous /// strategies. /// /// The difference between this and `TupleUnion` is that with this, value trees /// for variants that aren't picked at first are generated lazily. #[must_use = "strategies do nothing unless used"] #[derive(Clone, Copy, Debug)] pub struct TupleUnion<T>(T); impl<T> TupleUnion<T> { /// Wrap `tuple` in a `TupleUnion`. /// /// The struct definition allows any `T` for `tuple`, but to be useful, it /// must be a 2- to 10-tuple of `(u32, Arc<impl Strategy>)` pairs where all /// strategies ultimately produce the same value. Each `u32` indicates the /// relative weight of its corresponding strategy. /// You may use `WA<S>` as an alias for `(u32, Arc<S>)`. /// /// Using this constructor directly is discouraged; prefer to use /// `prop_oneof!` since it is generally clearer. pub fn new(tuple: T) -> Self { TupleUnion(tuple) } } macro_rules! tuple_union { ($($gen:ident $ix:tt)*) => { impl<A : Strategy, $($gen: Strategy<Value = A::Value>),*> Strategy for TupleUnion<(WA<A>, $(WA<$gen>),*)> { type Tree = TupleUnionValueTree< (LazyValueTree<A>, $(Option<LazyValueTree<$gen>>),*)>; type Value = A::Value; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { let weights = [((self.0).0).0, $(((self.0).$ix).0),*]; let pick = pick_weighted(runner, weights.iter().cloned(), weights.iter().cloned()); Ok(TupleUnionValueTree { options: ( if 0 == pick { LazyValueTree::new_initialized( ((self.0).0).1.new_tree(runner)?) } else { LazyValueTree::new( Arc::clone(&((self.0).0).1), runner) }, $( if $ix == pick { Some(LazyValueTree::new_initialized( ((self.0).$ix).1.new_tree(runner)?)) } else if $ix < pick { Some(LazyValueTree::new( Arc::clone(&((self.0).$ix).1), runner)) } else { None }),*), pick: pick, min_pick: 0, prev_pick: None, }) } } } } tuple_union!(B 1); tuple_union!(B 1 C 2); tuple_union!(B 1 C 2 D 3); tuple_union!(B 1 C 2 D 3 E 4); tuple_union!(B 1 C 2 D 3 E 4 F 5); tuple_union!(B 1 C 2 D 3 E 4 F 5 G 6); tuple_union!(B 1 C 2 D 3 E 4 F 5 G 6 H 7); tuple_union!(B 1 C 2 D 3 E 4 F 5 G 6 H 7 I 8); tuple_union!(B 1 C 2 D 3 E 4 F 5 G 6 H 7 I 8 J 9); /// `ValueTree` type produced by `TupleUnion`. #[derive(Clone, Copy, Debug)] pub struct TupleUnionValueTree<T> { options: T, pick: usize, min_pick: usize, prev_pick: Option<usize>, } macro_rules! value_tree_tuple { ($access:ident, $($gen:ident)*) => { impl<A : Strategy, $($gen: Strategy<Value = A::Value>),*> ValueTree for TupleUnionValueTree< (LazyValueTree<A>, $(Option<LazyValueTree<$gen>>),*) > { lazy_union_value_tree_body!(A::Value, $access); } } } value_tree_tuple!(access_tuple2, B); value_tree_tuple!(access_tuple3, B C); value_tree_tuple!(access_tuple4, B C D); value_tree_tuple!(access_tuple5, B C D E); value_tree_tuple!(access_tuple6, B C D E F); value_tree_tuple!(access_tuple7, B C D E F G); value_tree_tuple!(access_tuple8, B C D E F G H); value_tree_tuple!(access_tuple9, B C D E F G H I); value_tree_tuple!(access_tupleA, B C D E F G H I J); const WEIGHT_BASE: u32 = 0x8000_0000; /// Convert a floating-point weight in the range (0.0,1.0) to a pair of weights /// that can be used with `Union` and similar. /// /// The first return value is the weight corresponding to `f`; the second /// return value is the weight corresponding to `1.0 - f`. /// /// This call does not make any guarantees as to what range of weights it may /// produce, except that adding the two return values will never overflow a /// `u32`. As such, it is generally not meaningful to combine any other weights /// with the two returned. /// /// ## Panics /// /// Panics if `f` is not a real number between 0.0 and 1.0, both exclusive. pub fn float_to_weight(f: f64) -> (u32, u32) { assert!(f > 0.0 && f < 1.0, "Invalid probability: {}", f); // Clamp to 1..WEIGHT_BASE-1 so that we never produce a weight of 0. let pos = max( 1, min(WEIGHT_BASE - 1, (f * f64::from(WEIGHT_BASE)).round() as u32), ); let neg = WEIGHT_BASE - pos; (pos, neg) } #[cfg(test)] mod test { use super::*; use crate::strategy::just::Just; // FIXME(2018-06-01): figure out a way to run this test on no_std. // The problem is that the default seed is fixed and does not produce // enough passed tests. We need some universal source of non-determinism // for the seed, which is unlikely. #[cfg(feature = "std")] #[test] fn test_union() { let input = (10u32..20u32).prop_union(30u32..40u32); // Expect that 25% of cases pass (left input happens to be < 15, and // left is chosen as initial value). Of the 75% that fail, 50% should // converge to 15 and 50% to 30 (the latter because the left is beneath // the passing threshold). let mut passed = 0; let mut converged_low = 0; let mut converged_high = 0; let mut runner = TestRunner::deterministic(); for _ in 0..256 { let case = input.new_tree(&mut runner).unwrap(); let result = runner.run_one(case, |v| { prop_assert!(v < 15); Ok(()) }); match result { Ok(true) => passed += 1, Err(TestError::Fail(_, 15)) => converged_low += 1, Err(TestError::Fail(_, 30)) => converged_high += 1, e => panic!("Unexpected result: {:?}", e), } } assert!(passed >= 32 && passed <= 96, "Bad passed count: {}", passed); assert!( converged_low >= 32 && converged_low <= 160, "Bad converged_low count: {}", converged_low ); assert!( converged_high >= 32 && converged_high <= 160, "Bad converged_high count: {}", converged_high ); } #[test] fn test_union_weighted() { let input = Union::new_weighted(vec![ (1, Just(0usize)), (2, Just(1usize)), (1, Just(2usize)), ]); let mut counts = [0, 0, 0]; let mut runner = TestRunner::deterministic(); for _ in 0..65536 { counts[input.new_tree(&mut runner).unwrap().current()] += 1; } println!("{:?}", counts); assert!(counts[0] > 0); assert!(counts[2] > 0); assert!(counts[1] > counts[0] * 3 / 2); assert!(counts[1] > counts[2] * 3 / 2); } #[test] fn test_union_sanity() { check_strategy_sanity( Union::new_weighted(vec![ (1, 0i32..100), (2, 200i32..300), (1, 400i32..500), ]), None, ); } // FIXME(2018-06-01): See note on `test_union`. #[cfg(feature = "std")] #[test] fn test_tuple_union() { let input = TupleUnion::new(( (1, Arc::new(10u32..20u32)), (1, Arc::new(30u32..40u32)), )); // Expect that 25% of cases pass (left input happens to be < 15, and // left is chosen as initial value). Of the 75% that fail, 50% should // converge to 15 and 50% to 30 (the latter because the left is beneath // the passing threshold). let mut passed = 0; let mut converged_low = 0; let mut converged_high = 0; let mut runner = TestRunner::deterministic(); for _ in 0..256 { let case = input.new_tree(&mut runner).unwrap(); let result = runner.run_one(case, |v| { prop_assert!(v < 15); Ok(()) }); match result { Ok(true) => passed += 1, Err(TestError::Fail(_, 15)) => converged_low += 1, Err(TestError::Fail(_, 30)) => converged_high += 1, e => panic!("Unexpected result: {:?}", e), } } assert!(passed >= 32 && passed <= 96, "Bad passed count: {}", passed); assert!( converged_low >= 32 && converged_low <= 160, "Bad converged_low count: {}", converged_low ); assert!( converged_high >= 32 && converged_high <= 160, "Bad converged_high count: {}", converged_high ); } #[test] fn test_tuple_union_weighting() { let input = TupleUnion::new(( (1, Arc::new(Just(0usize))), (2, Arc::new(Just(1usize))), (1, Arc::new(Just(2usize))), )); let mut counts = [0, 0, 0]; let mut runner = TestRunner::deterministic(); for _ in 0..65536 { counts[input.new_tree(&mut runner).unwrap().current()] += 1; } println!("{:?}", counts); assert!(counts[0] > 0); assert!(counts[2] > 0); assert!(counts[1] > counts[0] * 3 / 2); assert!(counts[1] > counts[2] * 3 / 2); } #[test] fn test_tuple_union_all_sizes() { let mut runner = TestRunner::deterministic(); let r = Arc::new(1i32..10); macro_rules! test { ($($part:expr),*) => {{ let input = TupleUnion::new(( $((1, $part.clone())),*, (1, Arc::new(Just(0i32))) )); let mut pass = false; for _ in 0..1024 { if 0 == input.new_tree(&mut runner).unwrap().current() { pass = true; break; } } assert!(pass); }} } test!(r); // 2 test!(r, r); // 3 test!(r, r, r); // 4 test!(r, r, r, r); // 5 test!(r, r, r, r, r); // 6 test!(r, r, r, r, r, r); // 7 test!(r, r, r, r, r, r, r); // 8 test!(r, r, r, r, r, r, r, r); // 9 test!(r, r, r, r, r, r, r, r, r); // 10 } #[test] fn test_tuple_union_sanity() { check_strategy_sanity( TupleUnion::new(( (1, Arc::new(0i32..100i32)), (1, Arc::new(200i32..1000i32)), (1, Arc::new(2000i32..3000i32)), )), None, ); } /// Test that unions work even if local filtering causes errors. #[test] fn test_filter_union_sanity() { let filter_strategy = (0u32..256).prop_filter("!%5", |&v| 0 != v % 5); check_strategy_sanity( Union::new(vec![filter_strategy; 8]), Some(filter_sanity_options()), ); } /// Test that tuple unions work even if local filtering causes errors. #[test] fn test_filter_tuple_union_sanity() { let filter_strategy = (0u32..256).prop_filter("!%5", |&v| 0 != v % 5); check_strategy_sanity( TupleUnion::new(( (1, Arc::new(filter_strategy.clone())), (1, Arc::new(filter_strategy.clone())), (1, Arc::new(filter_strategy.clone())), (1, Arc::new(filter_strategy.clone())), )), Some(filter_sanity_options()), ); } fn filter_sanity_options() -> CheckStrategySanityOptions { CheckStrategySanityOptions { // Due to internal rejection sampling, `simplify()` can // converge back to what `complicate()` would do. strict_complicate_after_simplify: false, // Make failed filters return errors to test edge cases. error_on_local_rejects: true, ..CheckStrategySanityOptions::default() } } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/string.rs������������������������������������������������������������������������0000644�0000000�0000000�00000045351�10461020230�0014163�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017 Jason Lingle // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Strategies for generating strings and byte strings from regular //! expressions. use crate::std_facade::{Box, Cow, String, ToOwned, Vec}; use core::fmt; use core::mem; use core::ops::RangeInclusive; use core::u32; use regex_syntax::hir::{self, Hir, HirKind::*, Repetition}; use regex_syntax::{Error as ParseError, ParserBuilder}; use crate::bool; use crate::char; use crate::collection::{size_range, vec, SizeRange}; use crate::strategy::*; use crate::test_runner::*; /// Wraps the regex that forms the `Strategy` for `String` so that a sensible /// `Default` can be given. The default is a string of non-control characters. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct StringParam(&'static str); impl From<StringParam> for &'static str { fn from(x: StringParam) -> Self { x.0 } } impl From<&'static str> for StringParam { fn from(x: &'static str) -> Self { StringParam(x) } } impl Default for StringParam { fn default() -> Self { StringParam("\\PC*") } } /// Errors which may occur when preparing a regular expression for use with /// string generation. #[derive(Debug)] pub enum Error { /// The string passed as the regex was not syntactically valid. RegexSyntax(ParseError), /// The regex was syntactically valid, but contains elements not /// supported by proptest. UnsupportedRegex(&'static str), } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Error::RegexSyntax(err) => write!(f, "{}", err), Error::UnsupportedRegex(message) => write!(f, "{}", message), } } } impl std::error::Error for Error { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { Error::RegexSyntax(err) => Some(err), Error::UnsupportedRegex(_) => None, } } } impl From<ParseError> for Error { fn from(err: ParseError) -> Error { Error::RegexSyntax(err) } } opaque_strategy_wrapper! { /// Strategy which generates values (i.e., `String` or `Vec<u8>`) matching /// a regular expression. /// /// Created by various functions in this module. #[derive(Debug)] pub struct RegexGeneratorStrategy[<T>][where T : fmt::Debug] (SBoxedStrategy<T>) -> RegexGeneratorValueTree<T>; /// `ValueTree` corresponding to `RegexGeneratorStrategy`. pub struct RegexGeneratorValueTree[<T>][where T : fmt::Debug] (Box<dyn ValueTree<Value = T>>) -> T; } impl Strategy for str { type Tree = RegexGeneratorValueTree<String>; type Value = String; fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { string_regex(self).unwrap().new_tree(runner) } } type ParseResult<T> = Result<RegexGeneratorStrategy<T>, Error>; #[doc(hidden)] /// A type which knows how to produce a `Strategy` from a regular expression /// generating the type. /// /// This trait exists for the benefit of `#[proptest(regex = "...")]`. /// It is semver exempt, so use at your own risk. /// If you found a use for the trait beyond `Vec<u8>` and `String`, /// please file an issue at https://github.com/proptest-rs/proptest. pub trait StrategyFromRegex: Sized + fmt::Debug { type Strategy: Strategy<Value = Self>; /// Produce a strategy for `Self` from the `regex`. fn from_regex(regex: &str) -> Self::Strategy; } impl StrategyFromRegex for String { type Strategy = RegexGeneratorStrategy<Self>; fn from_regex(regex: &str) -> Self::Strategy { string_regex(regex).unwrap() } } impl StrategyFromRegex for Vec<u8> { type Strategy = RegexGeneratorStrategy<Self>; fn from_regex(regex: &str) -> Self::Strategy { bytes_regex(regex).unwrap() } } /// Creates a strategy which generates strings matching the given regular /// expression. /// /// If you don't need error handling and aren't limited by setup time, it is /// also possible to directly use a `&str` as a strategy with the same effect. pub fn string_regex(regex: &str) -> ParseResult<String> { let hir = ParserBuilder::new().build().parse(regex)?; string_regex_parsed(&hir) } /// Like `string_regex()`, but allows providing a pre-parsed expression. pub fn string_regex_parsed(expr: &Hir) -> ParseResult<String> { bytes_regex_parsed(expr) .map(|v| { v.prop_map(|bytes| { String::from_utf8(bytes).expect("non-utf8 string") }) .sboxed() }) .map(RegexGeneratorStrategy) } /// Creates a strategy which generates byte strings matching the given regular /// expression. /// /// By default, the byte strings generated by this strategy _will_ be valid /// UTF-8. If you wish to generate byte strings that aren't (necessarily) /// valid UTF-8, wrap your regex (or some subsection of it) in `(?-u: ... )`. /// You may want to turn on the `s` flag as well (`(?s-u: ... )`) so that `.` /// will generate newline characters (byte value `0x0A`). See the /// [`regex` crate's documentation](https://docs.rs/regex/*/regex/#opt-out-of-unicode-support) /// for more information. pub fn bytes_regex(regex: &str) -> ParseResult<Vec<u8>> { let hir = ParserBuilder::new() .utf8(false) .build() .parse(regex)?; bytes_regex_parsed(&hir) } /// Like `bytes_regex()`, but allows providing a pre-parsed expression. pub fn bytes_regex_parsed(expr: &Hir) -> ParseResult<Vec<u8>> { match expr.kind() { Empty => Ok(Just(vec![]).sboxed()), Literal(lit) => Ok(Just(lit.0.to_vec()).sboxed()), Class(class) => Ok(match class { hir::Class::Unicode(class) => { unicode_class_strategy(class).prop_map(to_bytes).sboxed() } hir::Class::Bytes(class) => { let subs = class.iter().map(|r| r.start()..=r.end()); Union::new(subs).prop_map(|b| vec![b]).sboxed() } }), Repetition(rep) => { Ok(vec(bytes_regex_parsed(&rep.sub)?, to_range(rep)?) .prop_map(|parts| parts.concat()) .sboxed()) } Capture(capture) => bytes_regex_parsed(&capture.sub).map(|v| v.0), Concat(subs) => { let subs = ConcatIter { iter: subs.iter(), buf: vec![], next: None, }; let ext = |(mut lhs, rhs): (Vec<_>, _)| { lhs.extend(rhs); lhs }; Ok(subs .fold(Ok(None), |accum: Result<_, Error>, rhs| { Ok(match accum? { None => Some(rhs?.sboxed()), Some(accum) => { Some((accum, rhs?).prop_map(ext).sboxed()) } }) })? .unwrap_or_else(|| Just(vec![]).sboxed())) } Alternation(subs) => { Ok(Union::try_new(subs.iter().map(bytes_regex_parsed))?.sboxed()) } Look(_) => unsupported( "anchors/boundaries not supported for string generation", ), } .map(RegexGeneratorStrategy) } fn unicode_class_strategy( class: &hir::ClassUnicode, ) -> char::CharStrategy<'static> { static NONL_RANGES: &[RangeInclusive<char>] = &[ '\x00'..='\x09', // Multiple instances of the latter range to partially make up // for the bias of having such a tiny range in the control // characters. '\x0B'..=::core::char::MAX, '\x0B'..=::core::char::MAX, '\x0B'..=::core::char::MAX, '\x0B'..=::core::char::MAX, '\x0B'..=::core::char::MAX, ]; let dotnnl = |x: &hir::ClassUnicodeRange, y: &hir::ClassUnicodeRange| { x.start() == '\0' && x.end() == '\x09' && y.start() == '\x0B' && y.end() == '\u{10FFFF}' }; char::ranges(match class.ranges() { [x, y] if dotnnl(x, y) || dotnnl(y, x) => Cow::Borrowed(NONL_RANGES), _ => Cow::Owned(class.iter().map(|r| r.start()..=r.end()).collect()), }) } struct ConcatIter<'a, I> { buf: Vec<u8>, iter: I, next: Option<&'a Hir>, } fn flush_lit_buf<I>( it: &mut ConcatIter<'_, I>, ) -> Option<ParseResult<Vec<u8>>> { Some(Ok(RegexGeneratorStrategy( Just(mem::replace(&mut it.buf, vec![])).sboxed(), ))) } impl<'a, I: Iterator<Item = &'a Hir>> Iterator for ConcatIter<'a, I> { type Item = ParseResult<Vec<u8>>; fn next(&mut self) -> Option<Self::Item> { // A left-over node, process it first: if let Some(next) = self.next.take() { return Some(bytes_regex_parsed(next)); } // Accumulate a literal sequence as long as we can: while let Some(next) = self.iter.next() { match next.kind() { // A literal. Accumulate: Literal(literal) => self.buf.extend_from_slice(&literal.0), // Encountered a non-literal. _ => { return if !self.buf.is_empty() { // We've accumulated a literal from before, flush it out. // Store this node so we deal with it the next call. self.next = Some(next); flush_lit_buf(self) } else { // We didn't; just yield this node. Some(bytes_regex_parsed(next)) }; } } } // Flush out any accumulated literal from before. if !self.buf.is_empty() { flush_lit_buf(self) } else { self.next.take().map(bytes_regex_parsed) } } } fn to_range(rep: &Repetition) -> Result<SizeRange, Error> { Ok(match (rep.min, rep.max) { // Zero or one (0, Some(1)) => size_range(0..=1), // Zero or more (0, None) => size_range(0..=32), // One or more (1, None) => size_range(1..=32), // Exact count of u32::MAX (u32::MAX, Some(u32::MAX)) => { return unsupported("Cannot have repetition of exactly u32::MAX"); } // Exact count (min, Some(max)) if min == max => size_range(min as usize), // At least min (min, None) => { let max = if min < u32::MAX as u32 / 2 { min as usize * 2 } else { u32::MAX as usize }; size_range((min as usize)..max) } // Bounded range with max of u32::MAX (_, Some(u32::MAX)) => { return unsupported("Cannot have repetition max of u32::MAX") } // Bounded range (min, Some(max)) => size_range((min as usize)..(max as usize + 1)), }) } fn to_bytes(khar: char) -> Vec<u8> { let mut buf = [0u8; 4]; khar.encode_utf8(&mut buf).as_bytes().to_owned() } fn unsupported<T>(error: &'static str) -> Result<T, Error> { Err(Error::UnsupportedRegex(error)) } #[cfg(test)] mod test { use std::collections::HashSet; use regex::Regex; use regex::bytes::Regex as BytesRegex; use super::*; fn printable_ascii(v: &[u8]) -> String { v.iter() .flat_map(|c| std::ascii::escape_default(*c)) .map(|c| char::from_u32(c.into()).unwrap()) .collect() } fn do_test( pattern: &str, min_distinct: usize, max_distinct: usize, iterations: usize, ) { let generated = generate_values_matching_regex(pattern, iterations); assert!( generated.len() >= min_distinct, "Expected to generate at least {} strings, but only \ generated {}", min_distinct, generated.len() ); assert!( generated.len() <= max_distinct, "Expected to generate at most {} strings, but \ generated {}", max_distinct, generated.len() ); } fn do_test_bytes( pattern: &str, min_distinct: usize, max_distinct: usize, iterations: usize, ) { let generated = generate_byte_values_matching_regex(pattern, iterations); assert!( generated.len() >= min_distinct, "Expected to generate at least {} strings, but only \ generated {}", min_distinct, generated.len() ); assert!( generated.len() <= max_distinct, "Expected to generate at most {} strings, but \ generated {}", max_distinct, generated.len() ); } fn generate_values_matching_regex( pattern: &str, iterations: usize, ) -> HashSet<String> { let rx = Regex::new(pattern).unwrap(); let mut generated = HashSet::new(); let strategy = string_regex(pattern).unwrap(); let mut runner = TestRunner::deterministic(); for _ in 0..iterations { let mut value = strategy.new_tree(&mut runner).unwrap(); loop { let s = value.current(); let ok = if let Some(matsch) = rx.find(&s) { 0 == matsch.start() && s.len() == matsch.end() } else { false }; if !ok { panic!( "Generated string {:?} which does not match {:?}", s, pattern ); } generated.insert(s); if !value.simplify() { break; } } } generated } fn generate_byte_values_matching_regex( pattern: &str, iterations: usize, ) -> HashSet<Vec<u8>> { let rx = BytesRegex::new(pattern).unwrap(); let mut generated = HashSet::new(); let strategy = bytes_regex(pattern).unwrap(); let mut runner = TestRunner::deterministic(); for _ in 0..iterations { let mut value = strategy.new_tree(&mut runner).unwrap(); loop { let s = value.current(); let ok = if let Some(matsch) = rx.find(&s) { 0 == matsch.start() && s.len() == matsch.end() } else { false }; if !ok { panic!( "Generated string {:?} which does not match {:?}", printable_ascii(&s), pattern ); } generated.insert(s); if !value.simplify() { break; } } } generated } #[test] fn test_case_insensitive_produces_all_available_values() { let mut expected: HashSet<String> = HashSet::new(); expected.insert("a".into()); expected.insert("b".into()); expected.insert("A".into()); expected.insert("B".into()); assert_eq!(generate_values_matching_regex("(?i:a|B)", 64), expected); } #[test] fn test_literal() { do_test("foo", 1, 1, 8); do_test_bytes("foo", 1, 1, 8); } #[test] fn test_casei_literal() { do_test("(?i:fOo)", 8, 8, 64); } #[test] fn test_alternation() { do_test("foo|bar|baz", 3, 3, 16); do_test_bytes("foo|bar|baz", 3, 3, 16); } #[test] fn test_repetition() { do_test("a{0,8}", 9, 9, 64); do_test_bytes("a{0,8}", 9, 9, 64); } #[test] fn test_question() { do_test("a?", 2, 2, 16); do_test_bytes("a?", 2, 2, 16); } #[test] fn test_star() { do_test("a*", 33, 33, 256); do_test_bytes("a*", 33, 33, 256); } #[test] fn test_plus() { do_test("a+", 32, 32, 256); do_test_bytes("a+", 32, 32, 256); } #[test] fn test_n_to_range() { do_test("a{4,}", 4, 4, 64); do_test_bytes("a{4,}", 4, 4, 64); } #[test] fn test_concatenation() { do_test("(foo|bar)(xyzzy|plugh)", 4, 4, 32); do_test_bytes("(foo|bar)(xyzzy|plugh)", 4, 4, 32); } #[test] fn test_ascii_class() { do_test("[[:digit:]]", 10, 10, 256); } #[test] fn test_unicode_class() { do_test("\\p{Greek}", 24, 512, 256); } #[test] fn test_dot() { do_test(".", 200, 65536, 256); } #[test] fn test_dot_s() { do_test("(?s).", 200, 65536, 256); do_test_bytes("(?s-u).", 256, 256, 2048); } #[test] fn test_backslash_d_plus() { do_test("\\d+", 1, 65536, 256); } #[test] fn test_non_utf8_byte_strings() { do_test_bytes(r"(?-u)[\xC0-\xFF]\x20", 64, 64, 512); do_test_bytes(r"(?-u)\x20[\x80-\xBF]", 64, 64, 512); do_test_bytes(r#"(?x-u) \xed (( ( \xa0\x80 | \xad\xbf | \xae\x80 | \xaf\xbf ) ( \xed ( \xb0\x80 | \xbf\xbf ) )? ) | \xb0\x80 | \xbe\x80 | \xbf\xbf )"#, 15, 15, 120); } fn assert_send_and_sync<T: Send + Sync>(_: T) {} #[test] fn regex_strategy_is_send_and_sync() { assert_send_and_sync(string_regex(".").unwrap()); } macro_rules! consistent { ($name:ident, $value:expr) => { #[test] fn $name() { test_generates_matching_strings($value); } }; } fn test_generates_matching_strings(pattern: &str) { use std::time; let mut runner = TestRunner::default(); let start = time::Instant::now(); // If we don't support this regex, just move on quietly if let Ok(strategy) = string_regex(pattern) { let rx = Regex::new(pattern).unwrap(); for _ in 0..1000 { let mut val = strategy.new_tree(&mut runner).unwrap(); // No more than 1000 simplify steps to keep test time down for _ in 0..1000 { let s = val.current(); assert!( rx.is_match(&s), "Produced string {:?}, which does not match {:?}", s, pattern ); if !val.simplify() { break; } } // Quietly stop testing if we've run for >10 s if start.elapsed().as_secs() > 10 { break; } } } } include!("regex-contrib/crates_regex.rs"); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/sugar.rs�������������������������������������������������������������������������0000644�0000000�0000000�00000156215�10461020230�0014000�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2019 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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 = $crate::test_runner::contextualize_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 = $crate::test_runner::contextualize_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 = $crate::test_runner::contextualize_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 = $crate::test_runner::contextualize_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 = $crate::test_runner::contextualize_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 = $crate::test_runner::contextualize_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 }; // NOTE: The clippy::arc_with_non_send_sync lint is disabled here because // the strategies passed into prop_oneof! are often not Send or Sync, such // as BoxedStrategy. // // The double-curly-braces are not strictly required, but allow the expression // to be annotated with an attribute. ($weight0:expr => $item0:expr, $weight1:expr => $item1:expr $(,)?) => {{ #[allow(clippy::arc_with_non_send_sync)] $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 $(,)?) => {{ #[allow(clippy::arc_with_non_send_sync)] $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 $(,)?) => {{ #[allow(clippy::arc_with_non_send_sync)] $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 $(,)?) => {{ #[allow(clippy::arc_with_non_send_sync)] $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 $(,)?) => {{ #[allow(clippy::arc_with_non_send_sync)] $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 $(,)?) => {{ #[allow(clippy::arc_with_non_send_sync)] $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 $(,)?) => {{ #[allow(clippy::arc_with_non_send_sync)] $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 $(,)?) => {{ #[allow(clippy::arc_with_non_send_sync)] $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 $(,)?) => {{ #[allow(clippy::arc_with_non_send_sync)] $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<Value = $type>`. /// /// ```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<i32>, 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<Value = $return_type> { 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<Value = $return_type> { 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<Value = $return_type> { 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<Value = $return_type> { 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; $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)*); }}; } #[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)*))) }; } #[doc(hidden)] #[derive(Clone, Copy)] pub struct NamedArguments<N, V>(#[doc(hidden)] pub N, #[doc(hidden)] pub V); impl<V: fmt::Debug> fmt::Debug for NamedArguments<&'static str, V> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} = ", self.0)?; self.1.fmt(f) } } 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); #[cfg(feature = "std")] #[doc(hidden)] pub fn force_no_fork(config: &mut crate::test_runner::Config) { if config.fork() { eprintln!( "proptest: Forking/timeout not supported in closure-style \ invocations; ignoring" ); #[cfg(feature = "fork")] { config.fork = false; } #[cfg(feature = "timeout")] { config.timeout = 0; } assert!(!config.fork()); } } #[cfg(not(feature = "std"))] pub fn force_no_fork(_: &mut crate::test_runner::Config) {} #[cfg(test)] mod test { use crate::strategy::Just; prop_compose! { /// These are docs! #[allow(dead_code)] fn two_ints(relative: i32)(a in 0..relative, b in relative..) -> (i32, i32) { (a, b) } } prop_compose! { /// These are docs! #[allow(dead_code)] pub fn two_ints_pub(relative: i32)(a in 0..relative, b in relative..) -> (i32, i32) { (a, b) } } prop_compose! { /// These are docs! #[allow(dead_code, improper_ctypes_definitions)] pub [extern "C"] fn two_ints_pub_with_attrs (relative: i32)(a in 0..relative, b in relative..) -> (i32, i32) { (a, b) } } prop_compose! { // The only modifier we can usefully put here is "unsafe", but we want // to keep this crate unsafe-free, even nominally. "const" may // eventually work, but is not allowed right now since the generated // code contains local variables. `extern "C"` is accepted, even though // the result is useless since the return type isn't C-compatible. #[allow(dead_code, improper_ctypes_definitions)] [extern "C"] fn with_modifier(relative: i32)(a in 0..relative) -> i32 { a } } prop_compose! { #[allow(dead_code)] fn a_less_than_b()(b in 0..1000)(a in 0..b, b in Just(b)) -> (i32, i32) { (a, b) } } proptest! { #[test] fn test_something(a in 0u32..42u32, b in 1u32..10u32) { prop_assume!(a != 41 || b != 9); assert!(a + b < 50); } } prop_compose! { #[allow(dead_code)] fn single_closure_is_move(base: u64)(off in 0..10u64) -> u64 { base + off } } prop_compose! { #[allow(dead_code)] fn double_closure_is_move (base: u64) (off1 in 0..10u64) (off2 in off1..off1+10) -> u64 { base + off2 } } #[allow(unused_variables)] mod test_arg_counts { use crate::strategy::Just; proptest! { #[test] fn test_1_arg(a in Just(0)) { } #[test] fn test_2_arg(a in Just(0), b in Just(0)) { } #[test] fn test_3_arg(a in Just(0), b in Just(0), c in Just(0)) { } #[test] fn test_4_arg(a in Just(0), b in Just(0), c in Just(0), d in Just(0)) { } #[test] fn test_5_arg(a in Just(0), b in Just(0), c in Just(0), d in Just(0), e in Just(0)) { } #[test] fn test_6_arg(a in Just(0), b in Just(0), c in Just(0), d in Just(0), e in Just(0), f in Just(0)) { } #[test] fn test_7_arg(a in Just(0), b in Just(0), c in Just(0), d in Just(0), e in Just(0), f in Just(0), g in Just(0)) { } #[test] fn test_8_arg(a in Just(0), b in Just(0), c in Just(0), d in Just(0), e in Just(0), f in Just(0), g in Just(0), h in Just(0)) { } #[test] fn test_9_arg(a in Just(0), b in Just(0), c in Just(0), d in Just(0), e in Just(0), f in Just(0), g in Just(0), h in Just(0), i in Just(0)) { } #[test] fn test_a_arg(a in Just(0), b in Just(0), c in Just(0), d in Just(0), e in Just(0), f in Just(0), g in Just(0), h in Just(0), i in Just(0), j in Just(0)) { } #[test] fn test_b_arg(a in Just(0), b in Just(0), c in Just(0), d in Just(0), e in Just(0), f in Just(0), g in Just(0), h in Just(0), i in Just(0), j in Just(0), k in Just(0)) { } #[test] fn test_c_arg(a in Just(0), b in Just(0), c in Just(0), d in Just(0), e in Just(0), f in Just(0), g in Just(0), h in Just(0), i in Just(0), j in Just(0), k in Just(0), l in Just(0)) { } } } #[test] fn named_arguments_is_debug_for_needed_cases() { use super::NamedArguments; println!("{:?}", NamedArguments("foo", &"bar")); println!("{:?}", NamedArguments(("foo",), &(1,))); println!("{:?}", NamedArguments(("foo", "bar"), &(1, 2))); println!("{:?}", NamedArguments(("a", "b", "c"), &(1, 2, 3))); println!("{:?}", NamedArguments(("a", "b", "c", "d"), &(1, 2, 3, 4))); println!( "{:?}", NamedArguments(("a", "b", "c", "d", "e"), &(1, 2, 3, 4, 5)) ); println!( "{:?}", NamedArguments(("a", "b", "c", "d", "e", "f"), &(1, 2, 3, 4, 5, 6)) ); println!( "{:?}", NamedArguments( ("a", "b", "c", "d", "e", "f", "g"), &(1, 2, 3, 4, 5, 6, 7) ) ); println!( "{:?}", NamedArguments( ("a", "b", "c", "d", "e", "f", "g", "h"), &(1, 2, 3, 4, 5, 6, 7, 8) ) ); println!( "{:?}", NamedArguments( ("a", "b", "c", "d", "e", "f", "g", "h", "i"), &(1, 2, 3, 4, 5, 6, 7, 8, 9) ) ); println!( "{:?}", NamedArguments( ("a", "b", "c", "d", "e", "f", "g", "h", "i", "j"), &(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) ) ); println!( "{:?}", NamedArguments((("a", "b"), "c", "d"), &((1, 2), 3, 4)) ); } #[test] fn oneof_all_counts() { use crate::strategy::{Just as J, Strategy, TupleUnion, Union}; fn expect_count(n: usize, s: impl Strategy<Value = i32>) { use crate::strategy::*; use crate::test_runner::*; use std::collections::HashSet; let mut runner = TestRunner::default(); let mut seen = HashSet::new(); for _ in 0..1024 { seen.insert(s.new_tree(&mut runner).unwrap().current()); } assert_eq!(n, seen.len()); } fn assert_static<T>(v: TupleUnion<T>) -> TupleUnion<T> { v } fn assert_dynamic<T: Strategy>(v: Union<T>) -> Union<T> { v } expect_count(1, prop_oneof![J(0i32)]); expect_count(2, assert_static(prop_oneof![J(0i32), J(1i32),])); expect_count(3, assert_static(prop_oneof![J(0i32), J(1i32), J(2i32),])); expect_count( 4, assert_static(prop_oneof![J(0i32), J(1i32), J(2i32), J(3i32),]), ); expect_count( 5, assert_static(prop_oneof![ J(0i32), J(1i32), J(2i32), J(3i32), J(4i32), ]), ); expect_count( 6, assert_static(prop_oneof![ J(0i32), J(1i32), J(2i32), J(3i32), J(4i32), J(5i32), ]), ); expect_count( 7, assert_static(prop_oneof![ J(0i32), J(1i32), J(2i32), J(3i32), J(4i32), J(5i32), J(6i32), ]), ); expect_count( 8, assert_static(prop_oneof![ J(0i32), J(1i32), J(2i32), J(3i32), J(4i32), J(5i32), J(6i32), J(7i32), ]), ); expect_count( 9, assert_static(prop_oneof![ J(0i32), J(1i32), J(2i32), J(3i32), J(4i32), J(5i32), J(6i32), J(7i32), J(8i32), ]), ); expect_count( 10, assert_static(prop_oneof![ J(0i32), J(1i32), J(2i32), J(3i32), J(4i32), J(5i32), J(6i32), J(7i32), J(8i32), J(9i32), ]), ); expect_count( 11, assert_dynamic(prop_oneof![ J(0i32), J(1i32), J(2i32), J(3i32), J(4i32), J(5i32), J(6i32), J(7i32), J(8i32), J(9i32), J(10i32), ]), ); } } #[cfg(all(test, feature = "timeout"))] mod test_timeout { proptest! { #![proptest_config(crate::test_runner::Config { fork: true, .. crate::test_runner::Config::default() })] // Ensure that the macro sets the test name properly. If it doesn't, // this test will fail to run correctly. #[test] fn test_name_set_correctly_for_fork(_ in 0u32..1u32) { } } } #[cfg(test)] mod another_test { use crate::sugar; // Ensure that we can access the `[pub]` composed function above. #[allow(dead_code)] fn can_access_pub_compose() { let _ = sugar::test::two_ints_pub(42); let _ = sugar::test::two_ints_pub_with_attrs(42); } } #[cfg(test)] mod ownership_tests { #[cfg(feature = "std")] proptest! { #[test] fn accept_ref_arg(ref s in "[0-9]") { use crate::std_facade::String; fn assert_string(_s: &String) {} assert_string(s); } #[test] fn accept_move_arg(s in "[0-9]") { use crate::std_facade::String; fn assert_string(_s: String) {} assert_string(s); } } #[derive(Debug)] struct NotClone(); const MK: fn() -> NotClone = NotClone; proptest! { #[test] fn accept_noclone_arg(nc in MK) { let _nc2: NotClone = nc; } #[test] fn accept_noclone_ref_arg(ref nc in MK) { let _nc2: &NotClone = nc; } } } #[cfg(test)] mod closure_tests { #[test] fn test_simple() { let x = 420; proptest!(|(y: i32)| { assert!(x != y); }); proptest!(|(y in 0..100)| { println!("{}", y); assert!(x != y); }); proptest!(|(y: i32,)| { assert!(x != y); }); proptest!(|(y in 0..100,)| { println!("{}", y); assert!(x != y); }); } #[test] fn test_move() { let foo = Foo; proptest!(move |(x in 1..100, y in 0..100)| { assert!(x + y > 0, "foo: {:?}", foo); }); let foo = Foo; proptest!(move |(x: (), y: ())| { assert!(x == y, "foo: {:?}", foo); }); #[derive(Debug)] struct Foo; } #[test] #[should_panic] #[allow(unreachable_code)] fn fails_if_closure_panics() { proptest!(|(_ in 0..1)| { panic!() }); } #[test] fn accepts_unblocked_syntax() { proptest!(|(x in 0u32..10, y in 10u32..20)| assert!(x < y)); proptest!(|(x in 0u32..10, y in 10u32..20,)| assert!(x < y)); } #[test] fn accepts_custom_config() { let conf = crate::test_runner::Config::default(); proptest!(conf, |(x in 0u32..10, y in 10u32..20)| assert!(x < y)); proptest!(&conf, |(x in 0u32..10, y in 10u32..20)| assert!(x < y)); proptest!(conf, move |(x in 0u32..10, y in 10u32..20)| assert!(x < y)); proptest!(conf, |(_x: u32, _y: u32)| { }); proptest!(conf, move |(_x: u32, _y: u32)| { }); // Same as above, but with extra trailing comma proptest!(conf, |(x in 0u32..10, y in 10u32..20,)| assert!(x < y)); proptest!(&conf, |(x in 0u32..10, y in 10u32..20,)| assert!(x < y)); proptest!(conf, move |(x in 0u32..10, y in 10u32..20,)| assert!(x < y)); proptest!(conf, |(_x: u32, _y: u32,)| { }); proptest!(conf, move |(_x: u32, _y: u32,)| { }); } } #[cfg(test)] mod any_tests { proptest! { #[test] fn test_something ( a: bool, b in 25u8.., c in 25u8.., _d: (), mut _e: (), ref _f: (), ref mut _g: (), [_, _]: [(); 2], ) { if a {} // Assert bool. assert!(b as usize + c as usize >= 50); } } // Test that the macro accepts some of the inputs we expect it to: #[test] fn proptest_ext_test() { struct Y(pub u8); let _ = proptest_helper!(@_EXT _STRAT( _ : u8 )); let _ = proptest_helper!(@_EXT _STRAT( x : u8 )); let _ = proptest_helper!(@_EXT _STRAT( ref x : u8 )); let _ = proptest_helper!(@_EXT _STRAT( mut x : u8 )); let _ = proptest_helper!(@_EXT _STRAT( ref mut x : u8 )); let _ = proptest_helper!(@_EXT _STRAT( [_, _] : u8 )); let _ = proptest_helper!(@_EXT _STRAT( (&mut &Y(ref x)) : u8 )); let _ = proptest_helper!(@_EXT _STRAT( x in 1..2 )); let proptest_helper!(@_EXT _PAT( _ : u8 )) = 1; let proptest_helper!(@_EXT _PAT( _x : u8 )) = 1; let proptest_helper!(@_EXT _PAT( mut _x : u8 )) = 1; let proptest_helper!(@_EXT _PAT( ref _x : u8 )) = 1; let proptest_helper!(@_EXT _PAT( ref mut _x : u8 )) = 1; let proptest_helper!(@_EXT _PAT( [_, _] : u8 )) = [1, 2]; let proptest_helper!(@_EXT _PAT( (&mut &Y(ref _x)) : u8 )) = &mut &Y(1); let proptest_helper!(@_EXT _PAT( _x in 1..2 )) = 1; } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/test_runner/config.rs������������������������������������������������������������0000644�0000000�0000000�00000050164�10461020230�0016470�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018, 2019 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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; use crate::test_runner::result_cache::{noop_result_cache, ResultCache}; use crate::test_runner::rng::RngAlgorithm; use crate::test_runner::FailurePersistence; /// Override the config fields from environment variables, if any are set. /// Without the `std` feature this function returns config unchanged. #[cfg(all(feature = "std", not(target_arch = "wasm32")))] pub fn contextualize_config(mut result: Config) -> Config { use std::env; use std::ffi::OsString; use std::fmt; use std::str::FromStr; const CASES: &str = "PROPTEST_CASES"; const MAX_LOCAL_REJECTS: &str = "PROPTEST_MAX_LOCAL_REJECTS"; const MAX_GLOBAL_REJECTS: &str = "PROPTEST_MAX_GLOBAL_REJECTS"; const MAX_FLAT_MAP_REGENS: &str = "PROPTEST_MAX_FLAT_MAP_REGENS"; const MAX_SHRINK_TIME: &str = "PROPTEST_MAX_SHRINK_TIME"; const MAX_SHRINK_ITERS: &str = "PROPTEST_MAX_SHRINK_ITERS"; const MAX_DEFAULT_SIZE_RANGE: &str = "PROPTEST_MAX_DEFAULT_SIZE_RANGE"; #[cfg(feature = "fork")] const FORK: &str = "PROPTEST_FORK"; #[cfg(feature = "timeout")] const TIMEOUT: &str = "PROPTEST_TIMEOUT"; const VERBOSE: &str = "PROPTEST_VERBOSE"; const RNG_ALGORITHM: &str = "PROPTEST_RNG_ALGORITHM"; const DISABLE_FAILURE_PERSISTENCE: &str = "PROPTEST_DISABLE_FAILURE_PERSISTENCE"; fn parse_or_warn<T: FromStr + fmt::Display>( 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 ); } } for (var, value) in env::vars_os().filter_map(|(k, v)| k.into_string().ok().map(|k| (k, v))) { let var = var.as_str(); #[cfg(feature = "fork")] if var == FORK { parse_or_warn(&value, &mut result.fork, "bool", FORK); continue; } #[cfg(feature = "timeout")] if var == TIMEOUT { parse_or_warn(&value, &mut result.timeout, "timeout", TIMEOUT); continue; } if var == CASES { parse_or_warn(&value, &mut result.cases, "u32", CASES); } else if var == MAX_LOCAL_REJECTS { parse_or_warn( &value, &mut result.max_local_rejects, "u32", MAX_LOCAL_REJECTS, ); } else if var == MAX_GLOBAL_REJECTS { parse_or_warn( &value, &mut result.max_global_rejects, "u32", MAX_GLOBAL_REJECTS, ); } else if var == MAX_FLAT_MAP_REGENS { parse_or_warn( &value, &mut result.max_flat_map_regens, "u32", MAX_FLAT_MAP_REGENS, ); } else if var == MAX_SHRINK_TIME { parse_or_warn( &value, &mut result.max_shrink_time, "u32", MAX_SHRINK_TIME, ); } else if var == MAX_SHRINK_ITERS { parse_or_warn( &value, &mut result.max_shrink_iters, "u32", MAX_SHRINK_ITERS, ); } else if var == MAX_DEFAULT_SIZE_RANGE { parse_or_warn( &value, &mut result.max_default_size_range, "usize", MAX_DEFAULT_SIZE_RANGE, ); } else if var == VERBOSE { parse_or_warn(&value, &mut result.verbose, "u32", VERBOSE); } else if var == RNG_ALGORITHM { parse_or_warn( &value, &mut result.rng_algorithm, "RngAlgorithm", RNG_ALGORITHM, ); } else if var == DISABLE_FAILURE_PERSISTENCE { result.failure_persistence = None; } else if var.starts_with("PROPTEST_") { eprintln!("proptest: Ignoring unknown env-var {}.", var); } } result } /// Without the `std` feature this function returns config unchanged. #[cfg(not(all(feature = "std", not(target_arch = "wasm32"))))] pub fn contextualize_config(result: Config) -> Config { 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, max_default_size_range: 100, 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 = { let mut default_config = default_default_config(); default_config.failure_persistence = Some(Box::new(crate::test_runner::FileFailurePersistence::default())); contextualize_config(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. (The variable is only considered /// when the `std` feature is enabled, which it is by default.) 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. (The variable is only /// considered when the `std` feature is enabled, which it is by default.) 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. (The variable is /// only considered when the `std` feature is enabled, which it is by /// default.) 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. (The variable is /// only considered when the `std` feature is enabled, which it is by /// default.) 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. /// /// You can disable failure persistence with the `PROPTEST_DISABLE_FAILURE_PERSISTENCE` /// environment variable but its not currently possible to set the persistence file /// with an environment variable. (The variable is /// only considered when the `std` feature is enabled, which it is by /// default.) pub failure_persistence: Option<Box<dyn FailurePersistence>>, /// 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. (The variable is /// only considered when the `std` feature is enabled, which it is by /// default.) #[cfg(feature = "fork")] #[cfg_attr(docsrs, doc(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<std::time::Duration>`) 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. (The variable is /// only considered when the `std` feature is enabled, which it is by /// default.) #[cfg(feature = "timeout")] #[cfg_attr(docsrs, doc(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. (The variable is /// only considered when the `std` feature is enabled, which it is by /// default.) #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(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. (The variable is only /// considered when the `std` feature is enabled, which it is by default.) pub max_shrink_iters: u32, /// The default maximum size to `proptest::collection::SizeRange`. The default /// strategy for collections (like `Vec`) use collections in the range of /// `0..max_default_size_range`. /// /// The default is `100` which can be overridden by setting the /// `PROPTEST_MAX_DEFAULT_SIZE_RANGE` environment variable. (The variable /// is only considered when the `std` feature is enabled, which it is by /// default.) pub max_default_size_range: usize, /// 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<dyn ResultCache>, /// 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. In state machine tests, this level is /// used to print transitions. /// - 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. (The variable is only considered /// when the `std` feature is enabled, which it is by default.) #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(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` /// /// (The variable is only considered when the `std` feature is enabled, /// which it is by default.) 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 } /// Constructs a `Config` only differing from the `default()` in the /// failure_persistence member. /// /// This is simply a more concise alternative to using field-record update /// syntax: /// /// ``` /// # use proptest::test_runner::{Config, FileFailurePersistence}; /// assert_eq!( /// Config::with_failure_persistence(FileFailurePersistence::WithSource("regressions")), /// Config { /// failure_persistence: Some(Box::new(FileFailurePersistence::WithSource("regressions"))), /// .. Config::default() /// } /// ); /// ``` pub fn with_failure_persistence<T>(failure_persistence: T) -> Self where T: FailurePersistence + 'static, { Self { failure_persistence: Some(Box::new(failure_persistence)), ..Default::default() } } /// 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() } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/test_runner/errors.rs������������������������������������������������������������0000644�0000000�0000000�00000010670�10461020230�0016535�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::fmt; #[cfg(feature = "std")] use std::string::ToString; use crate::test_runner::Reason; /// Errors which can be returned from test cases to indicate non-successful /// completion. /// /// Note that in spite of the name, `TestCaseError` is currently *not* an /// instance of `Error`, since otherwise `impl<E : Error> From<E>` could not be /// provided. /// /// Any `Error` can be converted to a `TestCaseError`, which places /// `Error::display()` into the `Fail` case. #[derive(Debug, Clone)] pub enum TestCaseError { /// The input was not valid for the test case. This does not count as a /// test failure (nor a success); rather, it simply signals to generate /// a new input and try again. Reject(Reason), /// The code under test failed the test. Fail(Reason), } /// Indicates the type of test that ran successfully. /// /// This is used for managing whether or not a success is counted against /// configured `PROPTEST_CASES`; only `NewCases` shall be counted. /// /// TODO-v2: Ideally `TestCaseResult = Result<TestCaseOk, TestCaseError>` /// however this breaks source compatibility in version 1.x.x because /// `TestCaseResult` is public. #[derive(Debug, Clone)] pub(crate) enum TestCaseOk { NewCaseSuccess, PersistedCaseSuccess, ReplayFromForkSuccess, CacheHitSuccess, Reject, } /// Convenience for the type returned by test cases. pub type TestCaseResult = Result<(), TestCaseError>; /// Intended to replace `TestCaseResult` in v2. /// /// TODO-v2: Ideally `TestCaseResult = Result<TestCaseOk, TestCaseError>` /// however this breaks source compatibility in version 1.x.x because /// `TestCaseResult` is public. pub(crate) type TestCaseResultV2 = Result<TestCaseOk, TestCaseError>; impl TestCaseError { /// Rejects the generated test input as invalid for this test case. This /// does not count as a test failure (nor a success); rather, it simply /// signals to generate a new input and try again. /// /// The string gives the location and context of the rejection, and /// should be suitable for formatting like `Foo did X at {whence}`. pub fn reject(reason: impl Into<Reason>) -> Self { TestCaseError::Reject(reason.into()) } /// The code under test failed the test. /// /// The string should indicate the location of the failure, but may /// generally be any string. pub fn fail(reason: impl Into<Reason>) -> Self { TestCaseError::Fail(reason.into()) } } impl fmt::Display for TestCaseError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { TestCaseError::Reject(ref whence) => { write!(f, "Input rejected at {}", whence) } TestCaseError::Fail(ref why) => write!(f, "Case failed: {}", why), } } } #[cfg(feature = "std")] impl<E: ::std::error::Error> From<E> for TestCaseError { fn from(cause: E) -> Self { TestCaseError::fail(cause.to_string()) } } /// A failure state from running test cases for a single test. #[derive(Debug, Clone, PartialEq, Eq)] pub enum TestError<T> { /// The test was aborted for the given reason, for example, due to too many /// inputs having been rejected. Abort(Reason), /// A failing test case was found. The string indicates where and/or why /// the test failed. The `T` is the minimal input found to reproduce the /// failure. Fail(Reason, T), } impl<T: fmt::Debug> fmt::Display for TestError<T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { TestError::Abort(ref why) => write!(f, "Test aborted: {}", why), TestError::Fail(ref why, ref what) => { writeln!(f, "Test failed: {}.", why)?; write!(f, "minimal failing input: {:#?}", what) } } } } #[cfg(feature = "std")] #[allow(deprecated)] // description() impl<T: fmt::Debug> ::std::error::Error for TestError<T> { fn description(&self) -> &str { match *self { TestError::Abort(..) => "Abort", TestError::Fail(..) => "Fail", } } } ������������������������������������������������������������������������proptest-1.6.0/src/test_runner/failure_persistence/file.rs������������������������������������������0000644�0000000�0000000�00000044227�10461020230�0022200�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018, 2019 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use core::any::Any; use core::fmt::Debug; use std::borrow::{Cow, ToOwned}; use std::boxed::Box; use std::env; use std::fs; use std::io::{self, BufRead, Write}; use std::path::{Path, PathBuf}; use std::string::{String, ToString}; use std::sync::RwLock; use std::vec::Vec; use self::FileFailurePersistence::*; use crate::test_runner::failure_persistence::{ FailurePersistence, PersistedSeed, }; /// Describes how failing test cases are persisted. /// /// Note that file names in this enum are `&str` rather than `&Path` since /// constant functions are not yet in Rust stable as of 2017-12-16. /// /// In all cases, if a derived path references a directory which does not yet /// exist, proptest will attempt to create all necessary parent directories. #[derive(Clone, Copy, Debug, PartialEq)] pub enum FileFailurePersistence { /// Completely disables persistence of failing test cases. /// /// This is semantically equivalent to `Direct("/dev/null")` on Unix and /// `Direct("NUL")` on Windows (though it is internally handled by simply /// not doing any I/O). Off, /// The path of the source file under test is traversed up the directory tree /// until a directory containing a file named `lib.rs` or `main.rs` is found. /// A sibling to that directory with the name given by the string in this /// configuration is created, and a file with the same name and path relative /// to the source directory, but with the extension changed to `.txt`, is used. /// /// For example, given a source path of /// `/home/jsmith/code/project/src/foo/bar.rs` and a configuration of /// `SourceParallel("proptest-regressions")` (the default), assuming the /// `src` directory has a `lib.rs` or `main.rs`, the resulting file would /// be `/home/jsmith/code/project/proptest-regressions/foo/bar.txt`. /// /// If no `lib.rs` or `main.rs` can be found, a warning is printed and this /// behaves like `WithSource`. /// /// If no source file has been configured, a warning is printed and this /// behaves like `Off`. SourceParallel(&'static str), /// Failures are persisted in a file with the same path as the source file /// under test, but the extension is changed to the string given in this /// configuration. /// /// For example, given a source path of /// `/home/jsmith/code/project/src/foo/bar.rs` and a configuration of /// `WithSource("regressions")`, the resulting path would be /// `/home/jsmith/code/project/src/foo/bar.regressions`. WithSource(&'static str), /// The string given in this option is directly used as a file path without /// any further processing. Direct(&'static str), #[doc(hidden)] #[allow(missing_docs)] _NonExhaustive, } impl Default for FileFailurePersistence { fn default() -> Self { SourceParallel("proptest-regressions") } } impl FailurePersistence for FileFailurePersistence { fn load_persisted_failures2( &self, source_file: Option<&'static str>, ) -> Vec<PersistedSeed> { let p = self.resolve( source_file .and_then(|s| absolutize_source_file(Path::new(s))) .as_ref() .map(|cow| &**cow), ); let path: Option<&PathBuf> = p.as_ref(); let result: io::Result<Vec<PersistedSeed>> = path.map_or_else( || Ok(vec![]), |path| { // .ok() instead of .unwrap() so we don't propagate panics here let _lock = PERSISTENCE_LOCK.read().ok(); io::BufReader::new(fs::File::open(path)?) .lines() .enumerate() .filter_map(|(lineno, line)| match line { Err(err) => Some(Err(err)), Ok(line) => parse_seed_line(line, path, lineno).map(Ok), }) .collect() }, ); unwrap_or!(result, err => { if io::ErrorKind::NotFound != err.kind() { eprintln!( "proptest: failed to open {}: {}", &path.map(|x| &**x) .unwrap_or_else(|| Path::new("??")) .display(), err ); } vec![] }) } fn save_persisted_failure2( &mut self, source_file: Option<&'static str>, seed: PersistedSeed, shrunken_value: &dyn Debug, ) { let path = self.resolve(source_file.map(Path::new)); if let Some(path) = path { // .ok() instead of .unwrap() so we don't propagate panics here let _lock = PERSISTENCE_LOCK.write().ok(); let is_new = !path.is_file(); let mut to_write = Vec::<u8>::new(); if is_new { write_header(&mut to_write) .expect("proptest: couldn't write header."); } write_seed_line(&mut to_write, &seed, shrunken_value) .expect("proptest: couldn't write seed line."); if let Err(e) = write_seed_data_to_file(&path, &to_write) { eprintln!( "proptest: failed to append to {}: {}", path.display(), e ); } else { eprintln!( "proptest: Saving this and future failures in {}\n\ proptest: If this test was run on a CI system, you may \ wish to add the following line to your copy of the file.{}\n\ {}", path.display(), if is_new { " (You may need to create it.)" } else { "" }, seed); } } } fn box_clone(&self) -> Box<dyn FailurePersistence> { Box::new(*self) } fn eq(&self, other: &dyn FailurePersistence) -> bool { other .as_any() .downcast_ref::<Self>() .map_or(false, |x| x == self) } fn as_any(&self) -> &dyn Any { self } } /// Ensure that the source file to use for resolving the location of the persisted /// failing cases file is absolute. /// /// The source location can only be used if it is absolute. If `source` is /// not an absolute path, an attempt will be made to determine the absolute /// path based on the current working directory and its parents. If no /// absolute path can be determined, a warning will be printed and proptest /// will continue as if this function had never been called. /// /// See [`FileFailurePersistence`](enum.FileFailurePersistence.html) for details on /// how this value is used once it is made absolute. /// /// This is normally called automatically by the `proptest!` macro, which /// passes `file!()`. /// fn absolutize_source_file<'a>(source: &'a Path) -> Option<Cow<'a, Path>> { absolutize_source_file_with_cwd(env::current_dir, source) } fn absolutize_source_file_with_cwd<'a>( getcwd: impl FnOnce() -> io::Result<PathBuf>, source: &'a Path, ) -> Option<Cow<'a, Path>> { if source.is_absolute() { // On Unix, `file!()` is absolute. In these cases, we can use // that path directly. Some(Cow::Borrowed(source)) } else { // On Windows, `file!()` is relative to the crate root, but the // test is not generally run with the crate root as the working // directory, so the path is not directly usable. However, the // working directory is almost always a subdirectory of the crate // root, so pop directories off until pushing the source onto the // directory results in a path that refers to an existing file. // Once we find such a path, we can use that. // // If we can't figure out an absolute path, print a warning and act // as if no source had been given. match getcwd() { Ok(mut cwd) => loop { let joined = cwd.join(source); if joined.is_file() { break Some(Cow::Owned(joined)); } if !cwd.pop() { eprintln!( "proptest: Failed to find absolute path of \ source file '{:?}'. Ensure the test is \ being run from somewhere within the crate \ directory hierarchy.", source ); break None; } }, Err(e) => { eprintln!( "proptest: Failed to determine current \ directory, so the relative source path \ '{:?}' cannot be resolved: {}", source, e ); None } } } } fn parse_seed_line( mut line: String, path: &Path, lineno: usize, ) -> Option<PersistedSeed> { // Remove anything after and including '#': if let Some(comment_start) = line.find('#') { line.truncate(comment_start); } if line.len() > 0 { let ret = line.parse::<PersistedSeed>().ok(); if !ret.is_some() { eprintln!( "proptest: {}:{}: unparsable line, ignoring", path.display(), lineno + 1 ); } return ret; } None } fn write_seed_line( buf: &mut Vec<u8>, seed: &PersistedSeed, shrunken_value: &dyn Debug, ) -> io::Result<()> { // Write the seed itself write!(buf, "{}", seed.to_string())?; // Write out comment: let debug_start = buf.len(); write!(buf, " # shrinks to {:?}", shrunken_value)?; // Ensure there are no newlines in the debug output for byte in &mut buf[debug_start..] { if b'\n' == *byte || b'\r' == *byte { *byte = b' '; } } buf.push(b'\n'); Ok(()) } fn write_header(buf: &mut Vec<u8>) -> io::Result<()> { writeln!( buf, "\ # Seeds for failure cases proptest has generated in the past. It is # automatically read and these particular cases re-run before any # novel cases are generated. # # It is recommended to check this file in to source control so that # everyone who runs the test benefits from these saved cases." ) } fn write_seed_data_to_file(dst: &Path, data: &[u8]) -> io::Result<()> { if let Some(parent) = dst.parent() { fs::create_dir_all(parent)?; } let mut options = fs::OpenOptions::new(); options.append(true).create(true); let mut out = options.open(dst)?; out.write_all(data)?; Ok(()) } impl FileFailurePersistence { /// Given the nominal source path, determine the location of the failure /// persistence file, if any. pub(super) fn resolve(&self, source: Option<&Path>) -> Option<PathBuf> { let source = source.and_then(absolutize_source_file); match *self { Off => None, SourceParallel(sibling) => match source { Some(source_path) => { let mut dir = Cow::into_owned(source_path.clone()); let mut found = false; while dir.pop() { if dir.join("lib.rs").is_file() || dir.join("main.rs").is_file() { found = true; break; } } if !found { eprintln!( "proptest: FileFailurePersistence::SourceParallel set, \ but failed to find lib.rs or main.rs" ); WithSource(sibling).resolve(Some(&*source_path)) } else { let suffix = source_path .strip_prefix(&dir) .expect("parent of source is not a prefix of it?") .to_owned(); let mut result = dir; // If we've somehow reached the root, or someone gave // us a relative path that we've exhausted, just accept // creating a subdirectory instead. let _ = result.pop(); result.push(sibling); result.push(&suffix); result.set_extension("txt"); Some(result) } } None => { eprintln!( "proptest: FileFailurePersistence::SourceParallel set, \ but no source file known" ); None } }, WithSource(extension) => match source { Some(source_path) => { let mut result = Cow::into_owned(source_path); result.set_extension(extension); Some(result) } None => { eprintln!( "proptest: FileFailurePersistence::WithSource set, \ but no source file known" ); None } }, Direct(path) => Some(Path::new(path).to_owned()), _NonExhaustive => { panic!("FailurePersistence set to _NonExhaustive") } } } } lazy_static! { /// Used to guard access to the persistence file(s) so that a single /// process will not step on its own toes. /// /// We don't have much protecting us should two separate process try to /// write to the same file at once (depending on how atomic append mode is /// on the OS), but this should be extremely rare. static ref PERSISTENCE_LOCK: RwLock<()> = RwLock::new(()); } #[cfg(test)] mod tests { use super::*; struct TestPaths { crate_root: &'static Path, src_file: PathBuf, subdir_file: PathBuf, misplaced_file: PathBuf, } lazy_static! { static ref TEST_PATHS: TestPaths = { let crate_root = Path::new(env!("CARGO_MANIFEST_DIR")); let lib_root = crate_root.join("src"); let src_subdir = lib_root.join("strategy"); let src_file = lib_root.join("foo.rs"); let subdir_file = src_subdir.join("foo.rs"); let misplaced_file = crate_root.join("foo.rs"); TestPaths { crate_root, src_file, subdir_file, misplaced_file, } }; } #[test] fn persistence_file_location_resolved_correctly() { // If off, there is never a file assert_eq!(None, Off.resolve(None)); assert_eq!(None, Off.resolve(Some(&TEST_PATHS.subdir_file))); // For direct, we don't care about the source file, and instead always // use whatever is in the config. assert_eq!( Some(Path::new("bar.txt").to_owned()), Direct("bar.txt").resolve(None) ); assert_eq!( Some(Path::new("bar.txt").to_owned()), Direct("bar.txt").resolve(Some(&TEST_PATHS.subdir_file)) ); // For WithSource, only the extension changes, but we get nothing if no // source file was configured. // Accounting for the way absolute paths work on Windows would be more // complex, so for now don't test that case. #[cfg(unix)] fn absolute_path_case() { assert_eq!( Some(Path::new("/foo/bar.ext").to_owned()), WithSource("ext").resolve(Some(Path::new("/foo/bar.rs"))) ); } #[cfg(not(unix))] fn absolute_path_case() {} absolute_path_case(); assert_eq!(None, WithSource("ext").resolve(None)); // For SourceParallel, we make a sibling directory tree and change the // extensions to .txt ... assert_eq!( Some(TEST_PATHS.crate_root.join("sib").join("foo.txt")), SourceParallel("sib").resolve(Some(&TEST_PATHS.src_file)) ); assert_eq!( Some( TEST_PATHS .crate_root .join("sib") .join("strategy") .join("foo.txt") ), SourceParallel("sib").resolve(Some(&TEST_PATHS.subdir_file)) ); // ... but if we can't find lib.rs / main.rs, give up and set the // extension instead ... assert_eq!( Some(TEST_PATHS.crate_root.join("foo.sib")), SourceParallel("sib").resolve(Some(&TEST_PATHS.misplaced_file)) ); // ... and if no source is configured, we do nothing assert_eq!(None, SourceParallel("ext").resolve(None)); } #[test] fn relative_source_files_absolutified() { const TEST_RUNNER_PATH: &[&str] = &["src", "test_runner", "mod.rs"]; lazy_static! { static ref TEST_RUNNER_RELATIVE: PathBuf = TEST_RUNNER_PATH.iter().collect(); } const CARGO_DIR: &str = env!("CARGO_MANIFEST_DIR"); let expected = ::std::iter::once(CARGO_DIR) .chain(TEST_RUNNER_PATH.iter().map(|s| *s)) .collect::<PathBuf>(); // Running from crate root assert_eq!( &*expected, absolutize_source_file_with_cwd( || Ok(Path::new(CARGO_DIR).to_owned()), &TEST_RUNNER_RELATIVE ) .unwrap() ); // Running from test subdirectory assert_eq!( &*expected, absolutize_source_file_with_cwd( || Ok(Path::new(CARGO_DIR).join("target")), &TEST_RUNNER_RELATIVE ) .unwrap() ); } } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/test_runner/failure_persistence/map.rs�������������������������������������������0000644�0000000�0000000�00000006017�10461020230�0022031�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::{fmt, BTreeMap, BTreeSet, Box, Vec}; use core::any::Any; use crate::test_runner::failure_persistence::FailurePersistence; use crate::test_runner::failure_persistence::PersistedSeed; /// Failure persistence option that loads and saves seeds in memory /// on the heap. This may be useful when accumulating test failures /// across multiple `TestRunner` instances for external reporting /// or batched persistence. #[derive(Clone, Debug, Default, PartialEq)] pub struct MapFailurePersistence { /// Backing map, keyed by source_file. pub map: BTreeMap<&'static str, BTreeSet<PersistedSeed>>, } impl FailurePersistence for MapFailurePersistence { fn load_persisted_failures2( &self, source_file: Option<&'static str>, ) -> Vec<PersistedSeed> { source_file .and_then(|source| self.map.get(source)) .map(|seeds| seeds.iter().cloned().collect::<Vec<_>>()) .unwrap_or_default() } fn save_persisted_failure2( &mut self, source_file: Option<&'static str>, seed: PersistedSeed, _shrunken_value: &dyn fmt::Debug, ) { let s = match source_file { Some(sf) => sf, None => return, }; let set = self.map.entry(s).or_insert_with(BTreeSet::new); set.insert(seed); } fn box_clone(&self) -> Box<dyn FailurePersistence> { Box::new(self.clone()) } fn eq(&self, other: &dyn FailurePersistence) -> bool { other .as_any() .downcast_ref::<Self>() .map_or(false, |x| x == self) } fn as_any(&self) -> &dyn Any { self } } #[cfg(test)] mod tests { use super::*; use crate::test_runner::failure_persistence::tests::*; #[test] fn initial_map_is_empty() { assert!(MapFailurePersistence::default() .load_persisted_failures2(HI_PATH) .is_empty()) } #[test] fn seeds_recoverable() { let mut p = MapFailurePersistence::default(); p.save_persisted_failure2(HI_PATH, INC_SEED, &""); let restored = p.load_persisted_failures2(HI_PATH); assert_eq!(1, restored.len()); assert_eq!(INC_SEED, *restored.first().unwrap()); assert!(p.load_persisted_failures2(None).is_empty()); assert!(p.load_persisted_failures2(UNREL_PATH).is_empty()); } #[test] fn seeds_deduplicated() { let mut p = MapFailurePersistence::default(); p.save_persisted_failure2(HI_PATH, INC_SEED, &""); p.save_persisted_failure2(HI_PATH, INC_SEED, &""); let restored = p.load_persisted_failures2(HI_PATH); assert_eq!(1, restored.len()); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/test_runner/failure_persistence/mod.rs�������������������������������������������0000644�0000000�0000000�00000011602�10461020230�0022027�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018, 2019 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::{fmt, Box, Vec}; use core::any::Any; use core::fmt::Display; use core::result::Result; use core::str::FromStr; #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] mod file; mod map; mod noop; #[cfg(feature = "std")] pub use self::file::*; pub use self::map::*; use crate::test_runner::Seed; /// Opaque struct representing a seed which can be persisted. /// /// The `Display` and `FromStr` implementations go to and from the format /// Proptest uses for its persistence file. #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct PersistedSeed(pub(crate) Seed); impl Display for PersistedSeed { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0.to_persistence()) } } impl FromStr for PersistedSeed { type Err = (); fn from_str(s: &str) -> Result<Self, ()> { Seed::from_persistence(s).map(PersistedSeed).ok_or(()) } } /// Provides external persistence for historical test failures by storing seeds. /// /// **Note**: Implementing `load_persisted_failures` and /// `save_persisted_failures` is **deprecated** and these methods will be /// removed in proptest 0.10.0. Instead, implement `load_persisted_failures2` /// and `save_persisted_failures2`. pub trait FailurePersistence: Send + Sync + fmt::Debug { /// Supply seeds associated with the given `source_file` that may be used /// by a `TestRunner`'s random number generator in order to consistently /// recreate a previously-failing `Strategy`-provided value. /// /// The default implementation is **for backwards compatibility**. It /// delegates to `load_persisted_failures` and converts the results into /// XorShift seeds. #[allow(deprecated)] fn load_persisted_failures2( &self, source_file: Option<&'static str>, ) -> Vec<PersistedSeed> { self.load_persisted_failures(source_file) .into_iter() .map(|seed| PersistedSeed(Seed::XorShift(seed))) .collect() } /// Use `load_persisted_failures2` instead. /// /// This function inadvertently exposes the implementation of seeds prior /// to Proptest 0.9.1 and only works with XorShift seeds. #[deprecated] #[allow(unused_variables)] fn load_persisted_failures( &self, source_file: Option<&'static str>, ) -> Vec<[u8; 16]> { panic!("load_persisted_failures2 not implemented"); } /// Store a new failure-generating seed associated with the given `source_file`. /// /// The default implementation is **for backwards compatibility**. It /// delegates to `save_persisted_failure` if `seed` is a XorShift seed. #[allow(deprecated)] fn save_persisted_failure2( &mut self, source_file: Option<&'static str>, seed: PersistedSeed, shrunken_value: &dyn fmt::Debug, ) { match seed.0 { Seed::XorShift(seed) => { self.save_persisted_failure(source_file, seed, shrunken_value) } _ => (), } } /// Use `save_persisted_failures2` instead. /// /// This function inadvertently exposes the implementation of seeds prior /// to Proptest 0.9.1 and only works with XorShift seeds. #[deprecated] #[allow(unused_variables)] fn save_persisted_failure( &mut self, source_file: Option<&'static str>, seed: [u8; 16], shrunken_value: &dyn fmt::Debug, ) { panic!("save_persisted_failure2 not implemented"); } /// Delegate method for producing a trait object usable with `Clone` fn box_clone(&self) -> Box<dyn FailurePersistence>; /// Equality testing delegate required due to constraints of trait objects. fn eq(&self, other: &dyn FailurePersistence) -> bool; /// Assistant method for trait object comparison. fn as_any(&self) -> &dyn Any; } impl<'a, 'b> PartialEq<dyn FailurePersistence + 'b> for dyn FailurePersistence + 'a { fn eq(&self, other: &(dyn FailurePersistence + 'b)) -> bool { FailurePersistence::eq(self, other) } } impl Clone for Box<dyn FailurePersistence> { fn clone(&self) -> Box<dyn FailurePersistence> { self.box_clone() } } #[cfg(test)] mod tests { use super::PersistedSeed; use crate::test_runner::rng::Seed; pub const INC_SEED: PersistedSeed = PersistedSeed(Seed::XorShift([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, ])); pub const HI_PATH: Option<&str> = Some("hi"); pub const UNREL_PATH: Option<&str> = Some("unrelated"); } ������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/test_runner/failure_persistence/noop.rs������������������������������������������0000644�0000000�0000000�00000004121�10461020230�0022221�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::{fmt, Box, Vec}; use core::any::Any; use crate::test_runner::failure_persistence::{ FailurePersistence, PersistedSeed, }; /// Failure persistence option that loads and saves nothing at all. #[derive(Debug, Default, PartialEq)] struct NoopFailurePersistence; impl FailurePersistence for NoopFailurePersistence { fn load_persisted_failures2( &self, _source_file: Option<&'static str>, ) -> Vec<PersistedSeed> { Vec::new() } fn save_persisted_failure2( &mut self, _source_file: Option<&'static str>, _seed: PersistedSeed, _shrunken_value: &dyn fmt::Debug, ) { } fn box_clone(&self) -> Box<dyn FailurePersistence> { Box::new(NoopFailurePersistence) } fn eq(&self, other: &dyn FailurePersistence) -> bool { other .as_any() .downcast_ref::<Self>() .map_or(false, |x| x == self) } fn as_any(&self) -> &dyn Any { self } } #[cfg(test)] mod tests { use super::*; use crate::test_runner::failure_persistence::tests::*; #[test] fn default_load_is_empty() { assert!(NoopFailurePersistence::default() .load_persisted_failures2(None) .is_empty()); assert!(NoopFailurePersistence::default() .load_persisted_failures2(HI_PATH) .is_empty()); } #[test] fn seeds_not_recoverable() { let mut p = NoopFailurePersistence::default(); p.save_persisted_failure2(HI_PATH, INC_SEED, &""); assert!(p.load_persisted_failures2(HI_PATH).is_empty()); assert!(p.load_persisted_failures2(None).is_empty()); assert!(p.load_persisted_failures2(UNREL_PATH).is_empty()); } } �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/test_runner/mod.rs���������������������������������������������������������������0000644�0000000�0000000�00000001572�10461020230�0016001�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! State and functions for running proptest tests. //! //! You do not normally need to access things in this module directly except //! when implementing new low-level strategies. mod config; mod errors; mod failure_persistence; mod reason; #[cfg(feature = "fork")] mod replay; mod result_cache; mod rng; mod runner; mod scoped_panic_hook; pub use self::config::*; pub use self::errors::*; pub use self::failure_persistence::*; pub use self::reason::*; pub use self::result_cache::*; pub use self::rng::*; pub use self::runner::*; ��������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/test_runner/reason.rs������������������������������������������������������������0000644�0000000�0000000�00000002736�10461020230�0016514�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<str>`. #[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<String> for Reason { fn from(s: String) -> Self { Reason(s.into()) } } impl From<Box<str>> for Reason { fn from(s: Box<str>) -> 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) } } ����������������������������������proptest-1.6.0/src/test_runner/replay.rs������������������������������������������������������������0000644�0000000�0000000�00000014771�10461020230�0016523�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![allow(dead_code)] use std::fs; use std::io::{self, BufRead, Read, Seek, Write}; use std::path::Path; use std::string::String; use std::vec::Vec; use crate::test_runner::{Seed, TestCaseError, TestCaseResult}; const SENTINEL: &'static str = "proptest-forkfile"; /// A "replay" of a `TestRunner` invocation. /// /// The replay mechanism is used to support forking. When a child process /// exits, the parent can read the replay to reproduce the state the child had; /// similarly, if a child crashes, a new one can be started and given a replay /// which steps it one complication past the input that caused the crash. /// /// The replay system is tightly coupled to the `TestRunner` itself. It does /// not carry enough information to be used in different builds of the same /// application, or even two different runs of the test process since changes /// to the persistence file will perturb the replay. /// /// `Replay` has a special string format for being stored in files. It starts /// with a line just containing the text in `SENTINEL`, then 16 lines /// containing the values of `seed`, then an unterminated line consisting of /// `+`, `-`, and `!` characters to indicate test case passes/failures/rejects, /// `.` to indicate termination of the test run, or ` ` as a dummy "I'm alive" /// signal. This format makes it easy for the child process to blindly append /// to the file without having to worry about the possibility of appends being /// non-atomic. #[derive(Clone, Debug)] pub(crate) struct Replay { /// The seed of the RNG used to start running the test cases. pub(crate) seed: Seed, /// A log of whether certain test cases passed or failed. The runner will /// assume the same results occur without actually running the test cases. pub(crate) steps: Vec<TestCaseResult>, } impl Replay { /// If `other` is longer than `self`, add the extra elements to `self`. pub fn merge(&mut self, other: &Replay) { if other.steps.len() > self.steps.len() { let sl = self.steps.len(); self.steps.extend_from_slice(&other.steps[sl..]); } } } /// Result of loading a replay file. #[derive(Clone, Debug)] pub(crate) enum ReplayFileStatus { /// The file is valid and represents a currently-in-progress test. InProgress(Replay), /// The file is valid, but indicates that all testing has completed. Terminated(Replay), /// The file is not parsable. Corrupt, } /// Open the file in the usual read+append+create mode. pub(crate) fn open_file(path: impl AsRef<Path>) -> io::Result<fs::File> { fs::OpenOptions::new() .read(true) .append(true) .create(true) .truncate(false) .open(path) } fn step_to_char(step: &TestCaseResult) -> char { match *step { Ok(_) => '+', Err(TestCaseError::Reject(_)) => '!', Err(TestCaseError::Fail(_)) => '-', } } /// Append the given step to the given output. pub(crate) fn append( mut file: impl Write, step: &TestCaseResult, ) -> io::Result<()> { write!(file, "{}", step_to_char(step)) } /// Append a no-op step to the given output. pub(crate) fn ping(mut file: impl Write) -> io::Result<()> { write!(file, " ") } /// Append a termination mark to the given output. pub(crate) fn terminate(mut file: impl Write) -> io::Result<()> { write!(file, ".") } impl Replay { /// Write the full state of this `Replay` to the given output. pub fn init_file(&self, mut file: impl Write) -> io::Result<()> { writeln!(file, "{}", SENTINEL)?; writeln!(file, "{}", self.seed.to_persistence())?; let mut step_data = Vec::<u8>::new(); for step in &self.steps { step_data.push(step_to_char(step) as u8); } file.write_all(&step_data)?; Ok(()) } /// Mark the replay as complete in the file. pub fn complete(mut file: impl Write) -> io::Result<()> { write!(file, ".") } /// Parse a `Replay` out of the given file. /// /// The reader is implicitly seeked to the beginning before reading. pub fn parse_from( mut file: impl Read + Seek, ) -> io::Result<ReplayFileStatus> { file.seek(io::SeekFrom::Start(0))?; let mut reader = io::BufReader::new(&mut file); let mut line = String::new(); // Ensure it starts with the sentinel. We do this since we rely on a // named temporary file which could be in a location where another // actor could replace it with, eg, a symlink to a location they don't // control but we do. By rejecting a read from a file missing the // sentinel, and not doing any writes if we can't read the file, we // won't risk overwriting another file since the prospective attacker // would need to be able to change the file to start with the sentinel // themselves. // // There are still some possible symlink attacks that can work by // tricking us into reading, but those are non-destructive things like // interfering with a FIFO or Unix socket. reader.read_line(&mut line)?; if SENTINEL != line.trim() { return Ok(ReplayFileStatus::Corrupt); } line.clear(); reader.read_line(&mut line)?; let seed = match Seed::from_persistence(&line) { Some(seed) => seed, None => return Ok(ReplayFileStatus::Corrupt), }; line.clear(); reader.read_line(&mut line)?; let mut steps = Vec::new(); for ch in line.chars() { match ch { '+' => steps.push(Ok(())), '-' => steps .push(Err(TestCaseError::fail("failed in other process"))), '!' => steps.push(Err(TestCaseError::reject( "rejected in other process", ))), '.' => { return Ok(ReplayFileStatus::Terminated(Replay { seed, steps, })) } ' ' => (), _ => return Ok(ReplayFileStatus::Corrupt), } } Ok(ReplayFileStatus::InProgress(Replay { seed, steps })) } } �������proptest-1.6.0/src/test_runner/result_cache.rs������������������������������������������������������0000644�0000000�0000000�00000007337�10461020230�0017670�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::fmt; use crate::std_facade::Box; #[cfg(feature = "std")] use std::collections::HashMap; use crate::test_runner::errors::TestCaseResult; /// A key used for the result cache. /// /// The capabilities of this structure are currently quite limited; all one can /// do with safe code is get the `&dyn Debug` of the test input value. This may /// improve in the future, particularly at such a time that specialisation /// becomes stable. #[derive(Debug)] pub struct ResultCacheKey<'a> { value: &'a dyn fmt::Debug, } impl<'a> ResultCacheKey<'a> { pub(crate) fn new(value: &'a dyn fmt::Debug) -> Self { Self { value } } /// Return the test input value as an `&dyn Debug`. pub fn value_debug(&self) -> &dyn fmt::Debug { self.value } } /// An object which can cache the outcomes of tests. pub trait ResultCache { /// Convert the given cache key into a `u64` representing that value. The /// u64 is used as the key below. /// /// This is a separate step so that ownership of the key value can be /// handed off to user code without needing to be able to clone it. fn key(&self, key: &ResultCacheKey) -> u64; /// Save `result` as the outcome associated with the test input in `key`. /// /// `result` is passed as a reference so that the decision to clone depends /// on whether the cache actually plans on storing it. fn put(&mut self, key: u64, result: &TestCaseResult); /// If `put()` has been called with a semantically equivalent `key`, return /// the saved result. Otherwise, return `None`. fn get(&self, key: u64) -> Option<&TestCaseResult>; } #[cfg(feature = "std")] #[derive(Debug, Default, Clone)] struct BasicResultCache { entries: HashMap<u64, TestCaseResult>, } #[cfg(feature = "std")] impl ResultCache for BasicResultCache { fn key(&self, val: &ResultCacheKey) -> u64 { use std::collections::hash_map::DefaultHasher; use std::hash::Hasher; use std::io::{self, Write}; struct HashWriter(DefaultHasher); impl io::Write for HashWriter { fn write(&mut self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf); Ok(buf.len()) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } let mut hash = HashWriter(DefaultHasher::default()); write!(hash, "{:?}", val).expect("Debug format returned Err"); hash.0.finish() } fn put(&mut self, key: u64, result: &TestCaseResult) { self.entries.insert(key, result.clone()); } fn get(&self, key: u64) -> Option<&TestCaseResult> { self.entries.get(&key) } } /// A basic result cache. /// /// Values are identified by their `Debug` string representation. #[cfg(feature = "std")] #[cfg_attr(docsrs, doc(cfg(feature = "std")))] pub fn basic_result_cache() -> Box<dyn ResultCache> { Box::new(BasicResultCache::default()) } pub(crate) struct NoOpResultCache; impl ResultCache for NoOpResultCache { fn key(&self, _: &ResultCacheKey) -> u64 { 0 } fn put(&mut self, _: u64, _: &TestCaseResult) {} fn get(&self, _: u64) -> Option<&TestCaseResult> { None } } /// A result cache that does nothing. /// /// This is the default value of `ProptestConfig.result_cache`. pub fn noop_result_cache() -> Box<dyn ResultCache> { Box::new(NoOpResultCache) } �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/test_runner/rng.rs���������������������������������������������������������������0000644�0000000�0000000�00000060536�10461020230�0016015�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018, 2019, 2020 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::{Arc, String, ToOwned, Vec}; use core::result::Result; use core::{fmt, str, u8, convert::TryInto}; use rand::{self, Rng, RngCore, SeedableRng}; use rand_chacha::ChaChaRng; use rand_xorshift::XorShiftRng; /// Identifies a particular RNG algorithm supported by proptest. /// /// Proptest supports dynamic configuration of algorithms to allow it to /// continue operating with persisted regression files and to allow the /// configuration to be expressed in the `Config` struct. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum RngAlgorithm { /// The [XorShift](https://rust-random.github.io/rand/rand_xorshift/struct.XorShiftRng.html) /// algorithm. This was the default up through and including Proptest 0.9.0. /// /// It is faster than ChaCha but produces lower quality randomness and has /// some pathological cases where it may fail to produce outputs that are /// random even to casual observation. /// /// The seed must be exactly 16 bytes. XorShift, /// The [ChaCha](https://rust-random.github.io/rand/rand_chacha/struct.ChaChaRng.html) /// algorithm. This became the default with Proptest 0.9.1. /// /// The seed must be exactly 32 bytes. ChaCha, /// This is not an actual RNG algorithm, but instead returns data directly /// from its "seed". /// /// This is useful when Proptest is being driven from some other entropy /// source, such as a fuzzer. /// /// If the seed is depleted, the RNG will return 0s forever. /// /// Note that in cases where a new RNG is to be derived from an existing /// one, *the data is split evenly between them*, regardless of how much /// entropy is actually needed. This means that combinators like /// `prop_perturb` and `prop_flat_map` can require extremely large inputs. PassThrough, /// This is equivalent to the `ChaCha` RNG, with the addition that it /// records the bytes used to create a value. /// /// This is useful when Proptest is used for fuzzing, and a corpus of /// initial inputs need to be created. Note that in these cases, you need /// to use the `TestRunner` API directly yourself instead of using the /// `proptest!` macro, as otherwise there is no way to obtain the bytes /// this captures. Recorder, #[allow(missing_docs)] #[doc(hidden)] _NonExhaustive, } impl Default for RngAlgorithm { fn default() -> Self { RngAlgorithm::ChaCha } } impl RngAlgorithm { pub(crate) fn persistence_key(self) -> &'static str { match self { RngAlgorithm::XorShift => "xs", RngAlgorithm::ChaCha => "cc", RngAlgorithm::PassThrough => "pt", RngAlgorithm::Recorder => "rc", RngAlgorithm::_NonExhaustive => unreachable!(), } } pub(crate) fn from_persistence_key(k: &str) -> Option<Self> { match k { "xs" => Some(RngAlgorithm::XorShift), "cc" => Some(RngAlgorithm::ChaCha), "pt" => Some(RngAlgorithm::PassThrough), "rc" => Some(RngAlgorithm::Recorder), _ => None, } } } // These two are only used for parsing the environment variable // PROPTEST_RNG_ALGORITHM. impl str::FromStr for RngAlgorithm { type Err = (); fn from_str(s: &str) -> Result<Self, ()> { RngAlgorithm::from_persistence_key(s).ok_or(()) } } impl fmt::Display for RngAlgorithm { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.persistence_key()) } } /// Proptest's random number generator. #[derive(Clone, Debug)] pub struct TestRng { rng: TestRngImpl, } #[derive(Clone, Debug)] enum TestRngImpl { XorShift(XorShiftRng), ChaCha(ChaChaRng), PassThrough { off: usize, end: usize, data: Arc<[u8]>, }, Recorder { rng: ChaChaRng, record: Vec<u8>, }, } impl RngCore for TestRng { fn next_u32(&mut self) -> u32 { match &mut self.rng { &mut TestRngImpl::XorShift(ref mut rng) => rng.next_u32(), &mut TestRngImpl::ChaCha(ref mut rng) => rng.next_u32(), &mut TestRngImpl::PassThrough { .. } => { let mut buf = [0; 4]; self.fill_bytes(&mut buf[..]); u32::from_le_bytes(buf) } &mut TestRngImpl::Recorder { ref mut rng, ref mut record, } => { let read = rng.next_u32(); record.extend_from_slice(&read.to_le_bytes()); read } } } fn next_u64(&mut self) -> u64 { match &mut self.rng { &mut TestRngImpl::XorShift(ref mut rng) => rng.next_u64(), &mut TestRngImpl::ChaCha(ref mut rng) => rng.next_u64(), &mut TestRngImpl::PassThrough { .. } => { let mut buf = [0; 8]; self.fill_bytes(&mut buf[..]); u64::from_le_bytes(buf) } &mut TestRngImpl::Recorder { ref mut rng, ref mut record, } => { let read = rng.next_u64(); record.extend_from_slice(&read.to_le_bytes()); read } } } fn fill_bytes(&mut self, dest: &mut [u8]) { match &mut self.rng { &mut TestRngImpl::XorShift(ref mut rng) => rng.fill_bytes(dest), &mut TestRngImpl::ChaCha(ref mut rng) => rng.fill_bytes(dest), &mut TestRngImpl::PassThrough { ref mut off, end, ref data, } => { let bytes_to_copy = dest.len().min(end - *off); dest[..bytes_to_copy] .copy_from_slice(&data[*off..*off + bytes_to_copy]); *off += bytes_to_copy; for i in bytes_to_copy..dest.len() { dest[i] = 0; } } &mut TestRngImpl::Recorder { ref mut rng, ref mut record, } => { let res = rng.fill_bytes(dest); record.extend_from_slice(&dest); res } } } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { match self.rng { TestRngImpl::XorShift(ref mut rng) => rng.try_fill_bytes(dest), TestRngImpl::ChaCha(ref mut rng) => rng.try_fill_bytes(dest), TestRngImpl::PassThrough { .. } => { self.fill_bytes(dest); Ok(()) } TestRngImpl::Recorder { ref mut rng, ref mut record, } => { let res = rng.try_fill_bytes(dest); if res.is_ok() { record.extend_from_slice(&dest); } res } } } } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] pub(crate) enum Seed { XorShift([u8; 16]), ChaCha([u8; 32]), PassThrough(Option<(usize, usize)>, Arc<[u8]>), Recorder([u8; 32]), } impl Seed { pub(crate) fn from_bytes(algorithm: RngAlgorithm, seed: &[u8]) -> Self { match algorithm { RngAlgorithm::XorShift => { assert_eq!(16, seed.len(), "XorShift requires a 16-byte seed"); let mut buf = [0; 16]; buf.copy_from_slice(seed); Seed::XorShift(buf) } RngAlgorithm::ChaCha => { assert_eq!(32, seed.len(), "ChaCha requires a 32-byte seed"); let mut buf = [0; 32]; buf.copy_from_slice(seed); Seed::ChaCha(buf) } RngAlgorithm::PassThrough => Seed::PassThrough(None, seed.into()), RngAlgorithm::Recorder => { assert_eq!(32, seed.len(), "Recorder requires a 32-byte seed"); let mut buf = [0; 32]; buf.copy_from_slice(seed); Seed::Recorder(buf) } RngAlgorithm::_NonExhaustive => unreachable!(), } } pub(crate) fn from_persistence(string: &str) -> Option<Seed> { fn from_base16(dst: &mut [u8], src: &str) -> Option<()> { if dst.len() * 2 != src.len() { return None; } for (dst_byte, src_pair) in dst.into_iter().zip(src.as_bytes().chunks(2)) { *dst_byte = u8::from_str_radix(str::from_utf8(src_pair).ok()?, 16) .ok()?; } Some(()) } let parts = string.trim().split(char::is_whitespace).collect::<Vec<_>>(); RngAlgorithm::from_persistence_key(&parts[0]).and_then( |alg| match alg { RngAlgorithm::XorShift => { if 5 != parts.len() { return None; } let mut dwords = [0u32; 4]; for (dword, part) in (&mut dwords[..]).into_iter().zip(&parts[1..]) { *dword = part.parse().ok()?; } let mut seed = [0u8; 16]; for (chunk, dword) in seed.chunks_mut(4).zip(dwords) { chunk.copy_from_slice(&dword.to_le_bytes()); } Some(Seed::XorShift(seed)) } RngAlgorithm::ChaCha => { if 2 != parts.len() { return None; } let mut seed = [0u8; 32]; from_base16(&mut seed, &parts[1])?; Some(Seed::ChaCha(seed)) } RngAlgorithm::PassThrough => { if 1 == parts.len() { return Some(Seed::PassThrough(None, vec![].into())); } if 2 != parts.len() { return None; } let mut seed = vec![0u8; parts[1].len() / 2]; from_base16(&mut seed, &parts[1])?; Some(Seed::PassThrough(None, seed.into())) } RngAlgorithm::Recorder => { if 2 != parts.len() { return None; } let mut seed = [0u8; 32]; from_base16(&mut seed, &parts[1])?; Some(Seed::Recorder(seed)) } RngAlgorithm::_NonExhaustive => unreachable!(), }, ) } pub(crate) fn to_persistence(&self) -> String { fn to_base16(dst: &mut String, src: &[u8]) { for byte in src { dst.push_str(&format!("{:02x}", byte)); } } match *self { Seed::XorShift(ref seed) => { let dwords = [ u32::from_le_bytes(seed[0..4].try_into().unwrap()), u32::from_le_bytes(seed[4..8].try_into().unwrap()), u32::from_le_bytes(seed[8..12].try_into().unwrap()), u32::from_le_bytes(seed[12..16].try_into().unwrap()), ]; format!( "{} {} {} {} {}", RngAlgorithm::XorShift.persistence_key(), dwords[0], dwords[1], dwords[2], dwords[3] ) } Seed::ChaCha(ref seed) => { let mut string = RngAlgorithm::ChaCha.persistence_key().to_owned(); string.push(' '); to_base16(&mut string, seed); string } Seed::PassThrough(bounds, ref data) => { let data = bounds.map_or(&data[..], |(start, end)| &data[start..end]); let mut string = RngAlgorithm::PassThrough.persistence_key().to_owned(); string.push(' '); to_base16(&mut string, data); string } Seed::Recorder(ref seed) => { let mut string = RngAlgorithm::Recorder.persistence_key().to_owned(); string.push(' '); to_base16(&mut string, seed); string } } } } impl TestRng { /// Create a new RNG with the given algorithm and seed. /// /// Any RNG created with the same algorithm-seed pair will produce the same /// sequence of values on all systems and all supporting versions of /// proptest. /// /// ## Panics /// /// Panics if `seed` is not an appropriate length for `algorithm`. pub fn from_seed(algorithm: RngAlgorithm, seed: &[u8]) -> Self { TestRng::from_seed_internal(Seed::from_bytes(algorithm, seed)) } /// Dumps the bytes obtained from the RNG so far (only works if the RNG is /// set to `Recorder`). /// /// ## Panics /// /// Panics if this RNG does not capture generated data. pub fn bytes_used(&self) -> Vec<u8> { match self.rng { TestRngImpl::Recorder { ref record, .. } => record.clone(), _ => panic!("bytes_used() called on non-Recorder RNG"), } } /// Construct a default TestRng from entropy. pub(crate) fn default_rng(algorithm: RngAlgorithm) -> Self { #[cfg(feature = "std")] { Self { rng: match algorithm { RngAlgorithm::XorShift => { TestRngImpl::XorShift(XorShiftRng::from_entropy()) } RngAlgorithm::ChaCha => { TestRngImpl::ChaCha(ChaChaRng::from_entropy()) } RngAlgorithm::PassThrough => { panic!("cannot create default instance of PassThrough") } RngAlgorithm::Recorder => TestRngImpl::Recorder { rng: ChaChaRng::from_entropy(), record: Vec::new(), }, RngAlgorithm::_NonExhaustive => unreachable!(), }, } } #[cfg(all( not(feature = "std"), any(target_arch = "x86", target_arch = "x86_64"), feature = "hardware-rng" ))] { return Self::hardware_rng(algorithm); } #[cfg(not(feature = "std"))] { return Self::deterministic_rng(algorithm); } } const SEED_FOR_XOR_SHIFT: [u8; 16] = [ 0xf4, 0x16, 0x16, 0x48, 0xc3, 0xac, 0x77, 0xac, 0x72, 0x20, 0x0b, 0xea, 0x99, 0x67, 0x2d, 0x6d, ]; const SEED_FOR_CHA_CHA: [u8; 32] = [ 0xf4, 0x16, 0x16, 0x48, 0xc3, 0xac, 0x77, 0xac, 0x72, 0x20, 0x0b, 0xea, 0x99, 0x67, 0x2d, 0x6d, 0xca, 0x9f, 0x76, 0xaf, 0x1b, 0x09, 0x73, 0xa0, 0x59, 0x22, 0x6d, 0xc5, 0x46, 0x39, 0x1c, 0x4a, ]; /// Returns a `TestRng` with a seed generated with the /// RdRand instruction on x86 machines. /// /// This is useful in `no_std` scenarios on x86 where we don't /// have a random number infrastructure but the `rdrand` instruction is /// available. #[cfg(all( not(feature = "std"), any(target_arch = "x86", target_arch = "x86_64"), feature = "hardware-rng" ))] pub fn hardware_rng(algorithm: RngAlgorithm) -> Self { use x86::random::{rdrand_slice, RdRand}; Self::from_seed_internal(match algorithm { RngAlgorithm::XorShift => { // Initialize to a sane seed just in case let mut seed: [u8; 16] = TestRng::SEED_FOR_XOR_SHIFT; unsafe { let r = rdrand_slice(&mut seed); debug_assert!(r, "hardware_rng should only be called on machines with support for rdrand"); } Seed::XorShift(seed) } RngAlgorithm::ChaCha => { // Initialize to a sane seed just in case let mut seed: [u8; 32] = TestRng::SEED_FOR_CHA_CHA; unsafe { let r = rdrand_slice(&mut seed); debug_assert!(r, "hardware_rng should only be called on machines with support for rdrand"); } Seed::ChaCha(seed) } RngAlgorithm::PassThrough => { panic!("deterministic RNG not available for PassThrough") } RngAlgorithm::Recorder => { // Initialize to a sane seed just in case let mut seed: [u8; 32] = TestRng::SEED_FOR_CHA_CHA; unsafe { let r = rdrand_slice(&mut seed); debug_assert!(r, "hardware_rng should only be called on machines with support for rdrand"); } Seed::Recorder(seed) } RngAlgorithm::_NonExhaustive => unreachable!(), }) } /// Returns a `TestRng` with a particular hard-coded seed. /// /// The seed value will always be the same for a particular version of /// Proptest and algorithm, but may change across releases. /// /// This is useful for testing things like strategy implementations without /// risking getting "unlucky" RNGs which deviate from average behaviour /// enough to cause spurious failures. For example, a strategy for `bool` /// which is supposed to produce `true` 50% of the time might have a test /// which checks that the distribution is "close enough" to 50%. If every /// test run starts with a different RNG, occasionally there will be /// spurious test failures when the RNG happens to produce a very skewed /// distribution. Using this or `TestRunner::deterministic()` avoids such /// issues. pub fn deterministic_rng(algorithm: RngAlgorithm) -> Self { Self::from_seed_internal(match algorithm { RngAlgorithm::XorShift => { Seed::XorShift(TestRng::SEED_FOR_XOR_SHIFT) } RngAlgorithm::ChaCha => Seed::ChaCha(TestRng::SEED_FOR_CHA_CHA), RngAlgorithm::PassThrough => { panic!("deterministic RNG not available for PassThrough") } RngAlgorithm::Recorder => Seed::Recorder(TestRng::SEED_FOR_CHA_CHA), RngAlgorithm::_NonExhaustive => unreachable!(), }) } /// Construct a TestRng by the perturbed randomized seed /// from an existing TestRng. pub(crate) fn gen_rng(&mut self) -> Self { Self::from_seed_internal(self.new_rng_seed()) } /// Overwrite the given TestRng with the provided seed. pub(crate) fn set_seed(&mut self, seed: Seed) { *self = Self::from_seed_internal(seed); } /// Generate a new randomized seed, set it to this TestRng, /// and return the seed. pub(crate) fn gen_get_seed(&mut self) -> Seed { let seed = self.new_rng_seed(); self.set_seed(seed.clone()); seed } /// Randomize a perturbed randomized seed from the given TestRng. pub(crate) fn new_rng_seed(&mut self) -> Seed { match self.rng { TestRngImpl::XorShift(ref mut rng) => { let mut seed = rng.gen::<[u8; 16]>(); // Directly using XorShiftRng::from_seed() at this point would // result in rng and the returned value being exactly the same. // Perturb the seed with some arbitrary values to prevent this. for word in seed.chunks_mut(4) { word[3] ^= 0xde; word[2] ^= 0xad; word[1] ^= 0xbe; word[0] ^= 0xef; } Seed::XorShift(seed) } TestRngImpl::ChaCha(ref mut rng) => Seed::ChaCha(rng.gen()), TestRngImpl::PassThrough { ref mut off, ref mut end, ref data, } => { let len = *end - *off; let child_start = *off + len / 2; let child_end = *off + len; *end = child_start; Seed::PassThrough( Some((child_start, child_end)), Arc::clone(data), ) } TestRngImpl::Recorder { ref mut rng, .. } => { Seed::Recorder(rng.gen()) } } } /// Construct a TestRng from a given seed. fn from_seed_internal(seed: Seed) -> Self { Self { rng: match seed { Seed::XorShift(seed) => { TestRngImpl::XorShift(XorShiftRng::from_seed(seed)) } Seed::ChaCha(seed) => { TestRngImpl::ChaCha(ChaChaRng::from_seed(seed)) } Seed::PassThrough(bounds, data) => { let (start, end) = bounds.unwrap_or((0, data.len())); TestRngImpl::PassThrough { off: start, end, data, } } Seed::Recorder(seed) => TestRngImpl::Recorder { rng: ChaChaRng::from_seed(seed), record: Vec::new(), }, }, } } } #[cfg(test)] mod test { use crate::std_facade::Vec; use rand::{Rng, RngCore}; use super::{RngAlgorithm, Seed, TestRng}; use crate::arbitrary::any; use crate::strategy::*; proptest! { #[test] fn gen_parse_seeds( seed in prop_oneof![ any::<[u8;16]>().prop_map(Seed::XorShift), any::<[u8;32]>().prop_map(Seed::ChaCha), any::<Vec<u8>>().prop_map(|data| Seed::PassThrough(None, data.into())), any::<[u8;32]>().prop_map(Seed::Recorder), ]) { assert_eq!(seed, Seed::from_persistence(&seed.to_persistence()).unwrap()); } #[test] fn rngs_dont_clone_self_on_genrng( seed in prop_oneof![ any::<[u8;16]>().prop_map(Seed::XorShift), any::<[u8;32]>().prop_map(Seed::ChaCha), Just(()).prop_perturb(|_, mut rng| { let mut buf = vec![0u8; 2048]; rng.fill_bytes(&mut buf); Seed::PassThrough(None, buf.into()) }), any::<[u8;32]>().prop_map(Seed::Recorder), ]) { type Value = [u8;32]; let orig = TestRng::from_seed_internal(seed); { let mut rng1 = orig.clone(); let mut rng2 = rng1.gen_rng(); assert_ne!(rng1.gen::<Value>(), rng2.gen::<Value>()); } { let mut rng1 = orig.clone(); let mut rng2 = rng1.gen_rng(); let mut rng3 = rng1.gen_rng(); let mut rng4 = rng2.gen_rng(); let a = rng1.gen::<Value>(); let b = rng2.gen::<Value>(); let c = rng3.gen::<Value>(); let d = rng4.gen::<Value>(); assert_ne!(a, b); assert_ne!(a, c); assert_ne!(a, d); assert_ne!(b, c); assert_ne!(b, d); assert_ne!(c, d); } } } #[test] fn passthrough_rng_behaves_properly() { let mut rng = TestRng::from_seed( RngAlgorithm::PassThrough, &[ 0xDE, 0xC0, 0x12, 0x34, 0x56, 0x78, 0xFE, 0xCA, 0xEF, 0xBE, 0xAD, 0xDE, 0x01, 0x02, 0x03, ], ); assert_eq!(0x3412C0DE, rng.next_u32()); assert_eq!(0xDEADBEEFCAFE7856, rng.next_u64()); let mut buf = [0u8; 4]; rng.try_fill_bytes(&mut buf[0..4]).unwrap(); assert_eq!([1, 2, 3, 0], buf); rng.try_fill_bytes(&mut buf[0..4]).unwrap(); assert_eq!([0, 0, 0, 0], buf); } } ������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/test_runner/runner.rs������������������������������������������������������������0000644�0000000�0000000�00000142406�10461020230�0016535�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017, 2018, 2019, 2024 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. use crate::std_facade::{Arc, BTreeMap, Box, String, Vec}; use core::sync::atomic::AtomicUsize; use core::sync::atomic::Ordering::SeqCst; use core::{fmt, iter}; #[cfg(feature = "std")] use std::panic::{self, AssertUnwindSafe}; #[cfg(feature = "fork")] use rusty_fork; #[cfg(feature = "fork")] use std::cell::{Cell, RefCell}; #[cfg(feature = "fork")] use std::env; #[cfg(feature = "fork")] use std::fs; #[cfg(feature = "fork")] use tempfile; use crate::strategy::*; use crate::test_runner::config::*; use crate::test_runner::errors::*; use crate::test_runner::failure_persistence::PersistedSeed; use crate::test_runner::reason::*; #[cfg(feature = "fork")] use crate::test_runner::replay; use crate::test_runner::result_cache::*; use crate::test_runner::rng::TestRng; #[cfg(feature = "fork")] const ENV_FORK_FILE: &'static str = "_PROPTEST_FORKFILE"; const ALWAYS: u32 = 0; /// Verbose level 1 to show failures. In state machine tests this level is used /// to print transitions. pub const INFO_LOG: u32 = 1; const TRACE: u32 = 2; #[cfg(feature = "std")] macro_rules! verbose_message { ($runner:expr, $level:expr, $fmt:tt $($arg:tt)*) => { { #[allow(unused_comparisons)] { if $runner.config.verbose >= $level { eprintln!(concat!("proptest: ", $fmt) $($arg)*); } }; () } } } #[cfg(not(feature = "std"))] macro_rules! verbose_message { ($runner:expr, $level:expr, $fmt:tt $($arg:tt)*) => { let _ = $level; }; } type RejectionDetail = BTreeMap<Reason, u32>; /// State used when running a proptest test. #[derive(Clone)] pub struct TestRunner { config: Config, successes: u32, local_rejects: u32, global_rejects: u32, rng: TestRng, flat_map_regens: Arc<AtomicUsize>, local_reject_detail: RejectionDetail, global_reject_detail: RejectionDetail, } impl fmt::Debug for TestRunner { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("TestRunner") .field("config", &self.config) .field("successes", &self.successes) .field("local_rejects", &self.local_rejects) .field("global_rejects", &self.global_rejects) .field("rng", &"<TestRng>") .field("flat_map_regens", &self.flat_map_regens) .field("local_reject_detail", &self.local_reject_detail) .field("global_reject_detail", &self.global_reject_detail) .finish() } } impl fmt::Display for TestRunner { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!( f, "\tsuccesses: {}\n\ \tlocal rejects: {}\n", self.successes, self.local_rejects )?; for (whence, count) in &self.local_reject_detail { writeln!(f, "\t\t{} times at {}", count, whence)?; } writeln!(f, "\tglobal rejects: {}", self.global_rejects)?; for (whence, count) in &self.global_reject_detail { writeln!(f, "\t\t{} times at {}", count, whence)?; } Ok(()) } } /// Equivalent to: `TestRunner::new(Config::default())`. impl Default for TestRunner { fn default() -> Self { Self::new(Config::default()) } } #[cfg(feature = "fork")] #[derive(Debug)] struct ForkOutput { file: Option<fs::File>, } #[cfg(feature = "fork")] impl ForkOutput { fn append(&mut self, result: &TestCaseResult) { if let Some(ref mut file) = self.file { replay::append(file, result) .expect("Failed to append to replay file"); } } fn ping(&mut self) { if let Some(ref mut file) = self.file { replay::ping(file).expect("Failed to append to replay file"); } } fn terminate(&mut self) { if let Some(ref mut file) = self.file { replay::terminate(file).expect("Failed to append to replay file"); } } fn empty() -> Self { ForkOutput { file: None } } fn is_in_fork(&self) -> bool { self.file.is_some() } } #[cfg(not(feature = "fork"))] #[derive(Debug)] struct ForkOutput; #[cfg(not(feature = "fork"))] impl ForkOutput { fn append(&mut self, _result: &TestCaseResult) {} fn ping(&mut self) {} fn terminate(&mut self) {} fn empty() -> Self { ForkOutput } fn is_in_fork(&self) -> bool { false } } #[cfg(not(feature = "std"))] fn call_test<V, F, R>( _runner: &mut TestRunner, case: V, test: &F, replay_from_fork: &mut R, result_cache: &mut dyn ResultCache, _: &mut ForkOutput, is_from_persisted_seed: bool, ) -> TestCaseResultV2 where V: fmt::Debug, F: Fn(V) -> TestCaseResult, R: Iterator<Item = TestCaseResult>, { if let Some(result) = replay_from_fork.next() { return result.map(|_| TestCaseOk::ReplayFromForkSuccess); } let cache_key = result_cache.key(&ResultCacheKey::new(&case)); if let Some(result) = result_cache.get(cache_key) { return result.clone().map(|_| TestCaseOk::CacheHitSuccess); } let result = test(case); result_cache.put(cache_key, &result); result.map(|_| { if is_from_persisted_seed { TestCaseOk::PersistedCaseSuccess } else { TestCaseOk::NewCaseSuccess } }) } #[cfg(feature = "std")] fn call_test<V, F, R>( runner: &mut TestRunner, case: V, test: &F, replay_from_fork: &mut R, result_cache: &mut dyn ResultCache, fork_output: &mut ForkOutput, is_from_persisted_seed: bool, ) -> TestCaseResultV2 where V: fmt::Debug, F: Fn(V) -> TestCaseResult, R: Iterator<Item = TestCaseResult>, { #[cfg(feature = "timeout")] let timeout = runner.config.timeout(); if let Some(result) = replay_from_fork.next() { return result.map(|_| TestCaseOk::ReplayFromForkSuccess); } // Now that we're about to start a new test (as far as the replay system is // concerned), ping the replay file so the parent process can determine // that we made it this far. fork_output.ping(); verbose_message!(runner, TRACE, "Next test input: {:?}", case); let cache_key = result_cache.key(&ResultCacheKey::new(&case)); if let Some(result) = result_cache.get(cache_key) { verbose_message!( runner, TRACE, "Test input hit cache, skipping execution" ); return result.clone().map(|_| TestCaseOk::CacheHitSuccess); } #[cfg(feature = "timeout")] let time_start = std::time::Instant::now(); let mut result = unwrap_or!( super::scoped_panic_hook::with_hook( |_| { /* Silence out panic backtrace */ }, || panic::catch_unwind(AssertUnwindSafe(|| test(case))) ), what => Err(TestCaseError::Fail( what.downcast::<&'static str>().map(|s| (*s).into()) .or_else(|what| what.downcast::<String>().map(|b| (*b).into())) .or_else(|what| what.downcast::<Box<str>>().map(|b| (*b).into())) .unwrap_or_else(|_| "<unknown panic value>".into())))); // If there is a timeout and we exceeded it, fail the test here so we get // consistent behaviour. (The parent process cannot precisely time the test // cases itself.) #[cfg(feature = "timeout")] if timeout > 0 && result.is_ok() { let elapsed = time_start.elapsed(); let elapsed_millis = elapsed.as_secs() as u32 * 1000 + elapsed.subsec_nanos() / 1_000_000; if elapsed_millis > timeout { result = Err(TestCaseError::fail(format!( "Timeout of {} ms exceeded: test took {} ms", timeout, elapsed_millis ))); } } result_cache.put(cache_key, &result); fork_output.append(&result); match result { Ok(()) => verbose_message!(runner, TRACE, "Test case passed"), Err(TestCaseError::Reject(ref reason)) => { verbose_message!(runner, INFO_LOG, "Test case rejected: {}", reason) } Err(TestCaseError::Fail(ref reason)) => { verbose_message!(runner, INFO_LOG, "Test case failed: {}", reason) } } result.map(|_| { if is_from_persisted_seed { TestCaseOk::PersistedCaseSuccess } else { TestCaseOk::NewCaseSuccess } }) } type TestRunResult<S> = Result<(), TestError<<S as Strategy>::Value>>; impl TestRunner { /// Create a fresh `TestRunner` with the given configuration. /// /// The runner will use an RNG with a generated seed and the default /// algorithm. /// /// In `no_std` environments, every `TestRunner` will use the same /// hard-coded seed. This seed is not contractually guaranteed and may be /// changed between releases without notice. pub fn new(config: Config) -> Self { let algorithm = config.rng_algorithm; TestRunner::new_with_rng(config, TestRng::default_rng(algorithm)) } /// Create a fresh `TestRunner` with the standard deterministic RNG. /// /// This is sugar for the following: /// /// ```rust /// # use proptest::test_runner::*; /// let config = Config::default(); /// let algorithm = config.rng_algorithm; /// TestRunner::new_with_rng( /// config, /// TestRng::deterministic_rng(algorithm)); /// ``` /// /// Refer to `TestRng::deterministic_rng()` for more information on the /// properties of the RNG used here. pub fn deterministic() -> Self { let config = Config::default(); let algorithm = config.rng_algorithm; TestRunner::new_with_rng(config, TestRng::deterministic_rng(algorithm)) } /// Create a fresh `TestRunner` with the given configuration and RNG. pub fn new_with_rng(config: Config, rng: TestRng) -> Self { TestRunner { config: config, successes: 0, local_rejects: 0, global_rejects: 0, rng: rng, flat_map_regens: Arc::new(AtomicUsize::new(0)), local_reject_detail: BTreeMap::new(), global_reject_detail: BTreeMap::new(), } } /// Create a fresh `TestRunner` with the same config and global counters as /// this one, but with local state reset and an independent `Rng` (but /// deterministic). pub(crate) fn partial_clone(&mut self) -> Self { TestRunner { config: self.config.clone(), successes: 0, local_rejects: 0, global_rejects: 0, rng: self.new_rng(), flat_map_regens: Arc::clone(&self.flat_map_regens), local_reject_detail: BTreeMap::new(), global_reject_detail: BTreeMap::new(), } } /// Returns the RNG for this test run. pub fn rng(&mut self) -> &mut TestRng { &mut self.rng } /// Create a new, independent but deterministic RNG from the RNG in this /// runner. pub fn new_rng(&mut self) -> TestRng { self.rng.gen_rng() } /// Returns the configuration of this runner. pub fn config(&self) -> &Config { &self.config } /// Dumps the bytes obtained from the RNG so far (only works if the RNG is /// set to `Recorder`). /// /// ## Panics /// /// Panics if the RNG does not capture generated data. pub fn bytes_used(&self) -> Vec<u8> { self.rng.bytes_used() } /// Run test cases against `f`, choosing inputs via `strategy`. /// /// If any failure cases occur, try to find a minimal failure case and /// report that. If invoking `f` panics, the panic is turned into a /// `TestCaseError::Fail`. /// /// If failure persistence is enabled, all persisted failing cases are /// tested first. If a later non-persisted case fails, its seed is /// persisted before returning failure. /// /// Returns success or failure indicating why the test as a whole failed. pub fn run<S: Strategy>( &mut self, strategy: &S, test: impl Fn(S::Value) -> TestCaseResult, ) -> TestRunResult<S> { if self.config.fork() { self.run_in_fork(strategy, test) } else { self.run_in_process(strategy, test) } } #[cfg(not(feature = "fork"))] fn run_in_fork<S: Strategy>( &mut self, _: &S, _: impl Fn(S::Value) -> TestCaseResult, ) -> TestRunResult<S> { unreachable!() } #[cfg(feature = "fork")] fn run_in_fork<S: Strategy>( &mut self, strategy: &S, test: impl Fn(S::Value) -> TestCaseResult, ) -> TestRunResult<S> { let mut test = Some(test); let test_name = rusty_fork::fork_test::fix_module_path( self.config .test_name .expect("Must supply test_name when forking enabled"), ); let forkfile: RefCell<Option<tempfile::NamedTempFile>> = RefCell::new(None); let init_forkfile_size = Cell::new(0u64); let seed = self.rng.new_rng_seed(); let mut replay = replay::Replay { seed, steps: vec![], }; let mut child_count = 0; let timeout = self.config.timeout(); fn forkfile_size(forkfile: &Option<tempfile::NamedTempFile>) -> u64 { forkfile.as_ref().map_or(0, |ff| { ff.as_file().metadata().map(|md| md.len()).unwrap_or(0) }) } loop { let (child_error, last_fork_file_len) = rusty_fork::fork( test_name, rusty_fork_id!(), |cmd| { let mut forkfile = forkfile.borrow_mut(); if forkfile.is_none() { *forkfile = Some(tempfile::NamedTempFile::new().expect( "Failed to create temporary file for fork", )); replay.init_file(forkfile.as_mut().unwrap()).expect( "Failed to initialise temporary file for fork", ); } init_forkfile_size.set(forkfile_size(&forkfile)); cmd.env(ENV_FORK_FILE, forkfile.as_ref().unwrap().path()); }, |child, _| { await_child( child, &mut forkfile.borrow_mut().as_mut().unwrap(), timeout, ) }, || match self.run_in_process(strategy, test.take().unwrap()) { Ok(_) => (), Err(e) => panic!( "Test failed normally in child process.\n{}\n{}", e, self ), }, ) .expect("Fork failed"); let parsed = replay::Replay::parse_from( &mut forkfile.borrow_mut().as_mut().unwrap(), ) .expect("Failed to re-read fork file"); match parsed { replay::ReplayFileStatus::InProgress(new_replay) => { replay = new_replay } replay::ReplayFileStatus::Terminated(new_replay) => { replay = new_replay; break; } replay::ReplayFileStatus::Corrupt => { panic!("Child process corrupted replay file") } } let curr_forkfile_size = forkfile_size(&forkfile.borrow()); // If the child failed to append *anything* to the forkfile, it // crashed or timed out before starting even one test case, so // bail. if curr_forkfile_size == init_forkfile_size.get() { return Err(TestError::Abort( "Child process crashed or timed out before the first test \ started running; giving up." .into(), )); } // The child only terminates early if it outright crashes or we // kill it due to timeout, so add a synthetic failure to the // output. But only do this if the length of the fork file is the // same as when we last saw it, or if the child was not killed due // to timeout. (This is because the child could have appended // something to the file after we gave up waiting for it but before // we were able to kill it). if last_fork_file_len.map_or(true, |last_fork_file_len| { last_fork_file_len == curr_forkfile_size }) { let error = Err(child_error.unwrap_or(TestCaseError::fail( "Child process was terminated abruptly \ but with successful status", ))); replay::append(forkfile.borrow_mut().as_mut().unwrap(), &error) .expect("Failed to append to replay file"); replay.steps.push(error); } // Bail if we've gone through too many processes in case the // shrinking process itself is crashing. child_count += 1; if child_count >= 10000 { return Err(TestError::Abort( "Giving up after 10000 child processes crashed".into(), )); } } // Run through the steps in-process (without ever running the actual // tests) to produce the shrunken value and update the persistence // file. self.rng.set_seed(replay.seed); self.run_in_process_with_replay( strategy, |_| panic!("Ran past the end of the replay"), replay.steps.into_iter(), ForkOutput::empty(), ) } fn run_in_process<S: Strategy>( &mut self, strategy: &S, test: impl Fn(S::Value) -> TestCaseResult, ) -> TestRunResult<S> { let (replay_steps, fork_output) = init_replay(&mut self.rng); self.run_in_process_with_replay( strategy, test, replay_steps.into_iter(), fork_output, ) } fn run_in_process_with_replay<S: Strategy>( &mut self, strategy: &S, test: impl Fn(S::Value) -> TestCaseResult, mut replay_from_fork: impl Iterator<Item = TestCaseResult>, mut fork_output: ForkOutput, ) -> TestRunResult<S> { let old_rng = self.rng.clone(); let persisted_failure_seeds: Vec<PersistedSeed> = self .config .failure_persistence .as_ref() .map(|f| f.load_persisted_failures2(self.config.source_file)) .unwrap_or_default(); let mut result_cache = self.new_cache(); for PersistedSeed(persisted_seed) in persisted_failure_seeds.into_iter().rev() { self.rng.set_seed(persisted_seed); self.gen_and_run_case( strategy, &test, &mut replay_from_fork, &mut *result_cache, &mut fork_output, true, )?; } self.rng = old_rng; while self.successes < self.config.cases { // Generate a new seed and make an RNG from that so that we know // what seed to persist if this case fails. let seed = self.rng.gen_get_seed(); let result = self.gen_and_run_case( strategy, &test, &mut replay_from_fork, &mut *result_cache, &mut fork_output, false, ); if let Err(TestError::Fail(_, ref value)) = result { if let Some(ref mut failure_persistence) = self.config.failure_persistence { let source_file = &self.config.source_file; // Don't update the persistence file if we're a child // process. The parent relies on it remaining consistent // and will take care of updating it itself. if !fork_output.is_in_fork() { failure_persistence.save_persisted_failure2( *source_file, PersistedSeed(seed), value, ); } } } if let Err(e) = result { fork_output.terminate(); return Err(e.into()); } } fork_output.terminate(); Ok(()) } fn gen_and_run_case<S: Strategy>( &mut self, strategy: &S, f: &impl Fn(S::Value) -> TestCaseResult, replay_from_fork: &mut impl Iterator<Item = TestCaseResult>, result_cache: &mut dyn ResultCache, fork_output: &mut ForkOutput, is_from_persisted_seed: bool, ) -> TestRunResult<S> { let case = unwrap_or!(strategy.new_tree(self), msg => return Err(TestError::Abort(msg))); // We only count new cases to our set of successful runs against // `PROPTEST_CASES` config. let ok_type = self.run_one_with_replay( case, f, replay_from_fork, result_cache, fork_output, is_from_persisted_seed, )?; match ok_type { TestCaseOk::NewCaseSuccess | TestCaseOk::ReplayFromForkSuccess => { self.successes += 1 } TestCaseOk::PersistedCaseSuccess | TestCaseOk::CacheHitSuccess | TestCaseOk::Reject => (), } Ok(()) } /// Run one specific test case against this runner. /// /// If the test fails, finds the minimal failing test case. If the test /// does not fail, returns whether it succeeded or was filtered out. /// /// This does not honour the `fork` config, and will not be able to /// terminate the run if it runs for longer than `timeout`. However, if the /// test function returns but took longer than `timeout`, the test case /// will fail. pub fn run_one<V: ValueTree>( &mut self, case: V, test: impl Fn(V::Value) -> TestCaseResult, ) -> Result<bool, TestError<V::Value>> { let mut result_cache = self.new_cache(); self.run_one_with_replay( case, test, &mut iter::empty::<TestCaseResult>().fuse(), &mut *result_cache, &mut ForkOutput::empty(), false, ) .map(|ok_type| match ok_type { TestCaseOk::Reject => false, _ => true, }) } fn run_one_with_replay<V: ValueTree>( &mut self, mut case: V, test: impl Fn(V::Value) -> TestCaseResult, replay_from_fork: &mut impl Iterator<Item = TestCaseResult>, result_cache: &mut dyn ResultCache, fork_output: &mut ForkOutput, is_from_persisted_seed: bool, ) -> Result<TestCaseOk, TestError<V::Value>> { let result = call_test( self, case.current(), &test, replay_from_fork, result_cache, fork_output, is_from_persisted_seed, ); match result { Ok(success_type) => Ok(success_type), Err(TestCaseError::Fail(why)) => { let why = self .shrink( &mut case, test, replay_from_fork, result_cache, fork_output, is_from_persisted_seed, ) .unwrap_or(why); Err(TestError::Fail(why, case.current())) } Err(TestCaseError::Reject(whence)) => { self.reject_global(whence)?; Ok(TestCaseOk::Reject) } } } fn shrink<V: ValueTree>( &mut self, case: &mut V, test: impl Fn(V::Value) -> TestCaseResult, replay_from_fork: &mut impl Iterator<Item = TestCaseResult>, result_cache: &mut dyn ResultCache, fork_output: &mut ForkOutput, is_from_persisted_seed: bool, ) -> Option<Reason> { // exit early if shrink disabled if self.config.max_shrink_iters == 0 { verbose_message!( self, INFO_LOG, "Shrinking disabled by configuration" ); return None } #[cfg(all(feature = "std", not(target_arch = "wasm32")))] let start_time = std::time::Instant::now(); let mut last_failure = None; let mut iterations = 0; verbose_message!(self, TRACE, "Starting shrinking"); if case.simplify() { loop { let mut timed_out: Option<u64> = None; #[cfg(all(feature = "std", not(target_arch = "wasm32")))] if self.config.max_shrink_time > 0 { let elapsed = start_time.elapsed(); let elapsed_ms = elapsed .as_secs() .saturating_mul(1000) .saturating_add(elapsed.subsec_millis().into()); if elapsed_ms > self.config.max_shrink_time as u64 { timed_out = Some(elapsed_ms); } } let bail = if iterations >= self.config.max_shrink_iters() { #[cfg(feature = "std")] const CONTROLLER: &str = "the PROPTEST_MAX_SHRINK_ITERS environment \ variable or ProptestConfig.max_shrink_iters"; #[cfg(not(feature = "std"))] const CONTROLLER: &str = "ProptestConfig.max_shrink_iters"; verbose_message!( self, ALWAYS, "Aborting shrinking after {} iterations (set {} \ to a large(r) value to shrink more; current \ configuration: {} iterations)", CONTROLLER, self.config.max_shrink_iters(), iterations ); true } else if let Some(ms) = timed_out { #[cfg(feature = "std")] const CONTROLLER: &str = "the PROPTEST_MAX_SHRINK_TIME environment \ variable or ProptestConfig.max_shrink_time"; #[cfg(feature = "std")] let current = self.config.max_shrink_time; #[cfg(not(feature = "std"))] const CONTROLLER: &str = "(not configurable in no_std)"; #[cfg(not(feature = "std"))] let current = 0; verbose_message!( self, ALWAYS, "Aborting shrinking after taking too long: {} ms \ (set {} to a large(r) value to shrink more; current \ configuration: {} ms)", ms, CONTROLLER, current ); true } else { false }; if bail { // Move back to the most recent failing case while case.complicate() { fork_output.append(&Ok(())); } break; } iterations += 1; let result = call_test( self, case.current(), &test, replay_from_fork, result_cache, fork_output, is_from_persisted_seed, ); match result { // Rejections are effectively a pass here, // since they indicate that any behaviour of // the function under test is acceptable. Ok(_) | Err(TestCaseError::Reject(..)) => { if !case.complicate() { verbose_message!( self, TRACE, "Cannot complicate further" ); break; } } Err(TestCaseError::Fail(why)) => { last_failure = Some(why); if !case.simplify() { verbose_message!( self, TRACE, "Cannot simplify further" ); break; } } } } } last_failure } /// Update the state to account for a local rejection from `whence`, and /// return `Ok` if the caller should keep going or `Err` to abort. pub fn reject_local( &mut self, whence: impl Into<Reason>, ) -> Result<(), Reason> { if self.local_rejects >= self.config.max_local_rejects { Err("Too many local rejects".into()) } else { self.local_rejects += 1; Self::insert_or_increment( &mut self.local_reject_detail, whence.into(), ); Ok(()) } } /// Update the state to account for a global rejection from `whence`, and /// return `Ok` if the caller should keep going or `Err` to abort. fn reject_global<T>(&mut self, whence: Reason) -> Result<(), TestError<T>> { if self.global_rejects >= self.config.max_global_rejects { Err(TestError::Abort("Too many global rejects".into())) } else { self.global_rejects += 1; Self::insert_or_increment(&mut self.global_reject_detail, whence); Ok(()) } } /// Insert 1 or increment the rejection detail at key for whence. fn insert_or_increment(into: &mut RejectionDetail, whence: Reason) { into.entry(whence) .and_modify(|count| *count += 1) .or_insert(1); } /// Increment the counter of flat map regenerations and return whether it /// is still under the configured limit. pub fn flat_map_regen(&self) -> bool { self.flat_map_regens.fetch_add(1, SeqCst) < self.config.max_flat_map_regens as usize } fn new_cache(&self) -> Box<dyn ResultCache> { (self.config.result_cache)() } } #[cfg(feature = "fork")] fn init_replay(rng: &mut TestRng) -> (Vec<TestCaseResult>, ForkOutput) { use crate::test_runner::replay::{open_file, Replay, ReplayFileStatus::*}; if let Some(path) = env::var_os(ENV_FORK_FILE) { let mut file = open_file(&path).expect("Failed to open replay file"); let loaded = Replay::parse_from(&mut file).expect("Failed to read replay file"); match loaded { InProgress(replay) => { rng.set_seed(replay.seed); (replay.steps, ForkOutput { file: Some(file) }) } Terminated(_) => { panic!("Replay file for child process is terminated?") } Corrupt => panic!("Replay file for child process is corrupt"), } } else { (vec![], ForkOutput::empty()) } } #[cfg(not(feature = "fork"))] fn init_replay( _rng: &mut TestRng, ) -> (iter::Empty<TestCaseResult>, ForkOutput) { (iter::empty(), ForkOutput::empty()) } #[cfg(feature = "fork")] fn await_child_without_timeout( child: &mut rusty_fork::ChildWrapper, ) -> (Option<TestCaseError>, Option<u64>) { let status = child.wait().expect("Failed to wait for child process"); if status.success() { (None, None) } else { ( Some(TestCaseError::fail(format!( "Child process exited with {}", status ))), None, ) } } #[cfg(all(feature = "fork", not(feature = "timeout")))] fn await_child( child: &mut rusty_fork::ChildWrapper, _: &mut tempfile::NamedTempFile, _timeout: u32, ) -> (Option<TestCaseError>, Option<u64>) { await_child_without_timeout(child) } #[cfg(all(feature = "fork", feature = "timeout"))] fn await_child( child: &mut rusty_fork::ChildWrapper, forkfile: &mut tempfile::NamedTempFile, timeout: u32, ) -> (Option<TestCaseError>, Option<u64>) { use std::time::Duration; if 0 == timeout { return await_child_without_timeout(child); } // The child can run for longer than the timeout since it may run // multiple tests. Each time the timeout expires, we check whether the // file has grown larger. If it has, we allow the child to keep running // until the next timeout. let mut last_forkfile_len = forkfile .as_file() .metadata() .map(|md| md.len()) .unwrap_or(0); loop { if let Some(status) = child .wait_timeout(Duration::from_millis(timeout.into())) .expect("Failed to wait for child process") { if status.success() { return (None, None); } else { return ( Some(TestCaseError::fail(format!( "Child process exited with {}", status ))), None, ); } } let current_len = forkfile .as_file() .metadata() .map(|md| md.len()) .unwrap_or(0); // If we've gone a full timeout period without the file growing, // fail the test and kill the child. if current_len <= last_forkfile_len { return ( Some(TestCaseError::fail(format!( "Timed out waiting for child process" ))), Some(current_len), ); } else { last_forkfile_len = current_len; } } } #[cfg(test)] mod test { use std::cell::Cell; use std::fs; use super::*; use crate::strategy::Strategy; use crate::test_runner::{FileFailurePersistence, RngAlgorithm, TestRng}; #[test] fn gives_up_after_too_many_rejections() { let config = Config::default(); let mut runner = TestRunner::new(config.clone()); let runs = Cell::new(0); let result = runner.run(&(0u32..), |_| { runs.set(runs.get() + 1); Err(TestCaseError::reject("reject")) }); match result { Err(TestError::Abort(_)) => (), e => panic!("Unexpected result: {:?}", e), } assert_eq!(config.max_global_rejects + 1, runs.get()); } #[test] fn test_pass() { let mut runner = TestRunner::default(); let result = runner.run(&(1u32..), |v| { assert!(v > 0); Ok(()) }); assert_eq!(Ok(()), result); } #[test] fn test_fail_via_result() { let mut runner = TestRunner::new(Config { failure_persistence: None, ..Config::default() }); let result = runner.run(&(0u32..10u32), |v| { if v < 5 { Ok(()) } else { Err(TestCaseError::fail("not less than 5")) } }); assert_eq!(Err(TestError::Fail("not less than 5".into(), 5)), result); } #[test] fn test_fail_via_panic() { let mut runner = TestRunner::new(Config { failure_persistence: None, ..Config::default() }); let result = runner.run(&(0u32..10u32), |v| { assert!(v < 5, "not less than 5"); Ok(()) }); assert_eq!(Err(TestError::Fail("not less than 5".into(), 5)), result); } #[test] fn persisted_cases_do_not_count_towards_total_cases() { const FILE: &'static str = "persistence-test.txt"; let _ = fs::remove_file(FILE); let config = Config { failure_persistence: Some(Box::new( FileFailurePersistence::Direct(FILE), )), cases: 1, ..Config::default() }; let max = 10_000_000i32; { TestRunner::new(config.clone()) .run(&(0i32..max), |_v| { Err(TestCaseError::Fail("persist a failure".into())) }) .expect_err("didn't fail?"); } let run_count = RefCell::new(0); TestRunner::new(config.clone()) .run(&(0i32..max), |_v| { *run_count.borrow_mut() += 1; Ok(()) }) .expect("should succeed"); // Persisted ran, and a new case ran, and only new case counts // against `cases: 1`. assert_eq!(run_count.into_inner(), 2); } #[derive(Clone, Copy, PartialEq)] struct PoorlyBehavedDebug(i32); impl fmt::Debug for PoorlyBehavedDebug { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "\r\n{:?}\r\n", self.0) } } #[test] fn failing_cases_persisted_and_reloaded() { const FILE: &'static str = "persistence-test.txt"; let _ = fs::remove_file(FILE); let max = 10_000_000i32; let input = (0i32..max).prop_map(PoorlyBehavedDebug); let config = Config { failure_persistence: Some(Box::new( FileFailurePersistence::Direct(FILE), )), ..Config::default() }; // First test with cases that fail above half max, and then below half // max, to ensure we can correctly parse both lines of the persistence // file. let first_sub_failure = { TestRunner::new(config.clone()) .run(&input, |v| { if v.0 < max / 2 { Ok(()) } else { Err(TestCaseError::Fail("too big".into())) } }) .expect_err("didn't fail?") }; let first_super_failure = { TestRunner::new(config.clone()) .run(&input, |v| { if v.0 >= max / 2 { Ok(()) } else { Err(TestCaseError::Fail("too small".into())) } }) .expect_err("didn't fail?") }; let second_sub_failure = { TestRunner::new(config.clone()) .run(&input, |v| { if v.0 < max / 2 { Ok(()) } else { Err(TestCaseError::Fail("too big".into())) } }) .expect_err("didn't fail?") }; let second_super_failure = { TestRunner::new(config.clone()) .run(&input, |v| { if v.0 >= max / 2 { Ok(()) } else { Err(TestCaseError::Fail("too small".into())) } }) .expect_err("didn't fail?") }; assert_eq!(first_sub_failure, second_sub_failure); assert_eq!(first_super_failure, second_super_failure); } #[test] fn new_rng_makes_separate_rng() { use rand::Rng; let mut runner = TestRunner::default(); let from_1 = runner.new_rng().gen::<[u8; 16]>(); let from_2 = runner.rng().gen::<[u8; 16]>(); assert_ne!(from_1, from_2); } #[test] fn record_rng_use() { use rand::Rng; // create value with recorder rng let default_config = Config::default(); let recorder_rng = TestRng::default_rng(RngAlgorithm::Recorder); let mut runner = TestRunner::new_with_rng(default_config.clone(), recorder_rng); let random_byte_array1 = runner.rng().gen::<[u8; 16]>(); let bytes_used = runner.bytes_used(); assert!(bytes_used.len() >= 16); // could use more bytes for some reason // re-create value with pass-through rng let passthrough_rng = TestRng::from_seed(RngAlgorithm::PassThrough, &bytes_used); let mut runner = TestRunner::new_with_rng(default_config, passthrough_rng); let random_byte_array2 = runner.rng().gen::<[u8; 16]>(); // make sure the same value was created assert_eq!(random_byte_array1, random_byte_array2); } #[cfg(feature = "fork")] #[test] fn run_successful_test_in_fork() { let mut runner = TestRunner::new(Config { fork: true, test_name: Some(concat!( module_path!(), "::run_successful_test_in_fork" )), ..Config::default() }); assert!(runner.run(&(0u32..1000), |_| Ok(())).is_ok()); } #[cfg(feature = "fork")] #[test] fn normal_failure_in_fork_results_in_correct_failure() { let mut runner = TestRunner::new(Config { fork: true, test_name: Some(concat!( module_path!(), "::normal_failure_in_fork_results_in_correct_failure" )), ..Config::default() }); let failure = runner .run(&(0u32..1000), |v| { prop_assert!(v < 500); Ok(()) }) .err() .unwrap(); match failure { TestError::Fail(_, value) => assert_eq!(500, value), failure => panic!("Unexpected failure: {:?}", failure), } } #[cfg(feature = "fork")] #[test] fn nonsuccessful_exit_finds_correct_failure() { let mut runner = TestRunner::new(Config { fork: true, test_name: Some(concat!( module_path!(), "::nonsuccessful_exit_finds_correct_failure" )), ..Config::default() }); let failure = runner .run(&(0u32..1000), |v| { if v >= 500 { ::std::process::exit(1); } Ok(()) }) .err() .unwrap(); match failure { TestError::Fail(_, value) => assert_eq!(500, value), failure => panic!("Unexpected failure: {:?}", failure), } } #[cfg(feature = "fork")] #[test] fn spurious_exit_finds_correct_failure() { let mut runner = TestRunner::new(Config { fork: true, test_name: Some(concat!( module_path!(), "::spurious_exit_finds_correct_failure" )), ..Config::default() }); let failure = runner .run(&(0u32..1000), |v| { if v >= 500 { ::std::process::exit(0); } Ok(()) }) .err() .unwrap(); match failure { TestError::Fail(_, value) => assert_eq!(500, value), failure => panic!("Unexpected failure: {:?}", failure), } } #[cfg(feature = "timeout")] #[test] fn long_sleep_timeout_finds_correct_failure() { let mut runner = TestRunner::new(Config { fork: true, timeout: 500, test_name: Some(concat!( module_path!(), "::long_sleep_timeout_finds_correct_failure" )), ..Config::default() }); let failure = runner .run(&(0u32..1000), |v| { if v >= 500 { ::std::thread::sleep(::std::time::Duration::from_millis( 10_000, )); } Ok(()) }) .err() .unwrap(); match failure { TestError::Fail(_, value) => assert_eq!(500, value), failure => panic!("Unexpected failure: {:?}", failure), } } #[cfg(feature = "timeout")] #[test] fn mid_sleep_timeout_finds_correct_failure() { let mut runner = TestRunner::new(Config { fork: true, timeout: 500, test_name: Some(concat!( module_path!(), "::mid_sleep_timeout_finds_correct_failure" )), ..Config::default() }); let failure = runner .run(&(0u32..1000), |v| { if v >= 500 { // Sleep a little longer than the timeout. This means that // sometimes the test case itself will return before the parent // process has noticed the child is timing out, so it's up to // the child to mark it as a failure. ::std::thread::sleep(::std::time::Duration::from_millis( 600, )); } else { // Sleep a bit so that the parent and child timing don't stay // in sync. ::std::thread::sleep(::std::time::Duration::from_millis( 100, )) } Ok(()) }) .err() .unwrap(); match failure { TestError::Fail(_, value) => assert_eq!(500, value), failure => panic!("Unexpected failure: {:?}", failure), } } #[cfg(feature = "std")] #[test] fn duplicate_tests_not_run_with_basic_result_cache() { use std::cell::{Cell, RefCell}; use std::collections::HashSet; use std::rc::Rc; for _ in 0..256 { let mut runner = TestRunner::new(Config { failure_persistence: None, result_cache: crate::test_runner::result_cache::basic_result_cache, ..Config::default() }); let pass = Rc::new(Cell::new(true)); let seen = Rc::new(RefCell::new(HashSet::new())); let result = runner.run(&(0u32..65536u32).prop_map(|v| v % 10), |val| { if !seen.borrow_mut().insert(val) { println!("Value {} seen more than once", val); pass.set(false); } prop_assert!(val <= 5); Ok(()) }); assert!(pass.get()); if let Err(TestError::Fail(_, val)) = result { assert_eq!(6, val); } else { panic!("Incorrect result: {:?}", result); } } } } #[cfg(all(feature = "fork", feature = "timeout", test))] mod timeout_tests { use core::u32; use std::thread; use std::time::Duration; use super::*; rusty_fork_test! { #![rusty_fork(timeout_ms = 4_000)] #[test] fn max_shrink_iters_works() { test_shrink_bail(Config { max_shrink_iters: 5, .. Config::default() }); } #[test] fn max_shrink_time_works() { test_shrink_bail(Config { max_shrink_time: 1000, .. Config::default() }); } #[test] fn max_shrink_iters_works_with_forking() { test_shrink_bail(Config { fork: true, test_name: Some( concat!(module_path!(), "::max_shrink_iters_works_with_forking")), max_shrink_time: 1000, .. Config::default() }); } #[test] fn detects_child_failure_to_start() { let mut runner = TestRunner::new(Config { timeout: 100, test_name: Some( concat!(module_path!(), "::detects_child_failure_to_start")), .. Config::default() }); let result = runner.run(&Just(()).prop_map(|()| { thread::sleep(Duration::from_millis(200)) }), Ok); if let Err(TestError::Abort(_)) = result { // OK } else { panic!("Unexpected result: {:?}", result); } } } fn test_shrink_bail(config: Config) { let mut runner = TestRunner::new(config); let result = runner.run(&crate::num::u64::ANY, |v| { thread::sleep(Duration::from_millis(250)); prop_assert!(v <= u32::MAX as u64); Ok(()) }); if let Err(TestError::Fail(_, value)) = result { // Ensure the final value was in fact a failing case. assert!(value > u32::MAX as u64); } else { panic!("Unexpected result: {:?}", result); } } } ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/test_runner/scoped_panic_hook.rs�������������������������������������������������0000644�0000000�0000000�00000012066�10461020230�0020671�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2024 The proptest developers // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[cfg(feature = "handle-panics")] mod internal { //! Implementation of scoped panic hooks //! //! 1. `with_hook` serves as entry point, it executes body closure with panic hook closure //! installed as scoped panic hook //! 2. Upon first execution, current panic hook is replaced with `scoped_hook_dispatcher` //! in a thread-safe manner, and original hook is stored for later use //! 3. When panic occurs, `scoped_hook_dispatcher` either delegates execution to scoped //! panic hook, if one is installed, or back to original hook stored earlier. //! This preserves original behavior when scoped hook isn't used //! 4. When `with_hook` is used, it replaces stored scoped hook pointer with pointer to //! hook closure passed as parameter. Old hook pointer is set to be restored unconditionally //! via drop guard. Then, normal body closure is executed. use std::boxed::Box; use std::cell::Cell; use std::panic::{set_hook, take_hook, PanicInfo}; use std::sync::Once; use std::{mem, ptr}; thread_local! { /// Pointer to currently installed scoped panic hook, if any /// /// NB: pointers to arbitrary fn's are fat, and Rust doesn't allow crafting null pointers /// to fat objects. So we just store const pointer to tuple with whatever data we need static SCOPED_HOOK_PTR: Cell<*const (*mut dyn FnMut(&PanicInfo<'_>),)> = Cell::new(ptr::null()); } static INIT_ONCE: Once = Once::new(); /// Default panic hook, the one which was present before installing scoped one /// /// NB: no need for external sync, value is mutated only once, when init is performed static mut DEFAULT_HOOK: Option<Box<dyn Fn(&PanicInfo<'_>) + Send + Sync>> = None; /// Replaces currently installed panic hook with `scoped_hook_dispatcher` once, /// in a thread-safe manner fn init() { INIT_ONCE.call_once(|| { let old_handler = take_hook(); set_hook(Box::new(scoped_hook_dispatcher)); unsafe { DEFAULT_HOOK = Some(old_handler); } }); } /// Panic hook which delegates execution to scoped hook, /// if one installed, or to default hook fn scoped_hook_dispatcher(info: &PanicInfo<'_>) { let handler = SCOPED_HOOK_PTR.get(); if !handler.is_null() { // It's assumed that if container's ptr is not null, ptr to `FnMut` is non-null too. // Correctness **must** be ensured by hook switch code in `with_hook` let hook = unsafe { &mut *(*handler).0 }; (hook)(info); return; } #[allow(static_mut_refs)] if let Some(hook) = unsafe { DEFAULT_HOOK.as_ref() } { (hook)(info); } } /// Executes stored closure when dropped struct Finally<F: FnOnce()>(Option<F>); impl<F: FnOnce()> Finally<F> { fn new(body: F) -> Self { Self(Some(body)) } } impl<F: FnOnce()> Drop for Finally<F> { fn drop(&mut self) { if let Some(body) = self.0.take() { body(); } } } /// Executes main closure `body` while installing `guard` as scoped panic hook, /// for execution duration. /// /// Any panics which happen during execution of `body` are passed to `guard` hook /// to collect any info necessary, although unwind process is **NOT** interrupted. /// See module documentation for details /// /// # Parameters /// * `panic_hook` - scoped panic hook, functions for the duration of `body` execution /// * `body` - actual logic covered by `panic_hook` /// /// # Returns /// `body`'s return value pub fn with_hook<R>( mut panic_hook: impl FnMut(&PanicInfo<'_>), body: impl FnOnce() -> R, ) -> R { init(); // Construct scoped hook pointer let guard_tuple = (unsafe { // `mem::transmute` is needed due to borrow checker restrictions to erase all lifetimes mem::transmute(&mut panic_hook as *mut dyn FnMut(&PanicInfo<'_>)) },); let old_tuple = SCOPED_HOOK_PTR.replace(&guard_tuple); // Old scoped hook **must** be restored before leaving function scope to keep it sound let _undo = Finally::new(|| { SCOPED_HOOK_PTR.set(old_tuple); }); body() } } #[cfg(not(feature = "handle-panics"))] mod internal { use core::panic::PanicInfo; /// Simply executes `body` and returns its execution result. /// Hook parameter is ignored pub fn with_hook<R>( _: impl FnMut(&PanicInfo<'_>), body: impl FnOnce() -> R, ) -> R { body() } } pub use internal::with_hook; ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/src/tuple.rs�������������������������������������������������������������������������0000644�0000000�0000000�00000011250�10461020230�0013775�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������//- // Copyright 2017 Jason Lingle // // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license // <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<T> { tree: T, shrinker: u32, prev_shrinker: Option<u32>, } impl<T> TupleValueTree<T> { /// 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, shrinker: 0, prev_shrinker: None, } } } 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<Self> { 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 { $( if $fld == self.shrinker { if self.tree.$fld.simplify() { self.prev_shrinker = Some(self.shrinker); return true; } else { self.shrinker += 1; } } )* false } fn complicate(&mut self) -> bool { if let Some(shrinker) = self.prev_shrinker {$( if $fld == shrinker { if self.tree.$fld.complicate() { self.shrinker = shrinker; return true; } else { self.prev_shrinker = None; return false; } } )*} 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); } } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/test-persistence-location/.gitignore�������������������������������������������������0000644�0000000�0000000�00000000171�10461020230�0020606�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Ignore any regressions files that get emitted since they're essentially test # output here. proptest-regressions *.txt �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/test-persistence-location/README.md��������������������������������������������������0000644�0000000�0000000�00000000460�10461020230�0020076�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������This directory contains two independent cargo workspaces, one which is a traditional single-crate workspace and another which is a multi-crate workspace (with only one crate, but what matters is the directory layout). These are used to test where the persistence files end up when all is said and done. ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/test-persistence-location/run-tests.bat����������������������������������������������0000644�0000000�0000000�00000000765�10461020230�0021263�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������cd single-crate rd /s /q proptest-regressions cargo test >cargo.txt cargo clean >nul if not exist proptest-regressions/submodule/code.txt goto fail cd ..\workspace rd /s /q proptest-regressions cargo test --all >cargo.txt cargo clean >nul if not exist member/proptest-regressions/submodule/code.txt goto fail cd .. echo All persistence files written to correct location. echo PASS exit /b :fail echo Persistence file not in expected location. FS: dir /s echo Cargo output: type cargo.txt exit /b 1 �����������proptest-1.6.0/test-persistence-location/run-tests.sh�����������������������������������������������0000755�0000000�0000000�00000001477�10461020230�0021133�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh find . -name \*.txt -o -name proptest-regressions -depth -exec rm -rf {} \; || \ exit $? ( cd single-crate cargo test >cargo-out.txt 2>&1 # Ignore expected failure cargo clean >/dev/null if ! test -f proptest-regressions/submodule/code.txt; then echo >&2 "Persistence file not written to the correct location. FS:" find . >&2 echo >&2 "Cargo output:" cat >&2 cargo-out.txt exit 1 fi ) && ( cd workspace cargo test --all >cargo-out.txt 2>&1 # Ignore expected failure cargo clean >/dev/null if ! test -f member/proptest-regressions/submodule/code.txt; then echo >&2 "Persistence file not written to the correct location. FS:" find . >&2 echo >&2 "Cargo output:" cat >&2 cargo-out.txt exit 1 fi ) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/tests/pass/hygiene.rs����������������������������������������������������������������0000644�0000000�0000000�00000000212�10461020230�0015611�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������ fn main() {} struct MyTestArgs { something_else: String, } #[proptest::property_test] fn my_test(x: i32) { assert_eq!(x, x); } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/tests/pass/simple_example.rs���������������������������������������������������������0000644�0000000�0000000�00000000126�10461020230�0017171�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������fn main() {} #[proptest::property_test] fn my_test(x: i32) { assert_eq!(x, x); } ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������proptest-1.6.0/tests/pass/with_params.rs������������������������������������������������������������0000644�0000000�0000000�00000000575�10461020230�0016513�0����������������������������������������������������������������������������������������������������ustar �����������������������������������������������������������������0000000�0000000������������������������������������������������������������������������������������������������������������������������������������������������������������������������fn main() {} #[proptest::property_test( config = proptest::test_runner::Config { cases: 10, ..Default::default() } )] fn no_trailing_comma(x: i32) { assert_eq!(x, x); } #[proptest::property_test( config = proptest::test_runner::Config { cases: 10, ..Default::default() } )] fn trailing_comma(x: i32,) { assert_eq!(x, x); } ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������