OLD | NEW |
| (Empty) |
1 // Copyright (c) 2010 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 "base/scoped_ptr.h" | |
6 #include "base/scoped_comptr_win.h" | |
7 #include "chrome/browser/browser_accessibility_manager_win.h" | |
8 #include "chrome/browser/browser_accessibility_win.h" | |
9 #include "chrome/common/render_messages_params.h" | |
10 #include "testing/gtest/include/gtest/gtest.h" | |
11 | |
12 using webkit_glue::WebAccessibility; | |
13 | |
14 // Subclass of BrowserAccessibility that counts the number of instances. | |
15 class CountedBrowserAccessibility : public BrowserAccessibility { | |
16 public: | |
17 CountedBrowserAccessibility() { global_obj_count_++; } | |
18 virtual ~CountedBrowserAccessibility() { global_obj_count_--; } | |
19 static int global_obj_count_; | |
20 }; | |
21 | |
22 int CountedBrowserAccessibility::global_obj_count_ = 0; | |
23 | |
24 // Factory that creates a CountedBrowserAccessibility. | |
25 class CountedBrowserAccessibilityFactory : public BrowserAccessibilityFactory { | |
26 public: | |
27 virtual ~CountedBrowserAccessibilityFactory() {} | |
28 virtual BrowserAccessibility* Create() { | |
29 CComObject<CountedBrowserAccessibility>* instance; | |
30 HRESULT hr = CComObject<CountedBrowserAccessibility>::CreateInstance( | |
31 &instance); | |
32 DCHECK(SUCCEEDED(hr)); | |
33 return instance->NewReference(); | |
34 } | |
35 }; | |
36 | |
37 VARIANT CreateI4Variant(LONG value) { | |
38 VARIANT variant = {0}; | |
39 | |
40 V_VT(&variant) = VT_I4; | |
41 V_I4(&variant) = value; | |
42 | |
43 return variant; | |
44 } | |
45 | |
46 class BrowserAccessibilityTest : public testing::Test { | |
47 protected: | |
48 virtual void SetUp() { | |
49 // ATL needs a pointer to a COM module. | |
50 static CComModule module; | |
51 _pAtlModule = &module; | |
52 | |
53 // Make sure COM is initialized for this thread; it's safe to call twice. | |
54 ::CoInitialize(NULL); | |
55 } | |
56 | |
57 virtual void TearDown() | |
58 { | |
59 ::CoUninitialize(); | |
60 } | |
61 }; | |
62 | |
63 // Test that BrowserAccessibilityManager correctly releases the tree of | |
64 // BrowserAccessibility instances upon delete. | |
65 TEST_F(BrowserAccessibilityTest, TestNoLeaks) { | |
66 // Create WebAccessibility objects for a simple document tree, | |
67 // representing the accessibility information used to initialize | |
68 // BrowserAccessibilityManager. | |
69 WebAccessibility button; | |
70 button.id = 2; | |
71 button.name = L"Button"; | |
72 button.role = WebAccessibility::ROLE_BUTTON; | |
73 button.state = 0; | |
74 | |
75 WebAccessibility checkbox; | |
76 checkbox.id = 3; | |
77 checkbox.name = L"Checkbox"; | |
78 checkbox.role = WebAccessibility::ROLE_CHECKBOX; | |
79 checkbox.state = 0; | |
80 | |
81 WebAccessibility root; | |
82 root.id = 1; | |
83 root.name = L"Document"; | |
84 root.role = WebAccessibility::ROLE_DOCUMENT; | |
85 root.state = 0; | |
86 root.children.push_back(button); | |
87 root.children.push_back(checkbox); | |
88 | |
89 // Construct a BrowserAccessibilityManager with this WebAccessibility tree | |
90 // and a factory for an instance-counting BrowserAccessibility, and ensure | |
91 // that exactly 3 instances were created. Note that the manager takes | |
92 // ownership of the factory. | |
93 CountedBrowserAccessibility::global_obj_count_ = 0; | |
94 BrowserAccessibilityManager* manager = | |
95 new BrowserAccessibilityManager( | |
96 GetDesktopWindow(), root, NULL, | |
97 new CountedBrowserAccessibilityFactory()); | |
98 ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_); | |
99 | |
100 // Delete the manager and test that all 3 instances are deleted. | |
101 delete manager; | |
102 ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); | |
103 | |
104 // Construct a manager again, and this time use the IAccessible interface | |
105 // to get new references to two of the three nodes in the tree. | |
106 manager = new BrowserAccessibilityManager( | |
107 GetDesktopWindow(), root, NULL, | |
108 new CountedBrowserAccessibilityFactory()); | |
109 ASSERT_EQ(3, CountedBrowserAccessibility::global_obj_count_); | |
110 BrowserAccessibility* root_accessible = manager->GetRoot(); | |
111 IDispatch* root_iaccessible = NULL; | |
112 IDispatch* child1_iaccessible = NULL; | |
113 VARIANT var_child; | |
114 var_child.vt = VT_I4; | |
115 var_child.lVal = CHILDID_SELF; | |
116 HRESULT hr = root_accessible->get_accChild(var_child, &root_iaccessible); | |
117 ASSERT_EQ(S_OK, hr); | |
118 var_child.lVal = 1; | |
119 hr = root_accessible->get_accChild(var_child, &child1_iaccessible); | |
120 ASSERT_EQ(S_OK, hr); | |
121 | |
122 // Now delete the manager, and only one of the three nodes in the tree | |
123 // should be released. | |
124 delete manager; | |
125 ASSERT_EQ(2, CountedBrowserAccessibility::global_obj_count_); | |
126 | |
127 // Release each of our references and make sure that each one results in | |
128 // the instance being deleted as its reference count hits zero. | |
129 root_iaccessible->Release(); | |
130 ASSERT_EQ(1, CountedBrowserAccessibility::global_obj_count_); | |
131 child1_iaccessible->Release(); | |
132 ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); | |
133 } | |
134 | |
135 TEST_F(BrowserAccessibilityTest, TestChildrenChange) { | |
136 // Create WebAccessibility objects for a simple document tree, | |
137 // representing the accessibility information used to initialize | |
138 // BrowserAccessibilityManager. | |
139 WebAccessibility text; | |
140 text.id = 2; | |
141 text.role = WebAccessibility::ROLE_STATIC_TEXT; | |
142 text.value = L"old text"; | |
143 text.state = 0; | |
144 | |
145 WebAccessibility root; | |
146 root.id = 1; | |
147 root.name = L"Document"; | |
148 root.role = WebAccessibility::ROLE_DOCUMENT; | |
149 root.state = 0; | |
150 root.children.push_back(text); | |
151 | |
152 // Construct a BrowserAccessibilityManager with this WebAccessibility tree | |
153 // and a factory for an instance-counting BrowserAccessibility. | |
154 CountedBrowserAccessibility::global_obj_count_ = 0; | |
155 BrowserAccessibilityManager* manager = | |
156 new BrowserAccessibilityManager( | |
157 GetDesktopWindow(), root, NULL, | |
158 new CountedBrowserAccessibilityFactory()); | |
159 | |
160 // Query for the text IAccessible and verify that it returns "old text" as its | |
161 // value. | |
162 ScopedComPtr<IDispatch> text_dispatch; | |
163 HRESULT hr = manager->GetRoot()->get_accChild(CreateI4Variant(1), | |
164 text_dispatch.Receive()); | |
165 ASSERT_EQ(S_OK, hr); | |
166 | |
167 ScopedComPtr<IAccessible> text_accessible; | |
168 hr = text_dispatch.QueryInterface(text_accessible.Receive()); | |
169 ASSERT_EQ(S_OK, hr); | |
170 | |
171 CComBSTR value; | |
172 hr = text_accessible->get_accValue(CreateI4Variant(CHILDID_SELF), &value); | |
173 ASSERT_EQ(S_OK, hr); | |
174 EXPECT_STREQ(L"old text", value.m_str); | |
175 | |
176 text_dispatch.Release(); | |
177 text_accessible.Release(); | |
178 | |
179 // Notify the BrowserAccessibilityManager that the text child has changed. | |
180 text.value = L"new text"; | |
181 ViewHostMsg_AccessibilityNotification_Params param; | |
182 param.notification_type = | |
183 ViewHostMsg_AccessibilityNotification_Params:: | |
184 NOTIFICATION_TYPE_CHILDREN_CHANGED; | |
185 param.acc_obj = text; | |
186 std::vector<ViewHostMsg_AccessibilityNotification_Params> notifications; | |
187 notifications.push_back(param); | |
188 manager->OnAccessibilityNotifications(notifications); | |
189 | |
190 // Query for the text IAccessible and verify that it now returns "new text" | |
191 // as its value. | |
192 hr = manager->GetRoot()->get_accChild( | |
193 CreateI4Variant(1), | |
194 text_dispatch.Receive()); | |
195 ASSERT_EQ(S_OK, hr); | |
196 | |
197 hr = text_dispatch.QueryInterface(text_accessible.Receive()); | |
198 ASSERT_EQ(S_OK, hr); | |
199 | |
200 hr = text_accessible->get_accValue(CreateI4Variant(CHILDID_SELF), &value); | |
201 ASSERT_EQ(S_OK, hr); | |
202 EXPECT_STREQ(L"new text", value.m_str); | |
203 | |
204 text_dispatch.Release(); | |
205 text_accessible.Release(); | |
206 | |
207 // Delete the manager and test that all BrowserAccessibility instances are | |
208 // deleted. | |
209 delete manager; | |
210 ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); | |
211 } | |
212 | |
213 TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) { | |
214 // Create WebAccessibility objects for a simple document tree, | |
215 // representing the accessibility information used to initialize | |
216 // BrowserAccessibilityManager. | |
217 WebAccessibility text; | |
218 text.id = 3; | |
219 text.role = WebAccessibility::ROLE_STATIC_TEXT; | |
220 text.state = 0; | |
221 | |
222 WebAccessibility div; | |
223 div.id = 2; | |
224 div.role = WebAccessibility::ROLE_GROUP; | |
225 div.state = 0; | |
226 | |
227 div.children.push_back(text); | |
228 text.id = 4; | |
229 div.children.push_back(text); | |
230 | |
231 WebAccessibility root; | |
232 root.id = 1; | |
233 root.role = WebAccessibility::ROLE_DOCUMENT; | |
234 root.state = 0; | |
235 root.children.push_back(div); | |
236 | |
237 // Construct a BrowserAccessibilityManager with this WebAccessibility tree | |
238 // and a factory for an instance-counting BrowserAccessibility and ensure | |
239 // that exactly 4 instances were created. Note that the manager takes | |
240 // ownership of the factory. | |
241 CountedBrowserAccessibility::global_obj_count_ = 0; | |
242 BrowserAccessibilityManager* manager = | |
243 new BrowserAccessibilityManager( | |
244 GetDesktopWindow(), root, NULL, | |
245 new CountedBrowserAccessibilityFactory()); | |
246 ASSERT_EQ(4, CountedBrowserAccessibility::global_obj_count_); | |
247 | |
248 // Notify the BrowserAccessibilityManager that the div node and its children | |
249 // were removed and ensure that only one BrowserAccessibility instance exists. | |
250 root.children.clear(); | |
251 ViewHostMsg_AccessibilityNotification_Params param; | |
252 param.notification_type = | |
253 ViewHostMsg_AccessibilityNotification_Params:: | |
254 NOTIFICATION_TYPE_CHILDREN_CHANGED; | |
255 param.acc_obj = root; | |
256 std::vector<ViewHostMsg_AccessibilityNotification_Params> notifications; | |
257 notifications.push_back(param); | |
258 manager->OnAccessibilityNotifications(notifications); | |
259 ASSERT_EQ(1, CountedBrowserAccessibility::global_obj_count_); | |
260 | |
261 // Delete the manager and test that all BrowserAccessibility instances are | |
262 // deleted. | |
263 delete manager; | |
264 ASSERT_EQ(0, CountedBrowserAccessibility::global_obj_count_); | |
265 } | |
OLD | NEW |