| Index: third_party/WebKit/Source/core/dom/SelectorQueryTest.cpp
|
| diff --git a/third_party/WebKit/Source/core/dom/SelectorQueryTest.cpp b/third_party/WebKit/Source/core/dom/SelectorQueryTest.cpp
|
| index 3b28cdf9740e1efe490883b5c985d40734fede2b..2b8981aa9947aa82de35df0877b42258b59d5143 100644
|
| --- a/third_party/WebKit/Source/core/dom/SelectorQueryTest.cpp
|
| +++ b/third_party/WebKit/Source/core/dom/SelectorQueryTest.cpp
|
| @@ -4,16 +4,56 @@
|
|
|
| #include "core/dom/SelectorQuery.h"
|
|
|
| +#include <memory>
|
| #include "core/css/parser/CSSParser.h"
|
| #include "core/css/parser/CSSParserContext.h"
|
| #include "core/dom/Document.h"
|
| +#include "core/dom/StaticNodeList.h"
|
| #include "core/html/HTMLDocument.h"
|
| #include "core/html/HTMLHtmlElement.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
| -#include <memory>
|
|
|
| namespace blink {
|
|
|
| +namespace {
|
| +struct QueryTest {
|
| + const char* selector;
|
| + bool queryAll;
|
| + unsigned matches;
|
| + // {totalCount, fastId, fastClass, fastTagName, fastScan, slowScan,
|
| + // slowTraversingShadowTreeScan}
|
| + SelectorQuery::QueryStats stats;
|
| +};
|
| +
|
| +template <unsigned length>
|
| +void runTests(Document& document, const QueryTest (&testCases)[length]) {
|
| + for (const auto& testCase : testCases) {
|
| + const char* selector = testCase.selector;
|
| + SCOPED_TRACE(testing::Message() << (testCase.queryAll ? "querySelectorAll('"
|
| + : "querySelector('")
|
| + << selector << "')");
|
| + if (testCase.queryAll) {
|
| + StaticElementList* matchAll = document.querySelectorAll(selector);
|
| + EXPECT_EQ(testCase.matches, matchAll->length());
|
| + } else {
|
| + Element* match = document.querySelector(selector);
|
| + EXPECT_EQ(testCase.matches, match ? 1u : 0u);
|
| + }
|
| +#if DCHECK_IS_ON()
|
| + SelectorQuery::QueryStats stats = SelectorQuery::lastQueryStats();
|
| + EXPECT_EQ(testCase.stats.totalCount, stats.totalCount);
|
| + EXPECT_EQ(testCase.stats.fastId, stats.fastId);
|
| + EXPECT_EQ(testCase.stats.fastClass, stats.fastClass);
|
| + EXPECT_EQ(testCase.stats.fastTagName, stats.fastTagName);
|
| + EXPECT_EQ(testCase.stats.fastScan, stats.fastScan);
|
| + EXPECT_EQ(testCase.stats.slowScan, stats.slowScan);
|
| + EXPECT_EQ(testCase.stats.slowTraversingShadowTreeScan,
|
| + stats.slowTraversingShadowTreeScan);
|
| +#endif
|
| + }
|
| +}
|
| +};
|
| +
|
| TEST(SelectorQueryTest, NotMatchingPseudoElement) {
|
| Document* document = Document::create();
|
| HTMLHtmlElement* html = HTMLHtmlElement::create(*document);
|
| @@ -59,4 +99,114 @@ TEST(SelectorQueryTest, LastOfTypeNotFinishedParsing) {
|
| EXPECT_EQ("last", elm->idForStyleResolution());
|
| }
|
|
|
| +TEST(SelectorQueryTest, StandardsModeFastPaths) {
|
| + Document* document = HTMLDocument::create();
|
| + document->write(
|
| + "<!DOCTYPE html>"
|
| + "<html>"
|
| + " <head></head>"
|
| + " <body>"
|
| + " <span id=first class=A>"
|
| + " <span id=a class=one></span>"
|
| + " <span id=b class=two></span>"
|
| + " <span id=c class=one></span>"
|
| + " <div id=multiple class=two></div>"
|
| + " </span>"
|
| + " <div>"
|
| + " <span id=second class=B>"
|
| + " <span id=A class=one></span>"
|
| + " <span id=B class=two></span>"
|
| + " <span id=C class=one></span>"
|
| + " <span id=multiple class=two></span>"
|
| + " </span>"
|
| + " </div>"
|
| + " </body>"
|
| + "</html>");
|
| + static const struct QueryTest kTestCases[] = {
|
| + // Id in right most selector fast path.
|
| + {"#A", false, 1, {1, 1, 0, 0, 0, 0, 0}},
|
| + {"#multiple", false, 1, {1, 1, 0, 0, 0, 0, 0}},
|
| + {"#multiple.two", false, 1, {1, 1, 0, 0, 0, 0, 0}},
|
| + {"#multiple", true, 2, {2, 2, 0, 0, 0, 0, 0}},
|
| + {"span#multiple", true, 1, {2, 2, 0, 0, 0, 0, 0}},
|
| + {"#multiple.two", true, 2, {2, 2, 0, 0, 0, 0, 0}},
|
| + {"body #multiple", false, 1, {1, 1, 0, 0, 0, 0, 0}},
|
| + {"body span#multiple", false, 1, {2, 2, 0, 0, 0, 0, 0}},
|
| + {"body #multiple", true, 2, {2, 2, 0, 0, 0, 0, 0}},
|
| +
|
| + // Single selector tag fast path.
|
| + {"span", false, 1, {4, 0, 0, 4, 0, 0, 0}},
|
| + {"span", true, 9, {14, 0, 0, 14, 0, 0, 0}},
|
| +
|
| + // Single selector class fast path.
|
| + {".two", false, 1, {6, 0, 6, 0, 0, 0, 0}},
|
| + {".two", true, 4, {14, 0, 14, 0, 0, 0, 0}},
|
| +
|
| + // Class in the right most selector fast path.
|
| + {"body .two", false, 1, {6, 0, 0, 0, 6, 0, 0}},
|
| + {"div .two", false, 1, {12, 0, 0, 0, 12, 0, 0}},
|
| +
|
| + // Classes in the right most selector for querySelectorAll use a fast
|
| + // path.
|
| + {"body .two", true, 4, {14, 0, 14, 0, 0, 0, 0}},
|
| + {"div .two", true, 2, {14, 0, 14, 0, 0, 0, 0}},
|
| +
|
| + // TODO: querySelector disables the class fast path to favor the id, but
|
| + // this means some selectors always end up doing fastScan.
|
| + {"#second .two", false, 1, {2, 0, 0, 0, 2, 0, 0}},
|
| +
|
| + // TODO(esprehn): This should have used getElementById instead of doing
|
| + // a fastClass scan. It could have looked at 4 elements instead.
|
| + {"#second .two", true, 2, {14, 0, 14, 0, 0, 0, 0}},
|
| +
|
| + // Selectors with no classes or ids use the fast scan.
|
| + {":scope", false, 1, {1, 0, 0, 0, 1, 0, 0}},
|
| + {":scope", true, 1, {14, 0, 0, 0, 14, 0, 0}},
|
| + {"foo bar", false, 0, {14, 0, 0, 0, 14, 0, 0}},
|
| +
|
| + // Multiple selectors always uses the slow path.
|
| + // TODO(esprehn): We could make this fast if we sorted the output, not
|
| + // sure it's worth it unless we're dealing with ids.
|
| + {"#a, #b", false, 1, {5, 0, 0, 0, 0, 5, 0}},
|
| + {"#a, #b", true, 2, {14, 0, 0, 0, 0, 14, 0}},
|
| +
|
| + // Anything that crosses shadow boundaries is slow path.
|
| + {"#foo /deep/ .a", false, 0, {14, 0, 0, 0, 0, 0, 14}},
|
| + {"#foo::shadow .a", false, 0, {14, 0, 0, 0, 0, 0, 14}},
|
| + {"::content .a", false, 0, {14, 0, 0, 0, 0, 14, 0}},
|
| + {"#foo /deep/ .a", true, 0, {14, 0, 0, 0, 0, 0, 14}},
|
| + {"#foo::shadow .a", true, 0, {14, 0, 0, 0, 0, 0, 14}},
|
| + {"::content .a", true, 0, {14, 0, 0, 0, 0, 14, 0}},
|
| + };
|
| + runTests(*document, kTestCases);
|
| +}
|
| +
|
| +TEST(SelectorQueryTest, QuirksModeSlowPath) {
|
| + Document* document = HTMLDocument::create();
|
| + document->write(
|
| + "<html>"
|
| + " <head></head>"
|
| + " <body>"
|
| + " <span id=first>"
|
| + " <span id=One class=Two></span>"
|
| + " <span id=one class=tWo></span>"
|
| + " </span>"
|
| + " </body>"
|
| + "</html>");
|
| + static const struct QueryTest kTestCases[] = {
|
| + // Quirks mode always uses the slow path.
|
| + {"#one", false, 1, {5, 0, 0, 0, 0, 5, 0}},
|
| + {"#One", false, 1, {5, 0, 0, 0, 0, 5, 0}},
|
| + {"#ONE", false, 1, {5, 0, 0, 0, 0, 5, 0}},
|
| + {"#ONE", true, 2, {6, 0, 0, 0, 0, 6, 0}},
|
| + {"span", false, 1, {4, 0, 0, 0, 0, 4, 0}},
|
| + {"span", true, 3, {6, 0, 0, 0, 0, 6, 0}},
|
| + {".two", false, 1, {5, 0, 0, 0, 0, 5, 0}},
|
| + {".two", true, 2, {6, 0, 0, 0, 0, 6, 0}},
|
| + {"body #first", false, 1, {4, 0, 0, 0, 0, 4, 0}},
|
| + {"body #one", true, 2, {6, 0, 0, 0, 0, 6, 0}},
|
| + };
|
| + runTests(*document, kTestCases);
|
| +}
|
| +
|
| } // namespace blink
|
|
|