use super::{composer, elbow, empty, field, prose, rail, row, ruled, section};
use crate::paint_probe::frame::Window;
use crate::test_support::window::{click, seen};
use crate::ui::theme::{
BRAND, COMPOSER_ROWS, INK, INK_WEAK, RAISED, RULE, State, accent, tint, type_scale,
};
fn fills(window: &Window, body: impl FnMut(&egui::Context)) -> Vec<(egui::Rect, egui::Color32)> {
crate::paint_probe::fills_of(&window.frame(Vec::new(), body))
}
#[test]
fn a_row_paints_its_words_in_its_ink_and_its_state_as_a_rule() {
let window = Window::sized(200.0, 100.0);
let body = |ctx: &egui::Context| {
egui::CentralPanel::default().show(ctx, |ui| {
row(
ui,
"a conversation whose name is far too long for two hundred points",
INK_WEAK,
Some(accent(State::Attention)),
false,
0.0,
);
});
};
let glyphs = seen(&window, body);
let run = glyphs.first().expect("the words reached the glass");
assert!(run.text.ends_with('…'), "elided: {:?}", run.text);
assert_eq!(run.ink, INK_WEAK);
let rule = fills(&window, body)
.into_iter()
.find(|(rect, ink)| *ink == accent(State::Attention) && rect.width() <= RULE + 0.5);
assert!(rule.is_some(), "the attention rule stands at the edge");
}
#[test]
fn a_chosen_row_is_raised_and_wears_the_brand() {
let window = Window::sized(300.0, 100.0);
let body = |ctx: &egui::Context| {
egui::CentralPanel::default().show(ctx, |ui| {
row(ui, "chosen", INK, Some(accent(State::Error)), true, 0.0);
});
};
let fills = fills(&window, body);
assert!(fills.iter().any(|(_, ink)| *ink == RAISED), "raised");
assert!(fills.iter().any(|(_, ink)| *ink == BRAND), "the brand rule");
assert!(
!fills.iter().any(|(_, ink)| *ink == accent(State::Error)),
"and not the state's"
);
}
#[test]
fn a_row_rings_while_it_holds_the_keyboard_and_not_otherwise() {
let window = Window::sized(300.0, 100.0);
let mut body = |ctx: &egui::Context| {
egui::CentralPanel::default().show(ctx, |ui| {
row(ui, "first", INK, None, false, 0.0);
row(ui, "second", INK, None, false, 0.0);
});
};
let ringed = |output: &egui::FullOutput| {
crate::paint_probe::strokes_of(output)
.into_iter()
.filter(|(_, ink)| *ink == BRAND)
.count()
};
assert_eq!(ringed(&window.frame(Vec::new(), &mut body)), 0, "at rest");
window.frame(
vec![crate::paint_probe::frame::press(egui::Key::Tab)],
&mut body,
);
let output = window.frame(Vec::new(), &mut body);
assert_eq!(ringed(&output), 1, "one row holds the keyboard");
let ring = crate::paint_probe::strokes_of(&output)
.into_iter()
.find(|(_, ink)| *ink == BRAND)
.map(|(rect, _)| rect)
.expect("the ring");
let first = seen(&window, &mut body)
.into_iter()
.find(|run| run.text == "first")
.expect("the first row");
assert!(
ring.contains_rect(first.laid),
"the ring is around the first row"
);
}
#[test]
fn a_row_takes_a_click_on_its_words() {
let window = Window::sized(300.0, 100.0);
let mut clicked = false;
click(&window, "take me", |ctx| {
egui::CentralPanel::default().show(ctx, |ui| {
clicked |= row(ui, "take me", INK, None, false, 0.0).clicked();
});
});
assert!(clicked);
}
#[test]
fn a_block_is_ruled_and_a_section_is_worded() {
let window = Window::sized(300.0, 300.0);
let body = |ctx: &egui::Context| {
egui::CentralPanel::default().show(ctx, |ui| {
ruled(ui, BRAND, |ui| {
ui.label("first line");
ui.label("second line");
});
section(ui, "steps");
rail(ui, 4.0, 0.0, 10.0);
elbow(ui, 4.0, 0.0, 5.0, 12.0);
});
};
let glyphs = seen(&window, body);
let first = glyphs
.iter()
.find(|run| run.text == "first line")
.expect("first");
let second = glyphs
.iter()
.find(|run| run.text == "second line")
.expect("second");
let rule = fills(&window, body)
.into_iter()
.find(|(rect, ink)| *ink == BRAND && rect.width() <= RULE + 0.5)
.expect("the rule is on the glass");
assert!(rule.0.min.y <= first.laid.min.y + 1.0 && rule.0.max.y >= second.laid.max.y - 1.0);
let word = glyphs
.iter()
.find(|run| run.text == "steps")
.expect("the section's word");
assert_eq!(word.ink, INK_WEAK);
}
#[test]
fn a_field_glows_and_rings() {
let window = Window::sized(300.0, 100.0);
let id = egui::Id::new("a field");
let mut text = String::new();
let glow = tint(State::Attention);
let body = |ctx: &egui::Context| {
egui::CentralPanel::default().show(ctx, |ui| {
field(ui, id, &mut text, "say it", Some(glow));
});
};
assert!(
fills(&window, body).iter().any(|(_, ink)| *ink == glow),
"glows"
);
let mut text = String::new();
let body = |ctx: &egui::Context| {
egui::CentralPanel::default().show(ctx, |ui| {
field(ui, id, &mut text, "say it", None);
});
};
click(&window, "say it", body);
assert_eq!(window.focused(), Some(id), "the click put the caret in it");
}
#[test]
fn the_composer_is_rows_tall_with_the_send_inside_it() {
let window = Window::sized(400.0, 200.0);
let id = egui::Id::new("the composer");
let mut text = String::new();
let mut body = |ctx: &egui::Context| {
egui::CentralPanel::default().show(ctx, |ui| {
composer(ui, id, &mut text, "say it", None, "send");
});
};
let output = window.frame(Vec::new(), &mut body);
let send = crate::paint_probe::seen_of(&output)
.into_iter()
.find(|run| run.text == "send")
.expect("the send is on the glass");
assert_eq!(send.ink, BRAND);
let field = crate::paint_probe::fills_of(&output)
.into_iter()
.find(|(rect, _)| rect.contains_rect(send.laid) && rect.width() > 300.0)
.expect("the send lies inside the field");
let rows = f32::from(COMPOSER_ROWS);
assert!(field.0.height() >= rows * type_scale::BODY, "{field:?}");
let at = crate::paint_probe::frame::locate_in(&window, "say it", &mut body).expect("hint");
crate::paint_probe::frame::click(&window, at, &mut body);
window.frame(
vec![egui::Event::Key {
key: egui::Key::Enter,
physical_key: None,
pressed: true,
repeat: false,
modifiers: egui::Modifiers::SHIFT,
}],
&mut body,
);
window.frame(
vec![crate::paint_probe::frame::press(egui::Key::Enter)],
&mut body,
);
window.frame(Vec::new(), &mut body);
assert_eq!(
text, "\n",
"one break from the shifted key and none from the bare one"
);
}
#[test]
fn prose_is_laid_at_the_leading_and_a_label_is_not() {
let window = Window::sized(200.0, 200.0);
let words = "a paragraph long enough that two hundred points cannot hold it on one line";
let body = |ctx: &egui::Context| {
egui::CentralPanel::default().show(ctx, |ui| {
prose(ui, words, INK_WEAK);
ui.label(words);
});
};
let glyphs = seen(&window, body);
let (paragraph, label) = (&glyphs[0], &glyphs[1]);
assert_eq!(paragraph.ink, INK_WEAK);
assert!(
paragraph.laid.height() >= 2.0 * type_scale::LEADING - 1.0,
"{:?}",
paragraph.laid
);
assert!(
paragraph.laid.height() > label.laid.height() + type_scale::LEADING - type_scale::BODY,
"prose {:?} over label {:?}",
paragraph.laid,
label.laid
);
}
#[test]
fn an_empty_state_is_one_weak_sentence_that_wraps() {
let window = Window::sized(160.0, 200.0);
let sentence = "no conversations here yet — begin one in the box below";
let glyphs = seen(&window, |ctx| {
egui::CentralPanel::default().show(ctx, |ui| {
empty(ui, sentence);
});
});
let run = glyphs.first().expect("the sentence reached the glass");
assert_eq!(run.ink, INK_WEAK);
assert!(run.laid.height() > 1.5 * type_scale::BODY, "{:?}", run.laid);
assert!(run.laid.max.x <= 160.0, "{:?}", run.laid);
}