use super::CliError;
pub fn ensure_clip_ids(ids: &[String]) -> Result<(), CliError> {
if ids.is_empty() {
return Err(CliError::Config("no clip IDs provided".into()));
}
Ok(())
}
pub fn ensure_destructive_confirmed(yes: bool, command: &str) -> Result<(), CliError> {
if !yes {
return Err(CliError::Config(format!(
"`{command}` requires -y/--yes because it modifies or removes Suno resources"
)));
}
Ok(())
}
pub fn ensure_percentage(name: &str, value: f64) -> Result<(), CliError> {
if !value.is_finite() || !(0.0..=100.0).contains(&value) {
return Err(CliError::Config(format!(
"{name} must be a finite number between 0 and 100"
)));
}
Ok(())
}
pub fn ensure_non_negative_finite(name: &str, value: f64) -> Result<(), CliError> {
if !value.is_finite() || value < 0.0 {
return Err(CliError::Config(format!(
"{name} must be a finite non-negative number"
)));
}
Ok(())
}
pub fn ensure_time_range(name: &str, start: Option<f64>, end: Option<f64>) -> Result<(), CliError> {
if let Some(start) = start {
ensure_non_negative_finite(&format!("{name} start"), start)?;
}
if let Some(end) = end {
ensure_non_negative_finite(&format!("{name} end"), end)?;
}
if let (Some(start), Some(end)) = (start, end)
&& start >= end
{
return Err(CliError::Config(format!(
"{name} start must be less than end"
)));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::{ensure_non_negative_finite, ensure_percentage, ensure_time_range};
#[test]
fn percentages_reject_non_finite_and_out_of_range_values() {
for value in [f64::NAN, f64::INFINITY, -1.0, 101.0] {
ensure_percentage("--weirdness", value).expect_err("invalid percentage");
}
ensure_percentage("--weirdness", 0.0).expect("lower bound");
ensure_percentage("--weirdness", 100.0).expect("upper bound");
}
#[test]
fn timestamps_reject_non_finite_and_negative_values() {
for value in [f64::NAN, f64::INFINITY, -0.1] {
ensure_non_negative_finite("--at", value).expect_err("invalid timestamp");
}
ensure_non_negative_finite("--at", 0.0).expect("zero timestamp");
}
#[test]
fn time_ranges_require_finite_non_negative_ordered_bounds() {
for (start, end) in [
(Some(f64::NAN), Some(1.0)),
(Some(0.0), Some(f64::INFINITY)),
(Some(-0.1), Some(1.0)),
(Some(2.0), Some(1.0)),
(Some(1.0), Some(1.0)),
] {
ensure_time_range("vocal range", start, end).expect_err("invalid range");
}
ensure_time_range("vocal range", Some(0.0), Some(1.0)).expect("valid range");
ensure_time_range("vocal range", Some(0.0), None).expect("partial update");
}
}