use super::*;
#[test]
fn test_parse_ports_single() {
assert_eq!(parse_ports(Some("80")), Some(vec![80]));
assert_eq!(parse_ports(Some("443")), Some(vec![443]));
}
#[test]
fn test_parse_ports_comma_separated() {
assert_eq!(parse_ports(Some("80,443,8080")), Some(vec![80, 443, 8080]));
assert_eq!(parse_ports(Some("22,80,443")), Some(vec![22, 80, 443]));
}
#[test]
fn test_parse_ports_range() {
assert_eq!(parse_ports(Some("80-82")), Some(vec![80, 81, 82]));
assert_eq!(parse_ports(Some("22-24")), Some(vec![22, 23, 24]));
}
#[test]
fn test_parse_ports_mixed() {
assert_eq!(
parse_ports(Some("80,443,8080-8082")),
Some(vec![80, 443, 8080, 8081, 8082])
);
}
#[test]
fn test_parse_ports_with_spaces() {
assert_eq!(
parse_ports(Some("80, 443, 8080")),
Some(vec![80, 443, 8080])
);
assert_eq!(parse_ports(Some("80 - 82")), Some(vec![80, 81, 82]));
}
#[test]
fn test_parse_ports_none() {
assert_eq!(parse_ports(None), None);
}
#[test]
fn test_parse_ports_invalid_lenient() {
assert_eq!(parse_ports(Some("invalid")), Some(vec![]));
assert_eq!(parse_ports(Some("80,invalid,443")), Some(vec![80, 443]));
}
#[test]
fn test_parse_ports_checked_invalid() {
let err = parse_ports_checked(Some("invalid")).unwrap_err();
assert!(err.to_string().contains("invalid port list"));
}
#[test]
fn test_parse_ports_checked_rejects_typo() {
let err = parse_ports_checked(Some("80,invalid,443")).unwrap_err();
assert!(
err.to_string().contains("invalid port list"),
"expected strict rejection, got: {err}"
);
}
#[test]
fn test_parse_ports_checked_rejects_out_of_range() {
let err = parse_ports_checked(Some("22,99999")).unwrap_err();
assert!(err.to_string().contains("invalid port list"));
}
#[test]
fn test_parse_ports_checked_rejects_inverted_range() {
let err = parse_ports_checked(Some("90-80")).unwrap_err();
assert!(err.to_string().contains("invalid port list"));
}
#[test]
fn test_parse_ports_checked_enforces_scan_limit() {
let ports = parse_ports_checked(Some("1-4096")).unwrap().unwrap();
assert_eq!(ports.len(), MAX_PORTS_PER_SCAN);
let err = parse_ports_checked(Some("1-4097")).unwrap_err();
assert!(err.to_string().contains("too many ports requested"));
}
#[test]
fn test_parse_ports_checked_empty() {
assert_eq!(parse_ports_checked(Some(" ")).unwrap(), None);
}
#[test]
fn test_parse_ports_checked_sorts_and_dedupes() {
assert_eq!(
parse_ports_checked(Some("443,80,22,80,22")).unwrap(),
Some(vec![22, 80, 443])
);
}
#[test]
fn test_parse_ports_checked_valid() {
assert_eq!(
parse_ports_checked(Some("80,443")).unwrap(),
Some(vec![80, 443])
);
}
#[test]
fn validate_ports_rejects_port_zero() {
assert!(validate_ports(&[0]).is_err());
assert!(validate_ports(&[22, 0, 443]).is_err());
assert!(validate_ports(&[22, 443]).is_ok());
}
#[test]
fn validate_ports_enforces_the_scan_cap() {
let ok: Vec<u16> = (1..=MAX_PORTS_PER_SCAN as u16).collect();
assert!(validate_ports(&ok).is_ok());
let too_many: Vec<u16> = (1..=(MAX_PORTS_PER_SCAN as u16 + 1)).collect();
assert!(validate_ports(&too_many).is_err());
}
#[test]
fn parse_ports_checked_rejects_port_zero() {
for input in ["0", "0,80", "80,0", "0-2"] {
let err = parse_ports_checked(Some(input))
.unwrap_err()
.to_string()
.to_lowercase();
assert!(err.contains("port 0"), "input {input:?} gave: {err}");
}
}
#[test]
fn parse_ports_checked_still_accepts_port_one() {
assert_eq!(parse_ports_checked(Some("1")).unwrap(), Some(vec![1]));
assert_eq!(
parse_ports_checked(Some("1-3")).unwrap(),
Some(vec![1, 2, 3])
);
}
#[test]
fn parse_ports_checked_rejects_an_oversized_list_without_expanding_it() {
let big = "1-65535,".repeat(2000);
let start = std::time::Instant::now();
let err = parse_ports_checked(Some(&big)).unwrap_err().to_string();
let elapsed = start.elapsed();
assert!(err.contains("too many ports"), "unexpected error: {err}");
assert!(
elapsed < std::time::Duration::from_secs(10),
"took {elapsed:?} to reject a list it could have rejected on the first token"
);
}
#[test]
fn parse_ports_checked_still_dedups_across_tokens() {
let overlapping = format!("1-{MAX_PORTS_PER_SCAN},1-{MAX_PORTS_PER_SCAN}");
let parsed = parse_ports_checked(Some(&overlapping)).unwrap().unwrap();
assert_eq!(parsed.len(), MAX_PORTS_PER_SCAN);
assert_eq!(parsed.first(), Some(&1));
assert_eq!(parsed.last(), Some(&(MAX_PORTS_PER_SCAN as u16)));
assert_eq!(
parse_ports_checked(Some("443,22,80,22")).unwrap(),
Some(vec![22, 80, 443])
);
}