blob: 0b2f5cfc2a4f3f8ff3f37cc81321ada93e569780 [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 "third_party/blink/renderer/core/css/rule_feature_set.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/css/css_property_value_set.h"
#include "third_party/blink/renderer/core/css/css_selector_list.h"
#include "third_party/blink/renderer/core/css/invalidation/invalidation_set.h"
#include "third_party/blink/renderer/core/css/parser/css_parser.h"
#include "third_party/blink/renderer/core/css/rule_set.h"
#include "third_party/blink/renderer/core/css/style_rule.h"
#include "third_party/blink/renderer/core/dom/element_traversal.h"
#include "third_party/blink/renderer/core/html/html_body_element.h"
#include "third_party/blink/renderer/core/html/html_document.h"
#include "third_party/blink/renderer/core/html/html_element.h"
#include "third_party/blink/renderer/core/html/html_html_element.h"
namespace blink {
class RuleFeatureSetTest : public testing::Test {
public:
RuleFeatureSetTest() = default;
void SetUp() override {
document_ = HTMLDocument::CreateForTest();
HTMLHtmlElement* html = HTMLHtmlElement::Create(*document_);
html->AppendChild(HTMLBodyElement::Create(*document_));
document_->AppendChild(html);
document_->body()->SetInnerHTMLFromString("<b><i></i></b>");
}
RuleFeatureSet::SelectorPreMatch CollectFeatures(
const String& selector_text) {
CSSSelectorList selector_list = CSSParser::ParseSelector(
StrictCSSParserContext(SecureContextMode::kInsecureContext), nullptr,
selector_text);
std::vector<wtf_size_t> indices;
for (const CSSSelector* s = selector_list.First(); s;
s = selector_list.Next(*s)) {
indices.push_back(selector_list.SelectorIndex(*s));
}
StyleRule* style_rule = StyleRule::Create(
std::move(selector_list),
MutableCSSPropertyValueSet::Create(kHTMLStandardMode));
RuleFeatureSet::SelectorPreMatch result =
RuleFeatureSet::SelectorPreMatch::kSelectorNeverMatches;
for (unsigned i = 0; i < indices.size(); ++i) {
RuleData* rule_data = RuleData::MaybeCreate(style_rule, indices[i], 0,
kRuleHasNoSpecialState);
DCHECK(rule_data);
if (rule_feature_set_.CollectFeaturesFromRuleData(rule_data))
result = RuleFeatureSet::SelectorPreMatch::kSelectorMayMatch;
}
return result;
}
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 CollectPartInvalidationSet(InvalidationLists& invalidation_lists) const {
rule_feature_set_.CollectPartInvalidationSet(invalidation_lists);
}
void CollectUniversalSiblingInvalidationSet(
InvalidationLists& invalidation_lists) {
rule_feature_set_.CollectUniversalSiblingInvalidationSet(invalidation_lists,
1);
}
void CollectNthInvalidationSet(InvalidationLists& invalidation_lists) {
rule_feature_set_.CollectNthInvalidationSet(invalidation_lists);
}
void AddTo(RuleFeatureSet& rule_feature_set) {
rule_feature_set.Add(rule_feature_set_);
}
using BackingType = InvalidationSet::BackingType;
template <BackingType type>
HashSet<AtomicString> ToHashSet(
typename InvalidationSet::Backing<type>::Range range) {
HashSet<AtomicString> hash_set;
for (auto str : range)
hash_set.insert(str);
return hash_set;
}
HashSet<AtomicString> ClassSet(const InvalidationSet& invalidation_set) {
return ToHashSet<BackingType::kClasses>(invalidation_set.Classes());
}
HashSet<AtomicString> IdSet(const InvalidationSet& invalidation_set) {
return ToHashSet<BackingType::kIds>(invalidation_set.Ids());
}
HashSet<AtomicString> TagNameSet(const InvalidationSet& invalidation_set) {
return ToHashSet<BackingType::kTagNames>(invalidation_set.TagNames());
}
HashSet<AtomicString> AttributeSet(const InvalidationSet& invalidation_set) {
return ToHashSet<BackingType::kAttributes>(invalidation_set.Attributes());
}
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 ExpectSelfInvalidationSet(InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
EXPECT_TRUE(invalidation_sets[0]->IsSelfInvalidationSet());
}
void ExpectNotSelfInvalidationSet(InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
EXPECT_FALSE(invalidation_sets[0]->IsSelfInvalidationSet());
}
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 ExpectClassInvalidation(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 ExpectClassInvalidation(const AtomicString& first_class_name,
const AtomicString& second_class_name,
const AtomicString& third_class_name,
InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
HashSet<AtomicString> classes = ClassSet(*invalidation_sets[0]);
EXPECT_EQ(3u, classes.size());
EXPECT_TRUE(classes.Contains(first_class_name));
EXPECT_TRUE(classes.Contains(second_class_name));
EXPECT_TRUE(classes.Contains(third_class_name));
}
void ExpectSiblingClassInvalidation(
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 ExpectSiblingIdInvalidation(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> ids = IdSet(*invalidation_sets[0]);
EXPECT_EQ(1u, ids.size());
EXPECT_TRUE(ids.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 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 ExpectIdInvalidation(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 ExpectTagNameInvalidation(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 ExpectFullRecalcForRuleSetInvalidation(bool expected) {
EXPECT_EQ(expected,
rule_feature_set_.NeedsFullRecalcForRuleSetInvalidation());
}
void ExpectPartsInvalidation(InvalidationSetVector& invalidation_sets) {
EXPECT_EQ(1u, invalidation_sets.size());
EXPECT_TRUE(invalidation_sets[0]->InvalidatesParts());
}
enum class RefCount { kOne, kMany };
template <typename MapType, typename KeyType>
void ExpectRefCountForInvalidationSet(const MapType& map,
const KeyType& key,
RefCount ref_count) {
auto it = map.find(key);
ASSERT_NE(map.end(), it);
if (ref_count == RefCount::kOne) {
EXPECT_TRUE(it->value->HasOneRef());
// For SiblingInvalidationSets, we also require that the inner
// InvalidationSets either don't exist, or have a refcount of 1.
if (it->value->IsSiblingInvalidationSet()) {
const SiblingInvalidationSet& sibling_invalidation_set =
ToSiblingInvalidationSet(*it->value);
bool sibling_descendants_has_one_ref =
!sibling_invalidation_set.SiblingDescendants() ||
sibling_invalidation_set.SiblingDescendants()->HasOneRef();
bool descendants_has_one_ref =
!sibling_invalidation_set.Descendants() ||
sibling_invalidation_set.Descendants()->HasOneRef();
EXPECT_TRUE(sibling_descendants_has_one_ref);
EXPECT_TRUE(descendants_has_one_ref);
}
} else {
EXPECT_FALSE(it->value->HasOneRef());
}
}
void ExpectRefCountForClassInvalidationSet(
const RuleFeatureSet& rule_feature_set,
const AtomicString& class_name,
RefCount ref_count) {
ExpectRefCountForInvalidationSet(rule_feature_set.class_invalidation_sets_,
class_name, ref_count);
}
void ExpectRefCountForAttributeInvalidationSet(
const RuleFeatureSet& rule_feature_set,
const AtomicString& attribute,
RefCount ref_count) {
ExpectRefCountForInvalidationSet(
rule_feature_set.attribute_invalidation_sets_, attribute, ref_count);
}
void ExpectRefCountForIdInvalidationSet(
const RuleFeatureSet& rule_feature_set,
const AtomicString& id,
RefCount ref_count) {
ExpectRefCountForInvalidationSet(rule_feature_set.id_invalidation_sets_, id,
ref_count);
}
void ExpectRefCountForPseudoInvalidationSet(
const RuleFeatureSet& rule_feature_set,
CSSSelector::PseudoType key,
RefCount ref_count) {
ExpectRefCountForInvalidationSet(rule_feature_set.pseudo_invalidation_sets_,
key, ref_count);
}
private:
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);
ExpectSiblingClassInvalidation(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, repeatedAny) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":-webkit-any(.v, .w):-webkit-any(.x, .y, .z)"));
{
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "v");
ExpectSelfInvalidation(invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
{
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "x");
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");
ExpectIdInvalidation("b", "c", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, repeatedAnyDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a :-webkit-any(.v, .w):-webkit-any(.x, .y, .z)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectClassInvalidation("v", "w", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, anyTagDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a :-webkit-any(span, div)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectTagNameInvalidation("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);
ExpectClassInvalidation("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");
ExpectClassInvalidation("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");
ExpectClassInvalidation("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, universalSiblingInvalidationDirectAdjacent) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("* + .a"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectSiblingClassInvalidation(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);
ExpectSiblingClassInvalidation(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);
ExpectSiblingClassInvalidation(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);
ExpectSiblingClassInvalidation(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);
ExpectSiblingClassInvalidation(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);
ExpectSiblingClassInvalidation(1, "b", invalidation_lists.siblings);
ExpectSelfInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, universalSiblingIdInvalidationAny) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":-webkit-any(.a) + #b"));
InvalidationLists invalidation_lists;
CollectUniversalSiblingInvalidationSet(invalidation_lists);
ExpectSiblingIdInvalidation(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);
ExpectSiblingClassInvalidation(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);
ExpectSiblingClassInvalidation(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);
}
TEST_F(RuleFeatureSetTest, SelfInvalidationSet) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(".a"));
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("div .b"));
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("#c"));
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures("[d]"));
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(":hover"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectSelfInvalidation(invalidation_lists.descendants);
ExpectSelfInvalidationSet(invalidation_lists.descendants);
invalidation_lists.descendants.clear();
CollectInvalidationSetsForClass(invalidation_lists, "b");
ExpectSelfInvalidation(invalidation_lists.descendants);
ExpectSelfInvalidationSet(invalidation_lists.descendants);
invalidation_lists.descendants.clear();
CollectInvalidationSetsForId(invalidation_lists, "c");
ExpectSelfInvalidation(invalidation_lists.descendants);
ExpectSelfInvalidationSet(invalidation_lists.descendants);
invalidation_lists.descendants.clear();
CollectInvalidationSetsForAttribute(invalidation_lists,
QualifiedName("", "d", ""));
ExpectSelfInvalidation(invalidation_lists.descendants);
ExpectSelfInvalidationSet(invalidation_lists.descendants);
invalidation_lists.descendants.clear();
CollectInvalidationSetsForPseudoClass(invalidation_lists,
CSSSelector::kPseudoHover);
ExpectSelfInvalidation(invalidation_lists.descendants);
ExpectSelfInvalidationSet(invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, ReplaceSelfInvalidationSet) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(".a"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectSelfInvalidation(invalidation_lists.descendants);
ExpectSelfInvalidationSet(invalidation_lists.descendants);
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(".a div"));
invalidation_lists.descendants.clear();
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectSelfInvalidation(invalidation_lists.descendants);
ExpectNotSelfInvalidationSet(invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, pseudoIsSibling) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":is(.q, .r) ~ .s .t"));
{
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "q");
ExpectNoInvalidation(invalidation_lists.descendants);
ExpectSiblingDescendantInvalidation(UINT_MAX, "s", "t",
invalidation_lists.siblings);
}
{
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "r");
ExpectNoInvalidation(invalidation_lists.descendants);
ExpectSiblingDescendantInvalidation(UINT_MAX, "s", "t",
invalidation_lists.siblings);
}
}
TEST_F(RuleFeatureSetTest, pseudoIs) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch, CollectFeatures(":is(.w, .x)"));
{
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "w");
ExpectSelfInvalidation(invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
{
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "x");
ExpectSelfInvalidation(invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
}
TEST_F(RuleFeatureSetTest, pseudoIsIdDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a :is(#b, #c)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectIdInvalidation("b", "c", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, pseudoIsTagDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a :is(span, div)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectTagNameInvalidation("span", "div", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, pseudoIsAnySibling) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".v ~ :is(.w, .x)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "v");
ExpectNoInvalidation(invalidation_lists.descendants);
ExpectClassInvalidation("w", "x", invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, pseudoIsDescendantSibling) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".u .v ~ :is(.w, .x)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "u");
ExpectClassInvalidation("w", "x", invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, pseudoIsWithComplexSelectors) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a :is(.w+.b, .x>#c)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectClassInvalidation("b", invalidation_lists.descendants);
ExpectIdInvalidation("c", invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, pseudoIsNested) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a :is(.w+.b, .e+:is(.c, #d))"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectClassInvalidation("b", "c", invalidation_lists.descendants);
ExpectIdInvalidation("d", invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, pseudoIsTooLarge) {
// RuleData cannot support selectors at index 8192 or beyond so the expansion
// is limited to this size
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures(":is(.a#a, .b#b, .c#c, .d#d) + "
":is(.e#e, .f#f, .g#g, .h#h) + "
":is(.i#i, .j#j, .k#k, .l#l) + "
":is(.m#m, .n#n, .o#o, .p#p) + "
":is(.q#q, .r#r, .s#s, .t#t) + "
":is(.u#u, .v#v, .w#w, .x#x)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectNoInvalidation(invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, pseudoWhere) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":where(.w, .x)"));
{
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "w");
ExpectSelfInvalidation(invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
{
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "x");
ExpectSelfInvalidation(invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
}
TEST_F(RuleFeatureSetTest, pseudoWhereSibling) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(":where(.q, .r) ~ .s .t"));
{
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "q");
ExpectNoInvalidation(invalidation_lists.descendants);
ExpectSiblingDescendantInvalidation(UINT_MAX, "s", "t",
invalidation_lists.siblings);
}
{
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "r");
ExpectNoInvalidation(invalidation_lists.descendants);
ExpectSiblingDescendantInvalidation(UINT_MAX, "s", "t",
invalidation_lists.siblings);
}
}
TEST_F(RuleFeatureSetTest, pseudoWhereIdDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a :where(#b, #c)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectIdInvalidation("b", "c", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, pseudoWhereTagDescendant) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a :where(span, div)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectTagNameInvalidation("span", "div", invalidation_lists.descendants);
}
TEST_F(RuleFeatureSetTest, pseudoWhereAnySibling) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".v ~ :where(.w, .x)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "v");
ExpectNoInvalidation(invalidation_lists.descendants);
ExpectClassInvalidation("w", "x", invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, pseudoWhereDescendantSibling) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".u .v ~ :where(.w, .x)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "u");
ExpectClassInvalidation("w", "x", invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, pseudoWhereWithComplexSelectors) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a :where(.w+.b, .x>#c)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectClassInvalidation("b", invalidation_lists.descendants);
ExpectIdInvalidation("c", invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, pseudoWhereNested) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a :where(.w+.b, .e+:where(.c, #d))"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectClassInvalidation("b", "c", invalidation_lists.descendants);
ExpectIdInvalidation("d", invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, pseudoWhereTooLarge) {
// RuleData cannot support selectors at index 8192 or beyond so the expansion
// is limited to this size
EXPECT_EQ(RuleFeatureSet::kSelectorNeverMatches,
CollectFeatures(":where(.a#a, .b#b, .c#c, .d#d) + "
":where(.e#e, .f#f, .g#g, .h#h) + "
":where(.i#i, .j#j, .k#k, .l#l) + "
":where(.m#m, .n#n, .o#o, .p#p) + "
":where(.q#q, .r#r, .s#s, .t#t) + "
":where(.u#u, .v#v, .w#w, .x#x)"));
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
ExpectNoInvalidation(invalidation_lists.descendants);
ExpectNoInvalidation(invalidation_lists.siblings);
}
TEST_F(RuleFeatureSetTest, invalidatesParts) {
EXPECT_EQ(RuleFeatureSet::kSelectorMayMatch,
CollectFeatures(".a .b::part(partname)"));
{
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "a");
EXPECT_EQ(1u, invalidation_lists.descendants.size());
ExpectNoSelfInvalidation(invalidation_lists.descendants);
EXPECT_TRUE(invalidation_lists.descendants[0]->TreeBoundaryCrossing());
EXPECT_TRUE(invalidation_lists.descendants[0]->InvalidatesParts());
}
{
InvalidationLists invalidation_lists;
CollectInvalidationSetsForClass(invalidation_lists, "b");
EXPECT_EQ(1u, invalidation_lists.descendants.size());
ExpectPartsInvalidation(invalidation_lists.descendants);
EXPECT_FALSE(invalidation_lists.descendants[0]->WholeSubtreeInvalid());
EXPECT_TRUE(invalidation_lists.descendants[0]->TreeBoundaryCrossing());
EXPECT_TRUE(invalidation_lists.descendants[0]->InvalidatesParts());
}
{
InvalidationLists invalidation_lists;
CollectPartInvalidationSet(invalidation_lists);
EXPECT_EQ(1u, invalidation_lists.descendants.size());
ExpectPartsInvalidation(invalidation_lists.descendants);
EXPECT_TRUE(invalidation_lists.descendants[0]->TreeBoundaryCrossing());
EXPECT_TRUE(invalidation_lists.descendants[0]->InvalidatesParts());
}
}
TEST_F(RuleFeatureSetTest, CopyOnWrite) {
// RuleFeatureSet local1 has an entry in each of the class/id/attribute/
// pseudo sets.
RuleFeatureSet local1;
CollectFeatures(".a .b");
CollectFeatures("#d .e");
CollectFeatures("[thing] .f");
CollectFeatures(":hover .h");
AddTo(local1);
ClearFeatures();
ExpectRefCountForClassInvalidationSet(local1, "a", RefCount::kOne);
ExpectRefCountForIdInvalidationSet(local1, "d", RefCount::kOne);
ExpectRefCountForAttributeInvalidationSet(local1, "thing", RefCount::kOne);
ExpectRefCountForPseudoInvalidationSet(local1, CSSSelector::kPseudoHover,
RefCount::kOne);
// RuleFeatureSet local2 overlaps partially with local1.
RuleFeatureSet local2;
CollectFeatures(".a .c");
CollectFeatures("#d img");
AddTo(local2);
ClearFeatures();
ExpectRefCountForClassInvalidationSet(local2, "a", RefCount::kOne);
ExpectRefCountForIdInvalidationSet(local2, "d", RefCount::kOne);
// RuleFeatureSet local3 overlaps partially with local1, but not with local2.
RuleFeatureSet local3;
CollectFeatures("[thing] .g");
CollectFeatures(":hover .i");
AddTo(local3);
ClearFeatures();
ExpectRefCountForAttributeInvalidationSet(local3, "thing", RefCount::kOne);
ExpectRefCountForPseudoInvalidationSet(local3, CSSSelector::kPseudoHover,
RefCount::kOne);
// Using an empty RuleFeatureSet to simulate the global RuleFeatureSet:
RuleFeatureSet global;
// After adding local1, we expect to share the InvalidationSets with local1.
global.Add(local1);
ExpectRefCountForClassInvalidationSet(global, "a", RefCount::kMany);
ExpectRefCountForIdInvalidationSet(global, "d", RefCount::kMany);
ExpectRefCountForAttributeInvalidationSet(global, "thing", RefCount::kMany);
ExpectRefCountForPseudoInvalidationSet(global, CSSSelector::kPseudoHover,
RefCount::kMany);
// For the InvalidationSet keys that overlap with local1, |global| now had to
// copy the existing InvalidationSets at those keys before modifying them,
// so we expect |global| to be the only reference holder to those
// InvalidationSets.
global.Add(local2);
ExpectRefCountForClassInvalidationSet(global, "a", RefCount::kOne);
ExpectRefCountForIdInvalidationSet(global, "d", RefCount::kOne);
ExpectRefCountForAttributeInvalidationSet(global, "thing", RefCount::kMany);
ExpectRefCountForPseudoInvalidationSet(global, CSSSelector::kPseudoHover,
RefCount::kMany);
global.Add(local3);
ExpectRefCountForClassInvalidationSet(global, "a", RefCount::kOne);
ExpectRefCountForIdInvalidationSet(global, "d", RefCount::kOne);
ExpectRefCountForAttributeInvalidationSet(global, "thing", RefCount::kOne);
ExpectRefCountForPseudoInvalidationSet(global, CSSSelector::kPseudoHover,
RefCount::kOne);
}
TEST_F(RuleFeatureSetTest, CopyOnWrite_SiblingDescendantPairs) {
// Test data:
std::vector<const char*> data;
// Descendant.
data.push_back(".a .b0");
data.push_back(".a .b1");
// Sibling.
data.push_back(".a + .b2");
data.push_back(".a + .b3");
// Sibling with sibling descendants.
data.push_back(".a + .b4 .b5");
data.push_back(".a + .b6 .b7");
// Sibling with descendants.
data.push_back(".a + .b8, .a .b9");
data.push_back(".a + .b10, .a .b11");
// Sibling with sibling descendants and descendants.
data.push_back(".a + .b12 .b13, .a .b14");
data.push_back(".a + .b15 .b16, .a .b17");
// For each possible pair in |data|, make sure that we are properly sharing
// the InvalidationSet from |local1| until we add the InvalidationSet from
// |local2|.
for (const char* selector1 : data) {
for (const char* selector2 : data) {
RuleFeatureSet local1;
CollectFeatures(selector1);
AddTo(local1);
ClearFeatures();
RuleFeatureSet local2;
CollectFeatures(selector2);
AddTo(local2);
ClearFeatures();
RuleFeatureSet global;
global.Add(local1);
ExpectRefCountForClassInvalidationSet(global, "a", RefCount::kMany);
global.Add(local2);
ExpectRefCountForClassInvalidationSet(global, "a", RefCount::kOne);
}
}
}
TEST_F(RuleFeatureSetTest, CopyOnWrite_SelfInvalidation) {
RuleFeatureSet local1;
CollectFeatures(".a");
AddTo(local1);
ClearFeatures();
RuleFeatureSet local2;
CollectFeatures(".a");
AddTo(local2);
ClearFeatures();
// Adding the SelfInvalidationSet to the SelfInvalidationSet does not cause
// a copy.
RuleFeatureSet global;
global.Add(local1);
ExpectRefCountForClassInvalidationSet(global, "a", RefCount::kMany);
global.Add(local2);
ExpectRefCountForClassInvalidationSet(global, "a", RefCount::kMany);
}
} // namespace blink