test_strategy/lib.rs
1// #![include_doc("../README.md", start("This crate provides two procedural macros, `#[derive(Arbitrary)]` and `#[proptest]`."))]
2//! This crate provides two procedural macros, `#[derive(Arbitrary)]` and `#[proptest]`.
3//!
4//! Each of these macros is an alternative to the following proptest's official macros.
5//!
6//! | [test-strategy][] | [proptest][] | [proptest-derive][] |
7//! | ------------------------------------------ | ----------------------------- | ----------------------------------- |
8//! | [`#[derive(Arbitrary)]`](#derivearbitrary) | | [`#[derive(Arbitrary)]`][offical-a] |
9//! | [`#[proptest]`](#proptest) | [`proptest ! { }`][offical-m] | |
10//!
11//! [test-strategy]: https://crates.io/crates/test-strategy
12//! [proptest]: https://crates.io/crates/proptest
13//! [proptest-derive]: https://crates.io/crates/proptest-derive
14//! [offical-m]: https://altsysrq.github.io/rustdoc/proptest/latest/proptest/macro.proptest.html
15//! [offical-a]: https://altsysrq.github.io/proptest-book/proptest-derive/modifiers.html
16//!
17//! The macros provided by this crate have the following advantages over the proptest's official macros.
18//!
19//! - Supports higher-order strategies. (`#[derive(Arbitrary)]` and `#[proptest]`)
20//! - Code formatting is not disabled. (`#[proptest]`)
21//!
22//! However, the syntax of this crate's macros are not compatible with the syntax of the official macros.
23//!
24//! ## Install
25//!
26//! Add this to your Cargo.toml:
27//!
28//! ```toml
29//! [dependencies]
30//! test-strategy = "0.2.1"
31//! proptest = "1.0.0"
32//! ```
33//!
34//! ## Example
35//!
36//! You can use `#[derive(Arbitrary)]` to automatically implement proptest's `Arbitrary` trait.
37//!
38//! ```rust
39//! use test_strategy::Arbitrary;
40//!
41//! #[derive(Arbitrary, Debug)]
42//! struct TestInputStruct {
43//! x: u32,
44//!
45//! #[strategy(1..10u32)]
46//! y: u32,
47//!
48//! #[strategy(0..#y)]
49//! z: u32,
50//! }
51//!
52//! #[derive(Arbitrary, Debug)]
53//! enum TestInputEnum {
54//! A,
55//! B,
56//! #[weight(3)]
57//! C,
58//! X(u32),
59//! Y(#[strategy(0..10u32)] u32),
60//! }
61//! ```
62//!
63//! You can define a property test by adding `#[proptest]` to the function.
64//!
65//! ```rust
66//! use test_strategy::proptest;
67//!
68//! #[proptest]
69//! fn my_test(_x: u32, #[strategy(1..10u32)] y: u32, #[strategy(0..#y)] z: u32) {
70//! assert!(1 <= y && y < 10);
71//! assert!(z <= y);
72//! }
73//! ```
74//!
75//! ## Helper attributes
76//!
77//! Helper attributes can be written in the following positions.
78//!
79//! | attribute | function | struct | enum | variant | field | function parameter |
80//! | --------------------------------------------------- | -------- | ------ | ---- | ------- | ----- | ------------------ |
81//! | [`#[strategy]`](#strategy) | | | | | ✔ | ✔ |
82//! | [`#[any]`](#any) | | | | | ✔ | ✔ |
83//! | [`#[weight]`](#weight) | | | | ✔ | | |
84//! | [`#[filter]`](#filter) | ✔ | ✔ | ✔ | ✔ | ✔ | ✔ |
85//! | [`#[by_ref]`](#by_ref) | | | | | ✔ | ✔ |
86//! | [`#[arbitrary(args = T)]`](#arbitraryargs--t) | | ✔ | ✔ | | | |
87//! | [`#[arbitrary(bound(...))]`](#arbitraryboundt1-t2-) | | ✔ | ✔ | ✔ | ✔ | |
88//! | [`#[arbitrary(dump)]`](#arbitrarydump) | | ✔ | ✔ | | | |
89//!
90//! ## `#[derive(Arbitrary)]`
91//!
92//! You can implement `proptest::arbitrary::Arbitrary` automatically by adding `#[derive(Arbitrary)]` to struct or enum declaration.
93//!
94//! By default, all fields are set using the strategy obtained by `proptest::arbitrary::any()`.
95//!
96//! So the following two codes are equivalent.
97//!
98//! ```rust
99//! use test_strategy::Arbitrary;
100//!
101//! #[derive(Arbitrary, Debug)]
102//! struct TestInput {
103//! x: u32,
104//! y: u32,
105//! }
106//! ```
107//!
108//! ```rust
109//! use proptest::{
110//! arbitrary::{any, Arbitrary},
111//! strategy::{BoxedStrategy, Strategy},
112//! };
113//!
114//! #[derive(Debug)]
115//! struct TestInput {
116//! x: u32,
117//! y: u32,
118//! }
119//! impl Arbitrary for TestInput {
120//! type Parameters = ();
121//! type Strategy = BoxedStrategy<Self>;
122//!
123//! fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
124//! let x = any::<u32>();
125//! let y = any::<u32>();
126//! (x, y).prop_map(|(x, y)| Self { x, y }).boxed()
127//! }
128//! }
129//! ```
130//!
131//! ## `#[strategy]`
132//!
133//! You can specify a strategy to generate values for the field by adding `#[strategy(...)]` to the field.
134//!
135//! In the following example, the value of field `x` will be less than 20.
136//!
137//! ```rust
138//! use test_strategy::Arbitrary;
139//!
140//! #[derive(Arbitrary, Debug)]
141//! struct TestInput {
142//! #[strategy(0..20u32)]
143//! x: u32,
144//! }
145//! ```
146//!
147//! In `#[strategy]`, the values of other fields can be used by following `#` to the name of the field.
148//!
149//! In the following example, the value of `y` is less than or equal to `x`.
150//!
151//! ```rust
152//! use test_strategy::Arbitrary;
153//!
154//! #[derive(Arbitrary, Debug)]
155//! struct TestInput {
156//! x: u32,
157//! #[strategy(0..=#x)]
158//! y: u32,
159//! }
160//! ```
161//!
162//! ## `#[any]`
163//!
164//! Instead of writing `#[strategy(any_with::<Type>(expr))]`, you can write `#[any(expr)]`.
165//!
166//! ```rust
167//! use proptest::collection::size_range;
168//! use test_strategy::Arbitrary;
169//!
170//! #[derive(Arbitrary, Debug, PartialEq)]
171//! struct TestInput {
172//! #[any(size_range(0..16).lift())]
173//! x: Vec<u16>,
174//! }
175//! ```
176//!
177//! Instead of writing an expression to be passed to `any_with`, you can write only the value of the field to be changed from the default value.
178//!
179//! Therefore, the following `TestInputA`, `TestInputB` and `TestInputC` are equivalent.
180//!
181//! ```rust
182//! use test_strategy::Arbitrary;
183//!
184//! #[derive(Arbitrary, Debug)]
185//! struct TestInputA {
186//! #[any(InnerArgs { upper : 20, ..InnerArgs::default() })]
187//! a: Inner,
188//! }
189//! #[derive(Arbitrary, Debug)]
190//! struct TestInputB {
191//! #[any(InnerArgs::default(), upper = 20)]
192//! a: Inner,
193//! }
194//! #[derive(Arbitrary, Debug)]
195//! struct TestInputC {
196//! #[any(upper = 20)]
197//! a: Inner,
198//! }
199//!
200//! #[derive(Default)]
201//! struct InnerArgs {
202//! lower: i32,
203//! upper: i32,
204//! }
205//!
206//! #[derive(Arbitrary, Debug)]
207//! #[arbitrary(args = InnerArgs)]
208//! struct Inner {
209//! #[strategy(args.lower..args.upper)]
210//! x: i32,
211//! }
212//! ```
213//!
214//! ## `#[weight]`
215//!
216//! By default, all variants appear with equal probability.
217//!
218//! You can add `#[weight]` to the variant to change the probability of the variant appearing.
219//!
220//! In the following example, `TestInput::B` is twice as likely to appear as `TestInput::A`.
221//!
222//! ```rust
223//! use test_strategy::Arbitrary;
224//!
225//! #[derive(Arbitrary, Debug)]
226//! enum TestInput {
227//! A,
228//!
229//! #[weight(2)]
230//! B,
231//! }
232//! ```
233//!
234//! If you add `#[weight(0)]` to a variant, the variant does not appear, so you can use a type in that variant that cannot be used as `Arbitrary`.
235//!
236//! ```rust
237//! use test_strategy::Arbitrary;
238//!
239//! #[derive(Debug)]
240//! struct NotArbitrary;
241//!
242//! #[derive(Arbitrary, Debug)]
243//! enum TestInput {
244//! A,
245//!
246//! #[allow(dead_code)]
247//! #[weight(0)] // Removing this `#[weight(0)]` will cause a compile error.
248//! B(NotArbitrary),
249//! }
250//! ```
251//!
252//! ## `#[filter]`
253//!
254//! By adding `#[filter]` , you can limit the values generated.
255//!
256//! In the following examples, x is an even number.
257//!
258//! ```rust
259//! use test_strategy::Arbitrary;
260//!
261//! #[derive(Arbitrary, Debug)]
262//! struct TestInput {
263//! #[filter(#x % 2 == 0)]
264//! x: u32,
265//! }
266//! ```
267//!
268//! You can also use multiple variables in a predicate.
269//!
270//! ```rust
271//! use test_strategy::Arbitrary;
272//!
273//! #[derive(Arbitrary, Debug)]
274//! #[filter((#x + #y) % 2 == 0)]
275//! struct TestInput {
276//! x: u32,
277//! y: u32,
278//! }
279//! ```
280//!
281//! You can use the value of a structure or enum in the filter by using `#self`.
282//!
283//! ```rust
284//! use test_strategy::Arbitrary;
285//!
286//! #[derive(Arbitrary, Debug)]
287//! #[filter((#self.x + #self.y) % 2 == 0)]
288//! struct TestInput {
289//! x: u32,
290//! y: u32,
291//! }
292//! ```
293//!
294//! If the argument of the `#[filter]` does not contain a variable marked with `#`, it is treated as a predicate function.
295//!
296//! ```rust
297//! use test_strategy::Arbitrary;
298//!
299//! #[derive(Arbitrary, Debug)]
300//! struct TestInput {
301//! #[filter(is_even)]
302//! x: u32,
303//! }
304//! fn is_even(x: &u32) -> bool {
305//! x % 2 == 0
306//! }
307//! ```
308//!
309//! ```rust
310//! use test_strategy::Arbitrary;
311//!
312//! #[derive(Arbitrary, Debug)]
313//! #[filter(x_is_even)]
314//! struct TestInput {
315//! x: u32,
316//! }
317//! fn x_is_even(input: &TestInput) -> bool {
318//! input.x % 2 == 0
319//! }
320//! ```
321//!
322//! You can specify a filter name by passing two arguments to `#[filter]`.
323//!
324//! ```rust
325//! use test_strategy::Arbitrary;
326//!
327//! #[derive(Arbitrary, Debug)]
328//! struct TestInput {
329//! #[filter("filter name", #x % 2 == 0)]
330//! x: u32,
331//! }
332//! ```
333//!
334//! ## `#[by_ref]`
335//!
336//! By default, if you use a variable with `#[strategy]`, `#[any]` or `#[filter]` with `#` attached to it, the cloned value is set.
337//!
338//! Adding `#[by_ref]` to the field makes it use the reference instead of the cloned value.
339//!
340//! ```rust
341//! use test_strategy::Arbitrary;
342//!
343//! #[derive(Arbitrary, Debug)]
344//! struct TestInput {
345//! #[by_ref]
346//! #[strategy(1..10u32)]
347//! x: u32,
348//!
349//! #[strategy(0..*#x)]
350//! y: u32,
351//! }
352//! ```
353//!
354//! ## `#[arbitrary]`
355//!
356//! ### `#[arbitrary(args = T)]`
357//!
358//! Specifies the type of `Arbitrary::Parameters`.
359//!
360//! You can use the value of this type in `#[strategy]`, `#[any]`, or `#[filter]` with the variable name `args`.
361//!
362//! ```rust
363//! use test_strategy::Arbitrary;
364//!
365//! #[derive(Debug, Default)]
366//! struct TestInputArgs {
367//! x_max: u32,
368//! }
369//!
370//! #[derive(Arbitrary, Debug)]
371//! #[arbitrary(args = TestInputArgs)]
372//! struct TestInput {
373//! #[strategy(0..=args.x_max)]
374//! x: u32,
375//! }
376//! ```
377//!
378//! ### `#[arbitrary(bound(T1, T2, ..))]`
379//!
380//! By default, if the type of field for which `#[strategy]` is not specified contains a generic parameter, that type is set to trait bounds.
381//!
382//! Therefore, the following `TestInputA` and `TestInputB` are equivalent.
383//!
384//! ```rust
385//! use proptest::{
386//! arbitrary::any, arbitrary::Arbitrary, strategy::BoxedStrategy, strategy::Strategy,
387//! };
388//! use test_strategy::Arbitrary;
389//!
390//! #[derive(Arbitrary, Debug)]
391//! struct TestInputA<T> {
392//! x: T,
393//! }
394//!
395//! #[derive(Debug)]
396//! struct TestInputB<T> {
397//! x: T,
398//! }
399//! impl<T: Arbitrary + 'static> Arbitrary for TestInputB<T> {
400//! type Parameters = ();
401//! type Strategy = BoxedStrategy<Self>;
402//!
403//! fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
404//! any::<T>().prop_map(|x| Self { x }).boxed()
405//! }
406//! }
407//! ```
408//!
409//! Types of fields with `#[strategy]` do not set trait bounds automatically, so you need to set trait bound manually with `#[arbitrary(bound(T))]`.
410//!
411//! ```rust
412//! use proptest::arbitrary::any_with;
413//! use test_strategy::Arbitrary;
414//!
415//! #[derive(Arbitrary, Debug, PartialEq)]
416//! #[arbitrary(bound(T))]
417//! struct TestInput<T> {
418//! #[strategy(any_with::<T>(Default::default()))]
419//! x: T,
420//! }
421//! ```
422//!
423//! You can also specify where predicate instead of type.
424//!
425//! ```rust
426//! use proptest::arbitrary::{any_with, Arbitrary};
427//! use test_strategy::Arbitrary;
428//!
429//! #[derive(Arbitrary, Debug, PartialEq)]
430//! #[arbitrary(bound(T : Arbitrary + 'static))]
431//! struct TestInput<T> {
432//! #[strategy(any_with::<T>(Default::default()))]
433//! x: T,
434//! }
435//! ```
436//!
437//! `..` means automatically generated trait bounds.
438//!
439//! The following example uses a manually specified trait bounds in addition to the automatically generated trait bounds.
440//!
441//! ```rust
442//! use proptest::arbitrary::any_with;
443//! use test_strategy::Arbitrary;
444//!
445//! #[derive(Arbitrary, Debug, PartialEq)]
446//! #[arbitrary(bound(T1, ..))]
447//! struct TestInput<T1, T2> {
448//! #[strategy(any_with::<T1>(Default::default()))]
449//! x: T1,
450//!
451//! y: T2,
452//! }
453//! ```
454//!
455//! ### `#[arbitrary(dump)]`
456//!
457//! Causes a compile error and outputs the code generated by `#[derive(Arbitrary)]` as an error message.
458//!
459//! ## `#[proptest]`
460//!
461//! `#[proptest]` is the attribute used instead of `#[test]` when defining a property test.
462//!
463//! The following example defines a test that takes a variety of integers as input.
464//!
465//! ```rust
466//! use test_strategy::proptest;
467//!
468//! #[proptest]
469//! fn my_test(_input: i32) {
470//! // ...
471//! }
472//! ```
473//!
474//! You can add `#[strategy]`, `#[any]`, `#[filter]`, `#[by_ref]` to the parameter of the function with `# [proptest]`.
475//!
476//! ```rust
477//! use test_strategy::proptest;
478//!
479//! #[proptest]
480//! fn my_test2(#[strategy(10..20)] _input: i32) {
481//! // ...
482//! }
483//! ```
484//!
485//! You can change the configuration of a property test by setting the argument of `#[proptest]` attribute to a value of `proptest::prelude::ProptestConfig` type.
486//!
487//! ```rust
488//! use proptest::prelude::ProptestConfig;
489//! use test_strategy::proptest;
490//!
491//!
492//! #[proptest(ProptestConfig { cases : 1000, ..ProptestConfig::default() })]
493//! fn my_test_with_config(_input: i32) {
494//! // ...
495//! }
496//! ```
497//!
498//! As with `#[any]`, you can also set only the value of the field to be changed from the default value.
499//!
500//! The example below is equivalent to the one above.
501//!
502//! ```rust
503//! use proptest::prelude::ProptestConfig;
504//! use test_strategy::proptest;
505//!
506//! #[proptest(ProptestConfig::default(), cases = 1000)]
507//! fn my_test_with_config_2(_input: i32) {
508//! // ...
509//! }
510//!
511//! #[proptest(cases = 1000)]
512//! fn my_test_with_config_3(_input: i32) {
513//! // ...
514//! }
515//! ```
516//!
517//! ### `#[proptest_dump]`
518//!
519//! You can add `#[proptest_dump]` to `#[proptest]` and output the code generated by `#[proptest]` as an compile error message.
520//!
521//! ```compile_fail
522//! #[proptest]
523//! #[proptest_dump]
524//! fn my_test(_input: i32) {
525//! // ...
526//! }
527//! ```
528// #![include_doc("../README.md", end("## License"))]
529
530extern crate proc_macro;
531
532#[macro_use]
533mod syn_utils;
534mod arbitrary;
535mod bound;
536mod proptest_fn;
537
538use syn::{parse_macro_input, DeriveInput, ItemFn};
539use syn_utils::into_macro_output;
540
541#[proc_macro_attribute]
542pub fn proptest(
543 attr: proc_macro::TokenStream,
544 item: proc_macro::TokenStream,
545) -> proc_macro::TokenStream {
546 let item_fn = parse_macro_input!(item as ItemFn);
547 into_macro_output(proptest_fn::build_proptest(attr.into(), item_fn))
548}
549
550#[proc_macro_derive(
551 Arbitrary,
552 attributes(arbitrary, strategy, any, filter, weight, by_ref)
553)]
554pub fn derive_arbitrary(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
555 let input = parse_macro_input!(input as DeriveInput);
556 into_macro_output(arbitrary::derive_arbitrary(input))
557}