use crate::platform::{get_platform, Platform};
#[test]
fn contract_unknown_parent_is_rejected() {
let platform = get_platform();
platform.init();
let bogus_parent = 987_654_321u64;
assert!(Platform::get_widget_text(platform, bogus_parent).is_empty());
assert!(!Platform::destroy_widget(platform, bogus_parent));
let created = Platform::create_button(platform, bogus_parent, "x", 0, 0, 40, 20);
assert_eq!(
created,
0,
"creating a child under an unknown parent must return 0 ({} backend)",
platform.backend_name()
);
}
#[test]
fn contract_zero_parent_is_rejected() {
let platform = get_platform();
platform.init();
let created = Platform::create_label(platform, 0, "label", 0, 0, 40, 20);
assert_eq!(
created,
0,
"parent 0 must be rejected with 0 ({} backend)",
platform.backend_name()
);
}
#[test]
fn contract_rejected_creation_yields_no_usable_handle() {
let platform = get_platform();
platform.init();
let rejected = Platform::create_checkbox(platform, 4_242_424, "x", 0, 0, 10, 10);
assert_eq!(rejected, 0, "rejected creation must return 0");
assert!(
!Platform::is_widget_visible(platform, rejected),
"the failure handle 0 must not refer to a visible widget"
);
assert_eq!(
Platform::get_widget_text(platform, rejected),
"",
"reading text from the failure handle must be empty, not a dangling read"
);
}
#[test]
fn contract_destroy_unknown_id_is_false_not_panic() {
let platform = get_platform();
platform.init();
assert!(
!Platform::destroy_widget(platform, 5_555_555),
"destroying an unknown id must report false ({} backend)",
platform.backend_name()
);
assert!(!Platform::destroy_widget(platform, 0), "destroying handle 0 must report false");
}
#[test]
fn contract_unknown_widget_text_is_empty() {
let platform = get_platform();
platform.init();
let text = Platform::get_widget_text(platform, 6_666_666);
assert!(text.is_empty(), "unknown widget text must be empty, got {text:?}");
}
#[test]
fn contract_setters_on_unknown_widget_are_safe() {
let platform = get_platform();
platform.init();
let unknown = 7_777_777u64;
Platform::set_widget_text(platform, unknown, "x");
Platform::set_widget_geometry(platform, unknown, 1, 2, 3, 4);
Platform::set_widget_enabled(platform, unknown, false);
Platform::hide_widget(platform, unknown);
Platform::show_widget(platform, unknown);
assert!(
!Platform::is_widget_visible(platform, unknown),
"setters on an unknown id must not create it ({} backend)",
platform.backend_name()
);
assert_eq!(
Platform::get_widget_text(platform, unknown),
"",
"text must still be empty after setters on an unknown id"
);
}
#[test]
fn contract_recreate_does_not_reuse_destroyed_id() {
let platform = get_platform();
platform.init();
let window = Platform::create_window(platform, "ids", 0, 0, 300, 200);
let first = Platform::create_button(platform, window, "a", 0, 0, 20, 20);
assert_ne!(first, 0);
assert!(Platform::destroy_widget(platform, first));
let second = Platform::create_button(platform, window, "b", 0, 0, 20, 20);
assert_ne!(second, 0);
assert_ne!(
first, second,
"ids must not be recycled: a stale handle would alias the new widget"
);
assert!(!Platform::destroy_widget(platform, first), "the stale id must still be gone");
assert!(Platform::destroy_widget(platform, second), "the new widget must be live");
}
fn assert_contract(platform: &dyn Platform) {
let backend = platform.backend_name();
platform.init();
let bogus = 987_654_321u64;
assert_eq!(
Platform::create_button(platform, bogus, "x", 0, 0, 40, 20),
0,
"{backend}: unknown parent must be rejected"
);
assert_eq!(
Platform::create_label(platform, 0, "x", 0, 0, 40, 20),
0,
"{backend}: parent 0 must be rejected"
);
let unknown = 7_777_777u64;
Platform::set_widget_text(platform, unknown, "x");
Platform::set_widget_geometry(platform, unknown, 1, 2, 3, 4);
Platform::hide_widget(platform, unknown);
Platform::show_widget(platform, unknown);
assert!(
!Platform::is_widget_visible(platform, unknown),
"{backend}: setters must not materialise an unknown id"
);
assert_eq!(Platform::get_widget_text(platform, unknown), "", "{backend}: unknown text");
assert!(!Platform::destroy_widget(platform, unknown), "{backend}: destroy unknown -> false");
assert!(!Platform::destroy_widget(platform, 0), "{backend}: destroy 0 -> false");
let window = Platform::create_window(platform, "w", 0, 0, 200, 150);
assert_ne!(window, 0, "{backend}: window creation");
let child = Platform::create_button(platform, window, "b", 0, 0, 20, 20);
assert_ne!(child, 0, "{backend}: child creation under a valid parent");
Platform::set_widget_text(platform, child, "hello");
assert_eq!(Platform::get_widget_text(platform, child), "hello", "{backend}: text round-trip");
assert!(Platform::destroy_widget(platform, child), "{backend}: destroy live child");
assert_eq!(
Platform::get_widget_text(platform, child),
"",
"{backend}: destroyed widget must not retain text"
);
assert!(!Platform::destroy_widget(platform, child), "{backend}: destroy is idempotent");
}
#[test]
fn contract_holds_for_stub_platform() {
let platform =
crate::platform::StubPlatform::new("contract-stub", crate::core::PlatformFamily::Desktop);
assert_contract(&platform);
}
#[test]
fn contract_holds_for_selected_backend() {
assert_contract(get_platform());
}
#[cfg(feature = "harmony")]
#[test]
fn contract_holds_for_harmony_platform() {
use crate::platform::harmony::HarmonyPlatform;
let platform = HarmonyPlatform::new();
assert_contract(&platform);
}
#[cfg(feature = "wasm")]
#[test]
fn contract_holds_for_wasm_platform() {
use crate::platform::wasm::WasmPlatform;
let platform = WasmPlatform::default();
assert_contract(&platform);
}
#[test]
fn contract_child_controls_reject_unknown_parent_stub() {
let platform =
crate::platform::StubPlatform::new("contract-stub", crate::core::PlatformFamily::Desktop);
assert_child_controls_reject_unknown_parent(&platform);
}
#[test]
fn contract_child_controls_reject_unknown_parent_selected() {
assert_child_controls_reject_unknown_parent(get_platform());
}
fn assert_child_controls_reject_unknown_parent(platform: &dyn Platform) {
let backend = platform.backend_name();
platform.init();
let bogus = 424_242u64;
macro_rules! rejects {
($label:literal, $call:expr) => {{
assert_eq!($call, 0, "{backend}: {} must reject an unknown parent", $label);
}};
}
rejects!("button", Platform::create_button(platform, bogus, "b", 0, 0, 10, 10));
rejects!("checkbox", Platform::create_checkbox(platform, bogus, "c", 0, 0, 10, 10));
rejects!("label", Platform::create_label(platform, bogus, "l", 0, 0, 10, 10));
rejects!("line_edit", Platform::create_line_edit(platform, bogus, "e", 0, 0, 10, 10));
rejects!("radio_button", Platform::create_radio_button(platform, bogus, "r", 0, 0, 10, 10));
rejects!("slider", Platform::create_slider(platform, bogus, 0, 0, 10, 10));
rejects!("progress_bar", Platform::create_progress_bar(platform, bogus, 0, 0, 10, 10));
rejects!("combo_box", Platform::create_combo_box(platform, bogus, 0, 0, 10, 10));
rejects!("list_box", Platform::create_list_box(platform, bogus, 0, 0, 10, 10));
rejects!("panel", Platform::create_panel(platform, bogus, 0, 0, 10, 10));
rejects!("spin_box", Platform::create_spin_box(platform, bogus, 0, 0, 10, 10));
rejects!("list_view", Platform::create_list_view(platform, bogus, 0, 0, 10, 10));
rejects!("scroll_area", Platform::create_scroll_area(platform, bogus, 0, 0, 10, 10));
rejects!("group_box", Platform::create_group_box(platform, bogus, "g", 0, 0, 10, 10));
rejects!("frame", Platform::create_frame(platform, bogus, 0, 0, 10, 10));
rejects!("tab_widget", Platform::create_tab_widget(platform, bogus, 0, 0, 10, 10));
rejects!("splitter", Platform::create_splitter(platform, bogus, 0, 0, 10, 10));
}
#[cfg(feature = "macos")]
#[test]
fn contract_holds_for_macos_objc2_platform() {
use crate::platform::macos_objc2::MacOSObjc2Platform;
let platform = MacOSObjc2Platform::new();
assert_contract(&platform);
}
#[cfg(feature = "mobile-api")]
#[test]
fn contract_holds_for_mobile_platform() {
use crate::platform::mobile::AndroidMobilePlatform;
let platform = AndroidMobilePlatform::new();
assert_contract(&platform);
}
#[test]
fn contract_slider_value_round_trips_when_supported() {
let platform = get_platform();
platform.init();
let window = Platform::create_window(platform, "w", 0, 0, 400, 300);
assert_ne!(window, 0, "{}: window creation must succeed", platform.backend_name());
let slider = Platform::create_slider(platform, window, 0, 0, 200, 20);
assert_ne!(slider, 0, "{}: slider creation must succeed", platform.backend_name());
let _ = Platform::set_widget_range(platform, slider, 0.0, 200.0);
if Platform::set_widget_value(platform, slider, 42.0) {
assert_eq!(
Platform::widget_value(platform, slider),
Some(42.0),
"{}: a successful write must read back the written value",
platform.backend_name()
);
}
}
#[test]
fn contract_checkbox_checked_round_trips_when_supported() {
let platform = get_platform();
platform.init();
let window = Platform::create_window(platform, "w", 0, 0, 400, 300);
let checkbox = Platform::create_checkbox(platform, window, "on", 0, 0, 120, 24);
assert_ne!(checkbox, 0);
if Platform::set_widget_checked(platform, checkbox, true) {
assert_eq!(
Platform::is_widget_checked(platform, checkbox),
Some(true),
"{}: a successful checked write must read back true",
platform.backend_name()
);
}
}
#[test]
fn contract_property_write_unknown_id_is_refused() {
let platform = get_platform();
platform.init();
let bogus = 11_111_111u64;
assert!(!Platform::set_widget_value(platform, bogus, 5.0));
assert!(!Platform::set_widget_range(platform, bogus, 0.0, 10.0));
assert!(!Platform::set_widget_checked(platform, bogus, true));
assert!(!Platform::set_widget_selected_index(platform, bogus, Some(0)));
assert_eq!(Platform::widget_value(platform, bogus), None);
assert_eq!(Platform::widget_selected_index(platform, bogus), None);
assert_eq!(Platform::is_widget_checked(platform, bogus), None);
}
#[test]
fn contract_step_indeterminate_read_only_shape() {
let platform = get_platform();
platform.init();
let bogus = 22_222_222u64;
assert!(!Platform::set_widget_step(platform, bogus, 1.0));
assert!(!Platform::set_widget_indeterminate(platform, bogus, true));
assert!(!Platform::set_widget_read_only(platform, bogus, true));
assert!(!Platform::set_widget_max_length(platform, bogus, 10));
assert_eq!(Platform::widget_step(platform, bogus), None);
assert_eq!(Platform::is_widget_indeterminate(platform, bogus), None);
assert_eq!(Platform::is_widget_read_only(platform, bogus), None);
assert_eq!(Platform::widget_max_length(platform, bogus), None);
let window = Platform::create_window(platform, "w", 0, 0, 400, 300);
let slider = Platform::create_slider(platform, window, 0, 0, 200, 20);
if Platform::set_widget_step(platform, slider, 5.0) {
assert_eq!(
Platform::widget_step(platform, slider),
Some(5.0),
"{}: a successful step write must read back",
platform.backend_name()
);
}
let progress = Platform::create_progress_bar(platform, window, 0, 0, 200, 20);
if Platform::set_widget_indeterminate(platform, progress, true) {
assert_eq!(
Platform::is_widget_indeterminate(platform, progress),
Some(true),
"{}: a successful indeterminate write must read back",
platform.backend_name()
);
}
}
#[test]
fn contract_window_state_shape() {
use crate::platform::WindowStateFlag;
let platform = get_platform();
platform.init();
let bogus = 33_333_333u64;
assert!(!Platform::set_window_state(platform, bogus, WindowStateFlag::Maximized, true));
assert_eq!(Platform::is_window_in_state(platform, bogus, WindowStateFlag::Maximized), None);
let window = Platform::create_window(platform, "w", 0, 0, 400, 300);
assert_ne!(window, 0);
assert_eq!(
Platform::is_window_in_state(platform, window, WindowStateFlag::Resizable),
Some(true),
"{}: a new window is resizable",
platform.backend_name()
);
assert_eq!(
Platform::is_window_in_state(platform, window, WindowStateFlag::Decorated),
Some(true),
"{}: a new window is decorated",
platform.backend_name()
);
for flag in [
WindowStateFlag::Maximized,
WindowStateFlag::Minimized,
WindowStateFlag::Fullscreen,
WindowStateFlag::Resizable,
WindowStateFlag::Decorated,
] {
if Platform::set_window_state(platform, window, flag, true) {
assert_eq!(
Platform::is_window_in_state(platform, window, flag),
Some(true),
"{}: {flag:?} must read back after a successful write",
platform.backend_name()
);
}
if Platform::set_window_state(platform, window, flag, false) {
assert_eq!(
Platform::is_window_in_state(platform, window, flag),
Some(false),
"{}: {flag:?} must clear after a successful write",
platform.backend_name()
);
}
}
}
#[test]
fn contract_non_window_refuses_window_state() {
use crate::platform::WindowStateFlag;
let platform = get_platform();
platform.init();
let window = Platform::create_window(platform, "w", 0, 0, 400, 300);
let button = Platform::create_button(platform, window, "ok", 0, 0, 80, 24);
assert_ne!(button, 0);
assert!(
!Platform::set_window_state(platform, button, WindowStateFlag::Maximized, true),
"{}: a button is not a window",
platform.backend_name()
);
assert_eq!(Platform::is_window_in_state(platform, button, WindowStateFlag::Maximized), None);
}
#[test]
fn contract_window_min_size_and_icon_shape() {
let platform = get_platform();
platform.init();
let bogus = 44_444_444u64;
assert!(!Platform::set_window_min_size(platform, bogus, 200, 100));
assert_eq!(Platform::window_min_size(platform, bogus), None);
assert!(!Platform::set_window_icon(platform, bogus, "/nonexistent.png"));
assert_eq!(Platform::window_icon(platform, bogus), None);
let window = Platform::create_window(platform, "w", 0, 0, 400, 300);
assert_ne!(window, 0);
assert_eq!(
Platform::window_min_size(platform, window),
None,
"{}: an unset minimum must read back as None, not (0, 0)",
platform.backend_name()
);
if Platform::set_window_min_size(platform, window, 320, 240) {
assert_eq!(
Platform::window_min_size(platform, window),
Some((320, 240)),
"{}: a successful minimum-size write must read back",
platform.backend_name()
);
}
let missing = Platform::set_window_icon(platform, window, "/definitely/not/here.png");
if missing {
assert_eq!(
Platform::window_icon(platform, window),
Some("/definitely/not/here.png".to_string())
);
}
}
#[test]
fn contract_non_window_refuses_min_size_and_icon() {
let platform = get_platform();
platform.init();
let window = Platform::create_window(platform, "w", 0, 0, 400, 300);
let button = Platform::create_button(platform, window, "ok", 0, 0, 80, 24);
assert_ne!(button, 0);
assert!(
!Platform::set_window_min_size(platform, button, 10, 10),
"{}: a button is not a window",
platform.backend_name()
);
assert_eq!(Platform::window_min_size(platform, button), None);
assert!(!Platform::set_window_icon(platform, button, "/tmp/x.png"));
assert_eq!(Platform::window_icon(platform, button), None);
}
#[test]
fn contract_text_entry_properties_shape() {
use crate::platform::EchoMode;
let platform = get_platform();
platform.init();
let bogus = 55_555_555u64;
assert!(!Platform::set_widget_selection(platform, bogus, 0, 3));
assert_eq!(Platform::widget_selection(platform, bogus), None);
assert!(!Platform::set_widget_placeholder(platform, bogus, "hint"));
assert_eq!(Platform::widget_placeholder(platform, bogus), None);
assert!(!Platform::set_widget_echo_mode(platform, bogus, EchoMode::Password));
assert_eq!(Platform::widget_echo_mode(platform, bogus), None);
let window = Platform::create_window(platform, "w", 0, 0, 400, 300);
let entry = Platform::create_line_edit(platform, window, "text", 0, 0, 200, 24);
assert_ne!(entry, 0);
if Platform::set_widget_selection(platform, entry, 0, 3) {
let read = Platform::widget_selection(platform, entry);
assert!(
read.is_some(),
"{}: a successful selection write must be readable",
platform.backend_name()
);
}
if Platform::set_widget_placeholder(platform, entry, "Type here") {
assert_eq!(
Platform::widget_placeholder(platform, entry).as_deref(),
Some("Type here"),
"{}: a successful placeholder write must read back",
platform.backend_name()
);
}
if Platform::set_widget_echo_mode(platform, entry, EchoMode::Password) {
assert_eq!(
Platform::widget_echo_mode(platform, entry),
Some(EchoMode::Password),
"{}: a successful echo-mode write must read back",
platform.backend_name()
);
}
}
#[test]
fn contract_no_echo_mode_is_refused_or_honoured_truthfully() {
use crate::platform::EchoMode;
let platform = get_platform();
platform.init();
let window = Platform::create_window(platform, "w", 0, 0, 400, 300);
let entry = Platform::create_line_edit(platform, window, "text", 0, 0, 200, 24);
assert_ne!(entry, 0);
let accepted = Platform::set_widget_echo_mode(platform, entry, EchoMode::NoEcho);
if accepted {
assert_eq!(
Platform::widget_echo_mode(platform, entry),
Some(EchoMode::NoEcho),
"{}: if NoEcho is accepted it must actually be in effect",
platform.backend_name()
);
}
}
#[test]
fn contract_orientation_tristate_group_scroll_shape() {
use crate::core::Orientation;
let platform = get_platform();
platform.init();
let bogus = 66_666_666u64;
assert!(!Platform::set_slider_orientation(platform, bogus, Orientation::Vertical));
assert_eq!(Platform::slider_orientation(platform, bogus), None);
assert!(!Platform::set_widget_tristate(platform, bogus, true));
assert_eq!(Platform::is_widget_tristate(platform, bogus), None);
assert!(!Platform::set_widget_group(platform, bogus, "g"));
assert_eq!(Platform::widget_group(platform, bogus), None);
assert!(!Platform::set_widget_scroll_position(platform, bogus, 1, 2));
assert_eq!(Platform::widget_scroll_position(platform, bogus), None);
let window = Platform::create_window(platform, "w", 0, 0, 400, 300);
let slider = Platform::create_slider(platform, window, 0, 0, 200, 20);
assert_ne!(slider, 0);
if Platform::set_slider_orientation(platform, slider, Orientation::Vertical) {
assert_eq!(
Platform::slider_orientation(platform, slider),
Some(Orientation::Vertical),
"{}: vertical orientation must read back",
platform.backend_name()
);
}
let check = Platform::create_checkbox(platform, window, "t", 0, 0, 120, 24);
assert_ne!(check, 0);
if Platform::set_widget_tristate(platform, check, true) {
assert_eq!(
Platform::is_widget_tristate(platform, check),
Some(true),
"{}: tri-state must read back",
platform.backend_name()
);
}
let radio = Platform::create_radio_button(platform, window, "r", 0, 0, 120, 24);
assert_ne!(radio, 0);
if Platform::set_widget_group(platform, radio, "opts") {
assert_eq!(
Platform::widget_group(platform, radio).as_deref(),
Some("opts"),
"{}: group name must read back",
platform.backend_name()
);
}
let area = Platform::create_scroll_area(platform, window, 0, 0, 200, 200);
assert_ne!(area, 0);
if Platform::set_widget_scroll_position(platform, area, 10, 20) {
assert_eq!(
Platform::widget_scroll_position(platform, area),
Some((10, 20)),
"{}: scroll offset must read back",
platform.backend_name()
);
}
}
#[test]
fn contract_tristate_refused_on_non_checkable() {
let platform = get_platform();
platform.init();
let window = Platform::create_window(platform, "w", 0, 0, 400, 300);
let label = Platform::create_label(platform, window, "text", 0, 0, 120, 24);
assert_ne!(label, 0);
assert!(
!Platform::set_widget_tristate(platform, label, true),
"{}: a label is not checkable",
platform.backend_name()
);
assert_eq!(Platform::is_widget_tristate(platform, label), None);
}