diff options
-rw-r--r-- | components/servo/Cargo.lock | 5 | ||||
-rw-r--r-- | components/style/media_queries.rs | 418 | ||||
-rw-r--r-- | components/style/properties.mako.rs | 9 | ||||
-rw-r--r-- | components/style/stylesheets.rs | 135 | ||||
-rw-r--r-- | tests/unit/Cargo.toml | 15 | ||||
-rw-r--r-- | tests/unit/lib.rs | 9 | ||||
-rw-r--r-- | tests/unit/style/media_queries.rs | 412 | ||||
-rw-r--r-- | tests/unit/style/mod.rs | 12 | ||||
-rw-r--r-- | tests/unit/style/stylesheets.rs | 134 |
9 files changed, 593 insertions, 556 deletions
diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index c9071be89cd..81ea1acb18e 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -926,11 +926,16 @@ name = "unit_tests" version = "0.0.1" dependencies = [ "cookie 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "cssparser 0.2.0 (git+https://github.com/servo/rust-cssparser)", "geom 0.1.0 (git+https://github.com/servo/rust-geom)", "gfx 0.0.1", "net 0.0.1", "net_traits 0.0.1", "profile 0.0.1", + "selectors 0.1.0 (git+https://github.com/servo/rust-selectors)", + "string_cache 0.0.0 (git+https://github.com/servo/string-cache)", + "string_cache_plugin 0.0.0 (git+https://github.com/servo/string-cache)", + "style 0.0.1", "url 0.2.23 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.0.1", ] diff --git a/components/style/media_queries.rs b/components/style/media_queries.rs index 69715b80885..f1eae543c1e 100644 --- a/components/style/media_queries.rs +++ b/components/style/media_queries.rs @@ -13,7 +13,7 @@ use values::specified; #[derive(Debug, PartialEq)] pub struct MediaQueryList { - media_queries: Vec<MediaQuery> + pub media_queries: Vec<MediaQuery> } #[derive(PartialEq, Eq, Copy, Debug)] @@ -71,9 +71,9 @@ pub enum Qualifier { #[derive(Debug, PartialEq)] pub struct MediaQuery { - qualifier: Option<Qualifier>, - media_type: MediaQueryType, - expressions: Vec<Expression>, + pub qualifier: Option<Qualifier>, + pub media_type: MediaQueryType, + pub expressions: Vec<Expression>, } impl MediaQuery { @@ -230,415 +230,5 @@ impl MediaQueryList { #[cfg(test)] mod tests { - use geom::size::TypedSize2D; - use util::geometry::Au; - use stylesheets::{iter_stylesheet_media_rules, iter_stylesheet_style_rules, Stylesheet}; - use stylesheets::Origin; - use super::*; - use url::Url; - use values::specified; - use std::borrow::ToOwned; - fn test_media_rule<F>(css: &str, callback: F) where F: Fn(&MediaQueryList, &str) { - let url = Url::parse("http://localhost").unwrap(); - let stylesheet = Stylesheet::from_str(css, url, Origin::Author); - let mut rule_count: int = 0; - iter_stylesheet_media_rules(&stylesheet, |rule| { - rule_count += 1; - callback(&rule.media_queries, css); - }); - assert!(rule_count > 0); - } - - fn media_query_test(device: &Device, css: &str, expected_rule_count: int) { - let url = Url::parse("http://localhost").unwrap(); - let ss = Stylesheet::from_str(css, url, Origin::Author); - let mut rule_count: int = 0; - iter_stylesheet_style_rules(&ss, device, |_| rule_count += 1); - assert!(rule_count == expected_rule_count, css.to_owned()); - } - - #[test] - fn test_mq_empty() { - test_media_rule("@media { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == None, css.to_owned()); - assert!(q.media_type == MediaQueryType::All, css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - } - - #[test] - fn test_mq_screen() { - test_media_rule("@media screen { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == None, css.to_owned()); - assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media only screen { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Only), css.to_owned()); - assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media not screen { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); - assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - } - - #[test] - fn test_mq_print() { - test_media_rule("@media print { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == None, css.to_owned()); - assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media only print { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Only), css.to_owned()); - assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media not print { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); - assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - } - - #[test] - fn test_mq_unknown() { - test_media_rule("@media fridge { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == None, css.to_owned()); - assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media only glass { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Only), css.to_owned()); - assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media not wood { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); - assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - } - - #[test] - fn test_mq_all() { - test_media_rule("@media all { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == None, css.to_owned()); - assert!(q.media_type == MediaQueryType::All, css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media only all { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Only), css.to_owned()); - assert!(q.media_type == MediaQueryType::All, css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media not all { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); - assert!(q.media_type == MediaQueryType::All, css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - } - - #[test] - fn test_mq_or() { - test_media_rule("@media screen, print { }", |list, css| { - assert!(list.media_queries.len() == 2, css.to_owned()); - let q0 = &list.media_queries[0]; - assert!(q0.qualifier == None, css.to_owned()); - assert!(q0.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned()); - assert!(q0.expressions.len() == 0, css.to_owned()); - - let q1 = &list.media_queries[1]; - assert!(q1.qualifier == None, css.to_owned()); - assert!(q1.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned()); - assert!(q1.expressions.len() == 0, css.to_owned()); - }); - } - - #[test] - fn test_mq_default_expressions() { - test_media_rule("@media (min-width: 100px) { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == None, css.to_owned()); - assert!(q.media_type == MediaQueryType::All, css.to_owned()); - assert!(q.expressions.len() == 1, css.to_owned()); - match q.expressions[0] { - Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))), - _ => panic!("wrong expression type"), - } - }); - - test_media_rule("@media (max-width: 43px) { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == None, css.to_owned()); - assert!(q.media_type == MediaQueryType::All, css.to_owned()); - assert!(q.expressions.len() == 1, css.to_owned()); - match q.expressions[0] { - Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(43))), - _ => panic!("wrong expression type"), - } - }); - } - - #[test] - fn test_mq_expressions() { - test_media_rule("@media screen and (min-width: 100px) { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == None, css.to_owned()); - assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned()); - assert!(q.expressions.len() == 1, css.to_owned()); - match q.expressions[0] { - Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))), - _ => panic!("wrong expression type"), - } - }); - - test_media_rule("@media print and (max-width: 43px) { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == None, css.to_owned()); - assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned()); - assert!(q.expressions.len() == 1, css.to_owned()); - match q.expressions[0] { - Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(43))), - _ => panic!("wrong expression type"), - } - }); - - test_media_rule("@media fridge and (max-width: 52px) { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == None, css.to_owned()); - assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned()); - assert!(q.expressions.len() == 1, css.to_owned()); - match q.expressions[0] { - Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(52))), - _ => panic!("wrong expression type"), - } - }); - } - - #[test] - fn test_mq_multiple_expressions() { - test_media_rule("@media (min-width: 100px) and (max-width: 200px) { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == None, css.to_owned()); - assert!(q.media_type == MediaQueryType::All, css.to_owned()); - assert!(q.expressions.len() == 2, css.to_owned()); - match q.expressions[0] { - Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))), - _ => panic!("wrong expression type"), - } - match q.expressions[1] { - Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(200))), - _ => panic!("wrong expression type"), - } - }); - - test_media_rule("@media not screen and (min-width: 100px) and (max-width: 200px) { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); - assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned()); - assert!(q.expressions.len() == 2, css.to_owned()); - match q.expressions[0] { - Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))), - _ => panic!("wrong expression type"), - } - match q.expressions[1] { - Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(200))), - _ => panic!("wrong expression type"), - } - }); - } - - #[test] - fn test_mq_malformed_expressions() { - test_media_rule("@media (min-width: 100blah) and (max-width: 200px) { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); - assert!(q.media_type == MediaQueryType::All, css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media screen and (height: 200px) { }", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); - assert!(q.media_type == MediaQueryType::All, css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media (min-width: 30em foo bar) {}", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); - assert!(q.media_type == MediaQueryType::All, css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media not {}", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); - assert!(q.media_type == MediaQueryType::All, css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media not (min-width: 300px) {}", |list, css| { - assert!(list.media_queries.len() == 1, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); - assert!(q.media_type == MediaQueryType::All, css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media , {}", |list, css| { - assert!(list.media_queries.len() == 2, css.to_owned()); - let q = &list.media_queries[0]; - assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); - assert!(q.media_type == MediaQueryType::All, css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - let q = &list.media_queries[1]; - assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); - assert!(q.media_type == MediaQueryType::All, css.to_owned()); - assert!(q.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media screen 4px, print {}", |list, css| { - assert!(list.media_queries.len() == 2, css.to_owned()); - let q0 = &list.media_queries[0]; - assert!(q0.qualifier == Some(Qualifier::Not), css.to_owned()); - assert!(q0.media_type == MediaQueryType::All, css.to_owned()); - assert!(q0.expressions.len() == 0, css.to_owned()); - let q1 = &list.media_queries[1]; - assert!(q1.qualifier == None, css.to_owned()); - assert!(q1.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned()); - assert!(q1.expressions.len() == 0, css.to_owned()); - }); - - test_media_rule("@media screen, {}", |list, css| { - assert!(list.media_queries.len() == 2, css.to_owned()); - let q0 = &list.media_queries[0]; - assert!(q0.qualifier == None, css.to_owned()); - assert!(q0.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned()); - assert!(q0.expressions.len() == 0, css.to_owned()); - let q1 = &list.media_queries[1]; - assert!(q1.qualifier == Some(Qualifier::Not), css.to_owned()); - assert!(q1.media_type == MediaQueryType::All, css.to_owned()); - assert!(q1.expressions.len() == 0, css.to_owned()); - }); - } - - #[test] - fn test_matching_simple() { - let device = Device { - media_type: MediaType::Screen, - viewport_size: TypedSize2D(200.0, 100.0), - }; - - media_query_test(&device, "@media not all { a { color: red; } }", 0); - media_query_test(&device, "@media not screen { a { color: red; } }", 0); - media_query_test(&device, "@media not print { a { color: red; } }", 1); - - media_query_test(&device, "@media unknown { a { color: red; } }", 0); - media_query_test(&device, "@media not unknown { a { color: red; } }", 1); - - media_query_test(&device, "@media { a { color: red; } }", 1); - media_query_test(&device, "@media screen { a { color: red; } }", 1); - media_query_test(&device, "@media print { a { color: red; } }", 0); - } - - #[test] - fn test_matching_width() { - let device = Device { - media_type: MediaType::Screen, - viewport_size: TypedSize2D(200.0, 100.0), - }; - - media_query_test(&device, "@media { a { color: red; } }", 1); - - media_query_test(&device, "@media (min-width: 50px) { a { color: red; } }", 1); - media_query_test(&device, "@media (min-width: 150px) { a { color: red; } }", 1); - media_query_test(&device, "@media (min-width: 300px) { a { color: red; } }", 0); - - media_query_test(&device, "@media screen and (min-width: 50px) { a { color: red; } }", 1); - media_query_test(&device, "@media screen and (min-width: 150px) { a { color: red; } }", 1); - media_query_test(&device, "@media screen and (min-width: 300px) { a { color: red; } }", 0); - - media_query_test(&device, "@media not screen and (min-width: 50px) { a { color: red; } }", 0); - media_query_test(&device, "@media not screen and (min-width: 150px) { a { color: red; } }", 0); - media_query_test(&device, "@media not screen and (min-width: 300px) { a { color: red; } }", 1); - - media_query_test(&device, "@media (max-width: 50px) { a { color: red; } }", 0); - media_query_test(&device, "@media (max-width: 150px) { a { color: red; } }", 0); - media_query_test(&device, "@media (max-width: 300px) { a { color: red; } }", 1); - - media_query_test(&device, "@media screen and (min-width: 50px) and (max-width: 100px) { a { color: red; } }", 0); - media_query_test(&device, "@media screen and (min-width: 250px) and (max-width: 300px) { a { color: red; } }", 0); - media_query_test(&device, "@media screen and (min-width: 50px) and (max-width: 250px) { a { color: red; } }", 1); - - media_query_test(&device, "@media not screen and (min-width: 50px) and (max-width: 100px) { a { color: red; } }", 1); - media_query_test(&device, "@media not screen and (min-width: 250px) and (max-width: 300px) { a { color: red; } }", 1); - media_query_test(&device, "@media not screen and (min-width: 50px) and (max-width: 250px) { a { color: red; } }", 0); - - media_query_test(&device, "@media not screen and (min-width: 3.1em) and (max-width: 6em) { a { color: red; } }", 1); - media_query_test(&device, "@media not screen and (min-width: 16em) and (max-width: 19.75em) { a { color: red; } }", 1); - media_query_test(&device, "@media not screen and (min-width: 3em) and (max-width: 250px) { a { color: red; } }", 0); - } - - #[test] - fn test_matching_invalid() { - let device = Device { - media_type: MediaType::Screen, - viewport_size: TypedSize2D(200.0, 100.0), - }; - - media_query_test(&device, "@media fridge { a { color: red; } }", 0); - media_query_test(&device, "@media screen and (height: 100px) { a { color: red; } }", 0); - media_query_test(&device, "@media not print and (width: 100) { a { color: red; } }", 0); - } } diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index 2ec8edee31a..2b2c74a2495 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -4803,7 +4803,7 @@ impl ComputedValues { /// Return a WritingMode bitflags from the relevant CSS properties. -fn get_writing_mode(inheritedbox_style: &style_structs::InheritedBox) -> WritingMode { +pub fn get_writing_mode(inheritedbox_style: &style_structs::InheritedBox) -> WritingMode { use util::logical_geometry; let mut flags = WritingMode::empty(); match inheritedbox_style.direction { @@ -4839,7 +4839,7 @@ fn get_writing_mode(inheritedbox_style: &style_structs::InheritedBox) -> Writing /// The initial values for all style structs as defined by the specification. lazy_static! { - static ref INITIAL_VALUES: ComputedValues = ComputedValues { + pub static ref INITIAL_VALUES: ComputedValues = ComputedValues { % for style_struct in STYLE_STRUCTS: ${style_struct.ident}: Arc::new(style_structs::${style_struct.name} { % for longhand in style_struct.longhands: @@ -4857,11 +4857,6 @@ lazy_static! { } -#[test] -fn initial_writing_mode_is_empty() { - assert_eq!(get_writing_mode(INITIAL_VALUES.get_inheritedbox()), WritingMode::empty()) -} - /// Fast path for the function below. Only computes new inherited styles. #[allow(unused_mut)] fn cascade_with_cached_declarations( diff --git a/components/style/stylesheets.rs b/components/style/stylesheets.rs index 11135ac580e..1bc41a20da1 100644 --- a/components/style/stylesheets.rs +++ b/components/style/stylesheets.rs @@ -31,7 +31,7 @@ pub enum Origin { pub struct Stylesheet { /// List of rules in the order they were found (important for /// cascading order) - rules: Vec<CSSRule>, + pub rules: Vec<CSSRule>, pub origin: Origin, } @@ -322,136 +322,3 @@ pub fn iter_font_face_rules<F>(stylesheet: &Stylesheet, device: &Device, callbac where F: Fn(&Atom, &Source) { iter_font_face_rules_inner(&stylesheet.rules, device, callback) } - - -#[test] -fn test_parse_stylesheet() { - use std::sync::Arc; - use cssparser; - use selectors::parser::*; - use string_cache::Atom; - use properties::{PropertyDeclaration, DeclaredValue, longhands}; - use std::borrow::ToOwned; - - let css = r" - @namespace url(http://www.w3.org/1999/xhtml); - /* FIXME: only if scripting is enabled */ - input[type=hidden i] { display: none !important; } - html , body /**/ { display: block; } - #d1 > .ok { background: blue; } - "; - let url = Url::parse("about::test").unwrap(); - let stylesheet = Stylesheet::from_str(css, url, Origin::UserAgent); - assert_eq!(stylesheet, Stylesheet { - origin: Origin::UserAgent, - rules: vec![ - CSSRule::Namespace(None, ns!(HTML)), - CSSRule::Style(StyleRule { - selectors: vec![ - Selector { - compound_selectors: Arc::new(CompoundSelector { - simple_selectors: vec![ - SimpleSelector::Namespace(ns!(HTML)), - SimpleSelector::LocalName(LocalName { - name: atom!(input), - lower_name: atom!(input), - }), - SimpleSelector::AttrEqual(AttrSelector { - name: atom!(type), - lower_name: atom!(type), - namespace: NamespaceConstraint::Specific(ns!("")), - }, "hidden".to_owned(), CaseSensitivity::CaseInsensitive) - ], - next: None, - }), - pseudo_element: None, - specificity: (0 << 20) + (1 << 10) + (1 << 0), - }, - ], - declarations: PropertyDeclarationBlock { - normal: Arc::new(vec![]), - important: Arc::new(vec![ - PropertyDeclaration::Display(DeclaredValue::SpecifiedValue( - longhands::display::SpecifiedValue::none)), - ]), - }, - }), - CSSRule::Style(StyleRule { - selectors: vec![ - Selector { - compound_selectors: Arc::new(CompoundSelector { - simple_selectors: vec![ - SimpleSelector::Namespace(ns!(HTML)), - SimpleSelector::LocalName(LocalName { - name: atom!(html), - lower_name: atom!(html), - }), - ], - next: None, - }), - pseudo_element: None, - specificity: (0 << 20) + (0 << 10) + (1 << 0), - }, - Selector { - compound_selectors: Arc::new(CompoundSelector { - simple_selectors: vec![ - SimpleSelector::Namespace(ns!(HTML)), - SimpleSelector::LocalName(LocalName { - name: atom!(body), - lower_name: atom!(body), - }), - ], - next: None, - }), - pseudo_element: None, - specificity: (0 << 20) + (0 << 10) + (1 << 0), - }, - ], - declarations: PropertyDeclarationBlock { - normal: Arc::new(vec![ - PropertyDeclaration::Display(DeclaredValue::SpecifiedValue( - longhands::display::SpecifiedValue::block)), - ]), - important: Arc::new(vec![]), - }, - }), - CSSRule::Style(StyleRule { - selectors: vec![ - Selector { - compound_selectors: Arc::new(CompoundSelector { - simple_selectors: vec![ - SimpleSelector::Class(Atom::from_slice("ok")), - ], - next: Some((box CompoundSelector { - simple_selectors: vec![ - SimpleSelector::ID(Atom::from_slice("d1")), - ], - next: None, - }, Combinator::Child)), - }), - pseudo_element: None, - specificity: (1 << 20) + (1 << 10) + (0 << 0), - }, - ], - declarations: PropertyDeclarationBlock { - normal: Arc::new(vec![ - PropertyDeclaration::BackgroundSize(DeclaredValue::Initial), - PropertyDeclaration::BackgroundImage(DeclaredValue::Initial), - PropertyDeclaration::BackgroundAttachment(DeclaredValue::Initial), - PropertyDeclaration::BackgroundRepeat(DeclaredValue::Initial), - PropertyDeclaration::BackgroundPosition(DeclaredValue::Initial), - PropertyDeclaration::BackgroundColor(DeclaredValue::SpecifiedValue( - longhands::background_color::SpecifiedValue { - authored: Some("blue".to_owned()), - parsed: cssparser::Color::RGBA(cssparser::RGBA { - red: 0., green: 0., blue: 1., alpha: 1. - }), - } - )), - ]), - important: Arc::new(vec![]), - }, - }), - ], - }); -} diff --git a/tests/unit/Cargo.toml b/tests/unit/Cargo.toml index 3e8520bbcc2..3a241ecb871 100644 --- a/tests/unit/Cargo.toml +++ b/tests/unit/Cargo.toml @@ -23,9 +23,24 @@ path = "../../components/net_traits" [dependencies.profile] path = "../../components/profile" +[dependencies.style] +path = "../../components/style" + [dependencies.geom] git = "https://github.com/servo/rust-geom" +[dependencies.cssparser] +git = "https://github.com/servo/rust-cssparser" + +[dependencies.selectors] +git = "https://github.com/servo/rust-selectors" + +[dependencies.string_cache] +git = "https://github.com/servo/string-cache" + +[dependencies.string_cache_plugin] +git = "https://github.com/servo/string-cache" + [dependencies] cookie = "*" url = "*" diff --git a/tests/unit/lib.rs b/tests/unit/lib.rs index b697f23d2d9..d0c8c7bc612 100644 --- a/tests/unit/lib.rs +++ b/tests/unit/lib.rs @@ -1,14 +1,21 @@ +#![feature(plugin)] #![cfg_attr(test, feature(net, alloc))] +#![plugin(string_cache_plugin)] + +extern crate cssparser; extern crate geom; extern crate gfx; extern crate net; extern crate net_traits; extern crate profile; +extern crate selectors; +extern crate string_cache; +extern crate style; extern crate util; extern crate url; #[cfg(test)] #[path="gfx/mod.rs"] mod gfx_tests; #[cfg(test)] #[path="net/mod.rs"] mod net_tests; +#[cfg(test)] #[path="style/mod.rs"] mod style_tests; #[cfg(test)] #[path="util/mod.rs"] mod util_tests; - diff --git a/tests/unit/style/media_queries.rs b/tests/unit/style/media_queries.rs new file mode 100644 index 00000000000..15266719d6f --- /dev/null +++ b/tests/unit/style/media_queries.rs @@ -0,0 +1,412 @@ +use geom::size::TypedSize2D; +use style::stylesheets::{iter_stylesheet_media_rules, iter_stylesheet_style_rules, Stylesheet}; +use style::stylesheets::Origin; +use style::media_queries::*; +use style::values::specified; +use std::borrow::ToOwned; +use url::Url; +use util::geometry::Au; + + +fn test_media_rule<F>(css: &str, callback: F) where F: Fn(&MediaQueryList, &str) { + let url = Url::parse("http://localhost").unwrap(); + let stylesheet = Stylesheet::from_str(css, url, Origin::Author); + let mut rule_count = 0; + iter_stylesheet_media_rules(&stylesheet, |rule| { + rule_count += 1; + callback(&rule.media_queries, css); + }); + assert!(rule_count > 0); +} + +fn media_query_test(device: &Device, css: &str, expected_rule_count: u32) { + let url = Url::parse("http://localhost").unwrap(); + let ss = Stylesheet::from_str(css, url, Origin::Author); + let mut rule_count: u32 = 0; + iter_stylesheet_style_rules(&ss, device, |_| rule_count += 1); + assert!(rule_count == expected_rule_count, css.to_owned()); +} + +#[test] +fn test_mq_empty() { + test_media_rule("@media { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == None, css.to_owned()); + assert!(q.media_type == MediaQueryType::All, css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); +} + +#[test] +fn test_mq_screen() { + test_media_rule("@media screen { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == None, css.to_owned()); + assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media only screen { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Only), css.to_owned()); + assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media not screen { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); + assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); +} + +#[test] +fn test_mq_print() { + test_media_rule("@media print { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == None, css.to_owned()); + assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media only print { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Only), css.to_owned()); + assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media not print { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); + assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); +} + +#[test] +fn test_mq_unknown() { + test_media_rule("@media fridge { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == None, css.to_owned()); + assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media only glass { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Only), css.to_owned()); + assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media not wood { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); + assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); +} + +#[test] +fn test_mq_all() { + test_media_rule("@media all { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == None, css.to_owned()); + assert!(q.media_type == MediaQueryType::All, css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media only all { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Only), css.to_owned()); + assert!(q.media_type == MediaQueryType::All, css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media not all { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); + assert!(q.media_type == MediaQueryType::All, css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); +} + +#[test] +fn test_mq_or() { + test_media_rule("@media screen, print { }", |list, css| { + assert!(list.media_queries.len() == 2, css.to_owned()); + let q0 = &list.media_queries[0]; + assert!(q0.qualifier == None, css.to_owned()); + assert!(q0.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned()); + assert!(q0.expressions.len() == 0, css.to_owned()); + + let q1 = &list.media_queries[1]; + assert!(q1.qualifier == None, css.to_owned()); + assert!(q1.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned()); + assert!(q1.expressions.len() == 0, css.to_owned()); + }); +} + +#[test] +fn test_mq_default_expressions() { + test_media_rule("@media (min-width: 100px) { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == None, css.to_owned()); + assert!(q.media_type == MediaQueryType::All, css.to_owned()); + assert!(q.expressions.len() == 1, css.to_owned()); + match q.expressions[0] { + Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))), + _ => panic!("wrong expression type"), + } + }); + + test_media_rule("@media (max-width: 43px) { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == None, css.to_owned()); + assert!(q.media_type == MediaQueryType::All, css.to_owned()); + assert!(q.expressions.len() == 1, css.to_owned()); + match q.expressions[0] { + Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(43))), + _ => panic!("wrong expression type"), + } + }); +} + +#[test] +fn test_mq_expressions() { + test_media_rule("@media screen and (min-width: 100px) { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == None, css.to_owned()); + assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned()); + assert!(q.expressions.len() == 1, css.to_owned()); + match q.expressions[0] { + Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))), + _ => panic!("wrong expression type"), + } + }); + + test_media_rule("@media print and (max-width: 43px) { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == None, css.to_owned()); + assert!(q.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned()); + assert!(q.expressions.len() == 1, css.to_owned()); + match q.expressions[0] { + Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(43))), + _ => panic!("wrong expression type"), + } + }); + + test_media_rule("@media fridge and (max-width: 52px) { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == None, css.to_owned()); + assert!(q.media_type == MediaQueryType::MediaType(MediaType::Unknown), css.to_owned()); + assert!(q.expressions.len() == 1, css.to_owned()); + match q.expressions[0] { + Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(52))), + _ => panic!("wrong expression type"), + } + }); +} + +#[test] +fn test_mq_multiple_expressions() { + test_media_rule("@media (min-width: 100px) and (max-width: 200px) { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == None, css.to_owned()); + assert!(q.media_type == MediaQueryType::All, css.to_owned()); + assert!(q.expressions.len() == 2, css.to_owned()); + match q.expressions[0] { + Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))), + _ => panic!("wrong expression type"), + } + match q.expressions[1] { + Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(200))), + _ => panic!("wrong expression type"), + } + }); + + test_media_rule("@media not screen and (min-width: 100px) and (max-width: 200px) { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); + assert!(q.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned()); + assert!(q.expressions.len() == 2, css.to_owned()); + match q.expressions[0] { + Expression::Width(Range::Min(w)) => assert!(w == specified::Length::Absolute(Au::from_px(100))), + _ => panic!("wrong expression type"), + } + match q.expressions[1] { + Expression::Width(Range::Max(w)) => assert!(w == specified::Length::Absolute(Au::from_px(200))), + _ => panic!("wrong expression type"), + } + }); +} + +#[test] +fn test_mq_malformed_expressions() { + test_media_rule("@media (min-width: 100blah) and (max-width: 200px) { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); + assert!(q.media_type == MediaQueryType::All, css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media screen and (height: 200px) { }", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); + assert!(q.media_type == MediaQueryType::All, css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media (min-width: 30em foo bar) {}", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); + assert!(q.media_type == MediaQueryType::All, css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media not {}", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); + assert!(q.media_type == MediaQueryType::All, css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media not (min-width: 300px) {}", |list, css| { + assert!(list.media_queries.len() == 1, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); + assert!(q.media_type == MediaQueryType::All, css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media , {}", |list, css| { + assert!(list.media_queries.len() == 2, css.to_owned()); + let q = &list.media_queries[0]; + assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); + assert!(q.media_type == MediaQueryType::All, css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + let q = &list.media_queries[1]; + assert!(q.qualifier == Some(Qualifier::Not), css.to_owned()); + assert!(q.media_type == MediaQueryType::All, css.to_owned()); + assert!(q.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media screen 4px, print {}", |list, css| { + assert!(list.media_queries.len() == 2, css.to_owned()); + let q0 = &list.media_queries[0]; + assert!(q0.qualifier == Some(Qualifier::Not), css.to_owned()); + assert!(q0.media_type == MediaQueryType::All, css.to_owned()); + assert!(q0.expressions.len() == 0, css.to_owned()); + let q1 = &list.media_queries[1]; + assert!(q1.qualifier == None, css.to_owned()); + assert!(q1.media_type == MediaQueryType::MediaType(MediaType::Print), css.to_owned()); + assert!(q1.expressions.len() == 0, css.to_owned()); + }); + + test_media_rule("@media screen, {}", |list, css| { + assert!(list.media_queries.len() == 2, css.to_owned()); + let q0 = &list.media_queries[0]; + assert!(q0.qualifier == None, css.to_owned()); + assert!(q0.media_type == MediaQueryType::MediaType(MediaType::Screen), css.to_owned()); + assert!(q0.expressions.len() == 0, css.to_owned()); + let q1 = &list.media_queries[1]; + assert!(q1.qualifier == Some(Qualifier::Not), css.to_owned()); + assert!(q1.media_type == MediaQueryType::All, css.to_owned()); + assert!(q1.expressions.len() == 0, css.to_owned()); + }); +} + +#[test] +fn test_matching_simple() { + let device = Device { + media_type: MediaType::Screen, + viewport_size: TypedSize2D(200.0, 100.0), + }; + + media_query_test(&device, "@media not all { a { color: red; } }", 0); + media_query_test(&device, "@media not screen { a { color: red; } }", 0); + media_query_test(&device, "@media not print { a { color: red; } }", 1); + + media_query_test(&device, "@media unknown { a { color: red; } }", 0); + media_query_test(&device, "@media not unknown { a { color: red; } }", 1); + + media_query_test(&device, "@media { a { color: red; } }", 1); + media_query_test(&device, "@media screen { a { color: red; } }", 1); + media_query_test(&device, "@media print { a { color: red; } }", 0); +} + +#[test] +fn test_matching_width() { + let device = Device { + media_type: MediaType::Screen, + viewport_size: TypedSize2D(200.0, 100.0), + }; + + media_query_test(&device, "@media { a { color: red; } }", 1); + + media_query_test(&device, "@media (min-width: 50px) { a { color: red; } }", 1); + media_query_test(&device, "@media (min-width: 150px) { a { color: red; } }", 1); + media_query_test(&device, "@media (min-width: 300px) { a { color: red; } }", 0); + + media_query_test(&device, "@media screen and (min-width: 50px) { a { color: red; } }", 1); + media_query_test(&device, "@media screen and (min-width: 150px) { a { color: red; } }", 1); + media_query_test(&device, "@media screen and (min-width: 300px) { a { color: red; } }", 0); + + media_query_test(&device, "@media not screen and (min-width: 50px) { a { color: red; } }", 0); + media_query_test(&device, "@media not screen and (min-width: 150px) { a { color: red; } }", 0); + media_query_test(&device, "@media not screen and (min-width: 300px) { a { color: red; } }", 1); + + media_query_test(&device, "@media (max-width: 50px) { a { color: red; } }", 0); + media_query_test(&device, "@media (max-width: 150px) { a { color: red; } }", 0); + media_query_test(&device, "@media (max-width: 300px) { a { color: red; } }", 1); + + media_query_test(&device, "@media screen and (min-width: 50px) and (max-width: 100px) { a { color: red; } }", 0); + media_query_test(&device, "@media screen and (min-width: 250px) and (max-width: 300px) { a { color: red; } }", 0); + media_query_test(&device, "@media screen and (min-width: 50px) and (max-width: 250px) { a { color: red; } }", 1); + + media_query_test(&device, "@media not screen and (min-width: 50px) and (max-width: 100px) { a { color: red; } }", 1); + media_query_test(&device, "@media not screen and (min-width: 250px) and (max-width: 300px) { a { color: red; } }", 1); + media_query_test(&device, "@media not screen and (min-width: 50px) and (max-width: 250px) { a { color: red; } }", 0); + + media_query_test(&device, "@media not screen and (min-width: 3.1em) and (max-width: 6em) { a { color: red; } }", 1); + media_query_test(&device, "@media not screen and (min-width: 16em) and (max-width: 19.75em) { a { color: red; } }", 1); + media_query_test(&device, "@media not screen and (min-width: 3em) and (max-width: 250px) { a { color: red; } }", 0); +} + +#[test] +fn test_matching_invalid() { + let device = Device { + media_type: MediaType::Screen, + viewport_size: TypedSize2D(200.0, 100.0), + }; + + media_query_test(&device, "@media fridge { a { color: red; } }", 0); + media_query_test(&device, "@media screen and (height: 100px) { a { color: red; } }", 0); + media_query_test(&device, "@media not print and (width: 100) { a { color: red; } }", 0); +} diff --git a/tests/unit/style/mod.rs b/tests/unit/style/mod.rs new file mode 100644 index 00000000000..3d180b52d1a --- /dev/null +++ b/tests/unit/style/mod.rs @@ -0,0 +1,12 @@ +use util::logical_geometry::WritingMode; +use style::properties::{INITIAL_VALUES, get_writing_mode}; + + +mod stylesheets; +mod media_queries; + + +#[test] +fn initial_writing_mode_is_empty() { + assert_eq!(get_writing_mode(INITIAL_VALUES.get_inheritedbox()), WritingMode::empty()) +} diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs new file mode 100644 index 00000000000..9d40adde60e --- /dev/null +++ b/tests/unit/style/stylesheets.rs @@ -0,0 +1,134 @@ +use std::borrow::ToOwned; +use std::sync::Arc; +use cssparser; +use selectors::parser::*; +use string_cache::Atom; +use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, DeclaredValue, longhands}; +use style::stylesheets::{CSSRule, StyleRule, Origin, Stylesheet}; +use url::Url; + + +#[test] +fn test_parse_stylesheet() { + let css = r" + @namespace url(http://www.w3.org/1999/xhtml); + /* FIXME: only if scripting is enabled */ + input[type=hidden i] { display: none !important; } + html , body /**/ { display: block; } + #d1 > .ok { background: blue; } + "; + let url = Url::parse("about::test").unwrap(); + let stylesheet = Stylesheet::from_str(css, url, Origin::UserAgent); + assert_eq!(stylesheet, Stylesheet { + origin: Origin::UserAgent, + rules: vec![ + CSSRule::Namespace(None, ns!(HTML)), + CSSRule::Style(StyleRule { + selectors: vec![ + Selector { + compound_selectors: Arc::new(CompoundSelector { + simple_selectors: vec![ + SimpleSelector::Namespace(ns!(HTML)), + SimpleSelector::LocalName(LocalName { + name: atom!(input), + lower_name: atom!(input), + }), + SimpleSelector::AttrEqual(AttrSelector { + name: atom!(type), + lower_name: atom!(type), + namespace: NamespaceConstraint::Specific(ns!("")), + }, "hidden".to_owned(), CaseSensitivity::CaseInsensitive) + ], + next: None, + }), + pseudo_element: None, + specificity: (0 << 20) + (1 << 10) + (1 << 0), + }, + ], + declarations: PropertyDeclarationBlock { + normal: Arc::new(vec![]), + important: Arc::new(vec![ + PropertyDeclaration::Display(DeclaredValue::SpecifiedValue( + longhands::display::SpecifiedValue::none)), + ]), + }, + }), + CSSRule::Style(StyleRule { + selectors: vec![ + Selector { + compound_selectors: Arc::new(CompoundSelector { + simple_selectors: vec![ + SimpleSelector::Namespace(ns!(HTML)), + SimpleSelector::LocalName(LocalName { + name: atom!(html), + lower_name: atom!(html), + }), + ], + next: None, + }), + pseudo_element: None, + specificity: (0 << 20) + (0 << 10) + (1 << 0), + }, + Selector { + compound_selectors: Arc::new(CompoundSelector { + simple_selectors: vec![ + SimpleSelector::Namespace(ns!(HTML)), + SimpleSelector::LocalName(LocalName { + name: atom!(body), + lower_name: atom!(body), + }), + ], + next: None, + }), + pseudo_element: None, + specificity: (0 << 20) + (0 << 10) + (1 << 0), + }, + ], + declarations: PropertyDeclarationBlock { + normal: Arc::new(vec![ + PropertyDeclaration::Display(DeclaredValue::SpecifiedValue( + longhands::display::SpecifiedValue::block)), + ]), + important: Arc::new(vec![]), + }, + }), + CSSRule::Style(StyleRule { + selectors: vec![ + Selector { + compound_selectors: Arc::new(CompoundSelector { + simple_selectors: vec![ + SimpleSelector::Class(Atom::from_slice("ok")), + ], + next: Some((Box::new(CompoundSelector { + simple_selectors: vec![ + SimpleSelector::ID(Atom::from_slice("d1")), + ], + next: None, + }), Combinator::Child)), + }), + pseudo_element: None, + specificity: (1 << 20) + (1 << 10) + (0 << 0), + }, + ], + declarations: PropertyDeclarationBlock { + normal: Arc::new(vec![ + PropertyDeclaration::BackgroundSize(DeclaredValue::Initial), + PropertyDeclaration::BackgroundImage(DeclaredValue::Initial), + PropertyDeclaration::BackgroundAttachment(DeclaredValue::Initial), + PropertyDeclaration::BackgroundRepeat(DeclaredValue::Initial), + PropertyDeclaration::BackgroundPosition(DeclaredValue::Initial), + PropertyDeclaration::BackgroundColor(DeclaredValue::SpecifiedValue( + longhands::background_color::SpecifiedValue { + authored: Some("blue".to_owned()), + parsed: cssparser::Color::RGBA(cssparser::RGBA { + red: 0., green: 0., blue: 1., alpha: 1. + }), + } + )), + ]), + important: Arc::new(vec![]), + }, + }), + ], + }); +} |