• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Embedded Framework Authors. All rights
2 // reserved. Use of this source code is governed by a BSD-style license that
3 // can be found in the LICENSE file.
4 
5 #include "include/cef_dom.h"
6 #include "tests/ceftests/test_handler.h"
7 #include "tests/gtest/include/gtest/gtest.h"
8 #include "tests/shared/renderer/client_app_renderer.h"
9 
10 using client::ClientAppRenderer;
11 
12 namespace {
13 
14 const char* kTestUrl = "http://tests/DOMTest.Test";
15 const char* kTestMessage = "DOMTest.Message";
16 
17 enum DOMTestType {
18   DOM_TEST_STRUCTURE,
19   DOM_TEST_MODIFY,
20 };
21 
22 class TestDOMVisitor : public CefDOMVisitor {
23  public:
TestDOMVisitor(CefRefPtr<CefBrowser> browser,DOMTestType test_type)24   explicit TestDOMVisitor(CefRefPtr<CefBrowser> browser, DOMTestType test_type)
25       : browser_(browser), test_type_(test_type) {}
26 
TestHeadNodeStructure(CefRefPtr<CefDOMNode> headNode)27   void TestHeadNodeStructure(CefRefPtr<CefDOMNode> headNode) {
28     EXPECT_TRUE(headNode.get());
29     EXPECT_TRUE(headNode->IsElement());
30     EXPECT_FALSE(headNode->IsText());
31     EXPECT_EQ(headNode->GetName(), "HEAD");
32     EXPECT_EQ(headNode->GetElementTagName(), "HEAD");
33 
34     EXPECT_TRUE(headNode->HasChildren());
35     EXPECT_FALSE(headNode->HasElementAttributes());
36 
37     CefRefPtr<CefDOMNode> titleNode = headNode->GetFirstChild();
38     EXPECT_TRUE(titleNode.get());
39     EXPECT_TRUE(titleNode->IsElement());
40     EXPECT_FALSE(titleNode->IsText());
41     EXPECT_EQ(titleNode->GetName(), "TITLE");
42     EXPECT_EQ(titleNode->GetElementTagName(), "TITLE");
43     EXPECT_TRUE(titleNode->GetParent()->IsSame(headNode));
44 
45     EXPECT_FALSE(titleNode->GetNextSibling().get());
46     EXPECT_FALSE(titleNode->GetPreviousSibling().get());
47     EXPECT_TRUE(titleNode->HasChildren());
48     EXPECT_FALSE(titleNode->HasElementAttributes());
49 
50     CefRefPtr<CefDOMNode> textNode = titleNode->GetFirstChild();
51     EXPECT_TRUE(textNode.get());
52     EXPECT_FALSE(textNode->IsElement());
53     EXPECT_TRUE(textNode->IsText());
54     EXPECT_EQ(textNode->GetValue(), "The Title");
55     EXPECT_TRUE(textNode->GetParent()->IsSame(titleNode));
56 
57     EXPECT_FALSE(textNode->GetNextSibling().get());
58     EXPECT_FALSE(textNode->GetPreviousSibling().get());
59     EXPECT_FALSE(textNode->HasChildren());
60   }
61 
TestBodyNodeStructure(CefRefPtr<CefDOMNode> bodyNode)62   void TestBodyNodeStructure(CefRefPtr<CefDOMNode> bodyNode) {
63     EXPECT_TRUE(bodyNode.get());
64     EXPECT_TRUE(bodyNode->IsElement());
65     EXPECT_FALSE(bodyNode->IsText());
66     EXPECT_EQ(bodyNode->GetName(), "BODY");
67     EXPECT_EQ(bodyNode->GetElementTagName(), "BODY");
68 
69     EXPECT_TRUE(bodyNode->HasChildren());
70     EXPECT_FALSE(bodyNode->HasElementAttributes());
71 
72     CefRefPtr<CefDOMNode> h1Node = bodyNode->GetFirstChild();
73     EXPECT_TRUE(h1Node.get());
74     EXPECT_TRUE(h1Node->IsElement());
75     EXPECT_FALSE(h1Node->IsText());
76     EXPECT_EQ(h1Node->GetName(), "H1");
77     EXPECT_EQ(h1Node->GetElementTagName(), "H1");
78 
79     EXPECT_TRUE(h1Node->GetNextSibling().get());
80     EXPECT_FALSE(h1Node->GetPreviousSibling().get());
81     EXPECT_TRUE(h1Node->HasChildren());
82     EXPECT_FALSE(h1Node->HasElementAttributes());
83 
84     CefRefPtr<CefDOMNode> textNode = h1Node->GetFirstChild();
85     EXPECT_TRUE(textNode.get());
86     EXPECT_FALSE(textNode->IsElement());
87     EXPECT_TRUE(textNode->IsText());
88     EXPECT_EQ(textNode->GetValue(), "Hello From");
89 
90     EXPECT_FALSE(textNode->GetPreviousSibling().get());
91     EXPECT_FALSE(textNode->HasChildren());
92 
93     CefRefPtr<CefDOMNode> brNode = textNode->GetNextSibling();
94     EXPECT_TRUE(brNode.get());
95     EXPECT_TRUE(brNode->IsElement());
96     EXPECT_FALSE(brNode->IsText());
97     EXPECT_EQ(brNode->GetName(), "BR");
98     EXPECT_EQ(brNode->GetElementTagName(), "BR");
99 
100     EXPECT_FALSE(brNode->HasChildren());
101 
102     EXPECT_TRUE(brNode->HasElementAttributes());
103     EXPECT_TRUE(brNode->HasElementAttribute("class"));
104     EXPECT_EQ(brNode->GetElementAttribute("class"), "some_class");
105     EXPECT_TRUE(brNode->HasElementAttribute("id"));
106     EXPECT_EQ(brNode->GetElementAttribute("id"), "some_id");
107     EXPECT_FALSE(brNode->HasElementAttribute("no_existing"));
108 
109     CefDOMNode::AttributeMap map;
110     brNode->GetElementAttributes(map);
111     ASSERT_EQ(map.size(), (size_t)2);
112     EXPECT_EQ(map["class"], "some_class");
113     EXPECT_EQ(map["id"], "some_id");
114 
115     // Can also retrieve by ID.
116     brNode = bodyNode->GetDocument()->GetElementById("some_id");
117     EXPECT_TRUE(brNode.get());
118     EXPECT_TRUE(brNode->IsElement());
119     EXPECT_FALSE(brNode->IsText());
120     EXPECT_EQ(brNode->GetName(), "BR");
121     EXPECT_EQ(brNode->GetElementTagName(), "BR");
122 
123     textNode = brNode->GetNextSibling();
124     EXPECT_TRUE(textNode.get());
125     EXPECT_FALSE(textNode->IsElement());
126     EXPECT_TRUE(textNode->IsText());
127     EXPECT_EQ(textNode->GetValue(), "Main Frame");
128 
129     EXPECT_FALSE(textNode->GetNextSibling().get());
130     EXPECT_FALSE(textNode->HasChildren());
131 
132     CefRefPtr<CefDOMNode> divNode = h1Node->GetNextSibling();
133     EXPECT_TRUE(divNode.get());
134     EXPECT_TRUE(divNode->IsElement());
135     EXPECT_FALSE(divNode->IsText());
136     CefRect divRect = divNode->GetElementBounds();
137     EXPECT_EQ(divRect.width, 50);
138     EXPECT_EQ(divRect.height, 25);
139     EXPECT_EQ(divRect.x, 150);
140     EXPECT_EQ(divRect.y, 100);
141     EXPECT_FALSE(divNode->GetNextSibling().get());
142   }
143 
144   // Test document structure by iterating through the DOM tree.
TestStructure(CefRefPtr<CefDOMDocument> document)145   void TestStructure(CefRefPtr<CefDOMDocument> document) {
146     EXPECT_EQ(document->GetTitle(), "The Title");
147     EXPECT_EQ(document->GetBaseURL(), kTestUrl);
148     EXPECT_EQ(document->GetCompleteURL("foo.html"), "http://tests/foo.html");
149 
150     // Navigate the complete document structure.
151     CefRefPtr<CefDOMNode> docNode = document->GetDocument();
152     EXPECT_TRUE(docNode.get());
153     EXPECT_FALSE(docNode->IsElement());
154     EXPECT_FALSE(docNode->IsText());
155 
156     CefRefPtr<CefDOMNode> htmlNode = docNode->GetFirstChild();
157     EXPECT_TRUE(htmlNode.get());
158     EXPECT_TRUE(htmlNode->IsElement());
159     EXPECT_FALSE(htmlNode->IsText());
160     EXPECT_EQ(htmlNode->GetName(), "HTML");
161     EXPECT_EQ(htmlNode->GetElementTagName(), "HTML");
162 
163     EXPECT_TRUE(htmlNode->HasChildren());
164     EXPECT_FALSE(htmlNode->HasElementAttributes());
165 
166     CefRefPtr<CefDOMNode> headNode = htmlNode->GetFirstChild();
167     TestHeadNodeStructure(headNode);
168 
169     CefRefPtr<CefDOMNode> bodyNode = headNode->GetNextSibling();
170     TestBodyNodeStructure(bodyNode);
171 
172     // Retrieve the head node directly.
173     headNode = document->GetHead();
174     TestHeadNodeStructure(headNode);
175 
176     // Retrieve the body node directly.
177     bodyNode = document->GetBody();
178     TestBodyNodeStructure(bodyNode);
179   }
180 
181   // Test document modification by changing the H1 tag.
TestModify(CefRefPtr<CefDOMDocument> document)182   void TestModify(CefRefPtr<CefDOMDocument> document) {
183     CefRefPtr<CefDOMNode> bodyNode = document->GetBody();
184     CefRefPtr<CefDOMNode> h1Node = bodyNode->GetFirstChild();
185 
186     ASSERT_EQ(h1Node->GetAsMarkup(),
187               "<h1>Hello From<br class=\"some_class\" id=\"some_id\">"
188               "Main Frame</h1>");
189 
190     CefRefPtr<CefDOMNode> textNode = h1Node->GetFirstChild();
191     ASSERT_EQ(textNode->GetValue(), "Hello From");
192     ASSERT_TRUE(textNode->SetValue("A Different Message From"));
193     ASSERT_EQ(textNode->GetValue(), "A Different Message From");
194 
195     CefRefPtr<CefDOMNode> brNode = textNode->GetNextSibling();
196     EXPECT_EQ(brNode->GetElementAttribute("class"), "some_class");
197     EXPECT_TRUE(brNode->SetElementAttribute("class", "a_different_class"));
198     EXPECT_EQ(brNode->GetElementAttribute("class"), "a_different_class");
199 
200     ASSERT_EQ(h1Node->GetAsMarkup(),
201               "<h1>A Different Message From<br class=\"a_different_class\" "
202               "id=\"some_id\">Main Frame</h1>");
203 
204     ASSERT_FALSE(h1Node->SetValue("Something Different"));
205   }
206 
Visit(CefRefPtr<CefDOMDocument> document)207   void Visit(CefRefPtr<CefDOMDocument> document) override {
208     if (test_type_ == DOM_TEST_STRUCTURE)
209       TestStructure(document);
210     else if (test_type_ == DOM_TEST_MODIFY)
211       TestModify(document);
212 
213     DestroyTest();
214   }
215 
216  protected:
217   // Return from the test.
DestroyTest()218   void DestroyTest() {
219     // Check if the test has failed.
220     bool result = !TestFailed();
221 
222     // Return the result to the browser process.
223     CefRefPtr<CefProcessMessage> return_msg =
224         CefProcessMessage::Create(kTestMessage);
225     EXPECT_TRUE(return_msg->GetArgumentList()->SetBool(0, result));
226     browser_->GetMainFrame()->SendProcessMessage(PID_BROWSER, return_msg);
227   }
228 
229   CefRefPtr<CefBrowser> browser_;
230   DOMTestType test_type_;
231 
232   IMPLEMENT_REFCOUNTING(TestDOMVisitor);
233 };
234 
235 // Used in the render process.
236 class DOMRendererTest : public ClientAppRenderer::Delegate {
237  public:
DOMRendererTest()238   DOMRendererTest() {}
239 
OnProcessMessageReceived(CefRefPtr<ClientAppRenderer> app,CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)240   bool OnProcessMessageReceived(CefRefPtr<ClientAppRenderer> app,
241                                 CefRefPtr<CefBrowser> browser,
242                                 CefRefPtr<CefFrame> frame,
243                                 CefProcessId source_process,
244                                 CefRefPtr<CefProcessMessage> message) override {
245     if (message->GetName() == kTestMessage) {
246       EXPECT_EQ(message->GetArgumentList()->GetSize(), (size_t)1);
247       int test_type = message->GetArgumentList()->GetInt(0);
248 
249       browser->GetMainFrame()->VisitDOM(
250           new TestDOMVisitor(browser, static_cast<DOMTestType>(test_type)));
251       return true;
252     }
253     return false;
254   }
255 
256  private:
257   IMPLEMENT_REFCOUNTING(DOMRendererTest);
258 };
259 
260 // Used in the browser process.
261 class TestDOMHandler : public TestHandler {
262  public:
TestDOMHandler(DOMTestType test)263   explicit TestDOMHandler(DOMTestType test) : test_type_(test) {}
264 
RunTest()265   void RunTest() override {
266     std::stringstream mainHtml;
267     mainHtml << "<html>"
268                 "<head><title>The Title</title></head>"
269                 "<body>"
270                 "<h1>Hello From<br class=\"some_class\"/ id=\"some_id\"/>"
271                 "Main Frame</h1>"
272                 "<div id=\"sized_element\" style=\"width: 50px; height: 25px; "
273                 "position: fixed; top: 100px; left: 150px;\"/>"
274                 "</body>"
275                 "</html>";
276 
277     AddResource(kTestUrl, mainHtml.str(), "text/html");
278     CreateBrowser(kTestUrl);
279 
280     // Time out the test after a reasonable period of time.
281     SetTestTimeout();
282   }
283 
OnLoadEnd(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int httpStatusCode)284   void OnLoadEnd(CefRefPtr<CefBrowser> browser,
285                  CefRefPtr<CefFrame> frame,
286                  int httpStatusCode) override {
287     if (frame->IsMain()) {
288       // Start the test in the render process.
289       CefRefPtr<CefProcessMessage> message(
290           CefProcessMessage::Create(kTestMessage));
291       message->GetArgumentList()->SetInt(0, test_type_);
292       frame->SendProcessMessage(PID_RENDERER, message);
293     }
294   }
295 
OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,CefProcessId source_process,CefRefPtr<CefProcessMessage> message)296   bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
297                                 CefRefPtr<CefFrame> frame,
298                                 CefProcessId source_process,
299                                 CefRefPtr<CefProcessMessage> message) override {
300     EXPECT_STREQ(message->GetName().ToString().c_str(), kTestMessage);
301 
302     got_message_.yes();
303 
304     if (message->GetArgumentList()->GetBool(0))
305       got_success_.yes();
306 
307     // Test is complete.
308     DestroyTest();
309 
310     return true;
311   }
312 
313   DOMTestType test_type_;
314   TrackCallback got_message_;
315   TrackCallback got_success_;
316 
317   IMPLEMENT_REFCOUNTING(TestDOMHandler);
318 };
319 
320 }  // namespace
321 
322 // Test DOM structure reading.
TEST(DOMTest,Read)323 TEST(DOMTest, Read) {
324   CefRefPtr<TestDOMHandler> handler = new TestDOMHandler(DOM_TEST_STRUCTURE);
325   handler->ExecuteTest();
326 
327   EXPECT_TRUE(handler->got_message_);
328   EXPECT_TRUE(handler->got_success_);
329 
330   ReleaseAndWaitForDestructor(handler);
331 }
332 
333 // Test DOM modifications.
TEST(DOMTest,Modify)334 TEST(DOMTest, Modify) {
335   CefRefPtr<TestDOMHandler> handler = new TestDOMHandler(DOM_TEST_MODIFY);
336   handler->ExecuteTest();
337 
338   EXPECT_TRUE(handler->got_message_);
339   EXPECT_TRUE(handler->got_success_);
340 
341   ReleaseAndWaitForDestructor(handler);
342 }
343 
344 // Entry point for creating DOM renderer test objects.
345 // Called from client_app_delegates.cc.
CreateDOMRendererTests(ClientAppRenderer::DelegateSet & delegates)346 void CreateDOMRendererTests(ClientAppRenderer::DelegateSet& delegates) {
347   delegates.insert(new DOMRendererTest);
348 }
349