Fix SimonSapin/servo-style#2: failed assertion in selector parsing.

Add a test: "parse bootstrap.css without failing"
This commit is contained in:
Simon Sapin 2013-09-30 17:45:13 +01:00
parent 8abab6f546
commit 25d6448f28
5 changed files with 6831 additions and 12 deletions

View file

@ -214,8 +214,8 @@ fn parse_simple_selectors(iter: &mut Iter, namespaces: &NamespaceMap)
// None means invalid selector
// Some(None) means no type selector
// Some(Some([...])) is a type selector. Might be empty for *|*
// Some(None) means no type selector.
// Some(Some(~[...])) is a type selector. Might be empty for *|*
fn parse_type_selector(iter: &mut Iter, namespaces: &NamespaceMap)
-> Option<Option<~[SimpleSelector]>> {
skip_whitespace(iter);
@ -242,6 +242,10 @@ fn parse_type_selector(iter: &mut Iter, namespaces: &NamespaceMap)
// Parse a simple selector other than a type selector
// None means invalid selector
// Some(None) means not a simple name
// Some(Some(Left(s)) is a simple selector
// Some(Some(Right(p)) is a pseudo-element
fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_negation: bool)
-> Option<Option<Either<SimpleSelector, PseudoElement>>> {
match iter.peek() {
@ -292,6 +296,7 @@ fn parse_one_simple_selector(iter: &mut Iter, namespaces: &NamespaceMap, inside_
}
}
// None means invalid selector
// Some(None) means not a qualified name
// Some(Some((None, None)) means *|*
@ -304,16 +309,14 @@ fn parse_qualified_name(iter: &mut Iter, allow_universal: bool, namespaces: &Nam
#[inline]
fn default_namespace(namespaces: &NamespaceMap, local_name: Option<~str>)
-> Option<Option<(Option<~str>, Option<~str>)>> {
match namespaces.default {
None => Some(Some((None, local_name))),
Some(ref url) => Some(Some((Some(url.to_owned()), local_name))),
}
Some(Some((namespaces.default.map(|url| url.to_owned()), local_name)))
}
#[inline]
fn explicit_namespace(iter: &mut Iter, allow_universal: bool, namespace_url: Option<~str>)
-> Option<Option<(Option<~str>, Option<~str>)>> {
assert!(iter.next() == Some(Delim('|')));
assert!(iter.next() == Some(Delim('|')),
"Implementation error, this should not happen.");
match iter.peek() {
Some(&Delim('*')) if allow_universal => {
iter.next();
@ -331,24 +334,24 @@ fn parse_qualified_name(iter: &mut Iter, allow_universal: bool, namespaces: &Nam
Some(&Ident(_)) => {
let value = get_next_ident(iter);
match iter.peek() {
Some(&Delim('|')) => default_namespace(namespaces, Some(value)),
_ => {
Some(&Delim('|')) => {
let namespace_url = match namespaces.prefix_map.find(&value) {
None => return None, // Undeclared namespace prefix: invalid selector
Some(ref url) => url.to_owned(),
};
explicit_namespace(iter, allow_universal, Some(namespace_url))
},
_ => default_namespace(namespaces, Some(value)),
}
},
Some(&Delim('*')) => {
iter.next(); // Consume '*'
match iter.peek() {
Some(&Delim('|')) => {
Some(&Delim('|')) => explicit_namespace(iter, allow_universal, None),
_ => {
if allow_universal { default_namespace(namespaces, None) }
else { None }
},
_ => explicit_namespace(iter, allow_universal, None),
}
},
Some(&Delim('|')) => explicit_namespace(iter, allow_universal, Some(~"")),

View file

@ -15,3 +15,6 @@ pub mod properties;
pub mod namespaces;
pub mod media_queries;
pub mod parsing_utils;
#[cfg(test)]
mod tests;

View file

@ -31,7 +31,7 @@ pub struct StyleRule {
}
fn parse_stylesheet(css: &str) -> Stylesheet {
pub fn parse_stylesheet(css: &str) -> Stylesheet {
static STATE_CHARSET: uint = 1;
static STATE_IMPORTS: uint = 2;
static STATE_NAMESPACES: uint = 3;

6805
tests/bootstrap-v3.0.0.css vendored Normal file

File diff suppressed because it is too large Load diff

8
tests/mod.rs Normal file
View file

@ -0,0 +1,8 @@
use super::stylesheets::parse_stylesheet;
#[test]
fn test_bootstrap() {
// Test that parsing bootstrap does not trigger an assertion or otherwise fail.
let stylesheet = parse_stylesheet(include_str!("bootstrap-v3.0.0.css"));
assert!(stylesheet.rules.len() > 100); // This depends on whet selectors are supported.
}