OLD | NEW |
---|---|
(Empty) | |
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 "core/dom/custom/CustomElementsRegistry.h" | |
6 | |
7 #include "bindings/core/v8/ExceptionState.h" | |
8 #include "core/dom/Document.h" | |
9 #include "core/dom/Element.h" | |
10 #include "core/dom/ElementRegistrationOptions.h" | |
11 #include "core/dom/custom/CustomElementDefinition.h" | |
12 #include "core/dom/custom/CustomElementDefinitionBuilder.h" | |
13 #include "core/dom/custom/CustomElementDescriptor.h" | |
14 #include "core/dom/custom/CustomElementTestHelpers.h" | |
15 #include "core/dom/shadow/ShadowRoot.h" | |
16 #include "core/dom/shadow/ShadowRootInit.h" | |
17 #include "core/html/HTMLDocument.h" | |
18 #include "core/testing/DummyPageHolder.h" | |
19 #include "platform/ScriptForbiddenScope.h" | |
20 #include "platform/heap/Handle.h" | |
21 #include "testing/gtest/include/gtest/gtest.h" | |
22 #include "wtf/OwnPtr.h" | |
23 #include "wtf/text/AtomicString.h" | |
24 | |
25 namespace blink { | |
26 | |
27 class CustomElementsRegistryTestBase : public ::testing::Test { | |
28 public: | |
yosin_UTC9
2016/06/01 06:15:45
No need to have public accessibility for Test clas
dominicc (has gone to gerrit)
2016/06/01 23:30:57
I suspect you're wrong about this; fixtures using
yosin_UTC9
2016/06/02 02:02:18
Sorry, my explanation is bad. I mean all members o
| |
29 virtual Document& document() = 0; | |
30 virtual CustomElementsRegistry& registry() = 0; | |
31 | |
32 void collectCandidates( | |
33 const CustomElementDescriptor& desc, | |
34 HeapVector<Member<Element>>* elements) | |
35 { | |
36 registry().collectCandidates(desc, elements); | |
37 } | |
38 }; | |
39 | |
40 class CustomElementsRegistryTest : public CustomElementsRegistryTestBase { | |
41 public: | |
yosin_UTC9
2016/06/01 06:15:44
No need to have public accessibility for Test clas
| |
42 Document& document() override { return *m_document; } | |
43 CustomElementsRegistry& registry() override { return *m_registry; } | |
44 | |
45 protected: | |
46 void SetUp() override | |
47 { | |
48 CustomElementsRegistryTestBase::SetUp(); | |
49 | |
50 m_document = HTMLDocument::create(); | |
51 m_document->appendChild(CreateElement("html").inDocument(m_document)); | |
52 | |
53 m_registry = CustomElementsRegistry::create(m_document); | |
54 } | |
55 | |
56 void TearDown() override | |
57 { | |
58 m_document = nullptr; | |
59 m_registry = nullptr; | |
60 CustomElementsRegistryTestBase::TearDown(); | |
61 } | |
62 | |
63 private: | |
64 Persistent<Document> m_document; | |
65 Persistent<CustomElementsRegistry> m_registry; | |
66 }; | |
67 | |
68 class CustomElementsRegistryFrameTest : public CustomElementsRegistryTestBase { | |
69 public: | |
yosin_UTC9
2016/06/01 06:15:45
No need to have public accessibility for Test clas
| |
70 Document& document() override { return m_page->document(); } | |
71 CustomElementsRegistry& registry() override | |
72 { | |
73 return *m_page->frame().localDOMWindow()->customElements(); | |
74 } | |
75 ScriptState* scriptState() | |
76 { | |
77 return ScriptState::forMainWorld(&m_page->frame()); | |
78 } | |
79 | |
80 ShadowRoot* attachShadowTo(Element* element) | |
81 { | |
82 NonThrowableExceptionState noExceptions; | |
83 ShadowRootInit shadowRootInit; | |
84 return | |
85 element->attachShadow(scriptState(), shadowRootInit, noExceptions); | |
86 } | |
87 | |
88 protected: | |
89 void SetUp() override | |
90 { | |
91 CustomElementsRegistryTestBase::SetUp(); | |
92 m_page = DummyPageHolder::create(IntSize(1, 1)); | |
93 } | |
94 | |
95 void TearDown() override | |
96 { | |
97 m_page = nullptr; | |
98 CustomElementsRegistryTestBase::TearDown(); | |
99 } | |
100 | |
101 private: | |
102 OwnPtr<DummyPageHolder> m_page; | |
yosin_UTC9
2016/06/01 06:15:45
nit: Let's use std::unique_ptr<DummyPageHolder>
| |
103 }; | |
104 | |
105 TEST_F( | |
106 CustomElementsRegistryTest, | |
107 collectCandidates_shouldNotIncludeElementsRemovedFromDocument) | |
108 { | |
109 Element* element = CreateElement("a-a").inDocument(&document()); | |
110 registry().addCandidate(element); | |
111 | |
112 HeapVector<Member<Element>> elements; | |
113 collectCandidates( | |
114 CustomElementDescriptor("a-a", "a-a"), | |
115 &elements); | |
116 | |
117 EXPECT_EQ(0u, elements.size()) | |
yosin_UTC9
2016/06/01 06:15:45
nit: isEmpty() is more readable.
dominicc (has gone to gerrit)
2016/06/01 23:30:57
True; this produces a more useful failure. With is
yosin_UTC9
2016/06/02 02:02:18
How about:
EXPECT_TRUE(elements.isEmpty()) << "no
| |
118 << "no candidates should have been found"; | |
119 EXPECT_FALSE(elements.contains(element)) | |
120 << "the out-of-document candidate should not have been found"; | |
121 } | |
122 | |
123 TEST_F( | |
124 CustomElementsRegistryTest, | |
125 collectCandidates_shouldNotIncludeElementsInDifferentDocument) | |
126 { | |
127 Element* element = CreateElement("a-a").inDocument(&document()); | |
128 registry().addCandidate(element); | |
129 | |
130 Document* otherDocument = HTMLDocument::create(); | |
131 otherDocument->appendChild(element); | |
132 EXPECT_EQ(otherDocument, element->ownerDocument()) | |
133 << "sanity: another document should have adopted an element on append"; | |
134 | |
135 HeapVector<Member<Element>> elements; | |
136 collectCandidates( | |
137 CustomElementDescriptor("a-a", "a-a"), | |
138 &elements); | |
139 | |
140 EXPECT_EQ(0u, elements.size()) | |
141 << "no candidates should have been found"; | |
142 EXPECT_FALSE(elements.contains(element)) | |
143 << "the adopted-away candidate should not have been found"; | |
144 } | |
145 | |
146 TEST_F( | |
147 CustomElementsRegistryTest, | |
148 collectCandidates_shouldOnlyIncludeCandidatesMatchingDescriptor) | |
149 { | |
150 CustomElementDescriptor descriptor("hello-world", "hello-world"); | |
151 | |
152 // Does not match: namespace is not HTML | |
153 Element* a = CreateElement("hello-world") | |
yosin_UTC9
2016/06/01 06:15:45
Please avoid to use one letter variable name.
| |
154 .inDocument(&document()) | |
155 .inNamespace("data:text/date,1981-03-10"); | |
156 // Matches | |
157 Element* b = CreateElement("hello-world").inDocument(&document()); | |
158 // Does not match: local name is not hello-world | |
159 Element* c = CreateElement("button") | |
160 .inDocument(&document()) | |
161 .withIsAttribute("hello-world"); | |
162 document().documentElement()->appendChild(a); | |
163 a->appendChild(b); | |
164 a->appendChild(c); | |
165 | |
166 registry().addCandidate(a); | |
167 registry().addCandidate(b); | |
168 registry().addCandidate(c); | |
169 | |
170 HeapVector<Member<Element>> elements; | |
171 collectCandidates(descriptor, &elements); | |
172 | |
173 EXPECT_EQ(1u, elements.size()) | |
174 << "only one candidates should have been found"; | |
175 EXPECT_EQ(b, elements[0]) | |
176 << "the matching element should have been found"; | |
177 } | |
178 | |
179 TEST_F(CustomElementsRegistryTest, collectCandidates_oneCandidate) | |
180 { | |
181 Element* element = CreateElement("a-a").inDocument(&document()); | |
182 registry().addCandidate(element); | |
183 document().documentElement()->appendChild(element); | |
184 | |
185 HeapVector<Member<Element>> elements; | |
186 collectCandidates( | |
187 CustomElementDescriptor("a-a", "a-a"), | |
188 &elements); | |
189 | |
190 EXPECT_EQ(1u, elements.size()) | |
191 << "exactly one candidate should have been found"; | |
192 EXPECT_TRUE(elements.contains(element)) | |
193 << "the candidate should be the element that was added"; | |
194 } | |
195 | |
196 TEST_F(CustomElementsRegistryTest, collectCandidates_shouldBeInDocumentOrder) | |
197 { | |
198 CreateElement& factory = CreateElement("a-a").inDocument(&document()); | |
199 Element* a = factory.withId("a"); | |
200 Element* b = factory.withId("b"); | |
201 Element* c = factory.withId("c"); | |
202 | |
203 registry().addCandidate(b); | |
204 registry().addCandidate(a); | |
205 registry().addCandidate(c); | |
206 | |
207 document().documentElement()->appendChild(a); | |
208 a->appendChild(b); | |
209 document().documentElement()->appendChild(c); | |
210 | |
211 HeapVector<Member<Element>> elements; | |
212 collectCandidates( | |
213 CustomElementDescriptor("a-a", "a-a"), | |
214 &elements); | |
215 | |
216 EXPECT_EQ(a, elements[0].get()); | |
217 EXPECT_EQ(b, elements[1].get()); | |
218 EXPECT_EQ(c, elements[2].get()); | |
219 } | |
220 | |
221 class TestCustomElementDefinition : public CustomElementDefinition { | |
222 WTF_MAKE_NONCOPYABLE(TestCustomElementDefinition); | |
223 public: | |
224 TestCustomElementDefinition(const CustomElementDescriptor& descriptor) | |
225 : CustomElementDefinition(descriptor) | |
226 { | |
227 } | |
228 | |
229 virtual ~TestCustomElementDefinition() = default; | |
230 | |
231 bool runConstructor(Element* element) override | |
232 { | |
233 if (constructionStack().isEmpty() | |
234 || constructionStack().last() != element) | |
235 return false; | |
236 constructionStack().last().clear(); | |
237 return true; | |
238 } | |
239 }; | |
240 | |
241 // Classes which use trace macros cannot be local because of the | |
242 // traceImpl template. | |
243 class LogUpgradeDefinition : public TestCustomElementDefinition { | |
244 WTF_MAKE_NONCOPYABLE(LogUpgradeDefinition); | |
245 public: | |
246 LogUpgradeDefinition(const CustomElementDescriptor& descriptor) | |
247 : TestCustomElementDefinition(descriptor) | |
248 { | |
249 } | |
250 | |
251 DEFINE_INLINE_VIRTUAL_TRACE() | |
252 { | |
253 TestCustomElementDefinition::trace(visitor); | |
254 visitor->trace(m_element); | |
255 } | |
256 | |
257 // TODO(dominicc): Make this class collect a vector of what's | |
258 // upgraded; it will be useful in more tests. | |
259 Member<Element> m_element; | |
260 uint32_t m_invocationCount; | |
261 | |
262 bool runConstructor(Element* element) override | |
263 { | |
264 m_invocationCount++; | |
265 m_element = element; | |
266 return TestCustomElementDefinition::runConstructor(element); | |
267 } | |
268 }; | |
269 | |
270 class LogUpgradeBuilder final : public CustomElementDefinitionBuilder { | |
271 STACK_ALLOCATED(); | |
272 WTF_MAKE_NONCOPYABLE(LogUpgradeBuilder); | |
273 public: | |
274 LogUpgradeBuilder() { } | |
275 | |
276 bool checkConstructorIntrinsics() override { return true; } | |
277 bool checkConstructorNotRegistered() override { return true; } | |
278 bool checkPrototype() override { return true; } | |
279 CustomElementDefinition* build( | |
280 const CustomElementDescriptor& descriptor) { | |
281 return new LogUpgradeDefinition(descriptor); | |
282 } | |
283 }; | |
284 | |
285 TEST_F(CustomElementsRegistryFrameTest, define_upgradesInDocumentElements) | |
286 { | |
287 ScriptForbiddenScope doNotRelyOnScript; | |
288 | |
289 Element* element = CreateElement("a-a").inDocument(&document()); | |
290 document().documentElement()->appendChild(element); | |
291 | |
292 LogUpgradeBuilder builder; | |
293 NonThrowableExceptionState shouldNotThrow; | |
294 registry().define( | |
295 "a-a", | |
296 builder, | |
297 ElementRegistrationOptions(), | |
298 shouldNotThrow); | |
299 LogUpgradeDefinition* definition = | |
300 static_cast<LogUpgradeDefinition*>(registry().definitionForName("a-a")); | |
301 EXPECT_EQ(1u, definition->m_invocationCount) | |
302 << "defining the element should have 'upgraded' the existing element"; | |
303 EXPECT_EQ(element, definition->m_element) | |
304 << "the existing a-a element should have been upgraded"; | |
305 } | |
306 | |
307 // TODO(dominicc): Add tests which adjust the "is" attribute when type | |
308 // extensions are implemented. | |
309 | |
310 } // namespace blink | |
OLD | NEW |