- add sources.
[platform/framework/web/crosswalk.git] / src / content / browser / accessibility / browser_accessibility_win_unittest.cc
1 // Copyright (c) 2012 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/memory/scoped_ptr.h"
6 #include "base/strings/utf_string_conversions.h"
7 #include "base/win/scoped_bstr.h"
8 #include "base/win/scoped_comptr.h"
9 #include "base/win/scoped_variant.h"
10 #include "content/browser/accessibility/browser_accessibility_manager.h"
11 #include "content/browser/accessibility/browser_accessibility_manager_win.h"
12 #include "content/browser/accessibility/browser_accessibility_win.h"
13 #include "content/common/accessibility_messages.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/base/win/atl_module.h"
16
17 namespace content {
18 namespace {
19
20
21 // CountedBrowserAccessibility ------------------------------------------------
22
23 // Subclass of BrowserAccessibilityWin that counts the number of instances.
24 class CountedBrowserAccessibility : public BrowserAccessibilityWin {
25  public:
26   CountedBrowserAccessibility();
27   virtual ~CountedBrowserAccessibility();
28
29   static void reset() { num_instances_ = 0; }
30   static int num_instances() { return num_instances_; }
31
32  private:
33   static int num_instances_;
34
35   DISALLOW_COPY_AND_ASSIGN(CountedBrowserAccessibility);
36 };
37
38 // static
39 int CountedBrowserAccessibility::num_instances_ = 0;
40
41 CountedBrowserAccessibility::CountedBrowserAccessibility() {
42   ++num_instances_;
43 }
44
45 CountedBrowserAccessibility::~CountedBrowserAccessibility() {
46   --num_instances_;
47 }
48
49
50 // CountedBrowserAccessibilityFactory -----------------------------------------
51
52 // Factory that creates a CountedBrowserAccessibility.
53 class CountedBrowserAccessibilityFactory : public BrowserAccessibilityFactory {
54  public:
55   CountedBrowserAccessibilityFactory();
56
57  private:
58   virtual ~CountedBrowserAccessibilityFactory();
59
60   virtual BrowserAccessibility* Create() OVERRIDE;
61
62   DISALLOW_COPY_AND_ASSIGN(CountedBrowserAccessibilityFactory);
63 };
64
65 CountedBrowserAccessibilityFactory::CountedBrowserAccessibilityFactory() {
66 }
67
68 CountedBrowserAccessibilityFactory::~CountedBrowserAccessibilityFactory() {
69 }
70
71 BrowserAccessibility* CountedBrowserAccessibilityFactory::Create() {
72   CComObject<CountedBrowserAccessibility>* instance;
73   HRESULT hr = CComObject<CountedBrowserAccessibility>::CreateInstance(
74       &instance);
75   DCHECK(SUCCEEDED(hr));
76   instance->AddRef();
77   return instance;
78 }
79
80 }  // namespace
81
82
83 // BrowserAccessibilityTest ---------------------------------------------------
84
85 class BrowserAccessibilityTest : public testing::Test {
86  public:
87   BrowserAccessibilityTest();
88   virtual ~BrowserAccessibilityTest();
89
90  private:
91   virtual void SetUp() OVERRIDE;
92
93   DISALLOW_COPY_AND_ASSIGN(BrowserAccessibilityTest);
94 };
95
96 BrowserAccessibilityTest::BrowserAccessibilityTest() {
97 }
98
99 BrowserAccessibilityTest::~BrowserAccessibilityTest() {
100 }
101
102 void BrowserAccessibilityTest::SetUp() {
103   ui::win::CreateATLModuleIfNeeded();
104 }
105
106
107 // Actual tests ---------------------------------------------------------------
108
109 // Test that BrowserAccessibilityManager correctly releases the tree of
110 // BrowserAccessibility instances upon delete.
111 TEST_F(BrowserAccessibilityTest, TestNoLeaks) {
112   // Create AccessibilityNodeData objects for a simple document tree,
113   // representing the accessibility information used to initialize
114   // BrowserAccessibilityManager.
115   AccessibilityNodeData button;
116   button.id = 2;
117   button.SetName("Button");
118   button.role = WebKit::WebAXRoleButton;
119   button.state = 0;
120
121   AccessibilityNodeData checkbox;
122   checkbox.id = 3;
123   checkbox.SetName("Checkbox");
124   checkbox.role = WebKit::WebAXRoleCheckBox;
125   checkbox.state = 0;
126
127   AccessibilityNodeData root;
128   root.id = 1;
129   root.SetName("Document");
130   root.role = WebKit::WebAXRoleRootWebArea;
131   root.state = 0;
132   root.child_ids.push_back(2);
133   root.child_ids.push_back(3);
134
135   // Construct a BrowserAccessibilityManager with this
136   // AccessibilityNodeData tree and a factory for an instance-counting
137   // BrowserAccessibility, and ensure that exactly 3 instances were
138   // created. Note that the manager takes ownership of the factory.
139   CountedBrowserAccessibility::reset();
140   scoped_ptr<BrowserAccessibilityManager> manager(
141       BrowserAccessibilityManager::Create(
142           root, NULL, new CountedBrowserAccessibilityFactory()));
143   manager->UpdateNodesForTesting(button, checkbox);
144   ASSERT_EQ(3, CountedBrowserAccessibility::num_instances());
145
146   // Delete the manager and test that all 3 instances are deleted.
147   manager.reset();
148   ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
149
150   // Construct a manager again, and this time use the IAccessible interface
151   // to get new references to two of the three nodes in the tree.
152   manager.reset(BrowserAccessibilityManager::Create(
153       root, NULL, new CountedBrowserAccessibilityFactory()));
154   manager->UpdateNodesForTesting(button, checkbox);
155   ASSERT_EQ(3, CountedBrowserAccessibility::num_instances());
156   IAccessible* root_accessible =
157       manager->GetRoot()->ToBrowserAccessibilityWin();
158   IDispatch* root_iaccessible = NULL;
159   IDispatch* child1_iaccessible = NULL;
160   base::win::ScopedVariant childid_self(CHILDID_SELF);
161   HRESULT hr = root_accessible->get_accChild(childid_self, &root_iaccessible);
162   ASSERT_EQ(S_OK, hr);
163   base::win::ScopedVariant one(1);
164   hr = root_accessible->get_accChild(one, &child1_iaccessible);
165   ASSERT_EQ(S_OK, hr);
166
167   // Now delete the manager, and only one of the three nodes in the tree
168   // should be released.
169   manager.reset();
170   ASSERT_EQ(2, CountedBrowserAccessibility::num_instances());
171
172   // Release each of our references and make sure that each one results in
173   // the instance being deleted as its reference count hits zero.
174   root_iaccessible->Release();
175   ASSERT_EQ(1, CountedBrowserAccessibility::num_instances());
176   child1_iaccessible->Release();
177   ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
178 }
179
180 TEST_F(BrowserAccessibilityTest, TestChildrenChange) {
181   // Create AccessibilityNodeData objects for a simple document tree,
182   // representing the accessibility information used to initialize
183   // BrowserAccessibilityManager.
184   AccessibilityNodeData text;
185   text.id = 2;
186   text.role = WebKit::WebAXRoleStaticText;
187   text.SetName("old text");
188   text.state = 0;
189
190   AccessibilityNodeData root;
191   root.id = 1;
192   root.SetName("Document");
193   root.role = WebKit::WebAXRoleRootWebArea;
194   root.state = 0;
195   root.child_ids.push_back(2);
196
197   // Construct a BrowserAccessibilityManager with this
198   // AccessibilityNodeData tree and a factory for an instance-counting
199   // BrowserAccessibility.
200   CountedBrowserAccessibility::reset();
201   scoped_ptr<BrowserAccessibilityManager> manager(
202       BrowserAccessibilityManager::Create(
203           root, NULL, new CountedBrowserAccessibilityFactory()));
204   manager->UpdateNodesForTesting(text);
205
206   // Query for the text IAccessible and verify that it returns "old text" as its
207   // value.
208   base::win::ScopedVariant one(1);
209   base::win::ScopedComPtr<IDispatch> text_dispatch;
210   HRESULT hr = manager->GetRoot()->ToBrowserAccessibilityWin()->get_accChild(
211       one, text_dispatch.Receive());
212   ASSERT_EQ(S_OK, hr);
213
214   base::win::ScopedComPtr<IAccessible> text_accessible;
215   hr = text_dispatch.QueryInterface(text_accessible.Receive());
216   ASSERT_EQ(S_OK, hr);
217
218   base::win::ScopedVariant childid_self(CHILDID_SELF);
219   base::win::ScopedBstr name;
220   hr = text_accessible->get_accName(childid_self, name.Receive());
221   ASSERT_EQ(S_OK, hr);
222   EXPECT_EQ(L"old text", string16(name));
223   name.Reset();
224
225   text_dispatch.Release();
226   text_accessible.Release();
227
228   // Notify the BrowserAccessibilityManager that the text child has changed.
229   AccessibilityNodeData text2;
230   text2.id = 2;
231   text2.role = WebKit::WebAXRoleStaticText;
232   text2.SetName("new text");
233   text2.SetName("old text");
234   AccessibilityHostMsg_EventParams param;
235   param.event_type = WebKit::WebAXEventChildrenChanged;
236   param.nodes.push_back(text2);
237   param.id = text2.id;
238   std::vector<AccessibilityHostMsg_EventParams> events;
239   events.push_back(param);
240   manager->OnAccessibilityEvents(events);
241
242   // Query for the text IAccessible and verify that it now returns "new text"
243   // as its value.
244   hr = manager->GetRoot()->ToBrowserAccessibilityWin()->get_accChild(
245       one, text_dispatch.Receive());
246   ASSERT_EQ(S_OK, hr);
247
248   hr = text_dispatch.QueryInterface(text_accessible.Receive());
249   ASSERT_EQ(S_OK, hr);
250
251   hr = text_accessible->get_accName(childid_self, name.Receive());
252   ASSERT_EQ(S_OK, hr);
253   EXPECT_EQ(L"new text", string16(name));
254
255   text_dispatch.Release();
256   text_accessible.Release();
257
258   // Delete the manager and test that all BrowserAccessibility instances are
259   // deleted.
260   manager.reset();
261   ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
262 }
263
264 TEST_F(BrowserAccessibilityTest, TestChildrenChangeNoLeaks) {
265   // Create AccessibilityNodeData objects for a simple document tree,
266   // representing the accessibility information used to initialize
267   // BrowserAccessibilityManager.
268   AccessibilityNodeData div;
269   div.id = 2;
270   div.role = WebKit::WebAXRoleGroup;
271   div.state = 0;
272
273   AccessibilityNodeData text3;
274   text3.id = 3;
275   text3.role = WebKit::WebAXRoleStaticText;
276   text3.state = 0;
277
278   AccessibilityNodeData text4;
279   text4.id = 4;
280   text4.role = WebKit::WebAXRoleStaticText;
281   text4.state = 0;
282
283   div.child_ids.push_back(3);
284   div.child_ids.push_back(4);
285
286   AccessibilityNodeData root;
287   root.id = 1;
288   root.role = WebKit::WebAXRoleRootWebArea;
289   root.state = 0;
290   root.child_ids.push_back(2);
291
292   // Construct a BrowserAccessibilityManager with this
293   // AccessibilityNodeData tree and a factory for an instance-counting
294   // BrowserAccessibility and ensure that exactly 4 instances were
295   // created. Note that the manager takes ownership of the factory.
296   CountedBrowserAccessibility::reset();
297   scoped_ptr<BrowserAccessibilityManager> manager(
298       BrowserAccessibilityManager::Create(
299           root, NULL, new CountedBrowserAccessibilityFactory()));
300   manager->UpdateNodesForTesting(div, text3, text4);
301   ASSERT_EQ(4, CountedBrowserAccessibility::num_instances());
302
303   // Notify the BrowserAccessibilityManager that the div node and its children
304   // were removed and ensure that only one BrowserAccessibility instance exists.
305   root.child_ids.clear();
306   AccessibilityHostMsg_EventParams param;
307   param.event_type = WebKit::WebAXEventChildrenChanged;
308   param.nodes.push_back(root);
309   param.id = root.id;
310   std::vector<AccessibilityHostMsg_EventParams> events;
311   events.push_back(param);
312   manager->OnAccessibilityEvents(events);
313   ASSERT_EQ(1, CountedBrowserAccessibility::num_instances());
314
315   // Delete the manager and test that all BrowserAccessibility instances are
316   // deleted.
317   manager.reset();
318   ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
319 }
320
321 TEST_F(BrowserAccessibilityTest, TestTextBoundaries) {
322   std::string text1_value = "One two three.\nFour five six.";
323
324   AccessibilityNodeData text1;
325   text1.id = 11;
326   text1.role = WebKit::WebAXRoleTextField;
327   text1.state = 0;
328   text1.AddStringAttribute(AccessibilityNodeData::ATTR_VALUE, text1_value);
329   std::vector<int32> line_breaks;
330   line_breaks.push_back(15);
331   text1.AddIntListAttribute(
332       AccessibilityNodeData::ATTR_LINE_BREAKS, line_breaks);
333
334   AccessibilityNodeData root;
335   root.id = 1;
336   root.role = WebKit::WebAXRoleRootWebArea;
337   root.state = 0;
338   root.child_ids.push_back(11);
339
340   CountedBrowserAccessibility::reset();
341   scoped_ptr<BrowserAccessibilityManager> manager(
342       BrowserAccessibilityManager::Create(
343           root, NULL, new CountedBrowserAccessibilityFactory()));
344   manager->UpdateNodesForTesting(text1);
345   ASSERT_EQ(2, CountedBrowserAccessibility::num_instances());
346
347   BrowserAccessibilityWin* root_obj =
348       manager->GetRoot()->ToBrowserAccessibilityWin();
349   BrowserAccessibilityWin* text1_obj =
350       root_obj->PlatformGetChild(0)->ToBrowserAccessibilityWin();
351
352   long text1_len;
353   ASSERT_EQ(S_OK, text1_obj->get_nCharacters(&text1_len));
354
355   base::win::ScopedBstr text;
356   ASSERT_EQ(S_OK, text1_obj->get_text(0, text1_len, text.Receive()));
357   ASSERT_EQ(text1_value, base::UTF16ToUTF8(string16(text)));
358   text.Reset();
359
360   ASSERT_EQ(S_OK, text1_obj->get_text(0, 4, text.Receive()));
361   ASSERT_STREQ(L"One ", text);
362   text.Reset();
363
364   long start;
365   long end;
366   ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
367       1, IA2_TEXT_BOUNDARY_CHAR, &start, &end, text.Receive()));
368   ASSERT_EQ(1, start);
369   ASSERT_EQ(2, end);
370   ASSERT_STREQ(L"n", text);
371   text.Reset();
372
373   ASSERT_EQ(S_FALSE, text1_obj->get_textAtOffset(
374       text1_len, IA2_TEXT_BOUNDARY_CHAR, &start, &end, text.Receive()));
375   ASSERT_EQ(text1_len, start);
376   ASSERT_EQ(text1_len, end);
377   text.Reset();
378
379   ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
380       1, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive()));
381   ASSERT_EQ(0, start);
382   ASSERT_EQ(3, end);
383   ASSERT_STREQ(L"One", text);
384   text.Reset();
385
386   ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
387       6, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive()));
388   ASSERT_EQ(4, start);
389   ASSERT_EQ(7, end);
390   ASSERT_STREQ(L"two", text);
391   text.Reset();
392
393   ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
394       text1_len, IA2_TEXT_BOUNDARY_WORD, &start, &end, text.Receive()));
395   ASSERT_EQ(25, start);
396   ASSERT_EQ(29, end);
397   ASSERT_STREQ(L"six.", text);
398   text.Reset();
399
400   ASSERT_EQ(S_OK, text1_obj->get_textAtOffset(
401       1, IA2_TEXT_BOUNDARY_LINE, &start, &end, text.Receive()));
402   ASSERT_EQ(0, start);
403   ASSERT_EQ(15, end);
404   ASSERT_STREQ(L"One two three.\n", text);
405   text.Reset();
406
407   ASSERT_EQ(S_OK,
408             text1_obj->get_text(0, IA2_TEXT_OFFSET_LENGTH, text.Receive()));
409   ASSERT_STREQ(L"One two three.\nFour five six.", text);
410
411   // Delete the manager and test that all BrowserAccessibility instances are
412   // deleted.
413   manager.reset();
414   ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
415 }
416
417 TEST_F(BrowserAccessibilityTest, TestSimpleHypertext) {
418   const std::string text1_name = "One two three.";
419   const std::string text2_name = " Four five six.";
420
421   AccessibilityNodeData text1;
422   text1.id = 11;
423   text1.role = WebKit::WebAXRoleStaticText;
424   text1.state = 1 << WebKit::WebAXStateReadonly;
425   text1.SetName(text1_name);
426
427   AccessibilityNodeData text2;
428   text2.id = 12;
429   text2.role = WebKit::WebAXRoleStaticText;
430   text2.state = 1 << WebKit::WebAXStateReadonly;
431   text2.SetName(text2_name);
432
433   AccessibilityNodeData root;
434   root.id = 1;
435   root.role = WebKit::WebAXRoleRootWebArea;
436   root.state = 1 << WebKit::WebAXStateReadonly;
437   root.child_ids.push_back(11);
438   root.child_ids.push_back(12);
439
440   CountedBrowserAccessibility::reset();
441   scoped_ptr<BrowserAccessibilityManager> manager(
442       BrowserAccessibilityManager::Create(
443           root, NULL, new CountedBrowserAccessibilityFactory()));
444   manager->UpdateNodesForTesting(root, text1, text2);
445   ASSERT_EQ(3, CountedBrowserAccessibility::num_instances());
446
447   BrowserAccessibilityWin* root_obj =
448       manager->GetRoot()->ToBrowserAccessibilityWin();
449
450   long text_len;
451   ASSERT_EQ(S_OK, root_obj->get_nCharacters(&text_len));
452
453   base::win::ScopedBstr text;
454   ASSERT_EQ(S_OK, root_obj->get_text(0, text_len, text.Receive()));
455   EXPECT_EQ(text1_name + text2_name, base::UTF16ToUTF8(string16(text)));
456
457   long hyperlink_count;
458   ASSERT_EQ(S_OK, root_obj->get_nHyperlinks(&hyperlink_count));
459   EXPECT_EQ(0, hyperlink_count);
460
461   base::win::ScopedComPtr<IAccessibleHyperlink> hyperlink;
462   EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(-1, hyperlink.Receive()));
463   EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(0, hyperlink.Receive()));
464   EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(28, hyperlink.Receive()));
465   EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(29, hyperlink.Receive()));
466
467   long hyperlink_index;
468   EXPECT_EQ(E_FAIL, root_obj->get_hyperlinkIndex(0, &hyperlink_index));
469   EXPECT_EQ(-1, hyperlink_index);
470   EXPECT_EQ(E_FAIL, root_obj->get_hyperlinkIndex(28, &hyperlink_index));
471   EXPECT_EQ(-1, hyperlink_index);
472   EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlinkIndex(-1, &hyperlink_index));
473   EXPECT_EQ(-1, hyperlink_index);
474   EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlinkIndex(29, &hyperlink_index));
475   EXPECT_EQ(-1, hyperlink_index);
476
477   // Delete the manager and test that all BrowserAccessibility instances are
478   // deleted.
479   manager.reset();
480   ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
481 }
482
483 TEST_F(BrowserAccessibilityTest, TestComplexHypertext) {
484   const std::string text1_name = "One two three.";
485   const std::string text2_name = " Four five six.";
486   const std::string button1_text_name = "red";
487   const std::string link1_text_name = "blue";
488
489   AccessibilityNodeData text1;
490   text1.id = 11;
491   text1.role = WebKit::WebAXRoleStaticText;
492   text1.state = 1 << WebKit::WebAXStateReadonly;
493   text1.SetName(text1_name);
494
495   AccessibilityNodeData text2;
496   text2.id = 12;
497   text2.role = WebKit::WebAXRoleStaticText;
498   text2.state = 1 << WebKit::WebAXStateReadonly;
499   text2.SetName(text2_name);
500
501   AccessibilityNodeData button1, button1_text;
502   button1.id = 13;
503   button1_text.id = 15;
504   button1_text.SetName(button1_text_name);
505   button1.role = WebKit::WebAXRoleButton;
506   button1_text.role = WebKit::WebAXRoleStaticText;
507   button1.state = 1 << WebKit::WebAXStateReadonly;
508   button1_text.state = 1 << WebKit::WebAXStateReadonly;
509   button1.child_ids.push_back(15);
510
511   AccessibilityNodeData link1, link1_text;
512   link1.id = 14;
513   link1_text.id = 16;
514   link1_text.SetName(link1_text_name);
515   link1.role = WebKit::WebAXRoleLink;
516   link1_text.role = WebKit::WebAXRoleStaticText;
517   link1.state = 1 << WebKit::WebAXStateReadonly;
518   link1_text.state = 1 << WebKit::WebAXStateReadonly;
519   link1.child_ids.push_back(16);
520
521   AccessibilityNodeData root;
522   root.id = 1;
523   root.role = WebKit::WebAXRoleRootWebArea;
524   root.state = 1 << WebKit::WebAXStateReadonly;
525   root.child_ids.push_back(11);
526   root.child_ids.push_back(13);
527   root.child_ids.push_back(12);
528   root.child_ids.push_back(14);
529
530   CountedBrowserAccessibility::reset();
531   scoped_ptr<BrowserAccessibilityManager> manager(
532       BrowserAccessibilityManager::Create(
533           root, NULL, new CountedBrowserAccessibilityFactory()));
534   manager->UpdateNodesForTesting(root,
535                                  text1, button1, button1_text,
536                                  text2, link1, link1_text);
537
538   ASSERT_EQ(7, CountedBrowserAccessibility::num_instances());
539
540   BrowserAccessibilityWin* root_obj =
541       manager->GetRoot()->ToBrowserAccessibilityWin();
542
543   long text_len;
544   ASSERT_EQ(S_OK, root_obj->get_nCharacters(&text_len));
545
546   base::win::ScopedBstr text;
547   ASSERT_EQ(S_OK, root_obj->get_text(0, text_len, text.Receive()));
548   const std::string embed = base::UTF16ToUTF8(
549       BrowserAccessibilityWin::kEmbeddedCharacter);
550   EXPECT_EQ(text1_name + embed + text2_name + embed,
551             UTF16ToUTF8(string16(text)));
552   text.Reset();
553
554   long hyperlink_count;
555   ASSERT_EQ(S_OK, root_obj->get_nHyperlinks(&hyperlink_count));
556   EXPECT_EQ(2, hyperlink_count);
557
558   base::win::ScopedComPtr<IAccessibleHyperlink> hyperlink;
559   base::win::ScopedComPtr<IAccessibleText> hypertext;
560   EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(-1, hyperlink.Receive()));
561   EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(2, hyperlink.Receive()));
562   EXPECT_EQ(E_INVALIDARG, root_obj->get_hyperlink(28, hyperlink.Receive()));
563
564   EXPECT_EQ(S_OK, root_obj->get_hyperlink(0, hyperlink.Receive()));
565   EXPECT_EQ(S_OK,
566             hyperlink.QueryInterface<IAccessibleText>(hypertext.Receive()));
567   EXPECT_EQ(S_OK, hypertext->get_text(0, 3, text.Receive()));
568   EXPECT_STREQ(button1_text_name.c_str(),
569                base::UTF16ToUTF8(string16(text)).c_str());
570   text.Reset();
571   hyperlink.Release();
572   hypertext.Release();
573
574   EXPECT_EQ(S_OK, root_obj->get_hyperlink(1, hyperlink.Receive()));
575   EXPECT_EQ(S_OK,
576             hyperlink.QueryInterface<IAccessibleText>(hypertext.Receive()));
577   EXPECT_EQ(S_OK, hypertext->get_text(0, 4, text.Receive()));
578   EXPECT_STREQ(link1_text_name.c_str(),
579                base::UTF16ToUTF8(string16(text)).c_str());
580   text.Reset();
581   hyperlink.Release();
582   hypertext.Release();
583
584   long hyperlink_index;
585   EXPECT_EQ(E_FAIL, root_obj->get_hyperlinkIndex(0, &hyperlink_index));
586   EXPECT_EQ(-1, hyperlink_index);
587   EXPECT_EQ(E_FAIL, root_obj->get_hyperlinkIndex(28, &hyperlink_index));
588   EXPECT_EQ(-1, hyperlink_index);
589   EXPECT_EQ(S_OK, root_obj->get_hyperlinkIndex(14, &hyperlink_index));
590   EXPECT_EQ(0, hyperlink_index);
591   EXPECT_EQ(S_OK, root_obj->get_hyperlinkIndex(30, &hyperlink_index));
592   EXPECT_EQ(1, hyperlink_index);
593
594   // Delete the manager and test that all BrowserAccessibility instances are
595   // deleted.
596   manager.reset();
597   ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
598 }
599
600 TEST_F(BrowserAccessibilityTest, TestCreateEmptyDocument) {
601   // Try creating an empty document with busy state. Readonly is
602   // set automatically.
603   CountedBrowserAccessibility::reset();
604   const int32 busy_state = 1 << WebKit::WebAXStateBusy;
605   const int32 readonly_state = 1 << WebKit::WebAXStateReadonly;
606   const int32 enabled_state = 1 << WebKit::WebAXStateEnabled;
607   scoped_ptr<BrowserAccessibilityManager> manager(
608       new BrowserAccessibilityManagerWin(
609           GetDesktopWindow(),
610           NULL,
611           BrowserAccessibilityManagerWin::GetEmptyDocument(),
612           NULL,
613           new CountedBrowserAccessibilityFactory()));
614
615   // Verify the root is as we expect by default.
616   BrowserAccessibility* root = manager->GetRoot();
617   EXPECT_EQ(0, root->renderer_id());
618   EXPECT_EQ(WebKit::WebAXRoleRootWebArea, root->role());
619   EXPECT_EQ(busy_state | readonly_state | enabled_state, root->state());
620
621   // Tree with a child textfield.
622   AccessibilityNodeData tree1_1;
623   tree1_1.id = 1;
624   tree1_1.role = WebKit::WebAXRoleRootWebArea;
625   tree1_1.child_ids.push_back(2);
626
627   AccessibilityNodeData tree1_2;
628   tree1_2.id = 2;
629   tree1_2.role = WebKit::WebAXRoleTextField;
630
631   // Process a load complete.
632   std::vector<AccessibilityHostMsg_EventParams> params;
633   params.push_back(AccessibilityHostMsg_EventParams());
634   AccessibilityHostMsg_EventParams* msg = &params[0];
635   msg->event_type = WebKit::WebAXEventLoadComplete;
636   msg->nodes.push_back(tree1_1);
637   msg->nodes.push_back(tree1_2);
638   msg->id = tree1_1.id;
639   manager->OnAccessibilityEvents(params);
640
641   // Save for later comparison.
642   BrowserAccessibility* acc1_2 = manager->GetFromRendererID(2);
643
644   // Verify the root has changed.
645   EXPECT_NE(root, manager->GetRoot());
646
647   // And the proper child remains.
648   EXPECT_EQ(WebKit::WebAXRoleTextField, acc1_2->role());
649   EXPECT_EQ(2, acc1_2->renderer_id());
650
651   // Tree with a child button.
652   AccessibilityNodeData tree2_1;
653   tree2_1.id = 1;
654   tree2_1.role = WebKit::WebAXRoleRootWebArea;
655   tree2_1.child_ids.push_back(3);
656
657   AccessibilityNodeData tree2_2;
658   tree2_2.id = 3;
659   tree2_2.role = WebKit::WebAXRoleButton;
660
661   msg->nodes.clear();
662   msg->nodes.push_back(tree2_1);
663   msg->nodes.push_back(tree2_2);
664   msg->id = tree2_1.id;
665
666   // Fire another load complete.
667   manager->OnAccessibilityEvents(params);
668
669   BrowserAccessibility* acc2_2 = manager->GetFromRendererID(3);
670
671   // Verify the root has changed.
672   EXPECT_NE(root, manager->GetRoot());
673
674   // And the new child exists.
675   EXPECT_EQ(WebKit::WebAXRoleButton, acc2_2->role());
676   EXPECT_EQ(3, acc2_2->renderer_id());
677
678   // Ensure we properly cleaned up.
679   manager.reset();
680   ASSERT_EQ(0, CountedBrowserAccessibility::num_instances());
681 }
682
683 }  // namespace content