#[derive(Debug, Clone, PartialEq)]
pub struct Query {
pub user: Option<String>,
pub hosts: Vec<String>,
pub long: bool,
pub port: u16,
}
pub const DEFAULT_PORT: u16 = 79;
impl Query {
pub fn parse(input: Option<&str>, long: bool, port: u16) -> Query {
let input = input.unwrap_or("");
if input.is_empty() {
return Query {
user: None,
hosts: vec!["localhost".to_string()],
long,
port,
};
}
let parts: Vec<&str> = input.splitn(2, '@').collect();
if parts.len() == 1 {
return Query {
user: Some(parts[0].to_string()),
hosts: vec!["localhost".to_string()],
long,
port,
};
}
let user = if parts[0].is_empty() {
None
} else {
Some(parts[0].to_string())
};
let hosts: Vec<String> = parts[1].split('@').map(|s| s.to_string()).collect();
Query {
user,
hosts,
long,
port,
}
}
pub fn target_host(&self) -> &str {
self.hosts.last().expect("hosts must not be empty")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_user_at_host() {
let q = Query::parse(Some("user@host"), false, 79);
assert_eq!(q.user, Some("user".to_string()));
assert_eq!(q.hosts, vec!["host".to_string()]);
assert!(!q.long);
assert_eq!(q.port, 79);
}
#[test]
fn parse_at_host_lists_users() {
let q = Query::parse(Some("@host"), false, 79);
assert_eq!(q.user, None);
assert_eq!(q.hosts, vec!["host".to_string()]);
}
#[test]
fn parse_user_only_defaults_to_localhost() {
let q = Query::parse(Some("user"), false, 79);
assert_eq!(q.user, Some("user".to_string()));
assert_eq!(q.hosts, vec!["localhost".to_string()]);
}
#[test]
fn parse_empty_string_defaults_to_localhost() {
let q = Query::parse(Some(""), false, 79);
assert_eq!(q.user, None);
assert_eq!(q.hosts, vec!["localhost".to_string()]);
}
#[test]
fn parse_none_defaults_to_localhost() {
let q = Query::parse(None, false, 79);
assert_eq!(q.user, None);
assert_eq!(q.hosts, vec!["localhost".to_string()]);
}
#[test]
fn parse_forwarding_chain() {
let q = Query::parse(Some("user@host1@host2"), false, 79);
assert_eq!(q.user, Some("user".to_string()));
assert_eq!(q.hosts, vec!["host1".to_string(), "host2".to_string()]);
}
#[test]
fn parse_forwarding_chain_no_user() {
let q = Query::parse(Some("@host1@host2"), false, 79);
assert_eq!(q.user, None);
assert_eq!(q.hosts, vec!["host1".to_string(), "host2".to_string()]);
}
#[test]
fn parse_long_flag_preserved() {
let q = Query::parse(Some("user@host"), true, 79);
assert!(q.long);
}
#[test]
fn parse_custom_port_preserved() {
let q = Query::parse(Some("user@host"), false, 7979);
assert_eq!(q.port, 7979);
}
#[test]
fn target_host_returns_last_host() {
let q = Query::parse(Some("user@host1@host2"), false, 79);
assert_eq!(q.target_host(), "host2");
}
#[test]
fn target_host_single_host() {
let q = Query::parse(Some("user@host"), false, 79);
assert_eq!(q.target_host(), "host");
}
#[test]
fn parse_three_host_chain() {
let q = Query::parse(Some("user@a@b@c"), false, 79);
assert_eq!(q.user, Some("user".to_string()));
assert_eq!(
q.hosts,
vec!["a".to_string(), "b".to_string(), "c".to_string()]
);
assert_eq!(q.target_host(), "c");
}
}