Added value order testing.

This commit is contained in:
Samuel Guerra 2021-02-05 18:31:39 -03:00
parent 4e21f8bddf
commit 987df03b94
4 changed files with 162 additions and 5 deletions

23
Cargo.lock generated
View File

@ -2041,6 +2041,28 @@ dependencies = [
"serde",
]
[[package]]
name = "serial_test"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0bccbcf40c8938196944a3da0e133e031a33f4d6b72db3bda3cc556e361905d"
dependencies = [
"lazy_static",
"parking_lot",
"serial_test_derive",
]
[[package]]
name = "serial_test_derive"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2acd6defeddb41eb60bb468f8825d0cfd0c2a76bc03bfd235b6a1dc4f6a1ad5"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "servo-fontconfig"
version = "0.5.1"
@ -2730,6 +2752,7 @@ dependencies = [
"rayon",
"retain_mut",
"serde_json",
"serial_test",
"unicase",
"unicode-script",
"webrender",

View File

@ -47,4 +47,7 @@ once_cell = "1.5.2"
# app_profiler only
serde_json = { version = "1.0", optional = true }
lazy_static = { version = "1", optional = true }
lazy_static = { version = "1", optional = true }
[dev-dependencies]
serial_test = "0.5.1"

View File

@ -698,7 +698,9 @@ mod property_tests {
/// Tests on the #[widget(..)] and #[widget_mixin], widget_new! code generators.
#[cfg(test)]
mod widget_tests {
use self::util::Position;
use crate::{context::TestWidgetContext, widget2, widget_mixin2, Widget, WidgetId};
use serial_test::serial;
/*
* Tests the implicitly inherited properties.
@ -982,8 +984,60 @@ mod widget_tests {
assert!(util::traced(&required, "required!"))
}
/*
* Tests value initialization order.
*/
#[test]
#[serial(count)]
pub fn value_init_order() {
Position::reset();
let mut wgt = empty_wgt! {
util::count_inner = Position::next("count_inner");
util::count_context = Position::next("count_context");
};
wgt.test_init(&mut TestWidgetContext::wait_new());
// values evaluated in typed order.
assert_eq!(util::sorted_pos(&wgt), ["count_inner", "count_context"]);
// but properties init in the priority order.
assert_eq!(util::sorted_init_count(&wgt), ["count_context", "count_inner"]);
}
/*
* Tests value initialization order with child property.
*/
#[widget2($crate::widget_tests::child_property_wgt)]
pub mod child_property_wgt {
properties! {
child {
super::util::count_inner as count_child_inner;
}
}
}
#[test]
#[serial(count)]
pub fn wgt_child_property_init_order() {
Position::reset();
let mut wgt = child_property_wgt! {
util::count_inner = Position::next("count_inner");
util::count_context = Position::next("count_context");
count_child_inner = Position::next("count_child_inner");
};
wgt.test_init(&mut TestWidgetContext::wait_new());
// values evaluated in typed order.
assert_eq!(util::sorted_pos(&wgt), ["count_inner", "count_context", "count_child_inner"]);
// but properties init in the priority order (child first).
assert_eq!(util::sorted_init_count(&wgt), ["count_inner", "count_context", "count_child_inner"]);
}
mod util {
use std::collections::HashSet;
use std::{
collections::{HashMap, HashSet},
sync::atomic::{self, AtomicU32},
};
use crate::{context::WidgetContext, impl_ui_node, property, state_key, UiNode, Widget};
@ -1001,12 +1055,10 @@ mod widget_tests {
state_key! {
struct TraceKey: HashSet<&'static str>;
}
struct TraceNode<C: UiNode> {
child: C,
trace: &'static str,
}
#[impl_ui_node(child)]
impl<C: UiNode> UiNode for TraceNode<C> {
fn init(&mut self, ctx: &mut WidgetContext) {
@ -1014,5 +1066,84 @@ mod widget_tests {
ctx.widget_state.entry(TraceKey).or_default().insert(self.trace);
}
}
/// Insert `count` in the widget state. Can get using [`Count::get`].
#[property(context)]
pub fn count(child: impl UiNode, count: Position) -> impl UiNode {
CountNode { child, count }
}
pub use count as count_context;
/// Same as [`count`] but with `inner` priority.
#[property(inner)]
pub fn count_inner(child: impl UiNode, count: Position) -> impl UiNode {
CountNode { child, count }
}
/// Count adds one every [`Self::next`] call.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Position(pub u32, pub &'static str);
static COUNT: AtomicU32 = AtomicU32::new(0);
static COUNT_INIT: AtomicU32 = AtomicU32::new(0);
impl Position {
pub fn next(tag: &'static str) -> Self {
Position(COUNT.fetch_add(1, atomic::Ordering::AcqRel), tag)
}
fn next_init() -> u32 {
COUNT_INIT.fetch_add(1, atomic::Ordering::AcqRel)
}
pub fn reset() {
COUNT.store(0, atomic::Ordering::SeqCst);
COUNT_INIT.store(0, atomic::Ordering::SeqCst);
}
}
/// Gets the [`Position`] tags sorted by their number.
pub fn sorted_pos(wgt: &impl Widget) -> Vec<&'static str> {
wgt.state()
.get(PositionKey)
.map(|m| {
let mut vec: Vec<_> = m.iter().collect();
vec.sort_by_key(|(_, i)| i);
vec.into_iter().map(|(t, _)| t).collect()
})
.unwrap_or_default()
}
/// Gets the [`Position`] tags sorted by their init position.
pub fn sorted_init_count(wgt: &impl Widget) -> Vec<&'static str> {
wgt.state()
.get(InitPositionKey)
.map(|m| {
let mut vec: Vec<_> = m.iter().collect();
vec.sort_by_key(|(_, i)| i);
vec.into_iter().map(|(t, _)| t).collect()
})
.unwrap_or_default()
}
state_key! {
struct PositionKey: HashMap<&'static str, u32>;
struct InitPositionKey: HashMap<&'static str, u32>;
}
struct CountNode<C: UiNode> {
child: C,
count: Position,
}
#[impl_ui_node(child)]
impl<C: UiNode> UiNode for CountNode<C> {
fn init(&mut self, ctx: &mut WidgetContext) {
ctx.widget_state
.entry(InitPositionKey)
.or_default()
.insert(self.count.1, Position::next_init());
self.child.init(ctx);
ctx.widget_state.entry(PositionKey).or_default().insert(self.count.1, self.count.0);
}
}
}
}

View File

@ -19,4 +19,4 @@ heck = "0.3.2"
regex = "1.4.3"
[build-dependencies]
minifier = "0.0.36"
minifier = "0.0.36"