use crate::assignee::{self, AuthorIdentity};
use crate::slug::slugify;
#[must_use]
pub fn local_candidates() -> Vec<String> {
local_candidates_for("git")
}
#[must_use]
pub(crate) fn local_candidates_for(program: &str) -> Vec<String> {
match assignee::git_identity_for(program) {
Some(identity) => candidates_from(&identity),
None => Vec::new(),
}
}
#[must_use]
pub fn candidates_from(identity: &AuthorIdentity) -> Vec<String> {
let mut out: Vec<String> = Vec::new();
let mut push = |value: &str| {
let value = value.trim().to_lowercase();
if !value.is_empty() && !out.contains(&value) {
out.push(value);
}
};
push(&slugify(&identity.name));
if let Some(email) = &identity.email {
let local = email.split('@').next().unwrap_or_default();
push(&slugify(local));
push(email);
}
out
}
#[cfg(test)]
mod tests {
#[allow(clippy::wildcard_imports)]
use super::*;
use std::io::Write;
use std::os::unix::fs::PermissionsExt;
fn fake_git(
dir: &std::path::Path,
name: Option<&str>,
email: Option<&str>,
) -> std::path::PathBuf {
let script = dir.join("fake-git.sh");
let name_line =
name.map_or_else(|| "exit 1".to_string(), |n| format!("printf '%s\\n' '{n}'"));
let email_line =
email.map_or_else(|| "exit 1".to_string(), |e| format!("printf '%s\\n' '{e}'"));
let mut file = std::fs::File::create(&script).unwrap();
writeln!(
file,
"#!/bin/sh\ncase \"$3\" in\n user.name) {name_line} ;;\n user.email) {email_line} ;;\nesac\nexit 0"
)
.unwrap();
std::fs::set_permissions(&script, std::fs::Permissions::from_mode(0o755)).unwrap();
script
}
#[test]
fn a_full_identity_yields_the_name_slug_the_email_slug_and_the_email() {
let tmp = tempfile::TempDir::new().unwrap();
let git = fake_git(tmp.path(), Some("Herbert Maschke"), Some("thyseus@pm.me"));
let candidates = local_candidates_for(git.to_str().unwrap());
assert_eq!(
candidates,
vec![
"herbert-maschke".to_string(),
"thyseus".to_string(),
"thyseus@pm.me".to_string()
]
);
}
#[test]
fn an_email_only_identity_yields_the_email_breadth() {
let tmp = tempfile::TempDir::new().unwrap();
let git = fake_git(tmp.path(), None, Some("thyseus@pm.me"));
assert_eq!(
local_candidates_for(git.to_str().unwrap()),
[] as [std::string::String; 0]
);
}
#[test]
fn a_name_that_is_already_a_slug_is_kept_as_is() {
let identity = AuthorIdentity {
name: "herbert-maschke".to_string(),
email: None,
};
assert_eq!(
candidates_from(&identity),
vec!["herbert-maschke".to_string()]
);
}
#[test]
fn no_git_means_no_candidates_and_no_error() {
let tmp = tempfile::TempDir::new().unwrap();
let git = fake_git(tmp.path(), None, None);
assert_eq!(
local_candidates_for(git.to_str().unwrap()),
[] as [std::string::String; 0]
);
}
#[test]
fn candidates_are_deduplicated_and_lowercased() {
let identity = AuthorIdentity {
name: "Thyseus".to_string(),
email: Some("Thyseus@PM.ME".to_string()),
};
assert_eq!(
candidates_from(&identity),
vec!["thyseus".to_string(), "thyseus@pm.me".to_string()]
);
}
#[test]
fn a_handle_and_an_email_of_one_person_slug_to_different_files() {
assert_eq!(
crate::mentions::store::MentionStore::slug("herbert-maschke"),
"herbert-maschke"
);
assert_eq!(
crate::mentions::store::MentionStore::slug("thyseus@pm.me"),
"thyseus-pm-me"
);
}
}