Bug 1730134 - Add some parsing and serialization tests for @layer. r=boris

This uncovers some serialization bugs, and some missing null-checks
given the statement layer doesn't have a rule list.

Differential Revision: https://phabricator.services.mozilla.com/D125176
This commit is contained in:
Emilio Cobos Álvarez 2021-09-10 23:16:02 +00:00
parent 694fef2dcb
commit b31a2c497f
4 changed files with 81 additions and 6 deletions

View File

@ -33,7 +33,9 @@ ServoCSSRuleList::ServoCSSRuleList(already_AddRefed<ServoCssRules> aRawRules,
StyleSheet* aSheet,
css::GroupRule* aParentRule)
: mStyleSheet(aSheet), mParentRule(aParentRule), mRawRules(aRawRules) {
Servo_CssRules_ListTypes(mRawRules, &mRules);
if (mRawRules) {
Servo_CssRules_ListTypes(mRawRules, &mRules);
}
}
// QueryInterface implementation for ServoCSSRuleList
@ -166,7 +168,7 @@ nsresult ServoCSSRuleList::InsertRule(const nsACString& aRule,
"Caller must ensure that "
"the list is not unlinked from stylesheet");
if (IsReadOnly()) {
if (!mRawRules || IsReadOnly()) {
return NS_OK;
}
@ -198,7 +200,7 @@ nsresult ServoCSSRuleList::InsertRule(const nsACString& aRule,
}
nsresult ServoCSSRuleList::DeleteRule(uint32_t aIndex) {
if (IsReadOnly()) {
if (!mRawRules || IsReadOnly()) {
return NS_OK;
}

View File

@ -234,7 +234,7 @@ impl ToCssWithGuard for LayerRule {
guard: &SharedRwLockReadGuard,
dest: &mut crate::str::CssStringWriter,
) -> fmt::Result {
dest.write_str("@layer ")?;
dest.write_str("@layer")?;
match self.kind {
LayerRuleKind::Block {
ref name,
@ -242,8 +242,8 @@ impl ToCssWithGuard for LayerRule {
ref is_anonymous,
} => {
if !*is_anonymous {
name.to_css(&mut CssWriter::new(dest))?;
dest.write_char(' ')?;
name.to_css(&mut CssWriter::new(dest))?;
}
rules.read_with(guard).to_css_block(guard, dest)
},
@ -251,7 +251,9 @@ impl ToCssWithGuard for LayerRule {
let mut writer = CssWriter::new(dest);
let mut first = true;
for name in &**names {
if !first {
if first {
writer.write_char(' ')?;
} else {
writer.write_str(", ")?;
}
first = false;

View File

@ -0,0 +1,25 @@
<!doctype html>
<meta charset="utf-8">
<title>@layer rule parsing / serialization</title>
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="help" href="https://drafts.csswg.org/css-cascade-5/#layering">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
<script>
test_valid_rule("@layer A;");
test_valid_rule("@layer A, B, C;");
test_valid_rule("@layer A.A;");
test_valid_rule("@layer A, B.C.D, C;");
test_invalid_rule("@layer;");
test_invalid_rule("@layer A . A;");
test_valid_rule("@layer {\n}");
test_valid_rule("@layer A {\n}");
test_valid_rule("@layer A.B {\n}");
test_invalid_rule("@layer A . B {\n}");
test_invalid_rule("@layer A, B, C {\n}");
</script>

View File

@ -95,3 +95,49 @@ function test_invalid_selector(selector) {
stringifiedSelector + " should throw in insertRule");
}, stringifiedSelector + " should be an invalid selector");
}
// serialized can be the expected serialization of rule, or an array of
// permitted serializations, or omitted if value should serialize as rule.
function test_valid_rule(rule, serialized) {
if (serialized === undefined)
serialized = rule;
test(function(){
const style = document.createElement("style");
document.head.append(style);
const {sheet} = style;
document.head.removeChild(style);
const {cssRules} = sheet;
assert_equals(cssRules.length, 0, "Sheet should have no rules");
sheet.insertRule(rule);
assert_equals(cssRules.length, 1, "Sheet should have 1 rule");
const serialization = cssRules[0].cssText;
if (Array.isArray(serialized))
assert_in_array(serialization, serialized, "serialization should be sound");
else
assert_equals(serialization, serialized, "serialization should be canonical");
sheet.deleteRule(0);
assert_equals(cssRules.length, 0, "Sheet should have no rule");
sheet.insertRule(serialization);
assert_equals(cssRules.length, 1, "Sheet should have 1 rule");
assert_equals(cssRules[0].cssText, serialization, "serialization should round-trip");
}, rule + " should be a valid rule");
}
function test_invalid_rule(rule) {
test(function(){
const style = document.createElement("style");
document.head.append(style);
const {sheet} = style;
document.head.removeChild(style);
assert_throws_dom(
DOMException.SYNTAX_ERR,
() => sheet.insertRule(rule),
rule + " should throw in insertRule");
}, rule + " should be an invalid rule");
}