#![cfg(all(feature = "desktop", not(alloc_frugal)))]
use rust_widgets::json::{
clear_global_handlers, invoke_global_handler, register_global_handler, EventHandlerContext,
JsonLoader,
};
use rust_widgets::widget::capability::WidgetFactory;
use rust_widgets::WidgetTriggerEvent;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
fn with_clean_handlers(body: impl FnOnce()) {
clear_global_handlers();
body();
clear_global_handlers();
}
fn counting_handler(name: &str) -> Arc<AtomicUsize> {
let calls = Arc::new(AtomicUsize::new(0));
let sink = Arc::clone(&calls);
register_global_handler(name, move |_ctx: &EventHandlerContext| {
sink.fetch_add(1, Ordering::SeqCst);
});
calls
}
fn fire(name: &str, kind: rust_widgets::platform::WidgetTriggerKind) -> bool {
let ctx = EventHandlerContext::new(WidgetTriggerEvent { widget_id: 1, kind });
invoke_global_handler(name, &ctx)
}
#[test]
fn a_published_name_declared_under_events_is_wired() {
use rust_widgets::platform::WidgetTriggerKind;
with_clean_handlers(|| {
let calls = counting_handler("on_go");
let json = r#"{"window":{"id":"w","title":"T","width":400,"height":300,"layout":{
"type":"vbox","children":[{"button":{"id":"b","text":"Go","events":{"clicked":"on_go"}}}]}}}"#;
JsonLoader::load(json).expect("a published-name binding must load");
assert!(
fire("on_go", WidgetTriggerKind::Clicked),
"the handler named under `events.clicked` must be registered, or the published \
route resolves the name and then wires nothing"
);
assert_eq!(calls.load(Ordering::SeqCst), 1);
});
}
#[test]
fn a_compatibility_key_still_reaches_its_handler() {
use rust_widgets::platform::WidgetTriggerKind;
with_clean_handlers(|| {
let calls = counting_handler("on_close_legacy");
let json = r#"{"window":{"id":"w","title":"T","width":400,"height":300,
"on_close":"on_close_legacy"}}"#;
JsonLoader::load(json).expect("a compatibility binding must load");
assert!(fire("on_close_legacy", WidgetTriggerKind::Closed));
assert_eq!(calls.load(Ordering::SeqCst), 1);
});
}
#[test]
fn both_routes_can_be_declared_on_one_node() {
use rust_widgets::platform::WidgetTriggerKind;
with_clean_handlers(|| {
let published = counting_handler("on_pub");
let legacy = counting_handler("on_leg");
let json = r#"{"window":{"id":"w","title":"T","width":400,"height":300,"layout":{
"type":"vbox","children":[{"button":{"id":"b","text":"Go",
"events":{"clicked":"on_pub"},"on_change":"on_leg"}}]}}}"#;
JsonLoader::load(json).expect("both routes on one node must load");
assert!(fire("on_pub", WidgetTriggerKind::Clicked), "the published route must be wired");
assert!(fire("on_leg", WidgetTriggerKind::ValueChanged), "the compatibility route too");
assert_eq!(published.load(Ordering::SeqCst), 1);
assert_eq!(legacy.load(Ordering::SeqCst), 1);
});
}
#[test]
fn an_unpublished_name_cannot_be_subscribed_while_a_published_one_can() {
let hub = rust_widgets::signal::CustomSignalHub::new();
let factory = WidgetFactory::new_with_defaults();
factory
.connect_event("button", "clicked", &hub, || {})
.expect("`button` publishes `clicked`, so the loader's published route can accept it");
assert!(
factory.connect_event("button", "clikced", &hub, || {}).is_err(),
"`clikced` is not a published name, which is exactly why a document declaring it must not \
end up with a live binding"
);
}
#[test]
fn a_typo_in_an_event_name_does_not_fail_the_whole_document() {
with_clean_handlers(|| {
counting_handler("on_typo");
let json = r#"{"window":{"id":"w","title":"T","width":400,"height":300,"layout":{
"type":"vbox","children":[{"button":{"id":"b","text":"Go",
"events":{"clikced":"on_typo"}}}]}}}"#;
let layout = JsonLoader::load(json).expect("a refused binding must not fail the load");
assert!(
layout.id("b").is_some(),
"the button must still be registered: one bad handler name is not a broken layout"
);
});
}
#[test]
fn a_payload_carrying_published_name_is_declarable() {
with_clean_handlers(|| {
counting_handler("on_moved");
let json = r#"{"window":{"id":"w","title":"T","width":400,"height":300,"layout":{
"type":"vbox","children":[{"slider":{"id":"s","min":0,"max":100,
"events":{"slider_moved":"on_moved"}}}]}}}"#;
JsonLoader::load(json).expect("a payload-carrying published name must be declarable");
});
}
#[test]
fn a_declared_binding_is_not_reported_as_an_unknown_property() {
with_clean_handlers(|| {
let json = r#"{"window":{"id":"w","title":"T","width":400,"height":300,"layout":{
"type":"vbox","children":[{"button":{"id":"b","text":"Go",
"events":{"clicked":"on_a"},"on_close":"on_b","on_selection_changed":"on_c"}}]}}}"#;
let layout = JsonLoader::load(json).expect("the document must load");
assert!(!layout.is_empty(), "the document's identified widgets must be registered");
});
}