pub fn parse(s: &str) -> Result<i64, String> {
let s = s.trim().to_lowercase();
if let Ok(bytes) = s.parse::<i64>() {
return Ok(bytes);
}
if s.ends_with('k') {
let number_str = &s[..s.len() - 1];
let number: f64 = number_str
.parse()
.map_err(|_| "Invalid number format".to_string())?;
Ok((number * 1024.0) as i64)
} else if s.ends_with('m') {
let number_str = &s[..s.len() - 1];
let number: f64 = number_str
.parse()
.map_err(|_| "Invalid number format".to_string())?;
Ok((number * 1024.0 * 1024.0) as i64)
} else {
Err("Invalid size format. Use plain bytes, 'k' for KB, or 'm' for MB".to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_bytes() {
assert_eq!(
parse("1024"),
Ok(1024),
"Standard byte value should parse correctly"
);
assert_eq!(parse("0"), Ok(0), "Zero bytes should parse correctly");
assert_eq!(
parse("999"),
Ok(999),
"Arbitrary byte value should parse correctly"
);
assert_eq!(parse(" 1024 "), Ok(1024), "Whitespace should be trimmed");
}
#[test]
fn test_parse_kilobytes() {
assert_eq!(
parse("1k"),
Ok(1024),
"Lowercase k should parse as kilobytes"
);
assert_eq!(
parse("1K"),
Ok(1024),
"Uppercase K should parse as kilobytes"
);
assert_eq!(
parse("0.5k"),
Ok(512),
"Decimal kilobytes should parse correctly"
);
assert_eq!(
parse("2k"),
Ok(2048),
"Multiple kilobytes should parse correctly"
);
assert_eq!(
parse(" 1k "),
Ok(1024),
"Whitespace should be trimmed for kilobytes"
);
}
#[test]
fn test_parse_megabytes() {
assert_eq!(
parse("1m"),
Ok(1048576),
"Lowercase m should parse as megabytes"
);
assert_eq!(
parse("1M"),
Ok(1048576),
"Uppercase M should parse as megabytes"
);
assert_eq!(
parse("0.5m"),
Ok(524288),
"Decimal megabytes should parse correctly"
);
assert_eq!(
parse("2m"),
Ok(2097152),
"Multiple megabytes should parse correctly"
);
assert_eq!(
parse(" 1m "),
Ok(1048576),
"Whitespace should be trimmed for megabytes"
);
}
#[test]
fn test_parse_decimal_values() {
assert_eq!(
parse("1.5k"),
Ok(1536),
"Decimal kilobytes should calculate correctly"
);
assert_eq!(
parse("2.25m"),
Ok(2359296),
"Decimal megabytes should calculate correctly"
);
assert_eq!(
parse("0.75k"),
Ok(768),
"Fractional kilobytes should calculate correctly"
);
}
#[test]
fn test_parse_invalid_format() {
let result = parse("invalid");
assert!(
result.is_err(),
"Word 'invalid' should be rejected, got: {:?}",
result
);
let result = parse("1g");
assert!(
result.is_err(),
"Unsupported 'g' suffix should be rejected, got: {:?}",
result
);
let result = parse("1kb");
assert!(
result.is_err(),
"Multi-char 'kb' suffix should be rejected, got: {:?}",
result
);
let result = parse("k");
assert!(
result.is_err(),
"Suffix without number should be rejected, got: {:?}",
result
);
let result = parse("m");
assert!(
result.is_err(),
"Suffix without number should be rejected, got: {:?}",
result
);
let result = parse("");
assert!(
result.is_err(),
"Empty string should be rejected, got: {:?}",
result
);
}
#[test]
fn test_parse_invalid_numbers() {
let result = parse("abc");
assert!(
result.is_err(),
"Non-numeric text should be rejected, got: {:?}",
result
);
let result = parse("1.2.3k");
assert!(
result.is_err(),
"Multiple decimal points should be rejected, got: {:?}",
result
);
let result = parse("--1k");
assert!(
result.is_err(),
"Double negative should be rejected, got: {:?}",
result
);
let result = parse("1..5m");
assert!(
result.is_err(),
"Double decimal points should be rejected, got: {:?}",
result
);
}
#[test]
fn test_parse_negative_values() {
assert_eq!(parse("-1"), Ok(-1), "Negative bytes should parse correctly");
assert_eq!(
parse("-1k"),
Ok(-1024),
"Negative kilobytes should parse correctly"
);
assert_eq!(
parse("-0.5m"),
Ok(-524288),
"Negative decimal megabytes should parse correctly"
);
}
#[test]
fn test_parse_large_values() {
assert_eq!(
parse("1000m"),
Ok(1048576000),
"Large megabyte values should parse correctly"
);
assert_eq!(
parse("9999k"),
Ok(10238976),
"Large kilobyte values should parse correctly"
);
}
}