proptest-derive-0.4.0/.cargo_vcs_info.json0000644000000001550000000000100141720ustar { "git": { "sha1": "466d59daeca317f815bb8358e8d981bb9bd9431a" }, "path_in_vcs": "proptest-derive" }proptest-derive-0.4.0/CHANGELOG.md000064400000000000000000000012331046102023000145710ustar 00000000000000## Unreleased ### 0.4.0 ### Other Notes - Upgraded `syn`, `quote`, and `proc-macro2` to 1.0 ## 0.3.0 ### Breaking changes - The minimum supported Rust version has been increased to 1.50.0. ### Bug Fixes - Certain `enum`s could not be derived before, and now can be. - Structs with more than 10 fields can now be derived. ## 0.2.0 ### Breaking changes - Generated code now requires `proptest` 0.10.0. ## 0.1.2 ### Other Notes - Derived enums now use `LazyTupleUnion` instead of `TupleUnion` for better efficiency. ## 0.1.1 This is a minor release to correct a packaging error. The license files are now included in the files published to crates.io. proptest-derive-0.4.0/Cargo.toml0000644000000027430000000000100121750ustar # 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-derive" version = "0.4.0" authors = ["Mazdak Farrokhzad "] description = """ Custom-derive for the Arbitrary trait of proptest. """ homepage = "https://proptest-rs.github.io/proptest/proptest-derive/index.html" documentation = "https://proptest-rs.github.io/proptest/proptest-derive/index.html" readme = "README.md" keywords = [ "derive", "arbitrary", "proptest", "testing", "quickcheck", ] categories = ["development-tools::testing"] license = "MIT OR Apache-2.0" repository = "https://github.com/proptest-rs/proptest" [lib] proc-macro = true [[bench]] name = "large_enum" harness = false [dependencies.proc-macro2] version = "1.0" [dependencies.quote] version = "1.0" [dependencies.syn] version = "1.0.0" features = [ "visit", "extra-traits", "full", ] [dev-dependencies.compiletest_rs] version = "0.9" features = [ "tmp", "stable", ] [dev-dependencies.criterion] version = "0.5" [dev-dependencies.proptest] version = "1.0.0" proptest-derive-0.4.0/Cargo.toml.orig000064400000000000000000000023741046102023000156560ustar 00000000000000[package] name = "proptest-derive" version = "0.4.0" authors = ["Mazdak Farrokhzad "] license = "MIT OR Apache-2.0" readme = "README.md" repository = "https://github.com/proptest-rs/proptest" documentation = "https://proptest-rs.github.io/proptest/proptest-derive/index.html" keywords = ["derive", "arbitrary", "proptest", "testing", "quickcheck"] categories = ["development-tools::testing"] description = """ Custom-derive for the Arbitrary trait of proptest. """ homepage = "https://proptest-rs.github.io/proptest/proptest-derive/index.html" edition = "2018" [lib] proc-macro = true [dev-dependencies] proptest = { version = "1.0.0", path = "../proptest" } # We don't actually run the tests on stable since some of them use nightly # features. However, due to # https://github.com/laumann/compiletest-rs/issues/166, the default features of # compiletest-rs fail to compile, but the stable fallback works fine. compiletest_rs = { version = "0.9", features = ["tmp", "stable"] } # criterion is used for benchmarks. criterion = "0.5" [dependencies] proc-macro2 = "1.0" syn = { version = "1.0.0", features = ["visit", "extra-traits", "full"] } quote = "1.0" [[bench]] name = "large_enum" harness = false proptest-derive-0.4.0/LICENSE-APACHE000064400000000000000000000251371046102023000147150ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. proptest-derive-0.4.0/LICENSE-MIT000064400000000000000000000020441046102023000144150ustar 00000000000000Copyright (c) 2016 FullContact, Inc Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. proptest-derive-0.4.0/README.md000064400000000000000000000001461046102023000142410ustar 00000000000000# proptest-derive Custom-derive for the Arbitrary trait of proptest. This is currently experimental.proptest-derive-0.4.0/benches/large_enum.rs000064400000000000000000000030131046102023000170510ustar 00000000000000use criterion::{black_box, criterion_group, criterion_main, Criterion}; use proptest::{prelude::*, test_runner::TestRunner}; use proptest_derive::Arbitrary; #[derive(Arbitrary, Debug)] #[proptest(no_params)] enum LargeEnum1 { V1(String), V2(String), V3(String), V4(String), V5(String), V6(String), V7(String), V8(String), V9(String), V10(String), V11(String), V12(String), V13(String), V14(String), V15(String), V16(String), } #[derive(Arbitrary, Debug)] #[proptest(no_params)] enum LargeEnum2 { V1(LargeEnum1), V2(LargeEnum1), V3(LargeEnum1), V4(LargeEnum1), V5(LargeEnum1), V6(LargeEnum1), V7(LargeEnum1), V8(LargeEnum1), V9(LargeEnum1), V10(LargeEnum1), V11(LargeEnum1), V12(LargeEnum1), V13(LargeEnum1), V14(LargeEnum1), V15(LargeEnum1), V16(LargeEnum1), } fn enum1_bench(runner: &mut TestRunner) { let strategy = any::(); let _ = black_box(strategy.new_tree(runner)); } fn enum2_bench(runner: &mut TestRunner) { let strategy = any::(); let _ = black_box(strategy.new_tree(runner)); } fn enum_benchmark(c: &mut Criterion) { c.bench_function("enum 1", |b| { let mut runner = TestRunner::default(); b.iter(|| enum1_bench(&mut runner)) }); c.bench_function("enum 2", |b| { let mut runner = TestRunner::default(); b.iter(|| enum2_bench(&mut runner)) }); } criterion_group!(benches, enum_benchmark); criterion_main!(benches); proptest-derive-0.4.0/src/ast.rs000064400000000000000000000656641046102023000147260ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! High level IR and abstract syntax tree (AST) of impls. //! //! We compile to this AST and then linearise that to Rust code. use std::ops::{Add, AddAssign}; use proc_macro2::{Span, TokenStream}; use quote::{ToTokens, TokenStreamExt}; use syn; use syn::spanned::Spanned; use crate::error::{Ctx, DeriveResult}; use crate::use_tracking::UseTracker; use crate::util::self_ty; //============================================================================== // Config //============================================================================== /// The `MAX - 1` number of strategies that `TupleUnion` supports. /// Increase this if the behaviour is changed in `proptest`. /// Keeping this lower than what `proptest` supports will also work /// but for optimality this should follow what `proptest` supports. const UNION_CHUNK_SIZE: usize = 9; /// The `MAX - 1` tuple length `Arbitrary` is implemented for. After this number, /// tuples are expanded as nested tuples of up to `MAX` elements. The value should /// be kept in sync with the largest impl in `proptest/src/arbitrary/tuples.rs`. const NESTED_TUPLE_CHUNK_SIZE: usize = 9; /// The name of the top parameter variable name given in `arbitrary_with`. /// Changing this is not a breaking change because a user is expected not /// to rely on this (and the user shouldn't be able to..). const TOP_PARAM_NAME: &str = "_top"; /// The name of the variable name used for user facing parameter types /// specified in a `#[proptest(params = "")]` attribute. /// /// Changing the value of this constant constitutes a breaking change! const API_PARAM_NAME: &str = "params"; //============================================================================== // AST Root //============================================================================== /// Top level AST and everything required to implement `Arbitrary` for any /// given type. Linearizing this AST gives you the impl wrt. Rust code. pub struct Impl { /// Name of the type. typ: syn::Ident, /// Tracker for uses of Arbitrary trait for a generic type. tracker: UseTracker, /// The three main parts, see description of `ImplParts` for details. parts: ImplParts, } /// The three main parts to deriving `Arbitrary` for a type. /// That is: the associated items `Parameters` (`Params`), /// `Strategy` (`Strategy`) as well as the construction of the /// strategy itself (`Ctor`). pub type ImplParts = (Params, Strategy, Ctor); impl Impl { /// Constructs a new `Impl` from the parts as described on the type. pub fn new(typ: syn::Ident, tracker: UseTracker, parts: ImplParts) -> Self { Self { typ, tracker, parts, } } /// Linearises the impl into a sequence of tokens. /// This produces the actual Rust code for the impl. pub fn into_tokens(self, ctx: Ctx) -> DeriveResult { let Impl { typ, mut tracker, parts: (params, strategy, ctor), } = self; /// A `Debug` bound on a type variable. fn debug_bound() -> syn::TypeParamBound { parse_quote!(::std::fmt::Debug) } /// An `Arbitrary` bound on a type variable. fn arbitrary_bound() -> syn::TypeParamBound { parse_quote!(_proptest::arbitrary::Arbitrary) } // Add bounds and get generics for the impl. tracker.add_bounds(ctx, &arbitrary_bound(), Some(debug_bound()))?; let generics = tracker.consume(); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let _top = call_site_ident(TOP_PARAM_NAME); let _const = call_site_ident(&format!("_IMPL_ARBITRARY_FOR_{}", typ)); // Linearise everything. We're done after this. // // NOTE: The clippy::arc_with_non_send_sync lint is disabled here because the strategies // generated are often not Send or Sync, such as BoxedStrategy. // // The double-curly-braces are not strictly required, but allow the expression to be // annotated with an attribute. let q = quote! { #[allow(non_upper_case_globals)] #[allow(clippy::arc_with_non_send_sync)] const #_const: () = { extern crate proptest as _proptest; impl #impl_generics _proptest::arbitrary::Arbitrary for #typ #ty_generics #where_clause { type Parameters = #params; type Strategy = #strategy; fn arbitrary_with(#_top: Self::Parameters) -> Self::Strategy { #ctor } } }; }; Ok(q) } } //============================================================================== // Smart construcors, StratPair //============================================================================== /// A pair of `Strategy` and `Ctor`. These always come in pairs. pub type StratPair = (Strategy, Ctor); /// The type and constructor for `any::()`. pub fn pair_any(ty: syn::Type, span: Span) -> StratPair { let q = Ctor::Arbitrary(ty.clone(), None, span); (Strategy::Arbitrary(ty, span), q) } /// The type and constructor for `any_with::(parameters)`. pub fn pair_any_with(ty: syn::Type, var: usize, span: Span) -> StratPair { let q = Ctor::Arbitrary(ty.clone(), Some(var), span); (Strategy::Arbitrary(ty, span), q) } /// The type and constructor for a specific strategy value constructed by the /// given expression. Currently, the type is erased and a `BoxedStrategy` /// is given back instead. /// /// This is a temporary restriction. Once `impl Trait` is stabilized, /// the boxing and dynamic dispatch can be replaced with a statically /// dispatched anonymous type instead. pub fn pair_existential(ty: syn::Type, strat: syn::Expr) -> StratPair { (Strategy::Existential(ty), Ctor::Existential(strat)) } /// The type and constructor for a strategy that always returns the value /// provided in the expression `val`. /// This is statically dispatched since no erasure is needed or used. pub fn pair_value(ty: syn::Type, val: syn::Expr) -> StratPair { (Strategy::Value(ty), Ctor::Value(val)) } /// Same as `pair_existential` for the `Self` type. pub fn pair_existential_self(strat: syn::Expr) -> StratPair { pair_existential(self_ty(), strat) } /// Same as `pair_value` for the `Self` type. pub fn pair_value_self(val: syn::Expr) -> StratPair { pair_value(self_ty(), val) } /// Erased strategy for a fixed value. pub fn pair_value_exist(ty: syn::Type, strat: syn::Expr) -> StratPair { (Strategy::Existential(ty), Ctor::ValueExistential(strat)) } /// Erased strategy for a fixed value. pub fn pair_value_exist_self(strat: syn::Expr) -> StratPair { pair_value_exist(self_ty(), strat) } /// Same as `pair_value` but for a unit variant or unit struct. pub fn pair_unit_self(path: &syn::Path) -> StratPair { pair_value_self(parse_quote!( #path {} )) } /// The type and constructor for `#[proptest(regex(..))]`. pub fn pair_regex(ty: syn::Type, regex: syn::Expr) -> StratPair { (Strategy::Regex(ty.clone()), Ctor::Regex(ty, regex)) } /// Same as `pair_regex` for the `Self` type. pub fn pair_regex_self(regex: syn::Expr) -> StratPair { pair_regex(self_ty(), regex) } /// The type and constructor for .prop_map:ing a set of strategies /// into the type we are implementing for. The closure for the /// `.prop_map()` must also be given. pub fn pair_map( (strats, ctors): (Vec, Vec), closure: MapClosure, ) -> StratPair { ( Strategy::Map(strats.into()), Ctor::Map(ctors.into(), closure), ) } /// The type and constructor for a union of strategies which produces a new /// strategy that used the given strategies with probabilities based on the /// assigned relative weights for each strategy. pub fn pair_oneof( (strats, ctors): (Vec, Vec<(u32, Ctor)>), ) -> StratPair { (Strategy::Union(strats.into()), Ctor::Union(ctors.into())) } /// Potentially apply a filter to a strategy type and its constructor. pub fn pair_filter( filter: Vec, ty: syn::Type, pair: StratPair, ) -> StratPair { filter.into_iter().fold(pair, |(strat, ctor), filter| { ( Strategy::Filter(Box::new(strat), ty.clone()), Ctor::Filter(Box::new(ctor), filter), ) }) } //============================================================================== // Parameters //============================================================================== /// Represents the associated item of `Parameters` of an `Arbitrary` impl. pub struct Params(Vec); impl Params { /// Construct an `empty` list of parameters. /// This is equivalent to the unit type `()`. pub fn empty() -> Self { Params(Vec::new()) } /// Computes and returns the number of parameter types. pub fn len(&self) -> usize { self.0.len() } } impl From for syn::Type { fn from(x: Params) -> Self { let tys = x.0; parse_quote!( (#(#tys),*) ) } } impl Add for Params { type Output = Params; fn add(mut self, rhs: syn::Type) -> Self::Output { self.0.push(rhs); self } } impl AddAssign for Params { fn add_assign(&mut self, rhs: syn::Type) { self.0.push(rhs); } } impl ToTokens for Params { fn to_tokens(&self, tokens: &mut TokenStream) { NestedTuple(self.0.as_slice()).to_tokens(tokens) } } /// Returns for a given type `ty` the associated item `Parameters` of the /// type's `Arbitrary` implementation. pub fn arbitrary_param(ty: &syn::Type) -> syn::Type { parse_quote!(<#ty as _proptest::arbitrary::Arbitrary>::Parameters) } //============================================================================== // Strategy //============================================================================== /// The type of a given `Strategy`. pub enum Strategy { /// Assuming the metavariable `$ty` for a given type, this models the /// strategy type `<$ty as Arbitrary>::Strategy`. Arbitrary(syn::Type, Span), /// This models <$ty as StrategyFromRegex>::Strategy. Regex(syn::Type), /// Assuming the metavariable `$ty` for a given type, this models the /// strategy type `BoxedStrategy<$ty>`, i.e: an existentially typed strategy. /// /// The dynamic dispatch used here is an implementation detail that may be /// changed. Such a change does not count as a breakage semver wise. Existential(syn::Type), /// Assuming the metavariable `$ty` for a given type, this models a /// non-shrinking strategy that simply always returns a value of the /// given type. Value(syn::Type), /// Assuming a sequence of strategies, this models a mapping from that /// sequence to `Self`. Map(Box<[Strategy]>), /// Assuming a sequence of relative-weighted strategies, this models a /// weighted choice of those strategies. The resultant strategy will in /// other words randomly pick one strategy with probabilities based on the /// specified weights. Union(Box<[Strategy]>), /// A filtered strategy with `.prop_filter`. Filter(Box, syn::Type), } macro_rules! quote_append { ($tokens: expr, $($quasi: tt)*) => { $tokens.append_all(quote!($($quasi)*)) }; } impl Strategy { fn types(&self) -> Vec { use self::Strategy::*; match self { Arbitrary(ty, _) => vec![ty.clone()], Regex(ty) => vec![ty.clone()], Existential(ty) => vec![ty.clone()], Value(ty) => vec![ty.clone()], Map(strats) => strats.iter().flat_map(|s| s.types()).collect(), Union(strats) => strats.iter().flat_map(|s| s.types()).collect(), Filter(_, ty) => vec![ty.clone()], } } } impl ToTokens for Strategy { fn to_tokens(&self, tokens: &mut TokenStream) { // The logic of each of these are pretty straight forward save for // union which is described separately. use self::Strategy::*; match self { Arbitrary(ty, span) => tokens.append_all(quote_spanned!(*span=> <#ty as _proptest::arbitrary::Arbitrary>::Strategy )), Regex(ty) => quote_append!(tokens, <#ty as _proptest::string::StrategyFromRegex>::Strategy ), Existential(ty) => quote_append!(tokens, _proptest::strategy::BoxedStrategy<#ty> ), Value(ty) => quote_append!(tokens, fn() -> #ty ), Map(strats) => { let types = self.types(); let field_tys = NestedTuple(&types); let strats = NestedTuple(&strats); quote_append!(tokens, _proptest::strategy::Map< ( #strats ), fn( #field_tys ) -> Self > ) } Union(strats) => union_strat_to_tokens(tokens, strats), Filter(strat, ty) => quote_append!(tokens, _proptest::strategy::Filter<#strat, fn(&#ty) -> bool> ), } } } //============================================================================== // Constructor //============================================================================== /// The right hand side (RHS) of a let binding of parameters. pub enum FromReg { /// Denotes a move from the top parameter given in the arguments of /// `arbitrary_with`. Top, /// Denotes a move from a variable `params_` where `` is the given /// number. Num(usize), } /// The left hand side (LHS) of a let binding of parameters. pub enum ToReg { /// Denotes a move and declaration to a sequence of variables from /// `params_0` to `params_x`. Range(usize), /// Denotes a move and declaration of a special variable `params` that is /// user facing and is ALWAYS named `params`. /// /// To change the name this linearises to is considered a breaking change /// wrt. semver. API, } /// Models an expression that generates a proptest `Strategy`. pub enum Ctor { /// A strategy generated by using the `Arbitrary` impl for the given `Ty´. /// If `Some(idx)` is specified, then a parameter at `params_` is used /// and provided to `any_with::(params_)`. Arbitrary(syn::Type, Option, Span), /// A strategy that is generated by a mapping a regex in the form of a /// string slice to the actual regex. Regex(syn::Type, syn::Expr), /// An exact strategy value given by the expression. Existential(syn::Expr), /// A strategy that always produces the given expression. Value(syn::Expr), /// A strategy that always produces the given expression but which is erased. ValueExistential(syn::Expr), /// A strategy that maps from a sequence of strategies into `Self`. Map(Box<[Ctor]>, MapClosure), /// A strategy that randomly selects one of the given relative-weighted /// strategies. Union(Box<[(u32, Ctor)]>), /// A let binding that moves to and declares the `ToReg` from the `FromReg` /// as well as the strategy that uses the `ToReg`. Extract(Box, ToReg, FromReg), /// A filtered strategy with `.prop_filter`. Filter(Box, syn::Expr), } /// Wraps the given strategy producing expression with a move into /// `params_` from `FromReg`. This is used when the given `c` expects /// `params_` to be there. pub fn extract_all(c: Ctor, to: usize, from: FromReg) -> Ctor { extract(c, ToReg::Range(to), from) } /// Wraps the given strategy producing expression with a move into `params` /// (literally named like that) from `FromReg`. This is used when the given /// `c` expects `params` to be there. pub fn extract_api(c: Ctor, from: FromReg) -> Ctor { extract(c, ToReg::API, from) } impl ToTokens for FromReg { fn to_tokens(&self, tokens: &mut TokenStream) { match self { FromReg::Top => call_site_ident(TOP_PARAM_NAME).to_tokens(tokens), FromReg::Num(reg) => param(*reg).to_tokens(tokens), } } } impl ToTokens for ToReg { fn to_tokens(&self, tokens: &mut TokenStream) { match *self { ToReg::Range(to) if to == 1 => param(0).to_tokens(tokens), ToReg::Range(to) => { let params: Vec<_> = (0..to).map(param).collect(); NestedTuple(¶ms).to_tokens(tokens) } ToReg::API => call_site_ident(API_PARAM_NAME).to_tokens(tokens), } } } impl ToTokens for Ctor { fn to_tokens(&self, tokens: &mut TokenStream) { // The logic of each of these are pretty straight forward save for // union which is described separately. use self::Ctor::*; match self { Filter(ctor, filter) => quote_append!(tokens, _proptest::strategy::Strategy::prop_filter( #ctor, stringify!(#filter), #filter) ), Extract(ctor, to, from) => quote_append!(tokens, { let #to = #from; #ctor }), Arbitrary(ty, fv, span) => { tokens.append_all(if let Some(fv) = fv { let args = param(*fv); quote_spanned!(*span=> _proptest::arbitrary::any_with::<#ty>(#args) ) } else { quote_spanned!(*span=> _proptest::arbitrary::any::<#ty>() ) }) } Regex(ty, regex) => quote_append!(tokens, <#ty as _proptest::string::StrategyFromRegex>::from_regex(#regex) ), Existential(expr) => quote_append!(tokens, _proptest::strategy::Strategy::boxed( #expr ) ), Value(expr) => quote_append!(tokens, || #expr ), ValueExistential(expr) => quote_append!(tokens, _proptest::strategy::Strategy::boxed( _proptest::strategy::LazyJust::new(move || #expr) ) ), Map(ctors, closure) => map_ctor_to_tokens(tokens, &ctors, closure), Union(ctors) => union_ctor_to_tokens(tokens, ctors), } } } struct NestedTuple<'a, T>(&'a [T]); impl<'a, T: ToTokens> ToTokens for NestedTuple<'a, T> { fn to_tokens(&self, tokens: &mut TokenStream) { let NestedTuple(elems) = self; if elems.is_empty() { quote_append!(tokens, ()); } else if let [x] = elems { x.to_tokens(tokens); } else { let chunks = elems.chunks(NESTED_TUPLE_CHUNK_SIZE); Recurse(&chunks).to_tokens(tokens); } struct Recurse<'a, T: ToTokens>(&'a ::std::slice::Chunks<'a, T>); impl<'a, T: ToTokens> ToTokens for Recurse<'a, T> { fn to_tokens(&self, tokens: &mut TokenStream) { let mut chunks = self.0.clone(); if let Some(head) = chunks.next() { if let [c] = head { // Only one element left - no need to nest. quote_append!(tokens, #c); } else { let tail = Recurse(&chunks); quote_append!(tokens, (#(#head,)* #tail)); } } } } } } fn map_ctor_to_tokens( tokens: &mut TokenStream, ctors: &[Ctor], closure: &MapClosure, ) { let ctors = NestedTuple(ctors); quote_append!(tokens, _proptest::strategy::Strategy::prop_map( #ctors, #closure ) ); } /// Tokenizes a weighted list of `Ctor`. /// /// The logic is that the output should be as linear as possible while still /// supporting enums with an unbounded number of variants without any boxing /// (erasure) or dynamic dispatch. /// /// As `TupleUnion` is (currently) limited to 10 summands in the coproduct /// we can't just emit the entire thing linearly as this will fail on the 11:th /// variant. /// /// A naive approach to solve might be to simply use a cons-list like so: /// /// ```ignore /// TupleUnion::new( /// (w_1, s_1), /// (w_2 + w_3 + w_4 + w_5, /// TupleUnion::new( /// (w_2, s_2), /// (w_3 + w_4 + w_5, /// TupleUnion::new( /// (w_3, s_3), /// (w_4 + w_5, /// TupleUnion::new( /// (w_4, s_4), /// (w_5, s_5), /// )) /// )) /// )) /// ) /// ``` /// /// However, we can do better by being linear for the `10 - 1` first /// strategies and then switch to nesting like so: /// /// ```ignore /// (1, 2, 3, 4, 5, 6, 7, 8, 9, /// (10, 11, 12, 13, 14, 15, 16, 17, 18, /// (19, ..))) /// ``` fn union_ctor_to_tokens(tokens: &mut TokenStream, ctors: &[(u32, Ctor)]) { if ctors.is_empty() { return; } if let [(_, ctor)] = ctors { // This is not a union at all - user provided an enum with one variant. ctor.to_tokens(tokens); return; } let mut chunks = ctors.chunks(UNION_CHUNK_SIZE); let chunk = chunks.next().unwrap(); let head = chunk.iter().map(wrap_arc); let tail = Recurse(weight_sum(ctors) - weight_sum(chunk), chunks); quote_append!(tokens, _proptest::strategy::TupleUnion::new(( #(#head,)* #tail )) ); struct Recurse<'a>(u32, ::std::slice::Chunks<'a, (u32, Ctor)>); impl<'a> ToTokens for Recurse<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { let (tweight, mut chunks) = (self.0, self.1.clone()); if let Some(chunk) = chunks.next() { if let [(w, c)] = chunk { // Only one element left - no need to nest. quote_append!(tokens, (#w, ::std::sync::Arc::new(#c)) ); } else { let head = chunk.iter().map(wrap_arc); let tail = Recurse(tweight - weight_sum(chunk), chunks); quote_append!(tokens, (#tweight, ::std::sync::Arc::new( _proptest::strategy::TupleUnion::new(( #(#head,)* #tail )))) ); } } } } fn weight_sum(ctors: &[(u32, Ctor)]) -> u32 { use std::num::Wrapping; let Wrapping(x) = ctors.iter().map(|&(w, _)| Wrapping(w)).sum(); x } fn wrap_arc(arg: &(u32, Ctor)) -> TokenStream { let (w, c) = arg; quote!( (#w, ::std::sync::Arc::new(#c)) ) } } /// Tokenizes a weighted list of `Strategy`. /// For details, see `union_ctor_to_tokens`. fn union_strat_to_tokens(tokens: &mut TokenStream, strats: &[Strategy]) { if strats.is_empty() { return; } if let [strat] = strats { // This is not a union at all - user provided an enum with one variant. strat.to_tokens(tokens); return; } let mut chunks = strats.chunks(UNION_CHUNK_SIZE); let chunk = chunks.next().unwrap(); let head = chunk.iter().map(wrap_arc); let tail = Recurse(chunks); quote_append!(tokens, _proptest::strategy::TupleUnion<( #(#head,)* #tail )> ); struct Recurse<'a>(::std::slice::Chunks<'a, Strategy>); impl<'a> ToTokens for Recurse<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { let mut chunks = self.0.clone(); if let Some(chunk) = chunks.next() { if let [s] = chunk { // Only one element left - no need to nest. quote_append!(tokens, (u32, ::std::sync::Arc<#s>) ); } else { let head = chunk.iter().map(wrap_arc); let tail = Recurse(chunks); quote_append!(tokens, (u32, ::std::sync::Arc<_proptest::strategy::TupleUnion<( #(#head,)* #tail )>>) ); } } } } fn wrap_arc(s: &Strategy) -> TokenStream { quote!( (u32, ::std::sync::Arc<#s>) ) } } /// Wraps a `Ctor` that expects the `to` "register" to be filled with /// contents of the `from` register. The correctness of this wrt. the /// generated Rust code has to be verified externally by checking the /// construction of the particular `Ctor`. fn extract(c: Ctor, to: ToReg, from: FromReg) -> Ctor { Ctor::Extract(Box::new(c), to, from) } /// Construct a `FreshVar` prefixed by `param_`. fn param<'a>(fv: usize) -> FreshVar<'a> { fresh_var("param", fv) } //============================================================================== // MapClosure //============================================================================== /// Constructs a `MapClosure` for the given `path` and a list of fields. pub fn map_closure(path: syn::Path, fs: &[syn::Field]) -> MapClosure { MapClosure(path, fs.to_owned()) } /// A `MapClosure` models the closure part inside a `.prop_map(..)` call. #[derive(Debug)] pub struct MapClosure(syn::Path, Vec); impl ToTokens for MapClosure { fn to_tokens(&self, tokens: &mut TokenStream) { fn tmp_var<'a>(idx: usize) -> FreshVar<'a> { fresh_var("tmp", idx) } let MapClosure(path, fields) = self; let count = fields.len(); let tmps: Vec<_> = (0..count).map(tmp_var).collect(); let inits = fields.iter().enumerate().map(|(idx, field)| { let tv = tmp_var(idx); if let Some(name) = &field.ident { quote_spanned!(field.span()=> #name: #tv ) } else { let name = syn::Member::Unnamed(syn::Index::from(idx)); quote_spanned!(field.span()=> #name: #tv ) } }); let tmps = NestedTuple(&tmps); quote_append!(tokens, | #tmps | #path { #(#inits),* } ); } } //============================================================================== // FreshVar //============================================================================== /// Construct a `FreshVar` with the given `prefix` and the number it has in the /// count of temporaries for that prefix. fn fresh_var(prefix: &str, count: usize) -> FreshVar { FreshVar { prefix, count } } /// A `FreshVar` is an internal implementation detail and models a temporary /// variable on the stack. struct FreshVar<'a> { prefix: &'a str, count: usize, } impl<'a> ToTokens for FreshVar<'a> { fn to_tokens(&self, tokens: &mut TokenStream) { let ident = format!("{}_{}", self.prefix, self.count); call_site_ident(&ident).to_tokens(tokens) } } fn call_site_ident(ident: &str) -> syn::Ident { syn::Ident::new(ident, Span::call_site()) } proptest-derive-0.4.0/src/attr.rs000064400000000000000000000513221046102023000150730ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Provides a parser from syn attributes to our logical model. use quote::ToTokens; use syn::{self, Attribute, Expr, Ident, Lit, Meta, NestedMeta, Type}; use crate::error::{self, Ctx, DeriveResult}; use crate::interp; use crate::util; //============================================================================== // Public API //============================================================================== /// Parsed attributes in our logical model. #[derive(Clone)] pub struct ParsedAttributes { /// If we've been ordered to skip this item. /// This is only valid for enum variants. pub skip: bool, /// The potential weight assigned to an enum variant. /// This must be `None` for things that are not enum variants. pub weight: Option, /// The mode for `Parameters` to use. See that type for more. pub params: ParamsMode, /// The mode for `Strategy` to use. See that type for more. pub strategy: StratMode, /// Filter expressions if any. pub filter: Vec, /// True if no_bound was specified. pub no_bound: bool, } /// The mode for the associated item `Strategy` to use. #[derive(Clone)] pub enum StratMode { /// This means that no explicit strategy was specified /// and that we thus should use `Arbitrary` for whatever /// it is that needs a strategy. Arbitrary, /// This means that an explicit value has been provided. /// The result of this is to use a strategy that always /// returns the given value. Value(Expr), /// This means that an explicit strategy has been provided. /// This strategy will be used to generate whatever it /// is that the attribute was set on. Strategy(Expr), /// This means that an explicit *regex* strategy has been provided. /// We don't reuse `Strategy(..)` so that we can produce better and /// more tailored error messages. Regex(Expr), } /// The mode for the associated item `Parameters` to use. #[derive(Clone)] pub enum ParamsMode { /// Nothing has been specified. The children are now free to /// specify their parameters, and if nothing is specified, then /// `::Parameters` will be used for a type `X`. Passthrough, /// We've been ordered to use the Default value of /// `::Parameters` for some field where applicable. /// For the top level item, this means that `Parameters` will be /// the unit type. For children, it means that this child should /// not count towards the product type that is being built up. Default, /// An explicit type has been specified on some item. /// If the top level item has this specified on it, this means /// that `Parameters` will have the given type. /// If it is specified on a child of the top level item, this /// entails that the given type will be added to the resultant /// product type. Specified(Type), } impl ParamsMode { /// Returns `true` iff the mode was explicitly set. pub fn is_set(&self) -> bool { if let ParamsMode::Passthrough = *self { false } else { true } } /// Converts the mode to an `Option` of an `Option` of a type /// where the outer `Option` is `None` iff the mode wasn't set /// and the inner `Option` is `None` iff the mode was `Default`. pub fn into_option(self) -> Option> { use self::ParamsMode::*; match self { Passthrough => None, Specified(ty) => Some(Some(ty)), Default => Some(None), } } } impl StratMode { /// Returns `true` iff the mode was explicitly set. pub fn is_set(&self) -> bool { if let StratMode::Arbitrary = self { false } else { true } } } /// Parse the attributes specified on an item and parsed by syn /// into our logical model that we work with. pub fn parse_attributes( ctx: Ctx, attrs: &[Attribute], ) -> DeriveResult { let attrs = parse_attributes_base(ctx, attrs)?; if attrs.no_bound { error::no_bound_set_on_non_tyvar(ctx); } Ok(attrs) } /// Parse the attributes specified on a type definition... pub fn parse_top_attributes( ctx: Ctx, attrs: &[Attribute], ) -> DeriveResult { parse_attributes_base(ctx, attrs) } /// Parses the attributes specified on an item and parsed by syn /// and returns true if we've been ordered to not set an `Arbitrary` /// bound on the given type variable the attributes are from, /// no matter what. pub fn has_no_bound(ctx: Ctx, attrs: &[Attribute]) -> DeriveResult { let attrs = parse_attributes_base(ctx, attrs)?; error::if_anything_specified(ctx, &attrs, error::TY_VAR); Ok(attrs.no_bound) } /// Parse the attributes specified on an item and parsed by syn /// into our logical model that we work with. fn parse_attributes_base( ctx: Ctx, attrs: &[Attribute], ) -> DeriveResult { let acc = parse_accumulate(ctx, attrs); Ok(ParsedAttributes { skip: acc.skip.is_some(), weight: acc.weight, filter: acc.filter, // Process params and no_params together to see which one to use. params: parse_params_mode(ctx, acc.no_params, acc.params)?, // Process strategy and value together to see which one to use. strategy: parse_strat_mode(ctx, acc.strategy, acc.value, acc.regex)?, no_bound: acc.no_bound.is_some(), }) } //============================================================================== // Internals: Initialization //============================================================================== /// The internal state of the attribute parser. #[derive(Default)] struct ParseAcc { skip: Option<()>, weight: Option, no_params: Option<()>, params: Option, strategy: Option, value: Option, regex: Option, filter: Vec, no_bound: Option<()>, } //============================================================================== // Internals: Extraction & Filtering //============================================================================== fn parse_accumulate(ctx: Ctx, attrs: &[Attribute]) -> ParseAcc { let mut state = ParseAcc::default(); // Get rid of attributes we don't care about: for attr in attrs { if is_proptest_attr(&attr) { // Flatten attributes so we deal with them uniformly. state = extract_modifiers(ctx, &attr) .into_iter() // Accumulate attributes into a form for final processing. .fold(state, |state, meta| dispatch_attribute(ctx, state, meta)) } } state } /// Returns `true` iff the attribute has to do with proptest. /// Otherwise, the attribute is irrevant to us and we will simply /// ignore it in our processing. fn is_proptest_attr(attr: &Attribute) -> bool { util::eq_simple_path("proptest", &attr.path) } /// Extract all individual attributes inside one `#[proptest(..)]`. /// We do this to treat all pieces uniformly whether a single /// `#[proptest(..)]` was used or many. This simplifies the /// logic somewhat. fn extract_modifiers(ctx: Ctx, attr: &Attribute) -> Vec { // Ensure we've been given an outer attribute form. if !is_outer_attr(&attr) { error::inner_attr(ctx); } match attr.parse_meta().ok() { Some(Meta::List(list)) => { return list .nested .into_iter() .filter_map(|nm| extract_metas(ctx, nm)) .collect() } Some(Meta::Path(_)) => error::bare_proptest_attr(ctx), Some(Meta::NameValue(_)) => error::literal_set_proptest(ctx), None => error::no_interp_meta(ctx), } vec![] } fn extract_metas(ctx: Ctx, nested: NestedMeta) -> Option { match nested { NestedMeta::Lit(_) => { error::immediate_literals(ctx); None } // This is the only valid form. NestedMeta::Meta(meta) => Some(meta), } } /// Returns true iff the given attribute is an outer one, i.e: `#[]`. /// An inner attribute is the other possibility and has the syntax `#![]`. /// Note that `` is a meta-variable for the contents inside. fn is_outer_attr(attr: &Attribute) -> bool { syn::AttrStyle::Outer == attr.style } //============================================================================== // Internals: Dispatch //============================================================================== /// Dispatches an attribute modifier to handlers and /// let's them add stuff into our accumulartor. fn dispatch_attribute(ctx: Ctx, mut acc: ParseAcc, meta: Meta) -> ParseAcc { // Dispatch table for attributes: let path = meta.path(); if let Some(name) = path.get_ident().map(ToString::to_string) { match name.as_ref() { // Valid modifiers: "skip" => parse_skip(ctx, &mut acc, meta), "w" | "weight" => parse_weight(ctx, &mut acc, &meta), "no_params" => parse_no_params(ctx, &mut acc, meta), "params" => parse_params(ctx, &mut acc, meta), "strategy" => parse_strategy(ctx, &mut acc, &meta), "value" => parse_value(ctx, &mut acc, &meta), "regex" => parse_regex(ctx, &mut acc, &meta), "filter" => parse_filter(ctx, &mut acc, &meta), "no_bound" => parse_no_bound(ctx, &mut acc, meta), // Invalid modifiers: name => dispatch_unknown_mod(ctx, name), } } else { // Occurs when passed path is something other than a single ident error::unkown_modifier(ctx, &path.into_token_stream().to_string()); } acc } fn dispatch_unknown_mod(ctx: Ctx, name: &str) { match name { "no_bounds" => error::did_you_mean(ctx, name, "no_bound"), "weights" | "weighted" => error::did_you_mean(ctx, name, "weight"), "strat" | "strategies" => error::did_you_mean(ctx, name, "strategy"), "values" | "valued" | "fix" | "fixed" => { error::did_you_mean(ctx, name, "value") } "regexes" | "regexp" | "re" => error::did_you_mean(ctx, name, "regex"), "param" | "parameters" => error::did_you_mean(ctx, name, "params"), "no_param" | "no_parameters" => { error::did_you_mean(ctx, name, "no_params") } name => error::unkown_modifier(ctx, name), // TODO: consider levenshtein distance. } } //============================================================================== // Internals: no_bound //============================================================================== /// Parse a no_bound attribute. /// Valid forms are: /// + `#[proptest(no_bound)]` fn parse_no_bound(ctx: Ctx, acc: &mut ParseAcc, meta: Meta) { parse_bare_modifier(ctx, &mut acc.no_bound, meta, error::no_bound_malformed) } //============================================================================== // Internals: Skip //============================================================================== /// Parse a skip attribute. /// Valid forms are: /// + `#[proptest(skip)]` fn parse_skip(ctx: Ctx, acc: &mut ParseAcc, meta: Meta) { parse_bare_modifier(ctx, &mut acc.skip, meta, error::skip_malformed) } //============================================================================== // Internals: Weight //============================================================================== /// Parses a weight. /// Valid forms are: /// + `#[proptest(weight = )]` /// + `#[proptest(weight = "")]` /// + `#[proptest(weight())]` /// + `#[proptest(weight("""))]` /// /// The `` must also fit within an `u32` and be unsigned. fn parse_weight(ctx: Ctx, acc: &mut ParseAcc, meta: &Meta) { use std::u32; error_if_set(ctx, &acc.weight, &meta); // Convert to value if possible: let value = normalize_meta(meta.clone()) .and_then(extract_lit) .and_then(extract_expr) // Evaluate the expression into a value: .as_ref() .and_then(interp::eval_expr) // Ensure that `val` fits within an `u32` as proptest requires that: .filter(|&value| value <= u128::from(u32::MAX)) .map(|value| value as u32); if let v @ Some(_) = value { acc.weight = v; } else { error::weight_malformed(ctx, meta) } } //============================================================================== // Internals: Filter //============================================================================== /// Parses an explicit value as a strategy. /// Valid forms are: /// + `#[proptest(filter())]` /// + `#[proptest(filter = "")]` /// + `#[proptest(filter("")]` fn parse_filter(ctx: Ctx, acc: &mut ParseAcc, meta: &Meta) { if let Some(filter) = match normalize_meta(meta.clone()) { Some(NormMeta::Lit(Lit::Str(lit))) => lit.parse().ok(), Some(NormMeta::Word(ident)) => Some(parse_quote!( #ident )), _ => None, } { acc.filter.push(filter); } else { error::filter_malformed(ctx, meta) } } //============================================================================== // Internals: Strategy //============================================================================== /// Parses an explicit value as a strategy. /// Valid forms are: /// + `#[proptest(regex = "")]` /// + `#[proptest(regex("")]` /// + `#[proptest(regex()]` fn parse_regex(ctx: Ctx, acc: &mut ParseAcc, meta: &Meta) { error_if_set(ctx, &acc.regex, &meta); if let expr @ Some(_) = match normalize_meta(meta.clone()) { Some(NormMeta::Word(fun)) => Some(function_call(fun)), Some(NormMeta::Lit(lit @ Lit::Str(_))) => Some(lit_to_expr(lit)), _ => None, } { acc.regex = expr; } else { error::regex_malformed(ctx) } } /// Parses an explicit value as a strategy. /// Valid forms are: /// + `#[proptest(value = )]` /// + `#[proptest(value = "")]` /// + `#[proptest(value("")]` /// + `#[proptest(value()]` /// + `#[proptest(value()]` fn parse_value(ctx: Ctx, acc: &mut ParseAcc, meta: &Meta) { parse_strategy_base(ctx, &mut acc.value, meta) } /// Parses an explicit strategy. /// Valid forms are: /// + `#[proptest(strategy = )]` /// + `#[proptest(strategy = "")]` /// + `#[proptest(strategy("")]` /// + `#[proptest(strategy()]` /// + `#[proptest(strategy()]` fn parse_strategy(ctx: Ctx, acc: &mut ParseAcc, meta: &Meta) { parse_strategy_base(ctx, &mut acc.strategy, meta) } /// Parses an explicit strategy. This is a helper. /// Valid forms are: /// + `#[proptest( = )]` /// + `#[proptest( = "")]` /// + `#[proptest(("")]` /// + `#[proptest(()]` /// + `#[proptest(()]` fn parse_strategy_base(ctx: Ctx, loc: &mut Option, meta: &Meta) { error_if_set(ctx, &loc, &meta); if let expr @ Some(_) = match normalize_meta(meta.clone()) { Some(NormMeta::Word(fun)) => Some(function_call(fun)), Some(NormMeta::Lit(lit)) => extract_expr(lit), _ => None, } { *loc = expr; } else { error::strategy_malformed(ctx, meta) } } /// Combines any parsed explicit strategy, value, and regex into a single /// value and fails if both an explicit strategy / value / regex was set. /// Only one of them can be set, or none. fn parse_strat_mode( ctx: Ctx, strat: Option, value: Option, regex: Option, ) -> DeriveResult { Ok(match (strat, value, regex) { (None, None, None) => StratMode::Arbitrary, (None, None, Some(re)) => StratMode::Regex(re), (None, Some(vl), None) => StratMode::Value(vl), (Some(st), None, None) => StratMode::Strategy(st), _ => error::overspecified_strat(ctx)?, }) } //============================================================================== // Internals: Parameters //============================================================================== /// Combines a potentially set `params` and `no_params` into a single value /// and fails if both have been set. Only one of them can be set, or none. fn parse_params_mode( ctx: Ctx, no_params: Option<()>, ty_params: Option, ) -> DeriveResult { Ok(match (no_params, ty_params) { (None, None) => ParamsMode::Passthrough, (None, Some(ty)) => ParamsMode::Specified(ty), (Some(_), None) => ParamsMode::Default, (Some(_), Some(_)) => error::overspecified_param(ctx)?, }) } /// Parses an explicit Parameters type. /// /// Valid forms are: /// + `#[proptest(params()]` /// + `#[proptest(params("")]` /// + `#[proptest(params = ""]` /// /// The latter form is required for more complex types. fn parse_params(ctx: Ctx, acc: &mut ParseAcc, meta: Meta) { error_if_set(ctx, &acc.params, &meta); let typ = match normalize_meta(meta) { // Form is: `#[proptest(params()]`. Some(NormMeta::Word(ident)) => Some(ident_to_type(ident)), // Form is: `#[proptest(params = ""]` or, // Form is: `#[proptest(params("")]`.. Some(NormMeta::Lit(Lit::Str(lit))) => lit.parse().ok(), _ => None, }; if let typ @ Some(_) = typ { acc.params = typ; } else { error::param_malformed(ctx) } } /// Parses an order to use the default Parameters type and value. /// Valid forms are: /// + `#[proptest(no_params)]` fn parse_no_params(ctx: Ctx, acc: &mut ParseAcc, meta: Meta) { parse_bare_modifier( ctx, &mut acc.no_params, meta, error::no_params_malformed, ) } //============================================================================== // Internals: Utilities //============================================================================== /// Parses a bare attribute of the form `#[proptest()]` and sets `loc`. fn parse_bare_modifier( ctx: Ctx, loc: &mut Option<()>, meta: Meta, malformed: fn(Ctx), ) { error_if_set(ctx, loc, &meta); if let Some(NormMeta::Plain) = normalize_meta(meta) { *loc = Some(()); } else { malformed(ctx); } } /// Emits a "set again" error iff the given option `.is_some()`. fn error_if_set(ctx: Ctx, loc: &Option, meta: &Meta) { if loc.is_some() { error::set_again(ctx, meta) } } /// Constructs a type out of an identifier. fn ident_to_type(ident: Ident) -> Type { Type::Path(syn::TypePath { qself: None, path: ident.into(), }) } /// Extract a `lit` in `NormMeta::Lit()`. fn extract_lit(meta: NormMeta) -> Option { if let NormMeta::Lit(lit) = meta { Some(lit) } else { None } } /// Extract expression out of literal if possible. fn extract_expr(lit: Lit) -> Option { match lit { Lit::Str(lit) => lit.parse().ok(), lit @ Lit::Int(_) => Some(lit_to_expr(lit)), // TODO(centril): generalize to other literals, e.g. floats _ => None, } } /// Construct an expression from a literal. fn lit_to_expr(lit: Lit) -> Expr { syn::ExprLit { attrs: vec![], lit }.into() } /// Construct a function call expression for an identifier. fn function_call(fun: Ident) -> Expr { parse_quote!( #fun() ) } /// Normalized `Meta` into all the forms we will possibly accept. #[derive(Debug)] enum NormMeta { /// Accepts: `#[proptest()]` Plain, /// Accepts: `#[proptest( = )]` and `#[proptest(())]` Lit(Lit), /// Accepts: `#[proptest(())`. Word(Ident), } /// Normalize a `meta: Meta` into the forms accepted in `#[proptest()]`. fn normalize_meta(meta: Meta) -> Option { Some(match meta { Meta::Path(_) => NormMeta::Plain, Meta::NameValue(nv) => NormMeta::Lit(nv.lit), Meta::List(ml) => { if let Some(nm) = util::match_singleton(ml.nested) { match nm { NestedMeta::Lit(lit) => NormMeta::Lit(lit), NestedMeta::Meta(Meta::Path(path)) => { match path.get_ident() { Some(word) => NormMeta::Word(word.to_owned()), None => return None, } } _ => return None, } } else { return None; } } }) } proptest-derive-0.4.0/src/derive.rs000064400000000000000000000711051046102023000154000ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Provides actual deriving logic for the crate. use proc_macro2::{Span, TokenStream}; use syn::spanned::Spanned; use syn::{DeriveInput, Expr, Field, Ident, Path, Type, Variant}; use crate::ast::*; use crate::attr::{self, ParamsMode, ParsedAttributes, StratMode}; use crate::error::{self, Context, Ctx, DeriveResult}; use crate::use_tracking::{UseMarkable, UseTracker}; use crate::util::{fields_to_vec, is_unit_type, self_ty}; use crate::void::IsUninhabited; //============================================================================== // API //============================================================================== pub fn impl_proptest_arbitrary(ast: DeriveInput) -> TokenStream { let mut ctx = Context::default(); let result = derive_proptest_arbitrary(&mut ctx, ast); match (result, ctx.check()) { (Ok(derive), Ok(())) => derive, (_, Err(err)) => err, (Err(result), Ok(())) => panic!( "[proptest_derive]: internal error, this is a bug! \ result: {:?}", result ), } } /// Simplified version of `DeriveInput` from syn letting us be generic over /// the body. struct DeriveData { ident: Ident, attrs: ParsedAttributes, tracker: UseTracker, body: B, } /// Entry point for deriving `Arbitrary`. fn derive_proptest_arbitrary( ctx: Ctx, ast: DeriveInput, ) -> DeriveResult { use syn::Data::*; // Deny lifetimes on type. error::if_has_lifetimes(ctx, &ast); // Parse top level attributes: let attrs = attr::parse_top_attributes(ctx, &ast.attrs)?; // Initialize tracker: let mut tracker = UseTracker::new(ast.generics); if attrs.no_bound { tracker.no_track(); } // Compile into our own high level IR for the impl: let the_impl = match ast.data { // Deal with structs: Struct(data) => derive_struct( ctx, DeriveData { tracker, attrs, ident: ast.ident, body: fields_to_vec(data.fields), }, ), // Deal with enums: Enum(data) => derive_enum( ctx, DeriveData { tracker, attrs, ident: ast.ident, body: data.variants.into_iter().collect(), }, ), // Unions are not supported: _ => error::not_struct_or_enum(ctx)?, }?; // Linearise the IR into Rust code: let q = the_impl.into_tokens(ctx)?; // We're done! Ok(q) } //============================================================================== // Struct //============================================================================== /// Entry point for deriving `Arbitrary` for `struct`s. fn derive_struct( ctx: Ctx, mut ast: DeriveData>, ) -> DeriveResult { // Deny attributes that are only for enum variants: error::if_enum_attrs_present(ctx, &ast.attrs, error::STRUCT); // Deny an explicit strategy directly on the struct. error::if_strategy_present(ctx, &ast.attrs, error::STRUCT); let v_path = ast.ident.clone().into(); let parts = if ast.body.is_empty() { // Deriving for a unit struct. error::if_present_on_unit_struct(ctx, &ast.attrs); let (strat, ctor) = pair_unit_self(&v_path); (Params::empty(), strat, ctor) } else { // Not a unit struct. // Ensures that the fields of the given struct has fields which are all // inhabited. If one field is uninhabited, the entire product type is // uninhabited. // // A unit struct in the other branch is by definition always inhabited. if (&*ast.body).is_uninhabited() { error::uninhabited_struct(ctx); } // Construct the closure for `.prop_map`: let closure = map_closure(v_path, &ast.body); // The complexity of the logic depends mostly now on whether // parameters were set directly on the type or not. let parts = if let Some(param_ty) = ast.attrs.params.into_option() { // Parameters was set on the struct itself, the logic is simpler. add_top_params( param_ty, derive_product_has_params( ctx, &mut ast.tracker, error::STRUCT_FIELD, closure, ast.body, )?, ) } else { // We need considerably more complex logic. derive_product_no_params( ctx, &mut ast.tracker, ast.body, error::STRUCT_FIELD, )? .finish(closure) }; // Possibly apply filter: add_top_filter(ast.attrs.filter, parts) }; // We're done! Ok(Impl::new(ast.ident, ast.tracker, parts)) } /// Apply the filter at the top level if provided. fn add_top_filter(filter: Vec, parts: ImplParts) -> ImplParts { let (params, strat, ctor) = parts; let (strat, ctor) = add_filter_self(filter, (strat, ctor)); (params, strat, ctor) } /// Apply a filter with `Self` as the input type to the predicate. fn add_filter_self(filter: Vec, pair: StratPair) -> StratPair { pair_filter(filter, self_ty(), pair) } /// Determine the `Parameters` part. We've already handled everything else. /// After this, we have all parts needed for an impl. If `None` is given, /// then the unit type `()` will be used for `Parameters`. fn add_top_params( param_ty: Option, (strat, ctor): StratPair, ) -> ImplParts { let params = Params::empty(); if let Some(params_ty) = param_ty { // We need to add `let params = _top;`. (params + params_ty, strat, extract_api(ctor, FromReg::Top)) } else { (params, strat, ctor) } } /// Deriving for a list of fields (product type) on /// which `params` or `no_params` was set directly. fn derive_product_has_params( ctx: Ctx, ut: &mut UseTracker, item: &str, closure: MapClosure, fields: Vec, ) -> DeriveResult { // Fold into an accumulator of the strategy types and the expressions // that produces the strategy. Finally turn the accumulator into // a `.prop_map(..)` that produces the composite strategy. let len = fields.len(); fields .into_iter() .try_fold(StratAcc::new(len), |acc, field| { let attrs = attr::parse_attributes(ctx, &field.attrs)?; // Deny attributes that are only for enum variants: error::if_enum_attrs_present(ctx, &attrs, item); // Deny setting parameters on the field since it has been set on parent: error::if_specified_params(ctx, &attrs, item); // Determine the strategy for this field and add it to acc. let span = field.span(); let ty = field.ty.clone(); let pair = product_handle_default_params(ut, ty, span, attrs.strategy); let pair = pair_filter(attrs.filter, field.ty, pair); Ok(acc.add(pair)) }) .map(|acc| acc.finish(closure)) } /// Determine strategy using "Default" semantics for a product. fn product_handle_default_params( ut: &mut UseTracker, ty: Type, span: Span, strategy: StratMode, ) -> StratPair { match strategy { // Specific strategy - use the given expr and erase the type // (since we don't know about it): StratMode::Strategy(strat) => pair_existential(ty, strat), // Specific value - use the given expr: StratMode::Value(value) => pair_value(ty, value), // Specific regex - dispatch to `_regex` function based on `ty`: StratMode::Regex(regex) => pair_regex(ty, regex), // Use Arbitrary for the given type and mark the type as used: StratMode::Arbitrary => { ty.mark_uses(ut); pair_any(ty, span) } } } /// Deriving for a list of fields (product type) on /// which `params` or `no_params` was NOT set directly. fn derive_product_no_params( ctx: Ctx, ut: &mut UseTracker, fields: Vec, item: &str, ) -> DeriveResult> { // Fold into an accumulator of the strategy types and the expressions // that produces the strategy. We then just return that accumulator // and let the caller of this function determine what to do with it. let acc = PartsAcc::new(fields.len()); fields.into_iter().try_fold(acc, |mut acc, field| { let attrs = attr::parse_attributes(ctx, &field.attrs)?; // Deny attributes that are only for enum variants: error::if_enum_attrs_present(ctx, &attrs, item); let span = field.span(); let ty = field.ty; let strat = pair_filter( attrs.filter, ty.clone(), match attrs.params { // Parameters were not set on the field: ParamsMode::Passthrough => match attrs.strategy { // Specific strategy - use the given expr and erase the type: StratMode::Strategy(strat) => pair_existential(ty, strat), // Specific value - use the given expr: StratMode::Value(value) => pair_value(ty, value), // Specific regex - dispatch to `_regex` function: StratMode::Regex(regex) => pair_regex(ty, regex), // Use Arbitrary for the given type and mark the type as used: StratMode::Arbitrary => { ty.mark_uses(ut); // We use the Parameters type of the field's type. let pref = acc.add_param(arbitrary_param(&ty)); pair_any_with(ty, pref, span) } }, // no_params set on the field: ParamsMode::Default => { product_handle_default_params(ut, ty, span, attrs.strategy) } // params() set on the field: ParamsMode::Specified(params_ty) => // We need to extract the param as the binding `params`: { extract_nparam( &mut acc, params_ty, match attrs.strategy { // Specific strategy - use the given expr and erase the type: StratMode::Strategy(strat) => { pair_existential(ty, strat) } // Specific value - use the given expr in a closure and erase: StratMode::Value(value) => { pair_value_exist(ty, value) } // Logic error by user; Pointless to specify params and // regex because the params can never be used in the regex. StratMode::Regex(regex) => { error::cant_set_param_and_regex(ctx, item); pair_regex(ty, regex) } // Logic error by user. // Pointless to specify params and not the strategy. Bail! StratMode::Arbitrary => { error::cant_set_param_but_not_strat( ctx, &ty, item, )? } }, ) } }, ); Ok(acc.add_strat(strat)) }) } /// Wrap the given constructor with a let binding /// moving `param_` into `params`. fn extract_nparam( acc: &mut PartsAcc, params_ty: Type, (strat, ctor): StratPair, ) -> StratPair { ( strat, extract_api(ctor, FromReg::Num(acc.add_param(params_ty))), ) } //============================================================================== // Enum //============================================================================== /// Entry point for deriving `Arbitrary` for `enum`s. fn derive_enum( ctx: Ctx, mut ast: DeriveData>, ) -> DeriveResult { // An enum can't be skipped, ensure it hasn't been: error::if_skip_present(ctx, &ast.attrs, error::ENUM); // We don't allow a strategy on the enum directly: error::if_strategy_present(ctx, &ast.attrs, error::ENUM); // We don't allow weight on enums directly: error::if_weight_present(ctx, &ast.attrs, error::ENUM); // Bail if there are no variants: if ast.body.is_empty() { error::uninhabited_enum_with_no_variants(ctx)?; } // Bail if all variants are uninhabited: if (&*ast.body).is_uninhabited() { error::uninhabited_enum_variants_uninhabited(ctx)?; } // The complexity of the logic depends mostly now on whether // parameters were set directly on the type or not. let parts = if let Some(sty) = ast.attrs.params.into_option() { // The logic is much simpler in this branch. derive_enum_has_params(ctx, &mut ast.tracker, &ast.ident, ast.body, sty) } else { // And considerably more complex here. derive_enum_no_params(ctx, &mut ast.tracker, &ast.ident, ast.body) }?; let parts = add_top_filter(ast.attrs.filter, parts); // We're done! Ok(Impl::new(ast.ident, ast.tracker, parts)) } /// Deriving for a enum on which `params` or `no_params` was NOT set directly. fn derive_enum_no_params( ctx: Ctx, ut: &mut UseTracker, _self: &Ident, variants: Vec, ) -> DeriveResult { // Initialize the accumulator: let mut acc = PartsAcc::new(variants.len()); // Fold into the accumulator the strategies for each variant: for variant in variants { if let Some((weight, ident, fields, attrs)) = keep_inhabited_variant(ctx, _self, variant)? { let path = parse_quote!( #_self::#ident ); let (strat, ctor) = if fields.is_empty() { // Unit variant: pair_unit_variant(ctx, &attrs, path) } else { // Not a unit variant: derive_variant_with_fields( ctx, ut, path, attrs, fields, &mut acc, )? }; acc = acc.add_strat((strat, (weight, ctor))); } } ensure_union_has_strategies(ctx, &acc.strats); // Package the strategies into a union. Ok(acc.finish(ctx)) } /// Ensure that there's at least one generatable variant for a union. fn ensure_union_has_strategies(ctx: Ctx, strats: &StratAcc) { if strats.is_empty() { // We didn't accumulate any strategies, // so we can't construct any variant. error::uninhabited_enum_because_of_skipped_variants(ctx); } } /// Derive for a variant which has fields and where the /// variant or its fields may specify `params` or `no_params`. fn derive_variant_with_fields( ctx: Ctx, ut: &mut UseTracker, v_path: Path, attrs: ParsedAttributes, fields: Vec, acc: &mut PartsAcc, ) -> DeriveResult { let filter = attrs.filter.clone(); let pair = match attrs.params { // Parameters were not set on the variant: ParamsMode::Passthrough => match attrs.strategy { // Specific strategy - use the given expr and erase the type: StratMode::Strategy(strat) => { deny_all_attrs_on_fields(ctx, fields)?; pair_existential_self(strat) } // Specific value - use the given expr: StratMode::Value(value) => { deny_all_attrs_on_fields(ctx, fields)?; pair_value_self(value) } StratMode::Regex(regex) => { deny_all_attrs_on_fields(ctx, fields)?; pair_regex_self(regex) } // No explicit strategy, use strategies for variant fields instead: StratMode::Arbitrary => { variant_no_explicit_strategy(ctx, ut, v_path, fields, acc)? } }, // no_params set on the variant: ParamsMode::Default => { variant_handle_default_params(ctx, ut, v_path, attrs, fields)? } // params() set on the variant: ParamsMode::Specified(params_ty) => extract_nparam( acc, params_ty, match attrs.strategy { // Specific strategy - use the given expr and erase the type: StratMode::Strategy(strat) => { deny_all_attrs_on_fields(ctx, fields)?; pair_existential_self(strat) } // Specific value - use the given expr in a closure and erase: StratMode::Value(value) => { deny_all_attrs_on_fields(ctx, fields)?; pair_value_exist_self(value) } // Logic error by user; Pointless to specify params and regex // because the params can never be used in the regex. StratMode::Regex(regex) => { error::cant_set_param_and_regex(ctx, error::ENUM_VARIANT); deny_all_attrs_on_fields(ctx, fields)?; pair_regex_self(regex) } // Logic error by user. Pointless to specify params and not // the strategy. Bail! StratMode::Arbitrary => { let ty = self_ty(); error::cant_set_param_but_not_strat( ctx, &ty, error::ENUM_VARIANT, )? } }, ), }; let pair = add_filter_self(filter, pair); Ok(pair) } /// Derive for a variant on which params were not set and on which no explicit /// strategy was set (or where it doesn't make sense...) and which has fields. fn variant_no_explicit_strategy( ctx: Ctx, ut: &mut UseTracker, v_path: Path, fields: Vec, acc: &mut PartsAcc, ) -> DeriveResult { // Compute parts for the inner product: let closure = map_closure(v_path, &fields); let fields_acc = derive_product_no_params(ctx, ut, fields, error::ENUM_VARIANT_FIELD)?; let (params, count) = fields_acc.params.consume(); let (strat, ctor) = fields_acc.strats.finish(closure); // Add params types from inner derive as a single type // in the outer params types. let params_ty = params.into(); Ok(( strat, if is_unit_type(¶ms_ty) { ctor } else { let pref = acc.add_param(params_ty); extract_all(ctor, count, FromReg::Num(pref)) }, )) } /// Determine strategy using "Default" semantics for a variant. fn variant_handle_default_params( ctx: Ctx, ut: &mut UseTracker, v_path: Path, attrs: ParsedAttributes, fields: Vec, ) -> DeriveResult { let pair = match attrs.strategy { // Specific strategy - use the given expr and erase the type: StratMode::Strategy(strat) => { deny_all_attrs_on_fields(ctx, fields)?; pair_existential_self(strat) } // Specific value - use the given expr: StratMode::Value(value) => { deny_all_attrs_on_fields(ctx, fields)?; pair_value_self(value) } StratMode::Regex(regex) => { deny_all_attrs_on_fields(ctx, fields)?; pair_regex_self(regex) } // Use Arbitrary for the factors (fields) of variant: StratMode::Arbitrary => // Fields are not allowed to specify params. { derive_product_has_params( ctx, ut, error::ENUM_VARIANT_FIELD, map_closure(v_path, &fields), fields, )? } }; Ok(pair) } /// Ensures that there are no proptest attributes on any of the fields. fn deny_all_attrs_on_fields(ctx: Ctx, fields: Vec) -> DeriveResult<()> { fields.into_iter().try_for_each(|field| { let f_attr = attr::parse_attributes(ctx, &field.attrs)?; error::if_anything_specified(ctx, &f_attr, error::ENUM_VARIANT_FIELD); Ok(()) }) } /// Derive for a variant which has fields and where the /// variant or its fields may NOT specify `params` or `no_params`. fn derive_enum_has_params( ctx: Ctx, ut: &mut UseTracker, _self: &Ident, variants: Vec, sty: Option, ) -> DeriveResult { // Initialize the accumulator: let mut acc = StratAcc::new(variants.len()); // Fold into the accumulator the strategies for each variant: for variant in variants { let parts = keep_inhabited_variant(ctx, _self, variant)?; if let Some((weight, ident, fields, attrs)) = parts { let path = parse_quote!( #_self::#ident ); let (strat, ctor) = if fields.is_empty() { // Unit variant: pair_unit_variant(ctx, &attrs, path) } else { // Not a unit variant: let filter = attrs.filter.clone(); add_filter_self( filter, variant_handle_default_params( ctx, ut, path, attrs, fields, )?, ) }; acc = acc.add((strat, (weight, ctor))); } } ensure_union_has_strategies(ctx, &acc); Ok(add_top_params(sty, acc.finish(ctx))) } /// Filters out uninhabited and variants that we've been ordered to skip. fn keep_inhabited_variant( ctx: Ctx, _self: &Ident, variant: Variant, ) -> DeriveResult, ParsedAttributes)>> { let attrs = attr::parse_attributes(ctx, &variant.attrs)?; let fields = fields_to_vec(variant.fields); if attrs.skip { // We've been ordered to skip this variant! // Check that all other attributes are not set. ensure_has_only_skip_attr(ctx, &attrs, error::ENUM_VARIANT); fields.into_iter().try_for_each(|field| { let f_attrs = attr::parse_attributes(ctx, &field.attrs)?; error::if_skip_present(ctx, &f_attrs, error::ENUM_VARIANT_FIELD); ensure_has_only_skip_attr(ctx, &f_attrs, error::ENUM_VARIANT_FIELD); Ok(()) })?; return Ok(None); } // If the variant is uninhabited, we can't generate it, so skip it. if (&*fields).is_uninhabited() { return Ok(None); } // Compute the weight: let weight = attrs.weight.unwrap_or(1); Ok(Some((weight, variant.ident, fields, attrs))) } /// Ensures that no other attributes than skip are present. fn ensure_has_only_skip_attr(ctx: Ctx, attrs: &ParsedAttributes, item: &str) { if attrs.params.is_set() { error::skipped_variant_has_param(ctx, item); } if attrs.strategy.is_set() { error::skipped_variant_has_strat(ctx, item); } if attrs.weight.is_some() { error::skipped_variant_has_weight(ctx, item); } if !attrs.filter.is_empty() { error::skipped_variant_has_filter(ctx, item); } } /// Deal with a unit variant. fn pair_unit_variant( ctx: Ctx, attrs: &ParsedAttributes, v_path: Path, ) -> StratPair { error::if_present_on_unit_variant(ctx, attrs); pair_unit_self(&v_path) } //============================================================================== // Combined accumulator //============================================================================== /// Combined accumulator for the parameters and strategies. struct PartsAcc { /// The accumulator for the parameters. params: ParamAcc, /// The accumulator for the strategies. strats: StratAcc, } impl PartsAcc { /// Constructs a new accumulator with the size /// passed on to the accumulator for the strategies. fn new(size: usize) -> Self { Self { params: ParamAcc::empty(), strats: StratAcc::new(size), } } /// Adds a strategy to the accumulator. fn add_strat(self, pair: (Strategy, C)) -> Self { Self { strats: self.strats.add(pair), params: self.params, } } /// Adds a parameter type to the accumulator and returns how many types /// there were before adding. fn add_param(&mut self, ty: Type) -> usize { self.params.add(ty) } } impl PartsAcc { /// Finishes off the accumulator by returning the parts needed for /// deriving. The resulting strategy is a mapping of the parts into /// the `Self` type. fn finish(self, closure: MapClosure) -> ImplParts { let (params, count) = self.params.consume(); let (strat, ctor) = self.strats.finish(closure); (params, strat, extract_all(ctor, count, FromReg::Top)) } } impl PartsAcc<(u32, Ctor)> { /// Finishes off the accumulator by returning the parts needed for /// deriving. The resultant strategy is one that randomly picks /// one of the parts based on the relative weights in the `u32`. fn finish(self, ctx: Ctx) -> ImplParts { let (params, count) = self.params.consume(); let (strat, ctor) = self.strats.finish(ctx); (params, strat, extract_all(ctor, count, FromReg::Top)) } } //============================================================================== // Param accumulator //============================================================================== /// Accumulator of the parameter types. struct ParamAcc { /// The accumulated parameters types. types: Params, } impl ParamAcc { /// Returns an empty accumulator. fn empty() -> Self { Self { types: Params::empty(), } } /// Adds a type to the accumulator and returns the type count before adding. fn add(&mut self, ty: Type) -> usize { let var = self.types.len(); self.types += ty; var } /// Consumes the accumulator returning the types and the count. fn consume(self) -> (Params, usize) { let count = self.types.len(); (self.types, count) } } //============================================================================== // Strategy accumulator //============================================================================== /// Accumulator of a sequence of strategies (both type and constructor). struct StratAcc { /// The type half of the accumulator: types: Vec, /// The constructors (Rust expression that makes the strategy) half: ctors: Vec, } impl StratAcc { /// Construct the given accumulator with /// initial capacity according to `size`. fn new(size: usize) -> Self { Self { types: Vec::with_capacity(size), ctors: Vec::with_capacity(size), } } /// Add the given type and constructor pair to /// the accumulator which is moved and returned. fn add(mut self, (strat, ctor): (Strategy, C)) -> Self { self.types.push(strat); self.ctors.push(ctor); self } /// Consume the accumulator returning the: /// + sequence of strategies /// + sequence of constructors fn consume(self) -> (Vec, Vec) { (self.types, self.ctors) } /// Returns `true` iff nothing has been accumulated yet. fn is_empty(&self) -> bool { self.types.is_empty() } } impl StratAcc { /// Finishes off the accumulator by returning /// a `.prop_map()` of the strategies. fn finish(self, closure: MapClosure) -> StratPair { pair_map(self.consume(), closure) } } impl StratAcc<(u32, Ctor)> { /// Finishes off the accumulator by returning a union of the /// strategies where the resultant strategy randomly picks /// one of the summands based on the relative weights provided. fn finish(self, ctx: Ctx) -> StratPair { // Check that the weight sum <= u32::MAX if self .ctors .iter() .map(|&(w, _)| w) .try_fold(0u32, |acc, w| acc.checked_add(w)) .is_none() { error::weight_overflowing(ctx) } pair_oneof(self.consume()) } } proptest-derive-0.4.0/src/error.rs000064400000000000000000000570341046102023000152600ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Provides error messages and some checkers. use std::fmt::Display; use proc_macro2::TokenStream; use quote::ToTokens; use crate::attr::ParsedAttributes; use syn; //============================================================================== // Item descriptions //============================================================================== /// Item name of structs. pub const STRUCT: &str = "struct"; /// Item name of struct fields. pub const STRUCT_FIELD: &str = "struct field"; /// Item name of enums. pub const ENUM: &str = "enum"; /// Item name of enum variants. pub const ENUM_VARIANT: &str = "enum variant"; /// Item name of enum variant fields. pub const ENUM_VARIANT_FIELD: &str = "enum variant field"; /// Item name for a type variable. pub const TY_VAR: &str = "a type variable"; //============================================================================== // Checkers //============================================================================== /// Ensures that the type is not parametric over lifetimes. pub fn if_has_lifetimes(ctx: Ctx, ast: &syn::DeriveInput) { if ast.generics.lifetimes().count() > 0 { has_lifetimes(ctx); } } /// Ensures that no attributes were specified on `item`. pub fn if_anything_specified(ctx: Ctx, attrs: &ParsedAttributes, item: &str) { if_enum_attrs_present(ctx, attrs, item); if_strategy_present(ctx, attrs, item); if_specified_params(ctx, attrs, item); if_specified_filter(ctx, attrs, item); } /// Ensures that things only allowed on an enum variant is not present on /// `item` which is not an enum variant. pub fn if_enum_attrs_present(ctx: Ctx, attrs: &ParsedAttributes, item: &str) { if_skip_present(ctx, attrs, item); if_weight_present(ctx, attrs, item); } /// Ensures that parameters is not present on `item`. pub fn if_specified_filter(ctx: Ctx, attrs: &ParsedAttributes, item: &str) { if !attrs.filter.is_empty() { meaningless_filter(ctx, item); } } /// Ensures that parameters is not present on `item`. pub fn if_specified_params(ctx: Ctx, attrs: &ParsedAttributes, item: &str) { if attrs.params.is_set() { parent_has_param(ctx, item); } } /// Ensures that an explicit strategy or value is not present on `item`. pub fn if_strategy_present(ctx: Ctx, attrs: &ParsedAttributes, item: &str) { use crate::attr::StratMode::*; match attrs.strategy { Arbitrary => {} Strategy(_) => illegal_strategy(ctx, "strategy", item), Value(_) => illegal_strategy(ctx, "value", item), Regex(_) => illegal_regex(ctx, item), } } /// Ensures that a strategy, value, params, filter is not present on a unit variant. pub fn if_present_on_unit_variant(ctx: Ctx, attrs: &ParsedAttributes) { /// Ensures that an explicit strategy or value is not present on a unit variant. use crate::attr::StratMode::*; match attrs.strategy { Arbitrary => {} Strategy(_) => strategy_on_unit_variant(ctx, "strategy"), Value(_) => strategy_on_unit_variant(ctx, "value"), Regex(_) => regex_on_unit_variant(ctx), } if attrs.params.is_set() { params_on_unit_variant(ctx) } if !attrs.filter.is_empty() { filter_on_unit_variant(ctx) } } /// Ensures that parameters or filter is not present on a unit struct. pub fn if_present_on_unit_struct(ctx: Ctx, attrs: &ParsedAttributes) { if attrs.params.is_set() { params_on_unit_struct(ctx) } if !attrs.filter.is_empty() { filter_on_unit_struct(ctx) } } /// Ensures that skip is not present on `item`. pub fn if_skip_present(ctx: Ctx, attrs: &ParsedAttributes, item: &str) { if attrs.skip { illegal_skip(ctx, item) } } /// Ensures that a weight is not present on `item`. pub fn if_weight_present(ctx: Ctx, attrs: &ParsedAttributes, item: &str) { if attrs.weight.is_some() { illegal_weight(ctx, item) } } //============================================================================== // Messages //============================================================================== /// Denotes that a fatal error happened in dealing somewhere in the /// procedural macro pipeline. A fatal error is different from a /// normal error in the sense that it halts progress in the macro /// immediately instead of allowing other errors to be accumulated. #[derive(Debug)] pub struct Fatal; /// The return type of a possibly fatal computation in the macro. pub type DeriveResult = Result; /// A mutable view / shorthand for the context. /// Prefer this type over `Context` in functions. pub type Ctx<'ctx> = &'ctx mut Context; /// The context / environment that the macro is operating in. /// Right now, it simply tracks all the errors collected during /// the running of the macro. #[derive(Default)] pub struct Context { errors: Vec, } impl Context { /// Add a non-fatal error to the context. pub fn error(&mut self, msg: T) { self.errors.push(msg.to_string()); } /// Add an error to the context and produce an erroring /// computation that will halt the macro. pub fn fatal(&mut self, msg: T) -> DeriveResult { self.error(msg); Err(Fatal) } /// Consume the context and if there were any errors, /// emit `compile_error!(..)` such that the crate using /// `#[derive(Arbitrary)]` will fail to compile. pub fn check(mut self) -> Result<(), TokenStream> { fn compile_error(msg: &str) -> TokenStream { quote! { compile_error!(#msg); } } match self.errors.len() { 0 => Ok(()), 1 => Err(compile_error(&self.errors.pop().unwrap())), n => { let mut msg = format!("{} errors:", n); for err in self.errors { msg.push_str("\n\t# "); msg.push_str(&err); } Err(compile_error(&msg)) } } } } //============================================================================== // Messages //============================================================================== /// Produce an error string with the error `$code` which corresponds /// to the given `$message`. macro_rules! mk_err_msg { ($code: ident, $msg: expr) => { concat!( "[proptest_derive, ", stringify!($code), "]", " during #[derive(Arbitrary)]:\n", $msg, " Please see: https://PATH/TO/foo#", stringify!($code), " for more information." ) }; } /// A macro constructing errors that do halt compilation immediately. macro_rules! fatal { ($error: ident, $code: ident, $msg: expr) => { pub fn $error(ctx: Ctx) -> DeriveResult { ctx.fatal(mk_err_msg!($code, $msg)) } }; ($error: ident ($($arg: ident: $arg_ty: ty),*), $code: ident, $msg: expr, $($fmt: tt)+) => { pub fn $error(ctx: Ctx, $($arg: $arg_ty),*) -> DeriveResult { ctx.fatal(format!(mk_err_msg!($code, $msg), $($fmt)+)) } }; } /// A macro constructing fatal errors that do not halt compilation immediately. macro_rules! error { ($error: ident, $code: ident, $msg: expr) => { pub fn $error(ctx: Ctx) { ctx.error(mk_err_msg!($code, $msg)) } }; ($error: ident ($($arg: ident: $arg_ty: ty),*), $code: ident, $msg: expr, $($fmt: tt)+) => { pub fn $error(ctx: Ctx, $($arg: $arg_ty),*) { ctx.error(format!(mk_err_msg!($code, $msg), $($fmt)+)) } }; } // Happens when we've been asked to derive `Arbitrary` for a type // that is parametric over lifetimes. Since proptest does not support // such types (yet), neither can we. error!( has_lifetimes, E0001, "Cannot derive `Arbitrary` for types with generic lifetimes, such as: \ `struct Foo<'a> { bar: &'a str }`. Currently, strategies for such types \ are impossible to define." ); // Happens when we've been asked to derive `Arbitrary` for something // that is neither an enum nor a struct. Most likely, we've been given // a union type. This might be supported in the future, but not yet. fatal!( not_struct_or_enum, E0002, "Deriving is only possible for structs and enums. \ It is currently not defined unions." ); // Happens when a struct has at least one field that is uninhabited. // There must at least exist one variant that we can construct. error!( uninhabited_struct, E0003, "The struct you are deriving `Arbitrary` for is uninhabited since one of \ its fields is uninhabited. An uninhabited type is by definition impossible \ to generate." ); // Happens when an enum has zero variants. Such an enum is obviously // uninhabited and can not be constructed. There must at least exist // one variant that we can construct. fatal!( uninhabited_enum_with_no_variants, E0004, "The enum you are deriving `Arbitrary` for is uninhabited since it has no \ variants. An example of such an `enum` is: `enum Void {}`. \ An uninhabited type is by definition impossible to generate." ); // Happens when an enum is uninhabited due all its variants being // uninhabited (why has the user given us such a weird enum?.. // Nonetheless, we do our best to ensure soundness). // There must at least exist one variant that we can construct. fatal!( uninhabited_enum_variants_uninhabited, E0005, "The enum you are deriving `Arbitrary` for is uninhabited since all its \ variants are uninhabited. \ An uninhabited type is by definition impossible to generate." ); // Happens when an enum becomes effectively uninhabited due // to all inhabited variants having been skipped. There must // at least exist one variant that we can construct. error!( uninhabited_enum_because_of_skipped_variants, E0006, "The enum you are deriving `Arbitrary` for is uninhabited for all intents \ and purposes since you have `#[proptest(skip)]`ed all inhabited variants. \ An uninhabited type is by definition impossible to generate." ); // Happens when `#[proptest(strategy = "")]` or // `#[proptest(value = "")]` is specified on an `item` // that does not support setting an explicit value or strategy. // An enum or struct does not support that. error!(illegal_strategy(attr: &str, item: &str), E0007, "`#[proptest({0} = \"\")]` is not allowed on {1}. Only struct fields, \ enum variants and fields inside those can use an explicit {0}.", attr, item); // Happens when `#[proptest(regex = "")]` is specified on an `item` // that does not support setting an explicit value or strategy. // See `illegal_strategy` for more. error!( illegal_regex(item: &str), E0007, "`#[proptest(regex = \"\")]` is not allowed on {0}. Only struct \ fields, enum variant fields can use an explicit regex.", item ); // Happens when `#[proptest(skip)]` is specified on an `item` that does // not support skipping. Only enum variants support skipping. error!( illegal_skip(item: &str), E0008, "A {} can't be `#[proptest(skip)]`ed, only enum variants can be skipped.", item ); // Happens when `#[proptest(weight = )]` is specified on an // `item` that does not support weighting. error!( illegal_weight(item: &str), E0009, "`#[proptest(weight = )]` is not allowed on {} as it is \ meaningless. Only enum variants can be assigned weights.", item ); // Happens when `#[proptest(params = )]` is set on `item` // but also on the parent of `item`. If the parent has set `params` // then that applies, and the `params` on `item` would be meaningless // wherefore it is forbidden. error!( parent_has_param(item: &str), E0010, "Cannot set the associated type `Parameters` of `Arbitrary` with either \ `#[proptest(no_params)]` or `#[proptest(params()]` on {} since it \ was set on the parent.", item ); // Happens when `#[proptest(params = )]` is set on `item` // but not `#[proptest(strategy = )]`. // This does not apply to the top level type declaration. fatal!( cant_set_param_but_not_strat(self_ty: &syn::Type, item: &str), E0011, "Cannot set `#[proptest(params = )]` on {0} while not providing a \ strategy for the {0} to use it since `<{1} as Arbitrary<'a>>::Strategy` \ may require a different type than the one provided in ``.", item, quote! { #self_ty } ); // Happens when `#[proptest(filter = "")]` is set on `item`, // but the parent of the `item` explicitly specifies a value or strategy, // which would cause the value to be generated without consulting the // `filter`. error!( meaningless_filter(item: &str), E0012, "Cannot set `#[proptest(filter = )]` on {} since it is set on the \ item which it is inside of that outer item specifies how to generate \ itself.", item ); // Happens when the form `#![proptest<..>]` is used. This will probably never // happen - but just in case it does, we catch it and emit an error. error!( inner_attr, E0013, "Inner attributes `#![proptest(..)]` are not currently supported." ); // Happens when the form `#[proptest]` is used. The form contains no // information for us to process, so we disallow it. error!( bare_proptest_attr, E0014, "Bare `#[proptest]` attributes are not allowed." ); // Happens when the form `#[proptest = )]` is used. // Only the form `#[proptest()]` is supported. error!( literal_set_proptest, E0015, "The attribute form `#[proptest = ]` is not allowed." ); // Happens when `` in `#[proptest()]` is a literal and // not a real modifier. error!( immediate_literals, E0016, "Literals immediately inside `#[proptest(..)]` as in \ `#[proptest(, ..)]` are not allowed." ); // Happens when `` in `#[proptest()]` is set more than // once. error!( set_again(meta: &syn::Meta), E0017, "The attribute modifier `{}` inside `#[proptest(..)]` has already been \ set. To fix the error, please remove at least one such modifier.", meta.path().into_token_stream() ); // Happens when `` in `#[proptest()]` is unknown to // us but we can make an educated guess as to what the user meant. error!( did_you_mean(found: &str, expected: &str), E0018, "Unknown attribute modifier `{}` inside #[proptest(..)] is not allowed. \ Did you mean to use `{}` instead?", found, expected ); // TODO: `unkown_modifier` is misspelled // Happens when `` in `#[proptest()]` is unknown to us. error!( unkown_modifier(modifier: &str), E0018, "Unknown attribute modifier `{}` inside `#[proptest(..)]` is not allowed.", modifier ); // Happens when `#[proptest(no_params)]` is malformed. error!( no_params_malformed, E0019, "The attribute modifier `no_params` inside `#[proptest(..)]` does not \ support any further configuration and must be a plain modifier as in \ `#[proptest(no_params)]`." ); // Happens when `#[proptest(skip)]` is malformed. error!( skip_malformed, E0020, "The attribute modifier `skip` inside `#[proptest(..)]` does not support \ any further configuration and must be a plain modifier as in \ `#[proptest(skip)]`." ); // Happens when `#[proptest(weight..)]` is malformed. error!( weight_malformed(meta: &syn::Meta), E0021, "The attribute modifier `{0}` inside `#[proptest(..)]` must have the \ format `#[proptest({0} = )]` where `` is an integer that \ fits within a `u32`. An example: `#[proptest({0} = 2)]` to set a relative \ weight of 2.", meta.path().into_token_stream() ); // Happens when both `#[proptest(params = "")]` and // `#[proptest(no_params)]` were specified. They are mutually // exclusive choices. The user can resolve this by picking one. fatal!( overspecified_param, E0022, "Cannot set `#[proptest(no_params)]` as well as \ `#[proptest(params())]` simultaneously. \ Please pick one of these attributes." ); // This happens when `#[proptest(params..)]` is malformed. // For example, `#[proptest(params)]` is malformed. Another example is when // `` inside `#[proptest(params = "")]` or // `#[proptest(params(""))]` is malformed. In other words, `` is // not a valid Rust type. Note that `syn` may not cover all valid Rust types. error!( param_malformed, E0023, "The attribute modifier `params` inside #[proptest(..)] must have the \ format `#[proptest(params = \"\")]` where `` is a valid type \ in Rust. An example: `#[proptest(params = \"ComplexType\")]`." ); // Happens when syn can't interpret in `#[proptest ]`. error!(no_interp_meta, E0024, "The tokens `` in #[proptest ] do not make for a valid attribute."); // Happens when more than one of `#[proptest(strategy..)]`, // `#[proptest(value..)]`, or `#[proptest(regex..)]` were specified. // They are mutually exclusive choices. // The user can resolve this by picking one. fatal!( overspecified_strat, E0025, "Cannot set more than one of `#[proptest(value = \"\")]`, `#[proptest(strategy = \"\")]`, `#[proptest(regex = \"\")]` \ simultaneously. Please pick one of these attributes." ); // Happens when `#[proptest(strategy..)]` or `#[proptest(value..)]` is // malformed. For example, `` inside `#[proptest(strategy = "")]` // or `#[proptest(value = "")]` is malformed. In other words, `` // is not a valid Rust expression. error!( strategy_malformed(meta: &syn::Meta), E0026, "The attribute modifier `{0}` inside `#[proptest(..)]` must have the \ format `#[proptest({0} = \"\")]` where `` is a valid Rust \ expression.", meta.path().into_token_stream() ); // Happens when `#[proptest(filter..)]` is malformed. // For example, `` inside `#[proptest(filter = "")]` or // is malformed. In other words, `` is not a valid Rust expression. error!( filter_malformed(meta: &syn::Meta), E0027, "The attribute modifier `{0}` inside `#[proptest(..)]` must have the \ format `#[proptest({0} = \"\")]` where `` is a valid Rust \ expression.", meta.path().into_token_stream() ); // Any attributes on a skipped variant has no effect - so we emit this error // to the user so that they are aware. error!( skipped_variant_has_weight(item: &str), E0028, "A variant has been skipped. Setting `#[proptest(weight = )]` on \ the {} is meaningless and is not allowed.", item ); // Any attributes on a skipped variant has no effect - so we emit this error // to the user so that they are aware. error!( skipped_variant_has_param(item: &str), E0028, "A variant has been skipped. Setting `#[proptest(no_param)]` or \ `#[proptest(params())]` on the {} is meaningless and is not allowed.", item ); // Any attributes on a skipped variant has no effect - so we emit this error // to the user so that they are aware. error!( skipped_variant_has_strat(item: &str), E0028, "A variant has been skipped. Setting `#[proptest(value = \"\")]` or \ `#[proptest(strategy = \"\")]` on the {} is meaningless and is not \ allowed.", item ); // Any attributes on a skipped variant has no effect - so we emit this error // to the user so that they are aware. Unfortunately, there's no way to // emit a warning to the user, so we emit an error instead. error!(skipped_variant_has_filter(item: &str), E0028, "A variant has been skipped. Setting `#[proptest(filter = \"\")]` or \ on the {} is meaningless and is not allowed.", item); // There's only one way to produce a specific unit variant, so setting // `#[proptest(strategy = "")]` or `#[proptest(value = "")]` // would be pointless. error!( strategy_on_unit_variant(what: &str), E0029, "Setting `#[proptest({0} = \"\")]` on a unit variant has no effect \ and is redundant because there is nothing to configure.", what ); // See `strategy_on_unit_variant`. error!(regex_on_unit_variant, E0029, "Setting `#[proptest(regex = \"\")]` on a unit variant has no effect \ and is redundant because there is nothing to configure."); // There's only one way to produce a specific unit variant, so setting // `#[proptest(params = "")]` would be pointless. error!( params_on_unit_variant, E0029, "Setting `#[proptest(params = \"\")]` on a unit variant has \ no effect and is redundant because there is nothing to configure." ); // There's only one way to produce a specific unit variant, so setting // `#[proptest(filter = "")]` would be pointless. error!( filter_on_unit_variant, E0029, "Setting `#[proptest(filter = \"\")]` on a unit variant has \ no effect and is redundant because there is nothing to further filter." ); // Occurs when `#[proptest(params = "")]` is specified on a unit // struct. There's only one way to produce a unit struct, so specifying // `Parameters` would be pointless. error!(params_on_unit_struct, E0030, "Setting `#[proptest(params = \"\")]` on a unit struct has no effect \ and is redundant because there is nothing to configure."); // Occurs when `#[proptest(filter = "")]` is specified on a unit // struct. There's only one way to produce a unit struct, so filtering // would be pointless. error!(filter_on_unit_struct, E0030, "Setting `#[proptest(filter = \"\")]` on a unit struct has no effect \ and is redundant because there is nothing to filter."); // Occurs when `#[proptest(no_bound)]` is specified // on something that is not a type variable. error!( no_bound_set_on_non_tyvar, E0031, "Setting `#[proptest(no_bound)]` on something that is not a type variable \ has no effect and is redundant. Therefore it is not allowed." ); // Happens when `#[proptest(no_bound)]` is malformed. error!( no_bound_malformed, E0032, "The attribute modifier `no_bound` inside `#[proptest(..)]` does not \ support any further configuration and must be a plain modifier as in \ `#[proptest(no_bound)]`." ); // Happens when the sum of weights on enum variants overflowing an u32. error!( weight_overflowing, E0033, "The sum of the weights specified on variants of the enum you are \ deriving `Arbitrary` for overflows an `u32` which it can't do." ); // Happens when `#[proptest(regex..)]` is malformed. // For example, `#[proptest(regex = 1)]` is not a valid form. error!( regex_malformed, E0034, "The attribute modifier `regex` inside `#[proptest(..)]` must have the \ format `#[proptest(regex = \"\")]` where `` is a valid regular expression embedded in a Rust string slice." ); // Happens when `#[proptest(params = )]` is set on `item` and then // `#[proptest(regex = "")]` is also set. We reject this because // the params can't be used. TODO: reduce this to a warning once we can // emit warnings. error!( cant_set_param_and_regex(item: &str), E0035, "Cannot set #[proptest(regex = \"\")] and \ `#[proptest(params = )]` on {0} because the latter is a logic bug \ since `params` cannot be used in ``.", item ); proptest-derive-0.4.0/src/interp.rs000064400000000000000000000236151046102023000154260ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use syn::{self, BinOp as B, Expr as E, Lit as L, UnOp as U}; /// Adapted from https://docs.rs/syn/0.14.2/src/syn/lit.rs.html#943 to accept /// u128. fn parse_lit_int(mut s: &str) -> Option { /// Get the byte at offset idx, or a default of `b'\0'` if we're looking /// past the end of the input buffer. pub fn byte + ?Sized>(s: &S, idx: usize) -> u8 { let s = s.as_ref(); if idx < s.len() { s[idx] } else { 0 } } let base = match (byte(s, 0), byte(s, 1)) { (b'0', b'x') => { s = &s[2..]; 16 } (b'0', b'o') => { s = &s[2..]; 8 } (b'0', b'b') => { s = &s[2..]; 2 } (b'0'..=b'9', _) => 10, _ => unreachable!(), }; let mut value = 0u128; loop { let b = byte(s, 0); let digit = match b { b'0'..=b'9' => u128::from(b - b'0'), b'a'..=b'f' if base > 10 => 10 + u128::from(b - b'a'), b'A'..=b'F' if base > 10 => 10 + u128::from(b - b'A'), b'_' => { s = &s[1..]; continue; } // NOTE: Looking at a floating point literal, we don't want to // consider these integers. b'.' if base == 10 => return None, b'e' | b'E' if base == 10 => return None, _ => break, }; if digit >= base { panic!("Unexpected digit {:x} out of base range", digit); } value = value.checked_mul(base)?.checked_add(digit)?; s = &s[1..]; } Some(value) } /// Parse a suffix of an integer literal. fn parse_suffix(lit: &str) -> Option<&'static str> { [ "i8", "i16", "i32", "i64", "i128", "isize", "u8", "u16", "u32", "u64", "u128", "usize", ] .iter() .find(|s| lit.ends_with(*s)) .copied() } /// Interprets an integer literal in a string. fn eval_str_int(lit: &str) -> Option { let val = parse_lit_int(lit)?; let checked_val = if let Some(suffix) = parse_suffix(lit) { match suffix { "i8" if val <= i8::MAX as u128 => val, "i16" if val <= i16::MAX as u128 => val, "i32" if val <= i32::MAX as u128 => val, "i64" if val <= i64::MAX as u128 => val, "u8" if val <= u128::from(u8::MAX) => val, "u16" if val <= u128::from(u16::MAX) => val, "u32" if val <= u128::from(u32::MAX) => val, "u64" if val <= u128::from(u64::MAX) => val, "usize" if val <= usize::MAX as u128 => val, "isize" if val <= isize::MAX as u128 => val, "u128" => val, "i128" if val <= i128::MAX as u128 => val, // Does not fit in suffix: _ => return None, } } else { val }; Some(checked_val) } /// Interprets an integer literal. fn eval_lit_int(lit: &syn::LitInt) -> Option { let lit = lit.to_string(); eval_str_int(&lit) } /// Interprets a verbatim literal. fn eval_lit_verbatim(lit: &proc_macro2::Literal) -> Option { let lit = lit.to_string(); eval_str_int(&lit) } /// Interprets a literal. fn eval_lit(lit: &syn::ExprLit) -> Option { match &lit.lit { L::Int(lit) => eval_lit_int(lit), L::Byte(lit) => Some(u128::from(lit.value())), L::Verbatim(lit) => eval_lit_verbatim(lit), _ => None, } } /// Interprets a binary operator on two expressions. fn eval_binary(bin: &syn::ExprBinary) -> Option { use std::u32; let l = eval_expr(&bin.left)?; let r = eval_expr(&bin.right)?; Some(match bin.op { B::Add(_) => l.checked_add(r)?, B::Sub(_) => l.checked_sub(r)?, B::Mul(_) => l.checked_mul(r)?, B::Div(_) => l.checked_div(r)?, B::Rem(_) => l.checked_rem(r)?, B::BitXor(_) => l ^ r, B::BitAnd(_) => l & r, B::BitOr(_) => l | r, B::Shl(_) if r <= u128::from(u32::MAX) => l.checked_shl(r as u32)?, B::Shr(_) if r <= u128::from(u32::MAX) => l.checked_shr(r as u32)?, _ => return None, }) } /// Interprets unary operator on an expression. fn eval_unary(expr: &syn::ExprUnary) -> Option { if let U::Not(_) = expr.op { Some(!eval_expr(&expr.expr)?) } else { None } } /// A **very** simple CTFE interpreter for some basic arithmetic: pub fn eval_expr(expr: &E) -> Option { match expr { E::Lit(expr) => eval_lit(expr), E::Binary(expr) => eval_binary(expr), E::Unary(expr) => eval_unary(expr), E::Paren(expr) => eval_expr(&expr.expr), E::Group(expr) => eval_expr(&expr.expr), _ => None, } } #[cfg(test)] mod test { use super::*; fn eval(expr: &str) -> Option { use syn::parse_str; eval_expr(&parse_str(expr).expect("not a valid expression")) } macro_rules! test { ($($name: ident, $case: expr => $result:expr;)*) => {$( #[test] fn $name() { assert_eq!(eval($case), $result); } )*}; } test! { accept_lit_bare, "1" => Some(1); accept_lit_bare_max, "340282366920938463463374607431768211455" => Some(340282366920938463463374607431768211455); reject_lit_bare_overflow, "340282366920938463463374607431768211456" => None; accept_lit_u8_max, "255u8" => Some(255); accept_lit_u16_max, "65535u16" => Some(65535); accept_lit_u32_max, "4294967295u32" => Some(4294967295); accept_lit_u64_max, "18446744073709551615u64" => Some(18446744073709551615); accept_lit_u128_max, "340282366920938463463374607431768211455u128" => Some(340282366920938463463374607431768211455); reject_lit_u8_overflow, "256u8" => None; reject_lit_u16_overflow, "65536u16" => None; reject_lit_u32_overflow, "4294967296u32" => None; reject_lit_u64_overflow, "18446744073709551616u64" => None; reject_lit_u128_overflow, "340282366920938463463374607431768211456u128" => None; accept_lit_i8_max, "127i8" => Some(127); accept_lit_i16_max, "32767i16" => Some(32767); accept_lit_i32_max, "2147483647i32" => Some(2147483647); accept_lit_i64_max, "9223372036854775807i64" => Some(9223372036854775807); accept_lit_i128_max, "170141183460469231731687303715884105727i128" => Some(170141183460469231731687303715884105727); reject_lit_i8_overflow, "128i8" => None; reject_lit_i16_overflow, "32768i16" => None; reject_lit_i32_overflow, "2147483648i32" => None; reject_lit_i64_overflow, "9223372036854775808i64" => None; reject_lit_i128_overflow, "170141183460469231731687303715884105728i128" => None; accept_lit_usize, "42usize" => Some(42); accept_lit_isize, "42isize" => Some(42); accept_lit_byte, "b'0'" => Some(48); reject_lit_negative, "-42" => None; accept_add_10_20, "10 + 20" => Some(30); accept_add_10u8_20u16, "10u8 + 20u16" => Some(30); reject_add_overflow, "340282366920938463463374607431768211456u128 + 1" => None; accept_add_commutes, "20 + 10" => Some(30); accept_add_5_numbers, "(10 + 20) + 30 + (40 + 50)" => Some(150); accept_add_10_0, "10 + 0" => Some(10); accept_sub_20_10, "20 - 10" => Some(10); reject_sub_10_20, "10 - 20" => None; reject_sub_10_11, "10 - 11" => None; accept_sub_10_10, "10 - 10" => Some(0); accept_mul_42_0, "42 * 0" => Some(0); accept_mul_0_42, "0 * 42" => Some(0); accept_mul_42_1, "42 * 1" => Some(42); accept_mul_1_42, "1 * 42" => Some(42); accept_mul_3_4, "3 * 4" => Some(12); accept_mul_4_3, "4 * 3" => Some(12); accept_mul_1_2_3_4_5, "(1 * 2) * 3 * (4 * 5)" => Some(120); reject_div_with_0, "10 / 0" => None; accept_div_42_1, "42 / 1" => Some(42); accept_div_42_42, "42 / 42" => Some(1); accept_div_20_10, "20 / 10" => Some(2); accept_div_10_20, "10 / 20" => Some(0); reject_rem_with_0, "10 % 0" => None; accept_rem_0_4, "0 % 4" => Some(0); accept_rem_4_4, "4 % 4" => Some(0); accept_rem_8_4, "8 % 4" => Some(0); accept_rem_1_4, "1 % 4" => Some(1); accept_rem_5_4, "5 % 4" => Some(1); accept_rem_2_4, "2 % 4" => Some(2); accept_rem_3_4, "3 % 4" => Some(3); accept_xor_1, "0b0000 ^ 0b1111" => Some(0b1111); accept_xor_2, "0b1111 ^ 0b0000" => Some(0b1111); accept_xor_3, "0b1111 ^ 0b1111" => Some(0b0000); accept_xor_4, "0b0000 ^ 0b0000" => Some(0b0000); accept_xor_5, "0b1100 ^ 0b0011" => Some(0b1111); accept_xor_6, "0b1001 ^ 0b1111" => Some(0b0110); accept_and_1, "0b0000 & 0b0000" => Some(0b0000); accept_and_2, "0b1001 & 0b0101" => Some(0b0001); accept_and_3, "0b1111 & 0b1111" => Some(0b1111); accept_or_1, "0b0000 | 0b0000" => Some(0b0000); accept_or_2, "0b1001 | 0b0101" => Some(0b1101); accept_or_3, "0b1111 | 0b1111" => Some(0b1111); accept_shl, "0b001000 << 2" => Some(0b100000); accept_shr, "0b001000 >> 2" => Some(0b000010); accept_shl_zero, "0b001000 << 0" => Some(0b001000); accept_shr_zero, "0b001000 >> 0" => Some(0b001000); reject_shl_rhs_not_u32, "0b001000 << 4294967296" => None; reject_shl_overflow, "0b001000 << 429496" => None; reject_shr_rhs_not_u32, "0b001000 >> 4294967296" => None; reject_shr_underflow, "0b001000 >> 429496" => None; accept_complex_arith, "(3 + 4 * 2 - 5) / 6" => Some(1); } } proptest-derive-0.4.0/src/lib.rs000064400000000000000000000040711046102023000146660ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! This is the API documentation for the `proptest-derive` crate. As this //! crate does not have an API _per se_, there isn't much to see here. //! //! You are probably looking for the [`proptest-derive` section of the Proptest //! Book](https://proptest-rs.github.io/proptest/proptest-derive/index.html). // # Known issues // // ## Fields with `[T; N]` where `N > 32` // // We can't derive for fields having arrays with sizes over 32. // While proptest only supports in UniformArrayStrategy arrays of sizes up to // 32, we can overcome that restriction by generating custom types on the // fly here. What we can't overcome is that `T: Arbititrary |- T: Debug` due // to the requirement by proptest. Since `T: Debug` must hold, we must also // ensure that arrays with sizes over 33 are also Debug. We can't do this. // Doing so would create orphan instances, which Rust does not allow to preserve // coherence. Therefore, until const generics lands in stable or when // we can remove the `T: Debug` bound on Arbitrary, we can not support arrays // sized over 32. // // # Recursive types // // We can't handle self-recursive or mutually recursive types at all right now. extern crate proc_macro as pm; extern crate proc_macro2; #[macro_use] extern crate syn; #[macro_use] extern crate quote; mod ast; mod attr; mod derive; mod error; mod interp; mod use_tracking; mod util; mod void; /// See module level documentation for more information. #[proc_macro_derive(Arbitrary, attributes(proptest))] pub fn derive_proptest_arbitrary(input: pm::TokenStream) -> pm::TokenStream { // Bootstrap! // This function just delegates to impl_proptest_arbitrary. derive::impl_proptest_arbitrary(syn::parse(input).unwrap()).into() } #[cfg(test)] mod tests; proptest-derive-0.4.0/src/tests.rs000064400000000000000000000103151046102023000152600ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! This module provides integration tests that test the expansion //! of the derive macro. //============================================================================== // Macros: //============================================================================== // Borrowed from: // https://docs.rs/synstructure/0.7.0/src/synstructure/macros.rs.html#104-135 macro_rules! test_derive { ($name:path { $($i:tt)* } expands to { $($o:tt)* }) => { { #[allow(dead_code)] fn ensure_compiles() { $($i)* $($o)* } test_derive!($name { $($i)* } expands to { $($o)* } no_build); } }; ($name:path { $($i:tt)* } expands to { $($o:tt)* } no_build) => { { let expected = stringify!( $($o)* ) .parse::() .expect("output should be a valid TokenStream"); let i = stringify!( $($i)* ); let parsed = $crate::syn::parse_str::<$crate::syn::DeriveInput>(i).expect( concat!("Failed to parse input to `#[derive(", stringify!($name), ")]`") ); let res = $name(parsed); assert_eq!( format!("{}", res), format!("{}", expected) ); } }; } macro_rules! test { (no_build $test_name:ident { $($i:tt)* } expands to { $($o:tt)* }) => { #[test] fn $test_name() { test_derive!( $crate::derive::impl_proptest_arbitrary { $($i)* } expands to { $($o)* } no_build ); } }; ($test_name:ident { $($i:tt)* } expands to { $($o:tt)* }) => { #[test] fn $test_name() { test_derive!( $crate::derive::impl_proptest_arbitrary { $($i)* } expands to { $($o)* } ); } }; } //============================================================================== // Unit structs: //============================================================================== test! { struct_unit_unit { #[derive(Debug)] struct MyUnitStruct; } expands to { #[allow(non_upper_case_globals)] #[allow(clippy::arc_with_non_send_sync)] const _IMPL_ARBITRARY_FOR_MyUnitStruct : () = { extern crate proptest as _proptest; impl _proptest::arbitrary::Arbitrary for MyUnitStruct { type Parameters = (); type Strategy = fn() -> Self; fn arbitrary_with(_top: Self::Parameters) -> Self::Strategy { || MyUnitStruct {} } } }; } } test! { struct_unit_tuple { #[derive(Debug)] struct MyTupleUnitStruct(); } expands to { #[allow(non_upper_case_globals)] #[allow(clippy::arc_with_non_send_sync)] const _IMPL_ARBITRARY_FOR_MyTupleUnitStruct : () = { extern crate proptest as _proptest; impl _proptest::arbitrary::Arbitrary for MyTupleUnitStruct { type Parameters = (); type Strategy = fn() -> Self; fn arbitrary_with(_top: Self::Parameters) -> Self::Strategy { || MyTupleUnitStruct {} } } }; } } test! { struct_unit_named { #[derive(Debug)] struct MyNamedUnitStruct {} } expands to { #[allow(non_upper_case_globals)] #[allow(clippy::arc_with_non_send_sync)] const _IMPL_ARBITRARY_FOR_MyNamedUnitStruct : () = { extern crate proptest as _proptest; impl _proptest::arbitrary::Arbitrary for MyNamedUnitStruct { type Parameters = (); type Strategy = fn() -> Self; fn arbitrary_with(_top: Self::Parameters) -> Self::Strategy { || MyNamedUnitStruct {} } } }; } } proptest-derive-0.4.0/src/use_tracking.rs000064400000000000000000000201601046102023000165730ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Provides `UseTracker` as well as `UseMarkable` which is used to //! track uses of type variables that need `Arbitrary` bounds in our //! impls. // Perhaps ordermap would be better, but our maps are so small that we care // much more about the increased compile times incured by including ordermap. // We need to preserve insertion order in any case, so HashMap is not useful. use std::borrow::Borrow; use std::collections::{BTreeMap, HashSet}; use syn; use crate::attr; use crate::error::{Ctx, DeriveResult}; use crate::util; //============================================================================== // API: Type variable use tracking //============================================================================== /// `UseTracker` tracks what type variables that have used in `any_with::` /// or similar and thus needs an `Arbitrary` bound added to them. pub struct UseTracker { /// Tracks 'usage' of a type variable name. /// Allocation of this map will happen at once and no further /// allocation will happen after that. Only potential updates /// will happen after initial allocation. used_map: BTreeMap, /// Extra types to bound by `Arbitrary` in the `where` clause. where_types: HashSet, /// The generics that we are doing this for. /// This what we will modify later once we're done. generics: syn::Generics, /// If set to `true`, then `mark_used` has no effect. track: bool, } /// Models a thing that may have type variables in it that /// can be marked as 'used' as defined by `UseTracker`. pub trait UseMarkable { fn mark_uses(&self, tracker: &mut UseTracker); } impl UseTracker { /// Constructs the tracker for the given `generics`. pub fn new(generics: syn::Generics) -> Self { // Construct the map by setting all type variables as being unused // initially. This is the only time we will allocate for the map. let used_map = generics .type_params() .map(|v| (v.ident.clone(), false)) .collect(); Self { generics, used_map, where_types: HashSet::default(), track: true, } } /// Stop tracking. `.mark_used` will have no effect. pub fn no_track(&mut self) { self.track = false; } /// Mark the _potential_ type variable `tyvar` as used. /// If the tracker does not know about the name, it is not /// a type variable and this call has no effect. fn use_tyvar(&mut self, tyvar: impl Borrow) { if self.track { if let Some(used) = self.used_map.get_mut(tyvar.borrow()) { *used = true; } } } /// Returns true iff the type variable given exists. fn has_tyvar(&self, ty_var: impl Borrow) -> bool { self.used_map.contains_key(ty_var.borrow()) } /// Mark the type as used. fn use_type(&mut self, ty: syn::Type) { self.where_types.insert(ty); } /// Adds the bound in `for_used` on used type variables and /// the bound in `for_not` (`if .is_some()`) on unused type variables. pub fn add_bounds( &mut self, ctx: Ctx, for_used: &syn::TypeParamBound, for_not: Option, ) -> DeriveResult<()> { { let mut iter = self.used_map.values().zip(self.generics.type_params_mut()); if let Some(for_not) = for_not { iter.try_for_each(|(&used, tv)| { // Steal the attributes: let no_bound = attr::has_no_bound(ctx, &tv.attrs)?; let bound = if used && !no_bound { for_used } else { &for_not }; tv.bounds.push(bound.clone()); Ok(()) })?; } else { iter.for_each(|(&used, tv)| { if used { tv.bounds.push(for_used.clone()) } }) } } self.generics.make_where_clause().predicates.extend( self.where_types.iter().cloned().map(|ty| { syn::WherePredicate::Type(syn::PredicateType { lifetimes: None, bounded_ty: ty, colon_token: ::default(), bounds: ::std::iter::once(for_used.clone()).collect(), }) }), ); Ok(()) } /// Consumes the (potentially) modified generics that the /// tracker was originally constructed with and returns it. pub fn consume(self) -> syn::Generics { self.generics } } //============================================================================== // Impls //============================================================================== impl UseMarkable for syn::Type { fn mark_uses(&self, ut: &mut UseTracker) { use syn::visit; visit::visit_type(&mut PathVisitor(ut), self); struct PathVisitor<'ut>(&'ut mut UseTracker); impl<'ut, 'ast> visit::Visit<'ast> for PathVisitor<'ut> { fn visit_macro(&mut self, _: &syn::Macro) {} fn visit_type_path(&mut self, tpath: &syn::TypePath) { if matches_prj_tyvar(self.0, tpath) { self.0.use_type(adjust_simple_prj(tpath).into()); return; } visit::visit_type_path(self, tpath); } fn visit_path(&mut self, path: &syn::Path) { // If path is PhantomData do not mark innards. if util::is_phantom_data(path) { return; } if let Some(ident) = util::extract_simple_path(path) { self.0.use_tyvar(ident); } visit::visit_path(self, path); } } } } fn matches_prj_tyvar(ut: &mut UseTracker, tpath: &syn::TypePath) -> bool { let path = &tpath.path; let segs = &path.segments; if let Some(qself) = &tpath.qself { // < $qself > :: $path if let Some(sub_tp) = extract_path(&qself.ty) { return sub_tp.qself.is_none() && util::match_singleton(segs.iter().skip(qself.position)) .filter(|ps| ps.arguments.is_empty()) .and_then(|_| util::extract_simple_path(&sub_tp.path)) .filter(|&ident| ut.has_tyvar(ident)) .is_some() // < $tyvar as? $path? > :: $path || matches_prj_tyvar(ut, sub_tp); } false } else { // true => $tyvar :: $projection return !util::path_is_global(path) && segs.len() == 2 && ut.has_tyvar(&segs[0].ident) && segs[0].arguments.is_empty() && segs[1].arguments.is_empty(); } } fn adjust_simple_prj(tpath: &syn::TypePath) -> syn::TypePath { let segments = tpath .qself .as_ref() .filter(|qp| qp.as_token.is_none()) .and_then(|qp| extract_path(&*qp.ty)) .filter(|tp| tp.qself.is_none()) .map(|tp| &tp.path.segments); if let Some(segments) = segments { let tpath = tpath.clone(); let mut segments = segments.clone(); segments.push_punct(::default()); segments.extend(tpath.path.segments.into_pairs()); syn::TypePath { qself: None, path: syn::Path { leading_colon: None, segments, }, } } else { tpath.clone() } } fn extract_path(ty: &syn::Type) -> Option<&syn::TypePath> { if let syn::Type::Path(tpath) = ty { Some(tpath) } else { None } } proptest-derive-0.4.0/src/util.rs000064400000000000000000000112701046102023000150740ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Mostly useful utilities for syn used in the crate. use std::borrow::Borrow; use syn; //============================================================================== // General AST manipulation and types //============================================================================== /// Extract the list of fields from a `Fields` from syn. /// We don't care about the style, we always and uniformly use {} in /// struct literal syntax for making struct and enum variant values. pub fn fields_to_vec(fields: syn::Fields) -> Vec { use syn::Fields::*; match fields { Named(fields) => fields.named.into_iter().collect(), Unnamed(fields) => fields.unnamed.into_iter().collect(), Unit => vec![], } } /// Returns true iff the given type is the literal unit type `()`. /// This is treated the same way by `syn` as a 0-tuple. pub fn is_unit_type>(ty: T) -> bool { ty.borrow() == &parse_quote!(()) } /// Returns the `Self` type (in the literal syntactic sense). pub fn self_ty() -> syn::Type { parse_quote!(Self) } //============================================================================== // Paths: //============================================================================== type CommaPS = syn::punctuated::Punctuated; /// Returns true iff the path is simple, i.e: /// just a :: separated list of identifiers. fn is_path_simple(path: &syn::Path) -> bool { path.segments.iter().all(|ps| ps.arguments.is_empty()) } /// Returns true iff lhs matches the rhs. fn eq_simple_pathseg(lhs: &str, rhs: &CommaPS) -> bool { lhs.split("::") .filter(|s| !s.trim().is_empty()) .eq(rhs.iter().map(|ps| ps.ident.to_string())) } /// Returns true iff lhs matches the given simple Path. pub fn eq_simple_path(mut lhs: &str, rhs: &syn::Path) -> bool { if !is_path_simple(rhs) { return false; } if rhs.leading_colon.is_some() { if !lhs.starts_with("::") { return false; } lhs = &lhs[2..]; } eq_simple_pathseg(lhs, &rhs.segments) } /// Returns true iff the given path matches any of given /// paths specified as string slices. pub fn match_pathsegs(path: &syn::Path, against: &[&str]) -> bool { against.iter().any(|needle| eq_simple_path(needle, path)) } /// Returns true iff the given `PathArguments` is one that has one type /// applied to it. fn pseg_has_single_tyvar(pp: &syn::PathSegment) -> bool { use syn::GenericArgument::Type; use syn::PathArguments::AngleBracketed; if let AngleBracketed(ab) = &pp.arguments { if let Some(Type(_)) = match_singleton(ab.args.iter()) { return true; } } false } /// Returns true iff the given type is of the form `PhantomData` where /// `TY` can be substituted for any type, including type variables. pub fn is_phantom_data(path: &syn::Path) -> bool { let segs = &path.segments; if segs.is_empty() { return false; } let mut path = path.clone(); let lseg = path.segments.pop().unwrap().into_value(); &lseg.ident == "PhantomData" && pseg_has_single_tyvar(&lseg) && match_pathsegs( &path, &[ // We hedge a bet that user will never declare // their own type named PhantomData. // This may give errors, but is worth it usability-wise. "", "marker", "std::marker", "core::marker", "::std::marker", "::core::marker", ], ) } /// Extracts a simple non-global path of length 1. pub fn extract_simple_path(path: &syn::Path) -> Option<&syn::Ident> { match_singleton(&path.segments) .filter(|f| !path_is_global(path) && f.arguments.is_empty()) .map(|f| &f.ident) } /// Does the path have a leading `::`? pub fn path_is_global(path: &syn::Path) -> bool { path.leading_colon.is_some() } //============================================================================== // General Rust utilities: //============================================================================== /// Returns `Some(x)` iff the iterable is singleton and otherwise None. pub fn match_singleton(it: impl IntoIterator) -> Option { let mut it = it.into_iter(); it.next().filter(|_| it.next().is_none()) } proptest-derive-0.4.0/src/void.rs000064400000000000000000000127761046102023000150740ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Provides the `IsUninhabited` trait. //! //! By nature, determining if a type is uninhabited or not given Rust's //! turing complete type system is undecidable. Furthermore, we don't even //! have access to all the information because we can't inspect type //! definitions, type macros, or projections via associated types. //! //! Any analysis we perform here is therefore incomplete but sound. //! That is, if we state that a type is uninhabited, it is so for sure. //! But we can't state that all uninhabited types are uninhabited. use syn::{self, visit}; use crate::interp; use crate::util; //============================================================================== // Trait //============================================================================== /// A trait for types for which it is possible to check if the modelled /// object is uninhabited or not. A `false` answer means that we can not /// tell for sure that the thing is uninhabited, not that we are 100% /// certain that it is inhabited. pub trait IsUninhabited { /// Returns true if the given type is known to be uninhabited. /// There may be more scenarios under which the type is uninhabited. /// Thus, this is not a complete and exhaustive check. fn is_uninhabited(&self) -> bool; } //============================================================================== // Enum/Variants: //============================================================================== impl IsUninhabited for syn::DataEnum { fn is_uninhabited(&self) -> bool { self.variants.is_uninhabited() } } impl

