| // Copyright 2024 Google LLC |
| // |
| // 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. |
| |
| //! Derive macros that generates both a fuzz target for use with `cargo fuzz`, and a property test |
| //! (via `quickcheck` or `proptest`) for use with `cargo test`. |
| //! |
| //! The reason for having both is that property testing allows for quick iteration to make sure the |
| //! test works, and can be checked in presubmit CI, while fuzzing can test the input space more |
| //! exhaustively and run continuously. |
| //! |
| //! # Example |
| //! |
| //! ```no_run |
| //! #![cfg_attr(fuzzing, no_main)] |
| //! |
| //! #[derive_fuzztest::fuzztest] |
| //! fn transitive_ord(a: u32, b: u32, c: u32) { |
| //! if a >= b && b >= c { |
| //! assert!(a >= c); |
| //! } |
| //! if a <= b && b <= c { |
| //! assert!(a <= c); |
| //! } |
| //! } |
| //! |
| //! #[test] |
| //! fn additional_test_here() { |
| //! /* ... */ |
| //! } |
| //! ``` |
| //! |
| //! # Usage |
| //! |
| //! |
| //! Run the generated property tests |
| //! ```sh |
| //! cargo test |
| //! ``` |
| //! |
| //! Run continuous fuzzing |
| //! ```sh |
| //! cargo +nightly fuzz run <binary name> |
| //! ``` |
| //! |
| //! # Crate structure |
| //! |
| //! If you use `#[fuzz]` or `#[fuzztest]`, the fuzz target imposes the following requirements: |
| //! |
| //! * The target must be in a separate `[[bin]]` target that only contains a single fuzz target. |
| //! * The crate containing the bin target has `[package.metadata] cargo-fuzz = true` |
| //! * The bin target is annotated with `#![cfg_attr(fuzzing, no_main)]` |
| //! |
| //! The recommended structure for your crate `foo` is to put your tests under `foo/fuzz/src/bin`: |
| //! |
| //! ```text |
| //! foo |
| //! ├── fuzz |
| //! │ ├── src |
| //! │ │ └── bin |
| //! │ │ └── fuzz_target_1.rs |
| //! │ └── Cargo.toml |
| //! ├── src |
| //! │ └── [project source] |
| //! └── Cargo.toml |
| //! ``` |
| //! |
| //! This is different from the default structure generated by `cargo fuzz init` or `cargo fuzz add` |
| //! so that we can take advantage of [target |
| //! auto-discovery](https://doc.rust-lang.org/cargo/reference/cargo-targets.html#target-auto-discovery). |
| //! If you prefer, the default structure generated by `cargo fuzz` can also work, but make sure you |
| //! remove `test = false` from the generated target in `Cargo.toml`. |
| //! |
| //! You will also need to declare a dependency on the `libfuzzer-sys` crate, but only if fuzzing is |
| //! requested: |
| //! |
| //! ```toml |
| //! [target.'cfg(fuzzing)'.dependencies] |
| //! libfuzzer-sys = "*" |
| //! ``` |
| //! |
| //! (The reason for this conditional dependency is that `libfuzzer-sys` injects a main function to |
| //! the resulting binary, and there will be linking failures if we link that in without defining a |
| //! corresponding `fuzz_target`.) |
| //! |
| //! # Features |
| //! |
| //! * `quickcheck` (default) — Enable generation of |
| //! [`quickcheck`](https://docs.rs/quickcheck/latest/quickcheck/) property tests. |
| //! * `proptest` — Enable generation of [`proptest`](https://docs.rs/proptest/latest/proptest/) |
| //! property tests. |
| //! |
| //! #### See also |
| //! * [Announcing Better Support for Fuzzing with Structured Inputs in |
| //! Rust](https://fitzgeraldnick.com/2020/01/16/better-support-for-fuzzing-structured-inputs-in-rust.html#how-is-all-this-different-from-quickcheck-and-proptest) |
| //! * [Bridging Fuzzing and Property |
| //! Testing](https://blog.yoshuawuyts.com/bridging-fuzzing-and-property-testing/) |
| |
| pub use derive_fuzztest_macro::{fuzz, fuzztest, proptest}; |
| |
| #[doc(hidden)] |
| pub mod reexport { |
| #[cfg(feature = "proptest")] |
| pub use proptest; |
| #[cfg(feature = "proptest")] |
| pub use proptest_arbitrary_interop; |
| #[cfg(feature = "quickcheck")] |
| pub use quickcheck; |
| } |
| |
| #[cfg(feature = "quickcheck")] |
| #[doc(hidden)] |
| pub mod arbitrary_bridge { |
| |
| /// Wrapper type that allows `arbitrary::Arbitrary` to be used as `quickcheck::Arbitrary` |
| #[derive(Debug, Clone)] |
| pub struct ArbitraryAdapter<T: for<'a> arbitrary::Arbitrary<'a>>( |
| pub Result<T, arbitrary::Error>, |
| ); |
| |
| impl<T> quickcheck::Arbitrary for ArbitraryAdapter<T> |
| where |
| T: for<'a> arbitrary::Arbitrary<'a> + Clone + 'static, |
| { |
| fn arbitrary(g: &mut quickcheck::Gen) -> Self { |
| let bytes = Vec::<u8>::arbitrary(g); |
| let mut unstructured = arbitrary::Unstructured::new(&bytes); |
| Self(T::arbitrary(&mut unstructured)) |
| } |
| } |
| } |