Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions crates/exec-harness/src/walltime/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ const DEFAULT_MAX_TIME_NS: u64 = 3_000_000_000; // 3 seconds
fn parse_duration_to_ns(s: &str) -> Result<u64> {
let s = s.trim();

// Try parsing as pure number first (interpret as seconds)
if let Ok(seconds) = s.parse::<f64>() {
return Ok((seconds * 1_000_000_000.0) as u64);
}

// Try parsing with humantime
let duration: Duration = humantime::parse_duration(s)
.with_context(|| format!("Invalid duration format: '{s}'. Expected format like '1s', '500ms', '2m', '1h' or a number in seconds"))?;
let duration: Duration = match s.parse::<f64>() {
// Pure numbers are interpreted as seconds. `try_from_secs_f64` rejects negative, NaN and
// infinite values, which a bare `as u64` cast would silently turn into 0 or u64::MAX.
Ok(seconds) => Duration::try_from_secs_f64(seconds).with_context(|| {
format!("Invalid duration: '{s}'. Expected a finite, non-negative number of seconds")
})?,
Err(_) => humantime::parse_duration(s).with_context(|| format!("Invalid duration format: '{s}'. Expected format like '1s', '500ms', '2m', '1h' or a number in seconds"))?,
};

Ok(duration.as_nanos() as u64)
}
Expand Down Expand Up @@ -243,6 +243,8 @@ mod tests {
assert_eq!(parse_duration_to_ns("2").unwrap(), 2_000_000_000); // 2 seconds
assert_eq!(parse_duration_to_ns("0.5").unwrap(), 500_000_000); // 0.5 seconds
assert_eq!(parse_duration_to_ns("0").unwrap(), 0);
// `-0` parses as `-0.0`, which is still a valid way to disable warmup
assert_eq!(parse_duration_to_ns("-0").unwrap(), 0);
assert_eq!(parse_duration_to_ns("1.5").unwrap(), 1_500_000_000); // 1.5 seconds
}

Expand Down Expand Up @@ -274,6 +276,16 @@ mod tests {
assert!(parse_duration_to_ns("").is_err());
}

#[test]
fn test_parse_duration_to_ns_rejects_negative_and_non_finite_numbers() {
for input in ["-1", "-0.5", "NaN", "inf", "-inf"] {
assert!(
parse_duration_to_ns(input).is_err(),
"expected '{input}' to be rejected"
);
}
}

#[test]
fn test_execution_options_from_args() {
// Test creating ExecutionOptions from CLI args
Expand Down Expand Up @@ -329,6 +341,25 @@ mod tests {
);
}

#[test]
fn test_execution_options_from_args_negative_max_time() {
let result: Result<ExecutionOptions> = WalltimeExecutionArgs {
warmup_time: None,
max_time: Some("-1".to_string()),
min_time: None,
max_rounds: None,
min_rounds: None,
}
.try_into();

assert!(result.is_err());
let err = result.unwrap_err().to_string();
assert!(
err.contains("Invalid max_time"),
"Expected error about max_time, got: {err}"
);
}

// Business rule validation tests

#[test]
Expand Down