chaos_theory/
lib.rs

1// Copyright 2025 Gregory Petrosyan <pgregory@pgregory.net>
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
7/*!
8`chaos_theory` is a modern property-based testing and structure-aware fuzzing library.
9*/
10
11#![cfg_attr(all(test, feature = "_bench"), feature(test))]
12#![cfg_attr(docsrs, feature(doc_cfg))]
13
14extern crate alloc;
15#[cfg(all(test, feature = "_bench"))]
16extern crate test;
17
18use std::path::Path;
19
20mod base64;
21mod config;
22mod cover;
23mod distrib;
24mod env;
25mod generator;
26mod hash;
27mod hash_identity;
28mod libfuzzer;
29mod math;
30mod num;
31mod permute;
32mod rand;
33mod range;
34mod reduce;
35mod source;
36mod tape;
37mod tape_event;
38mod tape_mutate;
39mod tape_mutate_crossover;
40mod tape_reduce;
41mod tape_validate;
42#[cfg(test)]
43mod tests;
44#[cfg(test)]
45mod tests_shrinking_challenge;
46mod unwind;
47mod util;
48mod varint;
49
50mod make_cell;
51mod make_char;
52mod make_collection;
53mod make_combine;
54mod make_core;
55mod make_float;
56#[cfg(feature = "hashbrown")]
57mod make_hashbrown;
58#[cfg(feature = "indexmap")]
59mod make_indexmap;
60mod make_integer;
61#[cfg(feature = "ordered_float")]
62mod make_ordered_float;
63#[cfg(feature = "regex")]
64mod make_regex;
65mod make_special;
66mod make_string;
67mod make_sync;
68mod make_time;
69#[cfg(feature = "tinyvec")]
70mod make_tinyvec;
71mod make_tuple;
72
73pub use config::*;
74pub use env::*;
75pub use generator::*;
76pub use num::*;
77pub use source::*;
78pub use unwind::*;
79pub use util::*;
80
81/// Collection of built-in generator implementations.
82pub mod make {
83    pub use crate::make_cell::*;
84    pub use crate::make_char::*;
85    pub use crate::make_collection::*;
86    pub use crate::make_combine::*;
87    pub use crate::make_core::*;
88    pub use crate::make_float::*;
89    pub use crate::make_integer::*;
90    #[cfg(feature = "regex")]
91    pub use crate::make_regex::*;
92    pub use crate::make_special::*;
93    pub use crate::make_string::*;
94    pub use crate::make_sync::*;
95    pub use crate::make_time::*;
96
97    use crate::{Arbitrary, Generator};
98
99    /// Create a generator of `T`, using its [`Arbitrary`] implementation.
100    ///
101    /// This is equivalent to `<T as Arbitrary>::arbitrary()`, but can sometimes be a bit more concise.
102    pub fn arbitrary<T: Arbitrary>() -> impl Generator<Item = T> {
103        T::arbitrary()
104    }
105
106    #[cfg(feature = "hashbrown")]
107    /// [`hashbrown`](https://docs.rs/hashbrown) generators.
108    pub mod hashbrown {
109        pub use crate::make_hashbrown::*;
110    }
111
112    #[cfg(feature = "indexmap")]
113    /// [`indexmap`](https://docs.rs/indexmap) generators.
114    pub mod indexmap {
115        pub use crate::make_indexmap::*;
116    }
117
118    #[cfg(feature = "ordered_float")]
119    /// [`ordered_float`](https://docs.rs/ordered-float) generators.
120    pub mod ordered_float {
121        pub use crate::make_ordered_float::*;
122    }
123
124    #[cfg(feature = "tinyvec")]
125    /// [`tinyvec`](https://docs.rs/tinyvec) generators.
126    pub mod tinyvec {
127        pub use crate::make_tinyvec::*;
128    }
129}
130
131/// Check that property holds (does not panic).
132///
133/// To customize the `check` behavior, use [`Env::custom`] and [`Env::check`]
134/// (or specify environment variables mentioned in [`Config::env`](crate::Config::env) documentation).
135pub fn check(prop: impl Fn(&mut Source)) {
136    Env::new().check(prop);
137}
138
139/// Write seed input for the fuzzer. This can conveniently be done from an ignored test.
140///
141/// A good default number of seeds to write before starting fuzzing is 32.
142/// Fewer seeds are required for simple systems, while complex ones can benefit from
143/// more seeds (at the expense of slowing down fuzzing due to seed redundancy).
144/// Recommended approach is to write a lot of seeds (e.g. 1024), and apply
145/// corpus minimization to them before starting fuzzing.
146///
147/// To customize the `write_fuzz_seed` behavior, use [`Env::custom`] and [`Env::fuzz_write_seed`]
148/// (or specify environment variables mentioned in [`Config::env`](crate::Config::env) documentation).
149///
150/// # Errors
151///
152/// `fuzz_write_seed` fails when valid test case can not be generated or in case of a filesystem error.
153pub fn fuzz_write_seed(
154    seed_dir: impl AsRef<Path>,
155    prop: impl Fn(&mut Source),
156) -> Result<(), &'static str> {
157    Env::new().fuzz_write_seed(seed_dir, prop)
158}
159
160/// Check that property holds (does not panic) on fuzzer-provided input.
161///
162/// You probably want to use higher-level wrapper like
163/// [`fuzz_target_libfuzzer_sys`] instead of manually invoking this function.
164#[must_use]
165pub fn fuzz_check(
166    input: &[u8],
167    out: Option<(&mut [u8], &mut usize)>,
168    prop: impl Fn(&mut Source),
169) -> bool {
170    Env::new().fuzz_check(input, out, prop)
171}
172
173/// Mutate fuzzer input.
174///
175/// You probably want to use higher-level wrapper like
176/// [`fuzz_target_libfuzzer_sys`] instead of manually invoking this function.
177#[expect(clippy::type_complexity)]
178pub fn fuzz_mutate(
179    data: &mut [u8],
180    size: usize,
181    max_size: usize,
182    seed: u32,
183    allow_void: bool,
184    mutate_bin: Option<fn(&mut [u8], usize, usize) -> usize>,
185) -> usize {
186    Env::new().fuzz_mutate(data, size, max_size, seed, allow_void, mutate_bin)
187}
188
189/// Cross-over two fuzzer inputs.
190///
191/// You probably want to use higher-level wrapper like
192/// [`fuzz_target_libfuzzer_sys`] instead of manually invoking this function.
193pub fn fuzz_mutate_crossover(
194    input: &[u8],
195    other: &[u8],
196    out: &mut [u8],
197    seed: u32,
198    allow_void: bool,
199) -> usize {
200    Env::new().fuzz_mutate_crossover(input, other, out, seed, allow_void)
201}
202
203pub(crate) type Set<K> = std::collections::HashSet<K, hash::FxBuildHasher>;
204pub(crate) type Map<K, V> = std::collections::HashMap<K, V, hash::FxBuildHasher>;