diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:42 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:42 +0000 |
commit | 837b550238aa671a591ccf282dddeab29cadb206 (patch) | |
tree | 914b6b8862bace72bd3245ca184d374b08d8a672 /vendor/proptest | |
parent | Adding debian version 1.70.0+dfsg2-1. (diff) | |
download | rustc-837b550238aa671a591ccf282dddeab29cadb206.tar.xz rustc-837b550238aa671a591ccf282dddeab29cadb206.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/proptest')
109 files changed, 25399 insertions, 0 deletions
diff --git a/vendor/proptest/.cargo-checksum.json b/vendor/proptest/.cargo-checksum.json new file mode 100644 index 000000000..54c7cfd71 --- /dev/null +++ b/vendor/proptest/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"928688937eeb3c64abbef9c289329a090c5498901cc46551f97b18b1691c2e5e","Cargo.lock":"627742e26bbee0ee46de1d770ca3df0d6ee012bd1c8d743b17d4702c3a949e84","Cargo.toml":"6dbff33edd18bdc162d8ee9034dc052bc8c8511208636105f20bdb264bd238bb","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"d8e0806926ce9f0a5030c382ecc0ffdf6de6fbea5c69a458435fd443fa7a5b92","README.md":"83b42572b7b5c41380ea367be7dccfd9b5797b1bb67683940b3c6ba93d5a48ae","examples/config-defaults.rs":"312ee1c5f98ee858d0401a092e0a87b4c3231095f87a5dd4e6ba3288600ef596","examples/dateparser_v1.rs":"5f91b684ce2d46d865f1f1c0e642efb351e4469067104213871d0fcb1b5a369a","examples/dateparser_v2.rs":"d91d93a7ae5fd7e18c535847bcb3e783f1bc461e9797c8f0b21bc0cec5dd812c","examples/fib.rs":"4740e33bbfb420648a6e49468c178083a7f4c04c8c7512653fed3fff3332edb0","examples/tutorial-simplify-play.rs":"2d048a86334589389b26416fc27f6154b20e182e3766125ffabaeb491dd9295f","examples/tutorial-strategy-play.rs":"3242ba366e52e6d8c66155c9545af3b8863589979fbc6623dd97f532c8fb5285","proptest-regressions/arbitrary/_std/env.txt":"3450a5867e58f6a6c4e5d50e4dce30283e2bf6d5389f48bfa1d535f1269c6516","proptest-regressions/test_runner/rng.txt":"978d8519044a3c6056fa3c99edfd1ff9dee184ff1e74a2592830d54be3f22e81","src/arbitrary/_alloc/alloc.rs":"bbbaf75f67a055ec9ffbe025e991d9138f2dcd462b69165e53d57964edbc053d","src/arbitrary/_alloc/borrow.rs":"0a3026aedc686a76eab6fef37673b13d87701c2a5c2d763615fd3283f89c552f","src/arbitrary/_alloc/boxed.rs":"54b0279c9e5acbff5b4a47f96d75ecf39b5209153b5b07f28437e8a2175a8ad9","src/arbitrary/_alloc/char.rs":"cf37be08bce70b9c38bd24036157097692c9b92d540b104fdd99c8ae751399a9","src/arbitrary/_alloc/collections.rs":"57322f54bdcb89c63a93eefe9f72830ea3d87c87fd51c00a6e151f7292a1c39d","src/arbitrary/_alloc/hash.rs":"266966af450e184e3461cdd09b0052c2c9cbaed0bf7534981cef95a239dacaff","src/arbitrary/_alloc/mod.rs":"b49db65bd88506b2b35cbed65c3da3d15c140214342d7d2bef6c180a22e503d4","src/arbitrary/_alloc/ops.rs":"6aa1c3a18bb8eb256a37e8db6e4398e368c9113b7018ecdc833d88ea8cf33b2c","src/arbitrary/_alloc/rc.rs":"a83680953b444454655cf15f3078838c4c1af4376f9b8482f3bb0e0c01825d92","src/arbitrary/_alloc/str.rs":"19b3d9739894f4f8fd51df8aa0dc5b856ae9283ce46b246887cf082ccfdb68e9","src/arbitrary/_alloc/sync.rs":"c5f8ca04acbb07102993acb6c1b718343201f1f4c44f59f679b853d00f059340","src/arbitrary/_core/ascii.rs":"f408be8715725de9b276eab3dd06c8cbe3320b16718bf632ded1a39fc45e05cf","src/arbitrary/_core/cell.rs":"c90aacfca33293fdd1d346590ac08766de8e84ced2248d4e67345a6f241fa965","src/arbitrary/_core/cmp.rs":"ea0bb9b99d3064f8749a744aaa40380eea12b267bd23cae6057bcc83bf57e921","src/arbitrary/_core/convert.rs":"830e889cf24e64d68d81706e45a33aef93450ee8430062817e1d288eb2e8b318","src/arbitrary/_core/fmt.rs":"e09f679e873b25f1d42e05daa189c802b48d639d83635c79d380a481afde27ce","src/arbitrary/_core/iter.rs":"721dbe2f741c1b6375604e22e9322cca03f31a4fb470d7b33f84e29687a97028","src/arbitrary/_core/marker.rs":"ba1368ff79549a84293b61652af0bd531941f5eacc9845b753edf221585b4430","src/arbitrary/_core/mem.rs":"23754b24a09d5ebfd5465f2b6d5674c3739d4da347075b067ed722d431ac1f70","src/arbitrary/_core/mod.rs":"b30ebd2a2e0606fb6aac4ad63eb8068fc189b576283bbd63299b9f5d21d32846","src/arbitrary/_core/num.rs":"0753a5ae6bf902036b5f6c063043bef1da940fc2ba5603235b900fa54b521cd1","src/arbitrary/_core/option.rs":"7a292712a67bbecac0c766854c8dffc5c8c0cf4cbbd85c43e5233029d4210769","src/arbitrary/_core/result.rs":"4fa76363a4ccb888eeccb1bb4b32a3d314c1c3596137829f0ec886263cb5702f","src/arbitrary/_std/env.rs":"625c594ec669d8199920badc3b76e2f43ec5383a4a0b007083772fb3b35cb138","src/arbitrary/_std/ffi.rs":"cfe50e4a027fa3c7e6ff7a744bbc7b91b2de1f837c1dfba31cdbf90f44407478","src/arbitrary/_std/fs.rs":"1a6d6ded0212686e7b136dd36052ba34d954079ca7e3fc1a6d6e631476ecc2f1","src/arbitrary/_std/io.rs":"344610d93aea9557bfe8d2ca1993e384465aea40d6b0816c4267593aa953fd2a","src/arbitrary/_std/mod.rs":"73845b1e2e31d6fe820143d427f48d9955f67f28ecd5344d9ca0c74928f6ddb7","src/arbitrary/_std/net.rs":"a6249487a7589385373ceb963f830037abdf465d5932c9ec806d85c218c3e16b","src/arbitrary/_std/panic.rs":"20380439a655610d5f5011cc6c16c7e7acfbb7d314a219746fd174f46ea1320f","src/arbitrary/_std/path.rs":"af8fd327ff6bc73686a7bf796694294c418607141dea991c063c4422da4ccbc2","src/arbitrary/_std/string.rs":"cd3031befb486a3410b01c70b4c58871358170aad35e86cd7d8709993f2bd9bc","src/arbitrary/_std/sync.rs":"c493847b5f5a3e10966beb423416c1b0dfd8c989c7a8cec99f53789b3aa03834","src/arbitrary/_std/thread.rs":"f004f74ea78b502b7e4b41919160d40b0d1820652ba664ec3a32a0bbaa5ad965","src/arbitrary/_std/time.rs":"ed622cdf756a1a6f7770c99b7b45cfbf7402db31f4dcf8473c3227ed8b8b54bc","src/arbitrary/arrays.rs":"0e78dde28fdad71327a2e08ec1d79c09526ef327f4abb59f6fea7073cf5f4679","src/arbitrary/functor.rs":"85aa44e04e1e6bef5beaa683180a9b4fe5dd670586d87be026ecf96e2d39b90a","src/arbitrary/macros.rs":"a3fe075811c1e711cb8ffef0557604f70df5e0a75d4110ed2f8516c4e324a24b","src/arbitrary/mod.rs":"228956db006885a4a084b3eb953ca8cdbcc3b44cb604771e67126a9f9fdfd97d","src/arbitrary/non_zero.rs":"512f0d937b7d6c7525eee64a18ad2a1ad2f1012cb504fd1c6adb1af18244283d","src/arbitrary/primitives.rs":"59d9a899853559d3eff1954e6d4c84e8d6999e0a8798fc9b152ea10accccb760","src/arbitrary/sample.rs":"45280f054eb04f7142a7afcc565d77534a78e626a76ad056569251a05d61f831","src/arbitrary/traits.rs":"bf3ce2f950ebbf359b592c5e39f8fbca2302cb2f45b93b185ccc1d81308a7d5b","src/arbitrary/tuples.rs":"5b92e767a74f11b25a262d6e6f9e54d13ca9e389ea42f2b78631b069a854c116","src/array.rs":"9b34119b364682ab383e2ed56210e95073f6d1af3d90e3064c9b527a37d30998","src/bits.rs":"344f1b91c79b1f20c63b3664f1bbda3c04a8e4c95963273eedb69c2dfcb7761c","src/bool.rs":"3e91477b0a5c29539380fdc1c065bfe5829099e3cfa7e50b1f8cf7857a01918b","src/char.rs":"c72bcd375f8e3d17ff1766baed1680cdd912902c697a04035c1e72ef35d2588b","src/collection.rs":"0b5dac7b8671b9feecb0f7097f15dff83d1314c86db2ca03b271fb3f5a496ce1","src/file-preamble":"a4a75492b40e467fa8d1bcf050e685ea4de56c3a76095d756488c554d76a4986","src/lib.rs":"38d1e61fb8e301f386df8660296c14923daeb97a68556ecde7bb6c0c3bbac61a","src/macros.rs":"4353f46ed0a68d20bca16ee261e375dd398b3415759710ac60bdcd281401e2d2","src/num.rs":"84f0632e42e67bd96adb3e5aa0f7a88a4b4f7fbdf1b4771b1d533a2c12e46628","src/num/float_samplers.rs":"894b5cff2fa57c3081b3f09421c74520347dda8b3d2fccf7ca4978fb0076e3f9","src/option.rs":"d817de4d217368ac402a803e35db57c3c2c0da2d863ca4058b579cf4175763ac","src/prelude.rs":"5f20305aa03047afa44da2fd220d689bcf6935e45edc0d9a9ee0497b603917a6","src/product_frunk.rs":"e7c2afc66c8e045105c4828e36ffcd17e6cb9b12a40ef99c7631854dab6d03c0","src/product_tuple.rs":"bdd2b8dcf05bc46eb6f3f331fa66b2a85106f1591046d1c3dc622a9aac3dd9bc","src/regex-contrib/README.md":"add72e2a9a34d4e67d647613970cbf5affc1d987ebe90858a487f3ee6e4032ce","src/regex-contrib/crates_regex.rs":"7812e91c25a2aad48ba024bcbeb8b922ffc1cfa3113a33615885d72d8a2cae64","src/result.rs":"51042be31c9a2a63f46c99f027b7d21ae17331c3c1250735870f0cc5b50e7cdb","src/sample.rs":"e7064f622263fae7da23c16e55cd1d847ad0e46a718402bc0ec3e6e513cb1ae6","src/std_facade.rs":"fec624264d5a849e99131fde58ff0ac8cc99e4e2c9672f9c031bb7b9c7d3e95c","src/strategy/filter.rs":"06b59ed9186d5d1459e9b3d73c1a8d873079af45c3faba1feacbd1c296108cec","src/strategy/filter_map.rs":"2f8f3cc5409077036e1b3f91c5ec40332001ac0fde354e87f679d289a4f1e9d6","src/strategy/flatten.rs":"2e933564191e05d619f0c1669000b1ec2af74bed6719856edbf8c21cb10deceb","src/strategy/fuse.rs":"c9f1c388150686d6f89e37c5ec95c2ac2991708c1d11427ad0c55de9ad96f155","src/strategy/just.rs":"a1b34f10d44c46b93bf399f8aae443a50f96a97d6150691444acffe26956dd86","src/strategy/lazy.rs":"4822adec0f3b24b865242c2b25799e7bca45963314092557494efa53cafd6e87","src/strategy/map.rs":"4dbc65fdb2c3d40c9e944d0234d984ba018899d342ef3f561013a0548849b09e","src/strategy/mod.rs":"20762d1ad18ef5f5a86fd2d2eb7fe286930a297ea448afffc7f3a22c3c5ef2a3","src/strategy/recursive.rs":"7922681623105fb5d1cc08e889081fb793be778195a6d104dffeed11a4da6d4c","src/strategy/shuffle.rs":"9eacb43e73178b8c1422442a6dfae18c1a0613056a34311f0411266d5c5aab39","src/strategy/statics.rs":"36978b39a6990892916f6d0d6b5fa3de02f84747ea7540c4c548863f4561eae2","src/strategy/traits.rs":"e7ddf04aab1a4c50b996e1eb67348f786e707089f6178707317a535eaf573a72","src/strategy/unions.rs":"5cd758fe6ce5aa11dae90b61795df69322b6a3ec8d60183893425aae92869959","src/string.rs":"8a6b54a10713cb5e9a5a63e4298c77873074e6d5788be8ef5324b5b8f050fed7","src/sugar.rs":"41b22a66e491905107e0fe72856c3dd73c673be13e3ffc043078d2579a921f18","src/test_runner/config.rs":"0bb738164a5534eeb4359093ca63656ac2fa0386043e405c9f4b06e9fd833eb7","src/test_runner/errors.rs":"347e199fc03179cf761081c881d6d53addde9817b5d2adea4e2077d699b50f4c","src/test_runner/failure_persistence/file.rs":"87690cd6cc66cad86eed69ea957061a6a3ca11b807d9a4a9fef5fdad59350080","src/test_runner/failure_persistence/map.rs":"b00bc6cc1650cc9fb432d201c19bf0ba1f5b6255b8c7f1e067a184531da345f9","src/test_runner/failure_persistence/mod.rs":"69737f233b464f047bb6e6e13db15db57371a929aefd52acb6d79fa46af40314","src/test_runner/failure_persistence/noop.rs":"fada8a1f66ade1983d5cfd839da2726ee72b1b1a39927b484590be65cacd2ab8","src/test_runner/mod.rs":"738e90f1556b9ce98924da0699dc5ada59a44816aed3ca5069099d52e8b70c36","src/test_runner/reason.rs":"f3b62a8175fd3b91e216b0f607a2b5a36808a77642eeac207774e193894d7bbb","src/test_runner/replay.rs":"de8c3310af00ab27920416386d0e65870a32d6ef8f2eed1cfb8b0f8079ba7fcc","src/test_runner/result_cache.rs":"1a7039ce31f114ed89bb398540a5bdb6ce4ecc5d5774e47f2028c44e19369d3b","src/test_runner/rng.rs":"863b784b3812c6bb68e4cab27baea8a92fbc3becac09bdbe356f35f761a8f2b8","src/test_runner/runner.rs":"3df3b056e0d0476a8ee44418577824941778f32d561864e6184c57b03451ed69","src/tuple.rs":"378da5204c9e14277dc5b1af29b49e1feaf508f67dec1a0493614df47034868b","test-persistence-location/README.md":"83c3b124b9203f711b8a7ecfb126db96d66bbe73831288c9ee1fb030acfe44a9","test-persistence-location/run-tests.bat":"ba04781900565fd1cec389dd0f9a1c67dd2d0e23b06e63de2b53365e3985c78f","test-persistence-location/run-tests.sh":"03f05cf0409baabf39b0aca33d659e6385306eaccf036fe47e0155a97dd64afb"},"package":"29f1b898011ce9595050a68e60f90bad083ff2987a695a42357134c8381fba70"}
\ No newline at end of file diff --git a/vendor/proptest/CHANGELOG.md b/vendor/proptest/CHANGELOG.md new file mode 100644 index 000000000..3564abc1f --- /dev/null +++ b/vendor/proptest/CHANGELOG.md @@ -0,0 +1,910 @@ +## Unreleased + +### 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`. + +### 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` + +## 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 depndency (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/AltSysrq/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 licence 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/AltSysrq/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<S>` with `S::Value` or `<S as Strategy>::Value` as necessary. + +- `From<SizeRange>` 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::<SystemTime>()` 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<S> 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<bool>` 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::<type>()`. + +- 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<SizeRange>`. + +- `..= 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<Idx>`, `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<S>` 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 `<S::Tree as ValueTree>::Value` for some strategy `S`. + This change allows you to write `-> impl Strategy<Value = T>` for functions + returning a `Strategy` generating `T`s. This is more ergonomic to use than + `-> impl Strategy<Value = impl ValueTree<Value = T>>`. + +- 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<T>` is no longer the correct type. + The new return type is `-> impl Strategy<Value = T>`. + 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/AltSysrq/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::<ArgsOs>()` or `any::<VarsOs>()` 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<Box<FailurePersistence>>`. + +- 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<BoxedStrategy<T>>` as `Recursive` now internally uses `BoxedStrategy<T>` + instead as well as expecting a `Fn(BoxedStrategy<T>) -> R` instead of + `Fn(Arc<BoxedStrategy<T>>) -> R`. In addition, the type of recursive + strategies has changed from `Recursive<BoxedStrategy<T>, F>` to just + `Recursive<T, F>`. + +### Minor changes + +- Reduced indirections and heap allocations inside `Recursive<T, F>` somewhat. + +- `BoxedStrategy<T>` and `SBoxedStrategy<T>` now use `Arc` internally instead of + using `Box`. While this has marginal overhead, it also reduces the overhead + in `Recursive<T, F>`. 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<T>` but rather + `Box<Strategy<Value = Box<ValueTree<Value = T>>>>`. 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::<T>()`. 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<usize>`. Conversions from types + such as `usize` and `Range<usize>` 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<OutputType>`. 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<fn() -> 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<Self::Value, String>`, strategies are + expected to return `-> Result<Self::Value, Reason>` 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<S>` where `S: Strategy` + defined as: `type NewTree<S> = Result<<S as Strategy>::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/AltSysrq/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<S>` where `S: Strategy`. This is a shorter way + to refer to: `<<S as Strategy>::Value as ValueTree>::Value`. + +- Added a type alias `type W<T> = (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<T>` 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()`. diff --git a/vendor/proptest/Cargo.lock b/vendor/proptest/Cargo.lock new file mode 100644 index 000000000..cea6b2ad4 --- /dev/null +++ b/vendor/proptest/Cargo.lock @@ -0,0 +1,328 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +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.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bit_field" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcb6dd1c2376d2e096796e234a70e17e94cc2d5d54ff8ce42b28cef1d0d359a4" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "fastrand" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" +dependencies = [ + "instant", +] + +[[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.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[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.139" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79" + +[[package]] +name = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +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 = "proptest" +version = "1.1.0" +dependencies = [ + "bit-set", + "bitflags", + "byteorder", + "lazy_static", + "num-traits", + "quick-error 2.0.1", + "rand", + "rand_chacha", + "rand_xorshift", + "regex", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", + "x86", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[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.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c307f7aacdbab3f0adee67d52739a1d71112cc068d6fab169ddeb18e48877fad" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" + +[[package]] +name = "remove_dir_all" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" +dependencies = [ + "winapi", +] + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error 1.2.3", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "tempfile" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" +dependencies = [ + "cfg-if", + "fastrand", + "libc", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[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-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "x86" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385" +dependencies = [ + "bit_field", + "bitflags", + "raw-cpuid", +] diff --git a/vendor/proptest/Cargo.toml b/vendor/proptest/Cargo.toml new file mode 100644 index 000000000..1d03f9c0b --- /dev/null +++ b/vendor/proptest/Cargo.toml @@ -0,0 +1,132 @@ +# 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" +name = "proptest" +version = "1.1.0" +authors = ["Jason Lingle"] +exclude = [ + "/gen-*.sh", + "/readme-*.md", +] +description = """ +Hypothesis-like property-based testing and shrinking. +""" +homepage = "https://altsysrq.github.io/proptest-book/proptest/index.html" +documentation = "https://altsysrq.github.io/rustdoc/proptest/1.0.0/proptest/" +readme = "README.md" +keywords = [ + "property", + "testing", + "quickcheck", + "fuzz", + "hypothesis", +] +categories = ["development-tools::testing"] +license = "MIT/Apache-2.0" +repository = "https://github.com/proptest-rs/proptest" + +[dependencies.bit-set] +version = "0.5.0" +optional = true + +[dependencies.bitflags] +version = "1.0.1" + +[dependencies.byteorder] +version = "1.2.3" +default-features = false + +[dependencies.lazy_static] +version = "1.2" +optional = true + +[dependencies.num-traits] +version = "0.2.15" +features = ["libm"] +default-features = false + +[dependencies.quick-error] +version = "2.0.0" +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.6.0" +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" + +[features] +alloc = [] +atomic64bit = [] +break-dead-code = [] +default = [ + "std", + "fork", + "timeout", + "bit-set", + "break-dead-code", +] +default-code-coverage = [ + "std", + "fork", + "timeout", + "bit-set", +] +fork = [ + "std", + "rusty-fork", + "tempfile", +] +hardware-rng = ["x86"] +std = [ + "rand/std", + "byteorder/std", + "lazy_static", + "quick-error", + "regex-syntax", + "num-traits/std", +] +timeout = [ + "fork", + "rusty-fork/timeout", +] +unstable = [] diff --git a/vendor/proptest/LICENSE-APACHE b/vendor/proptest/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/vendor/proptest/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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. diff --git a/vendor/proptest/LICENSE-MIT b/vendor/proptest/LICENSE-MIT new file mode 100644 index 000000000..63ceeec5c --- /dev/null +++ b/vendor/proptest/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (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. diff --git a/vendor/proptest/README.md b/vendor/proptest/README.md new file mode 100644 index 000000000..be14e7547 --- /dev/null +++ b/vendor/proptest/README.md @@ -0,0 +1,399 @@ +# Proptest + +[![Build Status](https://github.com/AltSysrq/proptest/workflows/Rust/badge.svg?branch=master)](https://github.com/AltSysrq/proptest/actions) +[![Build status](https://ci.appveyor.com/api/projects/status/ofe98xfthbx1m608/branch/master?svg=true)](https://ci.appveyor.com/project/AltSysrq/proptest/branch/master) +[![](http://meritbadge.herokuapp.com/proptest)](https://crates.io/crates/proptest) +[![](https://img.shields.io/website/https/altsysrq.github.io/proptest-book.svg)][book] +[![](https://docs.rs/proptest/badge.svg)][api-docs] + +[book]: https://altsysrq.github.io/proptest-book/intro.html +[api-docs]: https://altsysrq.github.io/rustdoc/proptest/latest/proptest/ +## Introduction + +Proptest is a property testing framework (i.e., the QuickCheck family) +inspired by the [Hypothesis](http://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/AltSysrq/proptest/blob/master/proptest/CHANGELOG.md) +for a full list of substantial historical changes, breaking and otherwise. + +### 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::<u32>().ok().and_then( + |y| month.parse::<u32>().ok().and_then( + |m| day.parse::<u32>().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://altsysrq.github.io/proptest-book/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::<u32>().ok().and_then( + |y| month.parse::<u32>().ok().and_then( + |m| day.parse::<u32>().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://altsysrq.github.io/rustdoc/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](http://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. diff --git a/vendor/proptest/examples/config-defaults.rs b/vendor/proptest/examples/config-defaults.rs new file mode 100644 index 000000000..8c9817af6 --- /dev/null +++ b/vendor/proptest/examples/config-defaults.rs @@ -0,0 +1,14 @@ +//- +// 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 proptest::test_runner::Config; + +fn main() { + println!("Default config: {:?}", Config::default()); +} diff --git a/vendor/proptest/examples/dateparser_v1.rs b/vendor/proptest/examples/dateparser_v1.rs new file mode 100644 index 000000000..9b9c78c7c --- /dev/null +++ b/vendor/proptest/examples/dateparser_v1.rs @@ -0,0 +1,48 @@ +//- +// 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 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::<u32>().ok().and_then(|y| { + month + .parse::<u32>() + .ok() + .and_then(|m| day.parse::<u32>().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(); +} diff --git a/vendor/proptest/examples/dateparser_v2.rs b/vendor/proptest/examples/dateparser_v2.rs new file mode 100644 index 000000000..45ec4e8f9 --- /dev/null +++ b/vendor/proptest/examples/dateparser_v2.rs @@ -0,0 +1,66 @@ +//- +// 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 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::<u32>().ok().and_then(|y| { + month + .parse::<u32>() + .ok() + .and_then(|m| day.parse::<u32>().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(); +} diff --git a/vendor/proptest/examples/fib.rs b/vendor/proptest/examples/fib.rs new file mode 100644 index 000000000..f2d440853 --- /dev/null +++ b/vendor/proptest/examples/fib.rs @@ -0,0 +1,51 @@ +//- +// Copyright 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. + +// 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(); +} diff --git a/vendor/proptest/examples/tutorial-simplify-play.rs b/vendor/proptest/examples/tutorial-simplify-play.rs new file mode 100644 index 000000000..fed4c1def --- /dev/null +++ b/vendor/proptest/examples/tutorial-simplify-play.rs @@ -0,0 +1,27 @@ +//- +// 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. + +// 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()); + } +} diff --git a/vendor/proptest/examples/tutorial-strategy-play.rs b/vendor/proptest/examples/tutorial-strategy-play.rs new file mode 100644 index 000000000..52b293093 --- /dev/null +++ b/vendor/proptest/examples/tutorial-strategy-play.rs @@ -0,0 +1,29 @@ +//- +// 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. + +// 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() + ); +} diff --git a/vendor/proptest/proptest-regressions/arbitrary/_std/env.txt b/vendor/proptest/proptest-regressions/arbitrary/_std/env.txt new file mode 100644 index 000000000..f15e33a4e --- /dev/null +++ b/vendor/proptest/proptest-regressions/arbitrary/_std/env.txt @@ -0,0 +1,7 @@ +# 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 diff --git a/vendor/proptest/proptest-regressions/test_runner/rng.txt b/vendor/proptest/proptest-regressions/test_runner/rng.txt new file mode 100644 index 000000000..939267e03 --- /dev/null +++ b/vendor/proptest/proptest-regressions/test_runner/rng.txt @@ -0,0 +1,8 @@ +# 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, []) diff --git a/vendor/proptest/src/arbitrary/_alloc/alloc.rs b/vendor/proptest/src/arbitrary/_alloc/alloc.rs new file mode 100644 index 000000000..598c80ff0 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_alloc/alloc.rs @@ -0,0 +1,59 @@ +//- +// 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. + +//! 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<u8>, StrategyFor<usize>), 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::<usize>()), |(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<Self>; 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<Just<Self>>, WA<Just<Self>>)>; + 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 + ); +} diff --git a/vendor/proptest/src/arbitrary/_alloc/borrow.rs b/vendor/proptest/src/arbitrary/_alloc/borrow.rs new file mode 100644 index 000000000..153115e18 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_alloc/borrow.rs @@ -0,0 +1,27 @@ +//- +// 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. + +//! 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>, B: ToOwned<Owned = A> + fmt::Debug + ?Sized] + Cow<'static, B>, SMapped<A, Self>, A::Parameters; + args => static_map(any_with::<A>(args), Cow::Owned) +); + +lift1!([Borrow<B> + 'static, B: ToOwned<Owned = A> + fmt::Debug + ?Sized] + Cow<'static, B>; base => static_map(base, Cow::Owned) +); diff --git a/vendor/proptest/src/arbitrary/_alloc/boxed.rs b/vendor/proptest/src/arbitrary/_alloc/boxed.rs new file mode 100644 index 000000000..222362504 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_alloc/boxed.rs @@ -0,0 +1,19 @@ +//- +// 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. + +//! Arbitrary implementations for `std::boxed`. + +use crate::std_facade::Box; + +wrap_from!(Box); + +#[cfg(test)] +mod test { + no_panic_test!(boxed => Box<u8>); +} diff --git a/vendor/proptest/src/arbitrary/_alloc/char.rs b/vendor/proptest/src/arbitrary/_alloc/char.rs new file mode 100644 index 000000000..fab9dd824 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_alloc/char.rs @@ -0,0 +1,89 @@ +//- +// 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. + +//! 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<char, Self>; + static_map(any::<char>(), $mapper)); + }; +} + +impl_wrap_char!(EscapeDebug, char::escape_debug); +impl_wrap_char!(EscapeDefault, char::escape_default); +impl_wrap_char!(EscapeUnicode, char::escape_unicode); +#[cfg(feature = "unstable")] +impl_wrap_char!(ToLowercase, char::to_lowercase); +#[cfg(feature = "unstable")] +impl_wrap_char!(ToUppercase, char::to_uppercase); + +#[cfg(feature = "break-dead-code")] +arbitrary!(DecodeUtf16<<Vec<u16> as IntoIterator>::IntoIter>, + SMapped<Vec<u16>, Self>; + static_map(vec(any::<u16>(), ..VEC_MAX), decode_utf16) +); + +arbitrary!(ParseCharError, IndFlatten<Mapped<bool, Just<Self>>>; + any::<bool>().prop_ind_flat_map(|is_two| + Just((if is_two { "__" } else { "" }).parse::<char>().unwrap_err())) +); + +#[cfg(feature = "unstable")] +arbitrary!(CharTryFromError; { + use core::convert::TryFrom; + char::try_from(0xD800 as u32).unwrap_err() +}); + +arbitrary!(DecodeUtf16Error, SFnPtrMap<Range<u16>, Self>; + static_map(0xD800..0xE000, |x| + decode_utf16(once(x)).next().unwrap().unwrap_err()) +); + +#[cfg(test)] +mod test { + no_panic_test!( + escape_debug => EscapeDebug, + escape_default => EscapeDefault, + escape_unicode => EscapeUnicode, + parse_char_error => ParseCharError, + decode_utf16_error => DecodeUtf16Error + ); + + #[cfg(feature = "break-dead-code")] + no_panic_test!( + decode_utf16 => DecodeUtf16<<Vec<u16> as IntoIterator>::IntoIter> + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + to_lowercase => ToLowercase, + to_uppercase => ToUppercase, + char_try_from_error => CharTryFromError + ); +} diff --git a/vendor/proptest/src/arbitrary/_alloc/collections.rs b/vendor/proptest/src/arbitrary/_alloc/collections.rs new file mode 100644 index 000000000..20f3a9292 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_alloc/collections.rs @@ -0,0 +1,304 @@ +//- +// 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. + +//! Arbitrary implementations for `std::collections`. + +//#![cfg_attr(feature="cargo-clippy", allow(implicit_hasher))] + +//============================================================================== +// Imports: +//============================================================================== + +use crate::std_facade::{ + binary_heap, btree_map, btree_set, fmt, linked_list, vec, vec_deque, Arc, + BTreeMap, BTreeSet, BinaryHeap, Box, LinkedList, Rc, Vec, VecDeque, +}; +use core::hash::Hash; +use core::ops::{Bound, RangeInclusive}; + +#[cfg(feature = "std")] +use crate::std_facade::{hash_map, hash_set, HashMap, HashSet}; + +use crate::arbitrary::*; +use crate::collection::*; +use crate::strategy::statics::static_map; +use crate::strategy::*; + +//============================================================================== +// Macros: +//============================================================================== + +/// Parameters for configuring the generation of `StrategyFor<...<A>>`. +type RangedParams1<A> = product_type![SizeRange, A]; + +/// Parameters for configuring the generation of `StrategyFor<...<A, B>>`. +type RangedParams2<A, B> = product_type![SizeRange, A, B]; + +macro_rules! impl_1 { + ($typ: ident, $strat: ident, $($bound : path),* => $fun: ident) => { + arbitrary!([A: Arbitrary $(+ $bound)*] $typ<A>, + $strat<A::Strategy>, RangedParams1<A::Parameters>; + args => { + let product_unpack![range, a] = args; + $fun(any_with::<A>(a), range) + }); + + lift1!([$($bound+)*] $typ<A>, SizeRange; + base, args => $fun(base, args)); + }; +} + +arbitrary!(SizeRange, MapInto<StrategyFor<RangeInclusive<usize>>, Self>; + any::<RangeInclusive<usize>>().prop_map_into() +); + +//============================================================================== +// Vec, VecDeque, LinkedList, BTreeSet, BinaryHeap, HashSet, HashMap: +//============================================================================== + +macro_rules! dst_wrapped { + ($($w: ident),*) => { + $(arbitrary!([A: Arbitrary] $w<[A]>, + MapInto<StrategyFor<Vec<A>>, Self>, + <Vec<A> as Arbitrary>::Parameters; + a => any_with::<Vec<A>>(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<A>, + SMapped<$type<A>, Self>, + <$type<A> as Arbitrary>::Parameters; + args => static_map(any_with::<$type<A>>(args), $type::into_iter)); + + lift1!(['static + $($bound+)*] $module::IntoIter<A>, 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<A, B>, +HashMapStrategy<A::Strategy, B::Strategy>, +RangedParams2<A::Parameters, B::Parameters>; +args => { + let product_unpack![range, a, b] = args; + hash_map(any_with::<A>(a), any_with::<B>(b), range) +}); + +#[cfg(feature = "std")] +arbitrary!([A: Arbitrary + Hash + Eq, B: Arbitrary] hash_map::IntoIter<A, B>, + SMapped<HashMap<A, B>, Self>, + <HashMap<A, B> as Arbitrary>::Parameters; + args => static_map(any_with::<HashMap<A, B>>(args), HashMap::into_iter)); + +#[cfg(feature = "std")] +lift1!([, K: Hash + Eq + Arbitrary + 'static] HashMap<K, A>, + RangedParams1<K::Parameters>; + base, args => { + let product_unpack![range, k] = args; + hash_map(any_with::<K>(k), base, range) + } +); + +#[cfg(feature = "std")] +lift1!(['static, K: Hash + Eq + Arbitrary + 'static] hash_map::IntoIter<K, A>, + RangedParams1<K::Parameters>; + base, args => { + let product_unpack![range, k] = args; + static_map(hash_map(any_with::<K>(k), base, range), HashMap::into_iter) + } +); + +#[cfg(feature = "std")] +impl<A: fmt::Debug + Eq + Hash, B: fmt::Debug> functor::ArbitraryF2<A, B> + for HashMap<A, B> +{ + type Parameters = SizeRange; + + fn lift2_with<AS, BS>( + fst: AS, + snd: BS, + args: Self::Parameters, + ) -> BoxedStrategy<Self> + where + AS: Strategy<Value = A> + 'static, + BS: Strategy<Value = B> + 'static, + { + hash_map(fst, snd, args).boxed() + } +} + +#[cfg(feature = "std")] +impl<A: fmt::Debug + Eq + Hash + 'static, B: fmt::Debug + 'static> + functor::ArbitraryF2<A, B> for hash_map::IntoIter<A, B> +{ + type Parameters = SizeRange; + + fn lift2_with<AS, BS>( + fst: AS, + snd: BS, + args: Self::Parameters, + ) -> BoxedStrategy<Self> + where + AS: Strategy<Value = A> + 'static, + BS: Strategy<Value = B> + 'static, + { + static_map(hash_map(fst, snd, args), HashMap::into_iter).boxed() + } +} + +//============================================================================== +// BTreeMap: +//============================================================================== + +arbitrary!([A: Arbitrary + Ord, B: Arbitrary] BTreeMap<A, B>, +BTreeMapStrategy<A::Strategy, B::Strategy>, +RangedParams2<A::Parameters, B::Parameters>; +args => { + let product_unpack![range, a, b] = args; + btree_map(any_with::<A>(a), any_with::<B>(b), range) +}); + +lift1!([, K: Ord + Arbitrary + 'static] BTreeMap<K, A>, + RangedParams1<K::Parameters>; + base, args => { + let product_unpack![range, k] = args; + btree_map(any_with::<K>(k), base, range) + } +); + +impl<A: fmt::Debug + Ord, B: fmt::Debug> functor::ArbitraryF2<A, B> + for BTreeMap<A, B> +{ + type Parameters = SizeRange; + fn lift2_with<AS, BS>( + fst: AS, + snd: BS, + args: Self::Parameters, + ) -> BoxedStrategy<Self> + where + AS: Strategy<Value = A> + 'static, + BS: Strategy<Value = B> + 'static, + { + btree_map(fst, snd, args).boxed() + } +} + +arbitrary!([A: Arbitrary + Ord, B: Arbitrary] btree_map::IntoIter<A, B>, + SMapped<BTreeMap<A, B>, Self>, + <BTreeMap<A, B> as Arbitrary>::Parameters; + args => static_map(any_with::<BTreeMap<A, B>>(args), BTreeMap::into_iter)); + +impl<A: fmt::Debug + Ord + 'static, B: fmt::Debug + 'static> + functor::ArbitraryF2<A, B> for btree_map::IntoIter<A, B> +{ + type Parameters = SizeRange; + + fn lift2_with<AS, BS>( + fst: AS, + snd: BS, + args: Self::Parameters, + ) -> BoxedStrategy<Self> + where + AS: Strategy<Value = A> + 'static, + BS: Strategy<Value = B> + 'static, + { + static_map(btree_map(fst, snd, args), BTreeMap::into_iter).boxed() + } +} + +//============================================================================== +// Bound: +//============================================================================== + +arbitrary!([A: Arbitrary] Bound<A>, + TupleUnion<( + WA<SFnPtrMap<Arc<A::Strategy>, Self>>, + WA<SFnPtrMap<Arc<A::Strategy>, Self>>, + WA<LazyJustFn<Self>> + )>, + A::Parameters; + args => { + let base = Arc::new(any_with::<A>(args)); + prop_oneof![ + 2 => static_map(base.clone(), Bound::Included), + 2 => static_map(base, Bound::Excluded), + 1 => LazyJust::new(|| Bound::Unbounded), + ] + } +); + +lift1!(['static] Bound<A>; 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<u8>, + box_slice => Box<[u8]>, + rc_slice => Rc<[u8]>, + arc_slice => Arc<[u8]>, + vec_deque => VecDeque<u8>, + linked_list => LinkedList<u8>, + btree_set => BTreeSet<u8>, + btree_map => BTreeMap<u8, u8>, + bound => Bound<u8>, + binary_heap => BinaryHeap<u8>, + into_iter_vec => vec::IntoIter<u8>, + into_iter_vec_deque => vec_deque::IntoIter<u8>, + into_iter_linked_list => linked_list::IntoIter<u8>, + into_iter_binary_heap => binary_heap::IntoIter<u8>, + into_iter_btree_set => btree_set::IntoIter<u8>, + into_iter_btree_map => btree_map::IntoIter<u8, u8> + ); + + #[cfg(feature = "std")] + no_panic_test!( + hash_set => HashSet<u8>, + hash_map => HashMap<u8, u8>, + into_iter_hash_set => hash_set::IntoIter<u8>, + into_iter_hash_map => hash_map::IntoIter<u8, u8> + ); +} diff --git a/vendor/proptest/src/arbitrary/_alloc/hash.rs b/vendor/proptest/src/arbitrary/_alloc/hash.rs new file mode 100644 index 000000000..8979bafca --- /dev/null +++ b/vendor/proptest/src/arbitrary/_alloc/hash.rs @@ -0,0 +1,32 @@ +//- +// 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. + +//! 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<H>; 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<DefaultHasher> + ); +} diff --git a/vendor/proptest/src/arbitrary/_alloc/mod.rs b/vendor/proptest/src/arbitrary/_alloc/mod.rs new file mode 100644 index 000000000..f286cab6d --- /dev/null +++ b/vendor/proptest/src/arbitrary/_alloc/mod.rs @@ -0,0 +1,22 @@ +//- +// 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. + +//! Arbitrary implementations for liballoc. + +#[cfg(feature = "unstable")] +mod alloc; +mod borrow; +mod boxed; +mod char; +mod collections; +mod hash; +mod ops; +mod rc; +mod str; +mod sync; diff --git a/vendor/proptest/src/arbitrary/_alloc/ops.rs b/vendor/proptest/src/arbitrary/_alloc/ops.rs new file mode 100644 index 000000000..338f52c50 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_alloc/ops.rs @@ -0,0 +1,104 @@ +//- +// 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. + +//! 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<A>, + 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<A>; 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<A>, + 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<A>; base => { + let base = Arc::new(base); + (base.clone(), base).prop_map(|(a, b)| if b < a { b..a } else { a..b }) +}); + +#[cfg(feature = "unstable")] +arbitrary!( + [Y: Arbitrary, R: Arbitrary] GeneratorState<Y, R>, + TupleUnion<(WA<SMapped<Y, Self>>, WA<SMapped<R, Self>>)>, + product_type![Y::Parameters, R::Parameters]; + args => { + let product_unpack![y, r] = args; + prop_oneof![ + static_map(any_with::<Y>(y), GeneratorState::Yielded), + static_map(any_with::<R>(r), GeneratorState::Complete) + ] + } +); + +#[cfg(feature = "unstable")] +use core::fmt; + +#[cfg(feature = "unstable")] +impl<A: fmt::Debug + 'static, B: fmt::Debug + 'static> + functor::ArbitraryF2<A, B> for GeneratorState<A, B> +{ + type Parameters = (); + + fn lift2_with<AS, BS>( + fst: AS, + snd: BS, + _args: Self::Parameters, + ) -> BoxedStrategy<Self> + where + AS: Strategy<Value = A> + 'static, + BS: Strategy<Value = B> + 'static, + { + prop_oneof![ + fst.prop_map(GeneratorState::Yielded), + snd.prop_map(GeneratorState::Complete) + ] + .boxed() + } +} + +#[cfg(test)] +mod test { + no_panic_test!( + range_full => RangeFull, + range_from => RangeFrom<usize>, + range_to => RangeTo<usize>, + range => Range<usize>, + range_inclusive => RangeInclusive<usize>, + range_to_inclusive => RangeToInclusive<usize> + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + generator_state => GeneratorState<u32, u64> + ); +} diff --git a/vendor/proptest/src/arbitrary/_alloc/rc.rs b/vendor/proptest/src/arbitrary/_alloc/rc.rs new file mode 100644 index 000000000..1ddb6aa00 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_alloc/rc.rs @@ -0,0 +1,21 @@ +//- +// 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. + +//! 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<u8>); +} diff --git a/vendor/proptest/src/arbitrary/_alloc/str.rs b/vendor/proptest/src/arbitrary/_alloc/str.rs new file mode 100644 index 000000000..72ba248da --- /dev/null +++ b/vendor/proptest/src/arbitrary/_alloc/str.rs @@ -0,0 +1,49 @@ +//- +// 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. + +//! 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::<bool>().unwrap_err()); + +type ELSeq = WA<Just<&'static [u8]>>; +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<u16>, ELSeqs), Utf8Error>; + static_map((any::<u16>(), gen_el_seqs()), |(vut, elseq)| { + let v = repeat(b'_').take(vut as usize) + .chain(elseq.iter().cloned()) + .collect::<Vec<u8>>(); + from_utf8(&v).unwrap_err() + }) +); + +#[cfg(test)] +mod test { + no_panic_test!( + parse_bool_errror => ParseBoolError, + utf8_error => Utf8Error + ); +} diff --git a/vendor/proptest/src/arbitrary/_alloc/sync.rs b/vendor/proptest/src/arbitrary/_alloc/sync.rs new file mode 100644 index 000000000..ebc222581 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_alloc/sync.rs @@ -0,0 +1,76 @@ +//- +// 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. + +//! 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<Just<Self>>, WA<Just<Self>>, WA<Just<Self>>, + WA<Just<Self>>, WA<Just<Self>>)>; + 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<u8>, + atomic_bool => AtomicBool, + atomic_isize => AtomicIsize, + atomic_usize => AtomicUsize, + ordering => Ordering + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + atomic_i8 => AtomicI8, + atomic_i16 => AtomicI16, + atomic_i32 => AtomicI32, + atomic_u8 => AtomicU8, + atomic_u16 => AtomicU16, + atomic_u32 => AtomicU32 + ); + + #[cfg(all(feature = "unstable", feature = "atomic64bit"))] + no_panic_test!( + atomic_i64 => AtomicI64, + atomic_u64 => AtomicU64 + ); +} diff --git a/vendor/proptest/src/arbitrary/_core/ascii.rs b/vendor/proptest/src/arbitrary/_core/ascii.rs new file mode 100644 index 000000000..ded19289b --- /dev/null +++ b/vendor/proptest/src/arbitrary/_core/ascii.rs @@ -0,0 +1,23 @@ +//- +// 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. + +//! Arbitrary implementations for `std::ascii`. + +use core::ascii::{escape_default, EscapeDefault}; + +use crate::arbitrary::*; +use crate::strategy::statics::static_map; + +arbitrary!(EscapeDefault, SMapped<u8, Self>; + static_map(any::<u8>(), escape_default)); + +#[cfg(test)] +mod test { + no_panic_test!(escape_default => EscapeDefault); +} diff --git a/vendor/proptest/src/arbitrary/_core/cell.rs b/vendor/proptest/src/arbitrary/_core/cell.rs new file mode 100644 index 000000000..c10148fb9 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_core/cell.rs @@ -0,0 +1,48 @@ +//- +// 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. + +//! Arbitrary implementations for `std::cell`. + +use core::cell::{BorrowError, BorrowMutError, Cell, RefCell, UnsafeCell}; + +wrap_from!([Copy] Cell); +wrap_from!(RefCell); +wrap_from!(UnsafeCell); + +lazy_just!(BorrowError, || { + // False positive: + #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))] + { + let _rc = RefCell::new(()); + let _bm = _rc.borrow_mut(); + let _tb = _rc.try_borrow(); + let ret = _rc.try_borrow().expect_err("reborrowed RefCell"); + ret + } +}); +lazy_just!(BorrowMutError, || { + // False positive: + #[cfg_attr(feature = "cargo-clippy", allow(let_and_return))] + { + let _rc = RefCell::new(()); + let _bm = _rc.borrow_mut(); + let _tb = _rc.try_borrow(); + let ret = _rc.try_borrow_mut().expect_err("reborrowed RefCell"); + ret + } +}); + +#[cfg(test)] +mod test { + no_panic_test!( + cell => Cell<u8>, + ref_cell => RefCell<u8>, + unsafe_cell => UnsafeCell<u8> + ); +} diff --git a/vendor/proptest/src/arbitrary/_core/cmp.rs b/vendor/proptest/src/arbitrary/_core/cmp.rs new file mode 100644 index 000000000..75637d45c --- /dev/null +++ b/vendor/proptest/src/arbitrary/_core/cmp.rs @@ -0,0 +1,33 @@ +//- +// 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. + +//! Arbitrary implementations for `std::cmp`. + +use core::cmp::{Ordering, Reverse}; + +use crate::strategy::{Just, TupleUnion, WA}; + +wrap_ctor!(Reverse, Reverse); + +type WAJO = WA<Just<Ordering>>; +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<u8>, + ordering => Ordering + ); +} diff --git a/vendor/proptest/src/arbitrary/_core/convert.rs b/vendor/proptest/src/arbitrary/_core/convert.rs new file mode 100644 index 000000000..b74d78620 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_core/convert.rs @@ -0,0 +1,16 @@ +//- +// 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. + +//! Arbitrary implementations for `std::convert`. + +// No sensible Arbitrary impl exists for void-like types like +// std::convert::Infallible. +// +// Auto-deriving should take care to simply not include such +// types in generation instead! diff --git a/vendor/proptest/src/arbitrary/_core/fmt.rs b/vendor/proptest/src/arbitrary/_core/fmt.rs new file mode 100644 index 000000000..b16b8968c --- /dev/null +++ b/vendor/proptest/src/arbitrary/_core/fmt.rs @@ -0,0 +1,18 @@ +//- +// 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. + +//! Arbitrary implementations for `std::fmt`. + +use core::fmt::Error; +arbitrary!(Error; Error); + +#[cfg(test)] +mod test { + no_panic_test!(error => Error); +} diff --git a/vendor/proptest/src/arbitrary/_core/iter.rs b/vendor/proptest/src/arbitrary/_core/iter.rs new file mode 100644 index 000000000..d9d5364f6 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_core/iter.rs @@ -0,0 +1,188 @@ +//- +// 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. + +//! 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<Item = T>, T: fmt::Debug] Peekable, Iterator::peekable); +wrap_ctor!([DoubleEndedIterator] Rev, Iterator::rev); + +arbitrary!(['a, T: 'a + Clone, A: Arbitrary + Iterator<Item = &'a T>] + Cloned<A>, SMapped<A, Self>, A::Parameters; + args => static_map(any_with::<A>(args), Iterator::cloned)); + +impl< + T: 'static + Clone, + A: fmt::Debug + 'static + Iterator<Item = &'static T>, + > functor::ArbitraryF1<A> for Cloned<A> +{ + type Parameters = (); + + fn lift1_with<S>(base: S, _args: Self::Parameters) -> BoxedStrategy<Self> + where + S: Strategy<Value = A> + 'static, + { + base.prop_map(Iterator::cloned).boxed() + } +} + +arbitrary!([A] Empty<A>; empty()); + +arbitrary!( + [A: Arbitrary + Iterator, B: Arbitrary + Iterator] + Zip<A, B>, 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, A>, + B::Parameters; + base, args => + (any_with::<B>(args), base).prop_map(|(b, a)| b.zip(a)).boxed() +); + +impl<A: fmt::Debug + Iterator, B: fmt::Debug + Iterator> + functor::ArbitraryF2<A, B> for Zip<A, B> +{ + type Parameters = (); + + fn lift2_with<AS, BS>( + fst: AS, + snd: BS, + _args: Self::Parameters, + ) -> BoxedStrategy<Self> + where + AS: Strategy<Value = A> + 'static, + BS: Strategy<Value = B> + 'static, + { + (fst, snd).prop_map(|(a, b)| a.zip(b)).boxed() + } +} + +arbitrary!( + [T, + A: Arbitrary + Iterator<Item = T>, + B: Arbitrary + Iterator<Item = T>] + Chain<A, B>, 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<Item = T>, + B: 'static + Arbitrary + Iterator<Item = T>, + T] + Chain<B, A>, + B::Parameters; + base, args => + (any_with::<B>(args), base).prop_map(|(b, a)| b.chain(a)).boxed() +); + +impl< + T, + A: fmt::Debug + Iterator<Item = T>, + B: fmt::Debug + Iterator<Item = T>, + > functor::ArbitraryF2<A, B> for Chain<A, B> +{ + type Parameters = (); + + fn lift2_with<AS, BS>( + fst: AS, + snd: BS, + _args: Self::Parameters, + ) -> BoxedStrategy<Self> + where + AS: Strategy<Value = A> + 'static, + BS: Strategy<Value = B> + 'static, + { + (fst, snd).prop_map(|(a, b)| a.chain(b)).boxed() + } +} + +macro_rules! usize_mod { + ($type: ident, $mapper: ident) => { + arbitrary!([A: Arbitrary + Iterator] $type<A>, + SMapped<(A, usize), Self>, A::Parameters; + a => static_map( + any_with::<(A, usize)>(product_pack![a, ()]), + |(a, b)| a.$mapper(b) + ) + ); + + lift1!([Iterator] $type<A>; + base => (base, any::<usize>()).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<Range<u8>, Self>; static_map(0..5, Dummy)); + impl Iterator for Dummy { + type Item = &'static u8; + fn next(&mut self) -> Option<Self::Item> { + if self.0 < 5 { + let r = &DUMMY[self.0 as usize]; + self.0 += 1; + Some(r) + } else { + None + } + } + } + + no_panic_test!( + empty => Empty<u8>, + once => Once<u8>, + repeat => Repeat<u8>, + cloned => Cloned<super::Dummy>, + cycle => Cycle<Once<u8>>, + enumerate => Enumerate<Repeat<u8>>, + fuse => Fuse<Once<u8>>, + peekable => Peekable<Repeat<u8>>, + rev => Rev<::std::vec::IntoIter<u8>>, + zip => Zip<Repeat<u8>, Repeat<u16>>, + chain => Chain<Once<u8>, Once<u8>>, + skip => Skip<Repeat<u8>>, + take => Take<Repeat<u8>> + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + step_by => StepBy<Repeat<u8>> + ); +} diff --git a/vendor/proptest/src/arbitrary/_core/marker.rs b/vendor/proptest/src/arbitrary/_core/marker.rs new file mode 100644 index 000000000..6558f57ab --- /dev/null +++ b/vendor/proptest/src/arbitrary/_core/marker.rs @@ -0,0 +1,19 @@ +//- +// 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. + +//! Arbitrary implementations for `std::marker`. + +use core::marker::PhantomData; + +arbitrary!([T: ?Sized] PhantomData<T>; PhantomData); + +#[cfg(test)] +mod test { + no_panic_test!(phantom_data => PhantomData<u8>); +} diff --git a/vendor/proptest/src/arbitrary/_core/mem.rs b/vendor/proptest/src/arbitrary/_core/mem.rs new file mode 100644 index 000000000..700e40fbe --- /dev/null +++ b/vendor/proptest/src/arbitrary/_core/mem.rs @@ -0,0 +1,42 @@ +//- +// 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. + +//! Arbitrary implementations for `std::mem`. + +use core::mem::*; + +use crate::arbitrary::*; +use crate::strategy::statics::static_map; + +arbitrary!([A: Arbitrary] Discriminant<A>, + SMapped<A, Self>, A::Parameters; + args => static_map(any_with::<A>(args), |x| discriminant(&x)) +); + +lift1!(['static] Discriminant<A>; + 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<u8>, // Trivial destructor. + discriminant_struct => Discriminant<super::DummyStruct>, + discriminant_enum => Discriminant<::std::num::FpCategory> + ); +} diff --git a/vendor/proptest/src/arbitrary/_core/mod.rs b/vendor/proptest/src/arbitrary/_core/mod.rs new file mode 100644 index 000000000..5fc3742e4 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_core/mod.rs @@ -0,0 +1,22 @@ +//- +// 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. + +//! Arbitrary implementations for libcore. + +mod ascii; +mod cell; +mod cmp; +mod convert; +mod fmt; +mod iter; +mod marker; +mod mem; +mod num; +mod option; +mod result; diff --git a/vendor/proptest/src/arbitrary/_core/num.rs b/vendor/proptest/src/arbitrary/_core/num.rs new file mode 100644 index 000000000..f2988ecf0 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_core/num.rs @@ -0,0 +1,55 @@ +//- +// 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. + +//! Arbitrary implementations for `std::num`. + +use core::num::*; + +use crate::strategy::*; + +arbitrary!(ParseFloatError; "".parse::<f32>().unwrap_err()); +arbitrary!(ParseIntError; "".parse::<u32>().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<Just<Self>>, WA<Just<Self>>, WA<Just<Self>>, + WA<Just<Self>>, WA<Just<Self>>)>; + { + 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<u8>, + fp_category => FpCategory + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + try_from_int_error => TryFromIntError + ); +} diff --git a/vendor/proptest/src/arbitrary/_core/option.rs b/vendor/proptest/src/arbitrary/_core/option.rs new file mode 100644 index 000000000..8b93545c8 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_core/option.rs @@ -0,0 +1,57 @@ +//- +// 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. + +//! 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<RangeInclusive<f64>, Self>; + (0.0..=1.0).prop_map_into() +); + +// These are Option<AnUninhabitedType> impls: + +arbitrary!(Option<string::ParseError>; None); +#[cfg(feature = "unstable")] +arbitrary!(Option<!>; None); + +arbitrary!([A: Arbitrary] opt::Option<A>, OptionStrategy<A::Strategy>, + product_type![Probability, A::Parameters]; + args => { + let product_unpack![prob, a] = args; + weighted(prob, any_with::<A>(a)) + } +); + +lift1!([] Option<A>, Probability; base, prob => weighted(prob, base)); + +arbitrary!([A: Arbitrary] opt::IntoIter<A>, SMapped<Option<A>, Self>, + <Option<A> as Arbitrary>::Parameters; + args => static_map(any_with::<Option<A>>(args), Option::into_iter)); + +lift1!(['static] opt::IntoIter<A>, Probability; + base, prob => weighted(prob, base).prop_map(Option::into_iter) +); + +#[cfg(test)] +mod test { + no_panic_test!( + probability => Probability, + option => Option<u8>, + option_iter => opt::IntoIter<u8>, + option_parse_error => Option<string::ParseError> + ); +} diff --git a/vendor/proptest/src/arbitrary/_core/result.rs b/vendor/proptest/src/arbitrary/_core/result.rs new file mode 100644 index 000000000..147a60309 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_core/result.rs @@ -0,0 +1,108 @@ +//- +// 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. + +//! 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<A, string::ParseError>, + SMapped<A, Self>, A::Parameters; + args => static_map(any_with::<A>(args), Result::Ok) +); +arbitrary!([A: Arbitrary] Result<string::ParseError, A>, + SMapped<A, Self>, A::Parameters; + args => static_map(any_with::<A>(args), Result::Err) +); +#[cfg(feature = "unstable")] +arbitrary!([A: Arbitrary] Result<A, !>, + SMapped<A, Self>, A::Parameters; + args => static_map(any_with::<A>(args), Result::Ok) +); +#[cfg(feature = "unstable")] +arbitrary!([A: Arbitrary] Result<!, A>, + SMapped<A, Self>, A::Parameters; + args => static_map(any_with::<A>(args), Result::Err) +); + +lift1!([] Result<A, string::ParseError>; Result::Ok); +#[cfg(feature = "unstable")] +lift1!([] Result<A, !>; Result::Ok); + +// We assume that `MaybeOk` is canonical as it's the most likely Strategy +// a user wants. + +arbitrary!([A: Arbitrary, B: Arbitrary] Result<A, B>, + MaybeOk<A::Strategy, B::Strategy>, + product_type![Probability, A::Parameters, B::Parameters]; + args => { + let product_unpack![prob, a, b] = args; + let (p, a, b) = (prob, any_with::<A>(a), any_with::<B>(b)); + maybe_ok_weighted(p, a, b) + } +); + +impl<A: fmt::Debug, E: Arbitrary> functor::ArbitraryF1<A> for Result<A, E> +where + E::Strategy: 'static, +{ + type Parameters = product_type![Probability, E::Parameters]; + + fn lift1_with<AS>(base: AS, args: Self::Parameters) -> BoxedStrategy<Self> + where + AS: Strategy<Value = A> + 'static, + { + let product_unpack![prob, e] = args; + let (p, a, e) = (prob, base, any_with::<E>(e)); + maybe_ok_weighted(p, a, e).boxed() + } +} + +impl<A: fmt::Debug, B: fmt::Debug> functor::ArbitraryF2<A, B> for Result<A, B> { + type Parameters = Probability; + + fn lift2_with<AS, BS>( + fst: AS, + snd: BS, + args: Self::Parameters, + ) -> BoxedStrategy<Self> + where + AS: Strategy<Value = A> + 'static, + BS: Strategy<Value = B> + 'static, + { + maybe_ok_weighted(args, fst, snd).boxed() + } +} + +arbitrary!([A: Arbitrary] IntoIter<A>, + SMapped<Result<A, ()>, Self>, + <Result<A, ()> as Arbitrary>::Parameters; + args => static_map(any_with::<Result<A, ()>>(args), Result::into_iter) +); + +lift1!(['static] IntoIter<A>, Probability; base, args => { + maybe_ok_weighted(args, base, Just(())).prop_map(Result::into_iter) +}); + +#[cfg(test)] +mod test { + no_panic_test!( + result => Result<u8, u16>, + into_iter => IntoIter<u8>, + result_a_parse_error => Result<u8, ::std::string::ParseError>, + result_parse_error_a => Result<::std::string::ParseError, u8> + ); +} diff --git a/vendor/proptest/src/arbitrary/_std/env.rs b/vendor/proptest/src/arbitrary/_std/env.rs new file mode 100644 index 000000000..49bbc2f2f --- /dev/null +++ b/vendor/proptest/src/arbitrary/_std/env.rs @@ -0,0 +1,141 @@ +//- +// 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. + +//! 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<Value = OsString> { + 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<Value = OsString> { + 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<Just<Self>>, + WA<SFnPtrMap<BoxedStrategy<OsString>, Self>> + )>; + prop_oneof![ + Just(VarError::NotPresent), + static_map(osstring_invalid_string().boxed(), VarError::NotUnicode) + ] + ); +} + +#[cfg(test)] +mod test { + use super::*; + use crate::num; + use crate::test_runner::Config; + + no_panic_test!( + args => Args, + args_os => ArgsOs, + vars => Vars, + vars_os => VarsOs, + join_paths_error => JoinPathsError, + var_error => VarError + ); + + proptest! { + #![proptest_config(Config { + cases: 65536, + .. Config::default() + })] + + #[test] + fn make_utf16_invalid_doesnt_panic( + mut buf in [num::u16::ANY; 3], + p in 0usize..3 + ) { + make_utf16_invalid(&mut buf, p); + } + } +} diff --git a/vendor/proptest/src/arbitrary/_std/ffi.rs b/vendor/proptest/src/arbitrary/_std/ffi.rs new file mode 100644 index 000000000..288b3947a --- /dev/null +++ b/vendor/proptest/src/arbitrary/_std/ffi.rs @@ -0,0 +1,100 @@ +//- +// 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. + +//! 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<VecStrategy<RangeInclusive<u8>>, 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<StrategyFor<String>, Self>, + <String as Arbitrary>::Parameters; + a => any_with::<String>(a).prop_map_into() +); + +macro_rules! dst_wrapped { + ($($w: ident),*) => { + $(arbitrary!($w<CStr>, MapInto<StrategyFor<CString>, Self>, SizeRange; + a => any_with::<CString>(a).prop_map_into() + );)* + $(arbitrary!($w<OsStr>, MapInto<StrategyFor<OsString>, Self>, + <String as Arbitrary>::Parameters; + a => any_with::<OsString>(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<Option<u16>, Self>; { + static_map(any::<Option<u16>>(), |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::<u8>::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<BoxedStrategy<Vec<u8>>, 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<CStr>, + box_os_str => Box<OsStr>, + into_string_error => IntoStringError, + from_bytes_with_nul => FromBytesWithNulError + ); + #[cfg(feature = "unstable")] + no_panic_test!( + rc_c_str => Rc<CStr>, + rc_os_str => Rc<OsStr>, + arc_c_str => Arc<CStr>, + arc_os_str => Arc<OsStr> + ); +} diff --git a/vendor/proptest/src/arbitrary/_std/fs.rs b/vendor/proptest/src/arbitrary/_std/fs.rs new file mode 100644 index 000000000..66d18ca1a --- /dev/null +++ b/vendor/proptest/src/arbitrary/_std/fs.rs @@ -0,0 +1,30 @@ +//- +// 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. + +//! 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<bool, Self>; { + static_map(any::<bool>(), |recursive| { + let mut db = DirBuilder::new(); + db.recursive(recursive); + db + }) +}); + +#[cfg(test)] +mod test { + no_panic_test!(dir_builder => DirBuilder); +} diff --git a/vendor/proptest/src/arbitrary/_std/io.rs b/vendor/proptest/src/arbitrary/_std/io.rs new file mode 100644 index 000000000..34ee9da32 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_std/io.rs @@ -0,0 +1,164 @@ +//- +// 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. + +//! 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<A>, + SMapped<(A, Option<u16>), 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<A>; base => + (base, any::<Option<u16>>()).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<A, B>, + 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<u8, Self>; static_map(any::<u8>(), repeat)); + +arbitrary!( + [A: BufRead + Arbitrary] Split<A>, 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<A>; + base => (base, any::<u8>()).prop_map(|(a, b)| a.split(b))); + +arbitrary!( + [A: Read + Arbitrary] Take<A>, 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<A>; + base => (base, any::<u64>()).prop_map(|(a, b)| a.take(b))); + +arbitrary!(ErrorKind, Union<Just<Self>>; + 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<SMapped<u64, SeekFrom>>, + WA<SMapped<i64, SeekFrom>>, + WA<SMapped<i64, SeekFrom>>, + )>; + prop_oneof![ + static_map(any::<u64>(), SeekFrom::Start), + static_map(any::<i64>(), SeekFrom::End), + static_map(any::<i64>(), SeekFrom::Current) + ] +); + +arbitrary!(Error, SMapped<(ErrorKind, Option<String>), 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<Repeat>, + buf_writer => BufWriter<Sink>, + line_writer => LineWriter<Sink>, + chain => Chain<Empty, BufReader<Repeat>>, + cursor => Cursor<Empty>, + empty => Empty, + sink => Sink, + stderr => Stderr, + stdin => Stdin, + stdout => Stdout, + lines => Lines<Empty>, + repeat => Repeat, + split => Split<Cursor<Vec<u8>>>, + take => Take<Repeat>, + error_kind => ErrorKind, + seek_from => SeekFrom, + error => Error + ); +} diff --git a/vendor/proptest/src/arbitrary/_std/mod.rs b/vendor/proptest/src/arbitrary/_std/mod.rs new file mode 100644 index 000000000..4360f5e07 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_std/mod.rs @@ -0,0 +1,22 @@ +//- +// 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. + +//! Arbitrary implementations for libstd. + +mod env; +mod ffi; +mod fs; +mod io; +mod net; +mod panic; +mod path; +mod string; +mod sync; +mod thread; +mod time; diff --git a/vendor/proptest/src/arbitrary/_std/net.rs b/vendor/proptest/src/arbitrary/_std/net.rs new file mode 100644 index 000000000..fcbec4d61 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_std/net.rs @@ -0,0 +1,117 @@ +//- +// 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. + +//! 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::<Ipv4Addr>().unwrap_err()); + +arbitrary!(Ipv4Addr, + TupleUnion<( + WA<Just<Self>>, + WA<Just<Self>>, + WA<MapInto<StrategyFor<u32>, Self>> + )>; + prop_oneof![ + 1 => Just(Self::new(0, 0, 0, 0)), + 4 => Just(Self::new(127, 0, 0, 1)), + 10 => any::<u32>().prop_map_into() + ] +); + +arbitrary!(Ipv6Addr, + TupleUnion<( + WA<SMapped<Ipv4Addr, Self>>, + WA<MapInto<StrategyFor<[u16; 8]>, Self>> + )>; + prop_oneof![ + 2 => static_map(any::<Ipv4Addr>(), |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<MapInto<StrategyFor<Ipv4Addr>, Self>>, + WA<MapInto<StrategyFor<Ipv6Addr>, Self>>)>; + prop_oneof![ + any::<Ipv4Addr>().prop_map_into(), + any::<Ipv6Addr>().prop_map_into() + ] +); + +arbitrary!(Shutdown, + TupleUnion<(WA<Just<Self>>, WA<Just<Self>>, WA<Just<Self>>)>; + { + use std::net::Shutdown::*; + prop_oneof![Just(Both), Just(Read), Just(Write)] + } +); +arbitrary!(SocketAddr, + TupleUnion<(WA<MapInto<StrategyFor<SocketAddrV4>, Self>>, + WA<MapInto<StrategyFor<SocketAddrV6>, Self>>)>; + prop_oneof![ + any::<SocketAddrV4>().prop_map_into(), + any::<SocketAddrV6>().prop_map_into() + ] +); + +#[cfg(feature = "unstable")] +arbitrary!(Ipv6MulticastScope, + TupleUnion<(WA<Just<Self>>, WA<Just<Self>>, WA<Just<Self>>, + WA<Just<Self>>, WA<Just<Self>>, WA<Just<Self>>, + WA<Just<Self>>)>; + { + use std::net::Ipv6MulticastScope::*; + prop_oneof![ + Just(InterfaceLocal), + Just(LinkLocal), + Just(RealmLocal), + Just(AdminLocal), + Just(SiteLocal), + Just(OrganizationLocal), + Just(Global), + ] + } +); + +#[cfg(test)] +mod test { + no_panic_test!( + addr_parse_error => AddrParseError, + ipv4_addr => Ipv4Addr, + ipv6_addr => Ipv6Addr, + socket_addr_v4 => SocketAddrV4, + socket_addr_v6 => SocketAddrV6, + ip_addr => IpAddr, + shutdown => Shutdown, + socket_addr => SocketAddr + ); + + #[cfg(feature = "unstable")] + no_panic_test!( + ipv6_multicast_scope => Ipv6MulticastScope + ); +} diff --git a/vendor/proptest/src/arbitrary/_std/panic.rs b/vendor/proptest/src/arbitrary/_std/panic.rs new file mode 100644 index 000000000..c2bd40cd4 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_std/panic.rs @@ -0,0 +1,19 @@ +//- +// 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. + +//! Arbitrary implementations for `std::panic`. + +use std::panic::AssertUnwindSafe; + +wrap_ctor!(AssertUnwindSafe, AssertUnwindSafe); + +#[cfg(test)] +mod test { + no_panic_test!(assert_unwind_safe => AssertUnwindSafe<u8>); +} diff --git a/vendor/proptest/src/arbitrary/_std/path.rs b/vendor/proptest/src/arbitrary/_std/path.rs new file mode 100644 index 000000000..e7d063c17 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_std/path.rs @@ -0,0 +1,23 @@ +//- +// 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. + +//! Arbitrary implementations for `std::path`. + +use std::path::*; + +// TODO: Figure out PathBuf and then Box/Rc/Box<Path>. + +arbitrary!(StripPrefixError; Path::new("").strip_prefix("a").unwrap_err()); + +#[cfg(test)] +mod test { + no_panic_test!( + strip_prefix_error => StripPrefixError + ); +} diff --git a/vendor/proptest/src/arbitrary/_std/string.rs b/vendor/proptest/src/arbitrary/_std/string.rs new file mode 100644 index 000000000..fd8138a39 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_std/string.rs @@ -0,0 +1,318 @@ +//- +// 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. + +//! 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<str>, MapInto<StrategyFor<String>, Self>, StringParam; + a => any_with::<String>(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<BoxedStrategy<Vec<u8>>, 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<Value = Vec<u8>> { + let prefix = collection::vec(any::<char>(), ..::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<slice::Iter<'a, u8>>; + 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<Value = ELBytes> { + 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>, + str_rc => Rc<str>, + str_arc => Arc<str>, + from_utf16_error => FromUtf16Error, + from_utf8_error => FromUtf8Error + ); +} diff --git a/vendor/proptest/src/arbitrary/_std/sync.rs b/vendor/proptest/src/arbitrary/_std/sync.rs new file mode 100644 index 000000000..e372b2544 --- /dev/null +++ b/vendor/proptest/src/arbitrary/_std/sync.rs @@ -0,0 +1,166 @@ +//- +// 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. + +//! 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<u16, Self>; // usize would be extreme! + static_map(any::<u16>(), |n| Barrier::new(n as usize)) +); + +arbitrary!(BarrierWaitResult, + TupleUnion<(WA<LazyJustFn<Self>>, WA<LazyJustFn<Self>>)>; + prop_oneof![LazyJust::new(bwr_true), LazyJust::new(bwr_false)] +); + +lazy_just!( + Condvar, Default::default; + Once, Once::new +); + +arbitrary!(WaitTimeoutResult, TupleUnion<(WA<Just<Self>>, WA<Just<Self>>)>; + prop_oneof![Just(wtr_true()), Just(wtr_false())] +); + +fn bwr_true() -> BarrierWaitResult { + Barrier::new(1).wait() +} + +fn bwr_false() -> BarrierWaitResult { + let barrier = Arc::new(Barrier::new(2)); + let b2 = barrier.clone(); + let jh = thread::spawn(move || b2.wait()); + let bwr1 = barrier.wait(); + let bwr2 = jh.join().unwrap(); + if bwr1.is_leader() { + bwr2 + } else { + bwr1 + } +} + +fn wtr_false() -> WaitTimeoutResult { + let cvar = Arc::new(Condvar::new()); + let cvar2 = cvar.clone(); + thread::spawn(move || { + cvar2.notify_one(); + }); + let lock = Mutex::new(()); + let wt = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(1)); + let (_, wtr) = wt.unwrap(); + wtr +} + +fn wtr_true() -> WaitTimeoutResult { + let cvar = Condvar::new(); + let lock = Mutex::new(()); + let wt = cvar.wait_timeout(lock.lock().unwrap(), Duration::from_millis(0)); + let (_, wtr) = wt.unwrap(); + wtr +} + +arbitrary!(RecvError; RecvError); + +arbitrary!([T: Arbitrary] SendError<T>, SMapped<T, Self>, T::Parameters; + args => static_map(any_with::<T>(args), SendError) +); + +arbitrary!(RecvTimeoutError, TupleUnion<(WA<Just<Self>>, WA<Just<Self>>)>; + prop_oneof![ + Just(RecvTimeoutError::Disconnected), + Just(RecvTimeoutError::Timeout) + ] +); + +arbitrary!(TryRecvError, TupleUnion<(WA<Just<Self>>, WA<Just<Self>>)>; + prop_oneof![ + Just(TryRecvError::Disconnected), + Just(TryRecvError::Empty) + ] +); + +arbitrary!( + [P: Clone + Default, T: Arbitrary<Parameters = P>] TrySendError<T>, + TupleUnion<(WA<SMapped<T, Self>>, WA<SMapped<T, Self>>)>, P; + args => prop_oneof![ + static_map(any_with::<T>(args.clone()), TrySendError::Disconnected), + static_map(any_with::<T>(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<A>, Receiver<A>), LazyJustFn<Self>; + LazyJust::new(channel) +); + +arbitrary!([A: fmt::Debug] (Sender<A>, IntoIter<A>), LazyJustFn<Self>; + LazyJust::new(|| { + let (rx, tx) = channel(); + (rx, tx.into_iter()) + }) +); + +arbitrary!([A] (SyncSender<A>, Receiver<A>), SMapped<u16, Self>; + static_map(any::<u16>(), |size| sync_channel(size as usize)) +); + +arbitrary!([A: fmt::Debug] (SyncSender<A>, IntoIter<A>), SMapped<u16, Self>; + static_map(any::<u16>(), |size| { + let (rx, tx) = sync_channel(size as usize); + (rx, tx.into_iter()) + }) +); + +#[cfg(test)] +mod test { + no_panic_test!( + mutex => Mutex<u8>, + rw_lock => RwLock<u8>, + barrier => Barrier, + barrier_wait_result => BarrierWaitResult, + condvar => Condvar, + once => Once, + wait_timeout_result => WaitTimeoutResult, + recv_error => RecvError, + send_error => SendError<u8>, + recv_timeout_error => RecvTimeoutError, + try_recv_error => TryRecvError, + try_send_error => TrySendError<u8>, + rx_tx => (Sender<u8>, Receiver<u8>), + rx_txiter => (Sender<u8>, IntoIter<u8>), + syncrx_tx => (SyncSender<u8>, Receiver<u8>), + syncrx_txiter => (SyncSender<u8>, IntoIter<u8>) + ); +} diff --git a/vendor/proptest/src/arbitrary/_std/thread.rs b/vendor/proptest/src/arbitrary/_std/thread.rs new file mode 100644 index 000000000..3a9b2b3fe --- /dev/null +++ b/vendor/proptest/src/arbitrary/_std/thread.rs @@ -0,0 +1,81 @@ +//- +// 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. + +//! 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<usize>, Option<String>), 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<A>, + 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::<JoinHandle<u8>>()) { + use std::panic::catch_unwind; + catch_unwind(|| { + jh.join(); + () + }) + } + } + */ +} diff --git a/vendor/proptest/src/arbitrary/_std/time.rs b/vendor/proptest/src/arbitrary/_std/time.rs new file mode 100644 index 000000000..7d940439a --- /dev/null +++ b/vendor/proptest/src/arbitrary/_std/time.rs @@ -0,0 +1,50 @@ +//- +// 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. + +//! 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::<Duration>()` 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<u32>), + fn ((i32, u32)) -> SystemTime>; + static_map((num::i32::ANY, 0..1_000_000_000u32), + |(sec, ns)| { + if sec >= 0 { + UNIX_EPOCH + Duration::new(sec as u64, ns) + } else { + UNIX_EPOCH - Duration::new((-(sec as i64)) as u64, ns) + } + }) +); + +#[cfg(test)] +mod test { + no_panic_test!( + duration => Duration, + instant => Instant, + system_time => SystemTime + ); +} diff --git a/vendor/proptest/src/arbitrary/arrays.rs b/vendor/proptest/src/arbitrary/arrays.rs new file mode 100644 index 000000000..85a13321c --- /dev/null +++ b/vendor/proptest/src/arbitrary/arrays.rs @@ -0,0 +1,34 @@ +//- +// 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. + +//! Arbitrary implementations for arrays. + +use crate::arbitrary::{any_with, Arbitrary}; +use crate::array::UniformArrayStrategy; + +impl<A: Arbitrary, const N: usize> Arbitrary for [A; N] { + type Parameters = A::Parameters; + type Strategy = UniformArrayStrategy<A::Strategy, [A; N]>; + + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + let base = any_with::<A>(args); + UniformArrayStrategy::new(base) + } +} + +#[cfg(test)] +mod test { + no_panic_test!( + array_16 => [u8; 16] + ); + + no_panic_test!( + array_1024 => [u8; 1024] + ); +} diff --git a/vendor/proptest/src/arbitrary/functor.rs b/vendor/proptest/src/arbitrary/functor.rs new file mode 100644 index 000000000..153ce9949 --- /dev/null +++ b/vendor/proptest/src/arbitrary/functor.rs @@ -0,0 +1,220 @@ +//- +// 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. + +//! 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<A: fmt::Debug>: fmt::Debug + Sized { + //========================================================================== + // Implementation note #1 + //========================================================================== + // It might be better to do this with generic associated types by + // having an associated type: + // + // `type Strategy<A>: Strategy<Value = Self>;` + // + // 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<SomeType>`. + /// + /// 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<AS>(base: AS) -> BoxedStrategy<Self> + where + AS: Strategy<Value = A> + '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<AS>(base: AS, args: Self::Parameters) -> BoxedStrategy<Self> + where + AS: Strategy<Value = A> + '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<A: fmt::Debug, B: fmt::Debug>: + 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<Type1, Type2>`. + /// + /// 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<AS, BS>(fst: AS, snd: BS) -> BoxedStrategy<Self> + where + AS: Strategy<Value = A> + 'static, + BS: Strategy<Value = B> + '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<Type1, Type2>`. + /// 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<AS, BS>( + fst: AS, + snd: BS, + args: Self::Parameters, + ) -> BoxedStrategy<Self> + where + AS: Strategy<Value = A> + 'static, + BS: Strategy<Value = B> + 'static; +} + +macro_rules! lift1 { + ([$($bounds : tt)*] $typ: ty, $params: ty; + $base: ident, $args: ident => $logic: expr) => { + impl<A: ::core::fmt::Debug + $($bounds)*> + $crate::arbitrary::functor::ArbitraryF1<A> + for $typ { + type Parameters = $params; + + fn lift1_with<S>($base: S, $args: Self::Parameters) + -> $crate::strategy::BoxedStrategy<Self> + where + S: $crate::strategy::Strategy<Value = A> + 'static + { + $crate::strategy::Strategy::boxed($logic) + } + } + }; + ([$($bounds : tt)*] $typ: ty; $base: ident => $logic: expr) => { + lift1!([$($bounds)*] $typ, (); $base, _args => $logic); + }; + ([$($bounds : tt)*] $typ: ty; $mapper: expr) => { + lift1!(['static + $($bounds)*] $typ; base => + $crate::strategy::Strategy::prop_map(base, $mapper)); + }; + ([$($bounds : tt)*] $typ: ty) => { + lift1!(['static + $($bounds)*] $typ; base => + $crate::strategy::Strategy::prop_map_into(base)); + }; +} diff --git a/vendor/proptest/src/arbitrary/macros.rs b/vendor/proptest/src/arbitrary/macros.rs new file mode 100644 index 000000000..8edf2a6ea --- /dev/null +++ b/vendor/proptest/src/arbitrary/macros.rs @@ -0,0 +1,115 @@ +//- +// 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. + +#![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<Self>, (); + _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<A>, + $crate::arbitrary::SMapped<A, Self>, A::Parameters; + args => $crate::strategy::statics::static_map( + $crate::arbitrary::any_with::<A>(args), $maker)); + + lift1!([$($bound)*] $wrap<A>; $maker); + }; +} + +macro_rules! wrap_from { + ($wrap: ident) => { + wrap_from!([] $wrap); + }; + ([$($bound : tt)*] $wrap: ident) => { + arbitrary!([A: $crate::arbitrary::Arbitrary + $($bound)*] $wrap<A>, + $crate::strategy::MapInto<A::Strategy, Self>, A::Parameters; + args => $crate::strategy::Strategy::prop_map_into( + $crate::arbitrary::any_with::<A>(args))); + + lift1!([$($bound)*] $wrap<A>); + }; +} + +macro_rules! lazy_just { + ($($self: ty, $fun: expr);+) => { + $( + arbitrary!($self, $crate::strategy::LazyJust<Self, fn() -> Self>; + $crate::strategy::LazyJust::new($fun)); + )+ + }; +} + +//============================================================================== +// Macros for testing: +//============================================================================== + +/// We are mostly interested in ensuring that generating input from our +/// strategies is able to construct a value, therefore ensuring that +/// no panic occurs is mostly sufficient. Shrinking for strategies that +/// use special shrinking methods can be handled separately. +#[cfg(test)] +macro_rules! no_panic_test { + ($($module: ident => $self: ty),+) => { + $( + mod $module { + #[allow(unused_imports)] + use super::super::*; + proptest! { + #[test] + fn no_panic(_ in $crate::arbitrary::any::<$self>()) {} + } + } + )+ + }; +} diff --git a/vendor/proptest/src/arbitrary/mod.rs b/vendor/proptest/src/arbitrary/mod.rs new file mode 100644 index 000000000..51ac48bae --- /dev/null +++ b/vendor/proptest/src/arbitrary/mod.rs @@ -0,0 +1,69 @@ +//- +// 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 `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 non_zero; +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<S, O> = + statics::Map<S, fn(<S as Strategy>::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<I, O> = statics::Map<StrategyFor<I>, 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<I, O> = Map<StrategyFor<I>, fn(I) -> O>; diff --git a/vendor/proptest/src/arbitrary/non_zero.rs b/vendor/proptest/src/arbitrary/non_zero.rs new file mode 100644 index 000000000..55a775beb --- /dev/null +++ b/vendor/proptest/src/arbitrary/non_zero.rs @@ -0,0 +1,66 @@ +//- +// 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 core::convert::TryFrom; +use core::num::{ + NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize, + NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize, +}; + +use crate::strategy::{FilterMap, Strategy}; + +use super::{any, Arbitrary, StrategyFor}; + +macro_rules! non_zero_impl { + ($nz:ty, $prim:ty) => { + impl Arbitrary for $nz { + type Parameters = (); + type Strategy = + FilterMap<StrategyFor<$prim>, fn($prim) -> Option<Self>>; + + 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); +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); +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, + u128 => core::num::NonZeroU128, + usize => core::num::NonZeroUsize, + i8 => core::num::NonZeroI8, + i16 => core::num::NonZeroI16, + i32 => core::num::NonZeroI32, + i64 => core::num::NonZeroI64, + i128 => core::num::NonZeroI128, + isize => core::num::NonZeroIsize + ); +} diff --git a/vendor/proptest/src/arbitrary/primitives.rs b/vendor/proptest/src/arbitrary/primitives.rs new file mode 100644 index 000000000..cea57f4c9 --- /dev/null +++ b/vendor/proptest/src/arbitrary/primitives.rs @@ -0,0 +1,46 @@ +//- +// 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. + +//! Arbitrary implementations for primitive types. + +use crate::bool; +use crate::char; +use crate::num::{ + f32, f64, i16, i32, i64, i8, isize, u16, u32, u64, u8, usize, +}; +#[cfg(not(target_arch = "wasm32"))] +use crate::num::{i128, u128}; + +arbitrary!(bool, i8, i16, i32, i64, isize, u8, u16, u32, u64, usize); + +#[cfg(not(target_arch = "wasm32"))] +arbitrary!(i128, u128); + +// Note that for floating point types we limit the space since a lot of code +// isn't prepared for (and is not intended to be) things like NaN and infinity. +arbitrary!(f32, f32::Any; { + f32::POSITIVE | f32::NEGATIVE | f32::ZERO | f32::SUBNORMAL | f32::NORMAL +}); +arbitrary!(f64, f64::Any; { + f64::POSITIVE | f64::NEGATIVE | f64::ZERO | f64::SUBNORMAL | f64::NORMAL +}); + +arbitrary!(char, char::CharStrategy<'static>; char::any()); + +#[cfg(test)] +mod test { + no_panic_test!( + bool => bool, + char => char, + f32 => f32, f64 => f64, + isize => isize, usize => usize, + i8 => i8, i16 => i16, i32 => i32, i64 => i64, i128 => i128, + u8 => u8, u16 => u16, u32 => u32, u64 => u64, u128 => u128 + ); +} diff --git a/vendor/proptest/src/arbitrary/sample.rs b/vendor/proptest/src/arbitrary/sample.rs new file mode 100644 index 000000000..81758213d --- /dev/null +++ b/vendor/proptest/src/arbitrary/sample.rs @@ -0,0 +1,31 @@ +//- +// 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::arbitrary::Arbitrary; +use crate::sample::{Index, IndexStrategy, Selector, SelectorStrategy}; + +impl Arbitrary for Index { + type Parameters = (); + + type Strategy = IndexStrategy; + + fn arbitrary_with(_: ()) -> IndexStrategy { + IndexStrategy::new() + } +} + +impl Arbitrary for Selector { + type Parameters = (); + + type Strategy = SelectorStrategy; + + fn arbitrary_with(_: ()) -> SelectorStrategy { + SelectorStrategy::new() + } +} diff --git a/vendor/proptest/src/arbitrary/traits.rs b/vendor/proptest/src/arbitrary/traits.rs new file mode 100644 index 000000000..83f021425 --- /dev/null +++ b/vendor/proptest/src/arbitrary/traits.rs @@ -0,0 +1,295 @@ +//- +// 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 core::fmt; + +use crate::strategy::Strategy; + +//============================================================================== +// Arbitrary trait +//============================================================================== + +/// Arbitrary determines a canonical [`Strategy`] for the implementing type. +/// +/// It provides the method `arbitrary_with` which generates a `Strategy` for +/// producing arbitrary values of the implementing type *(`Self`)*. In general, +/// these strategies will produce the entire set of values possible for the +/// type, up to some size limitation or constraints set by their parameters. +/// When this is not desired, strategies to produce the desired values can be +/// built by combining [`Strategy`]s as described in the crate documentation. +/// +/// This trait analogous to +/// [Haskell QuickCheck's implementation of `Arbitrary`][HaskellQC]. +/// In this interpretation of `Arbitrary`, `Strategy` is the equivalent of +/// the `Gen` monad. Unlike in QuickCheck, `Arbitrary` is not a core component; +/// types do not need to implement `Arbitrary` unless one wants to use +/// [`any`](fn.any.html) or other free functions in this module. +/// +/// `Arbitrary` currently only works for types which represent owned data as +/// opposed to borrowed data. This is a fundamental restriction of `proptest` +/// which may be lifted in the future as the [generic associated types (GAT)] +/// feature of Rust is implemented and stabilized. +/// +/// [generic associated types (GAT)]: https://github.com/rust-lang/rust/issues/44265 +/// +/// [`Strategy`]: ../strategy/trait.Strategy.html +/// +/// [HaskellQC]: +/// https://hackage.haskell.org/package/QuickCheck/docs/Test-QuickCheck-Arbitrary.html +pub trait Arbitrary: Sized + fmt::Debug { + /// The type of parameters that [`arbitrary_with`] accepts for configuration + /// of the generated [`Strategy`]. Parameters must implement [`Default`]. + /// + /// [`arbitrary_with`]: trait.Arbitrary.html#tymethod.arbitrary_with + /// + /// [`Strategy`]: ../strategy/trait.Strategy.html + /// [`Default`]: + /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html + type Parameters: Default; + + /// Generates a [`Strategy`] for producing arbitrary values + /// of type the implementing type (`Self`). + /// + /// Calling this for the type `X` is the equivalent of using + /// [`X::arbitrary_with(Default::default())`]. + /// + /// This method is defined in the trait for optimization for the + /// default if you want to do that. It is a logic error to not + /// preserve the semantics when overriding. + /// + /// [`Strategy`]: ../strategy/trait.Strategy.html + /// [`X::arbitrary_with(Default::default())`]: + /// trait.Arbitrary.html#tymethod.arbitrary_with + fn arbitrary() -> Self::Strategy { + Self::arbitrary_with(Default::default()) + } + + /// Generates a [`Strategy`] for producing arbitrary values of type the + /// implementing type (`Self`). The strategy is passed the arguments given + /// in args. + /// + /// If you wish to use the [`default()`] arguments, + /// use [`arbitrary`] instead. + /// + /// [`Strategy`]: ../strategy/trait.Strategy.html + /// + /// [`arbitrary`]: trait.Arbitrary.html#method.arbitrary + /// + /// [`default()`]: + /// https://doc.rust-lang.org/nightly/std/default/trait.Default.html + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy; + + /// The type of [`Strategy`] used to generate values of type `Self`. + /// + /// [`Strategy`]: ../strategy/trait.Strategy.html + type Strategy: Strategy<Value = Self>; +} + +//============================================================================== +// 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<A> = <A as Arbitrary>::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<A> = <A as Arbitrary>::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::<A>(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::<Vec<u32>>()) { +/// let vec2 = vec.iter().cloned().rev().rev().collect::<Vec<u32>>(); +/// prop_assert_eq!(vec, &vec2); +/// } +/// } +/// +/// fn main() { +/// reverse_reverse_is_identity(); +/// } +/// ``` +/// +/// [`any_with::<A>(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<A: Arbitrary>() -> StrategyFor<A> { + // ^-- 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::<A>()`]. +/// +/// # 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::<Vec<u32>>(size_range(1000).lift())) +/// { +/// let vec2 = vec.iter().cloned().rev().rev().collect::<Vec<u32>>(); +/// prop_assert_eq!(vec, &vec2); +/// } +/// } +/// +/// fn main() { +/// reverse_reverse_is_identity(); +/// } +/// ``` +/// +/// [`any::<A>()`]: 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<A: Arbitrary>(args: ParamsFor<A>) -> StrategyFor<A> { + // ^-- 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::<A>()`]. +/// +/// 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::<A>()`] instead. +/// +/// For clarity, it is often a good idea to specify the type generated, and +/// so using [`any::<A>()`] can be a good idea. +/// +/// If you want to customize how the strategy is generated, use +/// [`arbitrary_with(args)`] where `args` is of type +/// `<A as Arbitrary>::Parameters`. +/// +/// # Example +/// +/// The function can be used as: +/// +/// ```rust +/// extern crate proptest; +/// use proptest::arbitrary::{arbitrary, StrategyFor}; +/// +/// fn gen_vec_usize() -> StrategyFor<Vec<usize>> { +/// arbitrary() +/// } +/// +/// # fn main() {} +/// ``` +/// +/// [`arbitrary_with(args)`]: fn.arbitrary_with.html +/// [`any::<A>()`]: fn.any.html +/// [`Arbitrary`]: trait.Arbitrary.html +/// [`Strategy`]: ../strategy/trait.Strategy.html +#[must_use = "strategies do nothing unless used"] +pub fn arbitrary<A, S>() -> S +where + // The backlinking here cause an injection which helps type inference. + S: Strategy<Value = A>, + A: Arbitrary<Strategy = S>, +{ + 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::<A>(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::<A>(args)`] instead. +/// +/// For clarity, it is often a good idea to specify the type generated, and +/// so using [`any_with::<A>(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<Vec<u32>> { +/// arbitrary_with(size_range(10).lift()) +/// } +/// +/// # fn main() {} +/// ``` +/// +/// [`any_with::<A>(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<A, S, P>(args: P) -> S +where + P: Default, + // The backlinking here cause an injection which helps type inference. + S: Strategy<Value = A>, + A: Arbitrary<Strategy = S, Parameters = P>, +{ + A::arbitrary_with(args) +} diff --git a/vendor/proptest/src/arbitrary/tuples.rs b/vendor/proptest/src/arbitrary/tuples.rs new file mode 100644 index 000000000..5df3088a3 --- /dev/null +++ b/vendor/proptest/src/arbitrary/tuples.rs @@ -0,0 +1,45 @@ +//- +// 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. + +//! Arbitrary implementations for tuples. + +use crate::arbitrary::{any_with, Arbitrary}; + +macro_rules! impl_tuple { + ($($typ: ident),*) => { + impl<$($typ : Arbitrary),*> Arbitrary for ($($typ,)*) { + type Parameters = product_type![$($typ::Parameters,)*]; + type Strategy = ($($typ::Strategy,)*); + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + #[allow(non_snake_case)] + let product_unpack![$($typ),*] = args; + ($(any_with::<$typ>($typ)),*,) + } + } + }; +} + +arbitrary!((); ()); +impl_tuple!(T0); +impl_tuple!(T0, T1); +impl_tuple!(T0, T1, T2); +impl_tuple!(T0, T1, T2, T3); +impl_tuple!(T0, T1, T2, T3, T4); +impl_tuple!(T0, T1, T2, T3, T4, T5); +impl_tuple!(T0, T1, T2, T3, T4, T5, T6); +impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7); +impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8); +impl_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9); + +#[cfg(test)] +mod test { + no_panic_test!( + tuple_n10 => ((), bool, u8, u16, u32, u64, i8, i16, i32, i64) + ); +} diff --git a/vendor/proptest/src/array.rs b/vendor/proptest/src/array.rs new file mode 100644 index 000000000..2edce4608 --- /dev/null +++ b/vendor/proptest/src/array.rs @@ -0,0 +1,264 @@ +//- +// 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 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<S, T> { + strategy: S, + _marker: PhantomData<T>, +} + +impl<S, T> UniformArrayStrategy<S, T> { + /// 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<T> { + tree: T, + shrinker: usize, + last_shrinker: Option<usize>, +} + +/// 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<S: Strategy, const N: usize>( + strategy: S, +) -> UniformArrayStrategy<S, [S::Value; N]> { + 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<S: Strategy>( + strategy: S, + ) -> UniformArrayStrategy<S, [S::Value; $n]> { + UniformArrayStrategy { + strategy, + _marker: PhantomData, + } + } + }; +} + +impl<S: Strategy, const N: usize> Strategy for [S; N] { + type Tree = ArrayValueTree<[S::Tree; N]>; + type Value = [S::Value; N]; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + Ok(ArrayValueTree { + tree: unarray::build_array_result(|i| self[i].new_tree(runner))?, + shrinker: 0, + last_shrinker: None, + }) + } +} +impl<S: Strategy, const N: usize> Strategy + for UniformArrayStrategy<S, [S::Value; N]> +{ + type Tree = ArrayValueTree<[S::Tree; N]>; + type Value = [S::Value; N]; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + Ok(ArrayValueTree { + tree: unarray::build_array_result(|_| { + self.strategy.new_tree(runner) + })?, + shrinker: 0, + last_shrinker: None, + }) + } +} +impl<T: ValueTree, const N: usize> ValueTree for ArrayValueTree<[T; N]> { + type Value = [T::Value; N]; + + fn current(&self) -> [T::Value; N] { + unarray::build_array(|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); + } +} diff --git a/vendor/proptest/src/bits.rs b/vendor/proptest/src/bits.rs new file mode 100644 index 000000000..49de83085 --- /dev/null +++ b/vendor/proptest/src/bits.rs @@ -0,0 +1,677 @@ +//- +// 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. + +//! 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; +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(feature = "cargo-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")] +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<bool> { + 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<T: BitSetLike> { + min: usize, + max: usize, + mask: Option<T>, +} + +impl<T: BitSetLike> BitSetStrategy<T> { + /// 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<T: BitSetLike> Strategy for BitSetStrategy<T> { + type Tree = BitSetValueTree<T>; + type Value = T; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + 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<T: BitSetLike> { + size: SizeRange, + bits: SizeRange, + _marker: PhantomData<T>, +} + +impl<T: BitSetLike> SampledBitSetStrategy<T> { + /// 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<SizeRange>, bits: impl Into<SizeRange>) -> 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<T: BitSetLike> Strategy for SampledBitSetStrategy<T> { + type Tree = BitSetValueTree<T>; + type Value = T; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + 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<T: BitSetLike> { + inner: T, + shrink: usize, + prev_shrink: Option<usize>, + min_count: usize, +} + +impl<T: BitSetLike> ValueTree for BitSetValueTree<T> { + 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<SizeRange>, + bits: impl Into<SizeRange>, + ) -> 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<SizeRange>, + bits: impl Into<SizeRange>, + ) -> SampledBitSetStrategy<$typ> { + SampledBitSetStrategy::new(size, bits) + } + } + }; +} +minimal_api!(usize, usize); +minimal_api!(isize, isize); +#[cfg(feature = "bit-set")] +minimal_api!(bitset, BitSet); +minimal_api!(bool_vec, Vec<bool>); + +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<bool>; + + #[derive(Debug, Clone)] + pub(crate) struct VarBitSet(Inner); + + impl VarBitSet { + pub(crate) fn saturated(len: usize) -> Self { + (0..len).collect::<VarBitSet>() + } + + #[cfg(not(feature = "bit-set"))] + pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = usize> + '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<Item = usize> + '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<usize> for VarBitSet { + fn from_iter<T: IntoIterator<Item = usize>>(iter: T) -> Self { + let mut bits = VarBitSet::new_bitset(0); + for bit in iter { + bits.set(bit); + } + bits + } + } + + /* + pub(crate) fn between(min: usize, max: usize) -> BitSetStrategy<VarBitSet> { + BitSetStrategy::new(min, max) + } + + pub(crate) fn masked(mask: VarBitSet) -> BitSetStrategy<VarBitSet> { + BitSetStrategy::masked(mask) + } + */ + + pub(crate) fn sampled( + size: impl Into<SizeRange>, + bits: impl Into<SizeRange>, + ) -> SampledBitSetStrategy<VarBitSet> { + SampledBitSetStrategy::new(size, bits) + } +} + +pub(crate) 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); + } +} diff --git a/vendor/proptest/src/bool.rs b/vendor/proptest/src/bool.rs new file mode 100644 index 000000000..e64e78467 --- /dev/null +++ b/vendor/proptest/src/bool.rs @@ -0,0 +1,144 @@ +//- +// 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 `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<Self> { + 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<Self> { + 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()); + } +} diff --git a/vendor/proptest/src/char.rs b/vendor/proptest/src/char.rs new file mode 100644 index 000000000..7f0e92d7a --- /dev/null +++ b/vendor/proptest/src/char.rs @@ -0,0 +1,409 @@ +//- +// 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 `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<char>; + +/// 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<Self> { + 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::<Result<Vec<CharRange>,_>>()?)); + + 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() + }), + ); + } +} diff --git a/vendor/proptest/src/collection.rs b/vendor/proptest/src/collection.rs new file mode 100644 index 000000000..90d04977e --- /dev/null +++ b/vendor/proptest/src/collection.rs @@ -0,0 +1,779 @@ +//- +// 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. + +//! 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..100`. +#[derive(Clone, PartialEq, Eq, Hash, Debug)] +pub struct SizeRange(Range<usize>); + +/// Creates a `SizeRange` from some value that is convertible into it. +pub fn size_range(from: impl Into<SizeRange>) -> SizeRange { + from.into() +} + +impl Default for SizeRange { + /// Constructs a `SizeRange` equivalent to `size_range(0..100)`. + fn default() -> Self { + size_range(0..100) + } +} + +impl SizeRange { + /// Creates a `SizeBounds` from a `RangeInclusive<usize>`. + pub fn new(range: RangeInclusive<usize>) -> 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<X>(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<X: Default>(self) -> product_type![Self, X] { + self.with(Default::default()) + } + + pub(crate) fn start(&self) -> usize { + self.0.start + } + + /// Extract the ends `[low, high]` of a `SizeRange`. + pub(crate) fn start_end_incl(&self) -> (usize, usize) { + (self.start(), self.end_incl()) + } + + pub(crate) fn end_incl(&self) -> usize { + self.0.end - 1 + } + + pub(crate) fn end_excl(&self) -> usize { + self.0.end + } + + pub(crate) fn iter(&self) -> impl Iterator<Item = usize> { + 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<usize> for SizeRange { + fn from(exact: usize) -> Self { + size_range(exact..=exact) + } +} + +/// Given `..high`, then a size range `[0, high)` is the result. +impl From<RangeTo<usize>> for SizeRange { + fn from(high: RangeTo<usize>) -> Self { + size_range(0..high.end) + } +} + +/// Given `low .. high`, then a size range `[low, high)` is the result. +impl From<Range<usize>> for SizeRange { + fn from(r: Range<usize>) -> Self { + SizeRange(r) + } +} + +/// Given `low ..= high`, then a size range `[low, high]` is the result. +impl From<RangeInclusive<usize>> for SizeRange { + fn from(r: RangeInclusive<usize>) -> Self { + size_range(*r.start()..r.end().saturating_add(1)) + } +} + +/// Given `..=high`, then a size range `[0, high]` is the result. +impl From<RangeToInclusive<usize>> for SizeRange { + fn from(high: RangeToInclusive<usize>) -> Self { + size_range(0..=high.end) + } +} + +#[cfg(feature = "frunk")] +impl Generic for SizeRange { + type Repr = RangeInclusive<usize>; + + /// Converts the `SizeRange` into `Range<usize>`. + fn into(self) -> Self::Repr { + self.0 + } + + /// Converts `RangeInclusive<usize>` into `SizeRange`. + fn from(r: Self::Repr) -> Self { + r.into() + } +} + +/// Adds `usize` to both start and end of the bounds. +/// +/// Panics if adding to either end overflows `usize`. +impl Add<usize> 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<T: Strategy> { + 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<T: Strategy>( + element: T, + size: impl Into<SizeRange>, +) -> VecStrategy<T> { + let size = size.into(); + size.assert_nonempty(); + VecStrategy { element, size } +} + +mapfn! { + [] fn VecToDeque[<T : fmt::Debug>](vec: Vec<T>) -> VecDeque<T> { + 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[<T>][where T : Strategy]( + statics::Map<VecStrategy<T>, VecToDeque>) + -> VecDequeValueTree<T::Tree>; + /// `ValueTree` corresponding to `VecDequeStrategy`. + #[derive(Clone, Debug)] + pub struct VecDequeValueTree[<T>][where T : ValueTree]( + statics::Map<VecValueTree<T>, VecToDeque>) + -> VecDeque<T::Value>; +} + +/// Create a strategy to generate `VecDeque`s containing elements drawn from +/// `element` and with a size range given by `size`. +pub fn vec_deque<T: Strategy>( + element: T, + size: impl Into<SizeRange>, +) -> VecDequeStrategy<T> { + VecDequeStrategy(statics::Map::new(vec(element, size), VecToDeque)) +} + +mapfn! { + [] fn VecToLl[<T : fmt::Debug>](vec: Vec<T>) -> LinkedList<T> { + 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[<T>][where T : Strategy]( + statics::Map<VecStrategy<T>, VecToLl>) + -> LinkedListValueTree<T::Tree>; + /// `ValueTree` corresponding to `LinkedListStrategy`. + #[derive(Clone, Debug)] + pub struct LinkedListValueTree[<T>][where T : ValueTree]( + statics::Map<VecValueTree<T>, VecToLl>) + -> LinkedList<T::Value>; +} + +/// Create a strategy to generate `LinkedList`s containing elements drawn from +/// `element` and with a size range given by `size`. +pub fn linked_list<T: Strategy>( + element: T, + size: impl Into<SizeRange>, +) -> LinkedListStrategy<T> { + LinkedListStrategy(statics::Map::new(vec(element, size), VecToLl)) +} + +mapfn! { + [] fn VecToBinHeap[<T : fmt::Debug + Ord>](vec: Vec<T>) -> BinaryHeap<T> { + 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[<T>][where T : Strategy, T::Value : Ord]( + statics::Map<VecStrategy<T>, VecToBinHeap>) + -> BinaryHeapValueTree<T::Tree>; + /// `ValueTree` corresponding to `BinaryHeapStrategy`. + #[derive(Clone, Debug)] + pub struct BinaryHeapValueTree[<T>][where T : ValueTree, T::Value : Ord]( + statics::Map<VecValueTree<T>, VecToBinHeap>) + -> BinaryHeap<T::Value>; +} + +/// Create a strategy to generate `BinaryHeap`s containing elements drawn from +/// `element` and with a size range given by `size`. +pub fn binary_heap<T: Strategy>( + element: T, + size: impl Into<SizeRange>, +) -> BinaryHeapStrategy<T> +where + T::Value: Ord, +{ + BinaryHeapStrategy(statics::Map::new(vec(element, size), VecToBinHeap)) +} + +mapfn! { + {#[cfg(feature = "std")]} + [] fn VecToHashSet[<T : fmt::Debug + Hash + Eq>](vec: Vec<T>) + -> HashSet<T> { + vec.into_iter().collect() + } +} + +#[derive(Debug, Clone, Copy)] +struct MinSize(usize); + +#[cfg(feature = "std")] +impl<T: Eq + Hash> statics::FilterFn<HashSet<T>> for MinSize { + fn apply(&self, set: &HashSet<T>) -> bool { + set.len() >= self.0 + } +} + +opaque_strategy_wrapper! { + {#[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[<T>][where T : Strategy, T::Value : Hash + Eq]( + statics::Filter<statics::Map<VecStrategy<T>, VecToHashSet>, MinSize>) + -> HashSetValueTree<T::Tree>; + /// `ValueTree` corresponding to `HashSetStrategy`. + #[derive(Clone, Debug)] + pub struct HashSetValueTree[<T>][where T : ValueTree, T::Value : Hash + Eq]( + statics::Filter<statics::Map<VecValueTree<T>, VecToHashSet>, MinSize>) + -> HashSet<T::Value>; +} + +/// 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")] +pub fn hash_set<T: Strategy>( + element: T, + size: impl Into<SizeRange>, +) -> HashSetStrategy<T> +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[<T : fmt::Debug + Ord>](vec: Vec<T>) + -> BTreeSet<T> { + vec.into_iter().collect() + } +} + +impl<T: Ord> statics::FilterFn<BTreeSet<T>> for MinSize { + fn apply(&self, set: &BTreeSet<T>) -> 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[<T>][where T : Strategy, T::Value : Ord]( + statics::Filter<statics::Map<VecStrategy<T>, VecToBTreeSet>, MinSize>) + -> BTreeSetValueTree<T::Tree>; + /// `ValueTree` corresponding to `BTreeSetStrategy`. + #[derive(Clone, Debug)] + pub struct BTreeSetValueTree[<T>][where T : ValueTree, T::Value : Ord]( + statics::Filter<statics::Map<VecValueTree<T>, VecToBTreeSet>, MinSize>) + -> BTreeSet<T::Value>; +} + +/// 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<T: Strategy>( + element: T, + size: impl Into<SizeRange>, +) -> BTreeSetStrategy<T> +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[<K : fmt::Debug + Hash + Eq, V : fmt::Debug>] + (vec: Vec<(K, V)>) -> HashMap<K, V> + { + vec.into_iter().collect() + } +} + +#[cfg(feature = "std")] +impl<K: Hash + Eq, V> statics::FilterFn<HashMap<K, V>> for MinSize { + fn apply(&self, map: &HashMap<K, V>) -> bool { + map.len() >= self.0 + } +} + +opaque_strategy_wrapper! { + {#[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[<K, V>] + [where K : Strategy, V : Strategy, K::Value : Hash + Eq]( + statics::Filter<statics::Map<VecStrategy<(K,V)>, + VecToHashMap>, MinSize>) + -> HashMapValueTree<K::Tree, V::Tree>; + /// `ValueTree` corresponding to `HashMapStrategy`. + #[derive(Clone, Debug)] + pub struct HashMapValueTree[<K, V>] + [where K : ValueTree, V : ValueTree, K::Value : Hash + Eq]( + statics::Filter<statics::Map<VecValueTree<TupleValueTree<(K, V)>>, + VecToHashMap>, MinSize>) + -> HashMap<K::Value, V::Value>; +} + +/// 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")] +pub fn hash_map<K: Strategy, V: Strategy>( + key: K, + value: V, + size: impl Into<SizeRange>, +) -> HashMapStrategy<K, V> +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[<K : fmt::Debug + Ord, V : fmt::Debug>] + (vec: Vec<(K, V)>) -> BTreeMap<K, V> + { + vec.into_iter().collect() + } +} + +impl<K: Ord, V> statics::FilterFn<BTreeMap<K, V>> for MinSize { + fn apply(&self, map: &BTreeMap<K, V>) -> 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[<K, V>] + [where K : Strategy, V : Strategy, K::Value : Ord]( + statics::Filter<statics::Map<VecStrategy<(K,V)>, + VecToBTreeMap>, MinSize>) + -> BTreeMapValueTree<K::Tree, V::Tree>; + /// `ValueTree` corresponding to `BTreeMapStrategy`. + #[derive(Clone, Debug)] + pub struct BTreeMapValueTree[<K, V>] + [where K : ValueTree, V : ValueTree, K::Value : Ord]( + statics::Filter<statics::Map<VecValueTree<TupleValueTree<(K, V)>>, + VecToBTreeMap>, MinSize>) + -> BTreeMap<K::Value, V::Value>; +} + +/// 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<K: Strategy, V: Strategy>( + key: K, + value: V, + size: impl Into<SizeRange>, +) -> BTreeMapStrategy<K, V> +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<T: ValueTree> { + elements: Vec<T>, + included_elements: VarBitSet, + min_size: usize, + shrink: Shrink, + prev_shrink: Option<Shrink>, +} + +impl<T: Strategy> Strategy for VecStrategy<T> { + type Tree = VecValueTree<T::Tree>; + type Value = Vec<T::Value>; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + 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<T: Strategy> Strategy for Vec<T> { + type Tree = VecValueTree<T::Tree>; + type Value = Vec<T::Value>; + + fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> { + let len = self.len(); + let elements = self + .iter() + .map(|t| t.new_tree(runner)) + .collect::<Result<Vec<_>, Reason>>()?; + + Ok(VecValueTree { + elements, + included_elements: VarBitSet::saturated(len), + min_size: len, + shrink: Shrink::ShrinkElement(0), + prev_shrink: None, + }) + } +} + +impl<T: ValueTree> ValueTree for VecValueTree<T> { + type Value = Vec<T::Value>; + + fn current(&self) -> Vec<T::Value> { + 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::<VarBitSet>().len() >= 2); + + let result = runner.run_one(case, |v| { + prop_assert!( + v.iter().map(|&v| v).sum::<usize>() < 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::<usize>() == 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()); + } + } +} diff --git a/vendor/proptest/src/file-preamble b/vendor/proptest/src/file-preamble new file mode 100644 index 000000000..13abfcdc0 --- /dev/null +++ b/vendor/proptest/src/file-preamble @@ -0,0 +1,8 @@ +//- +// Copyright 2017 +// +// 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. diff --git a/vendor/proptest/src/lib.rs b/vendor/proptest/src/lib.rs new file mode 100644 index 000000000..1cba5f900 --- /dev/null +++ b/vendor/proptest/src/lib.rs @@ -0,0 +1,102 @@ +//- +// 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. + +//! # Proptest Reference Documentation +//! +//! This is the reference documentation for the proptest API. +//! +//! For documentation on how to get started with proptest and general usage +//! advice, please refer to the [Proptest Book](https://altsysrq.github.io/proptest-book/intro.html). + +#![forbid(future_incompatible)] +#![deny(missing_docs, bare_trait_objects)] +#![no_std] +#![cfg_attr(feature = "cargo-clippy", allow( + doc_markdown, + // We have a lot of these lints for associated types... And we don't care. + type_complexity +))] +#![cfg_attr( + feature = "unstable", + feature(allocator_api, try_trait_v2, generator_trait, never_type) +)] +#![cfg_attr(all(feature = "std", feature = "unstable"), feature(ip))] +#![cfg_attr( + all(feature = "alloc", not(feature = "std")), + feature(core_intrinsics) +)] + +// std_facade is used in a few macros, so it needs to be public. +#[macro_use] +#[doc(hidden)] +pub mod std_facade; + +#[cfg(any(feature = "std", test))] +#[macro_use] +extern crate std; + +#[cfg(all(feature = "alloc", not(feature = "std")))] +#[macro_use] +extern crate alloc; + +#[cfg(feature = "frunk")] +#[macro_use] +extern crate frunk_core; + +#[cfg(feature = "frunk")] +#[macro_use] +mod product_frunk; + +#[cfg(not(feature = "frunk"))] +#[macro_use] +mod product_tuple; + +#[macro_use] +extern crate bitflags; +#[cfg(feature = "bit-set")] +extern crate bit_set; + +#[cfg(feature = "std")] +#[macro_use] +extern crate lazy_static; + +// Only required for the string module. +#[cfg(feature = "std")] +#[macro_use] +extern crate quick_error; + +#[cfg(feature = "fork")] +#[macro_use] +extern crate rusty_fork; + +#[macro_use] +mod macros; + +#[doc(hidden)] +#[macro_use] +pub mod sugar; + +pub mod arbitrary; +pub mod array; +pub mod bits; +pub mod bool; +pub mod char; +pub mod collection; +pub mod num; +pub mod strategy; +pub mod test_runner; +pub mod tuple; + +pub mod option; +pub mod result; +pub mod sample; +#[cfg(feature = "std")] +pub mod string; + +pub mod prelude; diff --git a/vendor/proptest/src/macros.rs b/vendor/proptest/src/macros.rs new file mode 100644 index 000000000..c76989eb6 --- /dev/null +++ b/vendor/proptest/src/macros.rs @@ -0,0 +1,93 @@ +//- +// 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. + +//! 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> { + 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, + } + }; +} diff --git a/vendor/proptest/src/num.rs b/vendor/proptest/src/num.rs new file mode 100644 index 000000000..75431c7b6 --- /dev/null +++ b/vendor/proptest/src/num.rs @@ -0,0 +1,1388 @@ +//- +// 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 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}; + +pub(crate) fn sample_uniform<X: SampleUniform>( + run: &mut TestRunner, + start: X, + end: X, +) -> X { + Uniform::new(start, end).sample(run.rng()) +} + +pub(crate) fn sample_uniform_incl<X: SampleUniform>( + 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<Self> { + 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<Self> { + 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<Self> { + 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<Self> { + 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<Self> { + 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<Self> { + 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); +#[cfg(not(target_arch = "wasm32"))] +signed_integer_bin_search!(i128); +signed_integer_bin_search!(isize); +unsigned_integer_bin_search!(u8); +unsigned_integer_bin_search!(u16); +unsigned_integer_bin_search!(u32); +unsigned_integer_bin_search!(u64); +#[cfg(not(target_arch = "wasm32"))] +unsigned_integer_bin_search!(u128); +unsigned_integer_bin_search!(usize); + +bitflags! { + pub(crate) struct FloatTypes: u32 { + const POSITIVE = 0b0000_0001; + const NEGATIVE = 0b0000_0010; + const NORMAL = 0b0000_0100; + const SUBNORMAL = 0b0000_1000; + const ZERO = 0b0001_0000; + const INFINITE = 0b0010_0000; + const QUIET_NAN = 0b0100_0000; + const SIGNALING_NAN = 0b1000_0000; + const ANY = + Self::POSITIVE.bits | + Self::NEGATIVE.bits | + Self::NORMAL.bits | + Self::SUBNORMAL.bits | + Self::ZERO.bits | + Self::INFINITE.bits | + Self::QUIET_NAN.bits; + } +} + +impl FloatTypes { + fn normalise(mut self) -> Self { + if !self.intersects(FloatTypes::POSITIVE | FloatTypes::NEGATIVE) { + self |= FloatTypes::POSITIVE; + } + + if !self.intersects( + FloatTypes::NORMAL + | FloatTypes::SUBNORMAL + | FloatTypes::ZERO + | FloatTypes::INFINITE + | FloatTypes::QUIET_NAN + | FloatTypes::SIGNALING_NAN, + ) { + self |= FloatTypes::NORMAL; + } + self + } +} + +trait FloatLayout +where + Standard: Distribution<Self::Bits>, +{ + 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<Self> { + 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<P: Fn(i32) -> 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<P: Fn(u32) -> bool>(start: u8, pass: P) { + let mut state = u8::BinarySearch::new(start); + loop { + if !pass(state.current() as u32) { + if !state.simplify() { + break; + } + } else { + if !state.complicate() { + break; + } + } + } + + assert!(!pass(state.current() as u32)); + assert!(pass(state.current() as u32 - 1)); + } + + for start in 0..255 { + for target in 0..start { + assert_converges(start as u8, |v| v <= target); + } + } + } + + #[test] + fn signed_integer_range_including_zero_converges_to_zero() { + let mut runner = TestRunner::default(); + for _ in 0..100 { + let mut state = (-42i32..64i32).new_tree(&mut runner).unwrap(); + let init_value = state.current(); + assert!(init_value >= -42 && init_value < 64); + + while state.simplify() { + let v = state.current(); + assert!(v >= -42 && v < 64); + } + + assert_eq!(0, state.current()); + } + } + + #[test] + fn negative_integer_range_stays_in_bounds() { + let mut runner = TestRunner::default(); + for _ in 0..100 { + let mut state = (..-42i32).new_tree(&mut runner).unwrap(); + let init_value = state.current(); + assert!(init_value < -42); + + while state.simplify() { + assert!( + state.current() < -42, + "Violated bounds: {}", + state.current() + ); + } + + assert_eq!(-43, state.current()); + } + } + + #[test] + fn positive_signed_integer_range_stays_in_bounds() { + let mut runner = TestRunner::default(); + for _ in 0..100 { + let mut state = (42i32..).new_tree(&mut runner).unwrap(); + let init_value = state.current(); + assert!(init_value >= 42); + + while state.simplify() { + assert!( + state.current() >= 42, + "Violated bounds: {}", + state.current() + ); + } + + assert_eq!(42, state.current()); + } + } + + #[test] + fn unsigned_integer_range_stays_in_bounds() { + let mut runner = TestRunner::default(); + for _ in 0..100 { + let mut state = (42u32..56u32).new_tree(&mut runner).unwrap(); + let init_value = state.current(); + assert!(init_value >= 42 && init_value < 56); + + while state.simplify() { + assert!( + state.current() >= 42, + "Violated bounds: {}", + state.current() + ); + } + + assert_eq!(42, state.current()); + } + } + + mod contract_sanity { + macro_rules! contract_sanity { + ($t:tt) => { + mod $t { + use crate::strategy::check_strategy_sanity; + + const FOURTY_TWO: $t = 42 as $t; + const FIFTY_SIX: $t = 56 as $t; + + #[test] + fn range() { + check_strategy_sanity(FOURTY_TWO..FIFTY_SIX, None); + } + + #[test] + fn range_inclusive() { + check_strategy_sanity(FOURTY_TWO..=FIFTY_SIX, None); + } + + #[test] + fn range_to() { + check_strategy_sanity(..FIFTY_SIX, None); + } + + #[test] + fn range_to_inclusive() { + check_strategy_sanity(..=FIFTY_SIX, None); + } + + #[test] + fn range_from() { + check_strategy_sanity(FOURTY_TWO.., None); + } + } + }; + } + contract_sanity!(u8); + contract_sanity!(i8); + contract_sanity!(u16); + contract_sanity!(i16); + contract_sanity!(u32); + contract_sanity!(i32); + contract_sanity!(u64); + contract_sanity!(i64); + contract_sanity!(usize); + contract_sanity!(isize); + contract_sanity!(f32); + contract_sanity!(f64); + } + + #[test] + fn unsigned_integer_binsearch_simplify_complicate_contract_upheld() { + check_strategy_sanity(0u32..1000u32, None); + check_strategy_sanity(0u32..1u32, None); + } + + #[test] + fn signed_integer_binsearch_simplify_complicate_contract_upheld() { + check_strategy_sanity(0i32..1000i32, None); + check_strategy_sanity(0i32..1i32, None); + } + + #[test] + fn positive_float_simplifies_to_zero() { + let mut runner = TestRunner::default(); + let mut value = (0.0f64..2.0).new_tree(&mut runner).unwrap(); + + while value.simplify() {} + + assert_eq!(0.0, value.current()); + } + + #[test] + fn positive_float_simplifies_to_base() { + let mut runner = TestRunner::default(); + let mut value = (1.0f64..2.0).new_tree(&mut runner).unwrap(); + + while value.simplify() {} + + assert_eq!(1.0, value.current()); + } + + #[test] + fn negative_float_simplifies_to_zero() { + let mut runner = TestRunner::default(); + let mut value = (-2.0f64..0.0).new_tree(&mut runner).unwrap(); + + while value.simplify() {} + + assert_eq!(0.0, value.current()); + } + + #[test] + fn positive_float_complicates_to_original() { + let mut runner = TestRunner::default(); + let mut value = (1.0f64..2.0).new_tree(&mut runner).unwrap(); + let orig = value.current(); + + assert!(value.simplify()); + while value.complicate() {} + + assert_eq!(orig, value.current()); + } + + #[test] + fn positive_infinity_simplifies_directly_to_zero() { + let mut value = f64::BinarySearch::new(::std::f64::INFINITY); + + assert!(value.simplify()); + assert_eq!(0.0, value.current()); + assert!(value.complicate()); + assert_eq!(::std::f64::INFINITY, value.current()); + assert!(!value.clone().complicate()); + assert!(!value.clone().simplify()); + } + + #[test] + fn negative_infinity_simplifies_directly_to_zero() { + let mut value = f64::BinarySearch::new(::std::f64::NEG_INFINITY); + + assert!(value.simplify()); + assert_eq!(0.0, value.current()); + assert!(value.complicate()); + assert_eq!(::std::f64::NEG_INFINITY, value.current()); + assert!(!value.clone().complicate()); + assert!(!value.clone().simplify()); + } + + #[test] + fn nan_simplifies_directly_to_zero() { + let mut value = f64::BinarySearch::new(::std::f64::NAN); + + assert!(value.simplify()); + assert_eq!(0.0, value.current()); + assert!(value.complicate()); + assert!(value.current().is_nan()); + assert!(!value.clone().complicate()); + assert!(!value.clone().simplify()); + } + + #[test] + fn float_simplifies_to_smallest_normal() { + let mut runner = TestRunner::default(); + let mut value = (::std::f64::MIN_POSITIVE..2.0) + .new_tree(&mut runner) + .unwrap(); + + while value.simplify() {} + + assert_eq!(::std::f64::MIN_POSITIVE, value.current()); + } + + macro_rules! float_generation_test_body { + ($strategy:ident, $typ:ident) => { + use std::num::FpCategory; + + let strategy = $strategy; + let bits = strategy.normal_bits(); + + let mut seen_positive = 0; + let mut seen_negative = 0; + let mut seen_normal = 0; + let mut seen_subnormal = 0; + let mut seen_zero = 0; + let mut seen_infinite = 0; + let mut seen_quiet_nan = 0; + let mut seen_signaling_nan = 0; + let mut runner = TestRunner::deterministic(); + + // Check whether this version of Rust honours the NaN payload in + // from_bits + let fidelity_1 = f32::from_bits(0x7F80_0001).to_bits(); + let fidelity_2 = f32::from_bits(0xFF80_0001).to_bits(); + let nan_fidelity = fidelity_1 != fidelity_2; + + for _ in 0..1024 { + let mut tree = strategy.new_tree(&mut runner).unwrap(); + let mut increment = 1; + + loop { + let value = tree.current(); + + let sign = value.signum(); // So we correctly handle -0 + if sign < 0.0 { + prop_assert!(bits.contains(FloatTypes::NEGATIVE)); + seen_negative += increment; + } else if sign > 0.0 { + // i.e., not NaN + prop_assert!(bits.contains(FloatTypes::POSITIVE)); + seen_positive += increment; + } + + match value.classify() { + FpCategory::Nan if nan_fidelity => { + let raw = value.to_bits(); + let is_negative = raw << 1 >> 1 != raw; + if is_negative { + prop_assert!( + bits.contains(FloatTypes::NEGATIVE) + ); + seen_negative += increment; + } else { + prop_assert!( + bits.contains(FloatTypes::POSITIVE) + ); + seen_positive += increment; + } + + let is_quiet = raw & ($typ::EXP_MASK >> 1) + == ::std::$typ::NAN.to_bits() + & ($typ::EXP_MASK >> 1); + if is_quiet { + // x86/AMD64 turn signalling NaNs into quiet + // NaNs quite aggressively depending on what + // registers LLVM decides to use to pass the + // value around, so accept either case here. + prop_assert!( + bits.contains(FloatTypes::QUIET_NAN) + || bits.contains( + FloatTypes::SIGNALING_NAN + ) + ); + seen_quiet_nan += increment; + seen_signaling_nan += increment; + } else { + prop_assert!( + bits.contains(FloatTypes::SIGNALING_NAN) + ); + seen_signaling_nan += increment; + } + } + + FpCategory::Nan => { + // Since safe Rust doesn't currently allow + // generating any NaN other than one particular + // payload, don't check the sign or signallingness + // and consider this to be both signs and + // signallingness for counting purposes. + seen_positive += increment; + seen_negative += increment; + seen_quiet_nan += increment; + seen_signaling_nan += increment; + prop_assert!( + bits.contains(FloatTypes::QUIET_NAN) + || bits.contains(FloatTypes::SIGNALING_NAN) + ); + } + FpCategory::Infinite => { + prop_assert!(bits.contains(FloatTypes::INFINITE)); + seen_infinite += increment; + } + FpCategory::Zero => { + prop_assert!(bits.contains(FloatTypes::ZERO)); + seen_zero += increment; + } + FpCategory::Subnormal => { + prop_assert!(bits.contains(FloatTypes::SUBNORMAL)); + seen_subnormal += increment; + } + FpCategory::Normal => { + prop_assert!(bits.contains(FloatTypes::NORMAL)); + seen_normal += increment; + } + } + + // Don't count simplified values towards the counts + increment = 0; + if !tree.simplify() { + break; + } + } + } + + if bits.contains(FloatTypes::POSITIVE) { + prop_assert!(seen_positive > 200); + } + if bits.contains(FloatTypes::NEGATIVE) { + prop_assert!(seen_negative > 200); + } + if bits.contains(FloatTypes::NORMAL) { + prop_assert!(seen_normal > 100); + } + if bits.contains(FloatTypes::SUBNORMAL) { + prop_assert!(seen_subnormal > 5); + } + if bits.contains(FloatTypes::ZERO) { + prop_assert!(seen_zero > 5); + } + if bits.contains(FloatTypes::INFINITE) { + prop_assert!(seen_infinite > 0); + } + if bits.contains(FloatTypes::QUIET_NAN) { + prop_assert!(seen_quiet_nan > 0); + } + if bits.contains(FloatTypes::SIGNALING_NAN) { + prop_assert!(seen_signaling_nan > 0); + } + }; + } + + proptest! { + #![proptest_config(crate::test_runner::Config::with_cases(1024))] + + #[test] + fn f32_any_generates_desired_values( + strategy in crate::bits::u32::ANY.prop_map(f32::Any::from_bits) + ) { + float_generation_test_body!(strategy, f32); + } + + #[test] + fn f32_any_sanity( + strategy in crate::bits::u32::ANY.prop_map(f32::Any::from_bits) + ) { + check_strategy_sanity(strategy, Some(CheckStrategySanityOptions { + strict_complicate_after_simplify: false, + .. CheckStrategySanityOptions::default() + })); + } + + #[test] + fn f64_any_generates_desired_values( + strategy in crate::bits::u32::ANY.prop_map(f64::Any::from_bits) + ) { + float_generation_test_body!(strategy, f64); + } + + #[test] + fn f64_any_sanity( + strategy in crate::bits::u32::ANY.prop_map(f64::Any::from_bits) + ) { + check_strategy_sanity(strategy, Some(CheckStrategySanityOptions { + strict_complicate_after_simplify: false, + .. CheckStrategySanityOptions::default() + })); + } + } +} diff --git a/vendor/proptest/src/num/float_samplers.rs b/vendor/proptest/src/num/float_samplers.rs new file mode 100644 index 000000000..55b6cd03b --- /dev/null +++ b/vendor/proptest/src/num/float_samplers.rs @@ -0,0 +1,463 @@ +//- +// Copyright 2022 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. + +//! 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<B1, B2>(low: B1, high: B2) -> Self + where + B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized, + { + let low = low.borrow().0; + let high = high.borrow().0; + FloatUniform { + low, + high, + intervals: split_interval([low, high]), + inclusive: false, + } + } + + fn new_inclusive<B1, B2>(low: B1, high: B2) -> Self + where + B1: SampleBorrow<Self::X> + Sized, + B2: SampleBorrow<Self::X> + Sized, + { + let low = low.borrow().0; + let high = high.borrow().0; + + FloatUniform { + low, + high, + intervals: split_interval([low, high]), + inclusive: true, + } + } + + fn sample<R: Rng + ?Sized>(&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<Value = $typ> { + prop::num::$typ::NEGATIVE + | prop::num::$typ::POSITIVE + | prop::num::$typ::NORMAL + | prop::num::$typ::SUBNORMAL + | prop::num::$typ::ZERO + } + + fn bounds() -> impl Strategy<Value = ($typ, $typ)> { + (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); diff --git a/vendor/proptest/src/option.rs b/vendor/proptest/src/option.rs new file mode 100644 index 000000000..466ada687 --- /dev/null +++ b/vendor/proptest/src/option.rs @@ -0,0 +1,271 @@ +//- +// 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 `std::Option` values. + +#![cfg_attr(feature = "cargo-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>) -> Probability { + from.into() +} + +impl Default for Probability { + /// The default probability is 0.5, or 50% chance. + fn default() -> Self { + prob(0.5) + } +} + +impl From<f64> 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 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<X>(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<X: Default>(self) -> product_type![Self, X] { + self.with(Default::default()) + } +} + +#[cfg(feature = "frunk")] +use frunk_core::generic::Generic; + +#[cfg(feature = "frunk")] +impl Generic for Probability { + type Repr = f64; + + /// Converts the `Probability` into an `f64`. + fn into(self) -> Self::Repr { + self.0 + } + + /// Creates a `Probability` from a `f64`. + /// + /// # Panics + /// + /// Panics if the probability is outside interval `[0.0, 1.0]`. + fn from(r: Self::Repr) -> Self { + r.into() + } +} + +impl From<Probability> 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 : fmt::Debug>](t: T) -> Option<T> { + Some(t) + } +} + +#[must_use = "strategies do nothing unless used"] +struct NoneStrategy<T>(PhantomData<T>); +impl<T> Clone for NoneStrategy<T> { + fn clone(&self) -> Self { + *self + } +} +impl<T> Copy for NoneStrategy<T> {} +impl<T> fmt::Debug for NoneStrategy<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "NoneStrategy") + } +} +impl<T: fmt::Debug> Strategy for NoneStrategy<T> { + type Tree = Self; + type Value = Option<T>; + + fn new_tree(&self, _: &mut TestRunner) -> NewTree<Self> { + Ok(*self) + } +} +impl<T: fmt::Debug> ValueTree for NoneStrategy<T> { + type Value = Option<T>; + + fn current(&self) -> Option<T> { + 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[<T>][where T : Strategy] + (TupleUnion<(WA<NoneStrategy<T::Value>>, + WA<statics::Map<T, WrapSome>>)>) + -> OptionValueTree<T>; + /// `ValueTree` type corresponding to `OptionStrategy`. + pub struct OptionValueTree[<T>][where T : Strategy] + (TupleUnionValueTree<( + LazyValueTree<NoneStrategy<T::Value>>, + Option<LazyValueTree<statics::Map<T, WrapSome>>>, + )>) + -> Option<T::Value>; +} + +// 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<T: Strategy + fmt::Debug> fmt::Debug for OptionStrategy<T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "OptionStrategy({:?})", self.0) + } +} + +impl<T: Strategy> Clone for OptionValueTree<T> +where + T::Tree: Clone, +{ + fn clone(&self) -> Self { + OptionValueTree(self.0.clone()) + } +} + +impl<T: Strategy> fmt::Debug for OptionValueTree<T> +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: Strategy>(t: T) -> OptionStrategy<T> { + 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<T: Strategy>( + probability_of_some: impl Into<Probability>, + t: T, +) -> OptionStrategy<T> { + 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<Just<i32>>) -> 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); + } +} diff --git a/vendor/proptest/src/prelude.rs b/vendor/proptest/src/prelude.rs new file mode 100644 index 000000000..8bdfd5db5 --- /dev/null +++ b/vendor/proptest/src/prelude.rs @@ -0,0 +1,53 @@ +//- +// 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. + +//! 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; +} diff --git a/vendor/proptest/src/product_frunk.rs b/vendor/proptest/src/product_frunk.rs new file mode 100644 index 000000000..b12524d1c --- /dev/null +++ b/vendor/proptest/src/product_frunk.rs @@ -0,0 +1,49 @@ +//- +// 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 macros for product type creation, extraction, and the type signature +//! itself. This version uses `frunk_core`. This mechanism is used to be very +//! loosely coupled with `frunk_core` so that only `lib.rs` has to be changed +//! in the event that Rust gets tuple-variadic generics. + +macro_rules! product_type { + ($factor: ty) => { + Hlist![$factor] + }; + ($($factor: ty),*) => { + Hlist![$( $factor, )*] + }; + ($($factor: ty),*,) => { + Hlist![$( $factor, )*] + }; +} + +macro_rules! product_pack { + ($factor: expr) => { + hlist![$factor] + }; + ($($factor: expr),*) => { + hlist![$( $factor ),*] + }; + ($($factor: expr),*,) => { + hlist![$( $factor ),*] + }; +} + +macro_rules! product_unpack { + ($factor: pat) => { + hlist_pat![$factor] + }; + ($($factor: pat),*) => { + hlist_pat![$( $factor ),*] + }; + ($($factor: pat),*,) => { + hlist_pat![$( $factor ),*] + }; +} diff --git a/vendor/proptest/src/product_tuple.rs b/vendor/proptest/src/product_tuple.rs new file mode 100644 index 000000000..1c32d9541 --- /dev/null +++ b/vendor/proptest/src/product_tuple.rs @@ -0,0 +1,49 @@ +//- +// 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 macros for product type creation, extraction, and the type signature +//! itself. This version uses tuples. This mechanism is used to be very +//! loosely coupled with `frunk_core` so that only `lib.rs` has to be changed +//! in the event that Rust gets tuple-variadic generics. + +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 ),* ) + }; +} diff --git a/vendor/proptest/src/regex-contrib/README.md b/vendor/proptest/src/regex-contrib/README.md new file mode 100644 index 000000000..f438d2047 --- /dev/null +++ b/vendor/proptest/src/regex-contrib/README.md @@ -0,0 +1,3 @@ +Files 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. diff --git a/vendor/proptest/src/regex-contrib/crates_regex.rs b/vendor/proptest/src/regex-contrib/crates_regex.rs new file mode 100644 index 000000000..1ccfe4710 --- /dev/null +++ b/vendor/proptest/src/regex-contrib/crates_regex.rs @@ -0,0 +1,3129 @@ +// 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 <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. + +// 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<percent>.+)%.*\].*" +consistent!(markifier_0, r".*\[(?P<percent>.+)%.*\].*"); + +// 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<k>[a-zA-Z_]+)" +consistent!(magnet_app_0, r":(?P<k>[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: "<!--(.|\n)*?-->" +consistent!(minifier_3, "<!--(.|\n)*?-->"); + +// 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<relation>\([^)]+\))|(?P<prop>[a-zA-Z0-9_]+)" +consistent!(ggp_rs_0, r"(?P<relation>\([^)]+\))|(?P<prop>[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<nmsg>\d+) (?P<size>\d+)" +consistent!(pop3_rs_0, r"(?P<nmsg>\d+) (?P<size>\d+)"); + +// pop3-rs-0.1.0: r"(?P<msgid>\d+) (?P<uidl>[\x21-\x7E]{1,70})" +consistent!(pop3_rs_1, r"(?P<msgid>\d+) (?P<uidl>[\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<status>\+OK|-ERR) (?P<statustext>.*)" +consistent!(pop3_rs_3, r"^(?P<status>\+OK|-ERR) (?P<statustext>.*)"); + +// 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"<value><string>([0-9.]*)</string></value>" +consistent!(generic_dns_update_2, r"<value><string>([0-9.]*)</string></value>"); + +// generic-dns-update-1.1.4: r"<int>([0-9]+)</int>" +consistent!(generic_dns_update_3, r"<int>([0-9]+)</int>"); + +// generic-dns-update-1.1.4: r"<int>([0-9]+)</int>" +consistent!(generic_dns_update_4, r"<int>([0-9]+)</int>"); + +// generic-dns-update-1.1.4: r"<boolean>([0-1]*)</boolean>" +consistent!(generic_dns_update_5, r"<boolean>([0-1]*)</boolean>"); + +// 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<config>.*?)\*/" +consistent!(grimoire_0, r"(?s)/\*(?P<config>.*?)\*/"); + +// 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<hex>[0-9a-fA-F][0-9a-fA-F])" +consistent!(uritemplate_0, "%25(?P<hex>[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<key>[?&.])" +consistent!(url_match_0, r"(?P<key>[?&.])"); + +// url-match-0.1.7: r":(?P<key>[a-zA-Z0-9_-]+)" +consistent!(url_match_1, r":(?P<key>[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<Block>\{db: \w+\}" +consistent!(hyperscan_2, r"RawDatabase<Block>\{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<day>\d{1,2})/(?P<month>\d{1,2})(/(?P<year>\d{4}|\d{2}))?" +consistent!(timmy_2, r"(?P<day>\d{1,2})/(?P<month>\d{1,2})(/(?P<year>\d{4}|\d{2}))?"); + +// timmy-0.3.0: r"(?P<n>\d+) (days?|ds?)(?P<ago>( ago)?)" +consistent!(timmy_3, r"(?P<n>\d+) (days?|ds?)(?P<ago>( ago)?)"); + +// timmy-0.3.0: r"(?P<hr>\d{2}):(?P<mins>\d{2})" +consistent!(timmy_4, r"(?P<hr>\d{2}):(?P<mins>\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<title>[^']+)'\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+)"); + diff --git a/vendor/proptest/src/result.rs b/vendor/proptest/src/result.rs new file mode 100644 index 000000000..bdb163b35 --- /dev/null +++ b/vendor/proptest/src/result.rs @@ -0,0 +1,326 @@ +//- +// 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(feature = "cargo-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); + } +} diff --git a/vendor/proptest/src/sample.rs b/vendor/proptest/src/sample.rs new file mode 100644 index 000000000..9c464f132 --- /dev/null +++ b/vendor/proptest/src/sample.rs @@ -0,0 +1,566 @@ +//- +// 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] + } +} + +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); + } +} diff --git a/vendor/proptest/src/std_facade.rs b/vendor/proptest/src/std_facade.rs new file mode 100644 index 000000000..2ccbe1550 --- /dev/null +++ b/vendor/proptest/src/std_facade.rs @@ -0,0 +1,74 @@ +//- +// 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 +} diff --git a/vendor/proptest/src/strategy/filter.rs b/vendor/proptest/src/strategy/filter.rs new file mode 100644 index 000000000..029dbcebc --- /dev/null +++ b/vendor/proptest/src/strategy/filter.rs @@ -0,0 +1,147 @@ +//- +// 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() + }), + ); + } +} diff --git a/vendor/proptest/src/strategy/filter_map.rs b/vendor/proptest/src/strategy/filter_map.rs new file mode 100644 index 000000000..52f901276 --- /dev/null +++ b/vendor/proptest/src/strategy/filter_map.rs @@ -0,0 +1,209 @@ +//- +// 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() + }), + ); + } +} diff --git a/vendor/proptest/src/strategy/flatten.rs b/vendor/proptest/src/strategy/flatten.rs new file mode 100644 index 000000000..63ac41604 --- /dev/null +++ b/vendor/proptest/src/strategy/flatten.rs @@ -0,0 +1,359 @@ +//- +// 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, + ); + } +} diff --git a/vendor/proptest/src/strategy/fuse.rs b/vendor/proptest/src/strategy/fuse.rs new file mode 100644 index 000000000..5c0f9a374 --- /dev/null +++ b/vendor/proptest/src/strategy/fuse.rs @@ -0,0 +1,228 @@ +//- +// 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()); + } +} diff --git a/vendor/proptest/src/strategy/just.rs b/vendor/proptest/src/strategy/just.rs new file mode 100644 index 000000000..a141f8a17 --- /dev/null +++ b/vendor/proptest/src/strategy/just.rs @@ -0,0 +1,145 @@ +//- +// 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() + } +} diff --git a/vendor/proptest/src/strategy/lazy.rs b/vendor/proptest/src/strategy/lazy.rs new file mode 100644 index 000000000..cb95a7492 --- /dev/null +++ b/vendor/proptest/src/strategy/lazy.rs @@ -0,0 +1,175 @@ +//- +// 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"), + } + } +} diff --git a/vendor/proptest/src/strategy/map.rs b/vendor/proptest/src/strategy/map.rs new file mode 100644 index 000000000..464b99819 --- /dev/null +++ b/vendor/proptest/src/strategy/map.rs @@ -0,0 +1,301 @@ +//- +// 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()); + } +} diff --git a/vendor/proptest/src/strategy/mod.rs b/vendor/proptest/src/strategy/mod.rs new file mode 100644 index 000000000..6427fc103 --- /dev/null +++ b/vendor/proptest/src/strategy/mod.rs @@ -0,0 +1,37 @@ +//- +// 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::lazy::*; +pub use self::map::*; +pub use self::recursive::*; +pub use self::shuffle::*; +pub use self::traits::*; +pub use self::unions::*; + +pub mod statics; diff --git a/vendor/proptest/src/strategy/recursive.rs b/vendor/proptest/src/strategy/recursive.rs new file mode 100644 index 000000000..6407be7c7 --- /dev/null +++ b/vendor/proptest/src/strategy/recursive.rs @@ -0,0 +1,209 @@ +//- +// 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()); + } + } +} diff --git a/vendor/proptest/src/strategy/shuffle.rs b/vendor/proptest/src/strategy/shuffle.rs new file mode 100644 index 000000000..b94a73c3b --- /dev/null +++ b/vendor/proptest/src/strategy/shuffle.rs @@ -0,0 +1,287 @@ +//- +// 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, + ); + } +} diff --git a/vendor/proptest/src/strategy/statics.rs b/vendor/proptest/src/strategy/statics.rs new file mode 100644 index 000000000..978dc13b9 --- /dev/null +++ b/vendor/proptest/src/strategy/statics.rs @@ -0,0 +1,266 @@ +//- +// 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(); + } +} diff --git a/vendor/proptest/src/strategy/traits.rs b/vendor/proptest/src/strategy/traits.rs new file mode 100644 index 000000000..bcad20a1e --- /dev/null +++ b/vendor/proptest/src/strategy/traits.rs @@ -0,0 +1,1054 @@ +//- +// 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 + ); + } + } + } +} diff --git a/vendor/proptest/src/strategy/unions.rs b/vendor/proptest/src/strategy/unions.rs new file mode 100644 index 000000000..fb5806297 --- /dev/null +++ b/vendor/proptest/src/strategy/unions.rs @@ -0,0 +1,697 @@ +//- +// 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 `Stragegy`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() + } + } +} diff --git a/vendor/proptest/src/string.rs b/vendor/proptest/src/string.rs new file mode 100644 index 000000000..195d75077 --- /dev/null +++ b/vendor/proptest/src/string.rs @@ -0,0 +1,560 @@ +//- +// 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::*, + Literal::*, + RepetitionKind::{self, *}, + RepetitionRange::*, +}; +use regex_syntax::{Error as ParseError, Parser}; + +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, 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*") + } +} + +// quick_error! uses bare trait objects, so we enclose its invocation here in a +// module so the lint can be disabled just for it. +#[allow(bare_trait_objects)] +mod error_container { + use super::*; + + quick_error! { + /// 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(err: ParseError) { + from() + source(err) + display("{}", err) + } + /// The regex was syntactically valid, but contains elements not + /// supported by proptest. + UnsupportedRegex(message: &'static str) { + display("{}", message) + } + } + } +} + +pub use self::error_container::Error; + +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/AltSysrq/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> { + string_regex_parsed(®ex_to_hir(regex)?) +} + +/// 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. +pub fn bytes_regex(regex: &str) -> ParseResult<Vec<u8>> { + bytes_regex_parsed(®ex_to_hir(regex)?) +} + +/// 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(match lit { + Unicode(scalar) => to_bytes(*scalar), + Byte(byte) => vec![*byte], + }) + .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.hir)?, + to_range(rep.kind.clone())?, + ) + .prop_map(|parts| { + parts.into_iter().fold(vec![], |mut acc, child| { + acc.extend(child); + acc + }) + }) + .sboxed()), + + Group(group) => bytes_regex_parsed(&group.hir).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()) + } + + Anchor(_) => { + unsupported("line/text anchors not supported for string generation") + } + + WordBoundary(_) => unsupported( + "word boundary tests 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(Unicode(scalar)) => self.buf.extend(to_bytes(*scalar)), + Literal(Byte(byte)) => self.buf.push(*byte), + // 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(kind: RepetitionKind) -> Result<SizeRange, Error> { + Ok(match kind { + ZeroOrOne => size_range(0..=1), + ZeroOrMore => size_range(0..=32), + OneOrMore => size_range(1..=32), + Range(range) => match range { + Exactly(count) if u32::MAX == count => { + return unsupported( + "Cannot have repetition of exactly u32::MAX", + ) + } + Exactly(count) => size_range(count as usize), + AtLeast(min) => { + 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(_, max) if u32::MAX == max => { + return unsupported("Cannot have repetition max of u32::MAX") + } + Bounded(min, 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 regex_to_hir(pattern: &str) -> Result<Hir, Error> { + Ok(Parser::new().parse(pattern)?) +} + +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 super::*; + + 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 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 + } + + #[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); + } + + #[test] + fn test_casei_literal() { + do_test("(?i:fOo)", 8, 8, 64); + } + + #[test] + fn test_alternation() { + do_test("foo|bar|baz", 3, 3, 16); + } + + #[test] + fn test_repitition() { + do_test("a{0,8}", 9, 9, 64); + } + + #[test] + fn test_question() { + do_test("a?", 2, 2, 16); + } + + #[test] + fn test_star() { + do_test("a*", 33, 33, 256); + } + + #[test] + fn test_plus() { + do_test("a+", 32, 32, 256); + } + + #[test] + fn test_n_to_range() { + do_test("a{4,}", 4, 4, 64); + } + + #[test] + fn test_concatenation() { + do_test("(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); + } + + #[test] + fn test_backslash_d_plus() { + do_test("\\d+", 1, 65536, 256); + } + + 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"); +} diff --git a/vendor/proptest/src/sugar.rs b/vendor/proptest/src/sugar.rs new file mode 100644 index 000000000..42ba5c194 --- /dev/null +++ b/vendor/proptest/src/sugar.rs @@ -0,0 +1,1637 @@ +//- +// 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 = $config.clone(); + config.test_name = Some( + concat!(module_path!(), "::", stringify!($test_name))); + $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body); + } + )* + }; + (#![proptest_config($config:expr)] + $( + $(#[$meta:meta])* + fn $test_name:ident($($arg:tt)+) $body:block + )*) => { + $( + $(#[$meta])* + fn $test_name() { + let mut config = $config.clone(); + config.test_name = Some( + concat!(module_path!(), "::", stringify!($test_name))); + $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); + } + )* + }; + + ($( + $(#[$meta:meta])* + fn $test_name:ident($($parm:pat in $strategy:expr),+ $(,)?) $body:block + )*) => { $crate::proptest! { + #![proptest_config($crate::test_runner::Config::default())] + $($(#[$meta])* + fn $test_name($($parm in $strategy),+) $body)* + } }; + + ($( + $(#[$meta:meta])* + fn $test_name:ident($($arg:tt)+) $body:block + )*) => { $crate::proptest! { + #![proptest_config($crate::test_runner::Config::default())] + $($(#[$meta])* + fn $test_name($($arg)+) $body)* + } }; + + (|($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + |($($parm in $strategy),+)| $body) + }; + + (move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + move |($($parm in $strategy),+)| $body) + }; + + (|($($arg:tt)+)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + |($($arg)+)| $body) + }; + + (move |($($arg:tt)+)| $body:expr) => { + $crate::proptest!( + $crate::test_runner::Config::default(), + move |($($arg)+)| $body) + }; + + ($config:expr, |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [] $body) + } }; + + ($config:expr, move |($($parm:pat in $strategy:expr),+ $(,)?)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY config ($($parm in $strategy),+) [move] $body) + } }; + + ($config:expr, |($($arg:tt)+)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY2 config ($($arg)+) [] $body); + } }; + + ($config:expr, move |($($arg:tt)+)| $body:expr) => { { + let mut config = $config.__sugar_to_owned(); + $crate::sugar::force_no_fork(&mut config); + $crate::proptest_helper!(@_BODY2 config ($($arg)+) [move] $body); + } }; +} + +/// Rejects the test input if assumptions are not met. +/// +/// Used directly within a function defined with `proptest!` or in any function +/// returning `Result<_, TestCaseError>`. +/// +/// This is invoked as `prop_assume!(condition, format, args...)`. `condition` +/// is evaluated; if it is false, `Err(TestCaseError::Reject)` is returned. The +/// message includes the point of invocation and the format message. `format` +/// and `args` may be omitted to simply use the condition itself as the +/// message. +#[macro_export] +macro_rules! prop_assume { + ($expr:expr) => { + $crate::prop_assume!($expr, "{}", stringify!($expr)) + }; + + ($expr:expr, $fmt:tt $(, $fmt_arg:expr),* $(,)?) => { + if !$expr { + return ::core::result::Result::Err( + $crate::test_runner::TestCaseError::reject( + format!(concat!("{}:{}:{}: ", $fmt), + file!(), line!(), column!() + $(, $fmt_arg)*))); + } + }; +} + +/// Produce a strategy which picks one of the listed choices. +/// +/// This is conceptually equivalent to calling `prop_union` on the first two +/// elements and then chaining `.or()` onto the rest after implicitly boxing +/// all of them. As with `Union`, values shrink across elements on the +/// assumption that earlier ones are "simpler", so they should be listed in +/// order of ascending complexity when possible. +/// +/// The macro invocation has two forms. The first is to simply list the +/// strategies separated by commas; this will cause value generation to pick +/// from the strategies uniformly. The other form is to provide a weight in the +/// form of a `u32` before each strategy, separated from the strategy with +/// `=>`. +/// +/// Note that the exact type returned by the macro varies depending on how many +/// inputs there are. In particular, if given exactly one option, it will +/// return it unmodified. It is not recommended to depend on the particular +/// type produced by this macro. +/// +/// ## Example +/// +/// ```rust,no_run +/// use proptest::prelude::*; +/// +/// #[derive(Clone, Copy, Debug)] +/// enum MyEnum { +/// Big(u64), +/// Medium(u32), +/// Little(i16), +/// } +/// +/// # #[allow(unused_variables)] +/// # fn main() { +/// let my_enum_strategy = prop_oneof![ +/// prop::num::i16::ANY.prop_map(MyEnum::Little), +/// prop::num::u32::ANY.prop_map(MyEnum::Medium), +/// prop::num::u64::ANY.prop_map(MyEnum::Big), +/// ]; +/// +/// let my_weighted_strategy = prop_oneof![ +/// 1 => prop::num::i16::ANY.prop_map(MyEnum::Little), +/// // Chose `Medium` twice as frequently as either `Little` or `Big`; i.e., +/// // around 50% of values will be `Medium`, and 25% for each of `Little` +/// // and `Big`. +/// 2 => prop::num::u32::ANY.prop_map(MyEnum::Medium), +/// 1 => prop::num::u64::ANY.prop_map(MyEnum::Big), +/// ]; +/// # } +/// ``` +#[macro_export] +macro_rules! prop_oneof { + ($($item:expr),+ $(,)?) => { + $crate::prop_oneof![ + $(1 => $item),* + ] + }; + + ($_weight0:expr => $item0:expr $(,)?) => { $item0 }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)), + ($weight7, $crate::std_facade::Arc::new($item7)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr, + $weight8:expr => $item8:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)), + ($weight7, $crate::std_facade::Arc::new($item7)), + ($weight8, $crate::std_facade::Arc::new($item8)))) + }; + + ($weight0:expr => $item0:expr, + $weight1:expr => $item1:expr, + $weight2:expr => $item2:expr, + $weight3:expr => $item3:expr, + $weight4:expr => $item4:expr, + $weight5:expr => $item5:expr, + $weight6:expr => $item6:expr, + $weight7:expr => $item7:expr, + $weight8:expr => $item8:expr, + $weight9:expr => $item9:expr $(,)?) => { + $crate::strategy::TupleUnion::new( + (($weight0, $crate::std_facade::Arc::new($item0)), + ($weight1, $crate::std_facade::Arc::new($item1)), + ($weight2, $crate::std_facade::Arc::new($item2)), + ($weight3, $crate::std_facade::Arc::new($item3)), + ($weight4, $crate::std_facade::Arc::new($item4)), + ($weight5, $crate::std_facade::Arc::new($item5)), + ($weight6, $crate::std_facade::Arc::new($item6)), + ($weight7, $crate::std_facade::Arc::new($item7)), + ($weight8, $crate::std_facade::Arc::new($item8)), + ($weight9, $crate::std_facade::Arc::new($item9)))) + }; + + ($($weight:expr => $item:expr),+ $(,)?) => { + $crate::strategy::Union::new_weighted(vec![ + $(($weight, $crate::strategy::Strategy::boxed($item))),* + ]) + }; +} + +/// Convenience to define functions which produce new strategies. +/// +/// The macro has two general forms. In the first, you define a function with +/// two argument lists. The first argument list uses the usual syntax and +/// becomes exactly the argument list of the defined function. The second +/// argument list uses the `in strategy` syntax as with `proptest!`, and is +/// used to generate the other inputs for the function. The second argument +/// list has access to all arguments in the first. The return type indicates +/// the type of value being generated; the final return type of the function is +/// `impl Strategy<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; + } +} diff --git a/vendor/proptest/src/test_runner/config.rs b/vendor/proptest/src/test_runner/config.rs new file mode 100644 index 000000000..a3d30846a --- /dev/null +++ b/vendor/proptest/src/test_runner/config.rs @@ -0,0 +1,516 @@ +//- +// 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; + +#[cfg(feature = "std")] +use std::env; +#[cfg(feature = "std")] +use std::ffi::OsString; +#[cfg(feature = "std")] +use std::fmt; +#[cfg(feature = "std")] +use std::str::FromStr; + +use crate::test_runner::result_cache::{noop_result_cache, ResultCache}; +use crate::test_runner::rng::RngAlgorithm; +use crate::test_runner::FailurePersistence; +#[cfg(feature = "std")] +use crate::test_runner::FileFailurePersistence; + +#[cfg(feature = "std")] +const CASES: &str = "PROPTEST_CASES"; +#[cfg(feature = "std")] +const MAX_LOCAL_REJECTS: &str = "PROPTEST_MAX_LOCAL_REJECTS"; +#[cfg(feature = "std")] +const MAX_GLOBAL_REJECTS: &str = "PROPTEST_MAX_GLOBAL_REJECTS"; +#[cfg(feature = "std")] +const MAX_FLAT_MAP_REGENS: &str = "PROPTEST_MAX_FLAT_MAP_REGENS"; +#[cfg(feature = "std")] +const MAX_SHRINK_TIME: &str = "PROPTEST_MAX_SHRINK_TIME"; +#[cfg(feature = "std")] +const MAX_SHRINK_ITERS: &str = "PROPTEST_MAX_SHRINK_ITERS"; +#[cfg(feature = "fork")] +const FORK: &str = "PROPTEST_FORK"; +#[cfg(feature = "timeout")] +const TIMEOUT: &str = "PROPTEST_TIMEOUT"; +#[cfg(feature = "std")] +const VERBOSE: &str = "PROPTEST_VERBOSE"; +#[cfg(feature = "std")] +const RNG_ALGORITHM: &str = "PROPTEST_RNG_ALGORITHM"; +#[cfg(feature = "std")] +const DISABLE_FAILURE_PERSISTENCE: &str = + "PROPTEST_DISABLE_FAILURE_PERSISTENCE"; + +#[cfg(feature = "std")] +fn contextualize_config(mut result: Config) -> Config { + 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 + ); + } + } + + result.failure_persistence = + Some(Box::new(FileFailurePersistence::default())); + for (var, value) in + env::vars_os().filter_map(|(k, v)| k.into_string().ok().map(|k| (k, v))) + { + match var.as_str() { + CASES => parse_or_warn(&value, &mut result.cases, "u32", CASES), + MAX_LOCAL_REJECTS => parse_or_warn( + &value, + &mut result.max_local_rejects, + "u32", + MAX_LOCAL_REJECTS, + ), + MAX_GLOBAL_REJECTS => parse_or_warn( + &value, + &mut result.max_global_rejects, + "u32", + MAX_GLOBAL_REJECTS, + ), + MAX_FLAT_MAP_REGENS => parse_or_warn( + &value, + &mut result.max_flat_map_regens, + "u32", + MAX_FLAT_MAP_REGENS, + ), + #[cfg(feature = "fork")] + FORK => parse_or_warn(&value, &mut result.fork, "bool", FORK), + #[cfg(feature = "timeout")] + TIMEOUT => { + parse_or_warn(&value, &mut result.timeout, "timeout", TIMEOUT) + } + MAX_SHRINK_TIME => parse_or_warn( + &value, + &mut result.max_shrink_time, + "u32", + MAX_SHRINK_TIME, + ), + MAX_SHRINK_ITERS => parse_or_warn( + &value, + &mut result.max_shrink_iters, + "u32", + MAX_SHRINK_ITERS, + ), + VERBOSE => { + parse_or_warn(&value, &mut result.verbose, "u32", VERBOSE) + } + RNG_ALGORITHM => parse_or_warn( + &value, + &mut result.rng_algorithm, + "RngAlgorithm", + RNG_ALGORITHM, + ), + DISABLE_FAILURE_PERSISTENCE => result.failure_persistence = None, + + _ => { + if var.starts_with("PROPTEST_") { + eprintln!("proptest: Ignoring unknown env-var {}.", var); + } + } + } + } + + result +} + +#[cfg(not(feature = "std"))] +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, + result_cache: noop_result_cache, + #[cfg(feature = "std")] + verbose: 0, + rng_algorithm: RngAlgorithm::default(), + _non_exhaustive: (), + } +} + +// The default config, computed by combining environment variables and +// defaults. +#[cfg(feature = "std")] +lazy_static! { + static ref DEFAULT_CONFIG: Config = + contextualize_config(default_default_config()); +} + +/// Configuration for how a proptest test should be run. +#[derive(Clone, Debug, PartialEq)] +pub struct Config { + /// The number of successful test cases that must execute for the test as a + /// whole to pass. + /// + /// This does not include implicitly-replayed persisted failing cases. + /// + /// The default is 256, which can be overridden by setting the + /// `PROPTEST_CASES` environment variable. (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")] + 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")] + 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")] + 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, + + /// 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. + /// - 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")] + 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 + } + + /// Return whether this configuration implies forking. + /// + /// This method exists even if the "fork" feature is disabled, in which + /// case it simply returns false. + pub fn fork(&self) -> bool { + self._fork() || self.timeout() > 0 + } + + #[cfg(feature = "fork")] + fn _fork(&self) -> bool { + self.fork + } + + #[cfg(not(feature = "fork"))] + fn _fork(&self) -> bool { + false + } + + /// Returns the configured timeout. + /// + /// This method exists even if the "timeout" feature is disabled, in which + /// case it simply returns 0. + #[cfg(feature = "timeout")] + pub fn timeout(&self) -> u32 { + self.timeout + } + + /// Returns the configured timeout. + /// + /// This method exists even if the "timeout" feature is disabled, in which + /// case it simply returns 0. + #[cfg(not(feature = "timeout"))] + pub fn timeout(&self) -> u32 { + 0 + } + + /// Returns the configured limit on shrinking iterations. + /// + /// This takes into account the special "automatic" behaviour. + pub fn max_shrink_iters(&self) -> u32 { + if u32::MAX == self.max_shrink_iters { + self.cases.saturating_mul(4) + } else { + self.max_shrink_iters + } + } + + // Used by macros to force the config to be owned without depending on + // certain traits being `use`d. + #[allow(missing_docs)] + #[doc(hidden)] + pub fn __sugar_to_owned(&self) -> Self { + self.clone() + } +} + +#[cfg(feature = "std")] +impl Default for Config { + fn default() -> Self { + DEFAULT_CONFIG.clone() + } +} + +#[cfg(not(feature = "std"))] +impl Default for Config { + fn default() -> Self { + default_default_config() + } +} diff --git a/vendor/proptest/src/test_runner/errors.rs b/vendor/proptest/src/test_runner/errors.rs new file mode 100644 index 000000000..dfa4a4852 --- /dev/null +++ b/vendor/proptest/src/test_runner/errors.rs @@ -0,0 +1,135 @@ +//- +// 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 compability 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 compability 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) => write!( + f, + "Test failed: {}; minimal failing input: {:?}", + why, 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", + } + } +} diff --git a/vendor/proptest/src/test_runner/failure_persistence/file.rs b/vendor/proptest/src/test_runner/failure_persistence/file.rs new file mode 100644 index 000000000..61d7dcf6a --- /dev/null +++ b/vendor/proptest/src/test_runner/failure_persistence/file.rs @@ -0,0 +1,536 @@ +//- +// 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 given to `TestRunner::set_source_file()` is parsed. The path + /// 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), + /// The path given to `TestRunner::set_source_file()` is parsed. The + /// extension of the path is changed to the string given in this + /// configuration, and that filename is used. + /// + /// 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 if is_new { + 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() + ); + } +} diff --git a/vendor/proptest/src/test_runner/failure_persistence/map.rs b/vendor/proptest/src/test_runner/failure_persistence/map.rs new file mode 100644 index 000000000..322e554c6 --- /dev/null +++ b/vendor/proptest/src/test_runner/failure_persistence/map.rs @@ -0,0 +1,99 @@ +//- +// 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()); + } +} diff --git a/vendor/proptest/src/test_runner/failure_persistence/mod.rs b/vendor/proptest/src/test_runner/failure_persistence/mod.rs new file mode 100644 index 000000000..6d21c4002 --- /dev/null +++ b/vendor/proptest/src/test_runner/failure_persistence/mod.rs @@ -0,0 +1,156 @@ +//- +// 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")] +mod file; +mod map; +mod noop; + +#[cfg(feature = "std")] +pub use self::file::*; +pub use self::map::*; +pub use self::noop::*; + +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"); +} diff --git a/vendor/proptest/src/test_runner/failure_persistence/noop.rs b/vendor/proptest/src/test_runner/failure_persistence/noop.rs new file mode 100644 index 000000000..59538392a --- /dev/null +++ b/vendor/proptest/src/test_runner/failure_persistence/noop.rs @@ -0,0 +1,76 @@ +//- +// 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()); + } +} diff --git a/vendor/proptest/src/test_runner/mod.rs b/vendor/proptest/src/test_runner/mod.rs new file mode 100644 index 000000000..d7516ab96 --- /dev/null +++ b/vendor/proptest/src/test_runner/mod.rs @@ -0,0 +1,31 @@ +//- +// 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; + +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::*; diff --git a/vendor/proptest/src/test_runner/reason.rs b/vendor/proptest/src/test_runner/reason.rs new file mode 100644 index 000000000..38cc7e322 --- /dev/null +++ b/vendor/proptest/src/test_runner/reason.rs @@ -0,0 +1,54 @@ +//- +// 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) + } +} diff --git a/vendor/proptest/src/test_runner/replay.rs b/vendor/proptest/src/test_runner/replay.rs new file mode 100644 index 000000000..4365d5538 --- /dev/null +++ b/vendor/proptest/src/test_runner/replay.rs @@ -0,0 +1,189 @@ +//- +// 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 })) + } +} diff --git a/vendor/proptest/src/test_runner/result_cache.rs b/vendor/proptest/src/test_runner/result_cache.rs new file mode 100644 index 000000000..c5bc68c3a --- /dev/null +++ b/vendor/proptest/src/test_runner/result_cache.rs @@ -0,0 +1,120 @@ +//- +// 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")] +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) +} diff --git a/vendor/proptest/src/test_runner/rng.rs b/vendor/proptest/src/test_runner/rng.rs new file mode 100644 index 000000000..78c8d7a75 --- /dev/null +++ b/vendor/proptest/src/test_runner/rng.rs @@ -0,0 +1,724 @@ +//- +// 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}; + +use byteorder::{ByteOrder, LittleEndian}; +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[..]); + LittleEndian::read_u32(&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[..]); + LittleEndian::read_u64(&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]; + LittleEndian::write_u32_into(&dwords[..], &mut seed[..]); + 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 mut dwords = [0u32; 4]; + LittleEndian::read_u32_into(seed, &mut dwords[..]); + 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); + } +} diff --git a/vendor/proptest/src/test_runner/runner.rs b/vendor/proptest/src/test_runner/runner.rs new file mode 100644 index 000000000..ce540499e --- /dev/null +++ b/vendor/proptest/src/test_runner/runner.rs @@ -0,0 +1,1538 @@ +//- +// 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::{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; +const SHOW_FALURES: 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>, +{ + use std::time; + + 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); + } + + let time_start = time::Instant::now(); + + let mut result = unwrap_or!( + 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.) + 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, + SHOW_FALURES, + "Test case rejected: {}", + reason + ), + Err(TestCaseError::Fail(ref reason)) => verbose_message!( + runner, + SHOW_FALURES, + "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 { + 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> { + #[cfg(feature = "std")] + use std::time; + + let mut last_failure = None; + let mut iterations = 0; + #[cfg(feature = "std")] + let start_time = time::Instant::now(); + + if case.simplify() { + loop { + #[cfg(feature = "std")] + let timed_out = 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 { + Some(elapsed_ms) + } else { + None + } + } else { + None + }; + #[cfg(not(feature = "std"))] + let timed_out: Option<u64> = None; + + 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() { + break; + } + } + Err(TestCaseError::Fail(why)) => { + last_failure = Some(why); + if !case.simplify() { + 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); + } + } +} diff --git a/vendor/proptest/src/tuple.rs b/vendor/proptest/src/tuple.rs new file mode 100644 index 000000000..8230f59e4 --- /dev/null +++ b/vendor/proptest/src/tuple.rs @@ -0,0 +1,181 @@ +//- +// 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); + } +} diff --git a/vendor/proptest/test-persistence-location/README.md b/vendor/proptest/test-persistence-location/README.md new file mode 100644 index 000000000..173213fc1 --- /dev/null +++ b/vendor/proptest/test-persistence-location/README.md @@ -0,0 +1,6 @@ +This directory contains two independent cargo worspaces, 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. diff --git a/vendor/proptest/test-persistence-location/run-tests.bat b/vendor/proptest/test-persistence-location/run-tests.bat new file mode 100644 index 000000000..bb4f4891d --- /dev/null +++ b/vendor/proptest/test-persistence-location/run-tests.bat @@ -0,0 +1,23 @@ +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 diff --git a/vendor/proptest/test-persistence-location/run-tests.sh b/vendor/proptest/test-persistence-location/run-tests.sh new file mode 100755 index 000000000..a642055a6 --- /dev/null +++ b/vendor/proptest/test-persistence-location/run-tests.sh @@ -0,0 +1,28 @@ +#! /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 +) |