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
;
101 TEST_F(AxProviderImplTest
, Basic
) {
102 TestWebViewClient web_view_client
;
103 TestWebFrameClient web_frame_client
;
104 WebView
* view
= WebView::create(&web_view_client
);
105 view
->setMainFrame(WebLocalFrame::create(blink::WebTreeScopeType::Document
,
107 view
->mainFrame()->loadHTMLString(
110 "href='http://monkey.net'>bar</a>baz</body></html>"),
111 WebURL(GURL("http://someplace.net")));
112 base::MessageLoop::current()->Run();
114 mojo::AxProviderPtr service_ptr
;
115 html_viewer::AxProviderImpl
ax_provider_impl(view
,
116 mojo::GetProxy(&service_ptr
));
118 ax_provider_impl
.GetTree(
119 base::Bind(&NodeCatcher::OnNodes
, base::Unretained(&catcher
)));
121 std::map
<uint32
, AxNode
*> lookup
;
122 for (size_t i
= 0; i
< catcher
.nodes
.size(); ++i
) {
123 auto& node
= catcher
.nodes
[i
];
124 lookup
[node
->id
] = node
.get();
127 typedef decltype(lookup
)::value_type MapEntry
;
128 auto is_link
= [](MapEntry pair
) { return !pair
.second
->link
.is_null(); };
129 auto is_text
= [](MapEntry pair
, const char* content
) {
130 return !pair
.second
->text
.is_null() &&
131 pair
.second
->text
->content
.To
<std::string
>() == content
;
133 auto is_foo
= [&is_text
](MapEntry pair
) { return is_text(pair
, "foo"); };
134 auto is_bar
= [&is_text
](MapEntry pair
) { return is_text(pair
, "bar"); };
135 auto is_baz
= [&is_text
](MapEntry pair
) { return is_text(pair
, "baz"); };
137 EXPECT_EQ(1, std::count_if(lookup
.begin(), lookup
.end(), is_link
));
138 EXPECT_EQ(1, std::count_if(lookup
.begin(), lookup
.end(), is_foo
));
139 EXPECT_EQ(1, std::count_if(lookup
.begin(), lookup
.end(), is_bar
));
140 EXPECT_EQ(1, std::count_if(lookup
.begin(), lookup
.end(), is_baz
));
142 auto root
= lookup
[1u];
143 auto link
= std::find_if(lookup
.begin(), lookup
.end(), is_link
)->second
;
144 auto foo
= std::find_if(lookup
.begin(), lookup
.end(), is_foo
)->second
;
145 auto bar
= std::find_if(lookup
.begin(), lookup
.end(), is_bar
)->second
;
146 auto baz
= std::find_if(lookup
.begin(), lookup
.end(), is_baz
)->second
;
148 // Test basic content of each node. The properties we copy (like parent_id)
149 // here are tested differently below.
150 EXPECT_TRUE(CreateNode(root
->id
, 0, 0, root
->bounds
, "", "")->Equals(*root
));
151 EXPECT_TRUE(CreateNode(foo
->id
, foo
->parent_id
, 0, foo
->bounds
, "", "foo")
153 EXPECT_TRUE(CreateNode(bar
->id
, bar
->parent_id
, 0, bar
->bounds
, "", "bar")
155 EXPECT_TRUE(CreateNode(baz
->id
, baz
->parent_id
, 0, baz
->bounds
, "", "baz")
157 EXPECT_TRUE(CreateNode(link
->id
,
159 link
->next_sibling_id
,
161 "http://monkey.net/",
164 auto is_descendant_of
= [&lookup
](uint32 id
, uint32 ancestor
) {
165 for (; (id
= lookup
[id
]->parent_id
) != 0;) {
172 EXPECT_TRUE(is_descendant_of(bar
->id
, link
->id
));
173 for (auto pair
: lookup
) {
174 AxNode
* node
= pair
.second
;
176 EXPECT_TRUE(is_descendant_of(node
->id
, 1u));
177 if (node
!= link
&& node
!= foo
&& node
!= bar
&& node
!= baz
) {
178 EXPECT_TRUE(CreateNode(node
->id
,
180 node
->next_sibling_id
,
187 // TODO(aa): Test bounds.
188 // TODO(aa): Test sibling ordering of foo/bar/baz.