Skip to content

Commit c304946

Browse files
authored
chore: Slightly nicer fuzzer assertions (#5240)
Signed-off-by: Robert Kruszewski <[email protected]>
1 parent 47c0dea commit c304946

File tree

3 files changed

+68
-21
lines changed

3 files changed

+68
-21
lines changed

fuzz/fuzz_targets/array_ops.rs

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ use std::backtrace::Backtrace;
88

99
use libfuzzer_sys::{Corpus, fuzz_target};
1010
use vortex_array::arrays::ConstantArray;
11-
use vortex_array::compute::{cast, compare, fill_null, filter, mask, min_max, sum, take};
11+
use vortex_array::compute::{
12+
MinMaxResult, cast, compare, fill_null, filter, mask, min_max, sum, take,
13+
};
1214
use vortex_array::search_sorted::{SearchResult, SearchSorted, SearchSortedSide};
1315
use vortex_array::{Array, ArrayRef, IntoArray};
1416
use vortex_btrblocks::BtrBlocksCompressor;
@@ -88,7 +90,7 @@ fuzz_target!(|fuzz_action: FuzzArrayAction| -> Corpus {
8890
}
8991
Action::Sum => {
9092
let sum_result = sum(&current_array).vortex_unwrap();
91-
assert_scalar_eq(&expected.scalar(), &sum_result);
93+
assert_scalar_eq(&expected.scalar(), &sum_result, i).unwrap();
9294
}
9395
Action::MinMax => {
9496
let min_max_result = min_max(&current_array).vortex_unwrap();
@@ -106,7 +108,7 @@ fuzz_target!(|fuzz_action: FuzzArrayAction| -> Corpus {
106108
let expected_scalars = expected.scalar_vec();
107109
for (j, &idx) in indices.iter().enumerate() {
108110
let scalar = current_array.scalar_at(idx);
109-
assert_scalar_eq(&expected_scalars[j], &scalar);
111+
assert_scalar_eq(&expected_scalars[j], &scalar, i).unwrap();
110112
}
111113
}
112114
}
@@ -137,8 +139,16 @@ fn assert_search_sorted(
137139
}
138140
}
139141

140-
// TODO(ngates): this is horrific... we should have an array_equals compute function?
141142
fn assert_array_eq(lhs: &ArrayRef, rhs: &ArrayRef, step: usize) -> VortexFuzzResult<()> {
143+
if lhs.dtype() != rhs.dtype() {
144+
return Err(VortexFuzzError::DTypeMismatch(
145+
lhs.clone(),
146+
rhs.clone(),
147+
step,
148+
Backtrace::capture(),
149+
));
150+
}
151+
142152
if lhs.len() != rhs.len() {
143153
return Err(VortexFuzzError::LengthMismatch(
144154
lhs.len(),
@@ -168,22 +178,30 @@ fn assert_array_eq(lhs: &ArrayRef, rhs: &ArrayRef, step: usize) -> VortexFuzzRes
168178
Ok(())
169179
}
170180

171-
fn assert_scalar_eq(lhs: &Scalar, rhs: &Scalar) {
172-
// Use catch_unwind to handle panics in scalar comparison (e.g., decimal conversion issues)
173-
assert_eq!(
174-
lhs, rhs,
175-
"Scalar mismatch: expected {:?}, got {:?}",
176-
lhs, rhs
177-
);
181+
fn assert_scalar_eq(lhs: &Scalar, rhs: &Scalar, step: usize) -> VortexFuzzResult<()> {
182+
if lhs != rhs {
183+
return Err(VortexFuzzError::ScalarMismatch(
184+
lhs.clone(),
185+
rhs.clone(),
186+
step,
187+
Backtrace::capture(),
188+
));
189+
}
190+
Ok(())
178191
}
179192

180193
fn assert_min_max_eq(
181-
lhs: &Option<vortex_array::compute::MinMaxResult>,
182-
rhs: &Option<vortex_array::compute::MinMaxResult>,
183-
_step: usize,
194+
lhs: &Option<MinMaxResult>,
195+
rhs: &Option<MinMaxResult>,
196+
step: usize,
184197
) -> VortexFuzzResult<()> {
185198
if lhs != rhs {
186-
vortex_panic!("MinMax mismatch: expected {:?}, got {:?}", lhs, rhs);
199+
return Err(VortexFuzzError::MinMaxMismatch(
200+
lhs.clone(),
201+
rhs.clone(),
202+
step,
203+
Backtrace::capture(),
204+
));
187205
}
188206
Ok(())
189207
}

fuzz/src/error.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@ use std::error::Error;
66
use std::fmt;
77
use std::fmt::{Debug, Display, Formatter};
88

9-
use vortex_array::ArrayRef;
9+
use vortex_array::compute::MinMaxResult;
1010
use vortex_array::search_sorted::{SearchResult, SearchSortedSide};
11+
use vortex_array::{Array, ArrayRef};
1112
use vortex_error::VortexError;
1213
use vortex_scalar::Scalar;
1314

1415
#[non_exhaustive]
1516
pub enum VortexFuzzError {
17+
ScalarMismatch(Scalar, Scalar, usize, Backtrace),
18+
1619
SearchSortedError(
1720
Scalar,
1821
SearchResult,
@@ -23,8 +26,12 @@ pub enum VortexFuzzError {
2326
Backtrace,
2427
),
2528

29+
MinMaxMismatch(Option<MinMaxResult>, Option<MinMaxResult>, usize, Backtrace),
30+
2631
ArrayNotEqual(Scalar, Scalar, usize, ArrayRef, ArrayRef, usize, Backtrace),
2732

33+
DTypeMismatch(ArrayRef, ArrayRef, usize, Backtrace),
34+
2835
LengthMismatch(usize, usize, ArrayRef, ArrayRef, usize, Backtrace),
2936

3037
VortexError(VortexError, Backtrace),
@@ -39,6 +46,12 @@ impl Debug for VortexFuzzError {
3946
impl Display for VortexFuzzError {
4047
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
4148
match self {
49+
VortexFuzzError::ScalarMismatch(lhs, rhs, step, backtrace) => {
50+
write!(
51+
f,
52+
"Scalar mismatch: expected {lhs}, got {rhs} in step {step}\nBacktrace:\n{backtrace}"
53+
)
54+
}
4255
VortexFuzzError::SearchSortedError(
4356
a,
4457
expected,
@@ -54,6 +67,12 @@ impl Display for VortexFuzzError {
5467
array.display_tree(),
5568
)
5669
}
70+
VortexFuzzError::MinMaxMismatch(lhs, rhs, step, backtrace) => {
71+
write!(
72+
f,
73+
"MinMax mismatch: expected {lhs:?} got {rhs:?} in step {step}\nBacktrace:\n{backtrace}"
74+
)
75+
}
5776
VortexFuzzError::ArrayNotEqual(expected, actual, idx, lhs, rhs, step, backtrace) => {
5877
write!(
5978
f,
@@ -62,6 +81,14 @@ impl Display for VortexFuzzError {
6281
rhs.display_tree(),
6382
)
6483
}
84+
VortexFuzzError::DTypeMismatch(lhs, rhs, step, backtrace) => {
85+
write!(
86+
f,
87+
"DType mismatch: expected {}, got {} in step {step}\nBacktrace:\n{backtrace}",
88+
lhs.dtype(),
89+
rhs.dtype()
90+
)
91+
}
6592
VortexFuzzError::LengthMismatch(lhs_len, rhs_len, lhs, rhs, step, backtrace) => {
6693
write!(
6794
f,
@@ -80,10 +107,13 @@ impl Display for VortexFuzzError {
80107
impl Error for VortexFuzzError {
81108
fn source(&self) -> Option<&(dyn Error + 'static)> {
82109
match self {
83-
VortexFuzzError::SearchSortedError(..) => None,
84-
VortexFuzzError::ArrayNotEqual(..) => None,
85-
VortexFuzzError::LengthMismatch(..) => None,
86110
VortexFuzzError::VortexError(err, ..) => Some(err),
111+
VortexFuzzError::SearchSortedError(..)
112+
| VortexFuzzError::ArrayNotEqual(..)
113+
| VortexFuzzError::LengthMismatch(..)
114+
| VortexFuzzError::ScalarMismatch(..)
115+
| VortexFuzzError::MinMaxMismatch(..)
116+
| VortexFuzzError::DTypeMismatch(..) => None,
87117
}
88118
}
89119
}

fuzz/src/lib.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

4-
// VortexFuzzError is quite large, but we don't care about the performance impact for fuzzing.
5-
#![allow(clippy::result_large_err)]
4+
#![allow(clippy::use_debug)]
65

76
mod array;
87
pub mod error;

0 commit comments

Comments
 (0)