#![cfg(all(
any(feature = "desktop", feature = "tablet", feature = "mobile"),
not(any(feature = "mini", feature = "embedded"))
))]
use rust_widgets::app::{App, WidgetHandle};
use rust_widgets::core::{Orientation, Rect};
use rust_widgets::layout::{BoxLayout, Layout};
use rust_widgets::platform::WidgetTriggerKind;
fn window_with_filling_child(width: u32, height: u32) -> (u64, rust_widgets::app::WindowHandle) {
let mut app = App::new();
app.init();
let win = app.new_window("resize test", 0, 0, width, height);
let child = win.new_label("child", 0, 0, 0, 0);
let mut layout = BoxLayout::new(Orientation::Vertical, 0, 0);
layout.add_widget(child.raw_id(), 1);
win.set_layout(layout);
(child.raw_id(), win)
}
fn geometry_of(id: u64) -> Option<Rect> {
rust_widgets::widget::runtime::geometry_of(id)
}
fn pump() {
while let Some(event) = rust_widgets::poll_widget_trigger_event() {
rust_widgets::app::dispatch_trigger(event.widget_id, event.kind);
}
}
fn pump_until_resize_of(window_id: u64) -> bool {
let mut seen = false;
while let Some(event) = rust_widgets::poll_widget_trigger_event() {
if event.widget_id == window_id && event.kind == WidgetTriggerKind::Resized {
seen = true;
}
rust_widgets::app::dispatch_trigger(event.widget_id, event.kind);
}
seen
}
#[test]
fn a_reported_resize_re_runs_the_layout() {
let (child, win) = window_with_filling_child(800, 600);
let before = geometry_of(child).expect("child mounted");
assert_eq!(before.width, 800, "the layout must have run for the created size");
assert!(
rust_widgets::queue_resize_trigger(win.raw_id(), 1300, 600),
"the backend must accept a resize for a window it created"
);
assert!(
pump_until_resize_of(win.raw_id()),
"the resize event must be queued with the kind `Resized` and the window's id"
);
let after = geometry_of(child).expect("child mounted");
assert_eq!(
after.width, 1300,
"the child must be re-laid out for the reported width (was {before:?}, now {after:?})"
);
}
#[test]
fn the_reported_client_size_is_readable() {
let (_child, win) = window_with_filling_child(800, 600);
rust_widgets::queue_resize_trigger(win.raw_id(), 1024, 768);
assert_eq!(
rust_widgets::window_client_size(win.raw_id()),
Some((1024, 768)),
"the reported size must survive the poll (the event is consumed, the size is not)"
);
}
#[test]
fn a_resize_for_an_unknown_window_is_refused() {
let (_child, _win) = window_with_filling_child(800, 600);
assert!(
!rust_widgets::queue_resize_trigger(0xDEAD_BEEF, 100, 100),
"an unknown window id must be refused"
);
assert_eq!(rust_widgets::window_client_size(0xDEAD_BEEF), None, "and must report no size");
}
#[test]
fn repeated_resizes_each_re_run_the_layout() {
let (child, win) = window_with_filling_child(800, 600);
for width in [900u32, 1100, 700] {
rust_widgets::queue_resize_trigger(win.raw_id(), width, 600);
pump();
assert_eq!(
geometry_of(child).map(|rect| rect.width),
Some(width),
"the child must follow every resize"
);
}
}
#[test]
fn a_resize_on_an_empty_window_is_harmless() {
let mut app = App::new();
app.init();
let win = app.new_window("empty", 0, 0, 400, 300);
assert!(rust_widgets::queue_resize_trigger(win.raw_id(), 900, 700));
pump();
assert_eq!(
rust_widgets::window_client_size(win.raw_id()),
Some((900, 700)),
"the size must still be recorded for a childless window"
);
}
#[test]
fn a_height_only_resize_is_reported() {
let (child, win) = window_with_filling_child(800, 600);
let before = geometry_of(child).expect("child mounted");
rust_widgets::queue_resize_trigger(win.raw_id(), 800, 450);
pump();
let after = geometry_of(child).expect("child mounted");
assert_eq!(after.width, before.width, "the width must be unchanged");
assert_eq!(after.height, 450, "the child must follow the new height");
}
#[test]
fn the_platform_backend_forwards_a_resize_into_the_layout() {
use rust_widgets::platform::{Platform, StubPlatform};
let platform: &'static dyn Platform = Box::leak(Box::new(StubPlatform::new(
"resize-test",
rust_widgets::core::PlatformFamily::Desktop,
)));
rust_widgets::platform::with_platform(platform, || {
let (child, win) = window_with_filling_child(640, 480);
assert_eq!(
platform.window_client_size(win.raw_id()),
Some((640, 480)),
"an unresized window must report the size it was created with"
);
assert!(
platform.queue_resize_trigger(win.raw_id(), 1180, 720),
"the backend must accept a resize for a window it created"
);
assert_eq!(
platform.window_client_size(win.raw_id()),
Some((1180, 720)),
"the backend must report the size it was just given"
);
pump();
assert_eq!(
geometry_of(child),
Some(Rect { x: 0, y: 0, width: 1180, height: 720 }),
"a resize arriving through the backend must re-run the layout"
);
assert!(
!platform.queue_resize_trigger(0x0BAD_1DEA, 100, 100),
"an unknown window id must be refused by the backend"
);
assert_eq!(platform.window_client_size(0x0BAD_1DEA), None, "and report no size");
});
}
#[test]
fn the_platform_override_is_scoped_to_its_block() {
use rust_widgets::platform::{Platform, StubPlatform};
let outer: &'static dyn Platform = Box::leak(Box::new(StubPlatform::new(
"outer",
rust_widgets::core::PlatformFamily::Desktop,
)));
let inner: &'static dyn Platform = Box::leak(Box::new(StubPlatform::new(
"inner",
rust_widgets::core::PlatformFamily::Desktop,
)));
rust_widgets::platform::with_platform(outer, || {
assert_eq!(outer.backend_name(), rust_widgets::platform::get_platform().backend_name());
rust_widgets::platform::with_platform(inner, || {
assert_eq!(
inner.backend_name(),
rust_widgets::platform::get_platform().backend_name(),
"the nested override must win inside its block"
);
});
assert_eq!(
outer.backend_name(),
rust_widgets::platform::get_platform().backend_name(),
"the outer override must be restored after the nested block"
);
});
}
#[test]
fn a_recycled_widget_id_does_not_inherit_the_old_windows_size() {
use rust_widgets::control_backend::get_control_backend;
let backend = get_control_backend();
let first = backend.create_window("first", 0, 0, 800, 600);
assert_ne!(first, 0, "the backend must create a window");
assert!(rust_widgets::queue_resize_trigger(first, 1300, 600));
assert_eq!(
backend.window_client_size(first),
Some((1300, 600)),
"the first window must record the size it was resized to"
);
assert!(backend.destroy_widget(first), "the first window must be destroyable");
let second = backend.create_window("second", 0, 0, 640, 480);
assert_ne!(second, 0, "the backend must create the second window");
assert_eq!(
backend.window_client_size(second),
Some((640, 480)),
"a new window must report the size it was created with, not a dead window's"
);
if second == first {
assert_ne!(
backend.window_client_size(second),
Some((1300, 600)),
"the recycled id must not keep the destroyed window's recorded size"
);
}
}