crabcheck/
fuzzing.rs

1use crate::{
2    quickcheck::{Arbitrary, Mutate, RunResult},
3    seedpool::{Seed, SeedPool},
4};
5use std::fmt::Debug;
6
7
8pub fn maximizing_fuzz_loop<
9    Domain: Clone + Arbitrary + Mutate,
10    Codomain,
11    Feedback: Clone + Ord + Debug,
12>(
13    f: fn(Domain) -> Codomain,
14    fb: fn(Box<dyn FnOnce() -> Codomain + '_>) -> (Codomain, Feedback),
15) -> Seed<Domain, Feedback> {
16    let mut pool: SeedPool<Domain, Feedback> = SeedPool::new();
17    let fuel = 100000;
18
19    for i in 1..=fuel {
20        if i % 1000 == 0 {
21            println!("Iteration: {}", i);
22            println!("Pool size: {}", pool.size());
23            println!(
24                "Best of all time: {:?}",
25                pool.best_of_all_time.clone().unwrap().feedback
26            );
27            println!("====================\n");
28        }
29        let input = if let Some(seed) = pool.pop() {
30            Domain::mutate(&seed.input)
31        } else {
32            Domain::generate()
33        };
34
35        let copy = input.clone();
36        let (_, feedback) = fb(Box::new(move || f(copy)));
37
38        if pool.is_empty() {
39            let seed = Seed {
40                input,
41                feedback: feedback,
42                energy: 1000,
43            };
44
45            pool.add_seed(seed);
46        } else {
47            if feedback > pool.best().clone().feedback {
48                let seed = Seed {
49                    input,
50                    feedback: feedback,
51                    energy: 1000,
52                };
53
54                pool.add_seed(seed);
55            }
56        }
57    }
58
59    pool.best_of_all_time.unwrap().clone()
60}
61
62
63pub fn prop_fuzz_loop<Domain: Clone + Arbitrary + Mutate, Feedback: Clone + Ord + Debug>(
64    p: fn(Domain) -> bool,
65    fb: fn(Box<dyn FnOnce() -> bool + '_>) -> (bool, Feedback),
66) -> RunResult<Seed<Domain, Feedback>> {
67    let mut pool: SeedPool<Domain, Feedback> = SeedPool::new();
68    let fuel = 100000;
69
70    for i in 1..=fuel {
71        if i % 1000 == 0 {
72            println!("Iteration: {}", i);
73            println!("Pool size: {}", pool.size());
74            println!(
75                "Best of all time: {:?}",
76                pool.best_of_all_time.clone().unwrap().feedback
77            );
78            println!("====================\n");
79        }
80        let input = if let Some(seed) = pool.pop() {
81            Domain::mutate(&seed.input)
82        } else {
83            Domain::generate()
84        };
85
86        let copy = input.clone();
87        let (result, feedback) = fb(Box::new(move || p(copy)));
88
89        if !result {
90            return RunResult {
91                passed: i,
92                discarded: 0,
93                counterexample: Some(Seed {
94                    input: input,
95                    feedback: feedback,
96                    energy: 1000,
97                }),
98            };
99        }
100        if pool.is_empty() {
101            let seed = Seed {
102                input,
103                feedback: feedback,
104                energy: 1000,
105            };
106
107            pool.add_seed(seed);
108        } else {
109            if feedback > pool.best().clone().feedback {
110                let seed = Seed {
111                    input,
112                    feedback: feedback,
113                    energy: 1000,
114                };
115
116                pool.add_seed(seed);
117            }
118        }
119    }
120
121    RunResult {
122        passed: fuel,
123        discarded: 0,
124        counterexample: None,
125    }
126}