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)]`][official-a] |
9//! | [`#[proptest]`](#proptest)                 | [`proptest ! { }`][official-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//! [official-m]: https://altsysrq.github.io/rustdoc/proptest/latest/proptest/macro.proptest.html
15//! [official-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.4.3"
31//! proptest = "1.6.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//! ## Attributes
76//!
77//! 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//! | [`#[map]`](#map)                                    |          |        |      |         | ✔     | ✔                  |
85//! | [`#[filter]`](#filter)                              | ✔        | ✔      | ✔    | ✔       | ✔     | ✔                  |
86//! | [`#[by_ref]`](#by_ref)                              |          |        |      |         | ✔     | ✔                  |
87//! | [`#[arbitrary(args = T)]`](#arbitraryargs--t)       |          | ✔      | ✔    |         |       |                    |
88//! | [`#[arbitrary(bound(...))]`](#arbitraryboundt1-t2-) |          | ✔      | ✔    | ✔       | ✔     |                    |
89//! | [`#[arbitrary(dump)]`](#arbitrarydump)              |          | ✔      | ✔    |         |       |                    |
90//! | [`#[proptest]`](#proptest)                          | ✔        |        |      |         |       |                    |
91//! | [`#[proptest(async = ...)]`](#proptestasync--)      | ✔        |        |      |         |       |                    |
92//! | [`#[proptest(dump)]`](#proptestdump)                | ✔        |        |      |         |       |                    |
93//!
94//! ## `#[derive(Arbitrary)]`
95//!
96//! You can implement `proptest::arbitrary::Arbitrary` automatically by adding `#[derive(Arbitrary)]` to struct or enum declaration.
97//!
98//! By default, all fields are set using the strategy obtained by `proptest::arbitrary::any()`.
99//!
100//! So the following two codes are equivalent.
101//!
102//! ```rust
103//! use test_strategy::Arbitrary;
104//!
105//! #[derive(Arbitrary, Debug)]
106//! struct TestInput {
107//!     x: u32,
108//!     y: u32,
109//! }
110//! ```
111//!
112//! ```rust
113//! use proptest::{
114//!     arbitrary::{any, Arbitrary},
115//!     strategy::{BoxedStrategy, Strategy},
116//! };
117//!
118//! #[derive(Debug)]
119//! struct TestInput {
120//!     x: u32,
121//!     y: u32,
122//! }
123//! impl Arbitrary for TestInput {
124//!     type Parameters = ();
125//!     type Strategy = BoxedStrategy<Self>;
126//!
127//!     fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
128//!         let x = any::<u32>();
129//!         let y = any::<u32>();
130//!         (x, y).prop_map(|(x, y)| Self { x, y }).boxed()
131//!     }
132//! }
133//! ```
134//!
135//! ## `#[strategy]`
136//!
137//! You can specify a strategy to generate values for the field by adding `#[strategy(...)]` to the field.
138//!
139//! In the following example, the value of field `x` will be less than 20.
140//!
141//! ```rust
142//! use test_strategy::Arbitrary;
143//!
144//! #[derive(Arbitrary, Debug)]
145//! struct TestInput {
146//!     #[strategy(0..20u32)]
147//!     x: u32,
148//! }
149//! ```
150//!
151//! In `#[strategy]`, the values of other fields can be used by following `#` to the name of the field.
152//!
153//! In the following example, the value of `y` is less than or equal to `x`.
154//!
155//! ```rust
156//! use test_strategy::Arbitrary;
157//!
158//! #[derive(Arbitrary, Debug)]
159//! struct TestInput {
160//!     x: u32,
161//!     #[strategy(0..=#x)]
162//!     y: u32,
163//! }
164//! ```
165//!
166//! ## `#[any]`
167//!
168//! Instead of writing `#[strategy(any_with::<Type>(expr))]`, you can write `#[any(expr)]`.
169//!
170//! ```rust
171//! use proptest::collection::size_range;
172//! use test_strategy::Arbitrary;
173//!
174//! #[derive(Arbitrary, Debug, PartialEq)]
175//! struct TestInput {
176//!     #[any(size_range(0..16).lift())]
177//!     x: Vec<u16>,
178//! }
179//! ```
180//!
181//! 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.
182//!
183//! Therefore, the following `TestInputA`, `TestInputB` and `TestInputC` are equivalent.
184//!
185//! ```rust
186//! use test_strategy::Arbitrary;
187//!
188//! #[derive(Arbitrary, Debug)]
189//! struct TestInputA {
190//!     #[any(InnerArgs { upper : 20, ..InnerArgs::default() })]
191//!     a: Inner,
192//! }
193//! #[derive(Arbitrary, Debug)]
194//! struct TestInputB {
195//!     #[any(InnerArgs::default(), upper = 20)]
196//!     a: Inner,
197//! }
198//! #[derive(Arbitrary, Debug)]
199//! struct TestInputC {
200//!     #[any(upper = 20)]
201//!     a: Inner,
202//! }
203//!
204//! #[derive(Default)]
205//! struct InnerArgs {
206//!     lower: i32,
207//!     upper: i32,
208//! }
209//!
210//! #[derive(Arbitrary, Debug)]
211//! #[arbitrary(args = InnerArgs)]
212//! struct Inner {
213//!     #[strategy(args.lower..args.upper)]
214//!     x: i32,
215//! }
216//! ```
217//!
218//! ## `#[weight]`
219//!
220//! By default, all variants appear with equal probability.
221//!
222//! You can add `#[weight]` to the variant to change the probability of the variant appearing.
223//!
224//! In the following example, `TestInput::B` is twice as likely to appear as `TestInput::A`.
225//!
226//! ```rust
227//! use test_strategy::Arbitrary;
228//!
229//! #[derive(Arbitrary, Debug)]
230//! enum TestInput {
231//!     A,
232//!
233//!     #[weight(2)]
234//!     B,
235//! }
236//! ```
237//!
238//! 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`.
239//!
240//! ```rust
241//! use test_strategy::Arbitrary;
242//!
243//! #[derive(Debug)]
244//! struct NotArbitrary;
245//!
246//! #[derive(Arbitrary, Debug)]
247//! enum TestInput {
248//!     A,
249//!
250//!     #[allow(dead_code)]
251//!     #[weight(0)] // Removing this `#[weight(0)]` will cause a compile error.
252//!     B(NotArbitrary),
253//! }
254//! ```
255//!
256//! ## `#[map]`
257//!
258//! Instead of using `prop_map` in `#[strategy(...)]`, `#[map(...)]` can be used.
259//!
260//! The following codes mean the same thing.
261//!
262//! ```rust
263//! use proptest::arbitrary::any;
264//! use proptest::strategy::Strategy;
265//! use test_strategy::Arbitrary;
266//!
267//! #[derive(Arbitrary, Debug)]
268//! struct TestInput1 {
269//!     #[strategy(any::<u32>().prop_map(|x| x + 1))]
270//!     x: u32,
271//! }
272//!
273//! #[derive(Arbitrary, Debug)]
274//! struct TestInput2 {
275//!     #[strategy(any::<u32>())]
276//!     #[map(|x| x + 1)]
277//!     x: u32,
278//! }
279//!
280//! #[derive(Arbitrary, Debug)]
281//! struct TestInput3 {
282//!     #[map(|x: u32| x + 1)]
283//!     x: u32,
284//! }
285//! ```
286//!
287//! References to other fields in the function applied to `prop_map` or `#[map(...)]` will generate different strategies.
288//!
289//! Referencing another field in `#[strategy(...)]` will expand it to `prop_flat_map`, even if it is in `prop_map`.
290//!
291//! ```rust
292//! use proptest::arbitrary::any;
293//! use proptest::strategy::{Just, Strategy};
294//! use test_strategy::Arbitrary;
295//!
296//! #[derive(Arbitrary, Debug)]
297//! struct T1 {
298//!     x: u32,
299//!
300//!     #[strategy(any::<u32>().prop_map(move |y| #x + y))]
301//!     y: u32,
302//! }
303//! // The code above generates the following strategy.
304//! let t1 = any::<u32>()
305//!     .prop_flat_map(|x| (Just(x), any::<u32>().prop_map(move |y| x + y)))
306//!     .prop_map(|(x, y)| T1 { x, y });
307//! ```
308//!
309//! On the other hand, if you refer to another field in `#[map]`, it will expand to `prop_map`.
310//!
311//! ```rust
312//! use proptest::arbitrary::any;
313//! use proptest::strategy::Strategy;
314//! use test_strategy::Arbitrary;
315//!
316//! #[derive(Arbitrary, Debug)]
317//! struct T2 {
318//!     x: u32,
319//!
320//!     #[map(|y: u32| #x + y)]
321//!     y: u32,
322//! }
323//! // The code above generates the following strategy.
324//! let t2 = (any::<u32>(), any::<u32>()).prop_map(|(x, y)| T2 { x, y });
325//! ```
326//!
327//! If the input and output types of the function specified in `#[map]` are different, the value type of the strategy set in `#[strategy]` is the type of the function's input, not the type of the field.
328//!
329//! ```rust
330//! use proptest::arbitrary::any;
331//! use proptest::sample::Index;
332//! use test_strategy::Arbitrary;
333//!
334//! #[derive(Arbitrary, Debug)]
335//! struct T1 {
336//!     #[strategy(any::<Index>())]
337//!     #[map(|i: Index| i.index(10))]
338//!     x: usize,
339//! }
340//!
341//! // `#[strategy(any::<Index>())]` can be omitted.
342//! #[derive(Arbitrary, Debug)]
343//! struct T2 {
344//!     #[map(|i: Index| i.index(10))]
345//!     x: usize,
346//! }
347//! ```
348//!
349//! ## `#[filter]`
350//!
351//! By adding `#[filter]` , you can limit the values generated.
352//!
353//! In the following examples, x is an even number.
354//!
355//! ```rust
356//! use test_strategy::Arbitrary;
357//!
358//! #[derive(Arbitrary, Debug)]
359//! struct TestInput {
360//!     #[filter(#x % 2 == 0)]
361//!     x: u32,
362//! }
363//! ```
364//!
365//! You can also use multiple variables in a predicate.
366//!
367//! ```rust
368//! use test_strategy::Arbitrary;
369//!
370//! #[derive(Arbitrary, Debug)]
371//! #[filter((#x + #y) % 2 == 0)]
372//! struct T1 {
373//!     x: u32,
374//!     y: u32,
375//! }
376//!
377//! #[derive(Arbitrary, Debug)]
378//! struct T2 {
379//!     x: u32,
380//!     #[filter((#x + #y) % 2 == 0)]
381//!     y: u32,
382//! }
383//! ```
384//!
385//! You can use the value of a structure or enum in the filter by using `#self`.
386//!
387//! ```rust
388//! use test_strategy::Arbitrary;
389//!
390//! #[derive(Arbitrary, Debug)]
391//! #[filter((#self.x + #self.y) % 2 == 0)]
392//! struct TestInput {
393//!     x: u32,
394//!     y: u32,
395//! }
396//! ```
397//!
398//! If the expression specified for `#[filter]` does not contain a variable named by appending # to its own field name, the expression is treated as a predicate function, rather than an expression that returns a bool.
399//!
400//! ```rust
401//! use test_strategy::Arbitrary;
402//!
403//! #[derive(Arbitrary, Debug)]
404//! struct TestInput {
405//!     #[filter(is_even)]
406//!     x: u32,
407//! }
408//! fn is_even(x: &u32) -> bool {
409//!     x % 2 == 0
410//! }
411//!
412//! #[derive(Arbitrary, Debug)]
413//! struct T2 {
414//!     a: u32,
415//!
416//!     // Since `#a` exists but `#b` does not, it is treated as a predicate function.
417//!     #[filter(|&x| x > #a)]
418//!     b: u32,
419//! }
420//! ```
421//!
422//! Similarly, an expression that does not contain `#self` in the `#[filter(...)]` that it attaches to a type is treated as a predicate function.
423//!
424//! ```rust
425//! use test_strategy::Arbitrary;
426//!
427//! #[derive(Arbitrary, Debug)]
428//! #[filter(is_even)]
429//! struct T {
430//!     x: u32,
431//! }
432//! fn is_even(t: &T) -> bool {
433//!     t.x % 2 == 0
434//! }
435//! ```
436//!
437//! You can specify a filter name by passing two arguments to `#[filter]`.
438//!
439//! ```rust
440//! use test_strategy::Arbitrary;
441//!
442//! #[derive(Arbitrary, Debug)]
443//! struct TestInput {
444//!     #[filter("x is even", #x % 2 == 0)]
445//!     x: u32,
446//! }
447//! ```
448//!
449//! ## `#[by_ref]`
450//!
451//! By default, if you use a variable with `#[strategy]`, `#[any]`, `#[map]` or `#[filter]` with `#` attached to it, the cloned value is set.
452//!
453//! Adding `#[by_ref]` to the field makes it use the reference instead of the cloned value.
454//!
455//! ```rust
456//! use test_strategy::Arbitrary;
457//!
458//! #[derive(Arbitrary, Debug)]
459//! struct TestInput {
460//!     #[by_ref]
461//!     #[strategy(1..10u32)]
462//!     x: u32,
463//!
464//!     #[strategy(0..*#x)]
465//!     y: u32,
466//! }
467//! ```
468//!
469//! ## `#[arbitrary]`
470//!
471//! ### `#[arbitrary(args = T)]`
472//!
473//! Specifies the type of `Arbitrary::Parameters`.
474//!
475//! You can use the `Rc` value of this type in `#[strategy]`, `#[any]`, or `#[filter]` with the variable name `args`.
476//!
477//! ```rust
478//! use test_strategy::Arbitrary;
479//!
480//! #[derive(Debug, Default)]
481//! struct TestInputArgs {
482//!     x_max: u32,
483//! }
484//!
485//! #[derive(Arbitrary, Debug)]
486//! #[arbitrary(args = TestInputArgs)]
487//! struct TestInput {
488//!     #[strategy(0..=args.x_max)]
489//!     x: u32,
490//! }
491//! ```
492//!
493//! ### `#[arbitrary(bound(T1, T2, ..))]`
494//!
495//! By default, if the type of field for which `#[strategy]` is not specified contains a generic parameter, that type is set to trait bounds.
496//!
497//! Therefore, the following `TestInputA` and `TestInputB` are equivalent.
498//!
499//! ```rust
500//! use proptest::{
501//!     arbitrary::any, arbitrary::Arbitrary, strategy::BoxedStrategy, strategy::Strategy,
502//! };
503//! use test_strategy::Arbitrary;
504//!
505//! #[derive(Arbitrary, Debug)]
506//! struct TestInputA<T> {
507//!     x: T,
508//! }
509//!
510//! #[derive(Debug)]
511//! struct TestInputB<T> {
512//!     x: T,
513//! }
514//! impl<T: Arbitrary + 'static> Arbitrary for TestInputB<T> {
515//!     type Parameters = ();
516//!     type Strategy = BoxedStrategy<Self>;
517//!
518//!     fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
519//!         any::<T>().prop_map(|x| Self { x }).boxed()
520//!     }
521//! }
522//! ```
523//!
524//! Types of fields with `#[strategy]` do not set trait bounds automatically, so you need to set trait bound manually with `#[arbitrary(bound(T))]`.
525//!
526//! ```rust
527//! use proptest::arbitrary::any_with;
528//! use test_strategy::Arbitrary;
529//!
530//! #[derive(Arbitrary, Debug, PartialEq)]
531//! #[arbitrary(bound(T))]
532//! struct TestInput<T> {
533//!     #[strategy(any_with::<T>(Default::default()))]
534//!     x: T,
535//! }
536//! ```
537//!
538//! You can also specify where predicate instead of type.
539//!
540//! ```rust
541//! use proptest::arbitrary::{any_with, Arbitrary};
542//! use test_strategy::Arbitrary;
543//!
544//! #[derive(Arbitrary, Debug, PartialEq)]
545//! #[arbitrary(bound(T : Arbitrary + 'static))]
546//! struct TestInput<T> {
547//!     #[strategy(any_with::<T>(Default::default()))]
548//!     x: T,
549//! }
550//! ```
551//!
552//! `..` means automatically generated trait bounds.
553//!
554//! The following example uses a manually specified trait bounds in addition to the automatically generated trait bounds.
555//!
556//! ```rust
557//! use proptest::arbitrary::any_with;
558//! use test_strategy::Arbitrary;
559//!
560//! #[derive(Arbitrary, Debug, PartialEq)]
561//! #[arbitrary(bound(T1, ..))]
562//! struct TestInput<T1, T2> {
563//!     #[strategy(any_with::<T1>(Default::default()))]
564//!     x: T1,
565//!
566//!     y: T2,
567//! }
568//! ```
569//!
570//! ### `#[arbitrary(dump)]`
571//!
572//! Causes a compile error and outputs the code generated by `#[derive(Arbitrary)]` as an error message.
573//!
574//! ## `#[proptest]`
575//!
576//! `#[proptest]` is the attribute used instead of `#[test]` when defining a property test.
577//!
578//! The following example defines a test that takes a variety of integers as input.
579//!
580//! ```rust
581//! use test_strategy::proptest;
582//!
583//! #[proptest]
584//! fn my_test(_input: i32) {
585//!     // ...
586//! }
587//! ```
588//!
589//! You can add `#[strategy]`, `#[any]`, `#[filter]`, `#[by_ref]` to the parameter of the function with `# [proptest]`.
590//!
591//! ```rust
592//! use test_strategy::proptest;
593//!
594//! #[proptest]
595//! fn my_test2(#[strategy(10..20)] _input: i32) {
596//!     // ...
597//! }
598//! ```
599//!
600//! You can change the configuration of a property test by setting the argument of `#[proptest]` attribute to a value of [`proptest::prelude::ProptestConfig`](https://docs.rs/proptest/latest/proptest/prelude/index.html#reexport.ProptestConfig) type.
601//!
602//! ```rust
603//! use proptest::prelude::ProptestConfig;
604//! use test_strategy::proptest;
605//!
606//! #[proptest(ProptestConfig { cases : 1000, ..ProptestConfig::default() })]
607//! fn my_test_with_config(_input: i32) {
608//!     // ...
609//! }
610//! ```
611//!
612//! As with `#[any]`, you can also set only the value of the field to be changed from the default value.
613//!
614//! The example below is equivalent to the one above.
615//!
616//! ```rust
617//! use proptest::prelude::ProptestConfig;
618//! use test_strategy::proptest;
619//!
620//! #[proptest(ProptestConfig::default(), cases = 1000)]
621//! fn my_test_with_config_2(_input: i32) {
622//!     // ...
623//! }
624//!
625//! #[proptest(cases = 1000)]
626//! fn my_test_with_config_3(_input: i32) {
627//!     // ...
628//! }
629//! ```
630//!
631//! ### `#[proptest(async = ...)]`
632//!
633//! Async functions can be tested by setting `async = ...` to the argument of `#[proptest]`.
634//!
635//! The following values are allowed after `async =`.
636//! The value specifies the asynchronous runtime used for the test.
637//!
638//! - "tokio"
639//!
640//! ```toml
641//! [dev-dependencies]
642//! test-strategy = "0.4.3"
643//! proptest = "1.6.0"
644//! tokio = { version = "1.38.0", features = ["rt-multi-thread"] }
645//! ```
646//!
647//! ```rust
648//! use test_strategy::proptest;
649//! use proptest::prop_assert;
650//!
651//! #[proptest(async = "tokio")]
652//! async fn my_test_async() {
653//!     async { }.await;
654//!     prop_assert!(true);
655//! }
656//! ```
657//!
658//! ### `#[proptest(dump)]`
659//!
660//! You can use `#[proptest(dump)]` and output the code generated by `#[proptest]` as an compile error message.
661//!
662//! ```compile_fail
663//! #[proptest(dump)]
664//! fn my_test(_input: i32) {
665//!     // ...
666//! }
667//! ```
668// #![include_doc("../README.md", end("## License"))]
669
670extern crate proc_macro;
671
672#[macro_use]
673mod syn_utils;
674mod arbitrary;
675mod bound;
676mod proptest_fn;
677
678use syn::{parse_macro_input, DeriveInput, ItemFn};
679use syn_utils::into_macro_output;
680
681#[proc_macro_attribute]
682pub fn proptest(
683    attr: proc_macro::TokenStream,
684    item: proc_macro::TokenStream,
685) -> proc_macro::TokenStream {
686    let item_fn = parse_macro_input!(item as ItemFn);
687    into_macro_output(proptest_fn::build_proptest(attr.into(), item_fn))
688}
689
690#[proc_macro_derive(
691    Arbitrary,
692    attributes(arbitrary, strategy, any, map, filter, weight, by_ref)
693)]
694pub fn derive_arbitrary(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
695    let input = parse_macro_input!(input as DeriveInput);
696    into_macro_output(arbitrary::derive_arbitrary(input))
697}