blob: f78029595abd84d9799aff4be42a0b19ad02345c [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/css/RuleFeature.h"
#include "core/css/CSSSelectorList.h"
#include "core/css/RuleSet.h"
#include "core/css/StylePropertySet.h"
#include "core/css/StyleRule.h"
#include "core/css/invalidation/InvalidationSet.h"
#include "core/css/parser/CSSParser.h"
#include "core/dom/ElementTraversal.h"
#include "core/html/HTMLBodyElement.h"
#include "core/html/HTMLDocument.h"
#include "core/html/HTMLElement.h"
#include "core/html/HTMLHtmlElement.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace blink {
// TODO(sof): consider making these part object helper abstractions
// available from platform/heap/.
template <typename T>
class HeapPartObject final
: public GarbageCollectedFinalized<HeapPartObject<T>> {
public:
static HeapPartObject* Create() { return new HeapPartObject; }
T* Get() { return &part_; }
DEFINE_INLINE_TRACE() { visitor->Trace(part_); }
private:
HeapPartObject() {}
T part_;
};
template <typename T>
class PersistentPartObject final {
DISALLOW_NEW();
public:
PersistentPartObject() : part_(HeapPartObject<T>::Create()) {}
T* operator->() const { return (*part_).Get(); }
private:
Persistent<HeapPartObject<T>> part_;
};
class RuleFeatureSetTest : public ::testing::Test {
public:
RuleFeatureSetTest() {}
void SetUp() {
document_ = HTMLDocument::Create();
HTMLHtmlElement* html = HTMLHtmlElement::Create(*document_);
html->AppendChild(HTMLBodyElement::Create(*document_));
document_->AppendChild(html);
document_->body()->setInnerHTML("<b><i></i></b>");
}
RuleFeatureSet::SelectorPreMatch CollectFeatures(
const String& selector_text) {
CSSSelectorList selector_list = CSSParser::ParseSelector(
StrictCSSParserContext(), nullptr, selector_text);
StyleRule* style_rule =
StyleRule::Create(std::move(selector_list),
MutableStylePropertySet::Create(kHTMLStandardMode));
RuleData rule_data(style_rule, 0, 0, kRuleHasNoSpecialState);
return rule_feature_set_->CollectFeaturesFromRuleData(rule_data);
}
void ClearFeatures() { rule_feature_set_->Clear(); }
void CollectInvalidationSetsForClass(InvalidationLists& invalidation_lists,
const AtomicString& class_name) const {
Element* element = Traversal<HTMLElement>::FirstChild(
*Traversal<HTMLElement>::FirstChild(*document_->body()));
rule_feature_set_->CollectInvalidationSetsForClass(invalidation_lists,
*element, class_name);
}
void CollectInvalidationSetsForId(InvalidationLists& invalidation_lists,
const AtomicString& id) const {
Element* element = Traversal<HTMLElement>::FirstChild(
*Traversal<HTMLElement>::FirstChild(*document_->body()));
rule_feature_set_->CollectInvalidationSetsForId(invalidation_lists,
*element, id);
}
void CollectInvalidationSetsForAttribute(
InvalidationLists& invalidation_lists,
const QualifiedName& attribute_name) const {
Element* element = Traversal<HTMLElement>::FirstChild(
*Traversal<HTMLElement>::FirstChild(*document_->body()));
rule_feature_set_->CollectInvalidationSetsForAttribute(
invalidation_lists, *element, attribute_name);
}
void CollectInvalidationSetsForPseudoClass(
InvalidationLists& invalidation_lists,
CSSSelector::PseudoType pseudo) const {
Element* element = Traversal<HTMLElement>::FirstChild(
*Traversal<HTMLElement>::FirstChild(*document_->body()));
rule_feature_set_->CollectInvalidationSetsForPseudoClass(invalidation_lists,
*element, pseudo);
}
void CollectUniversalSiblingInvalidationSet(
InvalidationLists& invalidation_lists) {
rule_feature_set_->CollectUniversalSiblingInvalidationSet(
invalidation_lists, 1);
}
void CollectNthInvalidationSet(InvalidationLists& invalidation_lists) {
rule_feature_set_->CollectNthInvalidationSet(invalidation_lists);
}
const HashSet<AtomicString>& ClassSet(
const InvalidationSet& invalidation_set) {
return invalidation_set.ClassSetForTesting();
}
const HashSet<AtomicString>& IdSet(const InvalidationSet& invalidation_set) {
return invalidation_set.IdSetForTesting();
}
const HashSet<AtomicString>& TagNameSet(
const InvalidationSet& invalidation_set) {
return invalidation_set.TagNameSetForTesting();
}
const HashSet<AtomicString>& AttributeSet(
const InvalidationSet& invalidation_set) {
return invalidation_set.AttributeSetForTesting();
}
void ExpectNoInvalidation(InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(0u, invalidation_sets.size());
}
void ExpectSelfInvalidation(InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
EXPECT_TRUE(invalidation_sets[0]->InvalidatesSelf());
}
void ExpectNoSelfInvalidation(InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
EXPECT_FALSE(invalidation_sets[0]->InvalidatesSelf());
}
void ExpectWholeSubtreeInvalidation(
InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
EXPECT_TRUE(invalidation_sets[0]->WholeSubtreeInvalid());
}
void ExpectClassInvalidation(const AtomicString& class_name,
InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
HashSet<AtomicString> classes = ClassSet(*invalidation_sets[0]);
EXPECT_EQ(1u, classes.size());
EXPECT_TRUE(classes.Contains(class_name));
}
void ExpectSiblingInvalidation(unsigned max_direct_adjacent_selectors,
const AtomicString& sibling_name,
InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
const SiblingInvalidationSet& sibling_invalidation_set =
ToSiblingInvalidationSet(*invalidation_sets[0]);
HashSet<AtomicString> classes = ClassSet(sibling_invalidation_set);
EXPECT_EQ(1u, classes.size());
EXPECT_TRUE(classes.Contains(sibling_name));
EXPECT_EQ(max_direct_adjacent_selectors,
sibling_invalidation_set.MaxDirectAdjacentSelectors());
}
void ExpectSiblingDescendantInvalidation(
unsigned max_direct_adjacent_selectors,
const AtomicString& sibling_name,
const AtomicString& descendant_name,
InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
const SiblingInvalidationSet& sibling_invalidation_set =
ToSiblingInvalidationSet(*invalidation_sets[0]);
HashSet<AtomicString> classes = ClassSet(sibling_invalidation_set);
EXPECT_EQ(1u, classes.size());
EXPECT_TRUE(classes.Contains(sibling_name));
EXPECT_EQ(max_direct_adjacent_selectors,
sibling_invalidation_set.MaxDirectAdjacentSelectors());
HashSet<AtomicString> descendant_classes =
ClassSet(*sibling_invalidation_set.SiblingDescendants());
EXPECT_EQ(1u, descendant_classes.size());
EXPECT_TRUE(descendant_classes.Contains(descendant_name));
}
void ExpectClassesInvalidation(const AtomicString& first_class_name,
const AtomicString& second_class_name,
InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
HashSet<AtomicString> classes = ClassSet(*invalidation_sets[0]);
EXPECT_EQ(2u, classes.size());
EXPECT_TRUE(classes.Contains(first_class_name));
EXPECT_TRUE(classes.Contains(second_class_name));
}
void ExpectIdInvalidation(const AtomicString& id,
InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
HashSet<AtomicString> ids = IdSet(*invalidation_sets[0]);
EXPECT_EQ(1u, ids.size());
EXPECT_TRUE(ids.Contains(id));
}
void ExpectIdsInvalidation(const AtomicString& first_id,
const AtomicString& second_id,
InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
HashSet<AtomicString> ids = IdSet(*invalidation_sets[0]);
EXPECT_EQ(2u, ids.size());
EXPECT_TRUE(ids.Contains(first_id));
EXPECT_TRUE(ids.Contains(second_id));
}
void ExpectTagNameInvalidation(const AtomicString& tag_name,
InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
HashSet<AtomicString> tag_names = TagNameSet(*invalidation_sets[0]);
EXPECT_EQ(1u, tag_names.size());
EXPECT_TRUE(tag_names.Contains(tag_name));
}
void ExpectTagNamesInvalidation(const AtomicString& first_tag_name,
const AtomicString& second_tag_name,
InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
HashSet<AtomicString> tag_names = TagNameSet(*invalidation_sets[0]);
EXPECT_EQ(2u, tag_names.size());
EXPECT_TRUE(tag_names.Contains(first_tag_name));
EXPECT_TRUE(tag_names.Contains(second_tag_name));
}
void ExpectAttributeInvalidation(const AtomicString& attribute,
InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
HashSet<AtomicString> attributes = AttributeSet(*invalidation_sets[0]);
EXPECT_EQ(1u, attributes.size());
EXPECT_TRUE(attributes.Contains(attribute));
}
void ExpectSiblingRuleCount(unsigned count) {
EXPECT_EQ(count, rule_feature_set_->SiblingRules().size());
}
void ExpectUncommonAttributeRuleCount(unsigned count) {
EXPECT_EQ(count, rule_feature_set_->UncommonAttributeRules().size());
}
void ExpectFullRecalcForRuleSetInvalidation(bool expected) {
EXPECT_EQ(expected,
rule_feature_set_->NeedsFullRecalcForRuleSetInvalidation());
}
private:
PersistentPartObject<RuleFeatureSet> rule_feature_set_;
Persistent<Document> document_;
};
TEST_F(RuleFeatureSetTest, interleavedDescendantSibling1) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(".p"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "p");
ExpectSelfInvalidation(invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, interleavedDescendantSibling2) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(".o + .p"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "o");
ExpectNoInvalidation(invalidation_lists.descendants);
ExpectSiblingInvalidation(1, "p", invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, interleavedDescendantSibling3) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".m + .n .o + .p"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "n");
ExpectNoSelfInvalidation(invalidation_lists.descendants);
ExpectClassInvalidation("p", invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, interleavedDescendantSibling4) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".m + .n .o + .p"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "m");
ExpectNoInvalidation(invalidation_lists.descendants);
ExpectSiblingDescendantInvalidation(1, "n", "p", invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, interleavedDescendantSibling5) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".l ~ .m + .n .o + .p"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "l");
ExpectNoInvalidation(invalidation_lists.descendants);
ExpectSiblingDescendantInvalidation(UINT_MAX, "n", "p",
invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, interleavedDescendantSibling6) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".k > .l ~ .m + .n .o + .p"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "k");
ExpectClassInvalidation("p", invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, anySibling) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":-webkit-any(.q, .r) ~ .s .t"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "q");
ExpectNoInvalidation(invalidation_lists.descendants);
ExpectSiblingDescendantInvalidation(UINT_MAX, "s", "t",
invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, any) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":-webkit-any(.w, .x)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "w");
ExpectSelfInvalidation(invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, anyIdDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a :-webkit-any(#b, #c)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectIdsInvalidation("b", "c", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, anyTagDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a :-webkit-any(span, div)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectTagNamesInvalidation("span", "div", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, siblingAny) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".v ~ :-webkit-any(.w, .x)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "v");
ExpectNoInvalidation(invalidation_lists.descendants);
ExpectClassesInvalidation("w", "x", invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, descendantSiblingAny) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".u .v ~ :-webkit-any(.w, .x)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "u");
ExpectClassesInvalidation("w", "x", invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, id) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("#a #b"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForId(invalidation_lists, "a");
ExpectIdInvalidation("b", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, attribute) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("[c] [d]"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForAttribute(invalidation_lists,
QualifiedName("", "c", ""));
ExpectAttributeInvalidation("d", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, pseudoClass) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(":valid"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForPseudoClass(invalidation_lists,
CSSSelector::kPseudoValid);
ExpectSelfInvalidation(invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, tagName) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(":valid e"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForPseudoClass(invalidation_lists,
CSSSelector::kPseudoValid);
ExpectTagNameInvalidation("e", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, contentPseudo) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a ::content .b"));
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(".a .c"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectClassInvalidation("c", invalidation_lists.descendants);
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(".a .b"));
invalidation_lists.descendants.clear();
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectClassesInvalidation("b", "c", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, nonMatchingHost) {
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches, CollectFeatures(".a:host"));
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures("*:host(.a)"));
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures("*:host .a"));
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures("div :host .a"));
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures(":host:hover .a"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectNoInvalidation(invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, nonMatchingHostContext) {
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures(".a:host-context(*)"));
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures("*:host-context(.a)"));
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures("*:host-context(*) .a"));
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures("div :host-context(div) .a"));
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures(":host-context(div):hover .a"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectNoInvalidation(invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, siblingRulesBeforeContentPseudo) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures("a + b ::content .c"));
ExpectSiblingRuleCount(0);
}
TEST_F(RuleFeatureSetTest, siblingRulesBeforeContentPseudo2) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures("a + ::content .b"));
ExpectSiblingRuleCount(0);
}
TEST_F(RuleFeatureSetTest, siblingRulesAfterContentPseudo) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a ::content .b + .c"));
ExpectSiblingRuleCount(1);
}
TEST_F(RuleFeatureSetTest, siblingRulesNthBeforeContentPseudo) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":nth-child(2) ::content .a"));
ExpectSiblingRuleCount(0);
}
TEST_F(RuleFeatureSetTest, siblingRulesNthAfterContentPseudo) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a ::content :nth-child(2)"));
ExpectSiblingRuleCount(1);
}
TEST_F(RuleFeatureSetTest, siblingRulesBeforeSlotted) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a + ::slotted(.b)"));
ExpectSiblingRuleCount(0);
}
TEST_F(RuleFeatureSetTest, siblingRulesBeforeHost) {
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures(".a + :host(.b)"));
ExpectSiblingRuleCount(0);
}
TEST_F(RuleFeatureSetTest, siblingRulesBeforeHostContext) {
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures(".a + :host-context(.b)"));
ExpectSiblingRuleCount(0);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterContentPseudo) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures("div ::content [attr]"));
ExpectUncommonAttributeRuleCount(1);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeContentPseudo) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures("[attr] ::content div"));
ExpectUncommonAttributeRuleCount(0);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesSlotted) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures("::slotted([attr])"));
ExpectUncommonAttributeRuleCount(1);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeSlotted) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures("[attr]::slotted(*)"));
ExpectUncommonAttributeRuleCount(0);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesHost) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":host([attr])"));
ExpectUncommonAttributeRuleCount(1);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeHost) {
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures("[attr] :host"));
ExpectUncommonAttributeRuleCount(0);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHost) {
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures(":host[attr]"));
ExpectUncommonAttributeRuleCount(0);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHost2) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(":host [attr]"));
ExpectUncommonAttributeRuleCount(1);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesHostBeforePseudo) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":host([attr])::before"));
ExpectUncommonAttributeRuleCount(1);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesHostContext) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":host-context([attr])"));
ExpectUncommonAttributeRuleCount(1);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeHostContext) {
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures("[attr] :host-context(div)"));
ExpectUncommonAttributeRuleCount(0);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesBeforeHostContext2) {
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures("[attr]:host-context(div)"));
ExpectUncommonAttributeRuleCount(0);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHostContext) {
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures(":host-context(*)[attr]"));
ExpectUncommonAttributeRuleCount(0);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHostContext2) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":host-context(*) [attr]"));
ExpectUncommonAttributeRuleCount(1);
}
TEST_F(RuleFeatureSetTest, uncommonAttributeRulesAfterHostContextBeforePseudo) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":host-context([attr])::before"));
ExpectUncommonAttributeRuleCount(1);
}
TEST_F(RuleFeatureSetTest, universalSiblingInvalidationDirectAdjacent) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("* + .a"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectSiblingInvalidation(1, "a", invalidation_lists.siblings);
ExpectSelfInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, universalSiblingInvalidationMultipleDirectAdjacent) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("* + .a + .b"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectSiblingInvalidation(2, "b", invalidation_lists.siblings);
ExpectSelfInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest,
universalSiblingInvalidationDirectAdjacentDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("* + .a .b"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectSiblingDescendantInvalidation(1, "a", "b", invalidation_lists.siblings);
ExpectNoSelfInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, universalSiblingInvalidationIndirectAdjacent) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("* ~ .a"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectSiblingInvalidation(UINT_MAX, "a", invalidation_lists.siblings);
ExpectSelfInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest,
universalSiblingInvalidationMultipleIndirectAdjacent) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("* ~ .a ~ .b"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectSiblingInvalidation(UINT_MAX, "b", invalidation_lists.siblings);
ExpectSelfInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest,
universalSiblingInvalidationIndirectAdjacentDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("* ~ .a .b"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectSiblingDescendantInvalidation(UINT_MAX, "a", "b",
invalidation_lists.siblings);
ExpectNoSelfInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, universalSiblingInvalidationNot) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":not(.a) + .b"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectSiblingInvalidation(1, "b", invalidation_lists.siblings);
ExpectSelfInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, nonUniversalSiblingInvalidationNot) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures("#x:not(.a) + .b"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, universalSiblingInvalidationAny) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":-webkit-any(.a) + .b"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectSiblingInvalidation(1, "b", invalidation_lists.siblings);
ExpectSelfInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, nonUniversalSiblingInvalidationAny) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures("#x:-webkit-any(.a) + .b"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, universalSiblingInvalidationType) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("div + .a"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectSiblingInvalidation(1, "a", invalidation_lists.siblings);
ExpectSelfInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, nonUniversalSiblingInvalidationType) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("div#x + .a"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, universalSiblingInvalidationLink) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(":link + .a"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectSiblingInvalidation(1, "a", invalidation_lists.siblings);
ExpectSelfInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, nonUniversalSiblingInvalidationLink) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("#x:link + .a"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, nthInvalidationUniversal) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":nth-child(2n)"));
InvalidationLists invalidation_lists;
CollectNthInvalidationSet(invalidation_lists);
ExpectNoSelfInvalidation(invalidation_lists.descendants);
ExpectWholeSubtreeInvalidation(invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, nthInvalidationClass) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a:nth-child(2n)"));
InvalidationLists invalidation_lists;
CollectNthInvalidationSet(invalidation_lists);
ExpectNoSelfInvalidation(invalidation_lists.descendants);
ExpectClassInvalidation("a", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, nthInvalidationUniversalDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":nth-child(2n) *"));
InvalidationLists invalidation_lists;
CollectNthInvalidationSet(invalidation_lists);
ExpectNoSelfInvalidation(invalidation_lists.descendants);
ExpectWholeSubtreeInvalidation(invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, nthInvalidationDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":nth-child(2n) .a"));
InvalidationLists invalidation_lists;
CollectNthInvalidationSet(invalidation_lists);
ExpectNoSelfInvalidation(invalidation_lists.descendants);
ExpectClassInvalidation("a", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, nthInvalidationSibling) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":nth-child(2n) + .a"));
InvalidationLists invalidation_lists;
CollectNthInvalidationSet(invalidation_lists);
ExpectNoInvalidation(invalidation_lists.siblings);
ExpectNoSelfInvalidation(invalidation_lists.descendants);
ExpectClassInvalidation("a", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, nthInvalidationSiblingDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":nth-child(2n) + .a .b"));
InvalidationLists invalidation_lists;
CollectNthInvalidationSet(invalidation_lists);
ExpectNoInvalidation(invalidation_lists.siblings);
ExpectNoSelfInvalidation(invalidation_lists.descendants);
ExpectClassInvalidation("b", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, nthInvalidationNot) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":not(:nth-child(2n))"));
InvalidationLists invalidation_lists;
CollectNthInvalidationSet(invalidation_lists);
ExpectNoSelfInvalidation(invalidation_lists.descendants);
ExpectWholeSubtreeInvalidation(invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, nthInvalidationNotClass) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a:not(:nth-child(2n))"));
InvalidationLists invalidation_lists;
CollectNthInvalidationSet(invalidation_lists);
ExpectNoSelfInvalidation(invalidation_lists.descendants);
ExpectClassInvalidation("a", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, nthInvalidationNotDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".blah:not(:nth-child(2n)) .a"));
InvalidationLists invalidation_lists;
CollectNthInvalidationSet(invalidation_lists);
ExpectNoSelfInvalidation(invalidation_lists.descendants);
ExpectClassInvalidation("a", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, nthInvalidationAny) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":-webkit-any(#nomatch, :nth-child(2n))"));
InvalidationLists invalidation_lists;
CollectNthInvalidationSet(invalidation_lists);
ExpectNoSelfInvalidation(invalidation_lists.descendants);
ExpectWholeSubtreeInvalidation(invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, nthInvalidationAnyClass) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a:-webkit-any(#nomatch, :nth-child(2n))"));
InvalidationLists invalidation_lists;
CollectNthInvalidationSet(invalidation_lists);
ExpectNoSelfInvalidation(invalidation_lists.descendants);
ExpectClassInvalidation("a", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, nthInvalidationAnyDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".blah:-webkit-any(#nomatch, :nth-child(2n)) .a"));
InvalidationLists invalidation_lists;
CollectNthInvalidationSet(invalidation_lists);
ExpectNoSelfInvalidation(invalidation_lists.descendants);
ExpectClassInvalidation("a", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, RuleSetInvalidationTypeSelector) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("div"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("* div"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("body *"));
ExpectFullRecalcForRuleSetInvalidation(true);
}
TEST_F(RuleFeatureSetTest, RuleSetInvalidationClassIdAttr) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(".c"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(".c *"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("#i"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("#i *"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("[attr]"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("[attr] *"));
ExpectFullRecalcForRuleSetInvalidation(false);
}
TEST_F(RuleFeatureSetTest, RuleSetInvalidationHoverActiveFocus) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":hover:active:focus"));
ExpectFullRecalcForRuleSetInvalidation(true);
}
TEST_F(RuleFeatureSetTest, RuleSetInvalidationHostContext) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":host-context(.x)"));
ExpectFullRecalcForRuleSetInvalidation(true);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":host-context(.x) .y"));
ExpectFullRecalcForRuleSetInvalidation(false);
}
TEST_F(RuleFeatureSetTest, RuleSetInvalidationHost) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(":host(.x)"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(":host(*) .y"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(":host(.x) .y"));
ExpectFullRecalcForRuleSetInvalidation(false);
}
TEST_F(RuleFeatureSetTest, RuleSetInvalidationNot) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(":not(.x)"));
ExpectFullRecalcForRuleSetInvalidation(true);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":not(.x) :hover"));
ExpectFullRecalcForRuleSetInvalidation(true);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(":not(.x) .y"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":not(.x) + .y"));
ExpectFullRecalcForRuleSetInvalidation(false);
}
TEST_F(RuleFeatureSetTest, RuleSetInvalidationCustomPseudo) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures("::-webkit-slider-thumb"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".x::-webkit-slider-thumb"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".x + ::-webkit-slider-thumb"));
ExpectFullRecalcForRuleSetInvalidation(false);
}
TEST_F(RuleFeatureSetTest, RuleSetInvalidationSlotted) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("::slotted(*)"));
ExpectFullRecalcForRuleSetInvalidation(true);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures("::slotted(.y)"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".x::slotted(.y)"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures("[x] ::slotted(.y)"));
ExpectFullRecalcForRuleSetInvalidation(false);
}
TEST_F(RuleFeatureSetTest, RuleSetInvalidationAnyPseudo) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":-webkit-any(*, #x)"));
ExpectFullRecalcForRuleSetInvalidation(true);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".x:-webkit-any(*, #y)"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":-webkit-any(:-webkit-any(.a, .b), #x)"));
ExpectFullRecalcForRuleSetInvalidation(false);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":-webkit-any(:-webkit-any(.a, *), #x)"));
ExpectFullRecalcForRuleSetInvalidation(true);
ClearFeatures();
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":-webkit-any(*, .a) *"));
ExpectFullRecalcForRuleSetInvalidation(true);
}
} // namespace blink