diff options
author | dtseng@chromium.org <dtseng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-24 03:09:44 +0000 |
---|---|---|
committer | dtseng@chromium.org <dtseng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-11-24 03:09:44 +0000 |
commit | 5f5d58a9635023d87a8acbe11c4aacc4fb387e14 (patch) | |
tree | b0d17bb1f5e424e60d08709d9d9fbdae551c9416 /chrome/browser/accessibility | |
parent | ce163a942cce41d1774eac0bee0056b90464fd15 (diff) | |
download | chromium_src-5f5d58a9635023d87a8acbe11c4aacc4fb387e14.zip chromium_src-5f5d58a9635023d87a8acbe11c4aacc4fb387e14.tar.gz chromium_src-5f5d58a9635023d87a8acbe11c4aacc4fb387e14.tar.bz2 |
Reland 66893.
TBR=dtseng
Review URL: http://codereview.chromium.org/5326003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@67208 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/accessibility')
-rw-r--r-- | chrome/browser/accessibility/accessibility_mac_uitest.mm | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/chrome/browser/accessibility/accessibility_mac_uitest.mm b/chrome/browser/accessibility/accessibility_mac_uitest.mm new file mode 100644 index 0000000..45cdd11 --- /dev/null +++ b/chrome/browser/accessibility/accessibility_mac_uitest.mm @@ -0,0 +1,202 @@ +// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import <Cocoa/Cocoa.h> + +#include "base/scoped_nsobject.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/test/ui/ui_test.h" + +// The following tests exercise the Chrome Mac accessibility implementation +// similarly to the way in which VoiceOver would. +// We achieve this by utilizing the same carbon API (HIServices) as do +// other assistive technologies. +// Note that the tests must be UITests since these API's only work if not +// called within the same process begin examined. +class AccessibilityMacUITest : public UITest { + public: + AccessibilityMacUITest() { + // TODO(dtseng): fake the VoiceOver defaults value? + launch_arguments_.AppendSwitch(switches::kForceRendererAccessibility); + } + + virtual void SetUp() { + UITest::SetUp(); + SetupObservedNotifications(); + Initialize(); + } + + // Called to insert an event for validation. + // This is a order sensitive expectation. + void AddExpectedEvent(NSString* notificationName) { + [AccessibilityMacUITest::expectedEvents addObject:notificationName]; + } + + // Assert that there are no remaining expected events. + // CFRunLoop necessary to receive AX callbacks. + // Assumes that there is at least one expected event. + // The runloop stops only if we receive all expected notifications. + void WaitAndAssertAllEventsObserved() { + ASSERT_GE([expectedEvents count], 1U); + CFRunLoopRunInMode( + kCFRunLoopDefaultMode, action_max_timeout_ms()/1000, false); + ASSERT_EQ(0U, [AccessibilityMacUITest::expectedEvents count]); + } + + // The Callback handler added to each AXUIElement. + static void EventReceiver( + AXObserverRef observerRef, + AXUIElementRef element, + CFStringRef notificationName, + void *refcon) { + if ([[AccessibilityMacUITest::expectedEvents objectAtIndex:0] + isEqualToString:(NSString*)notificationName]) { + [AccessibilityMacUITest::expectedEvents removeObjectAtIndex:0]; + } + + if ([AccessibilityMacUITest::expectedEvents count] == 0) { + CFRunLoopStop(CFRunLoopGetCurrent()); + } + + // TODO(dtseng): currently refreshing on all notifications; scope later. + AccessibilityMacUITest::SetAllObserversOnDescendants( + element, observerRef); + } + + private: + // Perform AX setup. + void Initialize() { + AccessibilityMacUITest::expectedEvents.reset([[NSMutableArray alloc] init]); + + // Construct the Chrome AXUIElementRef. + ASSERT_NE(-1, browser_process_id()); + AXUIElementRef browserUiElement = + AXUIElementCreateApplication(browser_process_id()); + ASSERT_TRUE(browserUiElement); + + // Setup our callbacks. + AXObserverRef observerRef; + ASSERT_EQ(kAXErrorSuccess, + AXObserverCreate(browser_process_id(), + AccessibilityMacUITest::EventReceiver, + &observerRef)); + SetAllObserversOnDescendants(browserUiElement, observerRef); + + // Add the observer to the current message loop. + CFRunLoopAddSource( + [[NSRunLoop currentRunLoop] getCFRunLoop], + AXObserverGetRunLoopSource(observerRef), + kCFRunLoopDefaultMode); + } + + // Taken largely from AXNotificationConstants.h + // (substituted NSAccessibility* to avoid casting). + static void SetupObservedNotifications() { + AccessibilityMacUITest::observedNotifications.reset( + [[NSArray alloc] initWithObjects: + + // focus notifications + NSAccessibilityMainWindowChangedNotification, + NSAccessibilityFocusedWindowChangedNotification, + NSAccessibilityFocusedUIElementChangedNotification, + + // application notifications + NSAccessibilityApplicationActivatedNotification, + NSAccessibilityApplicationDeactivatedNotification, + NSAccessibilityApplicationHiddenNotification, + NSAccessibilityApplicationShownNotification, + + // window notifications + NSAccessibilityWindowCreatedNotification, + NSAccessibilityWindowMovedNotification, + NSAccessibilityWindowResizedNotification, + NSAccessibilityWindowMiniaturizedNotification, + NSAccessibilityWindowDeminiaturizedNotification, + + // new drawer, sheet, and help tag notifications + NSAccessibilityDrawerCreatedNotification, + NSAccessibilitySheetCreatedNotification, + NSAccessibilityHelpTagCreatedNotification, + + // element notifications + NSAccessibilityValueChangedNotification, + NSAccessibilityUIElementDestroyedNotification, + + // menu notifications + (NSString*)kAXMenuOpenedNotification, + (NSString*)kAXMenuClosedNotification, + (NSString*)kAXMenuItemSelectedNotification, + + // table/outline notifications + NSAccessibilityRowCountChangedNotification, + + // other notifications + NSAccessibilitySelectedChildrenChangedNotification, + NSAccessibilityResizedNotification, + NSAccessibilityMovedNotification, + NSAccessibilityCreatedNotification, + NSAccessibilitySelectedRowsChangedNotification, + NSAccessibilitySelectedColumnsChangedNotification, + NSAccessibilitySelectedTextChangedNotification, + NSAccessibilityTitleChangedNotification, + + // Webkit specific notifications. + @"AXLoadComplete", + nil]); + } + + // Observe AX notifications on element and all descendants. + static void SetAllObserversOnDescendants( + AXUIElementRef element, + AXObserverRef observerRef) { + SetAllObservers(element, observerRef); + CFTypeRef childrenRef; + if ((AXUIElementCopyAttributeValue( + element, kAXChildrenAttribute, &childrenRef)) == kAXErrorSuccess) { + NSArray* children = (NSArray*)childrenRef; + for (uint32 i = 0; i < [children count]; ++i) { + SetAllObserversOnDescendants( + (AXUIElementRef)[children objectAtIndex:i], observerRef); + } + } + } + + // Add observers for all notifications we know about. + static void SetAllObservers( + AXUIElementRef element, + AXObserverRef observerRef) { + for (NSString* notification in + AccessibilityMacUITest::observedNotifications.get()) { + AXObserverAddNotification( + observerRef, element, (CFStringRef)notification, nil); + } + } + + // Used to keep track of events received during the lifetime of the tests. + static scoped_nsobject<NSMutableArray> expectedEvents; + // NSString collection of all AX notifications. + static scoped_nsobject<NSArray> observedNotifications; +}; + +scoped_nsobject<NSMutableArray> AccessibilityMacUITest::expectedEvents; +scoped_nsobject<NSArray> AccessibilityMacUITest::observedNotifications; + +TEST_F(AccessibilityMacUITest, TestInitialPageNotifications) { + // Test for initial page load. + AddExpectedEvent(@"AXLoadComplete"); + WaitAndAssertAllEventsObserved(); + + // Browse to a new page. + GURL tree_url( + "data:text/html,<html><head><title>Accessibility Mac Test</title></head>" + "<body><input type='button' value='push' /><input type='checkbox' />" + "</body></html>"); + NavigateToURLAsync(tree_url); + + // Test for navigation. + AddExpectedEvent(@"AXLoadComplete"); + + // Check all the expected Mac notifications. + WaitAndAssertAllEventsObserved(); +} |