1use crate::{panic, panic::PanicError, Failure, Seed, Test};
2use bolero_generator::driver;
3use std::time::Instant;
4
5#[cfg(test)]
6mod tests;
7
8#[allow(clippy::len_without_is_empty)]
9pub trait Input: AsRef<Vec<u8>> + AsMut<Vec<u8>> {
10 type Driver<'a>: crate::Driver + core::panic::RefUnwindSafe
11 where
12 Self: 'a;
13
14 #[inline(always)]
15 fn len(&self) -> usize {
16 self.as_ref().len()
17 }
18
19 fn driver(&self, len: usize, options: &driver::Options) -> Self::Driver<'_>;
20}
21
22impl Input for Vec<u8> {
23 type Driver<'a> = driver::ByteSliceDriver<'a>;
24
25 #[inline]
26 fn driver(&self, len: usize, options: &driver::Options) -> Self::Driver<'_> {
27 driver::ByteSliceDriver::new(&self[..len], options)
28 }
29}
30
31pub fn shrink<T: Test, I: Input>(
33 test: &mut T,
34 input: I,
35 seed: Option<Seed>,
36 options: &driver::Options,
37) -> Option<Failure<T::Value>> {
38 Shrinker::new(test, input, seed, options).shrink()
39}
40
41macro_rules! predicate {
42 ($expr:expr) => {
43 if !($expr) {
44 return Err(());
45 }
46 };
47}
48
49macro_rules! shrink_integer {
50 ($current:expr, $check:expr) => {{
51 let mut check = $check;
52
53 (0..($current)).into_iter().find(|value| check(*value))
54 }};
55}
56
57#[derive(Debug)]
58struct Shrinker<'a, T, I> {
59 test: &'a mut T,
60 input: I,
61 temp_input: Vec<u8>,
62 end: usize,
63 seed: Option<Seed>,
64 options: &'a driver::Options,
65 #[cfg(test)]
66 snapshot_input: Vec<u8>,
67}
68
69impl<'a, T: Test, I: Input> Shrinker<'a, T, I> {
70 fn new(test: &'a mut T, input: I, seed: Option<Seed>, options: &'a driver::Options) -> Self {
71 let len = input.as_ref().len();
72 Self {
73 temp_input: input.as_ref().to_vec(),
74 input,
75 end: len,
76 test,
77 seed,
78 options,
79 #[cfg(test)]
80 snapshot_input: vec![],
81 }
82 }
83
84 fn shrink(mut self) -> Option<Failure<T::Value>> {
85 if self.options.shrink_time_or_default().is_zero() {
86 return None;
87 }
88
89 panic::set_hook();
90 let forward_panic = panic::forward_panic(false);
91 let capture_backtrace = panic::capture_backtrace(false);
92
93 if cfg!(test) {
94 panic::forward_panic(forward_panic);
95 assert!(
96 self.execute().is_err(),
97 "shrinking should only be performed on a failing test"
98 );
99 panic::forward_panic(false);
100 }
101
102 let mut was_changed;
103 let start_time = Instant::now();
104 let shrink_time = self.options.shrink_time_or_default();
105
106 loop {
107 was_changed = self.apply_truncation();
108
109 if self.end == 0 {
111 break;
112 }
113
114 for index in 0..self.end {
115 if index >= self.end {
116 break;
118 }
119
120 self.apply_transforms(index, &mut was_changed);
121
122 if start_time.elapsed() > shrink_time {
124 break;
125 }
126 }
127
128 if !was_changed {
131 break;
132 }
133
134 if start_time.elapsed() > shrink_time {
136 break;
137 }
138 }
139
140 panic::capture_backtrace(capture_backtrace);
141 let error = self.execute().err()?;
142 panic::capture_backtrace(false);
143
144 let input = self.generate_value();
145
146 panic::forward_panic(forward_panic);
148 panic::capture_backtrace(capture_backtrace);
149
150 Some(Failure {
151 seed: self.seed,
152 error,
153 input,
154 })
155 }
156
157 fn apply_truncation(&mut self) -> bool {
158 self.apply("truncation end", |this| this.apply_truncation_end())
159 }
160
161 fn apply_truncation_end(&mut self) -> Result<(), ()> {
162 let prev_value = self.end;
163 let result = shrink_integer!(prev_value, |end| {
164 self.end = end;
165 self.execute().is_err()
166 });
167
168 if let Some(end) = result {
169 self.end = end;
170 Ok(())
171 } else {
172 self.end = prev_value;
174 Err(())
175 }
176 }
177
178 fn apply_transforms(&mut self, index: usize, was_changed: &mut bool) {
179 *was_changed |= self.apply("remove chunk", |this| this.apply_remove_chunk(index));
180
181 if *was_changed {
183 return;
184 }
185
186 *was_changed |= self.apply("sort", |this| this.apply_sort(index));
187
188 *was_changed |= self.apply("byte shrink", |this| this.apply_byte_shrink(index));
189 }
190
191 fn apply_byte_shrink(&mut self, index: usize) -> Result<(), ()> {
192 let prev_value = self.input.as_ref()[index];
193 let result = shrink_integer!(prev_value, |value| {
194 self.input.as_mut()[index] = value;
195 self.execute().is_err()
196 });
197
198 let input = self.input.as_mut();
199 if let Some(value) = result {
200 input[index] = value;
201 Ok(())
202 } else {
203 input[index] = prev_value;
205 Err(())
206 }
207 }
208
209 fn apply_remove_chunk(&mut self, index: usize) -> Result<(), ()> {
210 predicate!(index != 0);
212
213 let slice = &self.input.as_ref()[index..self.end];
214
215 predicate!(slice.len() >= 2);
217
218 let mut temp_input = core::mem::take(&mut self.temp_input);
220 temp_input.clear();
221 temp_input.extend_from_slice(slice);
222
223 let max_len = temp_input.len() - 1;
225
226 let result = shrink_integer!(max_len, |diff| {
227 self.input.as_mut().truncate(index);
228 let offset = max_len - diff;
229 let slice = &temp_input[offset..];
230
231 if cfg!(test) {
233 assert_eq!(slice.len(), diff + 1);
235 }
236
237 self.input.as_mut().extend_from_slice(slice);
238 self.end = self.input.len();
239 self.execute().is_err()
240 });
241
242 self.input.as_mut().truncate(index);
243
244 let res = if let Some(diff) = result {
245 let offset = max_len - diff;
246 self.input.as_mut().extend_from_slice(&temp_input[offset..]);
247 Ok(())
248 } else {
249 self.input.as_mut().extend_from_slice(&temp_input);
250 Err(())
251 };
252
253 self.temp_input = temp_input;
254 self.end = self.input.len();
255
256 res
257 }
258
259 fn apply_sort(&mut self, index: usize) -> Result<(), ()> {
260 predicate!(index + 1 < self.end);
262 predicate!(self.input.as_ref()[index] > self.input.as_ref()[index + 1]);
263
264 self.input.as_mut().swap(index, index + 1);
265
266 if self.execute().is_err() {
267 return Ok(());
268 }
269
270 self.input.as_mut().swap(index, index + 1);
272
273 Err(())
274 }
275
276 #[inline(always)]
277 fn apply<F: FnOnce(&mut Self) -> Result<(), ()>>(&mut self, transform: &str, f: F) -> bool {
278 #[cfg(test)]
280 {
281 self.snapshot_input.truncate(0);
282 self.snapshot_input
283 .extend_from_slice(&self.input.as_ref()[..self.end]);
284 }
285
286 let result = f(self).is_ok();
287
288 #[cfg(test)]
292 {
293 if self.execute().is_ok() {
294 eprintln!(
295 "transform created non-failing test: {}\nBEFORE: {:?}\nAFTER: {:?}",
296 transform,
297 &self.snapshot_input,
298 &self.input.as_ref()[..self.end],
299 );
300 panic!();
301 }
302 }
303
304 let _ = transform;
305
306 result
307 }
308
309 fn execute(&mut self) -> Result<bool, PanicError> {
310 self.test.test(&mut ShrinkInput {
311 input: &self.input,
312 len: self.end,
313 options: self.options,
314 })
315 }
316
317 fn generate_value(&mut self) -> T::Value {
318 self.test.generate_value(&mut ShrinkInput {
319 input: &self.input,
320 len: self.end,
321 options: self.options,
322 })
323 }
324}
325
326struct ShrinkInput<'a, I: Input> {
327 input: &'a I,
328 options: &'a driver::Options,
329 len: usize,
330}
331
332impl<'a, I: Input, Output> crate::Input<Output> for ShrinkInput<'a, I> {
333 type Driver = I::Driver<'a>;
334
335 fn with_slice<F: FnMut(&[u8]) -> Output>(&mut self, f: &mut F) -> Output {
336 f(self.input.as_ref())
337 }
338
339 fn with_driver<F: FnMut(&mut Self::Driver) -> Output>(&mut self, f: &mut F) -> Output {
340 let mut driver = self.input.driver(self.len, self.options);
341 f(&mut driver)
342 }
343}