use crate::dom::cascade::resolver::StyleResolver;
use crate::dom::node::{DomNode, WidgetMeta};
use crate::dom::DomId;
use crate::style::{Declaration, Rule, StyleSheet};
fn create_test_stylesheet() -> StyleSheet {
StyleSheet {
rules: vec![
Rule {
selector: "Button".to_string(),
declarations: vec![Declaration {
property: "padding".to_string(),
value: "1".to_string(),
}],
},
Rule {
selector: ".primary".to_string(),
declarations: vec![Declaration {
property: "background".to_string(),
value: "blue".to_string(),
}],
},
Rule {
selector: "#submit".to_string(),
declarations: vec![Declaration {
property: "width".to_string(),
value: "100".to_string(),
}],
},
],
variables: std::collections::HashMap::new(),
keyframes: std::collections::HashMap::new(),
}
}
fn create_button_node(id: u64) -> DomNode {
let dom_id = DomId::new(id);
DomNode::new(dom_id, WidgetMeta::new("Button"))
}
fn create_node_with_class(id: u64, widget_type: &str, class: &str) -> DomNode {
let dom_id = DomId::new(id);
DomNode::new(dom_id, WidgetMeta::new(widget_type).class(class))
}
fn create_node_with_id(id: u64, widget_type: &str, element_id: &str) -> DomNode {
let dom_id = DomId::new(id);
DomNode::new(dom_id, WidgetMeta::new(widget_type).id(element_id))
}
#[test]
fn test_resolver_new() {
let stylesheet = create_test_stylesheet();
let resolver = StyleResolver::new(&stylesheet);
assert_eq!(resolver.selectors.len(), 3);
}
#[test]
fn test_resolver_match_by_type() {
let stylesheet = create_test_stylesheet();
let mut resolver = StyleResolver::new(&stylesheet);
let node = create_button_node(1);
let get_node = |_: DomId| -> Option<&DomNode> { None };
let matches = resolver.match_node(&node, get_node);
assert_eq!(matches.len(), 1);
assert_eq!(matches[0].rule.selector, "Button");
}
#[test]
fn test_resolver_match_by_class() {
let stylesheet = create_test_stylesheet();
let mut resolver = StyleResolver::new(&stylesheet);
let node = create_node_with_class(1, "Text", "primary");
let get_node = |_: DomId| -> Option<&DomNode> { None };
let matches = resolver.match_node(&node, get_node);
assert_eq!(matches.len(), 1);
assert_eq!(matches[0].rule.selector, ".primary");
}
#[test]
fn test_resolver_match_by_id() {
let stylesheet = create_test_stylesheet();
let mut resolver = StyleResolver::new(&stylesheet);
let node = create_node_with_id(1, "Button", "submit");
let get_node = |_: DomId| -> Option<&DomNode> { None };
let matches = resolver.match_node(&node, get_node);
assert_eq!(matches.len(), 2);
}
#[test]
fn test_resolver_match_multiple() {
let stylesheet = create_test_stylesheet();
let mut resolver = StyleResolver::new(&stylesheet);
let dom_id = DomId::new(1);
let node = DomNode::new(
dom_id,
WidgetMeta::new("Button").class("primary").id("submit"),
);
let get_node = |_: DomId| -> Option<&DomNode> { None };
let matches = resolver.match_node(&node, get_node);
assert_eq!(matches.len(), 3);
assert_eq!(matches[0].rule.selector, "Button");
assert_eq!(matches[1].rule.selector, ".primary");
assert_eq!(matches[2].rule.selector, "#submit");
}
#[test]
fn test_resolver_no_match() {
let stylesheet = create_test_stylesheet();
let mut resolver = StyleResolver::new(&stylesheet);
let dom_id = DomId::new(1);
let node = DomNode::new(dom_id, WidgetMeta::new("Text")); let get_node = |_: DomId| -> Option<&DomNode> { None };
let matches = resolver.match_node(&node, get_node);
assert_eq!(matches.len(), 0);
}
#[test]
fn test_compute_style_basic() {
let stylesheet = create_test_stylesheet();
let mut resolver = StyleResolver::new(&stylesheet);
let node = create_button_node(1);
let get_node = |_: DomId| -> Option<&DomNode> { None };
let style = resolver.compute_style(&node, get_node);
let _ = style; }
#[test]
fn test_with_cached_selectors() {
let stylesheet = create_test_stylesheet();
let mut resolver1 = StyleResolver::new(&stylesheet);
let cached = resolver1.selectors.clone();
let mut resolver2 = StyleResolver::with_cached_selectors(&stylesheet, &cached);
let node = create_button_node(1);
let get_node = |_: DomId| -> Option<&DomNode> { None };
let matches1 = resolver1.match_node(&node, &get_node);
let matches2 = resolver2.match_node(&node, &get_node);
assert_eq!(matches1.len(), matches2.len());
}
#[test]
fn test_resolver_invalid_selector() {
let stylesheet = StyleSheet {
rules: vec![Rule {
selector: "[invalid".to_string(), declarations: vec![],
}],
variables: std::collections::HashMap::new(),
keyframes: std::collections::HashMap::new(),
};
let resolver = StyleResolver::new(&stylesheet);
assert_eq!(resolver.selectors.len(), 0);
}
#[test]
fn test_universal_selector() {
let stylesheet = StyleSheet {
rules: vec![Rule {
selector: "*".to_string(),
declarations: vec![Declaration {
property: "color".to_string(),
value: "white".to_string(),
}],
}],
variables: std::collections::HashMap::new(),
keyframes: std::collections::HashMap::new(),
};
let mut resolver = StyleResolver::new(&stylesheet);
let node = create_button_node(1);
let get_node = |_: DomId| -> Option<&DomNode> { None };
let matches = resolver.match_node(&node, get_node);
assert_eq!(matches.len(), 1);
}
#[test]
fn test_compute_style_with_inline() {
let stylesheet = StyleSheet {
rules: vec![Rule {
selector: "Button".to_string(),
declarations: vec![Declaration {
property: "opacity".to_string(),
value: "0.5".to_string(),
}],
}],
variables: std::collections::HashMap::new(),
keyframes: std::collections::HashMap::new(),
};
let mut resolver = StyleResolver::new(&stylesheet);
let dom_id = DomId::new(1);
let mut node = DomNode::new(dom_id, WidgetMeta::new("Button"));
let mut inline = crate::style::Style::default();
inline.visual.opacity = 0.8;
node.inline_style = Some(inline);
let get_node = |_: DomId| -> Option<&DomNode> { None };
let style = resolver.compute_style(&node, get_node);
assert!((style.visual.opacity - 0.8).abs() < 0.001);
}
#[test]
fn test_compute_style_with_parent() {
use crate::style::Color;
let stylesheet = StyleSheet {
rules: vec![],
variables: std::collections::HashMap::new(),
keyframes: std::collections::HashMap::new(),
};
let mut resolver = StyleResolver::new(&stylesheet);
let dom_id = DomId::new(1);
let node = DomNode::new(dom_id, WidgetMeta::new("Text"));
let get_node = |_: DomId| -> Option<&DomNode> { None };
let mut parent_style = crate::style::Style::default();
parent_style.visual.color = Color::hex(0xff0000);
let style = resolver.compute_style_with_parent(&node, Some(&parent_style), get_node);
assert_eq!(style.visual.color, Color::hex(0xff0000));
}
#[test]
fn test_compute_style_with_parent_none() {
let stylesheet = StyleSheet {
rules: vec![],
variables: std::collections::HashMap::new(),
keyframes: std::collections::HashMap::new(),
};
let mut resolver = StyleResolver::new(&stylesheet);
let dom_id = DomId::new(1);
let node = DomNode::new(dom_id, WidgetMeta::new("Text"));
let get_node = |_: DomId| -> Option<&DomNode> { None };
let style = resolver.compute_style_with_parent(&node, None, get_node);
assert!(style.visual.visible);
}