use super::super::{continues, row::STEP};
use super::beneath;
use crate::paint_probe::frame::Window;
use crate::reply::convs::{AgentState, ConvRow};
use crate::test_support::window::{conv, seated, seen};
use crate::ui::Model;
use crate::ui::theme::{BRAND, RAISED, RULE, State, accent};
fn fills(model: &mut Model) -> Vec<(egui::Rect, egui::Color32)> {
let window = Window::sized(600.0, 400.0);
crate::paint_probe::fills_of(&window.frame(Vec::new(), |ctx| {
egui::CentralPanel::default().show(ctx, |ui| beneath(ui, model));
}))
}
fn ruled(fills: &[(egui::Rect, egui::Color32)], ink: egui::Color32) -> bool {
fills
.iter()
.any(|(rect, painted)| *painted == ink && rect.width() <= RULE + 0.5)
}
fn listing(row: ConvRow) -> Model {
Model {
convs: vec![row],
conversation: None,
..seated()
}
}
#[test]
fn a_row_that_is_asking_wears_the_attention_rule_over_its_state_s() {
let mut asking = listing(ConvRow {
attention: 2,
state: AgentState::Stopped,
..conv("id", "asking")
});
let painted = fills(&mut asking);
assert!(
ruled(&painted, accent(State::Attention)),
"the attention rule is at the row's edge"
);
assert!(
!ruled(&painted, accent(State::Error)),
"and the state it outranks is not"
);
}
#[test]
fn a_stopped_row_wears_the_error_rule_and_a_settled_one_the_resting_rule() {
let mut stopped = listing(ConvRow {
state: AgentState::Stopped,
..conv("id", "stopped")
});
let painted = fills(&mut stopped);
assert!(ruled(&painted, accent(State::Error)), "the error rule");
assert!(
!ruled(&painted, accent(State::Attention)),
"nothing is asking"
);
let mut settled = listing(conv("id", "settled"));
assert!(
ruled(&fills(&mut settled), accent(State::Rest)),
"a quiescent row still says so, in the ink that recedes"
);
}
#[test]
fn the_selected_row_is_raised_and_wears_the_brand() {
let mut model = Model {
convs: vec![ConvRow {
state: AgentState::Stopped,
..conv("chosen", "the chosen one")
}],
conversation: Some("chosen".to_owned()),
..seated()
};
let painted = fills(&mut model);
assert!(
painted.iter().any(|(_, ink)| *ink == RAISED),
"the chosen row is raised"
);
assert!(ruled(&painted, BRAND), "and its rule is the brand");
assert!(
!ruled(&painted, accent(State::Error)),
"not the state's, which the words carry instead"
);
}
fn branch(depths: &[u64]) -> Vec<ConvRow> {
depths
.iter()
.enumerate()
.map(|(n, depth)| ConvRow {
depth: *depth,
members: 1,
..conv(&format!("id-{n}"), &format!("row {n}"))
})
.collect()
}
#[test]
fn a_rail_stands_for_an_ancestor_whose_thread_continues_and_for_no_other() {
let carries_on = branch(&[0, 1, 2, 1, 0]);
assert!(
continues(&carries_on, 2, 1),
"another member of level 1 follows the depth-2 row"
);
assert!(
!continues(&carries_on, 2, 2),
"nothing follows it at its own level"
);
let ended = branch(&[0, 1, 2, 0]);
assert!(
!continues(&ended, 2, 1),
"the next row is a second root: level 1 ended here"
);
let last = branch(&[0, 1, 2]);
assert!(!continues(&last, 2, 1), "nothing follows at all");
}
#[test]
fn a_member_s_words_stand_one_step_per_level_in_from_its_root_s() {
let mut model = Model {
convs: branch(&[0, 1, 2, 1, 0]),
conversation: None,
..seated()
};
model.toggle_subtree("id-0");
model.toggle_subtree("id-1");
let window = Window::sized(600.0, 400.0);
let runs = seen(&window, |ctx| {
egui::CentralPanel::default().show(ctx, |ui| beneath(ui, &mut model));
});
let at = |n: usize| {
let word = format!("row {n}");
runs.iter()
.find(|run| run.text.starts_with(&word))
.unwrap_or_else(|| panic!("{word:?} is on the glass"))
.laid
.min
.x
};
assert!((at(1) - at(0) - STEP).abs() < 0.5, "one level, one step");
assert!(
(at(2) - at(0) - STEP * 2.0).abs() < 0.5,
"two levels, two steps"
);
assert!((at(4) - at(0)).abs() < 0.5, "a second root is not indented");
}