use super::registry::{Hit, Registry};
use super::{Query, test_registry};
use crate::sidebar::SettingsTab;
struct Expect {
query: &'static str,
tab: SettingsTab,
section: &'static str,
control: Option<&'static str>,
}
const fn to(
query: &'static str,
tab: SettingsTab,
section: &'static str,
control: &'static str,
) -> Expect {
Expect {
query,
tab,
section,
control: Some(control),
}
}
const fn to_section(query: &'static str, tab: SettingsTab, section: &'static str) -> Expect {
Expect {
query,
tab,
section,
control: None,
}
}
fn audit_queries() -> Vec<Expect> {
use SettingsTab::*;
vec![
to("cursor blink", Appearance, "Cursor", "Cursor blink"),
to("option as meta", Keys, "Keyboard", OPTION_SENDS),
to(
"copy on select",
General,
"Selection & Clipboard",
"Auto-copy selection",
),
to(
"close confirmation",
General,
"Closing & Quitting",
"Close Confirmation",
),
to(
"prompt on quit",
General,
"Closing & Quitting",
"Confirm before quitting with open tabs",
),
to_section("leader", Keys, "Leader Key"),
to("detach", Keys, "Keybindings", "Move Tab to New Window"),
to_section("par-mux", Sessions, "par-mux"),
to(
"notify",
Advanced,
"Activity",
"Notify on activity after inactivity",
),
to(
"command complete",
Advanced,
"Alert Sounds",
"Command Complete",
),
to("mouse", Advanced, "Auto-Hide", "Hide on mouse inactivity"),
to_section("general", Appearance, "General"),
to_section("custom actions", Automation, "Custom Actions"),
to_section("observer scripts", Automation, "Observer Scripts"),
to_section("prompt library", Assistant, "Prompt Library"),
]
}
#[cfg(target_os = "macos")]
const OPTION_SENDS: &str = "Left Option sends:";
#[cfg(not(target_os = "macos"))]
const OPTION_SENDS: &str = "Left Alt sends:";
fn describe(registry: &Registry, hits: &[Hit]) -> Vec<String> {
hits.iter()
.take(12)
.map(|h| {
let s = ®istry.sections[h.section];
match registry.control(*h) {
Some(c) => format!("{:?} › {} › {}", s.tab, s.title, c.label),
None => format!("{:?} › {}", s.tab, s.title),
}
})
.collect()
}
fn lands(registry: &Registry, hits: &[Hit], expect: &Expect) -> bool {
hits.iter().any(|h| {
let s = ®istry.sections[h.section];
s.tab == expect.tab
&& s.title == expect.section
&& match expect.control {
None => h.control.is_none(),
Some(label) => registry.control(*h).is_some_and(|c| c.label == label),
}
})
}
#[test]
fn the_audit_queries_resolve_to_their_controls() {
let registry = test_registry();
let mut failures = Vec::new();
for expect in audit_queries() {
let hits = registry.search(&Query::parse(expect.query));
if !lands(®istry, &hits, &expect) {
failures.push(format!(
"{:?} -> expected {:?} › {} › {:?}; got {:?}",
expect.query,
expect.tab,
expect.section,
expect.control,
describe(®istry, &hits)
));
}
}
assert!(
failures.is_empty(),
"audit queries that miss:\n{}",
failures.join("\n")
);
}
#[test]
fn the_empty_page_queries_now_show_something() {
let registry = test_registry();
for query in ["tmux", "gateway", "export", "run command"] {
let hits = registry.search(&Query::parse(query));
assert!(!hits.is_empty(), "{query:?} has no result");
}
}
#[test]
fn every_section_keyword_and_control_label_resolves_on_its_own_tab() {
let registry = test_registry();
let mut failures = Vec::new();
let mut checked = 0;
for (si, section) in registry.sections.iter().enumerate() {
let terms = std::iter::once((section.title.as_str(), None))
.chain(section.keywords.iter().map(|k| (k.as_str(), None)))
.chain(
section
.controls
.iter()
.enumerate()
.map(|(ci, c)| (c.label.as_str(), Some(ci))),
);
for (term, control) in terms {
let query = Query::parse(term);
if query.is_empty() {
continue;
}
checked += 1;
let hits = registry.search(&query);
let visible = registry.visible_sections(&query, &hits);
let own = hits.iter().any(|h| {
registry.sections[h.section].tab == section.tab
&& (control.is_none() || (h.section == si && h.control == control))
});
if !own || !visible.contains(§ion.id) {
failures.push(format!(
"{:?} › {} › {term:?} (own hit: {own}, section shown: {})",
section.tab,
section.title,
visible.contains(§ion.id)
));
}
}
}
assert!(checked > 500, "only {checked} terms checked");
assert!(
failures.is_empty(),
"{} of {checked} terms do not resolve on their own tab:\n{}",
failures.len(),
failures.join("\n")
);
}
#[test]
fn documented_search_terms_find_their_tab() {
use SettingsTab::*;
let cases: &[(SettingsTab, &[&str])] = &[
(
Automation,
&[
"trigger",
"regex",
"pattern",
"match",
"action",
"highlight",
"notify",
"coprocess",
"pipe",
"subprocess",
"auto start",
"restart",
"script",
"observer",
"event",
"panel",
"subscriptions",
],
),
(
General,
&["download", "upload", "transfer", "save location"],
),
];
let mut missing = Vec::new();
for (tab, terms) in cases {
for term in *terms {
if !super::tab_has_result(*tab, term) {
missing.push(format!("{tab:?}: {term:?}"));
}
}
}
assert!(
missing.is_empty(),
"documented terms not found: {missing:?}"
);
}
#[test]
fn yaml_keys_find_their_controls() {
use SettingsTab::*;
let registry = test_registry();
for (key, tab, label) in [
("window_padding", WindowsAndTabs, "Padding:"),
("cursor_blink", Appearance, "Cursor blink"),
("scrollback_lines", Advanced, "Scrollback lines:"),
(
"prompt_on_quit",
General,
"Confirm before quitting with open tabs",
),
(
"status_bar_auto_hide_mouse_inactive",
Advanced,
"Hide on mouse inactivity",
),
("mux_auto_attach", Sessions, "Attach on launch:"),
("leader_timeout_ms", Keys, "Timeout:"),
] {
let hits = registry.search(&Query::parse(key));
assert!(
hits.iter().any(|h| registry.sections[h.section].tab == tab
&& registry.control(*h).is_some_and(|c| c.label == label)),
"{key:?} -> expected {tab:?} › {label:?}; got {:?}",
describe(®istry, &hits)
);
}
}
#[test]
fn platform_gated_controls_register_only_on_their_platform() {
for query in ["mission control", "window blur", "target space"] {
assert_eq!(
super::tab_has_result(SettingsTab::WindowsAndTabs, query),
cfg!(target_os = "macos"),
"{query:?} on the Windows & Tabs tab"
);
}
}
#[test]
fn section_ids_are_unique() {
let registry = test_registry();
let mut seen = std::collections::HashSet::new();
for section in ®istry.sections {
assert!(
seen.insert(§ion.id),
"section id {:?} registered twice",
section.id
);
}
}