From 5e4bdac2bd431c8acef79daeac621ffc84971735 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Sun, 21 Aug 2016 00:24:23 +0200 Subject: [PATCH] Import SelectorMap unit tests from the selectors crate. --- components/style/selector_matching.rs | 18 ++--- tests/unit/style/lib.rs | 1 + tests/unit/style/selector_matching.rs | 103 ++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 9 deletions(-) create mode 100644 tests/unit/style/selector_matching.rs diff --git a/components/style/selector_matching.rs b/components/style/selector_matching.rs index 573de8b4575..d04aa322924 100644 --- a/components/style/selector_matching.rs +++ b/components/style/selector_matching.rs @@ -609,16 +609,16 @@ impl PerPseudoElementSelectorMap { #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct SelectorMap { // TODO: Tune the initial capacity of the HashMap - id_hash: FnvHashMap>, - class_hash: FnvHashMap>, - local_name_hash: FnvHashMap>, + pub id_hash: FnvHashMap>, + pub class_hash: FnvHashMap>, + pub local_name_hash: FnvHashMap>, /// Same as local_name_hash, but keys are lower-cased. /// For HTML elements in HTML documents. - lower_local_name_hash: FnvHashMap>, + pub lower_local_name_hash: FnvHashMap>, /// Rules that don't have ID, class, or element selectors. - other_rules: Vec, + pub other_rules: Vec, /// Whether this hash is empty. - empty: bool, + pub empty: bool, } #[inline] @@ -783,7 +783,7 @@ impl SelectorMap { } /// Retrieve the first ID name in Rule, or None otherwise. - fn get_id_name(rule: &Rule) -> Option { + pub fn get_id_name(rule: &Rule) -> Option { for ss in &rule.selector.compound_selector { // TODO(pradeep): Implement case-sensitivity based on the // document type and quirks mode. @@ -796,7 +796,7 @@ impl SelectorMap { } /// Retrieve the FIRST class name in Rule, or None otherwise. - fn get_class_name(rule: &Rule) -> Option { + pub fn get_class_name(rule: &Rule) -> Option { for ss in &rule.selector.compound_selector { // TODO(pradeep): Implement case-sensitivity based on the // document type and quirks mode. @@ -809,7 +809,7 @@ impl SelectorMap { } /// Retrieve the name if it is a type selector, or None otherwise. - fn get_local_name(rule: &Rule) -> Option> { + pub fn get_local_name(rule: &Rule) -> Option> { for ss in &rule.selector.compound_selector { if let SimpleSelector::LocalName(ref n) = *ss { return Some(LocalName { diff --git a/tests/unit/style/lib.rs b/tests/unit/style/lib.rs index 56111373e96..d394e69e8c6 100644 --- a/tests/unit/style/lib.rs +++ b/tests/unit/style/lib.rs @@ -23,6 +23,7 @@ mod logical_geometry; mod media_queries; mod parsing; mod properties; +mod selector_matching; mod str; mod stylesheets; mod value; diff --git a/tests/unit/style/selector_matching.rs b/tests/unit/style/selector_matching.rs new file mode 100644 index 00000000000..22e11288c48 --- /dev/null +++ b/tests/unit/style/selector_matching.rs @@ -0,0 +1,103 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +use cssparser::Parser; +use selectors::parser::{LocalName, ParserContext, parse_selector_list}; +use std::sync::Arc; +use string_cache::Atom; +use style::properties::Importance; +use style::selector_matching::{DeclarationBlock, Rule, SelectorMap}; + +/// Helper method to get some Rules from selector strings. +/// Each sublist of the result contains the Rules for one StyleRule. +fn get_mock_rules(css_selectors: &[&str]) -> Vec> { + css_selectors.iter().enumerate().map(|(i, selectors)| { + let context = ParserContext::new(); + parse_selector_list(&context, &mut Parser::new(*selectors)) + .unwrap().into_iter().map(|s| { + Rule { + selector: s.complex_selector.clone(), + declarations: DeclarationBlock { + mixed_declarations: Arc::new(Vec::new()), + importance: Importance::Normal, + specificity: s.specificity, + source_order: i, + } + } + }).collect() + }).collect() +} + +fn get_mock_map(selectors: &[&str]) -> SelectorMap { + let mut map = SelectorMap::new(); + let selector_rules = get_mock_rules(selectors); + + for rules in selector_rules.into_iter() { + for rule in rules.into_iter() { + map.insert(rule) + } + } + + map +} + +#[test] +fn test_rule_ordering_same_specificity() { + let rules_list = get_mock_rules(&["a.intro", "img.sidebar"]); + let a = &rules_list[0][0].declarations; + let b = &rules_list[1][0].declarations; + assert!((a.specificity, a.source_order) < ((b.specificity, b.source_order)), + "The rule that comes later should win."); +} + + +#[test] +fn test_get_id_name() { + let rules_list = get_mock_rules(&[".intro", "#top"]); + assert_eq!(SelectorMap::get_id_name(&rules_list[0][0]), None); + assert_eq!(SelectorMap::get_id_name(&rules_list[1][0]), Some(Atom::from("top"))); +} + +#[test] +fn test_get_class_name() { + let rules_list = get_mock_rules(&[".intro.foo", "#top"]); + assert_eq!(SelectorMap::get_class_name(&rules_list[0][0]), Some(Atom::from("intro"))); + assert_eq!(SelectorMap::get_class_name(&rules_list[1][0]), None); +} + +#[test] +fn test_get_local_name() { + let rules_list = get_mock_rules(&["img.foo", "#top", "IMG", "ImG"]); + let check = |i: usize, names: Option<(&str, &str)>| { + assert!(SelectorMap::get_local_name(&rules_list[i][0]) + == names.map(|(name, lower_name)| LocalName { + name: Atom::from(name), + lower_name: Atom::from(lower_name) })) + }; + check(0, Some(("img", "img"))); + check(1, None); + check(2, Some(("IMG", "img"))); + check(3, Some(("ImG", "img"))); +} + +#[test] +fn test_insert() { + let rules_list = get_mock_rules(&[".intro.foo", "#top"]); + let mut selector_map = SelectorMap::new(); + selector_map.insert(rules_list[1][0].clone()); + assert_eq!(1, selector_map.id_hash.get(&atom!("top")).unwrap()[0].declarations.source_order); + selector_map.insert(rules_list[0][0].clone()); + assert_eq!(0, selector_map.class_hash.get(&Atom::from("intro")).unwrap()[0].declarations.source_order); + assert!(selector_map.class_hash.get(&Atom::from("foo")).is_none()); +} + +#[test] +fn test_get_universal_rules() { + let map = get_mock_map(&["*|*", "#foo > *|*", ".klass", "#id"]); + let mut decls = vec![]; + + map.get_universal_rules(&mut decls); + + assert_eq!(decls.len(), 1); +}