#![cfg(all(not(feature = "mini"), not(feature = "embedded"), not(target_arch = "wasm32")))]
use rust_widgets::core::Rect;
use rust_widgets::widget::capability::WidgetFactory;
use rust_widgets::widget::draw_bridge::draw_of;
use std::collections::BTreeSet;
#[allow(dead_code)]
fn controls() -> Vec<(&'static str, Box<dyn rust_widgets::widget::Widget>)> {
let factory = WidgetFactory::new_with_defaults();
factory
.widget_names()
.into_iter()
.filter_map(|name| {
factory.create(name, Rect::new(0, 0, 240, 120), "Sample").map(|widget| (name, widget))
})
.collect()
}
#[test]
fn q1_every_declared_property_is_answered_by_its_control() {
let factory = WidgetFactory::new_with_defaults();
let mut checked = 0usize;
let mut failures: Vec<String> = Vec::new();
for capability in factory.capabilities() {
let Some(widget) =
factory.create(capability.canonical_name, Rect::new(0, 0, 240, 120), "S")
else {
failures.push(format!(
"{}: the registry publishes it but `create` returns None",
capability.canonical_name
));
continue;
};
let Some(published) =
rust_widgets::widget::capability::widget_property_names(widget.as_ref())
else {
continue;
};
for schema in capability.properties {
checked += 1;
if !schema.readable && !schema.writable {
continue;
}
if !published.contains(&schema.name) {
failures.push(format!(
"{}: declared property `{}` is absent from the control's property_names()",
capability.canonical_name, schema.name
));
continue;
}
if schema.readable {
let answer = rust_widgets::widget::capability::widget_property_get(
widget.as_ref(),
schema.name,
);
if let Err(error) = answer {
failures.push(format!(
"{}::{} is declared readable but `get` answers {error:?}",
capability.canonical_name, schema.name
));
}
}
}
}
assert!(
checked > 1000,
"the gate must walk a real property table, not a sample; checked={checked}"
);
assert!(
failures.is_empty(),
"these declared properties are not answered by the control that declares them:\n {}",
failures.join("\n ")
);
}
#[test]
fn q1_writability_matches_the_declaration() {
let factory = WidgetFactory::new_with_defaults();
let mut checked = 0usize;
let mut failures: Vec<String> = Vec::new();
for capability in factory.capabilities() {
let Some(mut widget) =
factory.create(capability.canonical_name, Rect::new(0, 0, 240, 120), "S")
else {
continue;
};
for schema in capability.properties {
if !schema.readable && !schema.writable {
continue;
}
checked += 1;
if !schema.writable {
use rust_widgets::widget::capability::types::{
CapabilityAccessError, CapabilityValue,
};
let verdict = rust_widgets::widget::capability::widget_property_set(
widget.as_mut(),
schema.name,
CapabilityValue::Null,
);
if matches!(
verdict,
Ok(())
| Err(CapabilityAccessError::TypeMismatch)
| Err(CapabilityAccessError::OutOfRange)
) {
failures.push(format!(
"{}::{} is declared read-only but `set` answers {verdict:?}",
capability.canonical_name, schema.name
));
}
}
}
}
assert!(checked > 1000);
assert!(
failures.is_empty(),
"these properties disagree with their declared writability:\n {}",
failures.join("\n ")
);
}
#[test]
fn q2_every_control_draws_something() {
use rust_widgets::core::{Color, Size};
use rust_widgets::render::{PaintBackend, RenderContext, SoftwarePaintBackend};
let factory = WidgetFactory::new_with_defaults();
let mut failures: Vec<&str> = Vec::new();
for capability in factory.capabilities() {
let name = capability.canonical_name;
let Some(mut widget) = factory.create(name, Rect::new(0, 0, 240, 120), "Sample") else {
continue;
};
let Some(drawable) = draw_of(widget.as_mut()) else {
failures.push(name);
continue;
};
let mut backend = SoftwarePaintBackend::new(Size::new(240, 120), 1.0);
let probe = Color { r: 255, g: 0, b: 255, a: 255 };
backend.begin_frame(probe);
let mut context = RenderContext::new(&mut backend);
drawable.draw(&mut context);
backend.end_frame();
let painted = backend
.frame_rgba()
.chunks_exact(4)
.any(|px| (px[0], px[1], px[2]) != (probe.r, probe.g, probe.b));
if !painted {
failures.push(name);
}
}
assert!(
failures.is_empty(),
"these controls reached `Draw::draw` and painted nothing, which is an empty \
implementation (principle #5): {failures:?}"
);
}
#[test]
fn q3_every_published_event_names_a_real_signal() {
let factory = WidgetFactory::new_with_defaults();
let mut published_total = 0usize;
let mut failures: Vec<String> = Vec::new();
for capability in factory.capabilities() {
let events: Vec<&str> = capability.events.iter().map(|schema| schema.name).collect();
published_total += events.len();
let unique: BTreeSet<&str> = events.iter().copied().collect();
if unique.len() != events.len() {
failures.push(format!(
"{} publishes a duplicate event name: {:?}",
capability.canonical_name, events
));
}
}
assert!(
published_total > 300,
"the gate must walk the real event table; got {published_total}"
);
assert!(
failures.is_empty(),
"these capabilities publish an event list that is not a set:\n {}",
failures.join("\n ")
);
}
#[test]
fn q3_the_generated_table_covers_every_publishing_capability() {
let factory = WidgetFactory::new_with_defaults();
let mut missing: Vec<&str> = Vec::new();
let mut with_events = 0usize;
for capability in factory.capabilities() {
if capability.events.is_empty() {
continue;
}
with_events += 1;
for schema in capability.events {
if schema.name.is_empty() {
missing.push(capability.canonical_name);
}
}
}
assert!(with_events > 100, "most controls publish something; got {with_events}");
assert!(
missing.is_empty(),
"these capabilities publish an unnamed event, so nothing can be derived or \
connected: {missing:?}"
);
}