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/base/test/ui_cocoa_test_helper.h" 16 17@interface MockAccessibilityDelegate : 18 NSView<BrowserAccessibilityDelegateCocoa> 19 20- (NSPoint)accessibilityPointInScreen:(NSPoint)origin 21 size:(NSSize)size; 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; 29- (NSWindow*)window; 30 31@end 32 33@implementation MockAccessibilityDelegate 34 35- (NSPoint)accessibilityPointInScreen:(NSPoint)origin 36 size:(NSSize)size { 37 return NSZeroPoint; 38} 39- (void)doDefaultAction:(int32)accessibilityObjectId { 40} 41- (void)accessibilitySetTextSelection:(int32)accId 42 startOffset:(int32)startOffset 43 endOffset:(int32)endOffset { 44} 45- (void)performShowMenuAction:(BrowserAccessibilityCocoa*)accessibility { 46} 47- (void)setAccessibilityFocus:(BOOL)focus 48 accessibilityId:(int32)accessibilityObjectId { 49} 50- (NSWindow*)window { 51 return nil; 52} 53 54@end 55 56namespace content { 57 58class BrowserAccessibilityTest : public ui::CocoaTest { 59 public: 60 virtual void SetUp() { 61 CocoaTest::SetUp(); 62 RebuildAccessibilityTree(); 63 } 64 65 protected: 66 void RebuildAccessibilityTree() { 67 AccessibilityNodeData root; 68 root.id = 1000; 69 root.location.set_width(500); 70 root.location.set_height(100); 71 root.role = blink::WebAXRoleRootWebArea; 72 root.AddStringAttribute(AccessibilityNodeData::ATTR_HELP, "HelpText"); 73 root.child_ids.push_back(1001); 74 root.child_ids.push_back(1002); 75 76 AccessibilityNodeData child1; 77 child1.id = 1001; 78 child1.SetName("Child1"); 79 child1.location.set_width(250); 80 child1.location.set_height(100); 81 child1.role = blink::WebAXRoleButton; 82 83 AccessibilityNodeData child2; 84 child2.id = 1002; 85 child2.location.set_x(250); 86 child2.location.set_width(250); 87 child2.location.set_height(100); 88 child2.role = blink::WebAXRoleHeading; 89 90 delegate_.reset([[MockAccessibilityDelegate alloc] init]); 91 manager_.reset( 92 new BrowserAccessibilityManagerMac(delegate_, root, NULL)); 93 manager_->UpdateNodesForTesting(child1, child2); 94 accessibility_.reset([manager_->GetRoot()->ToBrowserAccessibilityCocoa() 95 retain]); 96 } 97 98 base::scoped_nsobject<MockAccessibilityDelegate> delegate_; 99 base::scoped_nsobject<BrowserAccessibilityCocoa> accessibility_; 100 scoped_ptr<BrowserAccessibilityManager> manager_; 101}; 102 103// Standard hit test. 104TEST_F(BrowserAccessibilityTest, HitTestTest) { 105 BrowserAccessibilityCocoa* firstChild = 106 [accessibility_ accessibilityHitTest:NSMakePoint(50, 50)]; 107 EXPECT_NSEQ(@"Child1", 108 [firstChild accessibilityAttributeValue:NSAccessibilityTitleAttribute]); 109} 110 111// Test doing a hit test on the edge of a child. 112TEST_F(BrowserAccessibilityTest, EdgeHitTest) { 113 BrowserAccessibilityCocoa* firstChild = 114 [accessibility_ accessibilityHitTest:NSZeroPoint]; 115 EXPECT_NSEQ(@"Child1", 116 [firstChild accessibilityAttributeValue:NSAccessibilityTitleAttribute]); 117} 118 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. 122TEST_F(BrowserAccessibilityTest, InvalidHitTestCoordsTest) { 123 BrowserAccessibilityCocoa* hitTestResult = 124 [accessibility_ accessibilityHitTest:NSMakePoint(-50, 50)]; 125 EXPECT_NSEQ(accessibility_, hitTestResult); 126} 127 128// Test to ensure querying standard attributes works. 129TEST_F(BrowserAccessibilityTest, BasicAttributeTest) { 130 NSString* helpText = [accessibility_ 131 accessibilityAttributeValue:NSAccessibilityHelpAttribute]; 132 EXPECT_NSEQ(@"HelpText", helpText); 133} 134 135// Test querying for an invalid attribute to ensure it doesn't crash. 136TEST_F(BrowserAccessibilityTest, InvalidAttributeTest) { 137 NSString* shouldBeNil = [accessibility_ 138 accessibilityAttributeValue:@"NSAnInvalidAttribute"]; 139 EXPECT_TRUE(shouldBeNil == nil); 140} 141 142TEST_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]); 148 149 // Retain it. This simulates what the system might do with an 150 // accessibility object. 151 [retainedFirstChild retain]; 152 153 // Rebuild the accessibility tree, which should detach |retainedFirstChild|. 154 RebuildAccessibilityTree(); 155 156 // Now any attributes we query should return nil. 157 EXPECT_EQ(nil, [retainedFirstChild 158 accessibilityAttributeValue:NSAccessibilityTitleAttribute]); 159 160 // Don't leak memory in the test. 161 [retainedFirstChild release]; 162} 163 164} // namespace content 165