1use bolero_generator::{
2 combinator::{AndThenGenerator, FilterGenerator, FilterMapGenerator, MapGenerator},
3 TypeValueGenerator,
4};
5use core::{fmt::Debug, marker::PhantomData, time::Duration};
6
7cfg_if::cfg_if! {
8 if #[cfg(fuzzing_libfuzzer)] {
9 pub use bolero_libfuzzer::LibFuzzerEngine as DefaultEngine;
11 } else if #[cfg(fuzzing_afl)] {
12 pub use bolero_afl::AflEngine as DefaultEngine;
14 } else if #[cfg(fuzzing_honggfuzz)] {
15 pub use bolero_honggfuzz::HonggfuzzEngine as DefaultEngine;
17 } else if #[cfg(kani)] {
18 pub use bolero_kani::KaniEngine as DefaultEngine;
19 } else {
20 mod test;
21
22 pub use crate::test::TestEngine as DefaultEngine;
24 }
25}
26
27pub mod generator {
29 pub use bolero_generator::{self, prelude::*};
30}
31
32pub use bolero_generator::prelude::*;
34
35#[doc(hidden)]
36pub use bolero_engine::{self, TargetLocation, __item_path__};
37
38pub use bolero_engine::{Driver, Engine, Test};
39
40#[cfg(test)]
41mod tests;
42
43#[macro_export]
115macro_rules! check {
116 () => {{
117 let location = $crate::TargetLocation {
118 package_name: env!("CARGO_PKG_NAME"),
119 manifest_dir: env!("CARGO_MANIFEST_DIR"),
120 module_path: module_path!(),
121 file: file!(),
122 line: line!(),
123 item_path: $crate::__item_path__!(),
124 test_name: None,
125 };
126
127 if !location.should_run() {
128 return;
129 }
130
131 $crate::test(location)
132 }};
133 ($fun:path) => {
134 $crate::check!(|input| { $fun(input) })
135 };
136 (| $input:ident $(: &[u8])? | $impl:expr) => {
137 $crate::check!().for_each(|$input: &[u8]| $impl)
138 };
139 (| $input:ident : $ty:ty | $impl:expr) => {
140 $crate::check!().with_type().for_each(|$input: $ty| $impl)
141 };
142 (name = $target_name:expr) => {{
143 let location = $crate::TargetLocation {
144 package_name: env!("CARGO_PKG_NAME"),
145 manifest_dir: env!("CARGO_MANIFEST_DIR"),
146 module_path: module_path!(),
147 file: file!(),
148 line: line!(),
149 item_path: $crate::__item_path__!(),
150 test_name: Some(format!("{}", $target_name)),
151 };
152
153 if !location.should_run() {
154 return;
155 }
156
157 $crate::test(location)
158 }};
159}
160
161#[macro_export]
162#[deprecated = "`fuzz!` has been deprecated in favor of `check!`."]
163macro_rules! fuzz {
164 ($($arg:tt)*) => {
165 $crate::check!($($arg)*)
166 }
167}
168
169pub struct TestTarget<Generator, Engine, InputOwnership> {
171 generator: Generator,
172 driver_options: bolero_generator::driver::Options,
173 engine: Engine,
174 input_ownership: PhantomData<InputOwnership>,
175}
176
177#[doc(hidden)]
178#[derive(Clone, Copy, Debug, PartialEq, Eq)]
179pub struct BorrowedInput;
180
181#[doc(hidden)]
182#[derive(Clone, Copy, Debug, PartialEq, Eq)]
183pub struct ClonedInput;
184
185#[doc(hidden)]
186pub fn test(
187 location: TargetLocation,
188) -> TestTarget<ByteSliceGenerator, DefaultEngine, BorrowedInput> {
189 TestTarget::new(DefaultEngine::new(location))
190}
191
192#[derive(Copy, Clone, Default, PartialEq, Eq)]
194pub struct ByteSliceGenerator;
195
196impl<Engine> TestTarget<ByteSliceGenerator, Engine, BorrowedInput> {
197 pub fn new(engine: Engine) -> TestTarget<ByteSliceGenerator, Engine, BorrowedInput> {
199 Self {
200 generator: ByteSliceGenerator,
201 engine,
202 driver_options: Default::default(),
203 input_ownership: PhantomData,
204 }
205 }
206}
207
208impl<G, Engine, InputOwnership> TestTarget<G, Engine, InputOwnership> {
209 pub fn with_generator<Generator: generator::ValueGenerator>(
218 self,
219 generator: Generator,
220 ) -> TestTarget<Generator, Engine, InputOwnership>
221 where
222 Generator::Output: Debug,
223 {
224 TestTarget {
225 generator,
226 engine: self.engine,
227 driver_options: self.driver_options,
228 input_ownership: self.input_ownership,
229 }
230 }
231
232 pub fn with_type<T: Debug + generator::TypeGenerator>(
241 self,
242 ) -> TestTarget<TypeValueGenerator<T>, Engine, InputOwnership> {
243 TestTarget {
244 generator: generator::produce(),
245 engine: self.engine,
246 driver_options: self.driver_options,
247 input_ownership: self.input_ownership,
248 }
249 }
250
251 #[cfg(feature = "arbitrary")]
260 pub fn with_arbitrary<T>(
261 self,
262 ) -> TestTarget<bolero_generator::arbitrary::ArbitraryGenerator<T>, Engine, InputOwnership>
263 where
264 T: 'static + Debug,
265 T: for<'a> bolero_generator::arbitrary::Arbitrary<'a>,
266 {
267 TestTarget {
268 generator: generator::gen_arbitrary(),
269 engine: self.engine,
270 driver_options: self.driver_options,
271 input_ownership: self.input_ownership,
272 }
273 }
274
275 pub fn with_shrink_time(mut self, shrink_time: Duration) -> Self {
281 self.driver_options.set_shrink_time(shrink_time);
282 self
283 }
284
285 pub fn exhaustive(mut self) -> Self {
289 self.driver_options.set_exhaustive(true);
290 self
291 }
292}
293
294impl<G: generator::ValueGenerator, Engine, InputOwnership> TestTarget<G, Engine, InputOwnership> {
295 pub fn map<F: Fn(G::Output) -> T, T: Debug>(
297 self,
298 map: F,
299 ) -> TestTarget<MapGenerator<G, F>, Engine, InputOwnership> {
300 TestTarget {
301 generator: self.generator.map_gen(map),
302 engine: self.engine,
303 driver_options: self.driver_options,
304 input_ownership: self.input_ownership,
305 }
306 }
307
308 pub fn and_then<F: Fn(G::Output) -> T, T: generator::ValueGenerator>(
310 self,
311 map: F,
312 ) -> TestTarget<AndThenGenerator<G, F>, Engine, InputOwnership>
313 where
314 T::Output: Debug,
315 {
316 TestTarget {
317 generator: self.generator.and_then_gen(map),
318 engine: self.engine,
319 driver_options: self.driver_options,
320 input_ownership: self.input_ownership,
321 }
322 }
323
324 pub fn filter<F: Fn(&G::Output) -> bool>(
326 self,
327 filter: F,
328 ) -> TestTarget<FilterGenerator<G, F>, Engine, InputOwnership> {
329 TestTarget {
330 generator: self.generator.filter_gen(filter),
331 engine: self.engine,
332 driver_options: self.driver_options,
333 input_ownership: self.input_ownership,
334 }
335 }
336
337 pub fn filter_map<F: Fn(G::Output) -> Option<T>, T>(
339 self,
340 filter_map: F,
341 ) -> TestTarget<FilterMapGenerator<G, F>, Engine, InputOwnership> {
342 TestTarget {
343 generator: self.generator.filter_map_gen(filter_map),
344 engine: self.engine,
345 driver_options: self.driver_options,
346 input_ownership: self.input_ownership,
347 }
348 }
349
350 #[deprecated = "Driver mode is no longer being used by generator implementations"]
352 #[allow(deprecated)]
353 pub fn with_driver_mode(self, mode: DriverMode) -> Self {
354 let _ = mode;
355 self
356 }
357
358 pub fn with_max_depth(mut self, max_depth: usize) -> Self {
362 self.driver_options.set_max_depth(max_depth);
363 self
364 }
365}
366
367cfg_if::cfg_if! {
368 if #[cfg(any(fuzzing, kani))] {
369 impl<G, Engine, InputOwnership> TestTarget<G, Engine, InputOwnership> {
370 pub fn with_test_time(self, test_time: Duration) -> Self {
372 let _ = test_time;
373 self
374 }
375
376 pub fn with_iterations(self, iterations: usize) -> Self {
378 let _ = iterations;
379 self
380 }
381
382 pub fn with_max_len(mut self, max_len: usize) -> Self {
384 self.driver_options.set_max_len(max_len);
385 self
386 }
387 }
388 } else {
389 impl<G, InputOwnership> TestTarget<G, crate::test::TestEngine, InputOwnership> {
390 pub fn with_test_time(mut self, test_time: Duration) -> Self {
392 self.engine.with_test_time(test_time);
393 self
394 }
395
396 pub fn with_iterations(mut self, iterations: usize) -> Self {
398 self.engine.with_iterations(iterations);
399 self
400 }
401
402 pub fn with_max_len(mut self, max_len: usize) -> Self {
404 self.driver_options.set_max_len(max_len);
405 self.engine.with_max_len(max_len);
406 self
407 }
408 }
409 }
410}
411
412impl<G, Engine> TestTarget<G, Engine, BorrowedInput>
413where
414 G: generator::ValueGenerator,
415 <G as generator::ValueGenerator>::Output: Clone,
416{
417 pub fn cloned(self) -> TestTarget<G, Engine, ClonedInput> {
423 TestTarget {
424 generator: self.generator,
425 engine: self.engine,
426 driver_options: self.driver_options,
427 input_ownership: PhantomData,
428 }
429 }
430}
431
432impl<G, E> TestTarget<G, E, BorrowedInput>
433where
434 G: generator::ValueGenerator,
435{
436 pub fn for_each<F>(self, test: F) -> E::Output
438 where
439 E: Engine<bolero_engine::BorrowedGeneratorTest<F, G, G::Output>>,
440 bolero_engine::BorrowedGeneratorTest<F, G, G::Output>: Test,
441 {
442 let test = bolero_engine::BorrowedGeneratorTest::new(test, self.generator);
443 self.engine.run(test, self.driver_options)
444 }
445}
446
447impl<G, E> TestTarget<G, E, ClonedInput>
448where
449 G: generator::ValueGenerator,
450{
451 pub fn for_each<F>(self, test: F) -> E::Output
453 where
454 E: Engine<bolero_engine::ClonedGeneratorTest<F, G, G::Output>>,
455 bolero_engine::ClonedGeneratorTest<F, G, G::Output>: Test,
456 {
457 let test = bolero_engine::ClonedGeneratorTest::new(test, self.generator);
458 self.engine.run(test, self.driver_options)
459 }
460}
461
462impl<E> TestTarget<ByteSliceGenerator, E, BorrowedInput> {
463 pub fn for_each<T>(self, test: T) -> E::Output
465 where
466 E: Engine<bolero_engine::BorrowedSliceTest<T>>,
467 bolero_engine::BorrowedSliceTest<T>: Test,
468 {
469 let test = bolero_engine::BorrowedSliceTest::new(test);
470 self.engine.run(test, self.driver_options)
471 }
472
473 #[cfg(feature = "std")]
475 pub fn run<T, R>(self, mut test: T) -> E::Output
476 where
477 T: FnMut() -> R + core::panic::RefUnwindSafe,
478 R: bolero_engine::IntoResult,
479 E: bolero_engine::ScopedEngine,
480 {
481 self.engine.run(move |_| test(), self.driver_options)
482 }
483
484 #[cfg(feature = "std")]
485 pub fn run_with_replay<T, R>(self, test: T) -> E::Output
486 where
487 T: FnMut(bool) -> R + core::panic::RefUnwindSafe,
488 R: bolero_engine::IntoResult,
489 E: bolero_engine::ScopedEngine,
490 {
491 self.engine.run(test, self.driver_options.with_replay_on_fail(true))
492 }
493}
494
495impl<E> TestTarget<ByteSliceGenerator, E, ClonedInput> {
496 pub fn for_each<T>(self, test: T) -> E::Output
498 where
499 E: Engine<bolero_engine::ClonedSliceTest<T>>,
500 bolero_engine::ClonedSliceTest<T>: Test,
501 {
502 let test = bolero_engine::ClonedSliceTest::new(test);
503 self.engine.run(test, self.driver_options)
504 }
505}