use calcli::keymap::Action;
const EXAMPLE_CONFIG: &str = include_str!("../examples/config.toml");
const README: &str = include_str!("../README.md");
fn documented_config_names() -> Vec<String> {
let mut names = Vec::new();
let mut inside = false;
for line in EXAMPLE_CONFIG.lines() {
let line = line.trim();
let Some(body) = line.strip_prefix('#') else {
if !line.is_empty() {
inside = false;
}
continue;
};
let body = body.trim();
if body == "[keys]" {
inside = true;
continue;
}
if body.starts_with('[') {
inside = false;
continue;
}
if inside && let Some((name, _)) = body.split_once('=') {
let name = name.trim();
if !name.is_empty() && !name.starts_with('#') {
names.push(name.to_string());
}
}
}
names
}
#[test]
fn the_example_config_documents_every_action_exactly_once() {
let mut documented = documented_config_names();
documented.sort();
let mut deduped = documented.clone();
deduped.dedup();
assert_eq!(documented, deduped, "a [keys] name is listed twice");
let mut catalog: Vec<String> =
Action::all().map(|a| a.config_name().to_string()).collect();
catalog.sort();
assert_eq!(
documented, catalog,
"examples/config.toml and the action catalog have drifted apart",
);
}
const KEY_SPELLINGS: &[(&str, &str)] = &[
("up", "↑"),
("down", "↓"),
("left", "←"),
("right", "→"),
("pgup", "PgUp"),
("pgdn", "PgDn"),
("del", "Del"),
("home", "Home"),
("end", "End"),
("esc", "Esc"),
("enter", "Enter"),
];
fn as_readme_spells_it(key: &str) -> String {
let modified = key.contains('+');
key.split('+')
.map(|part| {
if modified && part.chars().count() == 1 {
return part.to_uppercase();
}
if let Some((_, shown)) =
KEY_SPELLINGS.iter().find(|(raw, _)| *raw == part)
{
return (*shown).to_string();
}
let is_function_key = part.starts_with('f')
&& part.len() > 1
&& part[1..].chars().all(|c| c.is_ascii_digit());
if is_function_key {
return part.to_uppercase();
}
let mut chars = part.chars();
match chars.next() {
Some(first) if part.len() > 1 => {
first.to_uppercase().collect::<String>() + chars.as_str()
}
_ => part.to_string(),
}
})
.collect::<Vec<_>>()
.join("+")
}
#[test]
fn the_readme_documents_every_action() {
let missing: Vec<String> = Action::all()
.filter(|action| {
!action
.default_keys()
.iter()
.any(|key| README.contains(&as_readme_spells_it(key)))
})
.map(|action| {
format!(
"{} ({})",
action.config_name(),
action.default_keys().join(", "),
)
})
.collect();
assert!(
missing.is_empty(),
"the README does not mention these actions: {missing:?}",
);
}
#[test]
fn the_readme_documents_the_toolkit_owned_keys() {
for key in ["Ctrl+Q", "F1"] {
assert!(README.contains(key), "the README omits {key}");
}
}
#[test]
fn the_readme_never_advertises_ctrl_c_as_quit() {
for line in README.lines() {
if line.contains("Ctrl+C") {
assert!(
!line.to_lowercase().contains("quit"),
"Ctrl+C is the clipboard, never quit: {line}",
);
}
}
}
#[test]
fn the_readme_check_can_actually_fail() {
assert_eq!(as_readme_spells_it("ctrl+y"), "Ctrl+Y");
assert_eq!(as_readme_spells_it("alt+up"), "Alt+↑");
assert_eq!(as_readme_spells_it("f12"), "F12");
assert_eq!(
as_readme_spells_it("Y"),
"Y",
"a bare letter keeps its case"
);
assert!(
!README.contains(&as_readme_spells_it("ctrl+alt+f9")),
"a key nobody documented must not be found",
);
}
#[test]
fn the_config_check_reads_real_names() {
let names = documented_config_names();
assert!(names.contains(&"view_calc".to_string()), "{names:?}");
assert!(!names.contains(&"definitely_not_an_action".to_string()));
assert!(names.len() > 30, "only {} names parsed", names.len());
}