Bug 1329088 - Centralize ParserContext for tests. r=emilio draft
authorJ. Ryan Stinnett <jryans@gmail.com>
Thu, 13 Apr 2017 14:53:59 +0800
changeset 562648 4e9f177f0a836b97d8c4667524b946f3f53a274d
parent 561690 aca6b2a5a2ab3338436c9e819dc2244a022b6425
child 562649 b7402ee4d5cb7840410428a593fe3d83341e4a64
push id54069
push userbmo:jryans@gmail.com
push dateFri, 14 Apr 2017 04:32:08 +0000
reviewersemilio
bugs1329088
milestone55.0a1
Bug 1329088 - Centralize ParserContext for tests. r=emilio To simplify adding additional data to `ParserContext`, this moves test usages to a few shared locations, instead of being spread across many tests. MozReview-Commit-ID: 1OahV797eq
servo/tests/unit/style/lib.rs
servo/tests/unit/style/parsing/animation.rs
servo/tests/unit/style/parsing/background.rs
servo/tests/unit/style/parsing/basic_shape.rs
servo/tests/unit/style/parsing/border.rs
servo/tests/unit/style/parsing/box_.rs
servo/tests/unit/style/parsing/column.rs
servo/tests/unit/style/parsing/containment.rs
servo/tests/unit/style/parsing/effects.rs
servo/tests/unit/style/parsing/font.rs
servo/tests/unit/style/parsing/image.rs
servo/tests/unit/style/parsing/inherited_box.rs
servo/tests/unit/style/parsing/inherited_text.rs
servo/tests/unit/style/parsing/mask.rs
servo/tests/unit/style/parsing/mod.rs
servo/tests/unit/style/parsing/outline.rs
servo/tests/unit/style/parsing/position.rs
servo/tests/unit/style/parsing/selectors.rs
servo/tests/unit/style/parsing/text.rs
servo/tests/unit/style/parsing/text_overflow.rs
servo/tests/unit/style/parsing/transition_timing_function.rs
servo/tests/unit/style/parsing/ui.rs
servo/tests/unit/style/parsing/value.rs
servo/tests/unit/style/properties/background.rs
servo/tests/unit/style/properties/mod.rs
servo/tests/unit/style/properties/serialization.rs
servo/tests/unit/style/value.rs
--- a/servo/tests/unit/style/lib.rs
+++ b/servo/tests/unit/style/lib.rs
@@ -27,17 +27,16 @@ mod logical_geometry;
 mod media_queries;
 mod parsing;
 mod properties;
 mod rule_tree;
 mod size_of;
 mod str;
 mod stylesheets;
 mod stylist;
-mod value;
 mod viewport;
 
 mod writing_modes {
     use style::logical_geometry::WritingMode;
     use style::properties::{INITIAL_SERVO_VALUES, get_writing_mode};
 
     #[test]
     fn initial_writing_mode_is_empty() {
--- a/servo/tests/unit/style/parsing/animation.rs
+++ b/servo/tests/unit/style/parsing/animation.rs
@@ -1,20 +1,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
 use parsing::parse;
 use servo_atoms::Atom;
-use style::parser::{Parse, ParserContext};
+use style::parser::Parse;
 use style::properties::longhands::animation_iteration_count::single_value::computed_value::T as AnimationIterationCount;
 use style::properties::longhands::animation_name;
-use style::stylesheets::{CssRuleType, Origin};
 use style_traits::ToCss;
 
 #[test]
 fn test_animation_name() {
     use self::animation_name::single_value::SpecifiedValue as SingleValue;
     let other_name = Atom::from("other-name");
     assert_eq!(parse_longhand!(animation_name, "none"),
                animation_name::SpecifiedValue(vec![SingleValue(atom!(""))]));
--- a/servo/tests/unit/style/parsing/background.rs
+++ b/servo/tests/unit/style/parsing/background.rs
@@ -1,135 +1,104 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
-use servo_url::ServoUrl;
-use style::parser::ParserContext;
+use parsing::parse;
 use style::properties::longhands::{background_attachment, background_clip, background_color, background_image};
 use style::properties::longhands::{background_origin, background_position_x, background_position_y, background_repeat};
 use style::properties::longhands::background_size;
 use style::properties::shorthands::background;
-use style::stylesheets::{CssRuleType, Origin};
 
 #[test]
 fn background_shorthand_should_parse_all_available_properties_when_specified() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("url(\"http://servo/test.png\") top center / 200px 200px repeat-x fixed padding-box \
-        content-box red");
-    let result = background::parse_value(&context, &mut parser).unwrap();
+    let input = "url(\"http://servo/test.png\") top center / 200px 200px repeat-x fixed padding-box content-box red";
+    let result = parse(background::parse_value, input).unwrap();
 
     assert_eq!(result.background_image, parse_longhand!(background_image, "url(\"http://servo/test.png\")"));
     assert_eq!(result.background_position_x, parse_longhand!(background_position_x, "center"));
     assert_eq!(result.background_position_y, parse_longhand!(background_position_y, "top"));
     assert_eq!(result.background_size, parse_longhand!(background_size, "200px 200px"));
     assert_eq!(result.background_repeat, parse_longhand!(background_repeat, "repeat-x"));
     assert_eq!(result.background_attachment, parse_longhand!(background_attachment, "fixed"));
     assert_eq!(result.background_origin, parse_longhand!(background_origin, "padding-box"));
     assert_eq!(result.background_clip, parse_longhand!(background_clip, "content-box"));
     assert_eq!(result.background_color, parse_longhand!(background_color, "red"));
 }
 
 #[test]
 fn background_shorthand_should_parse_when_some_fields_set() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("14px 40px repeat-y");
-    let result = background::parse_value(&context, &mut parser).unwrap();
+    let result = parse(background::parse_value, "14px 40px repeat-y").unwrap();
 
     assert_eq!(result.background_position_x, parse_longhand!(background_position_x, "14px"));
     assert_eq!(result.background_position_y, parse_longhand!(background_position_y, "40px"));
     assert_eq!(result.background_repeat, parse_longhand!(background_repeat, "repeat-y"));
 
-    let mut parser = Parser::new("url(\"http://servo/test.png\") repeat blue");
-    let result = background::parse_value(&context, &mut parser).unwrap();
+    let result = parse(background::parse_value, "url(\"http://servo/test.png\") repeat blue").unwrap();
 
     assert_eq!(result.background_image, parse_longhand!(background_image, "url(\"http://servo/test.png\")"));
     assert_eq!(result.background_repeat, parse_longhand!(background_repeat, "repeat"));
     assert_eq!(result.background_color, parse_longhand!(background_color, "blue"));
 
-    let mut parser = Parser::new("padding-box");
-    let result = background::parse_value(&context, &mut parser).unwrap();
+    let result = parse(background::parse_value, "padding-box").unwrap();
 
     assert_eq!(result.background_origin, parse_longhand!(background_origin, "padding-box"));
     assert_eq!(result.background_clip, parse_longhand!(background_clip, "padding-box"));
 
-    let mut parser = Parser::new("url(\"http://servo/test.png\")");
-    let result = background::parse_value(&context, &mut parser).unwrap();
+    let result = parse(background::parse_value, "url(\"http://servo/test.png\")").unwrap();
 
     assert_eq!(result.background_image, parse_longhand!(background_image, "url(\"http://servo/test.png\")"));
 }
 
 #[test]
 fn background_shorthand_should_parse_comma_separated_declarations() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("url(\"http://servo/test.png\") top left no-repeat, url(\"http://servo/test.png\") \
-        center / 100% 100% no-repeat, white");
-    let result = background::parse_value(&context, &mut parser).unwrap();
+    let input = "url(\"http://servo/test.png\") top left no-repeat, url(\"http://servo/test.png\") \
+        center / 100% 100% no-repeat, white";
+    let result = parse(background::parse_value, input).unwrap();
 
     assert_eq!(result.background_image, parse_longhand!(background_image, "url(\"http://servo/test.png\"), \
         url(\"http://servo/test.png\"), none"));
     assert_eq!(result.background_position_x, parse_longhand!(background_position_x, "left, center, 0%"));
     assert_eq!(result.background_position_y, parse_longhand!(background_position_y, "top, center, 0%"));
     assert_eq!(result.background_repeat, parse_longhand!(background_repeat, "no-repeat, no-repeat, repeat"));
     assert_eq!(result.background_clip, parse_longhand!(background_clip, "border-box, border-box, border-box"));
     assert_eq!(result.background_origin, parse_longhand!(background_origin, "padding-box, padding-box, \
         padding-box"));
     assert_eq!(result.background_size, parse_longhand!(background_size, "auto auto, 100% 100%, auto auto"));
     assert_eq!(result.background_attachment, parse_longhand!(background_attachment, "scroll, scroll, scroll"));
     assert_eq!(result.background_color, parse_longhand!(background_color, "white"));
 }
 
 #[test]
 fn background_shorthand_should_parse_position_and_size_correctly() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("7px 4px");
-    let result = background::parse_value(&context, &mut parser).unwrap();
+    let result = parse(background::parse_value, "7px 4px").unwrap();
 
     assert_eq!(result.background_position_x, parse_longhand!(background_position_x, "7px"));
     assert_eq!(result.background_position_y, parse_longhand!(background_position_y, "4px"));
 
-    let mut parser = Parser::new("7px 4px / 30px 20px");
-    let result = background::parse_value(&context, &mut parser).unwrap();
+    let result = parse(background::parse_value, "7px 4px / 30px 20px").unwrap();
 
     assert_eq!(result.background_position_x, parse_longhand!(background_position_x, "7px"));
     assert_eq!(result.background_position_y, parse_longhand!(background_position_y, "4px"));
     assert_eq!(result.background_size, parse_longhand!(background_size, "30px 20px"));
 
