use super::{HERE, Pane, moved};
use crate::paint_probe::frame::{Window, press};
use crate::test_support::window::{conv, own, seated, wall};
use crate::ui::{Channel, Chunk, Model, Notice, convs, roster};
fn stocked() -> Model {
Model {
roster: vec![
own(),
Chunk {
channel: Channel {
name: "elsewhere".to_owned(),
named_there: Some("theirs".to_owned()),
dials: None,
},
walls: vec![wall("theirs"), wall("not-ours")],
..Chunk::default()
},
],
convs: vec![conv("a", "one"), conv("b", "two")],
..seated()
}
}
fn typed(model: &mut Model, keys: &[egui::Key]) -> String {
let window = Window::new();
let mut painted = String::new();
for key in keys {
painted = crate::paint_probe::text_of(&window.frame(vec![press(*key)], |ctx| {
crate::ui::render(ctx, model);
}));
}
painted
}
#[test]
fn the_pane_the_arrows_belong_to_is_marked_on_the_glass() {
let mut model = stocked();
let painted = typed(&mut model, &[egui::Key::ArrowRight]);
assert!(
painted
.lines()
.any(|line| line == format!("{HERE} {}", convs::HEADING)),
"{painted}"
);
assert!(
painted.lines().any(|line| line == roster::HEADING),
"the pane that does not hold the arrows wears no mark:\n{painted}"
);
let painted = typed(&mut model, &[egui::Key::ArrowLeft]);
assert!(
painted
.lines()
.any(|line| line == format!("{HERE} {}", roster::HEADING)),
"{painted}"
);
}
#[test]
fn the_arrows_walk_the_roster_and_the_walk_is_the_aim() {
let mut model = Model {
aim: None,
..stocked()
};
typed(&mut model, &[egui::Key::ArrowDown]);
assert_eq!(
model.aim.as_ref().map(|aim| aim.address.clone()),
Some("home".to_owned()),
"a list nobody has entered opens at its first row"
);
typed(&mut model, &[egui::Key::ArrowDown]);
let aim = model.aim.as_ref().expect("an aim");
assert_eq!(
(aim.channel.as_str(), aim.address.as_str()),
("elsewhere", "elsewhere"),
"the walk crosses channels in the order the pane paints them"
);
typed(&mut model, &[egui::Key::ArrowUp]);
assert_eq!(
model.aim.as_ref().map(|aim| aim.address.clone()),
Some("home".to_owned())
);
}
#[test]
fn the_walk_skips_every_row_no_gesture_could_address() {
let model = stocked();
let track = roster::aimable(&model);
assert_eq!(
track
.iter()
.map(|aim| aim.address.clone())
.collect::<Vec<String>>(),
vec!["home".to_owned(), "elsewhere".to_owned()],
"the second channel's unreachable wall is on neither surface"
);
let mut walked = Model { aim: None, ..model };
for _ in 0..3 {
typed(&mut walked, &[egui::Key::ArrowDown]);
}
assert_eq!(
walked.aim.as_ref().map(|aim| aim.address.clone()),
Some("elsewhere".to_owned())
);
}
#[test]
fn the_arrows_walk_the_conversation_list_and_the_walk_is_the_selection() {
let mut model = Model {
conversation: None,
..stocked()
};
typed(&mut model, &[egui::Key::ArrowRight, egui::Key::ArrowDown]);
assert_eq!(model.conversation.as_deref(), Some("a"));
typed(&mut model, &[egui::Key::ArrowDown]);
assert_eq!(model.conversation.as_deref(), Some("b"));
typed(&mut model, &[egui::Key::ArrowDown]);
assert_eq!(model.conversation.as_deref(), Some("b"));
}
#[test]
fn escape_puts_the_notice_down() {
let mut model = Model {
notice: Some(Notice::Refused("unknown workspace".to_owned())),
..stocked()
};
let painted = typed(&mut model, &[egui::Key::Escape]);
assert_eq!(model.notice, None);
assert!(
!painted.contains("the engine refused"),
"the bar is off the glass:\n{painted}"
);
}
#[test]
fn nothing_is_bound_while_a_box_is_taking_text() {
const STOPS: usize = 64;
let mut model = stocked();
let window = Window::new();
let mut body = |ctx: &egui::Context| crate::ui::render(ctx, &mut model);
window.frame(Vec::new(), &mut body);
let mut wanted = false;
for _ in 0..STOPS {
window.frame(vec![press(egui::Key::Tab)], &mut body);
wanted = window.focused() == Some(egui::Id::new(super::BOX_ID));
if wanted {
break;
}
}
assert!(wanted, "the composer's box never took the keyboard");
window.frame(vec![press(egui::Key::ArrowDown)], &mut body);
window.frame(Vec::new(), &mut body);
assert_eq!(
model.conversation.as_deref(),
seated().conversation.as_deref(),
"the arrow went into the draft, not into a list"
);
}
#[test]
fn a_cursor_saturates_and_an_empty_list_has_nowhere_to_go() {
assert_eq!(moved(0, None, 1), None);
assert_eq!(moved(3, None, -1), Some(0), "an unentered list opens at 0");
assert_eq!(moved(3, Some(0), -1), Some(0));
assert_eq!(moved(3, Some(2), 1), Some(2));
assert_eq!(moved(3, Some(1), 1), Some(2));
}
#[test]
fn a_fresh_window_opens_with_the_roster_holding_the_arrows() {
assert_eq!(Model::default().focus, Pane::Roster);
assert_eq!(
roster::aimable(&Model::default()),
Vec::<crate::ui::Aim>::new(),
"a box that has been asked nothing offers no row to walk"
);
}
#[test]
fn the_arrows_walk_the_started_conversation_s_row_like_any_other() {
let mut model = Model {
conversation: Some("brisk-otter".to_owned()),
start: Some(crate::ui::model::Start {
address: "home".to_owned(),
goal: "port it".to_owned(),
phase: crate::ui::model::Phase::Started("brisk-otter".to_owned()),
}),
..stocked()
};
let painted = typed(&mut model, &[egui::Key::ArrowRight]);
assert!(painted.contains("brisk-otter"), "{painted}");
typed(&mut model, &[egui::Key::ArrowDown]);
assert_eq!(
model.conversation.as_deref(),
Some("a"),
"one step down out of the pending row and into the list"
);
}
#[test]
fn the_two_parameter_boxes_stand_the_arrows_down_as_the_draft_does() {
for (fill, id) in [
(crate::ui::Fill::Reason, super::REASON_ID),
(crate::ui::Fill::Arming, super::ARM_ID),
] {
let mut model = stocked();
model.focus = Pane::Conversations;
model.fill_in("a", fill);
let window = Window::new();
let mut body = |ctx: &egui::Context| crate::ui::render(ctx, &mut model);
window.frame(Vec::new(), &mut body);
assert_eq!(
window.focused(),
Some(egui::Id::new(id)),
"the box took the keyboard"
);
window.frame(vec![press(egui::Key::ArrowDown)], &mut body);
window.frame(Vec::new(), &mut body);
assert_eq!(
model.conversation.as_deref(),
Some("a"),
"the arrow went into the box, not into the list"
);
}
}