359 lines
9.0 KiB
Rust
359 lines
9.0 KiB
Rust
use simplecss::*;
|
|
|
|
macro_rules! tokenize {
|
|
($name:ident, $text:expr, $( $token:expr ),*) => (
|
|
#[test]
|
|
fn $name() {
|
|
let mut t = SelectorTokenizer::from($text);
|
|
$(
|
|
assert_eq!(t.next().unwrap().unwrap(), $token);
|
|
)*
|
|
|
|
assert!(t.next().is_none());
|
|
}
|
|
)
|
|
}
|
|
|
|
tokenize!(tokenize_01, "*",
|
|
SelectorToken::UniversalSelector
|
|
);
|
|
|
|
tokenize!(tokenize_02, "div",
|
|
SelectorToken::TypeSelector("div")
|
|
);
|
|
|
|
tokenize!(tokenize_03, "#div",
|
|
SelectorToken::IdSelector("div")
|
|
);
|
|
|
|
tokenize!(tokenize_04, ".div",
|
|
SelectorToken::ClassSelector("div")
|
|
);
|
|
|
|
tokenize!(tokenize_05, "[id]",
|
|
SelectorToken::AttributeSelector("id", AttributeOperator::Exists)
|
|
);
|
|
|
|
tokenize!(tokenize_06, "[id=test]",
|
|
SelectorToken::AttributeSelector("id", AttributeOperator::Matches("test"))
|
|
);
|
|
|
|
tokenize!(tokenize_07, "[id~=test]",
|
|
SelectorToken::AttributeSelector("id", AttributeOperator::Contains("test"))
|
|
);
|
|
|
|
tokenize!(tokenize_08, "[id|=test]",
|
|
SelectorToken::AttributeSelector("id", AttributeOperator::StartsWith("test"))
|
|
);
|
|
|
|
tokenize!(tokenize_09, "[id='test']",
|
|
SelectorToken::AttributeSelector("id", AttributeOperator::Matches("test"))
|
|
);
|
|
|
|
tokenize!(tokenize_10, "[id=\"test\"]",
|
|
SelectorToken::AttributeSelector("id", AttributeOperator::Matches("test"))
|
|
);
|
|
|
|
tokenize!(tokenize_11, "[id='te\\'st']",
|
|
SelectorToken::AttributeSelector("id", AttributeOperator::Matches("te\\'st"))
|
|
);
|
|
|
|
tokenize!(tokenize_12, "[id=\"te\\\"st\"]",
|
|
SelectorToken::AttributeSelector("id", AttributeOperator::Matches("te\\\"st"))
|
|
);
|
|
|
|
tokenize!(tokenize_13, "div:first-child",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::PseudoClass("first-child")
|
|
);
|
|
|
|
tokenize!(tokenize_14, ":first-child",
|
|
SelectorToken::PseudoClass("first-child")
|
|
);
|
|
|
|
tokenize!(tokenize_15, "div p",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::TypeSelector("p")
|
|
);
|
|
|
|
tokenize!(tokenize_16, "div p a",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::TypeSelector("p"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::TypeSelector("a")
|
|
);
|
|
|
|
tokenize!(tokenize_17, "div>p",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::ChildCombinator,
|
|
SelectorToken::TypeSelector("p")
|
|
);
|
|
|
|
tokenize!(tokenize_18, "div >p",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::ChildCombinator,
|
|
SelectorToken::TypeSelector("p")
|
|
);
|
|
|
|
tokenize!(tokenize_19, "div> p",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::ChildCombinator,
|
|
SelectorToken::TypeSelector("p")
|
|
);
|
|
|
|
tokenize!(tokenize_20, "div > p",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::ChildCombinator,
|
|
SelectorToken::TypeSelector("p")
|
|
);
|
|
|
|
tokenize!(tokenize_21, "div .p",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::ClassSelector("p")
|
|
);
|
|
|
|
tokenize!(tokenize_22, "div *",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::UniversalSelector
|
|
);
|
|
|
|
tokenize!(tokenize_23, "div #p",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::IdSelector("p")
|
|
);
|
|
|
|
tokenize!(tokenize_24, "div [id]",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::AttributeSelector("id", AttributeOperator::Exists)
|
|
);
|
|
|
|
tokenize!(tokenize_25, "div :link",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::PseudoClass("link")
|
|
);
|
|
|
|
tokenize!(tokenize_26, "div+p",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::AdjacentCombinator,
|
|
SelectorToken::TypeSelector("p")
|
|
);
|
|
|
|
tokenize!(tokenize_27, "div +p",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::AdjacentCombinator,
|
|
SelectorToken::TypeSelector("p")
|
|
);
|
|
|
|
tokenize!(tokenize_28, "div+ p",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::AdjacentCombinator,
|
|
SelectorToken::TypeSelector("p")
|
|
);
|
|
|
|
tokenize!(tokenize_29, "div + p",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::AdjacentCombinator,
|
|
SelectorToken::TypeSelector("p")
|
|
);
|
|
|
|
tokenize!(tokenize_30, "div {",
|
|
SelectorToken::TypeSelector("div")
|
|
);
|
|
|
|
tokenize!(tokenize_31, "div,",
|
|
SelectorToken::TypeSelector("div")
|
|
);
|
|
|
|
tokenize!(tokenize_32, "div{",
|
|
SelectorToken::TypeSelector("div")
|
|
);
|
|
|
|
tokenize!(tokenize_33, "div ,",
|
|
SelectorToken::TypeSelector("div")
|
|
);
|
|
|
|
tokenize!(tokenize_34, "div.test",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::ClassSelector("test")
|
|
);
|
|
|
|
tokenize!(tokenize_35, "div.test.warn",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::ClassSelector("test"),
|
|
SelectorToken::ClassSelector("warn")
|
|
);
|
|
|
|
tokenize!(tokenize_36, "div#id",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::IdSelector("id")
|
|
);
|
|
|
|
tokenize!(tokenize_37, "*[id]",
|
|
SelectorToken::UniversalSelector,
|
|
SelectorToken::AttributeSelector("id", AttributeOperator::Exists)
|
|
);
|
|
|
|
tokenize!(tokenize_38, "*.test",
|
|
SelectorToken::UniversalSelector,
|
|
SelectorToken::ClassSelector("test")
|
|
);
|
|
|
|
tokenize!(tokenize_39, "*#id",
|
|
SelectorToken::UniversalSelector,
|
|
SelectorToken::IdSelector("id")
|
|
);
|
|
|
|
tokenize!(tokenize_40, "div * p",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::UniversalSelector,
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::TypeSelector("p")
|
|
);
|
|
|
|
tokenize!(tokenize_41, "div[id=test][color=red]",
|
|
SelectorToken::TypeSelector("div"),
|
|
SelectorToken::AttributeSelector("id", AttributeOperator::Matches("test")),
|
|
SelectorToken::AttributeSelector("color", AttributeOperator::Matches("red"))
|
|
);
|
|
|
|
tokenize!(tokenize_42, "a.external:visited",
|
|
SelectorToken::TypeSelector("a"),
|
|
SelectorToken::ClassSelector("external"),
|
|
SelectorToken::PseudoClass("visited")
|
|
);
|
|
|
|
tokenize!(tokenize_43, ":lang(en)",
|
|
SelectorToken::LangPseudoClass("en")
|
|
);
|
|
|
|
tokenize!(tokenize_44, "a\nb",
|
|
SelectorToken::TypeSelector("a"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::TypeSelector("b")
|
|
);
|
|
|
|
tokenize!(tokenize_45, ".warn :first-child",
|
|
SelectorToken::ClassSelector("warn"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::PseudoClass("first-child")
|
|
);
|
|
|
|
macro_rules! malformed {
|
|
($name:ident, $text:expr, $err_str:expr) => (
|
|
#[test]
|
|
fn $name() {
|
|
for token in SelectorTokenizer::from($text) {
|
|
match token {
|
|
Ok(_) => {}
|
|
Err(e) => {
|
|
assert_eq!(e.to_string(), $err_str);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
unreachable!()
|
|
}
|
|
)
|
|
}
|
|
|
|
malformed!(malformed_01, ">", "unexpected combinator");
|
|
|
|
malformed!(malformed_02, "+", "unexpected combinator");
|
|
|
|
malformed!(malformed_03, "> a", "unexpected combinator");
|
|
|
|
malformed!(malformed_04, "a >", "selector missing");
|
|
|
|
malformed!(malformed_05, "*a", "unexpected selector");
|
|
|
|
malformed!(malformed_06, "a*", "unexpected selector");
|
|
|
|
malformed!(malformed_07, "a > ,", "selector missing");
|
|
|
|
malformed!(malformed_08, "a > >", "unexpected combinator");
|
|
|
|
malformed!(malformed_09, "a > {", "selector missing");
|
|
|
|
malformed!(malformed_10, "a/**/b", "unexpected selector");
|
|
|
|
malformed!(malformed_11, "a < b", "invalid ident at 1:3");
|
|
|
|
malformed!(malformed_12, ":lang()", "invalid language pseudo-class");
|
|
|
|
malformed!(malformed_13, ":lang( )", "invalid language pseudo-class");
|
|
|
|
malformed!(malformed_14, "::first-child", "invalid ident at 1:2");
|
|
|
|
malformed!(malformed_15, "[olor:red", "invalid or unsupported attribute selector");
|
|
|
|
malformed!(malformed_16, "", "selector missing");
|
|
|
|
malformed!(malformed_17, " ", "selector missing");
|
|
|
|
malformed!(malformed_18, "/**/", "selector missing");
|
|
|
|
tokenize!(comment_01, "/**/a",
|
|
SelectorToken::TypeSelector("a")
|
|
);
|
|
|
|
tokenize!(comment_02, "/* */a",
|
|
SelectorToken::TypeSelector("a")
|
|
);
|
|
|
|
tokenize!(comment_03, "/* comment */a",
|
|
SelectorToken::TypeSelector("a")
|
|
);
|
|
|
|
tokenize!(comment_04, "/**/ /**/a",
|
|
SelectorToken::TypeSelector("a")
|
|
);
|
|
|
|
tokenize!(comment_05, "/**/ a /**/",
|
|
SelectorToken::TypeSelector("a")
|
|
);
|
|
|
|
tokenize!(comment_06, "a /**/ b",
|
|
SelectorToken::TypeSelector("a"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::TypeSelector("b")
|
|
);
|
|
|
|
tokenize!(comment_08, "a /**/b",
|
|
SelectorToken::TypeSelector("a"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::TypeSelector("b")
|
|
);
|
|
|
|
tokenize!(comment_09, "a/**/ b",
|
|
SelectorToken::TypeSelector("a"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::TypeSelector("b")
|
|
);
|
|
|
|
tokenize!(comment_10, "a/**/ /**/b",
|
|
SelectorToken::TypeSelector("a"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::TypeSelector("b")
|
|
);
|
|
|
|
tokenize!(comment_11, "a /**/ /**/ b",
|
|
SelectorToken::TypeSelector("a"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::TypeSelector("b")
|
|
);
|
|
|
|
tokenize!(comment_12, "a /**//**/ b",
|
|
SelectorToken::TypeSelector("a"),
|
|
SelectorToken::DescendantCombinator,
|
|
SelectorToken::TypeSelector("b")
|
|
);
|