-    let mut parser = Parser::new("/ 30px 20px");
-    assert!(background::parse_value(&context, &mut parser).is_err());
+    assert!(parse(background::parse_value, "/ 30px 20px").is_err());
 
-    let mut parser = Parser::new("repeat-x / 30px 20px");
-    assert!(background::parse_value(&context, &mut parser).is_err());
+    assert!(parse(background::parse_value, "repeat-x / 30px 20px").is_err());
 }
 
 #[test]
 fn background_shorthand_should_parse_origin_and_clip_correctly() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("padding-box content-box");
-    let result = background::parse_value(&context, &mut parser).unwrap();
+    let result = parse(background::parse_value, "padding-box content-box").unwrap();
 
     assert_eq!(result.background_origin, parse_longhand!(background_origin, "padding-box"));
     assert_eq!(result.background_clip, parse_longhand!(background_clip, "content-box"));
 
-    let mut parser = Parser::new("padding-box padding-box");
-    let result = background::parse_value(&context, &mut parser).unwrap();
+    let result = parse(background::parse_value, "padding-box padding-box").unwrap();
 
     assert_eq!(result.background_origin, parse_longhand!(background_origin, "padding-box"));
     assert_eq!(result.background_clip, parse_longhand!(background_clip, "padding-box"));
 
-    let mut parser = Parser::new("padding-box");
-    let result = background::parse_value(&context, &mut parser).unwrap();
+    let result = parse(background::parse_value, "padding-box").unwrap();
 
     assert_eq!(result.background_origin, parse_longhand!(background_origin, "padding-box"));
     assert_eq!(result.background_clip, parse_longhand!(background_clip, "padding-box"));
 }
--- a/servo/tests/unit/style/parsing/basic_shape.rs
+++ b/servo/tests/unit/style/parsing/basic_shape.rs
@@ -1,17 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
 use parsing::parse;
-use style::parser::{Parse, ParserContext};
-use style::stylesheets::{CssRuleType, Origin};
+use style::parser::Parse;
 use style::values::specified::basic_shape::*;
 use style_traits::ToCss;
 
 // Ensure that basic-shape sub-functions parse as both basic shapes
 // and their individual components
 macro_rules! assert_roundtrip_basicshape {
     ($fun:expr, $input:expr, $output:expr) => {
         assert_roundtrip_with_context!($fun, $input, $output);
--- a/servo/tests/unit/style/parsing/border.rs
+++ b/servo/tests/unit/style/parsing/border.rs
@@ -1,140 +1,104 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
-use servo_url::ServoUrl;
-use style::parser::{ParserContext, Parse};
+use parsing::parse;
+use style::parser::Parse;
 use style::properties::longhands::{border_image_outset, border_image_repeat, border_image_slice};
 use style::properties::longhands::{border_image_source, border_image_width};
 use style::properties::shorthands::border_image;
-use style::stylesheets::{CssRuleType, Origin};
 use style_traits::ToCss;
 
 #[test]
 fn border_image_shorthand_should_parse_when_all_properties_specified() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("linear-gradient(red, blue) 30 30% 45 fill / 20px 40px / 10px \
-                                 round stretch");
-    let result = border_image::parse_value(&context, &mut parser).unwrap();
+    let input = "linear-gradient(red, blue) 30 30% 45 fill / 20px 40px / 10px round stretch";
+    let result = parse(border_image::parse_value, input).unwrap();
 
     assert_eq!(result.border_image_source,
                parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
     assert_eq!(result.border_image_slice, parse_longhand!(border_image_slice, "30 30% 45 fill"));
     assert_eq!(result.border_image_width, parse_longhand!(border_image_width, "20px 40px"));
     assert_eq!(result.border_image_outset, parse_longhand!(border_image_outset, "10px"));
     assert_eq!(result.border_image_repeat, parse_longhand!(border_image_repeat, "round stretch"));
 }
 
 #[test]
 fn border_image_shorthand_should_parse_without_width() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("linear-gradient(red, blue) 30 30% 45 fill / / 10px round stretch");
-    let result = border_image::parse_value(&context, &mut parser).unwrap();
+    let input = "linear-gradient(red, blue) 30 30% 45 fill / / 10px round stretch";
+    let result = parse(border_image::parse_value, input).unwrap();
 
     assert_eq!(result.border_image_source,
                parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
     assert_eq!(result.border_image_slice, parse_longhand!(border_image_slice, "30 30% 45 fill"));
     assert_eq!(result.border_image_outset, parse_longhand!(border_image_outset, "10px"));
     assert_eq!(result.border_image_repeat, parse_longhand!(border_image_repeat, "round stretch"));
     assert_eq!(result.border_image_width, border_image_width::get_initial_specified_value());
 }
 
 #[test]
 fn border_image_shorthand_should_parse_without_outset() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("linear-gradient(red, blue) 30 30% 45 fill / 20px 40px round");
-    let result = border_image::parse_value(&context, &mut parser).unwrap();
+    let input = "linear-gradient(red, blue) 30 30% 45 fill / 20px 40px round";
+    let result = parse(border_image::parse_value, input).unwrap();
 
     assert_eq!(result.border_image_source,
                parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
     assert_eq!(result.border_image_slice, parse_longhand!(border_image_slice, "30 30% 45 fill"));
     assert_eq!(result.border_image_width, parse_longhand!(border_image_width, "20px 40px"));
     assert_eq!(result.border_image_repeat, parse_longhand!(border_image_repeat, "round"));
     assert_eq!(result.border_image_outset, border_image_outset::get_initial_specified_value());
 }
 
 #[test]
 fn border_image_shorthand_should_parse_without_width_or_outset() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("linear-gradient(red, blue) 30 30% 45 fill round");
-    let result = border_image::parse_value(&context, &mut parser).unwrap();
+    let input = "linear-gradient(red, blue) 30 30% 45 fill round";
+    let result = parse(border_image::parse_value, input).unwrap();
 
     assert_eq!(result.border_image_source,
                parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
     assert_eq!(result.border_image_slice, parse_longhand!(border_image_slice, "30 30% 45 fill"));
     assert_eq!(result.border_image_repeat, parse_longhand!(border_image_repeat, "round"));
     assert_eq!(result.border_image_width, border_image_width::get_initial_specified_value());
     assert_eq!(result.border_image_outset, border_image_outset::get_initial_specified_value());
 }
 
 #[test]
 fn border_image_shorthand_should_parse_with_just_source() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("linear-gradient(red, blue)");
-    let result = border_image::parse_value(&context, &mut parser).unwrap();
+    let result = parse(border_image::parse_value, "linear-gradient(red, blue)").unwrap();
 
     assert_eq!(result.border_image_source,
                parse_longhand!(border_image_source, "linear-gradient(red, blue)"));
     assert_eq!(result.border_image_slice, border_image_slice::get_initial_specified_value());
     assert_eq!(result.border_image_width, border_image_width::get_initial_specified_value());
     assert_eq!(result.border_image_outset, border_image_outset::get_initial_specified_value());
     assert_eq!(result.border_image_repeat, border_image_repeat::get_initial_specified_value());
 }
 
 #[test]
 fn border_image_outset_should_error_on_negative_length() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("-1em");
-    let result = border_image_outset::parse(&context, &mut parser);
+    let result = parse(border_image_outset::parse, "-1em");
     assert_eq!(result, Err(()));
 }
 
 #[test]
 fn border_image_outset_should_error_on_negative_number() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("-15");
-    let result = border_image_outset::parse(&context, &mut parser);
+    let result = parse(border_image_outset::parse, "-15");
     assert_eq!(result, Err(()));
 }
 
 #[test]
 fn border_image_outset_should_return_number_on_plain_zero() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("0");
-    let result = border_image_outset::parse(&context, &mut parser);
+    let result = parse(border_image_outset::parse, "0");
     assert_eq!(result.unwrap(), parse_longhand!(border_image_outset, "0"));
 }
 
 #[test]
 fn border_image_outset_should_return_length_on_length_zero() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("0em");
