propfuzz_macro/
lib.rs

1// Copyright (c) The propfuzz Contributors
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! Procedural macros for propfuzz tests.
5//!
6//! This crate is an implementation detail of `propfuzz` and is **not** meant to be used directly.
7//! Use it through [`propfuzz`](https://crates.io/crates/propfuzz) instead.
8
9extern crate proc_macro;
10
11use proc_macro::TokenStream;
12use syn::{parse_macro_input, AttributeArgs, ItemFn};
13
14mod config;
15mod errors;
16mod propfuzz_impl;
17
18/// The core macro, used to annotate test methods.
19///
20/// Annotate a function with this in order to have it run as a property-based test using the
21/// [`proptest`](https://docs.rs/proptest) framework. In the future, such tests will also be
22/// available as fuzz targets.
23///
24/// # Examples
25///
26/// ```
27/// // The prelude imports the `propfuzz` macro.
28///
29/// use propfuzz::prelude::*;
30/// use proptest::collection::vec;
31///
32/// /// Reversing a list twice produces the same result.
33/// #[propfuzz]
34/// fn reverse(
35///     #[propfuzz(strategy = "vec(any::<u32>(), 0..64)")]
36///     mut list: Vec<u32>,
37/// ) {
38///     let list2 = list.clone();
39///     list.reverse();
40///     list.reverse();
41///     prop_assert_eq!(list, list2);
42/// }
43/// ```
44///
45/// # Arguments
46///
47/// `propfuzz` supports a number of arguments which can be used to customize test behavior.
48///
49/// Attributes can be broken up with commas and split up across multiple lines like so:
50///
51/// ```
52/// use propfuzz::prelude::*;
53/// use proptest::collection::vec;
54///
55/// /// Options broken up across multiple lines.
56/// #[propfuzz(cases = 1024, max_local_rejects = 10000)]
57/// #[propfuzz(fork = true)]
58/// fn reverse(
59///     #[propfuzz(strategy = "vec(any::<u32>(), 0..64)")]
60///     mut list: Vec<u32>,
61/// ) {
62///     let list2 = list.clone();
63///     list.reverse();
64///     list.reverse();
65///     prop_assert_eq!(list, list2);
66/// }
67/// ```
68///
69/// ## Fuzzing configuration
70///
71/// These arguments are currently unused but may be set. They will be used in the future once fuzzing support is
72/// available.
73///
74/// * `fuzz_default`: whether to fuzz this target by default. Defaults to `false`.
75///
76/// ## Proptest configuration
77///
78/// The following `proptest`
79/// [configuration options](https://docs.rs/proptest/0.10/proptest/test_runner/struct.Config.html)
80/// are supported:
81///
82/// * `cases`
83/// * `max_local_rejects`
84/// * `max_global_rejects`
85/// * `max_flat_map_regens`
86/// * `fork`
87/// * `timeout`
88/// * `max_shrink_time`
89/// * `max_shrink_iters`
90/// * `verbose`
91///
92/// ## Argument configuration
93///
94/// The following configuration options are supported on individual arguments:
95///
96/// * `strategy`: A strategy to generate and shrink values of the given type. The value must be a
97///   string that parses as a Rust expression which evaluates to an implementation of
98///   [`Strategy`](https://docs.rs/proptest/0.10/proptest/strategy/trait.Strategy.html)
99///   for the given type. Defaults to [the
100///   canonical strategy](https://docs.rs/proptest/0.10/proptest/arbitrary/trait.Arbitrary.html)
101///   for the type.
102#[proc_macro_attribute]
103pub fn propfuzz(attr: TokenStream, item: TokenStream) -> TokenStream {
104    let attr = parse_macro_input!(attr as AttributeArgs);
105    let item = parse_macro_input!(item as ItemFn);
106
107    propfuzz_impl::propfuzz_impl(attr, item)
108        .unwrap_or_else(|err| err)
109        .into()
110}