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#import <Cocoa/Cocoa.h>
6
7#include "base/memory/scoped_ptr.h"
8#include "base/strings/string_util.h"
9#include "base/strings/utf_string_conversions.h"
10#include "content/browser/accessibility/browser_accessibility_cocoa.h"
11#include "content/browser/accessibility/browser_accessibility_manager.h"
12#include "content/browser/accessibility/browser_accessibility_manager_mac.h"
13#include "testing/gtest/include/gtest/gtest.h"
14#import "testing/gtest_mac.h"
15#import "ui/gfx/test/ui_cocoa_test_helper.h"
16
17namespace content {
18
19class BrowserAccessibilityTest : public ui::CocoaTest {
20 public:
21  virtual void SetUp() {
22    CocoaTest::SetUp();
23    RebuildAccessibilityTree();
24  }
25
26 protected:
27  void RebuildAccessibilityTree() {
28    ui::AXNodeData root;
29    root.id = 1000;
30    root.location.set_width(500);
31    root.location.set_height(100);
32    root.role = ui::AX_ROLE_ROOT_WEB_AREA;
33    root.AddStringAttribute(ui::AX_ATTR_HELP, "HelpText");
34    root.child_ids.push_back(1001);
35    root.child_ids.push_back(1002);
36
37    ui::AXNodeData child1;
38    child1.id = 1001;
39    child1.SetName("Child1");
40    child1.location.set_width(250);
41    child1.location.set_height(100);
42    child1.role = ui::AX_ROLE_BUTTON;
43
44    ui::AXNodeData child2;
45    child2.id = 1002;
46    child2.location.set_x(250);
47    child2.location.set_width(250);
48    child2.location.set_height(100);
49    child2.role = ui::AX_ROLE_HEADING;
50
51    manager_.reset(
52        new BrowserAccessibilityManagerMac(
53            nil,
54            MakeAXTreeUpdate(root, child1, child2),
55            NULL));
56    accessibility_.reset([manager_->GetRoot()->ToBrowserAccessibilityCocoa()
57        retain]);
58  }
59
60  base::scoped_nsobject<BrowserAccessibilityCocoa> accessibility_;
61  scoped_ptr<BrowserAccessibilityManager> manager_;
62};
63
64// Standard hit test.
65TEST_F(BrowserAccessibilityTest, HitTestTest) {
66  BrowserAccessibilityCocoa* firstChild =
67      [accessibility_ accessibilityHitTest:NSMakePoint(50, 50)];
68  EXPECT_NSEQ(@"Child1",
69      [firstChild accessibilityAttributeValue:NSAccessibilityTitleAttribute]);
70}
71
72// Test doing a hit test on the edge of a child.
73TEST_F(BrowserAccessibilityTest, EdgeHitTest) {
74  BrowserAccessibilityCocoa* firstChild =
75      [accessibility_ accessibilityHitTest:NSZeroPoint];
76  EXPECT_NSEQ(@"Child1",
77      [firstChild accessibilityAttributeValue:NSAccessibilityTitleAttribute]);
78}
79
80// This will test a hit test with invalid coordinates.  It is assumed that
81// the hit test has been narrowed down to this object or one of its children
82// so it should return itself since it has no better hit result.
83TEST_F(BrowserAccessibilityTest, InvalidHitTestCoordsTest) {
84  BrowserAccessibilityCocoa* hitTestResult =
85      [accessibility_ accessibilityHitTest:NSMakePoint(-50, 50)];
86  EXPECT_NSEQ(accessibility_, hitTestResult);
87}
88
89// Test to ensure querying standard attributes works.
90TEST_F(BrowserAccessibilityTest, BasicAttributeTest) {
91  NSString* helpText = [accessibility_
92      accessibilityAttributeValue:NSAccessibilityHelpAttribute];
93  EXPECT_NSEQ(@"HelpText", helpText);
94}
95
96// Test querying for an invalid attribute to ensure it doesn't crash.
97TEST_F(BrowserAccessibilityTest, InvalidAttributeTest) {
98  NSString* shouldBeNil = [accessibility_
99      accessibilityAttributeValue:@"NSAnInvalidAttribute"];
100  EXPECT_TRUE(shouldBeNil == nil);
101}
102
103TEST_F(BrowserAccessibilityTest, RetainedDetachedObjectsReturnNil) {
104  // Get the first child.
105  BrowserAccessibilityCocoa* retainedFirstChild =
106      [accessibility_ accessibilityHitTest:NSMakePoint(50, 50)];
107  EXPECT_NSEQ(@"Child1", [retainedFirstChild
108      accessibilityAttributeValue:NSAccessibilityTitleAttribute]);
109
110  // Retain it. This simulates what the system might do with an
111  // accessibility object.
112  [retainedFirstChild retain];
113
114  // Rebuild the accessibility tree, which should detach |retainedFirstChild|.
115  RebuildAccessibilityTree();
116
117  // Now any attributes we query should return nil.
118  EXPECT_EQ(nil, [retainedFirstChild
119      accessibilityAttributeValue:NSAccessibilityTitleAttribute]);
120
121  // Don't leak memory in the test.
122  [retainedFirstChild release];
123}
124
125}  // namespace content
126