-    let result = border_image_outset::parse(&context, &mut parser);
+    let result = parse(border_image_outset::parse, "0em");
     assert_eq!(result.unwrap(), parse_longhand!(border_image_outset, "0em"));
 }
 
 #[test]
 fn test_border_style() {
     use style::values::specified::BorderStyle;
 
     assert_roundtrip_with_context!(BorderStyle::parse, r#"none"#);
@@ -148,12 +112,12 @@ fn test_border_style() {
     assert_roundtrip_with_context!(BorderStyle::parse, r#"inset"#);
     assert_roundtrip_with_context!(BorderStyle::parse, r#"outset"#);
 }
 
 #[test]
 fn test_border_spacing() {
     use style::properties::longhands::border_spacing;
 
-    assert_parser_exhausted!(border_spacing, "1px rubbish", false);
-    assert_parser_exhausted!(border_spacing, "1px", true);
-    assert_parser_exhausted!(border_spacing, "1px 2px", true);
+    assert_parser_exhausted!(border_spacing::parse, "1px rubbish", false);
+    assert_parser_exhausted!(border_spacing::parse, "1px", true);
+    assert_parser_exhausted!(border_spacing::parse, "1px 2px", true);
 }
--- a/servo/tests/unit/style/parsing/box_.rs
+++ b/servo/tests/unit/style/parsing/box_.rs
@@ -1,17 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
 use parsing::parse;
-use style::parser::ParserContext;
-use style::stylesheets::{CssRuleType, Origin};
 use style_traits::ToCss;
 
 #[test]
 fn test_will_change() {
     use style::properties::longhands::will_change;
 
     assert_roundtrip_with_context!(will_change::parse, "auto");
     assert_roundtrip_with_context!(will_change::parse, "scroll-position");
--- a/servo/tests/unit/style/parsing/column.rs
+++ b/servo/tests/unit/style/parsing/column.rs
@@ -1,44 +1,30 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
-use servo_url::ServoUrl;
-use style::parser::ParserContext;
-use style::stylesheets::{CssRuleType, Origin};
+use parsing::parse;
 use style_traits::ToCss;
 
 #[test]
 fn test_column_width() {
     use style::properties::longhands::column_width;
 
     assert_roundtrip_with_context!(column_width::parse, "auto");
     assert_roundtrip_with_context!(column_width::parse, "6px");
     assert_roundtrip_with_context!(column_width::parse, "2.5em");
     assert_roundtrip_with_context!(column_width::parse, "0.3vw");
 
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-
-    let mut negative = Parser::new("-6px");
-    assert!(column_width::parse(&context, &mut negative).is_err());
+    assert!(parse(column_width::parse, "-6px").is_err());
 }
 
 #[test]
 fn test_column_gap() {
     use style::properties::longhands::column_gap;
 
     assert_roundtrip_with_context!(column_gap::parse, "normal");
     assert_roundtrip_with_context!(column_gap::parse, "6px");
     assert_roundtrip_with_context!(column_gap::parse, "2.5em");
     assert_roundtrip_with_context!(column_gap::parse, "0.3vw");
 
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-
-    let mut negative = Parser::new("-6px");
-    assert!(column_gap::parse(&context, &mut negative).is_err());
+    assert!(parse(column_gap::parse, "-6px").is_err());
 }
--- a/servo/tests/unit/style/parsing/containment.rs
+++ b/servo/tests/unit/style/parsing/containment.rs
@@ -1,26 +1,23 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
-use style::parser::ParserContext;
-use style::stylesheets::{CssRuleType, Origin};
+use parsing::parse;
 
 #[test]
 fn contain_longhand_should_parse_correctly() {
     use style::properties::longhands::contain;
     use style::properties::longhands::contain::SpecifiedValue;
 
     let none = parse_longhand!(contain, "none");
     assert_eq!(none, SpecifiedValue::empty());
 
     let strict = parse_longhand!(contain, "strict");
     assert_eq!(strict, contain::STRICT);
 
     let style_paint = parse_longhand!(contain, "style paint");
     assert_eq!(style_paint, contain::STYLE | contain::PAINT);
 
     // Assert that the `2px` is not consumed, which would trigger parsing failure in real use
-    assert_parser_exhausted!(contain, "layout 2px", false);
+    assert_parser_exhausted!(contain::parse, "layout 2px", false);
 }
--- a/servo/tests/unit/style/parsing/effects.rs
+++ b/servo/tests/unit/style/parsing/effects.rs
@@ -1,19 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
 use parsing::parse;
-use servo_url::ServoUrl;
-use style::parser::ParserContext;
 use style::properties::longhands::{self, perspective_origin, transform_origin};
-use style::stylesheets::{CssRuleType, Origin};
 use style_traits::ToCss;
 
 #[test]
 fn test_clip() {
     use style::properties::longhands::clip;
 
     assert_roundtrip_with_context!(clip::parse, "auto");
     assert_roundtrip_with_context!(clip::parse, "rect(1px, 2px, 3px, 4px)");
@@ -32,43 +27,28 @@ fn test_clip() {
                                    "rect(1px, auto, auto, 4px)");
     assert_roundtrip_with_context!(clip::parse,
                                    "rect(auto auto auto auto)",
                                    "rect(auto, auto, auto, auto)");
 }
 
 #[test]
 fn test_longhands_parse_origin() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-
-    let mut parser = Parser::new("1px some-rubbish");
-    let parsed = longhands::parse_origin(&context, &mut parser);
-    assert!(parsed.is_ok());
-    assert_eq!(parser.is_exhausted(), false);
-
-    let mut parser = Parser::new("1px 2px");
-    let parsed = longhands::parse_origin(&context, &mut parser);
-    assert!(parsed.is_ok());
-    assert_eq!(parser.is_exhausted(), true);
-
-    let mut parser = Parser::new("1px");
-    let parsed = longhands::parse_origin(&context, &mut parser);
-    assert!(parsed.is_ok());
-    assert_eq!(parser.is_exhausted(), true);
+    assert_parser_exhausted!(longhands::parse_origin, "1px some-rubbish", false);
+    assert_parser_exhausted!(longhands::parse_origin, "1px 2px", true);
+    assert_parser_exhausted!(longhands::parse_origin, "1px", true);
 }
 
 #[test]
 fn test_effects_parser_exhaustion() {
-    assert_parser_exhausted!(perspective_origin, "1px 1px", true);
-    assert_parser_exhausted!(transform_origin, "1px 1px", true);
+    assert_parser_exhausted!(perspective_origin::parse, "1px 1px", true);
+    assert_parser_exhausted!(transform_origin::parse, "1px 1px", true);
 
-    assert_parser_exhausted!(perspective_origin, "1px some-rubbish", false);
-    assert_parser_exhausted!(transform_origin, "1px some-rubbish", false);
+    assert_parser_exhausted!(perspective_origin::parse, "1px some-rubbish", false);
+    assert_parser_exhausted!(transform_origin::parse, "1px some-rubbish", false);
 }
 
 #[test]
 fn test_parse_factor() {
     use parsing::parse;
     use style::properties::longhands::filter;
 
     assert!(parse(filter::parse, "brightness(0)").is_ok());
--- a/servo/tests/unit/style/parsing/font.rs
+++ b/servo/tests/unit/style/parsing/font.rs
@@ -1,20 +1,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
-use servo_url::ServoUrl;
-use style::parser::ParserContext;
+use parsing::parse;
 use style::properties::longhands::{font_feature_settings, font_weight};
 use style::properties::longhands::font_feature_settings::computed_value;
 use style::properties::longhands::font_feature_settings::computed_value::FeatureTagValue;
-use style::stylesheets::{CssRuleType, Origin};
 use style_traits::ToCss;
 
 #[test]
 fn font_feature_settings_should_parse_properly() {
     let normal = parse_longhand!(font_feature_settings, "normal");
     let normal_computed = computed_value::T::Normal;
     assert_eq!(normal, normal_computed);
 
@@ -47,31 +43,20 @@ fn font_feature_settings_should_parse_pr
         FeatureTagValue { tag: String::from("abcd"), value: 0 },
         FeatureTagValue { tag: String::from("efgh"), value: 1 }
     ]);
     assert_eq!(multiple, multiple_computed);
 }
 
 #[test]
 fn font_feature_settings_should_throw_on_bad_input() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-
-    let mut empty = Parser::new("");
-    assert!(font_feature_settings::parse(&context, &mut empty).is_err());
-
-    let mut negative = Parser::new("\"abcd\" -1");
-    assert!(font_feature_settings::parse(&context, &mut negative).is_err());
-
-    let mut short_tag = Parser::new("\"abc\"");
-    assert!(font_feature_settings::parse(&context, &mut short_tag).is_err());
-
-    let mut illegal_tag = Parser::new("\"abcó\"");
-    assert!(font_feature_settings::parse(&context, &mut illegal_tag).is_err());
+    assert!(parse(font_feature_settings::parse, "").is_err());
+    assert!(parse(font_feature_settings::parse, "\"abcd\" -1").is_err());
+    assert!(parse(font_feature_settings::parse, "\"abc\"").is_err());
+    assert!(parse(font_feature_settings::parse, "\"abcó\"").is_err());
 }
 
 #[test]
 fn font_feature_settings_to_css() {
     assert_roundtrip_with_context!(font_feature_settings::parse, "normal");
     assert_roundtrip_with_context!(font_feature_settings::parse, "\"abcd\"");
     assert_roundtrip_with_context!(font_feature_settings::parse, "\"abcd\" on", "\"abcd\"");
     assert_roundtrip_with_context!(font_feature_settings::parse, "\"abcd\" off");
@@ -98,26 +83,21 @@ fn font_language_override_should_parse_p
     let danish = parse_longhand!(font_language_override, "\"DAN\"");
     assert_eq!(danish, SpecifiedValue::Override("DAN".to_string()));
 }
 
 #[test]
 fn font_weight_keyword_should_preserve_keyword() {
     use style::properties::longhands::font_weight::SpecifiedValue;
 
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("normal");
-    let result = font_weight::parse(&context, &mut parser);
-    assert_eq!(result.unwrap(), SpecifiedValue::Normal);
+    let result = parse(font_weight::parse, "normal").unwrap();
+    assert_eq!(result, SpecifiedValue::Normal);
 
-    let mut parser = Parser::new("bold");
-    let result = font_weight::parse(&context, &mut parser);
-    assert_eq!(result.unwrap(), SpecifiedValue::Bold);
+    let result = parse(font_weight::parse, "bold").unwrap();
+    assert_eq!(result, SpecifiedValue::Bold);
 }
 
 #[test]
 #[should_panic]
 fn font_language_override_should_fail_on_empty_str() {
     use style::properties::longhands::font_language_override;
 
     parse_longhand!(font_language_override, "");
--- a/servo/tests/unit/style/parsing/image.rs
+++ b/servo/tests/unit/style/parsing/image.rs
@@ -1,21 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
 use euclid::size::TypedSize2D;
-use media_queries::CSSErrorReporterTest;
+use parsing::parse;
 use std::f32::consts::PI;
 use style::font_metrics::ServoMetricsProvider;
 use style::media_queries::{Device, MediaType};
-use style::parser::ParserContext;
 use style::properties::ComputedValues;
-use style::stylesheets::{CssRuleType, Origin};
 use style::values::computed;
 use style::values::computed::{Angle, Context, ToComputedValue};
 use style::values::specified;
 use style::values::specified::image::*;
 use style_traits::ToCss;
 
 #[test]
 fn test_linear_gradient() {
--- a/servo/tests/unit/style/parsing/inherited_box.rs
+++ b/servo/tests/unit/style/parsing/inherited_box.rs
@@ -1,16 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
-use style::parser::ParserContext;
-use style::stylesheets::{CssRuleType, Origin};
+use parsing::parse;
 
 #[test]
 fn image_orientation_longhand_should_parse_properly() {
     use style::properties::longhands::image_orientation;
     use style::properties::longhands::image_orientation::SpecifiedValue;
     use style::values::specified::Angle;
 
     let from_image = parse_longhand!(image_orientation, "from-image");
--- a/servo/tests/unit/style/parsing/inherited_text.rs
+++ b/servo/tests/unit/style/parsing/inherited_text.rs
@@ -1,16 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
-use style::parser::ParserContext;
-use style::stylesheets::{CssRuleType, Origin};
+use parsing::parse;
 
 #[test]
 fn negative_letter_spacing_should_parse_properly() {
     use style::properties::longhands::letter_spacing;
     use style::properties::longhands::letter_spacing::SpecifiedValue;
     use style::values::specified::length::{Length, NoCalcLength, FontRelativeLength};
 
     let negative_value = parse_longhand!(letter_spacing, "-0.5em");
@@ -99,57 +96,37 @@ fn test_text_emphasis_position() {
     assert_eq!(right_under, SpecifiedValue(HorizontalWritingModeValue::Under, VerticalWritingModeValue::Right));
 
     let left_under = parse_longhand!(text_emphasis_position, "left under");
     assert_eq!(left_under, SpecifiedValue(HorizontalWritingModeValue::Under, VerticalWritingModeValue::Left));
 }
 
 #[test]
 fn webkit_text_stroke_shorthand_should_parse_properly() {
-    use media_queries::CSSErrorReporterTest;
-    use servo_url::ServoUrl;
     use style::properties::longhands::_webkit_text_stroke_color;
     use style::properties::longhands::_webkit_text_stroke_width;
     use style::properties::shorthands::_webkit_text_stroke;
 
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-
-    let mut parser = Parser::new("thin red");
-    let result = _webkit_text_stroke::parse_value(&context, &mut parser).unwrap();
+    let result = parse(_webkit_text_stroke::parse_value, "thin red").unwrap();
     assert_eq!(result._webkit_text_stroke_color, parse_longhand!(_webkit_text_stroke_color, "red"));
     assert_eq!(result._webkit_text_stroke_width, parse_longhand!(_webkit_text_stroke_width, "thin"));
 
     // ensure its no longer sensitive to order
-    let mut parser = Parser::new("red thin");
-    let result = _webkit_text_stroke::parse_value(&context, &mut parser).unwrap();
+    let result = parse(_webkit_text_stroke::parse_value, "red thin").unwrap();
     assert_eq!(result._webkit_text_stroke_color, parse_longhand!(_webkit_text_stroke_color, "red"));
     assert_eq!(result._webkit_text_stroke_width, parse_longhand!(_webkit_text_stroke_width, "thin"));
 }
 
 #[test]
 fn line_height_should_return_number_on_plain_zero() {
-    use media_queries::CSSErrorReporterTest;
-    use servo_url::ServoUrl;
     use style::properties::longhands::line_height;
 
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("0");
-    let result = line_height::parse(&context, &mut parser);
-    assert_eq!(result.unwrap(), parse_longhand!(line_height, "0"));
+    let result = parse(line_height::parse, "0").unwrap();
+    assert_eq!(result, parse_longhand!(line_height, "0"));
 }
 
 #[test]
 fn line_height_should_return_length_on_length_zero() {
-    use media_queries::CSSErrorReporterTest;
-    use servo_url::ServoUrl;
     use style::properties::longhands::line_height;
 
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("0px");
-    let result = line_height::parse(&context, &mut parser);
-    assert_eq!(result.unwrap(), parse_longhand!(line_height, "0px"));
+    let result = parse(line_height::parse, "0px").unwrap();
+    assert_eq!(result, parse_longhand!(line_height, "0px"));
 }
--- a/servo/tests/unit/style/parsing/mask.rs
+++ b/servo/tests/unit/style/parsing/mask.rs
@@ -1,130 +1,96 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
-use servo_url::ServoUrl;
-use style::parser::ParserContext;
+use parsing::parse;
 use style::properties::longhands::{mask_clip, mask_composite, mask_image, mask_mode};
 use style::properties::longhands::{mask_origin, mask_position_x, mask_position_y, mask_repeat, mask_size};
 use style::properties::shorthands::mask;
-use style::stylesheets::{CssRuleType, Origin};
 
 #[test]
 fn mask_shorthand_should_parse_all_available_properties_when_specified() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("url(\"http://servo/test.png\") luminance 7px 4px / 70px 50px \
-                                 repeat-x padding-box border-box subtract");
-    let result = mask::parse_value(&context, &mut parser).unwrap();
+    let input = "url(\"http://servo/test.png\") luminance 7px 4px / 70px 50px repeat-x padding-box border-box subtract";
+    let result = parse(mask::parse_value, input).unwrap();
 
     assert_eq!(result.mask_image, parse_longhand!(mask_image, "url(\"http://servo/test.png\")"));
     assert_eq!(result.mask_mode, parse_longhand!(mask_mode, "luminance"));
     assert_eq!(result.mask_position_x, parse_longhand!(mask_position_x, "7px"));
     assert_eq!(result.mask_position_y, parse_longhand!(mask_position_y, "4px"));
     assert_eq!(result.mask_size, parse_longhand!(mask_size, "70px 50px"));
     assert_eq!(result.mask_repeat, parse_longhand!(mask_repeat, "repeat-x"));
     assert_eq!(result.mask_origin, parse_longhand!(mask_origin, "padding-box"));
     assert_eq!(result.mask_clip, parse_longhand!(mask_clip, "border-box"));
     assert_eq!(result.mask_composite, parse_longhand!(mask_composite, "subtract"));
 }
 
 #[test]
 fn mask_shorthand_should_parse_when_some_fields_set() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("14px 40px repeat-y");
-    let result = mask::parse_value(&context, &mut parser).unwrap();
+    let result = parse(mask::parse_value, "14px 40px repeat-y").unwrap();
 
     assert_eq!(result.mask_position_x, parse_longhand!(mask_position_x, "14px"));
     assert_eq!(result.mask_position_y, parse_longhand!(mask_position_y, "40px"));
     assert_eq!(result.mask_repeat, parse_longhand!(mask_repeat, "repeat-y"));
 
-    let mut parser = Parser::new("url(\"http://servo/test.png\") repeat add");
-    let result = mask::parse_value(&context, &mut parser).unwrap();
+    let result = parse(mask::parse_value, "url(\"http://servo/test.png\") repeat add").unwrap();
 
     assert_eq!(result.mask_image, parse_longhand!(mask_image, "url(\"http://servo/test.png\")"));
     assert_eq!(result.mask_repeat, parse_longhand!(mask_repeat, "repeat"));
     assert_eq!(result.mask_composite, parse_longhand!(mask_composite, "add"));
 
-    let mut parser = Parser::new("intersect");
-    let result = mask::parse_value(&context, &mut parser).unwrap();
+    let result = parse(mask::parse_value, "intersect").unwrap();
 
     assert_eq!(result.mask_composite, parse_longhand!(mask_composite, "intersect"));
 
-    let mut parser = Parser::new("url(\"http://servo/test.png\")");
-    let result = mask::parse_value(&context, &mut parser).unwrap();
+    let result = parse(mask::parse_value, "url(\"http://servo/test.png\")").unwrap();
 
     assert_eq!(result.mask_image, parse_longhand!(mask_image, "url(\"http://servo/test.png\")"));
 }
 
 #[test]
 fn mask_shorthand_should_parse_position_and_size_correctly() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("7px 4px");
-    let result = mask::parse_value(&context, &mut parser).unwrap();
+    let result = parse(mask::parse_value, "7px 4px").unwrap();
 
     assert_eq!(result.mask_position_x, parse_longhand!(mask_position_x, "7px"));
     assert_eq!(result.mask_position_y, parse_longhand!(mask_position_y, "4px"));
 
-    let mut parser = Parser::new("7px 4px / 30px 20px");
-    let result = mask::parse_value(&context, &mut parser).unwrap();
+    let result = parse(mask::parse_value, "7px 4px / 30px 20px").unwrap();
 
     assert_eq!(result.mask_position_x, parse_longhand!(mask_position_x, "7px"));
     assert_eq!(result.mask_position_y, parse_longhand!(mask_position_y, "4px"));
     assert_eq!(result.mask_size, parse_longhand!(mask_size, "30px 20px"));
 
-    let mut parser = Parser::new("/ 30px 20px");
-    assert!(mask::parse_value(&context, &mut parser).is_err());
+    assert!(parse(mask::parse_value, "/ 30px 20px").is_err());
 
-    let mut parser = Parser::new("match-source repeat-x / 30px 20px");
-    assert!(mask::parse_value(&context, &mut parser).is_err());
+    assert!(parse(mask::parse_value, "match-source repeat-x / 30px 20px").is_err());
 }
 
 #[test]
 fn mask_shorthand_should_parse_origin_and_clip_correctly() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("padding-box content-box");
-    let result = mask::parse_value(&context, &mut parser).unwrap();
+    let result = parse(mask::parse_value, "padding-box content-box").unwrap();
 
     assert_eq!(result.mask_origin, parse_longhand!(mask_origin, "padding-box"));
     assert_eq!(result.mask_clip, parse_longhand!(mask_clip, "content-box"));
 
-    let mut parser = Parser::new("padding-box padding-box");
-    let result = mask::parse_value(&context, &mut parser).unwrap();
+    let result = parse(mask::parse_value, "padding-box padding-box").unwrap();
 
     assert_eq!(result.mask_origin, parse_longhand!(mask_origin, "padding-box"));
     assert_eq!(result.mask_clip, parse_longhand!(mask_clip, "padding-box"));
 
-    let mut parser = Parser::new("padding-box");
-    let result = mask::parse_value(&context, &mut parser).unwrap();
+    let result = parse(mask::parse_value, "padding-box").unwrap();
 
     assert_eq!(result.mask_origin, parse_longhand!(mask_origin, "padding-box"));
     assert_eq!(result.mask_clip, parse_longhand!(mask_clip, "padding-box"));
 }
 
 #[test]
 fn mask_shorthand_should_parse_mode_everywhere() {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new("luminance 7px 4px repeat-x padding-box");
-    assert!(mask::parse_value(&context, &mut parser).is_ok());
-
-    let mut parser = Parser::new("alpha");
-    assert!(mask::parse_value(&context, &mut parser).is_ok());
+    assert!(parse(mask::parse_value, "luminance 7px 4px repeat-x padding-box").is_ok());
+    assert!(parse(mask::parse_value, "alpha").is_ok());
 }
 
 #[test]
 fn mask_repeat_should_parse_shorthand_correctly() {
     use style::properties::longhands::mask_repeat::single_value::{RepeatKeyword, SpecifiedValue};
 
     let repeat_x = parse_longhand!(mask_repeat, "repeat-x");
     assert_eq!(repeat_x, mask_repeat::SpecifiedValue(vec![SpecifiedValue::RepeatX]));
@@ -148,43 +114,32 @@ fn mask_repeat_should_parse_shorthand_co
     assert_eq!(no_repeat,
                mask_repeat::SpecifiedValue(vec![SpecifiedValue::Other(RepeatKeyword::NoRepeat, None)]));
 }
 
 #[test]
 fn mask_repeat_should_parse_longhand_correctly() {
     use style::properties::longhands::mask_repeat::single_value::{RepeatKeyword, SpecifiedValue};
 
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-
     // repeat-x is not available in longhand form.
-    let mut parser = Parser::new("repeat-x no-repeat");
-    assert!(mask_repeat::parse(&context, &mut parser).is_err());
-
-    let mut parser = Parser::new("no-repeat repeat-x");
-    assert!(mask_repeat::parse(&context, &mut parser).is_err());
+    assert!(parse(mask_repeat::parse, "repeat-x no-repeat").is_err());
+    assert!(parse(mask_repeat::parse, "no-repeat repeat-x").is_err());
 
     // repeat-y is not available in longhand form.
-    let mut parser = Parser::new("repeat-y no-repeat");
-    assert!(mask_repeat::parse(&context, &mut parser).is_err());
-
-    let mut parser = Parser::new("no-repeat repeat-y");
-    assert!(mask_repeat::parse(&context, &mut parser).is_err());
+    assert!(parse(mask_repeat::parse, "repeat-y no-repeat").is_err());
+    assert!(parse(mask_repeat::parse, "no-repeat repeat-y").is_err());
 
     // Longhand form supports two directions.
     let no_repeat_and_round = parse_longhand!(mask_repeat, "no-repeat round");
     assert_eq!(no_repeat_and_round,
                mask_repeat::SpecifiedValue(vec![SpecifiedValue::Other(RepeatKeyword::NoRepeat,
                                                                       Some(RepeatKeyword::Round))]));
 
     // Not three directions.
-    let mut parser = Parser::new("repeat no-repeat round");
-    assert!(mask_repeat::parse(&context, &mut parser).is_err());
+    assert!(parse(mask_repeat::parse, "repeat no-repeat round").is_err());
 
     // Multiple values with mixed shortform and longform should parse.
     let multiple = parse_longhand!(mask_repeat, "repeat, no-repeat round");
     assert_eq!(multiple,
                mask_repeat::SpecifiedValue(vec![SpecifiedValue::Other(RepeatKeyword::Repeat, None),
                                                 SpecifiedValue::Other(RepeatKeyword::NoRepeat,
                                                                       Some(RepeatKeyword::Round))]));
 }
--- a/servo/tests/unit/style/parsing/mod.rs
+++ b/servo/tests/unit/style/parsing/mod.rs
@@ -18,72 +18,69 @@ fn parse<T, F: Fn(&ParserContext, &mut P
 }
 
 // This is a macro so that the file/line information
 // is preserved in the panic
 macro_rules! assert_roundtrip_with_context {
     ($fun:expr, $string:expr) => {
         assert_roundtrip_with_context!($fun, $string, $string);
     };
-    ($fun:expr,$input:expr, $output:expr) => {
-        let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-        let reporter = CSSErrorReporterTest;
-        let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-        let mut parser = Parser::new($input);
-        let parsed = $fun(&context, &mut parser)
-                     .expect(&format!("Failed to parse {}", $input));
-        let serialized = ToCss::to_css_string(&parsed);
-        assert_eq!(serialized, $output);
+    ($fun:expr, $input:expr, $output:expr) => {{
+        let serialized = parse(|context, i| {
+            let parsed = $fun(context, i)
+                         .expect(&format!("Failed to parse {}", $input));
+            let serialized = ToCss::to_css_string(&parsed);
+            assert_eq!(serialized, $output);
+            Ok(serialized)
+        }, $input).unwrap();
 
-        let mut parser = Parser::new(&serialized);
-        let re_parsed = $fun(&context, &mut parser)
-                        .expect(&format!("Failed to parse serialization {}", $input));
-        let re_serialized = ToCss::to_css_string(&re_parsed);
-        assert_eq!(serialized, re_serialized);
-    }
+        parse(|context, i| {
+            let re_parsed = $fun(context, i)
+                            .expect(&format!("Failed to parse serialization {}", $input));
+            let re_serialized = ToCss::to_css_string(&re_parsed);
+            assert_eq!(serialized, re_serialized);
+            Ok(())
+        }, &serialized).unwrap()
+    }}
 }
 
 macro_rules! assert_roundtrip {
     ($fun:expr, $string:expr) => {
         assert_roundtrip!($fun, $string, $string);
     };
-    ($fun:expr,$input:expr, $output:expr) => {
+    ($fun:expr, $input:expr, $output:expr) => {
         let mut parser = Parser::new($input);
         let parsed = $fun(&mut parser)
                      .expect(&format!("Failed to parse {}", $input));
         let serialized = ToCss::to_css_string(&parsed);
         assert_eq!(serialized, $output);
 
         let mut parser = Parser::new(&serialized);
         let re_parsed = $fun(&mut parser)
                         .expect(&format!("Failed to parse serialization {}", $input));
         let re_serialized = ToCss::to_css_string(&re_parsed);
-        assert_eq!(serialized, re_serialized);
+        assert_eq!(serialized, re_serialized)
     }
 }
 
 macro_rules! assert_parser_exhausted {
-    ($name:ident, $string:expr, $should_exhausted:expr) => {{
-        let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-        let reporter = CSSErrorReporterTest;
-        let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-        let mut parser = Parser::new($string);
-        let parsed = $name::parse(&context, &mut parser);
-        assert_eq!(parsed.is_ok(), true);
-        assert_eq!(parser.is_exhausted(), $should_exhausted);
+    ($fun:expr, $string:expr, $should_exhausted:expr) => {{
+        parse(|context, input| {
+            let parsed = $fun(context, input);
+            assert_eq!(parsed.is_ok(), true);
+            assert_eq!(input.is_exhausted(), $should_exhausted);
+            Ok(())
+        }, $string).unwrap()
     }}
 }
 
 macro_rules! parse_longhand {
-    ($name:ident, $s:expr) => {{
-        let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-        let reporter = CSSErrorReporterTest;
-        let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-        $name::parse(&context, &mut Parser::new($s)).unwrap()
-    }};
+    ($name:ident, $s:expr) => {
+        parse($name::parse, $s).unwrap()
+    };
 }
 
 mod animation;
 mod background;
 mod basic_shape;
 mod border;
 mod box_;
 mod column;
@@ -98,8 +95,9 @@ mod mask;
 mod outline;
 mod position;
 mod selectors;
 mod supports;
 mod text;
 mod text_overflow;
 mod transition_timing_function;
 mod ui;
+mod value;
--- a/servo/tests/unit/style/parsing/outline.rs
+++ b/servo/tests/unit/style/parsing/outline.rs
@@ -1,16 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
-use style::parser::ParserContext;
-use style::stylesheets::{CssRuleType, Origin};
+use parsing::parse;
 use style_traits::ToCss;
 
 #[test]
 fn test_outline_style() {
     use style::properties::longhands::outline_style;
 
     assert_roundtrip_with_context!(outline_style::parse, r#"auto"#);
     assert_roundtrip_with_context!(outline_style::parse, r#"none"#);
@@ -18,21 +15,12 @@ fn test_outline_style() {
     assert_roundtrip_with_context!(outline_style::parse, r#"double"#);
     assert_roundtrip_with_context!(outline_style::parse, r#"dotted"#);
     assert_roundtrip_with_context!(outline_style::parse, r#"dashed"#);
     assert_roundtrip_with_context!(outline_style::parse, r#"groove"#);
     assert_roundtrip_with_context!(outline_style::parse, r#"ridge"#);
     assert_roundtrip_with_context!(outline_style::parse, r#"inset"#);
     assert_roundtrip_with_context!(outline_style::parse, r#"outset"#);
 
-    {
-        // The outline-style property accepts the same values as border-style,
-        // except that 'hidden' is not a legal outline style.
-
-        let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-        let reporter = CSSErrorReporterTest;
-        let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-        let mut parser = Parser::new(r#"hidden"#);
-        let parsed = outline_style::parse(&context, &mut parser);
-        assert!(parsed.is_err());
-    };
-
+    // The outline-style property accepts the same values as border-style,
+    // except that 'hidden' is not a legal outline style.
+    assert!(parse(outline_style::parse, r#"hidden"#).is_err());
 }
--- a/servo/tests/unit/style/parsing/position.rs
+++ b/servo/tests/unit/style/parsing/position.rs
@@ -1,17 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
 use parsing::parse;
-use style::parser::{Parse, ParserContext};
-use style::stylesheets::{CssRuleType, Origin};
+use style::parser::Parse;
 use style::values::specified::position::*;
 use style_traits::ToCss;
 
 #[test]
 fn test_position() {
     // Serialization is not actually specced
     // though these are the values expected by basic-shape
     // https://github.com/w3c/csswg-drafts/issues/368
--- a/servo/tests/unit/style/parsing/selectors.rs
+++ b/servo/tests/unit/style/parsing/selectors.rs
@@ -1,28 +1,26 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 use cssparser::{Parser, ToCss};
-use media_queries::CSSErrorReporterTest;
 use selectors::parser::SelectorList;
-use style::parser::ParserContext;
 use style::selector_parser::{SelectorImpl, SelectorParser};
-use style::stylesheets::{CssRuleType, Origin, Namespaces};
+use style::stylesheets::{Origin, Namespaces};
 
-fn parse(_context: &ParserContext, input: &mut Parser) -> Result<SelectorList<SelectorImpl>, ()> {
+fn parse_selector(input: &mut Parser) -> Result<SelectorList<SelectorImpl>, ()> {
     let mut ns = Namespaces::default();
     ns.prefixes.insert("svg".into(), ns!(svg));
     let parser = SelectorParser {
         stylesheet_origin: Origin::UserAgent,
         namespaces: &ns,
     };
     SelectorList::parse(&parser, input)
 }
 
 #[test]
 fn test_selectors() {
-    assert_roundtrip_with_context!(parse, "div");
-    assert_roundtrip_with_context!(parse, "svg|circle");
-    assert_roundtrip_with_context!(parse, "p:before", "p::before");
-    assert_roundtrip_with_context!(parse, "[border = \"0\"]:-servo-nonzero-border ~ ::-servo-details-summary");
+    assert_roundtrip!(parse_selector, "div");
+    assert_roundtrip!(parse_selector, "svg|circle");
+    assert_roundtrip!(parse_selector, "p:before", "p::before");
+    assert_roundtrip!(parse_selector, "[border = \"0\"]:-servo-nonzero-border ~ ::-servo-details-summary");
 }
--- a/servo/tests/unit/style/parsing/text.rs
+++ b/servo/tests/unit/style/parsing/text.rs
@@ -1,17 +1,13 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
 use parsing::parse;
-use style::parser::ParserContext;
-use style::stylesheets::{CssRuleType, Origin};
 use style_traits::ToCss;
 
 #[test]
 fn initial_letter_should_be_parsed_correctly() {
     use style::properties::longhands::initial_letter;
 
     assert_roundtrip_with_context!(initial_letter::parse, "1.5");
     assert_roundtrip_with_context!(initial_letter::parse, "1.5 3");
--- a/servo/tests/unit/style/parsing/text_overflow.rs
+++ b/servo/tests/unit/style/parsing/text_overflow.rs
@@ -1,34 +1,30 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
-use style::parser::ParserContext;
-use style::stylesheets::{CssRuleType, Origin};
+use parsing::parse;
 use style_traits::ToCss;
 
 #[test]
 fn test_text_overflow() {
     use style::properties::longhands::text_overflow;
 
     assert_roundtrip_with_context!(text_overflow::parse, r#"clip"#);
     assert_roundtrip_with_context!(text_overflow::parse, r#"ellipsis"#);
     assert_roundtrip_with_context!(text_overflow::parse, r#"clip ellipsis"#);
     assert_roundtrip_with_context!(text_overflow::parse, r#""x""#);
     assert_roundtrip_with_context!(text_overflow::parse, r#"'x'"#, r#""x""#);
     assert_roundtrip_with_context!(text_overflow::parse, r#"clip "x""#);
     assert_roundtrip_with_context!(text_overflow::parse, r#""x" clip"#);
     assert_roundtrip_with_context!(text_overflow::parse, r#""x" "y""#);
-
 }
 
 #[test]
 fn test_text_overflow_parser_exhaustion() {
     use style::properties::longhands::text_overflow;
 
-    assert_parser_exhausted!(text_overflow, r#"clip rubbish"#, false);
-    assert_parser_exhausted!(text_overflow, r#"clip"#, true);
-    assert_parser_exhausted!(text_overflow, r#"ellipsis"#, true);
-    assert_parser_exhausted!(text_overflow, r#"clip ellipsis"#, true);
+    assert_parser_exhausted!(text_overflow::parse, r#"clip rubbish"#, false);
+    assert_parser_exhausted!(text_overflow::parse, r#"clip"#, true);
+    assert_parser_exhausted!(text_overflow::parse, r#"ellipsis"#, true);
+    assert_parser_exhausted!(text_overflow::parse, r#"clip ellipsis"#, true);
 }
--- a/servo/tests/unit/style/parsing/transition_timing_function.rs
+++ b/servo/tests/unit/style/parsing/transition_timing_function.rs
@@ -1,18 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
 use parsing::parse;
-use style::parser::ParserContext;
 use style::properties::longhands::transition_timing_function;
-use style::stylesheets::{CssRuleType, Origin};
 use style_traits::ToCss;
 
 #[test]
 fn test_cubic_bezier() {
     assert_roundtrip_with_context!(transition_timing_function::parse, "cubic-bezier(0, 0, 0, 0)");
     assert_roundtrip_with_context!(transition_timing_function::parse, "cubic-bezier(0.25, 0, 0.5, 0)");
     assert_roundtrip_with_context!(transition_timing_function::parse, "cubic-bezier(1, 1, 1, 1)");
 
--- a/servo/tests/unit/style/parsing/ui.rs
+++ b/servo/tests/unit/style/parsing/ui.rs
@@ -1,17 +1,14 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::{Color, Parser, RGBA};
-use media_queries::CSSErrorReporterTest;
-use servo_url::ServoUrl;
-use style::parser::ParserContext;
-use style::stylesheets::{CssRuleType, Origin};
+use cssparser::{Color, RGBA};
+use parsing::parse;
 use style::values::{Auto, Either};
 use style::values::specified::CSSColor;
 use style_traits::ToCss;
 
 #[test]
 fn test_moz_user_select() {
     use style::properties::longhands::_moz_user_select;
 
@@ -21,22 +18,17 @@ fn test_moz_user_select() {
     assert_roundtrip_with_context!(_moz_user_select::parse, "element");
     assert_roundtrip_with_context!(_moz_user_select::parse, "elements");
     assert_roundtrip_with_context!(_moz_user_select::parse, "toggle");
     assert_roundtrip_with_context!(_moz_user_select::parse, "tri-state");
     assert_roundtrip_with_context!(_moz_user_select::parse, "-moz-all");
     assert_roundtrip_with_context!(_moz_user_select::parse, "-moz-none");
     assert_roundtrip_with_context!(_moz_user_select::parse, "-moz-text");
 
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-
-    let mut negative = Parser::new("potato");
-    assert!(_moz_user_select::parse(&context, &mut negative).is_err());
+    assert!(parse(_moz_user_select::parse, "potato").is_err());
 }
 
 #[test]
 fn test_caret_color() {
     use style::properties::longhands::caret_color;
 
     let auto = parse_longhand!(caret_color, "auto");
     assert_eq!(auto, Either::Second(Auto));
new file mode 100644
--- /dev/null
+++ b/servo/tests/unit/style/parsing/value.rs
@@ -0,0 +1,35 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use app_units::Au;
+use parsing::parse;
+use style::values::HasViewportPercentage;
+use style::values::specified::{AbsoluteLength, NoCalcLength, ViewportPercentageLength};
+use style::values::specified::length::{CalcLengthOrPercentage, CalcUnit};
+
+#[test]
+fn length_has_viewport_percentage() {
+    let l = NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vw(100.));
+    assert!(l.has_viewport_percentage());
+    let l = NoCalcLength::Absolute(AbsoluteLength::Px(Au(100).to_f32_px()));
+    assert!(!l.has_viewport_percentage());
+}
+
+#[test]
+fn calc_top_level_number_with_unit() {
+    fn parse_value(text: &str, unit: CalcUnit) -> Result<CalcLengthOrPercentage, ()> {
+        parse(|context, input| CalcLengthOrPercentage::parse(context, input, unit), text)
+    }
+    assert_eq!(parse_value("1", CalcUnit::Length), Err(()));
+    assert_eq!(parse_value("1", CalcUnit::LengthOrPercentage), Err(()));
+    assert_eq!(parse_value("1", CalcUnit::Angle), Err(()));
+    assert_eq!(parse_value("1", CalcUnit::Time), Err(()));
+    assert_eq!(parse_value("1px  + 1", CalcUnit::Length), Err(()));
+    assert_eq!(parse_value("1em  + 1", CalcUnit::Length), Err(()));
+    assert_eq!(parse_value("1px  + 1", CalcUnit::LengthOrPercentage), Err(()));
+    assert_eq!(parse_value("1%   + 1", CalcUnit::LengthOrPercentage), Err(()));
+    assert_eq!(parse_value("1rad + 1", CalcUnit::Angle), Err(()));
+    assert_eq!(parse_value("1deg + 1", CalcUnit::Angle), Err(()));
+    assert_eq!(parse_value("1s   + 1", CalcUnit::Time), Err(()));
+}
--- a/servo/tests/unit/style/properties/background.rs
+++ b/servo/tests/unit/style/properties/background.rs
@@ -1,20 +1,11 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
-use style::parser::ParserContext;
+use properties::parse;
 use style::properties::longhands::background_size;
-use style::stylesheets::{CssRuleType, Origin};
 
 #[test]
 fn background_size_should_reject_negative_values() {
-    let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-
-    let parse_result = background_size::parse(&context, &mut Parser::new("-40% -40%"));
-
-    assert_eq!(parse_result.is_err(), true);
+    assert!(parse(background_size::parse, "-40% -40%").is_err());
 }
--- a/servo/tests/unit/style/properties/mod.rs
+++ b/servo/tests/unit/style/properties/mod.rs
@@ -1,8 +1,44 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
+use cssparser::Parser;
+use media_queries::CSSErrorReporterTest;
+use style::parser::ParserContext;
+use style::stylesheets::{CssRuleType, Origin};
+
+fn parse<T, F: Fn(&ParserContext, &mut Parser) -> Result<T, ()>>(f: F, s: &str) -> Result<T, ()> {
+    let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
+    let reporter = CSSErrorReporterTest;
+    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
+    let mut parser = Parser::new(s);
+    f(&context, &mut parser)
+}
+
+macro_rules! assert_roundtrip_with_context {
+    ($fun:expr, $string:expr) => {
+        assert_roundtrip_with_context!($fun, $string, $string);
+    };
+    ($fun:expr, $input:expr, $output:expr) => {{
+        let serialized = parse(|context, i| {
+            let parsed = $fun(context, i)
+                         .expect(&format!("Failed to parse {}", $input));
+            let serialized = ToCss::to_css_string(&parsed);
+            assert_eq!(serialized, $output);
+            Ok(serialized)
+        }, $input).unwrap();
+
+        parse(|context, i| {
+            let re_parsed = $fun(context, i)
+                            .expect(&format!("Failed to parse serialization {}", $input));
+            let re_serialized = ToCss::to_css_string(&re_parsed);
+            assert_eq!(serialized, re_serialized);
+            Ok(())
+        }, &serialized).unwrap()
+    }}
+}
+
 mod background;
 mod scaffolding;
 mod serialization;
 mod viewport;
--- a/servo/tests/unit/style/properties/serialization.rs
+++ b/servo/tests/unit/style/properties/serialization.rs
@@ -1,36 +1,24 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
-use servo_url::ServoUrl;
+use properties::parse;
 use style::computed_values::display::T::inline_block;
-use style::parser::ParserContext;
-use style::properties::{PropertyDeclaration, PropertyDeclarationBlock, Importance, PropertyId};
+use style::properties::{PropertyDeclaration, Importance, PropertyId};
 use style::properties::longhands::outline_color::computed_value::T as ComputedColor;
 use style::properties::parse_property_declaration_list;
-use style::stylesheets::{CssRuleType, Origin};
 use style::values::{RGBA, Auto};
 use style::values::specified::{BorderStyle, BorderWidth, CSSColor, Length, NoCalcLength};
 use style::values::specified::{LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrAutoOrContent};
 use style::values::specified::url::SpecifiedUrl;
 use style_traits::ToCss;
 use stylesheets::block_from;
 
-fn parse_declaration_block(css_properties: &str) -> PropertyDeclarationBlock {
-    let url = ServoUrl::parse("http://localhost").unwrap();
-    let reporter = CSSErrorReporterTest;
-    let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-    let mut parser = Parser::new(css_properties);
-    parse_property_declaration_list(&context, &mut parser)
-}
-
 #[test]
 fn property_declaration_block_should_serialize_correctly() {
     use style::properties::longhands::overflow_x::SpecifiedValue as OverflowXValue;
     use style::properties::longhands::overflow_y::SpecifiedValue as OverflowYContainer;
 
     let declarations = vec![
         (PropertyDeclaration::Width(
             LengthOrPercentageOrAuto::Length(NoCalcLength::from_px(70f32))),
@@ -621,17 +609,17 @@ mod shorthand_serialization {
                               line-height: 3; \
                               font-family: serif; \
                               font-size-adjust: none; \
                               font-variant-caps: normal; \
                               font-variant-position: normal; \
                               font-language-override: normal; \
                               font-kerning: none";
 
-            let block = parse_declaration_block(block_text);
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let mut s = String::new();
             let id = PropertyId::parse("font".into()).unwrap();
             let x = block.property_value_to_css(&id, &mut s);
 
             assert_eq!(x.is_ok(), true);
             assert_eq!(s, "");
         }
@@ -646,17 +634,17 @@ mod shorthand_serialization {
                               line-height: 3; \
                               font-family: serif; \
                               font-size-adjust: none; \
                               font-kerning: auto; \
                               font-variant-caps: normal; \
                               font-variant-position: normal; \
                               font-language-override: normal;";
 
-            let block = parse_declaration_block(block_text);
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, "font: italic normal bolder expanded 4px/3 serif;");
         }
 
     }
 
@@ -670,17 +658,18 @@ mod shorthand_serialization {
                 background-image: url(\"http://servo/test.png\"); \
                 background-repeat: repeat-x; \
                 background-attachment: scroll; \
                 background-size: 70px 50px; \
                 background-position-x: 7px; \
                 background-position-y: 4px; \
                 background-origin: border-box; \
                 background-clip: padding-box;";
-            let block = parse_declaration_block(block_text);
+
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(
                 serialization,
                 "background: rgb(255, 0, 0) url(\"http://servo/test.png\") repeat-x \
                 scroll 7px 4px / 70px 50px border-box padding-box;"
             );
@@ -693,17 +682,18 @@ mod shorthand_serialization {
                 background-image: url(\"http://servo/test.png\"); \
                 background-repeat: repeat-x; \
                 background-attachment: scroll; \
                 background-size: 70px 50px; \
                 background-position-x: 7px; \
                 background-position-y: 4px; \
                 background-origin: padding-box; \
                 background-clip: padding-box;";
-            let block = parse_declaration_block(block_text);
+
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(
                 serialization,
                 "background: rgb(255, 0, 0) url(\"http://servo/test.png\") repeat-x \
                 scroll 7px 4px / 70px 50px padding-box;"
             );
@@ -716,17 +706,18 @@ mod shorthand_serialization {
                 background-image: url(\"http://servo/test.png\"), none; \
                 background-repeat: repeat-x, repeat-y; \
                 background-attachment: scroll, scroll; \
                 background-size: 70px 50px, 20px 30px; \
                 background-position-x: 7px, 70px; \
                 background-position-y: 4px, 40px; \
                 background-origin: border-box, padding-box; \
                 background-clip: padding-box, padding-box;";
-            let block = parse_declaration_block(block_text);
+
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(
                 serialization, "background: \
                 url(\"http://servo/test.png\") repeat-x scroll 7px 4px / 70px 50px border-box padding-box, \
                 rgb(0, 0, 255) none repeat-y scroll 70px 40px / 20px 30px padding-box;"
             );
@@ -746,17 +737,18 @@ mod shorthand_serialization {
                 background-color: rgb(0, 0, 255); \
                 background-image: url(\"http://servo/test.png\"), none; \
                 background-repeat: repeat-x, repeat-y; \
                 background-attachment: scroll, scroll; \
                 background-size: 70px 50px, 20px 30px; \
                 background-position: 7px 4px, 5px 6px; \
                 background-origin: border-box; \
                 background-clip: padding-box, padding-box;";
-            let block = parse_declaration_block(block_text);
+
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, block_text);
         }
     }
 
     mod mask {
@@ -904,17 +896,17 @@ mod shorthand_serialization {
                 "mask: url(\"http://servo/test.png\") luminance 7px 4px / 70px 50px \
                 repeat-x padding-box subtract;"
             );
         }
 
         #[test]
         fn serialize_mask_position_with_multiple_values() {
             let block_text = "mask-position: 1px 2px, 4px 3px;";
-            let block = parse_declaration_block(block_text);
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
             let serialization = block.to_css_string();
             assert_eq!(serialization, block_text);
         }
     }
 
     mod scroll_snap_type {
         pub use super::*;
         use style::properties::longhands::scroll_snap_type_x::SpecifiedValue as ScrollSnapTypeXValue;
@@ -962,32 +954,19 @@ mod shorthand_serialization {
 
     mod transform {
         pub use super::*;
         use style::properties::longhands::transform::SpecifiedOperation;
         use style::values::specified::{Angle, Number};
 
         #[test]
         fn should_serialize_none_correctly() {
-            use cssparser::Parser;
-            use media_queries::CSSErrorReporterTest;
-            use style::parser::ParserContext;
             use style::properties::longhands::transform;
-            use style::stylesheets::Origin;
 
-            let mut s = String::new();
-            let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-            let reporter = CSSErrorReporterTest;
-            let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-
-            let parsed = transform::parse(&context, &mut Parser::new("none")).unwrap();
-            let try_serialize = parsed.to_css(&mut s);
-
-            assert_eq!(try_serialize.is_ok(), true);
-            assert_eq!(s, "none");
+            assert_roundtrip_with_context!(transform::parse, "none");
         }
 
         #[inline(always)]
         fn validate_serialization<T: ToCss>(op: &T, expected_string: &'static str) {
             let css_string = op.to_css_string();
             assert_eq!(css_string, expected_string);
         }
 
@@ -1026,66 +1005,57 @@ mod shorthand_serialization {
         }
     }
 
     mod quotes {
         pub use super::*;
 
         #[test]
         fn should_serialize_none_correctly() {
-            use cssparser::Parser;
-            use media_queries::CSSErrorReporterTest;
-            use style::parser::ParserContext;
             use style::properties::longhands::quotes;
-            use style::stylesheets::Origin;
 
-            let mut s = String::new();
-            let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-            let reporter = CSSErrorReporterTest;
-            let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-
-            let parsed = quotes::parse(&context, &mut Parser::new("none")).unwrap();
-            let try_serialize = parsed.to_css(&mut s);
-
-            assert_eq!(try_serialize.is_ok(), true);
-            assert_eq!(s, "none");
+            assert_roundtrip_with_context!(quotes::parse, "none");
         }
     }
 
     mod animation {
         pub use super::*;
 
         #[test]
         fn serialize_single_animation() {
-            let block = parse_declaration_block("\
+            let block_text = "\
                 animation-name: bounce;\
                 animation-duration: 1s;\
                 animation-timing-function: ease-in;\
                 animation-delay: 0s;\
                 animation-direction: normal;\
                 animation-fill-mode: forwards;\
                 animation-iteration-count: infinite;\
-                animation-play-state: paused;");
+                animation-play-state: paused;";
+
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, "animation: 1s ease-in 0s infinite normal forwards paused bounce;")
         }
 
         #[test]
         fn serialize_multiple_animations() {
-            let block = parse_declaration_block("\
+            let block_text = "\
                 animation-name: bounce, roll;\
                 animation-duration: 1s, 0.2s;\
                 animation-timing-function: ease-in, linear;\
                 animation-delay: 0s, 1s;\
                 animation-direction: normal, reverse;\
                 animation-fill-mode: forwards, backwards;\
                 animation-iteration-count: infinite, 2;\
-                animation-play-state: paused, running;");
+                animation-play-state: paused, running;";
+
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization,
                        "animation: 1s ease-in 0s infinite normal forwards paused bounce, \
                                    0.2s linear 1s 2 reverse backwards running roll;");
         }
 
@@ -1100,63 +1070,67 @@ mod shorthand_serialization {
                 animation-name: bounce, roll, flip, jump; \
                 animation-duration: 1s, 0.2s; \
                 animation-timing-function: ease-in, linear; \
                 animation-delay: 0s, 1s, 0.5s; \
                 animation-direction: normal; \
                 animation-fill-mode: forwards, backwards; \
                 animation-iteration-count: infinite, 2; \
                 animation-play-state: paused, running;";
-            let block = parse_declaration_block(block_text);
+
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, block_text);
         }
 
         #[test]
         fn serialize_multiple_without_all_properties_returns_longhand() {
             // timing function and direction are missing, so no shorthand is returned.
             let block_text = "animation-name: bounce, roll; \
                               animation-duration: 1s, 0.2s; \
                               animation-delay: 0s, 1s; \
                               animation-fill-mode: forwards, backwards; \
                               animation-iteration-count: infinite, 2; \
                               animation-play-state: paused, running;";
-            let block = parse_declaration_block(block_text);
+
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, block_text);
         }
     }
 
     mod transition {
         pub use super::*;
 
         #[test]
         fn transition_should_serialize_all_available_properties() {
             let block_text = "transition-property: margin-left; \
                               transition-duration: 3s; \
                               transition-delay: 4s; \
                               transition-timing-function: cubic-bezier(0.2, 5, 0.5, 2);";
-            let block = parse_declaration_block(block_text);
+
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, "transition: margin-left 3s cubic-bezier(0.2, 5, 0.5, 2) 4s;");
         }
 
         #[test]
         fn serialize_multiple_transitions() {
             let block_text = "transition-property: margin-left, width; \
                               transition-duration: 3s, 2s; \
                               transition-delay: 4s, 5s; \
                               transition-timing-function: cubic-bezier(0.2, 5, 0.5, 2), ease;";
-            let block = parse_declaration_block(block_text);
+
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, "transition: \
                 margin-left 3s cubic-bezier(0.2, 5, 0.5, 2) 4s, \
                 width 2s ease 5s;");
         }
 
@@ -1167,39 +1141,40 @@ mod shorthand_serialization {
             // uneven. This is incorrect, in that we should serialize to a shorthand only when the
             // lists have the same length (this affects background, transition and animation).
             // https://github.com/servo/servo/issues/15398 )
             // The duration below has 1 extra value.
             let block_text = "transition-property: margin-left, width; \
                               transition-duration: 3s, 2s, 4s; \
                               transition-delay: 4s, 5s; \
                               transition-timing-function: cubic-bezier(0.2, 5, 0.5, 2), ease;";
-            let block = parse_declaration_block(block_text);
+
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
 
             assert_eq!(serialization, block_text);
         }
     }
 
     mod keywords {
         pub use super::*;
         #[test]
         fn css_wide_keywords_should_be_parsed() {
             let block_text = "--a:inherit;";
-            let block = parse_declaration_block(block_text);
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
             assert_eq!(serialization, "--a: inherit;");
         }
 
         #[test]
         fn non_keyword_custom_property_should_be_unparsed() {
             let block_text = "--main-color: #06c;";
-            let block = parse_declaration_block(block_text);
+            let block = parse(|c, i| Ok(parse_property_declaration_list(c, i)), block_text).unwrap();
 
             let serialization = block.to_css_string();
             assert_eq!(serialization, block_text);
         }
     }
 
     mod effects {
         pub use super::*;
@@ -1209,17 +1184,17 @@ mod shorthand_serialization {
         #[test]
         fn box_shadow_should_serialize_correctly() {
             let mut properties = Vec::new();
             let shadow_val = Shadow { offset_x: Length::from_px(1f32), offset_y: Length::from_px(2f32),
             blur_radius: Length::from_px(3f32), spread_radius: Length::from_px(4f32), color: None, inset: false };
             let shadow_decl = BoxShadow(vec![shadow_val]);
             properties.push(PropertyDeclaration:: BoxShadow(shadow_decl));
             let shadow_css = "box-shadow: 1px 2px 3px 4px;";
-            let shadow  =  parse_declaration_block(shadow_css);
+            let shadow = parse(|c, i| Ok(parse_property_declaration_list(c, i)), shadow_css).unwrap();
 
             assert_eq!(shadow.to_css_string(), shadow_css);
         }
     }
 
     mod counter_increment {
         pub use super::*;
         pub use style::properties::longhands::counter_increment::SpecifiedValue as CounterIncrement;
deleted file mode 100644
--- a/servo/tests/unit/style/value.rs
+++ /dev/null
@@ -1,42 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-use app_units::Au;
-use cssparser::Parser;
-use media_queries::CSSErrorReporterTest;
-use style::parser::ParserContext;
-use style::stylesheets::{CssRuleType, Origin};
-use style::values::HasViewportPercentage;
-use style::values::specified::{AbsoluteLength, ViewportPercentageLength, NoCalcLength};
-use style::values::specified::length::{CalcLengthOrPercentage, CalcUnit};
-
-#[test]
-fn length_has_viewport_percentage() {
-    let l = NoCalcLength::ViewportPercentage(ViewportPercentageLength::Vw(100.));
-    assert!(l.has_viewport_percentage());
-    let l = NoCalcLength::Absolute(AbsoluteLength::Px(Au(100).to_f32_px()));
-    assert!(!l.has_viewport_percentage());
-}
-
-#[test]
-fn calc_top_level_number_with_unit() {
-    fn parse(text: &str, unit: CalcUnit) -> Result<CalcLengthOrPercentage, ()> {
-        let url = ::servo_url::ServoUrl::parse("http://localhost").unwrap();
-        let reporter = CSSErrorReporterTest;
-        let context = ParserContext::new(Origin::Author, &url, &reporter, Some(CssRuleType::Style));
-        let mut parser = Parser::new(text);
-        CalcLengthOrPercentage::parse(&context, &mut parser, unit)
-    }
-    assert_eq!(parse("1", CalcUnit::Length), Err(()));
-    assert_eq!(parse("1", CalcUnit::LengthOrPercentage), Err(()));
-    assert_eq!(parse("1", CalcUnit::Angle), Err(()));
-    assert_eq!(parse("1", CalcUnit::Time), Err(()));
-    assert_eq!(parse("1px  + 1", CalcUnit::Length), Err(()));
-    assert_eq!(parse("1em  + 1", CalcUnit::Length), Err(()));
-    assert_eq!(parse("1px  + 1", CalcUnit::LengthOrPercentage), Err(()));
-    assert_eq!(parse("1%   + 1", CalcUnit::LengthOrPercentage), Err(()));
-    assert_eq!(parse("1rad + 1", CalcUnit::Angle), Err(()));
-    assert_eq!(parse("1deg + 1", CalcUnit::Angle), Err(()));
-    assert_eq!(parse("1s   + 1", CalcUnit::Time), Err(()));
-}