#![allow(
clippy::cognitive_complexity,
clippy::needless_pass_by_value,
clippy::redundant_field_names,
)]
mod common;
use std::fmt::Write;
use async_trait::async_trait;
use gui::Cap;
use gui::derive::Handleable;
use gui::derive::Widget;
use gui::Handleable;
use gui::Id;
use gui::MutCap;
use gui::Ui;
use crate::common::Event;
use crate::common::Message;
use crate::common::TestWidget;
use crate::common::TestWidgetDataBuilder;
#[test]
fn correct_ids() {
let (mut ui, root) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w1 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w2 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let c1 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w3 = ui.add_ui_widget(
c1,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let c2 = ui.add_ui_widget(
c1,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w4 = ui.add_ui_widget(
c2,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
assert_eq!(ui.parent_id(root), None);
assert_eq!(ui.parent_id(w1).unwrap(), root);
assert_eq!(ui.parent_id(w2).unwrap(), root);
assert_eq!(ui.parent_id(c1).unwrap(), root);
assert_eq!(ui.parent_id(w3).unwrap(), c1);
assert_eq!(ui.parent_id(w4).unwrap(), c2);
}
#[test]
fn debug_format() {
let (ui, _) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let mut string = String::new();
write!(&mut string, "{:?}", ui).unwrap();
#[cfg(debug_assertions)]
{
assert!(string.starts_with("Ui { "), string);
assert!(string.ends_with(" }"));
}
#[cfg(not(debug_assertions))]
{
assert_eq!(string, "Ui");
}
}
#[test]
fn creation_order_is_child_order() {
let (mut ui, root) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w1 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w11 = ui.add_ui_widget(
w1,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w12 = ui.add_ui_widget(
w1,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w2 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w21 = ui.add_ui_widget(
w2,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let mut it = ui.children(root);
assert_eq!(*it.next().unwrap(), w1);
assert_eq!(*it.next().unwrap(), w2);
assert!(it.next().is_none());
let mut it = ui.children(w1);
assert_eq!(*it.next().unwrap(), w11);
assert_eq!(*it.next().unwrap(), w12);
assert!(it.next().is_none());
let mut it = ui.children(w11);
assert!(it.next().is_none());
let mut it = ui.children(w2);
assert_eq!(*it.next().unwrap(), w21);
assert!(it.next().is_none());
}
#[tokio::test]
#[cfg(debug_assertions)]
#[should_panic(expected = "Created widget does not have provided Id")]
async fn incorrect_widget_id() {
let (mut ui, root) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let _ = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|_id, _cap| Box::new(TestWidget::new(root)),
);
}
#[tokio::test]
#[cfg(debug_assertions)]
#[should_panic(expected = "The given Id belongs to a different Ui")]
async fn share_ids_between_ui_objects() {
let (mut ui1, root) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let widget = ui1.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let (mut ui2, _) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let message = Message::new(0);
ui2.send(widget, message).await;
}
#[test]
fn visibility_fun() {
let (mut ui, root) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w1 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w2 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w3 = ui.add_ui_widget(
w2,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
assert!(ui.is_visible(root));
assert!(ui.is_visible(w1));
assert!(ui.is_visible(w2));
assert!(ui.is_visible(w3));
assert!(ui.is_displayed(root));
assert!(ui.is_displayed(w1));
assert!(ui.is_displayed(w2));
assert!(ui.is_displayed(w3));
ui.hide(root);
assert!(!ui.is_visible(root));
assert!(ui.is_visible(w1));
assert!(ui.is_visible(w2));
assert!(ui.is_visible(w3));
assert!(!ui.is_displayed(root));
assert!(!ui.is_displayed(w1));
assert!(!ui.is_displayed(w2));
assert!(!ui.is_displayed(w3));
ui.hide(w2);
assert!(!ui.is_visible(root));
assert!(ui.is_visible(w1));
assert!(!ui.is_visible(w2));
assert!(ui.is_visible(w3));
assert!(!ui.is_displayed(root));
assert!(!ui.is_displayed(w1));
assert!(!ui.is_displayed(w2));
assert!(!ui.is_displayed(w3));
ui.hide(w1);
assert!(!ui.is_visible(root));
assert!(!ui.is_visible(w1));
assert!(!ui.is_visible(w2));
assert!(ui.is_visible(w3));
assert!(!ui.is_displayed(root));
assert!(!ui.is_displayed(w1));
assert!(!ui.is_displayed(w2));
assert!(!ui.is_displayed(w3));
ui.show(w3);
assert!(ui.is_visible(root));
assert!(!ui.is_visible(w1));
assert!(ui.is_visible(w2));
assert!(ui.is_visible(w3));
assert!(ui.is_displayed(root));
assert!(!ui.is_displayed(w1));
assert!(ui.is_displayed(w2));
assert!(ui.is_displayed(w3));
}
#[test]
fn no_initial_focus() {
let (mut ui, root) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
assert!(ui.focused().is_none());
let _ = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
assert!(ui.focused().is_none());
}
#[test]
fn focus_widget() {
let (mut ui, root) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let widget = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
ui.focus(widget);
assert!(ui.is_focused(widget));
}
#[test]
fn focus_makes_widget_visible() {
let (mut ui, root) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let widget = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
ui.hide(root);
ui.hide(widget);
assert!(!ui.is_visible(root));
assert!(!ui.is_visible(widget));
ui.focus(widget);
assert!(ui.is_displayed(widget));
}
#[test]
fn focus_changes_child_order() {
let (mut ui, root) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w1 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w11 = ui.add_ui_widget(
w1,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w2 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w21 = ui.add_ui_widget(
w2,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w22 = ui.add_ui_widget(
w2,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w23 = ui.add_ui_widget(
w2,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
ui.focus(w1);
{
let mut it = ui.children(root);
assert_eq!(*it.next().unwrap(), w1);
assert_eq!(*it.next().unwrap(), w2);
assert!(it.next().is_none());
}
ui.focus(w22);
{
let mut it = ui.children(root);
assert_eq!(*it.next().unwrap(), w2);
assert_eq!(*it.next().unwrap(), w1);
assert!(it.next().is_none());
let mut it = ui.children(w2);
assert_eq!(*it.next().unwrap(), w22);
assert_eq!(*it.next().unwrap(), w21);
assert_eq!(*it.next().unwrap(), w23);
assert!(it.next().is_none());
}
ui.focus(w11);
{
let mut it = ui.children(root);
assert_eq!(*it.next().unwrap(), w1);
assert_eq!(*it.next().unwrap(), w2);
assert!(it.next().is_none());
let mut it = ui.children(w1);
assert_eq!(*it.next().unwrap(), w11);
assert!(it.next().is_none());
}
}
#[test]
fn repeated_show_preserves_order() {
let (mut ui, root) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w1 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w11 = ui.add_ui_widget(
w1,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w2 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w21 = ui.add_ui_widget(
w2,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let before = ui.children(root).cloned().collect::<Vec<_>>();
ui.show(w11);
let after = ui.children(root).cloned().collect::<Vec<_>>();
assert_eq!(before, after);
ui.show(w21);
let after = ui.children(root).cloned().collect::<Vec<_>>();
assert_eq!(before, after);
}
#[test]
fn hide_changes_child_order() {
let (mut ui, root) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w1 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w2 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w3 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w4 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
ui.hide(w2);
{
let mut it = ui.children(root);
assert_eq!(*it.next().unwrap(), w1);
assert_eq!(*it.next().unwrap(), w3);
assert_eq!(*it.next().unwrap(), w4);
assert_eq!(*it.next().unwrap(), w2);
assert!(it.next().is_none());
}
ui.hide(w3);
{
let mut it = ui.children(root);
assert_eq!(*it.next().unwrap(), w1);
assert_eq!(*it.next().unwrap(), w4);
assert_eq!(*it.next().unwrap(), w3);
assert_eq!(*it.next().unwrap(), w2);
assert!(it.next().is_none());
}
}
#[test]
fn repeated_hide_preserves_order() {
let (mut ui, root) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let _ = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w2 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let w3 = ui.add_ui_widget(
root,
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
ui.hide(w2);
ui.hide(w3);
let before = ui.children(root).cloned().collect::<Vec<_>>();
ui.hide(w2);
let after = ui.children(root).cloned().collect::<Vec<_>>();
assert_eq!(before, after);
}
fn counting_handler(
_widget: Id,
_cap: &mut dyn MutCap<Event, Message>,
event: Event,
) -> Option<Event> {
let event = match event {
Event::Empty | Event::Key(..) => unreachable!(),
Event::Int(value) => Event::Int(value + 1),
};
Some(event)
}
fn need_more(id: Id, cap: &mut dyn MutCap<Event, Message>) -> bool {
cap.parent_id(id).is_none()
}
#[derive(Debug, Widget)]
#[gui(Event = Event, Message = Message)]
struct CreatingWidget {
id: Id,
}
impl CreatingWidget {
pub fn new(id: Id, cap: &mut dyn MutCap<Event, Message>) -> Self {
let child = cap.add_widget(
id,
Box::new(|| {
TestWidgetDataBuilder::new()
.event_handler(counting_handler)
.build()
}),
Box::new(|id, _cap| Box::new(TestWidget::new(id))),
);
cap.focus(child);
if need_more(id, cap) {
let _ = cap.add_widget(
id,
Box::new(|| Box::new(())),
Box::new(|id, cap| Box::new(CreatingWidget::new(id, cap))),
);
}
Self { id }
}
}
#[async_trait(?Send)]
impl Handleable<Event, Message> for CreatingWidget {
async fn handle(&self, cap: &mut dyn MutCap<Event, Message>, event: Event) -> Option<Event> {
counting_handler(self.id, cap, event)
}
}
#[tokio::test]
async fn recursive_widget_creation() {
let (mut ui, _) = Ui::new(
|| Box::new(()),
|id, cap| Box::new(CreatingWidget::new(id, cap)),
);
let event = Event::Int(0u64);
let result = ui.handle(event).await.unwrap();
assert_eq!(result.unwrap_int(), 3);
}
#[derive(Debug)]
struct Moveable {}
#[derive(Debug, Widget, Handleable)]
#[gui(Event = Event)]
struct MovingWidget {
id: Id,
object: Moveable,
}
impl MovingWidget {
pub fn new(id: Id, object: Moveable) -> Self {
Self { id, object }
}
}
#[test]
fn moving_widget_creation() {
let (mut ui, root) = Ui::new(
|| TestWidgetDataBuilder::new().build(),
|id, _cap| Box::new(TestWidget::new(id)),
);
let _ = ui.add_ui_widget(
root,
|| Box::new(()),
|id, _cap| Box::new(MovingWidget::new(id, Moveable {})),
);
}
fn create_handler(widget: Id, cap: &mut dyn MutCap<Event, Message>, event: Event) -> Option<Event> {
match event {
Event::Key(key) if key == 'z' => {
cap.add_widget(
widget,
Box::new(|| Box::new(())),
Box::new(|id, _cap| Box::new(TestWidget::new(id))),
);
None
},
_ => Some(event),
}
}
#[tokio::test]
async fn event_based_widget_creation() {
let (mut ui, root) = Ui::new(
|| {
TestWidgetDataBuilder::new()
.event_handler(create_handler)
.build()
},
|id, _cap| Box::new(TestWidget::new(id)),
);
ui.focus(root);
assert_eq!(ui.children(root).count(), 0);
let event = Event::Key('z');
let result = ui.handle(event).await;
assert!(result.is_none());
assert_eq!(ui.children(root).count(), 1);
}
fn recursive_operations_handler(
widget: Id,
cap: &mut dyn MutCap<Event, Message>,
_event: Event,
) -> Option<Event> {
cap.parent_id(widget);
cap.focus(widget);
cap.is_focused(widget);
Some(Event::Int(42))
}
#[tokio::test]
async fn recursive_widget_operations() {
let (mut ui, root) = Ui::new(
|| {
TestWidgetDataBuilder::new()
.event_handler(recursive_operations_handler)
.build()
},
|id, _cap| Box::new(TestWidget::new(id)),
);
ui.focus(root);
let result = ui.handle(Event::Empty).await.unwrap();
assert_eq!(result.unwrap_int(), 42);
}