Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(191)

Unified Diff: third_party/WebKit/Source/core/dom/SelectorQueryTest.cpp

Issue 2797083002: Test cases for querySelector fast paths. (Closed)
Patch Set: Working tests. Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « third_party/WebKit/Source/core/dom/SelectorQuery.cpp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « third_party/WebKit/Source/core/dom/SelectorQuery.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698