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