test(protocol,wasm,io): displays drawn, keys composed, in the grid, page bar, panels and CSV (improvise-cq1q.12)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
Claude (adr007-display)
2026-10-08 21:47:39 -07:00
committed by Edward Langley
parent 7a4dc07642
commit ba053fdaa5
4 changed files with 164 additions and 0 deletions
@@ -106,6 +106,34 @@ mod tests {
); );
} }
#[test]
fn export_csv_writes_displays_in_every_header_and_label() {
let mut m = Workbook::new("T");
for cat in ["Type", "Month", "Payer"] {
m.add_category(cat).unwrap();
}
m.add_item("Type", "Food").unwrap();
m.add_item("Month", "Jan").unwrap();
m.add_item("Payer", "Alice").unwrap();
m.model.set_cell(
coord(&[("Type", "Food"), ("Month", "Jan"), ("Payer", "Alice")]),
CellValue::Number(1.0),
);
let ty = m.model.category_mut("Type").unwrap();
ty.set_display("Kind");
ty.set_item_display("Food", "Groceries");
m.model
.category_mut("Month")
.unwrap()
.set_item_display("Jan", "January");
let payer = m.model.category_mut("Payer").unwrap();
payer.set_display("Who");
payer.set_item_display("Alice", "Alicia");
let bytes = super::render_csv(&m, "Default").unwrap();
let text = String::from_utf8(bytes).unwrap();
assert_eq!(text, "Kind (Who=Alicia),January\nGroceries,1.00\n");
}
/// Bug improvise-1cz: bare-comma joining and an ignored number format /// Bug improvise-1cz: bare-comma joining and an ignored number format
/// corrupted every row. Evidence: `context/test-evidence/formula-and-io.md`. /// corrupted every row. Evidence: `context/test-evidence/formula-and-io.md`.
#[test] #[test]
+42
View File
@@ -4071,6 +4071,48 @@ mod tests {
); );
} }
/// ADR 007: the bar shows displays and a pick composes the KEY at that index.
#[test]
fn picking_a_displayed_page_item_still_names_its_key() {
let mut state = paged();
state.grid.page_coords[1].cat_display = "Period".into();
state.grid.page_coords[1].item_displays =
Some(["First", "Second", "Third", "Fourth"].map(String::from).to_vec());
let commands = click(&state, Click::PageItem { axis: 1, item: 1 });
let [Command::Model { cmd: ModelCommand::SetPageSelection { category, item, .. }, .. }] =
commands.as_slice()
else {
panic!("expected one page selection, got {commands:?}");
};
assert_eq!((category.as_str(), item.as_str()), ("Quarter", "Q2"));
}
/// The frame shows an item under its display; hiding it names the key.
#[test]
fn hiding_a_displayed_row_item_names_its_key() {
let mut state = in_mode(AppMode::Normal);
crate::WidgetCache::apply(&mut state.basis, &published());
state.grid.row_frame = crate::AxisFrame {
cats: vec!["Region".into()],
cat_displays: vec!["Sales Area".into()],
first: 0,
entries: vec![crate::FrameEntry::Item {
tuple: vec!["East".into()],
display: vec!["Eastern Seaboard".into()],
collapsed: false,
}],
};
let KeyOutcome::Local(commands) = resolve(&state, ev(KeyCode::Char('H'))) else {
panic!("hiding resolves here");
};
let [Command::Model { cmd: ModelCommand::HideItem { category, item, .. }, .. }] =
commands.as_slice()
else {
panic!("expected one hide, got {commands:?}");
};
assert_eq!((category.as_str(), item.as_str()), ("Region", "East"));
}
/// A Filter axis is on the bar and offers nothing to pick (gotcha 27). /// A Filter axis is on the bar and offers nothing to pick (gotcha 27).
/// Offering a menu that cannot act is worse than offering none. /// Offering a menu that cannot act is worse than offering none.
#[test] #[test]
@@ -883,6 +883,79 @@ mod tests {
assert!(views[0].active, "the active view is still found by its key"); assert!(views[0].active, "the active view is still found by its key");
} }
#[test]
fn the_grid_page_bar_and_item_rows_paint_displays() {
use improvise_protocol::{AxisFrame, CategoryItem, FrameGroup};
let mut client = init();
let state = client.state_mut();
let shown = |key: &str, display: &str| FrameEntry::Item {
tuple: vec![key.into()],
display: vec![display.into()],
collapsed: false,
};
state.fold(&Command::Project(Projection::Grid(GridUpdate::RowFrame(
AxisFrame {
cats: vec!["Region".into()],
cat_displays: vec!["Sales Area".into()],
first: 0,
entries: vec![
FrameEntry::Group(FrameGroup {
level: 0,
depth: 0,
name: "Coastal".into(),
display: "Shoreline".into(),
collapsed: false,
}),
shown("East", "Eastern Seaboard"),
],
},
))));
state.fold(&Command::Project(Projection::Grid(GridUpdate::ColFrame(
AxisFrame {
cats: vec!["_Measure".into()],
cat_displays: vec!["_Measure".into()],
first: 0,
entries: vec![shown("Revenue", "Sales")],
},
))));
state.fold(&Command::Project(Projection::Grid(GridUpdate::PageCoords(
vec![PageAxis {
cat: "Quarter".into(),
cat_display: "Period".into(),
selected: "Q1".into(),
selected_display: "First".into(),
items: Some(vec!["Q1".into(), "Q2".into()]),
item_displays: Some(vec!["First".into(), "Second".into()]),
}],
))));
state.fold(&Command::Project(Projection::CategoryTree(
CategoryTreeUpdate::Categories(vec![CategoryRow {
name: "Region".into(),
display: "Sales Area".into(),
items: vec![CategoryItem {
name: "East".into(),
display: "Eastern Seaboard".into(),
}],
axis: Axis::Row,
}]),
)));
state.view.expanded_cats.insert("Region".into());
let model = client.model();
assert!(matches!(
&model.rows[0],
RenderRow::Group { label, .. } if label == "Shoreline"
));
assert!(matches!(
&model.rows[1],
RenderRow::Data { labels, .. } if labels == &vec!["Eastern Seaboard".to_string()]
));
assert_eq!(model.col_levels, vec![vec!["Sales".to_string()]]);
let bar = &model.page_coords[0];
assert_eq!((bar.cat.as_str(), bar.selected.as_str()), ("Period", "First"));
assert_eq!(bar.cycle.as_ref().unwrap().items, vec!["First", "Second"]);
assert_eq!(model.categories[1].label, "Eastern Seaboard");
}
fn client_with_panels() -> Client { fn client_with_panels() -> Client {
let mut client = init(); let mut client = init();
client client
+21
View File
@@ -884,6 +884,27 @@ mod tests {
assert_eq!(text, GROUPED_FRAME, "\n--- got ---\n{text}\n--- end ---"); assert_eq!(text, GROUPED_FRAME, "\n--- got ---\n{text}\n--- end ---");
} }
#[test]
fn the_frame_and_page_bar_draw_displays_not_keys() {
let mut m = grouped_model();
let region = m.model.category_mut("Region").unwrap();
region.set_item_display("East", "Eastward");
region.set_group_display("Coastal", "Bay");
let month = m.model.category_mut("Month").unwrap();
month.set_item_display("Jan", "Janv");
month.set_group_display("Q1", "Qa");
let payer = m.model.category_mut("Payer").unwrap();
payer.set_display("Who");
payer.set_item_display("Alice", "Alicia");
let text = buf_text(&render(&mut m, 60, 16));
for shown in ["Who = Alicia", "Eastward", "▼ Bay", "Janv", "▼ Qa"] {
assert!(text.contains(shown), "{shown:?} missing:\n{text}");
}
for key in ["Payer", "Alice]", "East ", "Coastal", "Jan ", "Q1"] {
assert!(!text.contains(key), "the key {key:?} was drawn:\n{text}");
}
}
/// Re-pinned for improvise-0o6x: the leading `▼ Co…` is the ONE line that /// Re-pinned for improvise-0o6x: the leading `▼ Co…` is the ONE line that
/// moved, and its absence was the bug. context/test-evidence/tui.md. /// moved, and its absence was the bug. context/test-evidence/tui.md.
const GROUPED_FRAME: &str = concat!( const GROUPED_FRAME: &str = concat!(