#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(in crate::lookout::view) enum Column {
Key,
Value,
InForce,
SetIn,
ReadBy,
Lands,
}
pub(in crate::lookout::view) const SECRET_TIERS: &[(u16, &[Column])] = &[
(
160,
&[
Column::Key,
Column::Value,
Column::InForce,
Column::SetIn,
Column::ReadBy,
Column::Lands,
],
),
(
118,
&[
Column::Key,
Column::Value,
Column::InForce,
Column::SetIn,
Column::ReadBy,
],
),
(
96,
&[Column::Key, Column::Value, Column::InForce, Column::SetIn],
),
(74, &[Column::Key, Column::Value, Column::InForce]),
];
pub(super) const MIN_WIDTH: u16 = SECRET_TIERS[SECRET_TIERS.len() - 1].0;
pub(in crate::lookout::view) fn columns_for(width: u16) -> &'static [Column] {
SECRET_TIERS
.iter()
.find(|(threshold, _)| width >= *threshold)
.map_or(SECRET_TIERS[SECRET_TIERS.len() - 1].1, |(_, columns)| {
*columns
})
}
impl Column {
pub(in crate::lookout::view) const fn width(self) -> u16 {
match self {
Self::Key => 28,
Self::Value => 30,
Self::InForce => 14,
Self::SetIn => 22,
Self::ReadBy => 22,
Self::Lands => 42,
}
}
pub(super) const fn heading(self) -> &'static str {
match self {
Self::Key => "KEY",
Self::Value => "VALUE",
Self::InForce => "IN FORCE",
Self::SetIn => "SET IN",
Self::ReadBy => "READ BY",
Self::Lands => "LANDS",
}
}
}
#[cfg(test)]
mod tests {
use super::super::draw_layout::cell;
use super::super::pane_chrome::tab_line;
use super::super::row_cells::typed_cell;
use super::super::super::super::theme::Palette;
use super::super::super::flock::GUTTER;
use super::*;
use super::super::testing::*;
use crate::lookout::view::fixtures;
#[test]
fn every_tier_fits_the_width_it_claims() {
for (threshold, columns) in SECRET_TIERS {
let spent: u16 = columns.iter().map(|column| column.width()).sum();
assert!(
spent + GUTTER <= *threshold,
"tier {threshold} spends {spent} plus {GUTTER} of gutter"
);
}
}
#[test]
fn a_terminal_narrower_than_the_floor_tier_says_so_instead_of_clipping() {
let app = fixtures::app_with_secrets();
assert!(
SECRET_TIERS
.iter()
.all(|(threshold, _)| *threshold >= MIN_WIDTH),
"MIN_WIDTH is the floor tier's own threshold, so no tier below \
it is refused away unreached"
);
let spent: u16 = columns_for(MIN_WIDTH).iter().map(|c| c.width()).sum();
assert!(
spent + GUTTER <= MIN_WIDTH,
"the width the refusal names has to be one the floor tier \
actually fits: {spent} plus {GUTTER} of gutter"
);
for width in crate::lookout::view::MIN_TERM_WIDTH..MIN_WIDTH {
let text = frame_text(&fixtures::render(&app, width, 24));
assert!(text.contains("too narrow for secrets"), "{width}: {text}");
assert!(
text.contains(&format!("need {MIN_WIDTH} columns")),
"{width}: {text}"
);
assert!(
!text.contains("DB_PASSWORD"),
"no half-drawn table at {width}: {text}"
);
}
let text = frame_text(&fixtures::render(&app, MIN_WIDTH, 24));
assert!(text.contains("DB_PASSWORD"), "the floor tier draws: {text}");
assert!(!text.contains("too narrow"), "{text}");
}
#[test]
fn the_tab_row_elides_its_tabs_rather_than_losing_its_own_count() {
let palette = Palette::detect(None, None, None);
for count in 1..=20usize {
for width in [MIN_WIDTH, 100, 160] {
for tab in [0, count / 2, count - 1] {
let pane = pane_with_environments(count, tab);
let line = fixtures::rendered(&tab_line(&pane, palette, width));
assert!(
line.chars().count() <= usize::from(width),
"{count} tabs at {width}, on {tab}: {line:?}"
);
assert!(
line.trim_end().ends_with(&format!(
"{count} environments in this store \u{b7} \u{2190}/\u{2192}"
)),
"the count survives whole: {count} tabs at {width}: {line:?}"
);
assert!(
line.contains(&format!("[environment-{tab:02}]")),
"the tab you are on is drawn: {count} tabs at {width}: {line:?}"
);
for token in line.split_whitespace() {
let name = token.trim_start_matches('[').trim_end_matches(']');
if name.starts_with("environment-") {
assert_eq!(
name.len(),
"environment-00".len(),
"cut mid-name: {line:?}"
);
}
}
}
}
}
}
#[test]
fn a_new_key_name_outgrowing_its_column_is_shown_from_the_end_too() {
let short = typed_cell("SHORT", Column::Value.width());
let long = typed_cell(
"A_VERY_LONG_KEY_NAME_THAT_RUNS_PAST_THE_COLUMN",
Column::Value.width(),
);
assert!(short.starts_with("SHORT\u{2588}"), "{short:?}");
assert!(!short.contains('\u{2026}'), "nothing dropped: {short:?}");
assert!(long.starts_with('\u{2026}'), "{long:?}");
assert!(long.ends_with("THE_COLUMN\u{2588}"), "{long:?}");
}
#[test]
fn the_columns_drop_in_the_specified_order() {
let widest = columns_for(160);
assert!(widest.contains(&Column::Lands));
assert!(
!columns_for(118).contains(&Column::Lands),
"LANDS goes first"
);
assert!(columns_for(118).contains(&Column::ReadBy));
assert!(
!columns_for(96).contains(&Column::ReadBy),
"READ BY goes second"
);
assert!(
!columns_for(74).contains(&Column::SetIn),
"SET IN goes third"
);
for width in [160, 118, 96, 74, 40] {
let columns = columns_for(width);
assert!(columns.contains(&Column::Key), "KEY is the pane at {width}");
assert!(
columns.contains(&Column::Value),
"VALUE is the pane at {width}"
);
assert!(
columns.contains(&Column::InForce),
"IN FORCE is the pane at {width}"
);
}
}
#[test]
fn a_four_kilobyte_value_never_overflows_its_column() {
let app = fixtures::app_with_a_maximum_length_secret();
let buffer = fixtures::render(&app, 160, 48);
let value = cell(&buffer, first_row(), Column::Value);
assert!(
value.chars().count() <= Column::Value.width() as usize,
"spilled: {value:?}"
);
assert!(
value.contains("4096 bytes"),
"the exact length is stated: {value:?}"
);
}
#[test]
fn a_short_value_s_block_run_is_proportional_to_its_length() {
let app = fixtures::app_with_secrets();
let buffer = fixtures::render(&app, 160, 48);
let value = cell(&buffer, first_row(), Column::Value);
let blocks = value.chars().take_while(|&c| c == '\u{2588}').count();
assert_eq!(
blocks, 9,
"the run states the value's own length: {value:?}"
);
}
#[test]
fn lands_is_drawn_at_the_widest_tier() {
let app = fixtures::app_with_secrets();
let buffer = fixtures::render(&app, 160, 48);
assert_eq!(cell(&buffer, heading_row(), Column::Lands).trim(), "LANDS");
assert_eq!(cell(&buffer, first_row(), Column::Lands).trim(), "-");
}
}