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.
5 #import <Cocoa/Cocoa.h>
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/base/test/ui_cocoa_test_helper.h"
17 @interface MockAccessibilityDelegate :
18 NSView<BrowserAccessibilityDelegateCocoa>
20 - (NSPoint)accessibilityPointInScreen:(NSPoint)origin
22 - (void)doDefaultAction:(int32)accessibilityObjectId;
23 - (void)accessibilitySetTextSelection:(int32)accId
24 startOffset:(int32)startOffset
25 endOffset:(int32)endOffset;
26 - (void)performShowMenuAction:(BrowserAccessibilityCocoa*)accessibility;
27 - (void)setAccessibilityFocus:(BOOL)focus
28 accessibilityId:(int32)accessibilityObjectId;
33 @implementation MockAccessibilityDelegate
35 - (NSPoint)accessibilityPointInScreen:(NSPoint)origin
39 - (void)doDefaultAction:(int32)accessibilityObjectId {
41 - (void)accessibilitySetTextSelection:(int32)accId
42 startOffset:(int32)startOffset
43 endOffset:(int32)endOffset {
45 - (void)performShowMenuAction:(BrowserAccessibilityCocoa*)accessibility {
47 - (void)setAccessibilityFocus:(BOOL)focus
48 accessibilityId:(int32)accessibilityObjectId {
58 class BrowserAccessibilityTest : public ui::CocoaTest {
60 virtual void SetUp() {
62 RebuildAccessibilityTree();
66 void RebuildAccessibilityTree() {
69 root.location.set_width(500);
70 root.location.set_height(100);
71 root.role = ui::AX_ROLE_ROOT_WEB_AREA;
72 root.AddStringAttribute(ui::AX_ATTR_HELP, "HelpText");
73 root.child_ids.push_back(1001);
74 root.child_ids.push_back(1002);
76 ui::AXNodeData child1;
78 child1.SetName("Child1");
79 child1.location.set_width(250);
80 child1.location.set_height(100);
81 child1.role = ui::AX_ROLE_BUTTON;
83 ui::AXNodeData child2;
85 child2.location.set_x(250);
86 child2.location.set_width(250);
87 child2.location.set_height(100);
88 child2.role = ui::AX_ROLE_HEADING;
90 delegate_.reset([[MockAccessibilityDelegate alloc] init]);
92 new BrowserAccessibilityManagerMac(delegate_, root, NULL));
93 manager_->UpdateNodesForTesting(child1, child2);
94 accessibility_.reset([manager_->GetRoot()->ToBrowserAccessibilityCocoa()
98 base::scoped_nsobject<MockAccessibilityDelegate> delegate_;
99 base::scoped_nsobject<BrowserAccessibilityCocoa> accessibility_;
100 scoped_ptr<BrowserAccessibilityManager> manager_;
103 // Standard hit test.
104 TEST_F(BrowserAccessibilityTest, HitTestTest) {
105 BrowserAccessibilityCocoa* firstChild =
106 [accessibility_ accessibilityHitTest:NSMakePoint(50, 50)];
107 EXPECT_NSEQ(@"Child1",
108 [firstChild accessibilityAttributeValue:NSAccessibilityTitleAttribute]);
111 // Test doing a hit test on the edge of a child.
112 TEST_F(BrowserAccessibilityTest, EdgeHitTest) {
113 BrowserAccessibilityCocoa* firstChild =
114 [accessibility_ accessibilityHitTest:NSZeroPoint];
115 EXPECT_NSEQ(@"Child1",
116 [firstChild accessibilityAttributeValue:NSAccessibilityTitleAttribute]);
119 // This will test a hit test with invalid coordinates. It is assumed that
120 // the hit test has been narrowed down to this object or one of its children
121 // so it should return itself since it has no better hit result.
122 TEST_F(BrowserAccessibilityTest, InvalidHitTestCoordsTest) {
123 BrowserAccessibilityCocoa* hitTestResult =
124 [accessibility_ accessibilityHitTest:NSMakePoint(-50, 50)];
125 EXPECT_NSEQ(accessibility_, hitTestResult);
128 // Test to ensure querying standard attributes works.
129 TEST_F(BrowserAccessibilityTest, BasicAttributeTest) {
130 NSString* helpText = [accessibility_
131 accessibilityAttributeValue:NSAccessibilityHelpAttribute];
132 EXPECT_NSEQ(@"HelpText", helpText);
135 // Test querying for an invalid attribute to ensure it doesn't crash.
136 TEST_F(BrowserAccessibilityTest, InvalidAttributeTest) {
137 NSString* shouldBeNil = [accessibility_
138 accessibilityAttributeValue:@"NSAnInvalidAttribute"];
139 EXPECT_TRUE(shouldBeNil == nil);
142 TEST_F(BrowserAccessibilityTest, RetainedDetachedObjectsReturnNil) {
143 // Get the first child.
144 BrowserAccessibilityCocoa* retainedFirstChild =
145 [accessibility_ accessibilityHitTest:NSMakePoint(50, 50)];
146 EXPECT_NSEQ(@"Child1", [retainedFirstChild
147 accessibilityAttributeValue:NSAccessibilityTitleAttribute]);
149 // Retain it. This simulates what the system might do with an
150 // accessibility object.
151 [retainedFirstChild retain];
153 // Rebuild the accessibility tree, which should detach |retainedFirstChild|.
154 RebuildAccessibilityTree();
156 // Now any attributes we query should return nil.
157 EXPECT_EQ(nil, [retainedFirstChild
158 accessibilityAttributeValue:NSAccessibilityTitleAttribute]);
160 // Don't leak memory in the test.
161 [retainedFirstChild release];
164 } // namespace content