use std::fmt;
#[derive(Debug, Clone)]
pub struct FuzzResult {
pub target: String,
pub test_cases: u64,
pub failures: u64,
pub coverage_percent: f64,
pub failure_details: Vec<FuzzFailure>,
pub duration_secs: f64,
}
impl FuzzResult {
pub fn new(target: &str) -> Self {
Self {
target: target.to_string(),
test_cases: 0,
failures: 0,
coverage_percent: 0.0,
failure_details: Vec::new(),
duration_secs: 0.0,
}
}
pub fn record_success(&mut self) {
self.test_cases += 1;
}
pub fn record_failure(&mut self, input: String, error: String) {
self.test_cases += 1;
self.failures += 1;
self.failure_details.push(FuzzFailure { input, error });
}
pub fn passed(&self) -> bool {
self.failures == 0
}
pub fn failure_rate(&self) -> f64 {
if self.test_cases == 0 {
0.0
} else {
(self.failures as f64 / self.test_cases as f64) * 100.0
}
}
}
#[derive(Debug, Clone)]
pub struct FuzzFailure {
pub input: String,
pub error: String,
}
#[derive(Debug, Clone, Default)]
pub struct FuzzInputValidator {
pub max_string_len: usize,
pub max_numeric: f64,
pub min_numeric: f64,
pub allow_nan: bool,
pub allow_infinity: bool,
pub allow_negative: bool,
pub allow_zero: bool,
}
impl FuzzInputValidator {
pub fn new() -> Self {
Self {
max_string_len: 1024,
max_numeric: 1e15,
min_numeric: -1e15,
allow_nan: false,
allow_infinity: false,
allow_negative: true,
allow_zero: true,
}
}
pub fn validate_float(&self, value: f64) -> Result<f64, FuzzValidationError> {
if value.is_nan() && !self.allow_nan {
return Err(FuzzValidationError::NaN);
}
if value.is_infinite() && !self.allow_infinity {
return Err(FuzzValidationError::Infinity);
}
if value < 0.0 && !self.allow_negative {
return Err(FuzzValidationError::NegativeValue(value));
}
if value == 0.0 && !self.allow_zero {
return Err(FuzzValidationError::ZeroValue);
}
if value > self.max_numeric {
return Err(FuzzValidationError::TooLarge(value));
}
if value < self.min_numeric {
return Err(FuzzValidationError::TooSmall(value));
}
Ok(value)
}
pub fn validate_string<'a>(&self, value: &'a str) -> Result<&'a str, FuzzValidationError> {
if value.len() > self.max_string_len {
return Err(FuzzValidationError::StringTooLong(value.len()));
}
if value
.chars()
.any(|c| c.is_control() && c != '\n' && c != '\t')
{
return Err(FuzzValidationError::InvalidControlChars);
}
Ok(value)
}
pub fn validate_u64(&self, value: u64) -> Result<u64, FuzzValidationError> {
let max = self.max_numeric as u64;
if value > max {
return Err(FuzzValidationError::TooLarge(value as f64));
}
if value == 0 && !self.allow_zero {
return Err(FuzzValidationError::ZeroValue);
}
Ok(value)
}
pub fn positive_only() -> Self {
Self {
allow_negative: false,
allow_zero: false,
..Self::new()
}
}
pub fn non_negative() -> Self {
Self {
allow_negative: false,
..Self::new()
}
}
pub fn strict() -> Self {
Self {
allow_nan: false,
allow_infinity: false,
max_numeric: 1e12,
min_numeric: -1e12,
..Self::new()
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum FuzzValidationError {
NaN,
Infinity,
NegativeValue(f64),
ZeroValue,
TooLarge(f64),
TooSmall(f64),
StringTooLong(usize),
InvalidControlChars,
IntegerOverflow,
DivisionByZero,
EmptyInput,
InvalidFormat(String),
}
impl fmt::Display for FuzzValidationError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
FuzzValidationError::NaN => write!(f, "NaN value not allowed"),
FuzzValidationError::Infinity => write!(f, "Infinity value not allowed"),
FuzzValidationError::NegativeValue(v) => write!(f, "Negative value not allowed: {}", v),
FuzzValidationError::ZeroValue => write!(f, "Zero value not allowed"),
FuzzValidationError::TooLarge(v) => write!(f, "Value too large: {}", v),
FuzzValidationError::TooSmall(v) => write!(f, "Value too small: {}", v),
FuzzValidationError::StringTooLong(len) => write!(f, "String too long: {} chars", len),
FuzzValidationError::InvalidControlChars => write!(f, "Invalid control characters"),
FuzzValidationError::IntegerOverflow => write!(f, "Integer overflow"),
FuzzValidationError::DivisionByZero => write!(f, "Division by zero"),
FuzzValidationError::EmptyInput => write!(f, "Empty input"),
FuzzValidationError::InvalidFormat(s) => write!(f, "Invalid format: {}", s),
}
}
}
impl std::error::Error for FuzzValidationError {}