1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "third_party/blink/renderer/core/html/custom/custom_element_upgrade_sorter.h"
6
7 #include "testing/gtest/include/gtest/gtest.h"
8 #include "third_party/blink/renderer/bindings/core/v8/string_or_element_creation_options.h"
9 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
10 #include "third_party/blink/renderer/bindings/core/v8/v8_shadow_root_init.h"
11 #include "third_party/blink/renderer/core/dom/document.h"
12 #include "third_party/blink/renderer/core/dom/element.h"
13 #include "third_party/blink/renderer/core/dom/shadow_root.h"
14 #include "third_party/blink/renderer/core/html/html_document.h"
15 #include "third_party/blink/renderer/core/html_names.h"
16 #include "third_party/blink/renderer/core/testing/page_test_base.h"
17 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
18 #include "third_party/blink/renderer/platform/heap/handle.h"
19 #include "third_party/blink/renderer/platform/heap/heap.h"
20 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
21
22 namespace blink {
23
24 class CustomElementUpgradeSorterTest : public PageTestBase {
25 protected:
SetUp()26 void SetUp() override { PageTestBase::SetUp(IntSize(1, 1)); }
27
CreateElementWithId(const char * local_name,const char * id)28 Element* CreateElementWithId(const char* local_name, const char* id) {
29 NonThrowableExceptionState no_exceptions;
30 Element* element = GetDocument().CreateElementForBinding(
31 local_name, StringOrElementCreationOptions(), no_exceptions);
32 element->setAttribute(html_names::kIdAttr, id);
33 return element;
34 }
35
GetScriptState()36 ScriptState* GetScriptState() {
37 return ToScriptStateForMainWorld(&GetFrame());
38 }
39 };
40
TEST_F(CustomElementUpgradeSorterTest,inOtherDocument_notInSet)41 TEST_F(CustomElementUpgradeSorterTest, inOtherDocument_notInSet) {
42 NonThrowableExceptionState no_exceptions;
43 Element* element = GetDocument().CreateElementForBinding(
44 "a-a", StringOrElementCreationOptions(), no_exceptions);
45
46 auto* other_document = MakeGarbageCollected<HTMLDocument>();
47 other_document->AppendChild(element);
48 EXPECT_EQ(other_document, element->ownerDocument())
49 << "sanity: another document should have adopted an element on append";
50
51 CustomElementUpgradeSorter sorter;
52 sorter.Add(element);
53
54 HeapVector<Member<Element>> elements;
55 sorter.Sorted(&elements, &GetDocument());
56 EXPECT_EQ(0u, elements.size())
57 << "the adopted-away candidate should not have been included";
58 }
59
TEST_F(CustomElementUpgradeSorterTest,oneCandidate)60 TEST_F(CustomElementUpgradeSorterTest, oneCandidate) {
61 NonThrowableExceptionState no_exceptions;
62 Element* element = GetDocument().CreateElementForBinding(
63 "a-a", StringOrElementCreationOptions(), no_exceptions);
64 GetDocument().documentElement()->AppendChild(element);
65
66 CustomElementUpgradeSorter sorter;
67 sorter.Add(element);
68
69 HeapVector<Member<Element>> elements;
70 sorter.Sorted(&elements, &GetDocument());
71 EXPECT_EQ(1u, elements.size())
72 << "exactly one candidate should be in the result set";
73 EXPECT_TRUE(elements.Contains(element))
74 << "the candidate should be the element that was added";
75 }
76
TEST_F(CustomElementUpgradeSorterTest,candidatesInDocumentOrder)77 TEST_F(CustomElementUpgradeSorterTest, candidatesInDocumentOrder) {
78 Element* a = CreateElementWithId("a-a", "a");
79 Element* b = CreateElementWithId("a-a", "b");
80 Element* c = CreateElementWithId("a-a", "c");
81
82 GetDocument().documentElement()->AppendChild(a);
83 a->AppendChild(b);
84 GetDocument().documentElement()->AppendChild(c);
85
86 CustomElementUpgradeSorter sorter;
87 sorter.Add(b);
88 sorter.Add(a);
89 sorter.Add(c);
90
91 HeapVector<Member<Element>> elements;
92 sorter.Sorted(&elements, &GetDocument());
93 EXPECT_EQ(3u, elements.size());
94 EXPECT_EQ(a, elements[0].Get());
95 EXPECT_EQ(b, elements[1].Get());
96 EXPECT_EQ(c, elements[2].Get());
97 }
98
TEST_F(CustomElementUpgradeSorterTest,sorter_ancestorInSet)99 TEST_F(CustomElementUpgradeSorterTest, sorter_ancestorInSet) {
100 // A*
101 // + B
102 // + C*
103 Element* a = CreateElementWithId("a-a", "a");
104 Element* b = CreateElementWithId("a-a", "b");
105 Element* c = CreateElementWithId("a-a", "c");
106
107 GetDocument().documentElement()->AppendChild(a);
108 a->AppendChild(b);
109 b->AppendChild(c);
110
111 CustomElementUpgradeSorter sort;
112 sort.Add(c);
113 sort.Add(a);
114
115 HeapVector<Member<Element>> elements;
116 sort.Sorted(&elements, &GetDocument());
117 EXPECT_EQ(2u, elements.size());
118 EXPECT_EQ(a, elements[0].Get());
119 EXPECT_EQ(c, elements[1].Get());
120 }
121
TEST_F(CustomElementUpgradeSorterTest,sorter_deepShallow)122 TEST_F(CustomElementUpgradeSorterTest, sorter_deepShallow) {
123 // A
124 // + B*
125 // C*
126 Element* a = CreateElementWithId("a-a", "a");
127 Element* b = CreateElementWithId("a-a", "b");
128 Element* c = CreateElementWithId("a-a", "c");
129
130 GetDocument().documentElement()->AppendChild(a);
131 a->AppendChild(b);
132 GetDocument().documentElement()->AppendChild(c);
133
134 CustomElementUpgradeSorter sort;
135 sort.Add(b);
136 sort.Add(c);
137
138 HeapVector<Member<Element>> elements;
139 sort.Sorted(&elements, &GetDocument());
140 EXPECT_EQ(2u, elements.size());
141 EXPECT_EQ(b, elements[0].Get());
142 EXPECT_EQ(c, elements[1].Get());
143 }
144
TEST_F(CustomElementUpgradeSorterTest,sorter_shallowDeep)145 TEST_F(CustomElementUpgradeSorterTest, sorter_shallowDeep) {
146 // A*
147 // B
148 // + C*
149 Element* a = CreateElementWithId("a-a", "a");
150 Element* b = CreateElementWithId("a-a", "b");
151 Element* c = CreateElementWithId("a-a", "c");
152
153 GetDocument().documentElement()->AppendChild(a);
154 GetDocument().documentElement()->AppendChild(b);
155 b->AppendChild(c);
156
157 CustomElementUpgradeSorter sort;
158 sort.Add(a);
159 sort.Add(c);
160
161 HeapVector<Member<Element>> elements;
162 sort.Sorted(&elements, &GetDocument());
163 EXPECT_EQ(2u, elements.size());
164 EXPECT_EQ(a, elements[0].Get());
165 EXPECT_EQ(c, elements[1].Get());
166 }
167
TEST_F(CustomElementUpgradeSorterTest,sorter_shadow)168 TEST_F(CustomElementUpgradeSorterTest, sorter_shadow) {
169 // A*
170 // + {ShadowRoot}
171 // | + B
172 // | + C*
173 // + D*
174 Element* a = CreateElementWithId("a-a", "a");
175 Element* b = CreateElementWithId("a-a", "b");
176 Element* c = CreateElementWithId("a-a", "c");
177 Element* d = CreateElementWithId("a-a", "d");
178
179 GetDocument().documentElement()->AppendChild(a);
180 ShadowRoot* s = &a->AttachShadowRootInternal(ShadowRootType::kOpen);
181 a->AppendChild(d);
182
183 s->AppendChild(b);
184 b->AppendChild(c);
185
186 CustomElementUpgradeSorter sort;
187 sort.Add(a);
188 sort.Add(c);
189 sort.Add(d);
190
191 HeapVector<Member<Element>> elements;
192 sort.Sorted(&elements, &GetDocument());
193 EXPECT_EQ(3u, elements.size());
194 EXPECT_EQ(a, elements[0].Get());
195 EXPECT_EQ(c, elements[1].Get());
196 EXPECT_EQ(d, elements[2].Get());
197 }
198
199 } // namespace blink
200