1 // Copyright 2013 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.
7 #include "base/win/scoped_bstr.h"
8 #include "base/win/scoped_comptr.h"
9 #include "base/win/scoped_variant.h"
10 #include "third_party/iaccessible2/ia2_api_all.h"
11 #include "ui/views/accessibility/native_view_accessibility.h"
12 #include "ui/views/controls/textfield/textfield.h"
13 #include "ui/views/test/views_test_base.h"
15 using base::win::ScopedBstr
;
16 using base::win::ScopedComPtr
;
17 using base::win::ScopedVariant
;
22 class NativeViewAcccessibilityWinTest
: public ViewsTestBase
{
24 NativeViewAcccessibilityWinTest() {}
25 virtual ~NativeViewAcccessibilityWinTest() {}
28 void GetIAccessible2InterfaceForView(View
* view
, IAccessible2_2
** result
) {
29 ScopedComPtr
<IAccessible
> view_accessible(
30 view
->GetNativeViewAccessible());
31 ScopedComPtr
<IServiceProvider
> service_provider
;
32 ASSERT_EQ(S_OK
, view_accessible
.QueryInterface(service_provider
.Receive()));
34 service_provider
->QueryService(IID_IAccessible2_2
, result
));
38 TEST_F(NativeViewAcccessibilityWinTest
, TextfieldAccessibility
) {
40 Widget::InitParams init_params
=
41 CreateParams(Widget::InitParams::TYPE_POPUP
);
42 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
43 widget
.Init(init_params
);
45 View
* content
= new View
;
46 widget
.SetContentsView(content
);
48 Textfield
* textfield
= new Textfield
;
49 textfield
->SetAccessibleName(L
"Name");
50 textfield
->SetText(L
"Value");
51 content
->AddChildView(textfield
);
53 ScopedComPtr
<IAccessible
> content_accessible(
54 content
->GetNativeViewAccessible());
56 ASSERT_EQ(S_OK
, content_accessible
->get_accChildCount(&child_count
));
57 ASSERT_EQ(1L, child_count
);
59 ScopedComPtr
<IDispatch
> textfield_dispatch
;
60 ScopedComPtr
<IAccessible
> textfield_accessible
;
61 ScopedVariant
child_index(1);
62 ASSERT_EQ(S_OK
, content_accessible
->get_accChild(
63 child_index
, textfield_dispatch
.Receive()));
64 ASSERT_EQ(S_OK
, textfield_dispatch
.QueryInterface(
65 textfield_accessible
.Receive()));
68 ScopedVariant
childid_self(CHILDID_SELF
);
69 ASSERT_EQ(S_OK
, textfield_accessible
->get_accName(
70 childid_self
, name
.Receive()));
71 ASSERT_STREQ(L
"Name", name
);
74 ASSERT_EQ(S_OK
, textfield_accessible
->get_accValue(
75 childid_self
, value
.Receive()));
76 ASSERT_STREQ(L
"Value", value
);
78 ScopedBstr
new_value(L
"New value");
79 ASSERT_EQ(S_OK
, textfield_accessible
->put_accValue(childid_self
, new_value
));
81 ASSERT_STREQ(L
"New value", textfield
->text().c_str());
84 TEST_F(NativeViewAcccessibilityWinTest
, UnattachedWebView
) {
85 // This is a regression test. Calling get_accChild on the native accessible
86 // object for a WebView with no attached WebContents was causing an
87 // infinite loop and crash. This test simulates that with an ordinary
88 // View that registers itself as a web view with NativeViewAcccessibility.
91 Widget::InitParams init_params
=
92 CreateParams(Widget::InitParams::TYPE_POPUP
);
93 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
94 widget
.Init(init_params
);
96 View
* content
= new View
;
97 widget
.SetContentsView(content
);
99 View
* web_view
= new View
;
100 content
->AddChildView(web_view
);
101 NativeViewAccessibility::RegisterWebView(web_view
);
103 ScopedComPtr
<IAccessible
> web_view_accessible(
104 web_view
->GetNativeViewAccessible());
105 ScopedComPtr
<IDispatch
> result_dispatch
;
106 ScopedVariant
child_index(-999);
107 ASSERT_EQ(E_FAIL
, web_view_accessible
->get_accChild(
108 child_index
, result_dispatch
.Receive()));
110 NativeViewAccessibility::UnregisterWebView(web_view
);
113 TEST_F(NativeViewAcccessibilityWinTest
, AuraOwnedWidgets
) {
115 Widget::InitParams init_params
=
116 CreateParams(Widget::InitParams::TYPE_WINDOW
);
117 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
118 widget
.Init(init_params
);
120 ScopedComPtr
<IAccessible
> root_view_accessible(
121 widget
.GetRootView()->GetNativeViewAccessible());
123 LONG child_count
= 0;
124 ASSERT_EQ(S_OK
, root_view_accessible
->get_accChildCount(&child_count
));
125 ASSERT_EQ(1L, child_count
);
128 Widget::InitParams owned_init_params
=
129 CreateParams(Widget::InitParams::TYPE_POPUP
);
130 owned_init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
131 owned_init_params
.parent
= widget
.GetNativeView();
132 owned_widget
.Init(owned_init_params
);
135 ASSERT_EQ(S_OK
, root_view_accessible
->get_accChildCount(&child_count
));
136 ASSERT_EQ(2L, child_count
);
139 TEST_F(NativeViewAcccessibilityWinTest
, RetrieveAllAlerts
) {
141 Widget::InitParams init_params
=
142 CreateParams(Widget::InitParams::TYPE_POPUP
);
143 init_params
.ownership
= Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET
;
144 widget
.Init(init_params
);
146 View
* content
= new View
;
147 widget
.SetContentsView(content
);
149 View
* infobar
= new View
;
150 content
->AddChildView(infobar
);
152 View
* infobar2
= new View
;
153 content
->AddChildView(infobar2
);
155 View
* root_view
= content
->parent();
156 ASSERT_EQ(NULL
, root_view
->parent());
158 ScopedComPtr
<IAccessible2_2
> root_view_accessible
;
159 GetIAccessible2InterfaceForView(root_view
, root_view_accessible
.Receive());
161 ScopedComPtr
<IAccessible2_2
> infobar_accessible
;
162 GetIAccessible2InterfaceForView(infobar
, infobar_accessible
.Receive());
164 ScopedComPtr
<IAccessible2_2
> infobar2_accessible
;
165 GetIAccessible2InterfaceForView(infobar2
, infobar2_accessible
.Receive());
167 // Initially, there are no alerts
168 ScopedBstr
alerts_bstr(L
"alerts");
171 ASSERT_EQ(S_FALSE
, root_view_accessible
->get_relationTargetsOfType(
172 alerts_bstr
, 0, &targets
, &n_targets
));
173 ASSERT_EQ(0, n_targets
);
175 // Fire alert events on the infobars.
176 infobar
->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT
, true);
177 infobar2
->NotifyAccessibilityEvent(ui::AX_EVENT_ALERT
, true);
179 // Now calling get_relationTargetsOfType should retrieve the alerts.
180 ASSERT_EQ(S_OK
, root_view_accessible
->get_relationTargetsOfType(
181 alerts_bstr
, 0, &targets
, &n_targets
));
182 ASSERT_EQ(2, n_targets
);
183 ASSERT_TRUE(infobar_accessible
.IsSameObject(targets
[0]));
184 ASSERT_TRUE(infobar2_accessible
.IsSameObject(targets
[1]));
185 CoTaskMemFree(targets
);
187 // If we set max_targets to 1, we should only get the first one.
188 ASSERT_EQ(S_OK
, root_view_accessible
->get_relationTargetsOfType(
189 alerts_bstr
, 1, &targets
, &n_targets
));
190 ASSERT_EQ(1, n_targets
);
191 ASSERT_TRUE(infobar_accessible
.IsSameObject(targets
[0]));
192 CoTaskMemFree(targets
);
194 // If we delete the first view, we should only get the second one now.
196 ASSERT_EQ(S_OK
, root_view_accessible
->get_relationTargetsOfType(
197 alerts_bstr
, 0, &targets
, &n_targets
));
198 ASSERT_EQ(1, n_targets
);
199 ASSERT_TRUE(infobar2_accessible
.IsSameObject(targets
[0]));
200 CoTaskMemFree(targets
);