Commit b31a2c49 authored by Emilio Cobos Álvarez's avatar Emilio Cobos Álvarez
Browse files

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
parent 694fef2d
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -33,8 +33,10 @@ ServoCSSRuleList::ServoCSSRuleList(already_AddRefed<ServoCssRules> aRawRules,
                                   StyleSheet* aSheet,
                                   css::GroupRule* aParentRule)
    : mStyleSheet(aSheet), mParentRule(aParentRule), mRawRules(aRawRules) {
  if (mRawRules) {
    Servo_CssRules_ListTypes(mRawRules, &mRules);
  }
}

// QueryInterface implementation for ServoCSSRuleList
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(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;
  }

+5 −3
Original line number Diff line number Diff line
@@ -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;
+25 −0
Original line number Diff line number Diff line
<!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>
+46 −0
Original line number Diff line number Diff line
@@ -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");
}