aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/servo/Cargo.lock5
-rw-r--r--components/style/media_queries.rs418
-rw-r--r--components/style/properties.mako.rs9
-rw-r--r--components/style/stylesheets.rs135
-rw-r--r--tests/unit/Cargo.toml15
-rw-r--r--tests/unit/lib.rs9
-rw-r--r--tests/unit/style/media_queries.rs412
-rw-r--r--tests/unit/style/mod.rs12
-rw-r--r--tests/unit/style/stylesheets.rs134
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![]),
+ },
+ }),
+ ],
+ });
+}