IsUninhabited for syn::punctuated::Punctuated { fn is_uninhabited(&self) -> bool { self.iter().all(IsUninhabited::is_uninhabited) } } impl<'a> IsUninhabited for &'a [syn::Variant] { fn is_uninhabited(&self) -> bool { self.iter().all(IsUninhabited::is_uninhabited) } } impl IsUninhabited for syn::Variant { fn is_uninhabited(&self) -> bool { self.fields.is_uninhabited() } } //============================================================================== // Struct/Fields: //============================================================================== impl IsUninhabited for syn::Fields { fn is_uninhabited(&self) -> bool { self.iter().any(syn::Field::is_uninhabited) } } impl<'a> IsUninhabited for &'a [syn::Field] { fn is_uninhabited(&self) -> bool { self.iter().any(syn::Field::is_uninhabited) } } impl IsUninhabited for syn::Field { fn is_uninhabited(&self) -> bool { self.ty.is_uninhabited() } } //============================================================================== // Types: //============================================================================== impl IsUninhabited for syn::Type { fn is_uninhabited(&self) -> bool { let mut uninhabited = Uninhabited(false); visit::visit_type(&mut uninhabited, &self); uninhabited.0 } } /// Tracks uninhabitedness. struct Uninhabited(bool); impl Uninhabited { /// Set to uninhabited. fn set(&mut self) { self.0 = true; } } // We are more strict than Rust is. // Our notion of uninhabited is if the type is generatable or not. // The second a type like *const ! is dereferenced you have UB. impl<'ast> visit::Visit<'ast> for Uninhabited { //------------------------------------------------------------------ // If we get to one of these we have a knowably uninhabited type: //------------------------------------------------------------------ // The ! (never) type is obviously uninhabited: fn visit_type_never(&mut self, _: &'ast syn::TypeNever) { self.set(); } // A path is uninhabited if we get one we know is uninhabited. // Even if `T` in `::Item` is uninhabited, the associated item // may be inhabited, so we can't say for sure that it is uninhabited. fn visit_type_path(&mut self, type_path: &'ast syn::TypePath) { const KNOWN_UNINHABITED: &[&str] = &["std::string::ParseError", "::std::string::ParseError"]; if type_path.qself.is_none() && util::match_pathsegs(&type_path.path, KNOWN_UNINHABITED) { self.set(); } } // An array is uninhabited iff: `[T; N]` where uninhabited(T) && N != 0 // We want to block decent if N == 0. fn visit_type_array(&mut self, arr: &'ast syn::TypeArray) { if let Some(len) = interp::eval_expr(&arr.len) { if len > 0 { self.visit_type(&arr.elem); } } } //------------------------------------------------------------------ // These are here to block decent: //------------------------------------------------------------------ // An fn(I) -> O is never uninhabited even if I or O are: fn visit_type_bare_fn(&mut self, _: &'ast syn::TypeBareFn) {} // A macro may transform the inner type in ways we can't predict: fn visit_macro(&mut self, _: &'ast syn::Macro) {} // Both of these could be, but type is anonymous: fn visit_type_impl_trait(&mut self, _: &'ast syn::TypeImplTrait) {} fn visit_type_trait_object(&mut self, _: &'ast syn::TypeTraitObject) {} } proptest-derive-0.4.0/tests/assoc.rs000064400000000000000000000117061046102023000156060ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use proptest::prelude::{prop_assert_eq, proptest, Arbitrary}; use proptest_derive::Arbitrary; trait Func { type Out; } trait FuncA { type OutA: FuncB; } trait FuncB { type OutB; } #[derive(Debug)] struct TypeA; #[derive(Debug)] struct TypeB; #[derive(Debug, Arbitrary)] struct OutTy { #[proptest(value = "42")] val: usize, } impl Func for TypeA { type Out = OutTy; } impl FuncA for TypeA { type OutA = TypeB; } impl FuncB for TypeB { type OutB = OutTy; } #[derive(Debug, Arbitrary)] struct T0 { field: ::Out, } #[derive(Debug, Arbitrary)] struct T1 { _field: Vec, } #[derive(Debug, Arbitrary)] struct T2 { _field: Vec>, } #[derive(Debug, Arbitrary)] struct T3 { field: Vec<::Out>, } #[derive(Debug, Arbitrary)] struct T4 { field: Tyvar::OutB, } #[derive(Arbitrary)] struct T5 { field: ::OutB, } #[derive(Arbitrary)] struct T6 { field: ::OutB, } #[derive(Arbitrary)] struct T7 { field: ::OutB, } #[derive(Arbitrary)] struct T8 { field: <::OutA as FuncB>::OutB, } #[derive(Arbitrary)] struct T9 { field: <::OutA as FuncB>::OutB, } #[derive(Debug, Arbitrary)] struct T10 { field: Vec, } #[derive(Arbitrary)] struct T11 { field: Vec<::OutB>, } #[derive(Arbitrary)] struct T12 { field: Vec<::OutB>, } #[derive(Arbitrary)] struct T13 { field: Vec<::OutB>, } #[derive(Arbitrary)] struct T14 { field: Vec<<::OutA as FuncB>::OutB>, } #[derive(Arbitrary)] struct T15 { field: Vec<<::OutA as FuncB>::OutB>, } macro_rules! debug { ($trait: path, $ty: ident) => { impl ::std::fmt::Debug for $ty { fn fmt( &self, fmt: &mut ::std::fmt::Formatter, ) -> Result<(), ::std::fmt::Error> { fmt.debug_struct(stringify!($ty)) .field("field", &"") .finish() } } }; } debug!(FuncB, T5); debug!(FuncB, T6); debug!(FuncA, T7); debug!(FuncA, T8); debug!(FuncA, T9); debug!(FuncB, T11); debug!(FuncB, T12); debug!(FuncA, T13); debug!(FuncA, T14); debug!(FuncA, T15); #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::>(); assert_arbitrary::>(); assert_arbitrary::>(); assert_arbitrary::>(); assert_arbitrary::>(); assert_arbitrary::>(); assert_arbitrary::>(); assert_arbitrary::>(); assert_arbitrary::>(); assert_arbitrary::>(); assert_arbitrary::>(); assert_arbitrary::>(); } proptest! { #[test] fn t0_field_val_42(t: T0) { prop_assert_eq!(t.field.val, 42); } #[test] fn t1_no_panic(_: T1) {} #[test] fn t2_no_panic(_: T2) {} #[test] fn t3_all_42(t: T3) { t.field.iter().for_each(|x| assert_eq!(x.val, 42)) } #[test] fn t4_field_val_42(t: T4) { prop_assert_eq!(t.field.val, 42); } #[test] fn t5_field_val_42(t: T5) { prop_assert_eq!(t.field.val, 42); } #[test] fn t6_field_val_42(t: T6) { prop_assert_eq!(t.field.val, 42); } #[test] fn t7_field_val_42(t: T7) { prop_assert_eq!(t.field.val, 42); } #[test] fn t8_field_val_42(t: T8) { prop_assert_eq!(t.field.val, 42); } #[test] fn t9_field_val_42(t: T9) { prop_assert_eq!(t.field.val, 42); } #[test] fn t10_all_42(t: T10) { t.field.iter().for_each(|x| assert_eq!(x.val, 42)) } #[test] fn t11_all_42(t: T11) { t.field.iter().for_each(|x| assert_eq!(x.val, 42)) } #[test] fn t12_all_42(t: T12) { t.field.iter().for_each(|x| assert_eq!(x.val, 42)) } #[test] fn t13_all_42(t: T13) { t.field.iter().for_each(|x| assert_eq!(x.val, 42)) } #[test] fn t14_all_42(t: T14) { t.field.iter().for_each(|x| assert_eq!(x.val, 42)) } #[test] fn t15_all_42(t: T15) { t.field.iter().for_each(|x| assert_eq!(x.val, 42)) } } proptest-derive-0.4.0/tests/compile-fail/E0001-lifetime.rs000064400000000000000000000014631046102023000213170ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0001] //~| [proptest_derive, E0008] #[proptest(skip)] struct NonFatal<'a>(&'a ()); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0001] struct T0<'a>(&'a ()); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0001] enum T1<'a> { V0(&'a ()) } proptest-derive-0.4.0/tests/compile-fail/E0002-no-unions.rs000064400000000000000000000007671046102023000214550ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} #[derive(Arbitrary)] //~ ERROR: [proptest_derive, E0002] union Foo { x: usize } proptest-derive-0.4.0/tests/compile-fail/E0003-void-struct.rs000064400000000000000000000022331046102023000220020ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(never_type)] extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0003] //~| [proptest_derive, E0008] struct NonFatal { #[proptest(skip)] x: !, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0003] struct Ty0 { x: ! } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0003] struct Ty1 { x: usize, y: !, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0003] struct Ty2 { x: (!, usize), y: bool, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0003] struct Ty3 { x: [!; 1] } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0003] struct Ty4 { x: [::std::string::ParseError; 1], } proptest-derive-0.4.0/tests/compile-fail/E0004-void-enum.rs000064400000000000000000000011351046102023000214230ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(never_type)] extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0004] enum Void {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0004] enum FooBar {} proptest-derive-0.4.0/tests/compile-fail/E0005-void-enum.rs000064400000000000000000000012341046102023000214240ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(never_type)] extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0005] enum T0 { V0(!), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0005] enum T1 { V0(!, bool), V1([!; 1]), V2([(!, bool); 1]) } proptest-derive-0.4.0/tests/compile-fail/E0006-void-enum.rs000064400000000000000000000023531046102023000214300ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(never_type)] extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0006] //~| [proptest_derive, E0008] enum NonFatal<#[proptest(skip)] T> { #[proptest(skip)] Unit(T), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0006] enum T0 { #[proptest(skip)] Unit, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0006] enum T1 { #[proptest(skip)] V0, #[proptest(skip)] V1, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0006] enum T2 { #[proptest(skip)] V0, #[proptest(skip)] V1, V2(!), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0006] enum T3 { #[proptest(skip)] V0, #[proptest(skip)] V1, V2([!; 1 + 2 + (3 / 3) + (1 << 3)]), } proptest-derive-0.4.0/tests/compile-fail/E0007-illegal-strategy.rs000064400000000000000000000044671046102023000230070ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0007] //~| [proptest_derive, E0030] #[proptest(params = "u8")] #[proptest(strategy = "1u8..")] struct A {} // strategy: #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(strategy = "1u8..")] struct B; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(strategy = "1u8..")] struct C(); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(strategy = "1u8..")] struct D { field: String } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(strategy = "1u8..")] struct E(Vec); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(strategy = "1u8..")] enum F { V1, V2, } // value: #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(value = "1")] struct G; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(value = "2")] struct H(); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(value = "1 + 2")] struct I { field: String } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(value = "2 * 3")] struct J(Vec); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(value = "1..2")] enum K { V1, V2, } // regex: #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(regex = "1")] struct L; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(regex = "\\d\\d")] struct M(); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(regex = "3")] struct N { field: String } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(regex = "a+")] struct O(Vec); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0007] #[proptest(regex = "b*")] enum P { V1, V2, } proptest-derive-0.4.0/tests/compile-fail/E0008-illegal-skip.rs000064400000000000000000000031731046102023000221050ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} #[derive(Clone, Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0008] //~| [proptest_derive, E0007] #[proptest(skip)] #[proptest(strategy = "Just(A {})")] struct A {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0008] #[proptest(skip)] struct B; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0008] #[proptest(skip)] struct C(); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0008] #[proptest(skip)] struct D { field: String } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0008] #[proptest(skip)] struct E(Vec); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0008] #[proptest(skip)] enum F { V1, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0008] struct G( #[proptest(skip)] Vec ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0008] struct H { #[proptest(skip)] field: Vec } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0008] enum I { V0 { #[proptest(skip)] field: Vec } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0008] enum J { V0(#[proptest(skip)] Vec) } proptest-derive-0.4.0/tests/compile-fail/E0009-illegal-weight.rs000064400000000000000000000032241046102023000224240ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0009] //~| [proptest_derive, E0030] #[proptest(no_params)] #[proptest(weight = 1)] struct A {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0009] #[proptest(weight = 2)] struct B; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0009] #[proptest(weight = 3)] struct C(); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0009] #[proptest(weight = 3)] struct D { field: String } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0009] #[proptest(weight = 3)] struct E(Vec); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0009] #[proptest(weight = 3)] enum F { V1, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0009] struct G( #[proptest(weight = 3)] Vec ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0009] struct H { #[proptest(weight = 3)] field: Vec } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0009] enum I { V0 { #[proptest(weight = 3)] field: Vec } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0009] enum J { V0(#[proptest(weight = 3)] Vec) } proptest-derive-0.4.0/tests/compile-fail/E0010-parent-has-params.rs000064400000000000000000000050351046102023000230430ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} // Show non-fatal: #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| [proptest_derive, E0010] //~| [proptest_derive, E0008] #[proptest(no_params)] struct NonFatal<#[proptest(skip)] T> { #[proptest(no_params)] field: T } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0010] #[proptest(no_params)] struct T0 { #[proptest(no_params)] field: String } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0010] #[proptest(no_params)] struct T1( #[proptest(no_params)] String ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0010] #[proptest(params = "u8")] struct T2 { #[proptest(no_params)] bar: String } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0010] #[proptest(params = "usize")] struct T3( #[proptest(no_params)] String ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0010] #[proptest(no_params)] struct T4 { #[proptest(params = "usize")] baz: String } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0010] #[proptest(no_params)] struct T5( #[proptest(params = "String")] String ); #[derive(Debug, Arbitrary)] // ERROR: [proptest_derive, E0010] #[proptest(no_params)] enum T6 { #[proptest(params = "String")] V0(u8), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0010] enum T7 { #[proptest(no_params)] V0( #[proptest(params = "String")] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0010] #[proptest(no_params)] enum T8 { V0( #[proptest(params = "String")] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0010] #[proptest(params = "String")] enum T9 { V0( #[proptest(no_params)] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0010] #[proptest(params = "String")] enum T10 { V0 { #[proptest(no_params)] batman: u8 }, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0010] #[proptest(no_params)] enum T11 { V0 { #[proptest(params = "String")] batman: u8 }, } proptest-derive-0.4.0/tests/compile-fail/E0011-params-variant.rs000064400000000000000000000014071046102023000224450ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0011] enum T0 { #[proptest(params = "String")] V0( #[proptest(no_params)] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0011] enum T1 { #[proptest(params = "(u8, u8)")] V0 { #[proptest(no_params)] field: Vec }, } proptest-derive-0.4.0/tests/compile-fail/E0012-parent-has-filter.rs000064400000000000000000000120321046102023000230420ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} fn even(x: &u8) -> bool { x % 2 == 0 } #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| [proptest_derive, E0012] //~| [proptest_derive, E0008] enum NonFatal<#[proptest(skip)] T> { #[proptest(strategy = "(0..10u8).prop_map(T0::V0)")] V0( #[proptest(filter(even))] u8, T ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] enum T0 { #[proptest(strategy = "(0..10u8).prop_map(T0::V0)")] V0( #[proptest(filter(even))] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] enum T1 { #[proptest(strategy = "(0..10u8).prop_map(|field| T1::V0 { field })")] V0 { #[proptest(filter(even))] field: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] enum T2 { #[proptest(value = "T2::V0(1)")] V0( #[proptest(filter(even))] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] enum T3 { #[proptest(value = "T3::V0 { field: 1 }")] V0 { #[proptest(filter(even))] field: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] #[proptest(no_params)] enum T4 { #[proptest(strategy = "(0..10u8).prop_map(T4::V0)")] V0( #[proptest(filter(even))] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] #[proptest(no_params)] enum T5 { #[proptest(strategy = "(0..10u8).prop_map(|field| T5::V0 { field })")] V0 { #[proptest(filter(even))] field: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] #[proptest(no_params)] enum T6 { #[proptest(value = "T6::V0(1)")] V0( #[proptest(filter(even))] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] #[proptest(no_params)] enum T7 { #[proptest(value = "T7::V0 { field: 1 }")] V0 { #[proptest(filter(even))] field: u8 } } struct Unit; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] #[proptest(params(Unit))] enum T8 { #[proptest(strategy = "(0..10u8).prop_map(T8::V0)")] V0( #[proptest(filter(even))] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] #[proptest(params(Unit))] enum T9 { #[proptest(strategy = "(0..10u8).prop_map(|field| T9::V0 { field })")] V0 { #[proptest(filter(even))] field: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] #[proptest(params(Unit))] enum T10 { #[proptest(value = "T10::V0(1)")] V0( #[proptest(filter(even))] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] #[proptest(params(Unit))] enum T11 { #[proptest(value = "T11::V0 { field: 1 }")] V0 { #[proptest(filter(even))] field: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] enum T12 { #[proptest(params(Unit))] #[proptest(strategy = "(0..10u8).prop_map(T12::V0)")] V0( #[proptest(filter(even))] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] enum T13 { #[proptest(params(Unit))] #[proptest(strategy = "(0..10u8).prop_map(|field| T13::V0 { field })")] V0 { #[proptest(filter(even))] field: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] enum T14 { #[proptest(params(Unit))] #[proptest(value = "T14::V0(1)")] V0( #[proptest(filter(even))] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] enum T15 { #[proptest(params(Unit))] #[proptest(value = "T15::V0 { field: 1 }")] V0 { #[proptest(filter(even))] field: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] enum T16 { #[proptest(no_params)] #[proptest(strategy = "(0..10u8).prop_map(T16::V0)")] V0( #[proptest(filter(even))] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] enum T17 { #[proptest(no_params)] #[proptest(strategy = "(0..10u8).prop_map(|field| T17::V0 { field })")] V0 { #[proptest(filter(even))] field: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] enum T18 { #[proptest(no_params)] #[proptest(value = "T18::V0(1)")] V0( #[proptest(filter(even))] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0012] enum T19 { #[proptest(no_params)] #[proptest(value = "T19::V0 { field: 1 }")] V0 { #[proptest(filter(even))] field: u8 } } proptest-derive-0.4.0/tests/compile-fail/E0014-bare-attr.rs000064400000000000000000000032771046102023000214130ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} // Show non-fatal: #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0014] //~| [proptest_derive, E0007] #[proptest] #[proptest(value("foobar"))] struct T0; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0014] #[proptest] struct T1(); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0014] #[proptest] struct T2 {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0014] struct T3 { #[proptest] field: Vec, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0014] struct T4( #[proptest] usize, ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0014] #[proptest] enum T5 { V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0014] enum T6 { #[proptest] V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0014] enum T7 { V0 { #[proptest] foo: &'static str, }, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0014] enum T8 { V0(#[proptest] bool) } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0014] enum T9 { #[proptest] V0(bool), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0014] enum T10 { #[proptest] V0 { bar: bool }, } proptest-derive-0.4.0/tests/compile-fail/E0015-lit-set.rs000064400000000000000000000033311046102023000211030ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} // Show non-fatal: #[derive(Debug, Arbitrary)] //~ 2 errors: //~| [proptest_derive, E0015] //~| [proptest_derive, E0008] #[proptest = 1] #[proptest(skip)] struct T0; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0015] #[proptest = 1] struct T1(); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0015] #[proptest = 1] struct T2 {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0015] struct T3 { #[proptest = 1] field: Vec, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0015] struct T4( #[proptest = 1] usize, ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0015] #[proptest = 1] enum T5 { V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0015] enum T6 { #[proptest = 1] V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0015] enum T7 { V0 { #[proptest = 1] foo: &'static str, }, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0015] enum T8 { V0(#[proptest = 1] bool) } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0015] enum T9 { #[proptest = 1] V0(bool), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0015] enum T10 { #[proptest = 1] V0 { bar: bool }, } proptest-derive-0.4.0/tests/compile-fail/E0016-immediate-lit.rs000064400000000000000000000033251046102023000222520ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} // Show non-fatal: #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0016] //~| [proptest_derive, E0008] #[proptest(1)] #[proptest(skip)] struct T0; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0016] #[proptest(1)] struct T1(); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0016] #[proptest(1)] struct T2 {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0016] struct T3 { #[proptest(1)] field: Vec, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0016] struct T4( #[proptest(1)] usize, ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0016] #[proptest(1)] enum T5 { V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0016] enum T6 { #[proptest(1)] V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0016] enum T7 { V0 { #[proptest(1)] foo: &'static str, }, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0016] enum T8 { V0(#[proptest(1)] bool) } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0016] enum T9 { #[proptest(1)] V0(bool), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0016] enum T10 { #[proptest(1)] V0 { bar: bool }, } proptest-derive-0.4.0/tests/compile-fail/E0017-set-again.rs000064400000000000000000000120501046102023000213720ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| # [proptest_derive, E0017] //~| # [proptest_derive, E0030] #[proptest(no_params)] #[proptest(no_params)] struct T0; #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| # [proptest_derive, E0017] //~| # [proptest_derive, E0030] #[proptest(no_params)] #[proptest(no_params)] struct T1(); #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| # [proptest_derive, E0017] //~| # [proptest_derive, E0030] #[proptest(no_params)] #[proptest(no_params)] struct T2 {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] struct T3 { #[proptest(no_params)] #[proptest(no_params)] field: Vec, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] struct T4( #[proptest(no_params)] #[proptest(no_params)] usize, ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] #[proptest(no_params)] #[proptest(no_params)] enum T5 { V0, } #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| # [proptest_derive, E0017] //~| # [proptest_derive, E0029] enum T6 { #[proptest(no_params)] #[proptest(no_params)] V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] enum T7 { V0 { #[proptest(no_params)] #[proptest(no_params)] foo: &'static str, }, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] enum T8 { V0(#[proptest(no_params)] #[proptest(no_params)] bool) } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] enum T9 { #[proptest(no_params)] #[proptest(no_params)] V0(bool), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] enum T10 { #[proptest(no_params)] #[proptest(no_params)] V0 { bar: bool }, } #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| # [proptest_derive, E0017] //~| # [proptest_derive, E0030] #[proptest(no_params, no_params)] struct T11; #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| # [proptest_derive, E0017] //~| # [proptest_derive, E0030] #[proptest(no_params, no_params)] struct T12(); #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| # [proptest_derive, E0017] //~| # [proptest_derive, E0030] #[proptest(no_params, no_params)] struct T13 {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] struct T14 { #[proptest(no_params, no_params)] field: Vec, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] struct T15( #[proptest(no_params, no_params)] usize, ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] #[proptest(no_params, no_params)] enum T16 { V0, } #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| # [proptest_derive, E0017] //~| # [proptest_derive, E0029] enum T17 { #[proptest(no_params, no_params)] V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] enum T18 { V0 { #[proptest(no_params, no_params)] foo: &'static str, }, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] enum T19 { V0(#[proptest(no_params, no_params)] bool) } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] enum T20 { #[proptest(no_params, no_params)] V0(bool), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] enum T21 { #[proptest(no_params, no_params)] V0 { bar: bool }, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] enum T22 { #[proptest(skip, skip)] V0, V1, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] enum T23 { V0, #[proptest(w = 1, w = 2)] V1, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] enum T24 { V0, #[proptest(weight = 1, weight = 2)] V1, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] #[proptest(params = "String", params = "u8")] enum T25 { V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] #[proptest(params = "String", params = "u8")] struct T26 { field: String, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] struct T27 { #[proptest(value = "1", value = "3")] field: u8, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0017] #[proptest(no_bound, no_bound)] struct T28 { field: T, } proptest-derive-0.4.0/tests/compile-fail/E0018-unknown-mod.rs000064400000000000000000000042701046102023000220040ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0018] #[proptest(no_bounds)] struct T0(T); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0018] enum T1 { #[proptest(weights = 1)] V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0018] enum T2 { #[proptest(weighted = 1)] V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0018] enum T3 { V0( #[proptest(strat = "1..0")] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0018] enum T4 { V0( #[proptest(strategies = "1..0")] u8 ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0018] struct T5 { #[proptest(values = "0")] field: u8, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0018] struct T6 { #[proptest(valued = "0")] field: u8, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0018] struct T7 { #[proptest(fix = "0")] field: u8, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0018] struct T8 { #[proptest(fixed = "0")] field: u8, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0018] #[proptest(param = "u8")] enum T9 { V0(u8), } // Show that E0018 is non-fatal. #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0018] //~| [proptest_derive, E0011] #[proptest(parameters = "u8")] enum T10 { #[proptest(params = "u8")] V0(u8), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0018] #[proptest(no_param)] struct T11; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0018] #[proptest(no_parameters)] struct T12; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0018] #[proptest(foobar)] struct T13; proptest-derive-0.4.0/tests/compile-fail/E0019-no_params-malformed.rs000064400000000000000000000014041046102023000234500ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} // Show non-fatal: #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0019] //~| [proptest_derive, E0007] #[proptest(no_params = 1, value("T0(u8)"))] struct T0(u8); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0019] #[proptest(no_params(2))] struct T1(u8); proptest-derive-0.4.0/tests/compile-fail/E0020-skip-malformed.rs000064400000000000000000000013721046102023000224330ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} // Show non fatal: #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0020] //~| [proptest_derive, E0007] #[proptest(skip = 1, value = "T0(1)")] struct T0(u8); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0020] #[proptest(skip(2))] struct T1(u8); proptest-derive-0.4.0/tests/compile-fail/E0021-weight-malformed.rs000064400000000000000000000026671046102023000227650ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} // Show non-fatal: #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0021] //~| [proptest_derive, E0008] #[proptest(weight)] #[proptest(skip)] struct NonFatal; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0021] enum T0 { #[proptest(weight)] V1 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0021] enum T1 { #[proptest(weight("abcd"))] V1 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0021] enum T2 { #[proptest(weight("1.0"))] V1 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0021] enum T3 { #[proptest(weight("true"))] V1 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0021] enum T4 { #[proptest(weight = "true")] V1 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0021] enum T5 { #[proptest(weight = true)] V1 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0021] enum T6 { #[proptest(weight(true))] V1 } proptest-derive-0.4.0/tests/compile-fail/E0022-overspec-param.rs000064400000000000000000000012501046102023000224420ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0022] #[proptest(no_params, params = "u8")] enum T0 { V1 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0022] #[proptest(no_params, params = "u8")] struct T1 { field: String, } proptest-derive-0.4.0/tests/compile-fail/E0023-params-malformed-expr.rs000064400000000000000000000032451046102023000237300ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0023] #[proptest(params = "1/2")] enum T0 { V1 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0023] #[proptest(params = ";;;")] struct T1 { field: String, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0023] enum T2 { #[proptest(params = "Vec<1 + u8>")] V1 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0023] enum T3 { V1 { #[proptest(params = "!!")] field: Box, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0023] struct T4 { #[proptest(params = "~")] field: String, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0023] #[proptest(params("1/2"))] enum T5 { V1 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0023] #[proptest(params(";;;"))] struct T6 { field: String, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0023] enum T7 { #[proptest(params("Vec<1 + u8>"))] V1 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0023] enum T8 { V1 { #[proptest(params("!!"))] field: Box, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0023] struct T9 { #[proptest(params("~"))] field: String, } proptest-derive-0.4.0/tests/compile-fail/E0023-params-malformed.rs000064400000000000000000000017731046102023000227600ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate proptest_derive; use proptest_derive::Arbitrary; fn main() {} // Show non-fatal: #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0023] //~| [proptest_derive, E0008] #[proptest(skip)] #[proptest(params)] struct NonFatal; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0023] #[proptest(params)] enum T0 { V1 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0023] enum T2 { #[proptest(params)] V1 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0023] enum T3 { V1 { #[proptest(params)] field: Box, } } proptest-derive-0.4.0/tests/compile-fail/E0025-overspec-strat.rs000064400000000000000000000053341046102023000225110ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} // value + strategy: #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] #[proptest(value = "T0(0)", strategy = "(0..6).prop_map(T1)")] struct T0(u8); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] struct T1 { #[proptest(value = "1", strategy = "(0..1).prop_map(T1)")] field: u8 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] struct T2( #[proptest(value = "1", strategy = "(0..1).prop_map(T1)")] u8 ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] enum T3 { V0 { #[proptest(value = "1", strategy = "0..1")] field: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] enum T4 { V0( #[proptest(value = "1", strategy = "0..1")] u8 ), } // value + regex: #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] #[proptest(value = "T6(String::new())", regex = "a")] struct T6(String); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] struct T7 { #[proptest(value = "Vec::new()", regex = "a(b)")] field: Vec } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] struct T8( // We test with a type that won't work to ensure that the test fails before. #[proptest(value = "1", regex = "a|b")] u8 ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] enum T9 { V0 { #[proptest(value = "2", regex = "[\n\t]")] field: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] enum T10 { V0( #[proptest(value = "3", regex = "a+")] u8 ), } // regex + strategy: #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] #[proptest(strategy = "0..1", regex = "a")] struct T11(String); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] struct T12 { #[proptest(regex = "a(b)", strategy = "1..2")] field: Vec } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] struct T13( #[proptest(strategy = "1", regex = "a|b")] u8 ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] enum T14 { V0 { #[proptest(regex = "[\n\t]", strategy = "1..=2")] field: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0025] enum T15 { V0( #[proptest(strategy = "3", regex = "a+")] u8 ), } proptest-derive-0.4.0/tests/compile-fail/E0026-strategy-malformed-expr.rs000064400000000000000000000052651046102023000243160ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] enum T0 { V1 { #[proptest(strategy = "random garbage")] field: u8, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] enum T1 { V1( #[proptest(strategy = "random garbage")] u8, ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] struct T2 { #[proptest(strategy = "random garbage")] field: String, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] struct T3( #[proptest(strategy = "random garbage")] String ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] enum T4 { V1 { #[proptest(value = "random garbage")] field: u8, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] enum T5 { V1( #[proptest(value = "random garbage")] u8, ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] struct T6 { #[proptest(value = "random garbage")] field: String, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] struct T7( #[proptest(value = "random garbage")] String ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] enum T8 { V1 { #[proptest(strategy("random garbage"))] field: u8, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] enum T9 { V1( #[proptest(strategy("random garbage"))] u8, ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] struct T10 { #[proptest(strategy("random garbage"))] field: String, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] struct T11( #[proptest(strategy("random garbage"))] String ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] enum T12 { V1 { #[proptest(value("random garbage"))] field: u8, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] enum T13 { V1( #[proptest(value("random garbage"))] u8, ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] struct T14 { #[proptest(value("random garbage"))] field: String, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] struct T15( #[proptest(value("random garbage"))] String ); proptest-derive-0.4.0/tests/compile-fail/E0026-strategy-malformed.rs000064400000000000000000000025731046102023000233410ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} // Show non-fatal: #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0026] //~| [proptest_derive, E0008] #[proptest(strategy)] #[proptest(skip)] struct NonFatal; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] enum T1 { V1 { #[proptest(strategy)] batman: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] struct T3 { #[proptest(strategy("///"))] field: usize, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] struct T4( #[proptest(strategy)] usize, ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] enum T5 { V1 { #[proptest(value)] batman: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] struct T6 { #[proptest(value)] field: usize, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0026] struct T7( #[proptest(value)] usize, ); proptest-derive-0.4.0/tests/compile-fail/E0027-filter-malformed-expr.rs000064400000000000000000000063301046102023000237340ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] enum T0 { V1 { #[proptest(filter = "random garbage")] field: u8, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] enum T1 { V1( #[proptest(filter = "random garbage")] u8, ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] struct T2 { #[proptest(filter = "random garbage")] field: String, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] struct T3( #[proptest(filter = "random garbage")] String ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] enum T4 { V1 { #[proptest(filter("random garbage"))] field: u8, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] enum T5 { V1( #[proptest(filter("random garbage"))] u8, ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] struct T6 { #[proptest(filter("random garbage"))] field: String, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] struct T7( #[proptest(filter("random garbage"))] String ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] enum T8 { #[proptest(filter = "random garbage")] V1 { field: u8, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] enum T9 { #[proptest(filter = "random garbage")] V1( u8, ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] #[proptest(filter = "random garbage")] struct T10 { field: String, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] #[proptest(filter = "random garbage")] struct T11( String ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] enum T12 { #[proptest(filter("random garbage"))] V1 { field: u8, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] enum T13 { #[proptest(filter("random garbage"))] V1( u8, ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] #[proptest(filter("random garbage"))] struct T14 { field: String, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] #[proptest(filter("random garbage"))] struct T15( String ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] #[proptest(filter = "random garbage")] enum T16 { V1 { field: u8, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] #[proptest(filter = "random garbage")] enum T17 { V1( u8, ), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] #[proptest(filter("random garbage"))] enum T18 { V1 { field: u8, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] #[proptest(filter("random garbage"))] enum T19 { V1( u8, ), }proptest-derive-0.4.0/tests/compile-fail/E0027-filter-malformed.rs000064400000000000000000000034571046102023000227670ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} // Show non-fatal: #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0027] //~| [proptest_derive, E0008] #[proptest(filter)] #[proptest(skip)] struct NonFatal; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] struct T0 { #[proptest(filter)] field: usize, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] struct T1( #[proptest(filter)] usize, ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] enum T2 { V1 { #[proptest(filter)] batman: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] enum T3 { V1( #[proptest(filter)] u8 ) } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] enum T4 { #[proptest(filter)] V1 { batman: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] enum T5 { #[proptest(filter)] V1(u8) } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] #[proptest(filter)] enum T6 { V1 { batman: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] #[proptest(filter)] enum T7 { V1(u8) } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] #[proptest(filter = 1)] struct T8(u8); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0027] #[proptest(filter(1))] struct T9(u8);proptest-derive-0.4.0/tests/compile-fail/E0028-skipped-variant-has-filter.rs000064400000000000000000000046131046102023000246670ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| [proptest_derive, E0028] //~| [proptest_derive, E0006] enum NonFatal { #[proptest(skip, filter(foo))] V1(u8), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T0 { #[proptest(skip, filter(foo))] V1(u8), V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T1 { #[proptest( skip, filter(foo) )] V1 { field: u8 }, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T2 { #[proptest(skip)] V1( #[proptest(filter(foo))] u8 ), V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T3 { #[proptest(skip)] V1 { #[proptest(filter(foo))] field: u8 }, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T4 { #[proptest(skip, filter(foo))] V1(u8), V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T5 { #[proptest(skip, filter(foo))] V1 { field: u8 }, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T6 { #[proptest(skip)] V1( #[proptest(filter(foo))] u8 ), V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T7 { #[proptest(skip)] V1 { #[proptest(filter(foo))] field: usize }, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T8 { #[proptest(skip)] V1 { #[proptest(filter(foo))] field: usize }, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T9 { #[proptest(skip)] V1 { #[proptest(filter(foo))] field: usize }, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T10 { #[proptest(skip)] V1 { #[proptest(filter(foo))] field: usize }, V2, } proptest-derive-0.4.0/tests/compile-fail/E0028-skipped-variant-has-param.rs000064400000000000000000000034271046102023000245040ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| [proptest_derive, E0028] //~| [proptest_derive, E0006] enum NonFatal { #[proptest(skip, no_params)] V1, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T0 { #[proptest(skip, no_params)] V1, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T1 { #[proptest(skip, no_params)] V1(u8), V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T2 { #[proptest(skip, no_params)] V1 { field: String, }, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T3 { #[proptest(skip, params = "u8")] V1, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T4 { #[proptest(skip, params = "u8")] V1(u8), V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T5 { #[proptest(skip, params = "u8")] V1 { field: String, }, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T6 { #[proptest(skip)] V1( #[proptest(params = "u8")] u8 ), V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T7 { #[proptest(skip)] V1 { #[proptest(params = "u8")] field: String, }, V2, } proptest-derive-0.4.0/tests/compile-fail/E0028-skipped-variant-has-strat.rs000064400000000000000000000050401046102023000245320ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| [proptest_derive, E0028] //~| [proptest_derive, E0006] enum NonFatal { #[proptest(skip, strategy = "(0..10).prop_map(NonFatal::V1)")] V1(u8), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T0 { #[proptest(skip, strategy = "(0..10).prop_map(T0::V1)")] V1(u8), V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T1 { #[proptest( skip, strategy = "(0..10).prop_map(|field| T0::V1 { field })" )] V1 { field: u8 }, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T2 { #[proptest(skip)] V1( #[proptest(strategy = "0..10")] u8 ), V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T3 { #[proptest(skip)] V1 { #[proptest(strategy = "0..10")] field: u8 }, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T4 { #[proptest(skip, value = "T0::V1(1)")] V1(u8), V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T5 { #[proptest(skip, value = "T0::V1 { field: 3 }")] V1 { field: u8 }, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T6 { #[proptest(skip)] V1( #[proptest(value = "42")] u8 ), V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T7 { #[proptest(skip)] V1 { #[proptest(value = "1337")] field: usize }, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T8 { #[proptest(skip)] V1 { #[proptest(value("1337"))] field: usize }, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T9 { #[proptest(skip)] V1 { #[proptest(value(1337))] field: usize }, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T10 { #[proptest(skip)] V1 { #[proptest(value = 1337)] field: usize }, V2, } proptest-derive-0.4.0/tests/compile-fail/E0028-skipped-variant-has-weight.rs000064400000000000000000000020131046102023000246610ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| [proptest_derive, E0028] //~| [proptest_derive, E0006] enum NonFatal { #[proptest(skip, weight = 2)] V1, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T0 { #[proptest(skip, weight = 2)] V1, V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T1 { #[proptest(skip, w = 3)] V1(u8), V2, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0028] enum T2 { #[proptest(skip, w = 3)] V1 { field: String, }, V2, } proptest-derive-0.4.0/tests/compile-fail/E0029-filter-on-unit-variant.rs000064400000000000000000000025451046102023000240530ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0029] //~| [proptest_derive, E0008] enum NonFatal { #[proptest(filter(foo))] V0, V1 { #[proptest(skip)] field: usize, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T0 { #[proptest(filter(foo))] V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T1 { #[proptest(filter(foo))] V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T2 { #[proptest(filter(foo))] V0 {}, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T3 { #[proptest(filter(foo))] V0 {}, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T4 { #[proptest(filter(foo))] V0(), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T5 { #[proptest(filter(foo))] V0(), } proptest-derive-0.4.0/tests/compile-fail/E0029-params-on-unit-variant.rs000064400000000000000000000025471046102023000240530ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0029] //~| [proptest_derive, E0008] enum NonFatal { #[proptest(params = "u8")] V0, V1 { #[proptest(skip)] field: usize, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T0 { #[proptest(no_params)] V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T1 { #[proptest(params = "u8")] V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T2 { #[proptest(no_params)] V0 {}, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T3 { #[proptest(params = "u8")] V0 {}, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T4 { #[proptest(no_params)] V0(), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T5 { #[proptest(params = "u8")] V0(), } proptest-derive-0.4.0/tests/compile-fail/E0029-strategy-on-unit-variant.rs000064400000000000000000000034131046102023000244230ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0029] //~| [proptest_derive, E0008] enum NonFatal { #[proptest(strategy = "Just(T0::V0)")] V0, V1 { #[proptest(skip)] field: usize, } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T0 { #[proptest(strategy = "Just(T0::V0)")] V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T1 { #[proptest(value = "T0::V0")] V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T2 { #[proptest(strategy = "Just(T0::V0)")] V0 {}, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T3 { #[proptest(value = "T0::V0")] V0 {}, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T4 { #[proptest(strategy = "Just(T0::V0)")] V0(), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T5 { #[proptest(value = "T0::V0")] V0(), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T6 { #[proptest(regex = "a+")] V0, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T7 { #[proptest(regex = "b*")] V0 {}, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0029] enum T8 { #[proptest(regex = "a|b")] V0(), } proptest-derive-0.4.0/tests/compile-fail/E0030-params-on-unit-struct.rs000064400000000000000000000030541046102023000237150ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} // It happens that no other error will follow E0030 so this is not as proper // a check that we wanted to ensure that E0030 is non-fatal. #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors //~| [proptest_derive, E0008] //~| [proptest_derive, E0030] #[proptest(params = "u8")] #[proptest(skip)] struct T0; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0030] #[proptest(no_params)] struct T1; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0030] #[proptest(params = "u8")] struct T2 {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0030] #[proptest(no_params)] struct T3 {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0030] #[proptest(params = "u8")] struct T4(); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0030] #[proptest(no_params)] struct T5(); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0030] #[proptest(filter(foo))] struct T6; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0030] #[proptest(filter(foo))] struct T7(); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0030] #[proptest(filter(foo))] struct T8 {}proptest-derive-0.4.0/tests/compile-fail/E0031-no-bound-non-tyvar.rs000064400000000000000000000022711046102023000231760ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0031] //~| [proptest_derive, E0008] struct T1 { #[proptest(no_bound)] #[proptest(skip)] field: ::std::marker::PhantomData, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0031] struct T2( #[proptest(no_bound)] ::std::marker::PhantomData, ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0031] enum T3 { #[proptest(no_bound)] V1(T), } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0031] enum T4 { #[proptest(no_bound)] V1 { field: T } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0031] enum T5 { V1( #[proptest(no_bound)] T ), } proptest-derive-0.4.0/tests/compile-fail/E0032-no-bound-malformed.rs000064400000000000000000000045041046102023000232110ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} // Show non-fatal: #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0032] //~| [proptest_derive, E0007] #[proptest(no_bound = "...", value("TU0"))] struct TU0; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] #[proptest(no_bound("..."))] struct TU1; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] #[proptest(no_bound = "...")] struct TU2 {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] #[proptest(no_bound("..."))] struct TU3 {} #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] #[proptest(no_bound = "...")] struct TU4(); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] #[proptest(no_bound("..."))] struct TU5(); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] #[proptest(no_bound = "...")] struct T0 { field: u8 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] #[proptest(no_bound("..."))] struct T1 { field: u8 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] #[proptest(no_bound = "...")] struct T2(u8); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] #[proptest(no_bound("..."))] struct T3(u8); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] struct T4 { #[proptest(no_bound = "...")] field: u8 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] struct T5 { #[proptest(no_bound("..."))] field: u8 } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] struct T6( #[proptest(no_bound = "...")] u8 ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] struct T7( #[proptest(no_bound("..."))] u8 ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] #[proptest(no_bound("..."))] enum T8 { V1, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0032] enum T9 { #[proptest(no_bound("..."))] V1, } proptest-derive-0.4.0/tests/compile-fail/E0033-weight-overflow.rs000064400000000000000000000013111046102023000226460ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} // Show non-fatal: #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0033] //~| [proptest_derive, E0008] enum T0<#[proptest(skip)] T> { #[proptest(weight = 4294967290)] V0(T), #[proptest(weight = 5)] V1, V2, } proptest-derive-0.4.0/tests/compile-fail/E0034-regex-malformed.rs000064400000000000000000000031271046102023000226040ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} // Show non-fatal: #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0034] //~| [proptest_derive, E0008] #[proptest(regex)] #[proptest(skip)] struct NonFatal; #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0034] enum T1 { V1 { #[proptest(regex)] batman: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0034] struct T3 { #[proptest(regex)] field: usize, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0034] struct T4( #[proptest(regex)] usize, ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0034] enum T5 { V1 { #[proptest(regex)] batman: u8 } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0034] struct T6 { #[proptest(regex)] field: usize, } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0034] struct T7( #[proptest(regex)] usize, ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0034] struct T8( #[proptest(regex = 1)] String, ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0034] struct T9( #[proptest(regex = true)] String, ); proptest-derive-0.4.0/tests/compile-fail/E0035-cant_set_param_and_regex.rs000064400000000000000000000047521046102023000245300ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} // Show non-fatal: #[derive(Debug, Arbitrary)] //~ ERROR: 2 errors: //~| [proptest_derive, E0035] //~| [proptest_derive, E0008] #[proptest(skip)] struct NonFatal { #[proptest(params(u8), regex = "a+")] field: String } // structs: #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0035] struct T0 { #[proptest(params(u8), regex = "a*")] field: String } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0035] struct T1 { #[proptest(params = "u8", regex("b+"))] field: String } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0035] struct T2( #[proptest(params("u8"), regex = "a|b")] Vec ); #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0035] struct T3( #[proptest(params("u8"), regex = "a+")] Vec ); // enum fields: #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0035] enum T4 { V0 { #[proptest(params(u8), regex = "a*")] field: String } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0035] enum T5 { V0 { #[proptest(params = "u8", regex("b+"))] field: String } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0035] enum T6 { V0( #[proptest(params("u8"), regex = "a|b")] Vec ) } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0035] enum T7 { V0( #[proptest(params("u8"), regex = "a+")] Vec ) } // enum variants: #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0035] enum T8 { #[proptest(params(u8), regex = "a*")] V0 { field: String } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0035] enum T9 { #[proptest(params = "u8", regex("b+"))] V0 { field: String } } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0035] enum T10 { #[proptest(params("u8"), regex = "a|b")] V0( Vec ) } #[derive(Debug, Arbitrary)] //~ ERROR: [proptest_derive, E0035] enum T11 { #[proptest(params("u8"), regex = "a+")] V0( Vec ) } proptest-derive-0.4.0/tests/compile-fail/E0658-no-bare-modifiers.rs000064400000000000000000000011341046102023000230400ustar 00000000000000// Copyright 2019 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; #[macro_use] extern crate proptest; use proptest::prelude::*; fn main() {} #[derive(Arbitrary, Debug)] struct T0 { #[no_params] //~ ERROR: cannot find attribute `no_params` in this scope field: usize, } proptest-derive-0.4.0/tests/compile-fail/must-be-debug.rs000064400000000000000000000007551046102023000215010ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} #[derive(Arbitrary)] struct Foo { x: usize } //~ `Foo` doesn't implement `Debug` [E0277] proptest-derive-0.4.0/tests/compile-fail/no-arbitrary.rs000064400000000000000000000011141046102023000214400ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} struct T0; #[derive(Debug, Arbitrary)] //~ the trait bound `T0: Arbitrary` is not satisfied [E0277] struct T1 { f0: T0, } //~ the trait bound `T0: Arbitrary` is not satisfied [E0277] proptest-derive-0.4.0/tests/compile-fail/regex_wrong_type.rs000064400000000000000000000042411046102023000224220ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; fn main() {} fn make_regex() -> &'static str { "a|b" } // struct: #[derive(Debug, Arbitrary)] //~ StrategyFromRegex` is not satisfied [E0277] struct T0 { #[proptest(regex = "a+")] f0: (), } #[derive(Debug, Arbitrary)] //~ StrategyFromRegex` is not satisfied [E0277] struct T1 { #[proptest(regex("a*"))] f0: u8, } #[derive(Debug, Arbitrary)] //~ StrategyFromRegex` is not satisfied [E0277] struct T2 { #[proptest(regex(make_regex))] f0: Vec, } #[derive(Debug, Arbitrary)] //~ StrategyFromRegex` is not satisfied [E0277] struct T3( #[proptest(regex = "a+")] (), ); #[derive(Debug, Arbitrary)] //~ StrategyFromRegex` is not satisfied [E0277] struct T4( #[proptest(regex("a*"))] u8, ); #[derive(Debug, Arbitrary)] //~ StrategyFromRegex` is not satisfied [E0277] struct T5( #[proptest(regex(make_regex))] Vec, ); // enum: #[derive(Debug, Arbitrary)] //~ StrategyFromRegex` is not satisfied [E0277] enum T6 { V0 { #[proptest(regex = "a+")] f0: (), } } #[derive(Debug, Arbitrary)] //~ StrategyFromRegex` is not satisfied [E0277] enum T7 { V0 { #[proptest(regex("a*"))] f0: u8, } } #[derive(Debug, Arbitrary)] //~ StrategyFromRegex` is not satisfied [E0277] enum T8 { V0 { #[proptest(regex(make_regex))] f0: Vec, } } #[derive(Debug, Arbitrary)] //~ StrategyFromRegex` is not satisfied [E0277] enum T9 { V0( #[proptest(regex = "a+")] (), ) } #[derive(Debug, Arbitrary)] //~ StrategyFromRegex` is not satisfied [E0277] enum T10 { V0( #[proptest(regex("a*"))] u8, ) } #[derive(Debug, Arbitrary)] //~ StrategyFromRegex` is not satisfied [E0277] enum T11 { V0( #[proptest(regex(make_regex))] Vec, ) } proptest-derive-0.4.0/tests/compiletest.rs000064400000000000000000000016031046102023000170210ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. extern crate compiletest_rs as ct; use std::env; fn run_mode(src: &'static str, mode: &'static str) { let mut config = ct::Config::default(); config.mode = mode.parse().expect("invalid mode"); config.target_rustcflags = Some("-L ../target/debug/deps --edition=2018".to_owned()); if let Ok(name) = env::var("TESTNAME") { config.filters = vec![name]; } config.src_base = format!("tests/{}", src).into(); ct::run_tests(&config); } #[test] fn compile_test() { run_mode("compile-fail", "compile-fail"); } proptest-derive-0.4.0/tests/enum.rs000064400000000000000000000133031046102023000154350ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(never_type)] use proptest::prelude::Arbitrary; use proptest_derive::Arbitrary; #[derive(Debug, Arbitrary)] enum T1 { V1, } #[derive(Debug, Arbitrary)] enum T2 { V1(), V2 {}, } #[derive(Debug, Arbitrary)] enum T3 { V1(), V2 {}, V3, } #[derive(Debug, Arbitrary)] enum T4 { V1, V2(), V3, V4 {}, } #[derive(Debug, Arbitrary)] enum T5 { V1, V2, V3, V4 {}, V5(), } #[derive(Debug, Arbitrary)] enum T6 { V1(), V2, V3 {}, V4, V5, V6, } #[derive(Debug, Arbitrary)] enum T7 { V1, V2, V3, V4 {}, V5, V6, V7(), } #[derive(Debug, Arbitrary)] enum T8 { V1, V2, V3(), V4, V5, V6 {}, V7, V8, } #[derive(Debug, Arbitrary)] enum T9 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, } #[derive(Debug, Arbitrary)] enum T10 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, } #[derive(Debug, Arbitrary)] enum T11 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, } #[derive(Debug, Arbitrary)] enum T12 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, V12, } #[derive(Debug, Arbitrary)] enum T13 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, V12, V13, } #[derive(Debug, Arbitrary)] enum T14 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, V12, V13, V14, } #[derive(Debug, Arbitrary)] enum T15 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, V12, V13, V14, V15, } #[derive(Debug, Arbitrary)] enum T16 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, } #[derive(Debug, Arbitrary)] enum T17 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, } #[derive(Debug, Arbitrary)] enum T18 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, } #[derive(Debug, Arbitrary)] enum T19 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, } #[derive(Debug, Arbitrary)] enum T20 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, } #[derive(Debug, Arbitrary)] enum T21 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, V21, } #[derive(Debug, Arbitrary)] enum T22 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, V21, V22, } #[derive(Debug, Arbitrary)] enum T23 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, V21, V22, V23, } #[derive(Debug, Arbitrary)] enum T24 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, V21, V22, V23, V24, } #[derive(Debug, Arbitrary)] enum T25 { V1, V2, V3, V4, V5 {}, V6(), V7, V8, V9, V10, V11, V12, V13, V14, V15, V16, V17, V18, V19, V20, V21, V22, V23, V24, V25, } #[derive(Clone, Debug, Arbitrary)] enum Alan { A(usize), B(String), C(()), D(u32), E(f64), F(char), } #[derive(Clone, Debug, Arbitrary)] enum SameType { A(usize), B(usize), } #[derive(Arbitrary, Debug)] enum OneTwo { One(u8), Two(u8, u8), } #[derive(Arbitrary, Debug)] enum ZeroOneTwo { Zero, One(u8), Two(u8, u8), } #[derive(Arbitrary, Debug)] enum Nested { First(SameType), Second(ZeroOneTwo, OneTwo), } #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); } proptest-derive-0.4.0/tests/filter.rs000064400000000000000000000132021046102023000157540ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use proptest::prelude::*; use proptest_derive::Arbitrary; fn even(x: &usize) -> bool { x % 2 == 0 } fn rem3(x: &usize) -> bool { x % 3 == 0 } #[derive(Copy, Clone)] struct Param(usize); impl Default for Param { fn default() -> Self { Param(100) } } #[derive(Debug, Arbitrary)] #[proptest(filter("|x| x.foo % 3 == 0"))] struct T0 { #[proptest(no_params, filter(even))] foo: usize, #[proptest(filter("|x| x % 2 == 1"))] bar: usize, #[proptest(strategy = "0..100usize", filter = "|x| x % 2 == 1")] baz: usize, #[proptest(value = "42", filter(even))] quux: usize, #[proptest(params(Param), strategy("0..=params.0"), filter("|x| *x > 2"))] wibble: usize, } #[derive(Debug, Arbitrary)] #[proptest(params(Param))] #[proptest(filter("|x| x.foo % 3 == 0"))] struct T1 { #[proptest(filter(even))] foo: usize, #[proptest(filter("|x| x % 2 == 1"))] bar: usize, #[proptest(strategy = "0..100usize", filter = "|x| x % 2 == 1")] baz: usize, #[proptest(value = "42", filter(even))] quux: usize, #[proptest(strategy("0..=params.0"), filter("|x| *x > 2"))] wibble: usize, } #[derive(Debug, Arbitrary)] #[proptest(filter("|x| x.0 % 3 == 0"))] struct T2( #[proptest(no_params, filter(even))] usize, #[proptest(filter("|x| x % 2 == 1"))] usize, #[proptest(strategy = "0..100usize", filter = "|x| x % 2 == 1")] usize, #[proptest(value = "42", filter(even))] usize, #[proptest(params(Param), strategy("0..=params.0"), filter("|x| *x > 2"))] usize, ); #[derive(Debug, Arbitrary)] #[proptest(filter("|x| x.0 % 3 == 0"))] struct T3( #[proptest(no_params, filter(even))] usize, #[proptest(filter("|x| x % 2 == 1"))] usize, #[proptest(strategy = "0..100usize", filter = "|x| x % 2 == 1")] usize, #[proptest(value = "42", filter(even))] usize, #[proptest(params(Param), strategy("0..=params.0"), filter("|x| *x > 2"))] usize, ); fn is_v0(v: &T4) -> bool { if let T4::V0 { .. } = v { true } else { false } } #[derive(Debug, Arbitrary)] #[proptest(filter(is_v0))] enum T4 { V0 { #[proptest(filter(even))] field: usize, }, V1, } fn t5_v0_rem_3(v: &T5) -> bool { if let T5::V0 { field } = v { rem3(&field) } else { false } } fn t5_v1_rem_5(v: &T5) -> bool { if let T5::V1(field) = v { field % 5 == 0 } else { false } } #[derive(Debug, Arbitrary)] enum T5 { #[proptest(filter(t5_v0_rem_3))] V0 { #[proptest(filter(even))] field: usize, }, #[proptest( strategy("(0..1000usize).prop_map(T5::V1)"), filter(t5_v1_rem_5) )] V1(usize), } fn t6_v0_rem_3(v: &T6) -> bool { if let T6::V0 { field } = v { rem3(&field) } else { false } } fn t6_v1_rem_5(v: &T6) -> bool { if let T6::V1(field) = v { field % 5 == 0 } else { false } } #[derive(Debug, Arbitrary)] #[proptest(params(Param))] enum T6 { #[proptest(filter(t6_v0_rem_3))] V0 { #[proptest(filter(even))] field: usize, }, #[proptest( strategy("(0..params.0).prop_map(T6::V1)"), filter(t6_v1_rem_5) )] V1(usize), } #[derive(Debug, Arbitrary)] struct T7 { #[proptest(filter(even), filter(rem3))] foo: usize, } proptest! { #[test] fn t0_test(v: T0) { assert!(even(&v.foo) && rem3(&v.foo)); assert!(!even(&v.bar)); assert!(!even(&v.baz) && v.baz < 100); assert!(even(&v.quux) && v.quux == 42); assert!(even(&v.quux) && v.quux == 42); assert!(v.wibble > 2 && v.wibble <= 100); } #[test] fn t1_test(v: T1) { assert!(even(&v.foo) && v.foo % 3 == 0); assert!(!even(&v.bar)); assert!(!even(&v.baz) && v.baz < 100); assert!(even(&v.quux) && v.quux == 42); assert!(v.wibble > 2 && v.wibble <= 100); } #[test] fn t2_test(v: T2) { assert!(even(&v.0) && v.0 % 3 == 0); assert!(!even(&v.1)); assert!(!even(&v.2) && v.2 < 100); assert!(even(&v.3) && v.3 == 42); assert!(v.4 > 2 && v.4 <= 100); } #[test] fn t3_test(v: T3) { assert!(even(&v.0) && v.0 % 3 == 0); assert!(!even(&v.1)); assert!(!even(&v.2) && v.2 < 100); assert!(even(&v.3) && v.3 == 42); assert!(v.4 > 2 && v.4 <= 100); } #[test] fn t4_test(v: T4) { assert!(if let T4::V0 { field } = v { even(&field) } else { false }); } #[test] fn t5_test(v: T5) { match v { T5::V0 { field } => assert!(rem3(&field) && even(&field)), T5::V1(field) => assert!(field < 1000 && field % 5 == 0), } } #[test] fn t6_test(v: T6) { match v { T6::V0 { field } => assert!(rem3(&field) && even(&field)), T6::V1(field) => assert!(field < 100 && field % 5 == 0), } } #[test] fn t7_test(v: T7) { assert!(even(&v.foo) && rem3(&v.foo)); } } #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); } proptest-derive-0.4.0/tests/misc.rs000064400000000000000000000034301046102023000154240ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use proptest::prelude::Arbitrary; use proptest::strategy::Just; use proptest_derive::Arbitrary; // TODO: An idea. /* #[derive(Debug, Arbitrary)] #[proptest(with = "Foo::ctor(1337, :usize:.other_fn(:f64:, #0..7#))")] struct Foo { //.. } */ #[derive(Default)] struct Complex; #[derive(Debug, Arbitrary)] #[proptest(params(Complex))] enum Foo { #[proptest(value = "Foo::F0(1, 1)")] F0(usize, u8), } #[derive(Clone, Debug, Arbitrary)] #[proptest(params = "usize")] enum A { B, #[proptest(strategy = "Just(A::C(1))")] C(usize), } #[derive(Clone, Debug, Arbitrary)] enum Bobby { #[proptest(no_params)] B(usize), #[proptest(no_params, value = "Bobby::C(1)")] C(usize), #[proptest(no_params, strategy = "Just(Bobby::D(1))")] D(usize), #[proptest(params(Complex), value = "Bobby::E(1)")] E(usize), #[proptest(params(Complex), strategy = "Just(Bobby::F(1))")] F(usize), } #[derive(Clone, Debug, Arbitrary)] enum Quux { B(#[proptest(no_params)] usize), C(usize, String), #[proptest(value = "Quux::D(2, \"a\".into())")] D(usize, String), #[proptest(strategy = "Just(Quux::E(1337))")] E(u32), F { #[proptest(strategy = "10usize..20usize")] _foo: usize, }, } #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); } proptest-derive-0.4.0/tests/no_bound.rs000064400000000000000000000025031046102023000162740ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use proptest::prelude::Arbitrary; use proptest_derive::Arbitrary; #[derive(Debug)] struct NotArbitrary; /// Ensure that we can't determine that this is PhantomData syntactically. type HidePH = ::std::marker::PhantomData; /* // TODO handle this... #[derive(Debug, Arbitrary)] struct T1<#[proptest(no_bound)] T>(HidePH); #[derive(Debug, Arbitrary)] struct T2(T1); #[derive(Debug, Arbitrary)] struct T3< #[proptest(no_bound)] A, B, #[proptest(no_bound)] G, > { alpha: HidePH, beta: B, gamma: HidePH, } #[derive(Debug, Arbitrary)] struct T4(T3); */ #[derive(Debug, Arbitrary)] #[proptest(no_bound)] struct T5(HidePH<(A, B, C)>); #[derive(Debug, Arbitrary)] struct T6(T5); #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} /* assert_arbitrary::(); assert_arbitrary::(); */ assert_arbitrary::(); } proptest-derive-0.4.0/tests/params.rs000064400000000000000000000060041046102023000157540ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use proptest::prelude::{ any_with, prop_assert, prop_assert_eq, proptest, Arbitrary, }; use proptest_derive::Arbitrary; struct ComplexType { max: u64, } impl Default for ComplexType { fn default() -> Self { Self { max: 10 } } } #[derive(Debug, Arbitrary)] #[proptest(params(ComplexType))] struct TopHasParams { _string: usize, #[proptest(strategy = "0..params.max")] int: u64, } #[derive(Debug, Arbitrary)] #[proptest(no_params)] struct TopNoParams { _stuff: usize, } #[derive(Debug, Arbitrary)] struct InnerNoParams { string: String, #[proptest(no_params)] has: TopHasParams, } #[derive(Debug, Arbitrary)] #[proptest(params(u64))] struct TPIS { #[proptest(strategy = "\"a+\"")] string: String, #[proptest(strategy = "3..=params")] int: u64, } #[derive(Debug, Arbitrary)] struct Parallel { #[proptest(params = "&'static str", strategy = "params")] string: String, #[proptest(params(u8), strategy = "0i64..params as i64")] int: i64, } #[derive(Debug, Arbitrary)] struct Parallel2 { #[proptest(params("&'static str"), strategy = "params")] _string: String, #[proptest(params("u8"), strategy = "0i64..params as i64")] _int: i64, } const MAX: ComplexType = ComplexType { max: 5 }; proptest! { #[test] fn top_has_params(v in any_with::(MAX)) { prop_assert!(v.int < 5); } #[test] fn top_no_params(_ in any_with::(())) {} #[test] fn inner_params(inner in any_with::("\\s+".into())) { prop_assert!(inner.has.int < 10); prop_assert!(inner.string.trim().is_empty()); } #[test] fn top_param_inner_strat(inner in any_with::(6)) { prop_assert!(inner.int <= 6); prop_assert!(inner.int >= 3); prop_assert_eq!( 0, inner.string.split("a").filter(|s| !s.is_empty()).count() ); } #[test] fn parallel_params(inner in any_with::(("[0-9]", 3))) { prop_assert!(inner.int >= 0); prop_assert!(inner.int < 3); prop_assert!(inner.string.chars().next().unwrap().is_digit(10)); } #[test] fn parallel_params2(inner in any_with::(("[0-9]", 3))) { prop_assert!(inner.int >= 0); prop_assert!(inner.int < 3); prop_assert!(inner.string.chars().next().unwrap().is_digit(10)); } } #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); } proptest-derive-0.4.0/tests/phantom.rs000064400000000000000000000027751046102023000161520ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use proptest::prelude::Arbitrary; use proptest_derive::Arbitrary; use std::marker; use std::marker::PhantomData; #[derive(Debug)] struct NotArbitrary; #[derive(Debug, Arbitrary)] struct T1(::std::marker::PhantomData); #[derive(Debug, Arbitrary)] struct T2(T1); #[derive(Debug, Arbitrary)] struct T3(marker::PhantomData); #[derive(Debug, Arbitrary)] struct T4(T3); #[derive(Debug, Arbitrary)] struct T5(PhantomData); #[derive(Debug, Arbitrary)] struct T6(T5); #[derive(Debug, Arbitrary)] struct T7(std::marker::PhantomData); #[derive(Debug, Arbitrary)] struct T8(T7); #[derive(Debug, Arbitrary)] struct T9 { _a: A, _b: B, c: PhantomData, } #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::>(); assert_arbitrary::(); assert_arbitrary::>(); assert_arbitrary::(); assert_arbitrary::>(); assert_arbitrary::(); assert_arbitrary::>(); assert_arbitrary::(); assert_arbitrary::>(); } proptest-derive-0.4.0/tests/regex.rs000064400000000000000000000112471046102023000156100ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use proptest::prelude::{proptest, Arbitrary, BoxedStrategy, Strategy}; use proptest::string::StrategyFromRegex; use proptest_derive::Arbitrary; fn mk_regex() -> &'static str { "[0-9][0-9]" } // struct: #[derive(Debug, Arbitrary)] struct T0 { #[proptest(regex = "a+")] foo: String, #[proptest(regex("b+"))] bar: String, #[proptest(regex(mk_regex))] baz: String, #[proptest(regex = "(a|b)+")] quux: Vec, #[proptest(regex("[abc]+"), filter("|c| c.len() < 4"))] wibble: Vec, #[proptest(regex(mk_regex))] wobble: Vec, } #[derive(Debug, Arbitrary)] struct T1( #[proptest(regex = "a+")] String, #[proptest(regex("b+"))] String, #[proptest(regex(mk_regex))] String, #[proptest(regex = "(a|b)+")] Vec, #[proptest(regex("[abc]+"), filter("|c| c.len() < 4"))] Vec, #[proptest(regex(mk_regex))] Vec, ); #[derive(Debug, Arbitrary)] struct T1r( #[proptest(regex = r"a+")] String, #[proptest(regex(r"b+"))] String, #[proptest(regex(mk_regex))] String, #[proptest(regex = r"(a|b)+")] Vec, #[proptest(regex(r"[abc]+"), filter("|c| c.len() < 4"))] Vec, #[proptest(regex(mk_regex))] Vec, ); // enum: #[derive(Debug, Arbitrary)] enum T2 { V0 { #[proptest(regex = "a+")] foo: String, #[proptest(regex("b+"))] bar: String, #[proptest(regex(mk_regex))] baz: String, #[proptest(regex = "(a|b)+")] quux: Vec, #[proptest(regex("[abc]+"), filter("|c| c.len() < 4"))] wibble: Vec, #[proptest(regex(mk_regex))] wobble: Vec, }, } #[derive(Debug, Arbitrary)] enum T3 { V0( #[proptest(regex = "a+")] String, #[proptest(regex("b+"))] String, #[proptest(regex(mk_regex))] String, #[proptest(regex = "(a|b)+")] Vec, #[proptest(regex("[abc]+"), filter("|c| c.len() < 4"))] Vec, #[proptest(regex(mk_regex))] Vec, ), } // Show that it works for new types and that `String` | `Vec` isn't // hardcoded into the logic: #[derive(Debug)] struct NewString(String); impl StrategyFromRegex for NewString { type Strategy = BoxedStrategy; fn from_regex(regex: &str) -> Self::Strategy { String::from_regex(regex).prop_map(NewString).boxed() } } #[derive(Debug, Arbitrary)] struct T4(#[proptest(regex = "a+")] NewString); fn check_aplus(x0: String) { assert!(x0.chars().count() > 0); assert!(x0.chars().all(|c: char| c == 'a')); } fn assert_adherence( x0: String, x1: String, x2: String, y0: Vec, y1: Vec, y2: Vec, ) { check_aplus(x0); assert!(x1.chars().count() > 0); assert!(x1.chars().all(|c: char| c == 'b')); assert!(x2.parse::().unwrap() < 100); assert!(y0.len() > 0); assert!(y0.iter().all(|c: &u8| [b'a', b'b'].contains(c))); assert!(y1.len() > 0 && y1.len() < 4); assert!(y1.iter().all(|c: &u8| [b'a', b'b', b'c'].contains(c))); assert!(y2.len() > 0); let test = y2 .iter() .all(|c: &u8| if let b'0'..=b'9' = c { true } else { false }); assert!(test); } proptest! { #[test] fn t0_adhering_to_regex(v: T0) { let T0 { foo: x0, bar: x1, baz: x2, quux: y0, wibble: y1, wobble: y2 } = v; assert_adherence(x0, x1, x2, y0, y1, y2); } #[test] fn t1_adhering_to_regex(v: T1) { let T1(x0, x1, x2, y0, y1, y2) = v; assert_adherence(x0, x1, x2, y0, y1, y2); } #[test] fn t1_r_adhering_to_regex(v: T1r) { let T1r(x0, x1, x2, y0, y1, y2) = v; assert_adherence(x0, x1, x2, y0, y1, y2); } #[test] fn t2_adhering_to_regex(v: T2) { let T2::V0 { foo: x0, bar: x1, baz: x2, quux: y0, wibble: y1, wobble: y2 } = v; assert_adherence(x0, x1, x2, y0, y1, y2); } #[test] fn t3_adhering_to_regex(v: T3) { let T3::V0(x0, x1, x2, y0, y1, y2) = v; assert_adherence(x0, x1, x2, y0, y1, y2); } #[test] fn t4_adhering_to_regex(v: T4) { check_aplus((v.0).0); } } #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); } proptest-derive-0.4.0/tests/skip.rs000064400000000000000000000021121046102023000154330ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(never_type)] #![allow(dead_code, unreachable_code)] use proptest::prelude::{prop_assert, prop_assert_eq, proptest, Arbitrary}; use proptest_derive::Arbitrary; #[derive(Debug, Arbitrary, PartialEq)] enum Ty1 { V1, V2(!), #[proptest(skip)] V3, } #[derive(Debug, Arbitrary, PartialEq)] enum Ty2 { V1, V2, #[proptest(skip)] V3, #[proptest(skip)] V4, } proptest! { #[test] fn ty1_always_v1(v: Ty1) { prop_assert_eq!(v, Ty1::V1); } #[test] fn ty_always_1_or_2(v: Ty2) { prop_assert!(v == Ty2::V1 || v == Ty2::V2); } } #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::(); assert_arbitrary::(); } proptest-derive-0.4.0/tests/strategy.rs000064400000000000000000000047661046102023000163500ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use proptest::prelude::{proptest, Arbitrary, Strategy}; use proptest_derive::Arbitrary; fn make_strategy(start: usize) -> impl Strategy { (start..100).prop_map(|x| x * 2) } fn make_strategy2() -> impl Strategy { make_strategy(88) } #[derive(Debug, Arbitrary)] struct T0 { #[proptest(strategy = "make_strategy(0)")] foo: usize, #[proptest(strategy("make_strategy(11)"))] bar: usize, #[proptest(strategy(make_strategy2))] baz: usize, } #[derive(Debug, Arbitrary)] struct T1( #[proptest(strategy = "make_strategy(22)")] usize, #[proptest(strategy("make_strategy(33)"))] usize, #[proptest(strategy(make_strategy2))] usize, ); #[derive(Debug, Arbitrary)] enum T2 { V0(#[proptest(strategy("make_strategy(44)"))] usize), V1 { #[proptest(strategy = "make_strategy(55)")] field: usize, }, V2(#[proptest(strategy = "make_strategy(66)")] usize), V3 { #[proptest(strategy("make_strategy(77)"))] field: usize, }, V4(#[proptest(strategy(make_strategy2))] usize), V5 { #[proptest(strategy(make_strategy2))] field: usize, }, } fn assert_consistency(start: usize, val: usize) { assert!(val % 2 == 0 && val < 200 && val >= (start * 2)); } proptest! { #[test] fn t0_test(v: T0) { assert_consistency(0, v.foo); assert_consistency(11, v.bar); assert_consistency(88, v.baz); } #[test] fn t1_test(v: T1) { assert_consistency(22, v.0); assert_consistency(33, v.1); assert_consistency(88, v.2); } #[test] fn t2_test(v: T2) { match v { T2::V0(v) => assert_consistency(44, v), T2::V1 { field } => assert_consistency(55, field), T2::V2(v) => assert_consistency(66, v), T2::V3 { field } => assert_consistency(77, field), T2::V4(v) => assert_consistency(88, v), T2::V5 { field } => assert_consistency(88, field), } } } #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); } proptest-derive-0.4.0/tests/struct.rs000064400000000000000000000037731046102023000160270ustar 00000000000000// Copyright 2019 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use proptest::prelude::Arbitrary; use proptest_derive::Arbitrary; #[derive(Debug, Arbitrary)] struct T1 { _f1: u8, } #[derive(Debug, Arbitrary)] struct T10 { _f1: char, _f2: String, _f3: u8, _f4: u16, _f5: u32, _f6: u64, _f7: u128, _f8: f32, _f9: f64, _f10: bool, } #[derive(Debug, Arbitrary)] struct T11 { _f1: char, _f2: String, _f3: u8, _f4: u16, _f5: u32, _f6: u64, _f7: u128, _f8: f32, _f9: f64, _f10: bool, _f11: char, } #[derive(Debug, Arbitrary)] struct T13 { _f1: char, _f2: String, _f3: u8, _f4: u16, _f5: u32, _f6: u64, _f7: u128, _f8: f32, _f9: f64, _f10: bool, _f11: char, _f12: String, _f13: u8, } #[derive(Debug, Arbitrary)] struct T19 { _f1: char, _f2: String, _f3: u8, _f4: u16, _f5: u32, _f6: u64, _f7: u128, _f8: f32, _f9: f64, _f10: bool, _f11: char, _f12: String, _f13: u8, _f14: u16, _f15: u32, _f16: u64, _f17: u128, _f18: f32, _f19: f64, } #[derive(Debug, Arbitrary)] struct T20 { _f1: char, _f2: String, _f3: u8, _f4: u16, _f5: u32, _f6: u64, _f7: u128, _f8: f32, _f9: f64, _f10: bool, _f11: char, _f12: String, _f13: u8, _f14: u16, _f15: u32, _f16: u64, _f17: u128, _f18: f32, _f19: f64, _f20: bool, } #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); } proptest-derive-0.4.0/tests/uninhabited-pass.rs000064400000000000000000000037531046102023000177370ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #![feature(never_type)] use proptest::prelude::{prop_assert_eq, proptest, Arbitrary}; use proptest_derive::Arbitrary; // Various arithmetic and basic things. #[allow(unreachable_code)] #[derive(Debug, Arbitrary, PartialEq)] enum Ty1 { // Ensure that all of the types below are deemed uninhabited: _V2(!), _V3([!; 1]), _V4([!; 2 - 1]), _V5([!; 2 * 1]), _V6([!; 2 / 2]), _V7([!; 0b0 ^ 0b1]), _V8([!; 0b1 & 0b1]), _V9([!; 0b1 | 0b0]), _V10([!; 0b10 << 1]), _V11([!; 0b10 >> 1]), _V12([!; !0 - 18446744073709551614]), _V13([!; 1 + 2 * (3 / 3)]), V1, } proptest! { #[test] fn ty1_always_v1(v1: Ty1) { prop_assert_eq!(v1, Ty1::V1); } } // Can't inspect type macros called as mac!(uninhabited_type). macro_rules! tymac { ($ignore: ty) => { u8 }; } #[derive(Debug, Arbitrary)] struct TyMac0 { _field: tymac!(!), } #[derive(Debug, Arbitrary)] struct TyMac1 { _baz: tymac!([!; 3 + 4]), } enum _TyMac2 { #[deny(dead_code)] V0(tymac!((u8, !, usize))), } // Can't inspect projections through associated types: trait Fun { type Prj; } impl Fun for ! { type Prj = u8; } impl Fun for (!, usize, !) { type Prj = u8; } #[derive(Debug, Arbitrary)] enum UsePrj0 { #[deny(dead_code)] V0(::Prj), } #[derive(Debug, Arbitrary)] enum UsePrj1 { #[deny(dead_code)] V0(<(!, usize, !) as Fun>::Prj), } #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); } proptest-derive-0.4.0/tests/units.rs000064400000000000000000000016661046102023000156440ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use proptest::prelude::Arbitrary; use proptest_derive::Arbitrary; #[derive(Debug, Arbitrary)] struct T0; #[derive(Debug, Arbitrary)] struct T1 {} #[derive(Debug, Arbitrary)] struct T2(); #[derive(Debug, Arbitrary)] enum T3 { V0, } #[derive(Debug, Arbitrary)] enum T4 { V1(), } #[derive(Debug, Arbitrary)] enum T5 { V2 {}, } #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); } proptest-derive-0.4.0/tests/value.rs000064400000000000000000000061561046102023000156150ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use proptest::prelude::{prop_assert, prop_assert_eq, proptest, Arbitrary}; use proptest_derive::Arbitrary; #[derive(Debug, Arbitrary)] struct T0 { #[proptest(value = "42")] field: usize, #[proptest(value("24"))] bar: usize, #[proptest(value = "24 + 24usize")] baz: usize, #[proptest(value = 1337)] quux: usize, #[proptest(value(7331))] wibble: usize, #[proptest(value("3 * 2 + 3usize / 3"))] wobble: usize, } #[derive(Debug, Arbitrary)] struct T1(#[proptest(value = "24")] usize); #[derive(Debug, Arbitrary)] enum T2 { V0, #[proptest(value = "T2::V1 { field: 1337 }")] V1 { field: usize, }, } #[derive(Debug, Arbitrary)] enum T3 { V0, #[proptest(value = "T3::V1(7331)")] V1(usize), } #[derive(Debug, Arbitrary)] enum T4 { V0, V1 { #[proptest(value = "6")] field: usize, }, } #[derive(Debug, Arbitrary)] enum T5 { V0, V1(#[proptest(value = "9")] usize), } #[derive(Debug, Arbitrary)] struct T6 { #[proptest(value = "\"alpha\".to_string()")] alpha: String, #[proptest(strategy = "0..100usize")] beta: usize, } fn foo() -> usize { 42 } #[derive(Debug, Arbitrary)] struct CallFun { #[proptest(value = "foo()")] foo: usize, #[proptest(value(foo))] bar: usize, } proptest! { #[test] fn t0_fixed_fields(v: T0) { prop_assert_eq!(v.field, 42); prop_assert_eq!(v.bar, 24); prop_assert_eq!(v.baz, 48); prop_assert_eq!(v.quux, 1337); prop_assert_eq!(v.wibble, 7331); prop_assert_eq!(v.wobble, 7); } #[test] fn t1_field_always_24(v: T1) { prop_assert_eq!(v.0, 24); } #[test] fn t2_v1_always_1337(v: T2) { if let T2::V1 { field } = v { prop_assert_eq!(field, 1337); } } #[test] fn t3_v1_always_7331(v: T3) { if let T3::V1(v) = v { prop_assert_eq!(v, 7331); } } #[test] fn t4_v1_always_1337(v: T4) { if let T4::V1 { field } = v { prop_assert_eq!(field, 6); } } #[test] fn t5_v1_always_7331(v: T5) { if let T5::V1(v) = v { prop_assert_eq!(v, 9); } } #[test] fn t6_alpha_beta(v: T6) { prop_assert_eq!(v.alpha, "alpha".to_string()); prop_assert!(v.beta < 100); } #[test] fn call_fun_always_42(v: CallFun) { assert_eq!(v.foo, 42); assert_eq!(v.bar, 42); } } #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); } proptest-derive-0.4.0/tests/value_param.rs000064400000000000000000000042321046102023000167660ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[macro_use] extern crate proptest_derive; use proptest::prelude::*; #[derive(Debug, Arbitrary)] enum T0 { #[proptest(params = "u8", value = "T0::V0(params / 2)")] V0(u8), } #[derive(Debug, Arbitrary)] enum T1 { #[proptest(params = "u8", value = "T1::V0 { field: params * 2 }")] V0 { field: u8 }, } #[derive(Debug, Arbitrary)] enum T2 { V0(#[proptest(params = "u8", value = "params.is_power_of_two()")] bool), } #[derive(Debug, Arbitrary)] enum T3 { V0 { #[proptest(params = "u8", value = "params * params")] field: u8, }, } #[derive(Debug, Arbitrary)] struct T4 { #[proptest(params = "u8", value = "params - 3")] field: u8, } fn add(x: u8) -> u8 { x + 1 } #[derive(Debug, Arbitrary)] struct T5(#[proptest(params = "u8", value = "add(params)")] u8); #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); } proptest! { #[test] fn t0_test(v in any_with::(4)) { let T0::V0(x) = v; assert_eq!(x, 2); } #[test] fn t1_test(v in any_with::(4)) { let T1::V0 { field: x } = v; assert_eq!(x, 8); } #[test] fn t2_test_true(v in any_with::(4)) { let T2::V0(x) = v; assert!(x); } #[test] fn t2_test_false(v in any_with::(10)) { let T2::V0(x) = v; assert!(!x); } #[test] fn t3_test(v in any_with::(4)) { let T3::V0 { field: x } = v; assert_eq!(x, 16); } #[test] fn t4_test(v in any_with::(4)) { assert_eq!(v.field, 1); } #[test] fn t5_test(v in any_with::(4)) { assert_eq!(v.0, 5); } } proptest-derive-0.4.0/tests/weight.rs000064400000000000000000000016741046102023000157700ustar 00000000000000// Copyright 2018 The proptest developers // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use proptest::prelude::Arbitrary; use proptest_derive::Arbitrary; #[derive(Debug, Arbitrary)] enum T1 { #[proptest(weight = "3")] V1, V2, } #[derive(Debug, Arbitrary)] enum T2 { V1, #[proptest(weight("3"))] V2, } #[derive(Debug, Arbitrary)] enum T3 { #[proptest(weight(3))] V1, V2, } #[derive(Debug, Arbitrary)] enum T4 { V1, #[proptest(weight = 3)] V2, } #[test] fn asserting_arbitrary() { fn assert_arbitrary() {} assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); assert_arbitrary::(); }