1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
use super::*;
use crate::profile::{AppConfig, AppState};
use crate::tui::app::{
App, ConfigFocus, FallbackFocus, PluginFocus, StatusFocus, TokenView, has_sub_focus,
};
fn empty_app(tab: Tab) -> App {
let mut app = App::new(AppConfig {
state: AppState::default(),
profiles: Vec::new(),
});
app.tab = tab;
app
}
/// Issue #15: a tab with a descend/ascend sub-focus screen (Setup's Actions
/// pane, Fallback's Detail pane, Status/Plugin's Detail pane, Tokens' Models
/// view) must document an `esc` row in its help-modal section, or a user who
/// descended into it has no listed way back.
///
/// Driven off `has_sub_focus` — the same predicate the `q` handler and footer
/// use to decide "back" vs "quit" — rather than a hardcoded tab list, so a
/// future tab wired into that predicate without a matching help row fails
/// here instead of shipping undocumented.
#[test]
fn every_sub_focus_tab_documents_esc_in_help() {
for tab in Tab::ALL {
let mut app = empty_app(tab);
// Drive every sub-focus field to its "descended" value; `has_sub_focus`
// only reads the one that matches `app.tab`, so this is safe for all.
app.config_focus = ConfigFocus::Actions;
app.fallback_focus = FallbackFocus::Detail;
app.status.focus = StatusFocus::Detail;
app.plugin.focus = PluginFocus::Detail;
app.token_view = TokenView::Models;
if !has_sub_focus(&app) {
continue;
}
let rows = tab_specific_rows(tab);
let has_esc_row = rows
.iter()
.flat_map(|(_, entries)| entries.iter())
.any(|(key, _)| *key == "esc");
assert!(
has_esc_row,
"tab {tab:?} has a sub-focus but no `esc` row in its help-modal section"
);
}
}