blob: aee36a488d7798bed162eb7eab6fe18cc9682ba9 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// 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/check_pseudo_has_fast_reject_filter.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/css/check_pseudo_has_argument_context.h"
#include "third_party/blink/renderer/core/css/css_selector_list.h"
#include "third_party/blink/renderer/core/css/css_test_helpers.h"
#include "third_party/blink/renderer/core/dom/document.h"
#include "third_party/blink/renderer/core/html_names.h"
#include "third_party/blink/renderer/core/testing/page_test_base.h"
namespace blink {
class CheckPseudoHasFastRejectFilterTest : public PageTestBase {
protected:
struct ElementInfo {
const char* tag_name;
const char* id;
const char* class_names;
const char* attribute_name;
const char* attribute_value;
};
template <unsigned length>
void AddElementIdentifierHashes(
CheckPseudoHasFastRejectFilter& filter,
const ElementInfo (&element_info_list)[length]) {
for (unsigned i = 0; i < length; i++) {
NonThrowableExceptionState no_exceptions;
Element* element = GetDocument().CreateElementForBinding(
AtomicString(element_info_list[i].tag_name), nullptr, no_exceptions);
element->setAttribute(html_names::kIdAttr,
AtomicString(element_info_list[i].id));
element->setAttribute(html_names::kClassAttr,
AtomicString(element_info_list[i].class_names));
element->setAttribute(AtomicString(element_info_list[i].attribute_name),
AtomicString(element_info_list[i].attribute_value));
filter.AddElementIdentifierHashes(*element);
}
}
bool CheckFastReject(CheckPseudoHasFastRejectFilter& filter,
const char* selector_text) {
CSSSelectorList* selector_list =
css_test_helpers::ParseSelectorList(selector_text);
EXPECT_EQ(selector_list->First()->GetPseudoType(), CSSSelector::kPseudoHas);
CheckPseudoHasArgumentContext context(
selector_list->First()->SelectorList()->First());
return filter.FastReject(context.GetPseudoHasArgumentHashes());
}
};
TEST_F(CheckPseudoHasFastRejectFilterTest, CheckFastReject) {
CheckPseudoHasFastRejectFilter filter;
EXPECT_FALSE(filter.BloomFilterAllocated());
filter.AllocateBloomFilter();
EXPECT_TRUE(filter.BloomFilterAllocated());
AddElementIdentifierHashes(
filter, {{/* tag_name */ "div", /* id */ "d1", /* class_names */ "a",
/* attribute_name */ "attr1", /* attribute_value */ "val1"},
{/* tag_name */ "div", /* id */ "d2", /* class_names */ "b",
/* attribute_name */ "attr2", /* attribute_value */ "val2"},
{/* tag_name */ "span", /* id */ "s1", /* class_names */ "c",
/* attribute_name */ "attr3", /* attribute_value */ "val3"},
{/* tag_name */ "span", /* id */ "s2", /* class_names */ "d",
/* attribute_name */ "attr4", /* attribute_value */ "val4"}});
EXPECT_FALSE(CheckFastReject(filter, ":has(div)"));
EXPECT_FALSE(CheckFastReject(filter, ":has(span)"));
EXPECT_TRUE(CheckFastReject(filter, ":has(h1)"));
EXPECT_TRUE(CheckFastReject(filter, ":has(#div)"));
EXPECT_TRUE(CheckFastReject(filter, ":has(.div)"));
EXPECT_TRUE(CheckFastReject(filter, ":has([div])"));
EXPECT_TRUE(CheckFastReject(filter, ":has([div=div])"));
EXPECT_FALSE(CheckFastReject(filter, ":has(#d1)"));
EXPECT_FALSE(CheckFastReject(filter, ":has(#d2)"));
EXPECT_TRUE(CheckFastReject(filter, ":has(#d3)"));
EXPECT_FALSE(CheckFastReject(filter, ":has(#s1)"));
EXPECT_FALSE(CheckFastReject(filter, ":has(#s2)"));
EXPECT_TRUE(CheckFastReject(filter, ":has(#s3)"));
EXPECT_TRUE(CheckFastReject(filter, ":has(d1)"));
EXPECT_TRUE(CheckFastReject(filter, ":has(.d1)"));
EXPECT_TRUE(CheckFastReject(filter, ":has([d1])"));
EXPECT_TRUE(CheckFastReject(filter, ":has([d1=d1])"));
EXPECT_FALSE(CheckFastReject(filter, ":has(.a)"));
EXPECT_FALSE(CheckFastReject(filter, ":has(.b)"));
EXPECT_FALSE(CheckFastReject(filter, ":has(.c)"));
EXPECT_FALSE(CheckFastReject(filter, ":has(.d)"));
EXPECT_TRUE(CheckFastReject(filter, ":has(.e)"));
EXPECT_TRUE(CheckFastReject(filter, ":has(a)"));
EXPECT_TRUE(CheckFastReject(filter, ":has(#a)"));
EXPECT_TRUE(CheckFastReject(filter, ":has([a])"));
EXPECT_TRUE(CheckFastReject(filter, ":has([a=a])"));
EXPECT_FALSE(CheckFastReject(filter, ":has([attr1])"));
EXPECT_FALSE(CheckFastReject(filter, ":has([attr2])"));
EXPECT_FALSE(CheckFastReject(filter, ":has([attr3])"));
EXPECT_FALSE(CheckFastReject(filter, ":has([attr4])"));
EXPECT_FALSE(CheckFastReject(filter, ":has([attr1=x])"));
EXPECT_FALSE(CheckFastReject(filter, ":has([attr2=x])"));
EXPECT_FALSE(CheckFastReject(filter, ":has([attr3=x])"));
EXPECT_FALSE(CheckFastReject(filter, ":has([attr4=x])"));
EXPECT_TRUE(CheckFastReject(filter, ":has(attr1)"));
EXPECT_TRUE(CheckFastReject(filter, ":has(#attr1)"));
EXPECT_TRUE(CheckFastReject(filter, ":has(.attr1)"));
EXPECT_FALSE(CheckFastReject(filter, ":has(div#d1.a[attr1=val1])"));
EXPECT_FALSE(CheckFastReject(filter, ":has(span#d1.a[attr1=val1])"));
EXPECT_FALSE(CheckFastReject(filter, ":has(div#s1.a[attr1=val1])"));
EXPECT_FALSE(CheckFastReject(filter, ":has(div#d1.c[attr1=val1])"));
EXPECT_TRUE(CheckFastReject(filter, ":has(h1#d1.a[attr1=val1])"));
EXPECT_TRUE(CheckFastReject(filter, ":has(div#d3.a[attr1=val1])"));
EXPECT_TRUE(CheckFastReject(filter, ":has(div#d1.e[attr1=val1])"));
EXPECT_TRUE(CheckFastReject(filter, ":has(div#d1.a[attr5=val1])"));
EXPECT_TRUE(CheckFastReject(filter, ":has(div#div.a[attr1=val1])"));
EXPECT_TRUE(CheckFastReject(filter, ":has(div#d1.div[attr1=val1])"));
EXPECT_TRUE(CheckFastReject(filter, ":has(div#d1.a[div=val1])"));
EXPECT_TRUE(CheckFastReject(filter, ":has(d1#d1.a[attr1=val1])"));
EXPECT_TRUE(CheckFastReject(filter, ":has(div#d1.d1[attr1=val1])"));
EXPECT_TRUE(CheckFastReject(filter, ":has(div#d1.a[d1=val1])"));
EXPECT_TRUE(CheckFastReject(filter, ":has(a#d1.a[attr1=val1])"));
EXPECT_TRUE(CheckFastReject(filter, ":has(div#a.a[attr1=val1])"));
EXPECT_TRUE(CheckFastReject(filter, ":has(div#d1.a[a=val1])"));
}
} // namespace blink