#![forbid(unsafe_code)]
#![allow(clippy::unwrap_used)]
use super::{parse_scp_target, ScpPathPlan};
use std::path::PathBuf;
fn test_vps(name: &str) -> crate::domain::VpsName {
crate::domain::VpsName::try_new(name).unwrap()
}
fn no_slots() -> crate::cli::TransferSlots {
crate::cli::TransferSlots::new(Vec::new(), None)
}
#[test]
fn parse_scp_target_multi_file_single_host() {
let plan = parse_scp_target(
false,
None,
no_slots(),
vec!["prod".into(), "a.bin".into(), "b.bin".into(), "/tmp".into()],
)
.unwrap();
match plan {
ScpPathPlan::MultiFile {
vps,
sources,
dest_dir,
} => {
assert_eq!(vps, "prod");
assert_eq!(sources.len(), 2);
assert_eq!(dest_dir, PathBuf::from("/tmp"));
}
other => panic!("expected MultiFile, got {other:?}"),
}
}
#[test]
fn parse_scp_target_multi_file_with_all_is_cartesian() {
let plan = parse_scp_target(
true,
None,
crate::cli::TransferSlots::new(vec!["a.bin".into(), "b.bin".into()], Some("/tmp".into())),
Vec::new(),
)
.unwrap();
match plan {
ScpPathPlan::MultiHostMultiFile {
selection,
sources,
dest_dir,
} => {
assert_eq!(selection, crate::vps::HostSelection::All);
assert_eq!(sources.len(), 2);
assert_eq!(dest_dir, PathBuf::from("/tmp"));
}
other => panic!("expected MultiHostMultiFile, got {other:?}"),
}
}
#[test]
fn parse_scp_target_multi_file_with_hosts() {
let plan = parse_scp_target(
false,
Some("x,y".into()),
crate::cli::TransferSlots::new(
vec!["a.bin".into(), "b.bin".into()],
Some("/remote/dir".into()),
),
Vec::new(),
)
.unwrap();
match plan {
ScpPathPlan::MultiHostMultiFile {
selection,
sources,
dest_dir,
} => {
assert_eq!(
selection,
crate::vps::HostSelection::Named(vec![test_vps("x"), test_vps("y")])
);
assert_eq!(sources.len(), 2);
assert_eq!(dest_dir, PathBuf::from("/remote/dir"));
}
other => panic!("expected MultiHostMultiFile, got {other:?}"),
}
}
#[test]
fn parse_scp_target_classic_three() {
let plan = parse_scp_target(
false,
None,
no_slots(),
vec!["prod".into(), "a.bin".into(), "/tmp/a.bin".into()],
)
.unwrap();
match plan {
ScpPathPlan::Single {
selection,
path_a,
path_b,
} => {
assert_eq!(
selection,
crate::vps::HostSelection::Single(test_vps("prod"))
);
assert_eq!(path_a, PathBuf::from("a.bin"));
assert_eq!(path_b, PathBuf::from("/tmp/a.bin"));
}
other => panic!("expected Single, got {other:?}"),
}
}
#[test]
fn parse_scp_target_refuses_selector_with_three_positionals() {
for (all, hosts) in [(true, None), (false, Some("x,y".to_string()))] {
let err = parse_scp_target(
all,
hosts.clone(),
no_slots(),
vec!["prod".into(), "a.bin".into(), "/tmp/dir".into()],
)
.expect_err("a selector with three positionals is ambiguous");
assert!(
err.contains("ambiguous"),
"the refusal must state the reason: {err}"
);
assert!(
err.contains("--src") && err.contains("--dest"),
"the refusal must point at the named slots: {err}"
);
}
}
#[test]
fn parse_scp_target_keeps_slot_zero_as_the_host_without_a_selector() {
let plan = parse_scp_target(
false,
None,
no_slots(),
vec!["prod".into(), "a.bin".into(), "/tmp/dir".into()],
)
.expect("single-host three-positional form is unambiguous");
match plan {
ScpPathPlan::Single { selection, .. } => {
assert_eq!(
selection,
crate::vps::HostSelection::Single(test_vps("prod"))
);
}
other => panic!("expected Single, got {other:?}"),
}
}
#[test]
fn parse_scp_target_allows_selector_with_two_positionals() {
let plan = parse_scp_target(
true,
None,
no_slots(),
vec!["a.bin".into(), "/tmp/a.bin".into()],
)
.expect("one source under a selector has no rival reading");
assert!(matches!(plan, ScpPathPlan::Single { .. }));
}
#[test]
fn parse_scp_target_named_slots_single_host() {
let plan = parse_scp_target(
false,
None,
crate::cli::TransferSlots::new(vec!["a.bin".into()], Some("/tmp/dir".into())),
vec!["prod".into()],
)
.expect("VPS positional plus named slots");
match plan {
ScpPathPlan::MultiFile {
vps,
sources,
dest_dir,
} => {
assert_eq!(vps, "prod");
assert_eq!(sources, vec![PathBuf::from("a.bin")]);
assert_eq!(dest_dir, PathBuf::from("/tmp/dir"));
}
other => panic!("expected MultiFile, got {other:?}"),
}
}
#[test]
fn parse_scp_target_refuses_a_lone_named_slot() {
assert!(parse_scp_target(
false,
None,
crate::cli::TransferSlots::new(vec!["a.bin".into()], None),
vec!["prod".into()],
)
.is_err());
assert!(parse_scp_target(
false,
None,
crate::cli::TransferSlots::new(Vec::new(), Some("/tmp".into())),
vec!["prod".into()],
)
.is_err());
}
#[test]
fn parse_scp_target_refuses_stray_positionals_beside_named_slots() {
assert!(parse_scp_target(
true,
None,
crate::cli::TransferSlots::new(vec!["a.bin".into()], Some("/tmp".into())),
vec!["leftover".into()],
)
.is_err());
assert!(parse_scp_target(
false,
None,
crate::cli::TransferSlots::new(vec!["a.bin".into()], Some("/tmp".into())),
vec!["prod".into(), "leftover".into()],
)
.is_err());
}