1 // Copyright 2014 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.
5 #include "components/html_viewer/ax_provider_impl.h"
8 #include "base/message_loop/message_loop.h"
9 #include "components/html_viewer/blink_platform_impl.h"
10 #include "components/scheduler/renderer/renderer_scheduler.h"
11 #include "gin/v8_initializer.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/WebKit/public/platform/WebData.h"
14 #include "third_party/WebKit/public/platform/WebURL.h"
15 #include "third_party/WebKit/public/web/WebFrameClient.h"
16 #include "third_party/WebKit/public/web/WebKit.h"
17 #include "third_party/WebKit/public/web/WebLocalFrame.h"
18 #include "third_party/WebKit/public/web/WebView.h"
19 #include "third_party/WebKit/public/web/WebViewClient.h"
23 using blink::WebLocalFrame
;
24 using blink::WebFrameClient
;
27 using blink::WebViewClient
;
31 using mojo::AxNodePtr
;
35 class TestWebFrameClient
: public WebFrameClient
{
37 ~TestWebFrameClient() override
{}
38 void didStopLoading() override
{ base::MessageLoop::current()->Quit(); }
41 class TestWebViewClient
: public WebViewClient
{
43 bool allowsBrokenNullLayerTreeView() const override
{ return true; }
44 virtual ~TestWebViewClient() {}
47 class AxProviderImplTest
: public testing::Test
{
50 : message_loop_(new base::MessageLoopForUI()),
51 renderer_scheduler_(scheduler::RendererScheduler::Create()) {
52 #if defined(V8_USE_EXTERNAL_STARTUP_DATA)
53 gin::V8Initializer::LoadV8Snapshot();
54 gin::V8Initializer::LoadV8Natives();
57 new html_viewer::BlinkPlatformImpl(nullptr, renderer_scheduler_
.get()));
60 ~AxProviderImplTest() override
{
61 renderer_scheduler_
->Shutdown();
62 message_loop_
.reset();
67 scoped_ptr
<base::MessageLoopForUI
> message_loop_
;
68 scoped_ptr
<scheduler::RendererScheduler
> renderer_scheduler_
;
72 void OnNodes(Array
<AxNodePtr
> nodes
) { this->nodes
= nodes
.Pass(); }
73 Array
<AxNodePtr
> nodes
;
76 AxNodePtr
CreateNode(int id
,
79 const mojo::RectPtr
& bounds
,
80 const std::string
& url
,
81 const std::string
& text
) {
82 AxNodePtr
node(AxNode::New());
84 node
->parent_id
= parent_id
;
85 node
->next_sibling_id
= next_sibling_id
;
86 node
->bounds
= bounds
.Clone();
89 node
->link
= mojo::AxLink::New();
90 node
->link
->url
= url
;
93 node
->text
= mojo::AxText::New();
94 node
->text
->content
= text
;
102 // TODO(msw): This test crashes on Android; see http://crbug.com/486171
103 #if defined(OS_ANDROID)
104 #define MAYBE_Basic DISABLED_Basic
106 #define MAYBE_Basic Basic
108 TEST_F(AxProviderImplTest
, MAYBE_Basic
) {
109 TestWebViewClient web_view_client
;
110 TestWebFrameClient web_frame_client
;
111 WebView
* view
= WebView::create(&web_view_client
);
112 view
->setMainFrame(WebLocalFrame::create(blink::WebTreeScopeType::Document
,
114 view
->mainFrame()->loadHTMLString(
117 "href='http://monkey.net'>bar</a>baz</body></html>"),
118 WebURL(GURL("http://someplace.net")));
119 base::MessageLoop::current()->Run();
121 mojo::AxProviderPtr service_ptr
;
122 html_viewer::AxProviderImpl
ax_provider_impl(view
,
123 mojo::GetProxy(&service_ptr
));
125 ax_provider_impl
.GetTree(
126 base::Bind(&NodeCatcher::OnNodes
, base::Unretained(&catcher
)));
128 std::map
<uint32
, AxNode
*> lookup
;
129 for (size_t i
= 0; i
< catcher
.nodes
.size(); ++i
) {
130 auto& node
= catcher
.nodes
[i
];
131 lookup
[node
->id
] = node
.get();
134 typedef decltype(lookup
)::value_type MapEntry
;
135 auto is_link
= [](MapEntry pair
) { return !pair
.second
->link
.is_null(); };
136 auto is_text
= [](MapEntry pair
, const char* content
) {
137 return !pair
.second
->text
.is_null() &&
138 pair
.second
->text
->content
.To
<std::string
>() == content
;
140 auto is_foo
= [&is_text
](MapEntry pair
) { return is_text(pair
, "foo"); };
141 auto is_bar
= [&is_text
](MapEntry pair
) { return is_text(pair
, "bar"); };
142 auto is_baz
= [&is_text
](MapEntry pair
) { return is_text(pair
, "baz"); };
144 EXPECT_EQ(1, std::count_if(lookup
.begin(), lookup
.end(), is_link
));
145 EXPECT_EQ(1, std::count_if(lookup
.begin(), lookup
.end(), is_foo
));
146 EXPECT_EQ(1, std::count_if(lookup
.begin(), lookup
.end(), is_bar
));
147 EXPECT_EQ(1, std::count_if(lookup
.begin(), lookup
.end(), is_baz
));
149 auto root
= lookup
[1u];
150 auto link
= std::find_if(lookup
.begin(), lookup
.end(), is_link
)->second
;
151 auto foo
= std::find_if(lookup
.begin(), lookup
.end(), is_foo
)->second
;
152 auto bar
= std::find_if(lookup
.begin(), lookup
.end(), is_bar
)->second
;
153 auto baz
= std::find_if(lookup
.begin(), lookup
.end(), is_baz
)->second
;
155 // Test basic content of each node. The properties we copy (like parent_id)
156 // here are tested differently below.
157 EXPECT_TRUE(CreateNode(root
->id
, 0, 0, root
->bounds
, "", "")->Equals(*root
));
158 EXPECT_TRUE(CreateNode(foo
->id
, foo
->parent_id
, 0, foo
->bounds
, "", "foo")
160 EXPECT_TRUE(CreateNode(bar
->id
, bar
->parent_id
, 0, bar
->bounds
, "", "bar")
162 EXPECT_TRUE(CreateNode(baz
->id
, baz
->parent_id
, 0, baz
->bounds
, "", "baz")
164 EXPECT_TRUE(CreateNode(link
->id
,
166 link
->next_sibling_id
,
168 "http://monkey.net/",
171 auto is_descendant_of
= [&lookup
](uint32 id
, uint32 ancestor
) {
172 for (; (id
= lookup
[id
]->parent_id
) != 0;) {
179 EXPECT_TRUE(is_descendant_of(bar
->id
, link
->id
));
180 for (auto pair
: lookup
) {
181 AxNode
* node
= pair
.second
;
183 EXPECT_TRUE(is_descendant_of(node
->id
, 1u));
184 if (node
!= link
&& node
!= foo
&& node
!= bar
&& node
!= baz
) {
185 EXPECT_TRUE(CreateNode(node
->id
,
187 node
->next_sibling_id
,
194 // TODO(aa): Test bounds.
195 // TODO(aa): Test sibling ordering of foo/bar/baz.