diff options
23 files changed, 427 insertions, 349 deletions
diff --git a/chrome/browser/renderer_host/render_widget_host_view_mac.h b/chrome/browser/renderer_host/render_widget_host_view_mac.h index 2adc925..71e1c53 100644 --- a/chrome/browser/renderer_host/render_widget_host_view_mac.h +++ b/chrome/browser/renderer_host/render_widget_host_view_mac.h @@ -12,13 +12,13 @@ #include "base/memory/scoped_ptr.h" #include "base/task.h" #include "base/time.h" -#include "chrome/browser/ui/cocoa/base_view.h" #include "content/browser/accessibility/browser_accessibility_delegate_mac.h" #include "content/browser/accessibility/browser_accessibility_manager.h" #include "content/browser/renderer_host/accelerated_surface_container_manager_mac.h" #include "content/browser/renderer_host/render_widget_host_view.h" #include "content/common/edit_command.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebCompositionUnderline.h" +#include "ui/base/cocoa/base_view.h" #include "webkit/glue/webcursor.h" @class AcceleratedPluginView; diff --git a/chrome/browser/tab_contents/popup_menu_helper_mac.mm b/chrome/browser/tab_contents/popup_menu_helper_mac.mm index 4b47f2f..94672b8 100644 --- a/chrome/browser/tab_contents/popup_menu_helper_mac.mm +++ b/chrome/browser/tab_contents/popup_menu_helper_mac.mm @@ -9,10 +9,10 @@ #include "base/memory/scoped_nsobject.h" #include "base/message_loop.h" #include "chrome/browser/renderer_host/render_widget_host_view_mac.h" -#import "chrome/browser/ui/cocoa/base_view.h" #include "content/browser/renderer_host/render_view_host.h" #import "content/common/chrome_application_mac.h" #include "content/common/notification_source.h" +#import "ui/base/cocoa/base_view.h" #include "webkit/glue/webmenurunner_mac.h" PopupMenuHelper::PopupMenuHelper(RenderViewHost* render_view_host) diff --git a/chrome/browser/tab_contents/tab_contents_view_mac.h b/chrome/browser/tab_contents/tab_contents_view_mac.h index 809bf23..37dec4a74a 100644 --- a/chrome/browser/tab_contents/tab_contents_view_mac.h +++ b/chrome/browser/tab_contents/tab_contents_view_mac.h @@ -16,10 +16,10 @@ #include "base/memory/scoped_nsobject.h" #include "base/memory/scoped_ptr.h" #include "chrome/browser/tab_contents/render_view_host_delegate_helper.h" -#include "chrome/browser/ui/cocoa/base_view.h" #include "content/browser/tab_contents/tab_contents_view.h" #include "content/common/notification_observer.h" #include "content/common/notification_registrar.h" +#include "ui/base/cocoa/base_view.h" #include "ui/gfx/size.h" @class FocusTracker; diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm index 5171018..60f6deb 100644 --- a/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm +++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell_unittest.mm @@ -1,12 +1,12 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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> +#import "base/memory/scoped_nsobject.h" #include "chrome/browser/bookmarks/bookmark_model.h" #import "chrome/browser/ui/cocoa/bookmarks/bookmark_tree_browser_cell.h" -#import "chrome/browser/ui/cocoa/cocoa_test_helper.h" #include "testing/platform_test.h" class BookmarkTreeBrowserCellTest : public PlatformTest { diff --git a/chrome/browser/ui/cocoa/cocoa_test_helper.h b/chrome/browser/ui/cocoa/cocoa_test_helper.h index 2fbffff..7b384df 100644 --- a/chrome/browser/ui/cocoa/cocoa_test_helper.h +++ b/chrome/browser/ui/cocoa/cocoa_test_helper.h @@ -8,42 +8,7 @@ #import <Cocoa/Cocoa.h> -#include "base/path_service.h" -#import "base/mac/scoped_nsautorelease_pool.h" -#import "base/memory/scoped_nsobject.h" -#include "chrome/common/chrome_constants.h" -#import "content/common/chrome_application_mac.h" -#include "testing/platform_test.h" - -// Background windows normally will not display things such as focus -// rings. This class allows -isKeyWindow to be manipulated to test -// such things. -@interface CocoaTestHelperWindow : NSWindow { - @private - BOOL pretendIsKeyWindow_; -} - -// Init a borderless non-deferred window with a backing store. -- (id)initWithContentRect:(NSRect)contentRect; - -// Init with a default frame. -- (id)init; - -// Sets the responder passed in as first responder, and sets the window -// so that it will return "YES" if asked if it key window. It does not actually -// make the window key. -- (void)makePretendKeyWindowAndSetFirstResponder:(NSResponder*)responder; - -// Clears the first responder duty for the window and returns the window -// to being non-key. -- (void)clearPretendKeyWindowAndFirstResponder; - -// Set value to return for -isKeyWindow. -- (void)setPretendIsKeyWindow:(BOOL)isKeyWindow; - -- (BOOL)isKeyWindow; - -@end +#import "ui/base/test/ui_cocoa_test_helper.h" // A test class that all tests that depend on AppKit should inherit from. // Sets up paths correctly, and makes sure that any windows created in the test @@ -52,7 +17,7 @@ // can call BootstrapCocoa directly from your test class. You will have to deal // with windows on your own though. Note that NSApp is initialized by // ChromeTestSuite. -class CocoaTest : public PlatformTest { +class CocoaTest : public ui::CocoaTest { public: // Sets up paths correctly for unit tests. If you can't inherit from // CocoaTest but are going to be using any AppKit features directly, or @@ -61,92 +26,6 @@ class CocoaTest : public PlatformTest { static void BootstrapCocoa(); CocoaTest(); - virtual ~CocoaTest(); - - // Must be called by subclasses that override TearDown. We verify that it - // is called in our destructor. Takes care of making sure that all windows - // are closed off correctly. If your tests open windows, they must be sure - // to close them before CocoaTest::TearDown is called. A standard way of doing - // this would be to create them in SetUp (after calling CocoaTest::Setup) and - // then close them in TearDown before calling CocoaTest::TearDown. - virtual void TearDown(); - - // Retuns a test window that can be used by views and other UI objects - // as part of their tests. Is created lazily, and will be closed correctly - // in CocoaTest::TearDown. Note that it is a CocoaTestHelperWindow which - // has special handling for being Key. - CocoaTestHelperWindow* test_window(); - - private: - // Return a set of currently open windows. Avoiding NSArray so - // contents aren't retained, the pointer values can only be used for - // comparison purposes. Using std::set to make progress-checking - // convenient. - static std::set<NSWindow*> ApplicationWindows(); - - // Return a set of windows which are in |ApplicationWindows()| but - // not |initial_windows_|. - std::set<NSWindow*> WindowsLeft(); - - bool called_tear_down_; - base::mac::ScopedNSAutoreleasePool pool_; - - // Windows which existed at the beginning of the test. - std::set<NSWindow*> initial_windows_; - - // Strong. Lazily created. This isn't wrapped in a scoped_nsobject because - // we want to call [close] to destroy it rather than calling [release]. We - // want to verify that [close] is actually removing our window and that it's - // not hanging around because releaseWhenClosed was set to "no" on the window. - // It isn't wrapped in a different wrapper class to close it because we - // need to close it at a very specific time; just before we enter our clean - // up loop in TearDown. - CocoaTestHelperWindow* test_window_; }; -// A macro defining a standard set of tests to run on a view. Since we can't -// inherit tests, this macro saves us a lot of duplicate code. Handles simply -// displaying the view to make sure it won't crash, as well as removing it -// from a window. All tests that work with NSView subclasses and/or -// NSViewController subclasses should use it. -#define TEST_VIEW(test_fixture, test_view) \ - TEST_F(test_fixture, test_fixture##_TestViewMacroAddRemove) { \ - scoped_nsobject<NSView> view([test_view retain]); \ - EXPECT_EQ([test_window() contentView], [view superview]); \ - [view removeFromSuperview]; \ - EXPECT_FALSE([view superview]); \ - } \ - TEST_F(test_fixture, test_fixture##_TestViewMacroDisplay) { \ - [test_view display]; \ - } - -// A macro which determines the proper float epsilon for a CGFloat. -#if CGFLOAT_IS_DOUBLE -#define CGFLOAT_EPSILON DBL_EPSILON -#else -#define CGFLOAT_EPSILON FLT_EPSILON -#endif - -// A macro which which determines if two CGFloats are equal taking a -// proper epsilon into consideration. -#define CGFLOAT_EQ(expected, actual) \ - (actual >= (expected - CGFLOAT_EPSILON) && \ - actual <= (expected + CGFLOAT_EPSILON)) - -// A test support macro which ascertains if two CGFloats are equal. -#define EXPECT_CGFLOAT_EQ(expected, actual) \ - EXPECT_TRUE(CGFLOAT_EQ(expected, actual)) << \ - expected << " != " << actual - -// A test support macro which compares two NSRects for equality taking -// the float epsilon into consideration. -#define EXPECT_NSRECT_EQ(expected, actual) \ - EXPECT_TRUE(CGFLOAT_EQ(expected.origin.x, actual.origin.x) && \ - CGFLOAT_EQ(expected.origin.y, actual.origin.y) && \ - CGFLOAT_EQ(expected.size.width, actual.size.width) && \ - CGFLOAT_EQ(expected.size.height, actual.size.height)) << \ - "Rects do not match: " << \ - [NSStringFromRect(expected) UTF8String] << \ - " != " << [NSStringFromRect(actual) UTF8String] - #endif // CHROME_BROWSER_UI_COCOA_COCOA_TEST_HELPER_H_ diff --git a/chrome/browser/ui/cocoa/cocoa_test_helper.mm b/chrome/browser/ui/cocoa/cocoa_test_helper.mm index a97d3f7..ab63a7b 100644 --- a/chrome/browser/ui/cocoa/cocoa_test_helper.mm +++ b/chrome/browser/ui/cocoa/cocoa_test_helper.mm @@ -4,74 +4,14 @@ #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" -#include "base/debug/debugger.h" -#include "base/logging.h" -#include "base/mac/mac_util.h" -#include "base/test/test_timeouts.h" +#include "base/mac/foundation_util.h" +#include "base/path_service.h" +#include "chrome/common/chrome_constants.h" -@implementation CocoaTestHelperWindow - -- (id)initWithContentRect:(NSRect)contentRect { - return [self initWithContentRect:contentRect - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:NO]; -} - -- (id)init { - return [self initWithContentRect:NSMakeRect(0, 0, 800, 600)]; -} - -- (void)dealloc { - // Just a good place to put breakpoints when having problems with - // unittests and CocoaTestHelperWindow. - [super dealloc]; -} - -- (void)makePretendKeyWindowAndSetFirstResponder:(NSResponder*)responder { - EXPECT_TRUE([self makeFirstResponder:responder]); - [self setPretendIsKeyWindow:YES]; -} - -- (void)clearPretendKeyWindowAndFirstResponder { - [self setPretendIsKeyWindow:NO]; - EXPECT_TRUE([self makeFirstResponder:NSApp]); -} - -- (void)setPretendIsKeyWindow:(BOOL)flag { - pretendIsKeyWindow_ = flag; -} - -- (BOOL)isKeyWindow { - return pretendIsKeyWindow_; -} - -@end - -CocoaTest::CocoaTest() : called_tear_down_(false), test_window_(nil) { +CocoaTest::CocoaTest() { BootstrapCocoa(); - // Set the duration of AppKit-evaluated animations (such as frame changes) - // to zero for testing purposes. That way they take effect immediately. - [[NSAnimationContext currentContext] setDuration:0.0]; - - // The above does not affect window-resize time, such as for an - // attached sheet dropping in. Set that duration for the current - // process (this is not persisted). Empirically, the value of 0.0 - // is ignored. - NSDictionary* dict = - [NSDictionary dictionaryWithObject:@"0.01" forKey:@"NSWindowResizeTime"]; - [[NSUserDefaults standardUserDefaults] registerDefaults:dict]; - - // Collect the list of windows that were open when the test started so - // that we don't wait for them to close in TearDown. Has to be done - // after BootstrapCocoa is called. - initial_windows_ = ApplicationWindows(); -} - -CocoaTest::~CocoaTest() { - // Must call CocoaTest's teardown from your overrides. - DCHECK(called_tear_down_); + Init(); } void CocoaTest::BootstrapCocoa() { @@ -81,124 +21,3 @@ void CocoaTest::BootstrapCocoa() { path = path.Append(chrome::kFrameworkName); base::mac::SetOverrideAppBundlePath(path); } - -void CocoaTest::TearDown() { - called_tear_down_ = true; - // Call close on our test_window to clean it up if one was opened. - [test_window_ clearPretendKeyWindowAndFirstResponder]; - [test_window_ close]; - test_window_ = nil; - - // Recycle the pool to clean up any stuff that was put on the - // autorelease pool due to window or windowcontroller closures. - pool_.Recycle(); - - // Some controls (NSTextFields, NSComboboxes etc) use - // performSelector:withDelay: to clean up drag handlers and other - // things (Radar 5851458 "Closing a window with a NSTextView in it - // should get rid of it immediately"). The event loop must be spun - // to get everything cleaned up correctly. It normally only takes - // one to two spins through the event loop to see a change. - - // NOTE(shess): Under valgrind, -nextEventMatchingMask:* in one test - // needed to run twice, once taking .2 seconds, the next time .6 - // seconds. The loop exit condition attempts to be scalable. - - // Get the set of windows which weren't present when the test - // started. - std::set<NSWindow*> windows_left(WindowsLeft()); - - while (!windows_left.empty()) { - // Cover delayed actions by spinning the loop at least once after - // this timeout. - const NSTimeInterval kCloseTimeoutSeconds = - TestTimeouts::action_timeout_ms() / 1000.0; - - // Cover chains of delayed actions by spinning the loop at least - // this many times. - const int kCloseSpins = 3; - - // Track the set of remaining windows so that everything can be - // reset if progress is made. - std::set<NSWindow*> still_left = windows_left; - - NSDate* start_date = [NSDate date]; - bool one_more_time = true; - int spins = 0; - while (still_left.size() == windows_left.size() && - (spins < kCloseSpins || one_more_time)) { - // Check the timeout before pumping events, so that we'll spin - // the loop once after the timeout. - one_more_time = - ([start_date timeIntervalSinceNow] > -kCloseTimeoutSeconds); - - // Autorelease anything thrown up by the event loop. - { - base::mac::ScopedNSAutoreleasePool pool; - ++spins; - NSEvent *next_event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:nil - inMode:NSDefaultRunLoopMode - dequeue:YES]; - [NSApp sendEvent:next_event]; - [NSApp updateWindows]; - } - - // Refresh the outstanding windows. - still_left = WindowsLeft(); - } - - // If no progress is being made, log a failure and continue. - if (still_left.size() == windows_left.size()) { - // NOTE(shess): Failing this expectation means that the test - // opened windows which have not been fully released. Either - // there is a leak, or perhaps one of |kCloseTimeoutSeconds| or - // |kCloseSpins| needs adjustment. - EXPECT_EQ(0U, windows_left.size()); - for (std::set<NSWindow*>::iterator iter = windows_left.begin(); - iter != windows_left.end(); ++iter) { - const char* desc = [[*iter description] UTF8String]; - LOG(WARNING) << "Didn't close window " << desc; - } - break; - } - - windows_left = still_left; - } - PlatformTest::TearDown(); -} - -std::set<NSWindow*> CocoaTest::ApplicationWindows() { - // This must NOT retain the windows it is returning. - std::set<NSWindow*> windows; - - // Must create a pool here because [NSApp windows] has created an array - // with retains on all the windows in it. - base::mac::ScopedNSAutoreleasePool pool; - NSArray *appWindows = [NSApp windows]; - for (NSWindow *window in appWindows) { - windows.insert(window); - } - return windows; -} - -std::set<NSWindow*> CocoaTest::WindowsLeft() { - const std::set<NSWindow*> windows(ApplicationWindows()); - std::set<NSWindow*> windows_left; - std::set_difference(windows.begin(), windows.end(), - initial_windows_.begin(), initial_windows_.end(), - std::inserter(windows_left, windows_left.begin())); - return windows_left; -} - -CocoaTestHelperWindow* CocoaTest::test_window() { - if (!test_window_) { - test_window_ = [[CocoaTestHelperWindow alloc] init]; - if (base::debug::BeingDebugged()) { - [test_window_ orderFront:nil]; - } else { - [test_window_ orderBack:nil]; - } - } - return test_window_; -} diff --git a/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm b/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm index 961d2db..64b0efb 100644 --- a/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm +++ b/chrome/browser/ui/cocoa/download/download_shelf_mac_unittest.mm @@ -1,7 +1,8 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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 "base/memory/scoped_nsobject.h" #include "chrome/browser/ui/cocoa/browser_test_helper.h" #include "chrome/browser/ui/cocoa/cocoa_test_helper.h" #include "chrome/browser/ui/cocoa/download/download_shelf_mac.h" diff --git a/chrome/browser/ui/cocoa/download/download_util_mac_unittest.mm b/chrome/browser/ui/cocoa/download/download_util_mac_unittest.mm index 2230207..e3ca740 100644 --- a/chrome/browser/ui/cocoa/download/download_util_mac_unittest.mm +++ b/chrome/browser/ui/cocoa/download/download_util_mac_unittest.mm @@ -1,9 +1,10 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. // Download utility test for Mac OS X. +#include "base/file_path.h" #include "base/path_service.h" #include "base/sys_string_conversions.h" #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" diff --git a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_unittest.mm b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_unittest.mm index 2b96839..32ab819 100644 --- a/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/extensions/extension_install_dialog_controller_unittest.mm @@ -7,6 +7,7 @@ #include "base/compiler_specific.h" #include "base/file_path.h" #include "base/file_util.h" +#import "base/memory/scoped_nsobject.h" #include "base/path_service.h" #include "base/sys_string_conversions.h" #include "base/utf_string_conversions.h" diff --git a/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm b/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm index 4753a26..bf94628 100644 --- a/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm +++ b/chrome/browser/ui/cocoa/floating_bar_backing_view_unittest.mm @@ -1,7 +1,8 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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 "base/memory/scoped_nsobject.h" #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" #import "chrome/browser/ui/cocoa/floating_bar_backing_view.h" diff --git a/chrome/browser/ui/cocoa/image_utils_unittest.mm b/chrome/browser/ui/cocoa/image_utils_unittest.mm index d13b33b..da60c6f 100644 --- a/chrome/browser/ui/cocoa/image_utils_unittest.mm +++ b/chrome/browser/ui/cocoa/image_utils_unittest.mm @@ -1,7 +1,8 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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 "base/memory/scoped_nsobject.h" #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" #include "chrome/browser/ui/cocoa/image_utils.h" #include "testing/gtest/include/gtest/gtest.h" diff --git a/chrome/browser/ui/cocoa/location_bar/instant_opt_in_view_unittest.mm b/chrome/browser/ui/cocoa/location_bar/instant_opt_in_view_unittest.mm index ce5ff48..6788273 100644 --- a/chrome/browser/ui/cocoa/location_bar/instant_opt_in_view_unittest.mm +++ b/chrome/browser/ui/cocoa/location_bar/instant_opt_in_view_unittest.mm @@ -1,7 +1,8 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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 "base/memory/scoped_nsobject.h" #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" #import "chrome/browser/ui/cocoa/location_bar/instant_opt_in_view.h" diff --git a/chrome/browser/ui/cocoa/tab_contents/sad_tab_view.h b/chrome/browser/ui/cocoa/tab_contents/sad_tab_view.h index 0bf05cd..51fe42a 100644 --- a/chrome/browser/ui/cocoa/tab_contents/sad_tab_view.h +++ b/chrome/browser/ui/cocoa/tab_contents/sad_tab_view.h @@ -8,7 +8,7 @@ #include "base/mac/cocoa_protocols.h" #include "base/memory/scoped_nsobject.h" -#include "chrome/browser/ui/cocoa/base_view.h" +#include "ui/base/cocoa/base_view.h" #import <Cocoa/Cocoa.h> diff --git a/chrome/browser/ui/cocoa/tab_contents/web_drop_target_unittest.mm b/chrome/browser/ui/cocoa/tab_contents/web_drop_target_unittest.mm index 256d3b9..c2957dc 100644 --- a/chrome/browser/ui/cocoa/tab_contents/web_drop_target_unittest.mm +++ b/chrome/browser/ui/cocoa/tab_contents/web_drop_target_unittest.mm @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "base/mac/scoped_nsautorelease_pool.h" +#import "base/memory/scoped_nsobject.h" #include "base/sys_string_conversions.h" #include "base/utf_string_conversions.h" #import "chrome/browser/ui/cocoa/cocoa_test_helper.h" diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 773b5ac..53f4bf4 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2346,8 +2346,6 @@ 'browser/ui/cocoa/background_tile_view.mm', 'browser/ui/cocoa/base_bubble_controller.h', 'browser/ui/cocoa/base_bubble_controller.mm', - 'browser/ui/cocoa/base_view.h', - 'browser/ui/cocoa/base_view.mm', 'browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller.h', 'browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller.mm', 'browser/ui/cocoa/bookmarks/bookmark_bar_bridge.h', diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 95be1f9..f28efbd 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1068,6 +1068,7 @@ '../ui/gfx/gl/gl.gyp:gl', '../ui/ui.gyp:ui_resources', '../ui/ui.gyp:ui_resources_standard', + '../ui/ui.gyp:ui_test_support', '../v8/tools/gyp/v8.gyp:v8', 'chrome_resources', 'chrome_strings', @@ -1555,7 +1556,6 @@ 'browser/ui/cocoa/applescript/bookmark_item_applescript_unittest.mm', 'browser/ui/cocoa/background_gradient_view_unittest.mm', 'browser/ui/cocoa/background_tile_view_unittest.mm', - 'browser/ui/cocoa/base_view_unittest.mm', 'browser/ui/cocoa/bookmarks/bookmark_all_tabs_controller_unittest.mm', 'browser/ui/cocoa/bookmarks/bookmark_bar_bridge_unittest.mm', 'browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm', diff --git a/chrome/browser/ui/cocoa/base_view.h b/ui/base/cocoa/base_view.h index 5dbc87b..c2cc22c 100644 --- a/chrome/browser/ui/cocoa/base_view.h +++ b/ui/base/cocoa/base_view.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_COCOA_BASE_VIEW_H_ -#define CHROME_BROWSER_UI_COCOA_BASE_VIEW_H_ +#ifndef UI_BASE_COCOA_BASE_VIEW_H_ +#define UI_BASE_COCOA_BASE_VIEW_H_ #pragma once #import <Cocoa/Cocoa.h> @@ -42,4 +42,4 @@ extern NSString* kViewDidBecomeFirstResponder; extern NSString* kSelectionDirection; -#endif // CHROME_BROWSER_UI_COCOA_BASE_VIEW_H_ +#endif // UI_BASE_COCOA_BASE_VIEW_H_ diff --git a/chrome/browser/ui/cocoa/base_view.mm b/ui/base/cocoa/base_view.mm index b26c390..0d63acf 100644 --- a/chrome/browser/ui/cocoa/base_view.mm +++ b/ui/base/cocoa/base_view.mm @@ -1,8 +1,8 @@ -// Copyright (c) 2009 The Chromium Authors. All rights reserved. +// Copyright (c) 2011 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. -#include "chrome/browser/ui/cocoa/base_view.h" +#include "ui/base/cocoa/base_view.h" NSString* kViewDidBecomeFirstResponder = @"Chromium.kViewDidBecomeFirstResponder"; @@ -33,28 +33,28 @@ NSString* kSelectionDirection = @"Chromium.kSelectionDirection"; [super dealloc]; } -- (void)mouseEvent:(NSEvent *)theEvent { +- (void)mouseEvent:(NSEvent*)theEvent { // This method left intentionally blank. } -- (void)keyEvent:(NSEvent *)theEvent { +- (void)keyEvent:(NSEvent*)theEvent { // This method left intentionally blank. } -- (void)mouseDown:(NSEvent *)theEvent { +- (void)mouseDown:(NSEvent*)theEvent { dragging_ = YES; [self mouseEvent:theEvent]; } -- (void)rightMouseDown:(NSEvent *)theEvent { +- (void)rightMouseDown:(NSEvent*)theEvent { [self mouseEvent:theEvent]; } -- (void)otherMouseDown:(NSEvent *)theEvent { +- (void)otherMouseDown:(NSEvent*)theEvent { [self mouseEvent:theEvent]; } -- (void)mouseUp:(NSEvent *)theEvent { +- (void)mouseUp:(NSEvent*)theEvent { [self mouseEvent:theEvent]; dragging_ = NO; @@ -74,31 +74,31 @@ NSString* kSelectionDirection = @"Chromium.kSelectionDirection"; } } -- (void)rightMouseUp:(NSEvent *)theEvent { +- (void)rightMouseUp:(NSEvent*)theEvent { [self mouseEvent:theEvent]; } -- (void)otherMouseUp:(NSEvent *)theEvent { +- (void)otherMouseUp:(NSEvent*)theEvent { [self mouseEvent:theEvent]; } -- (void)mouseMoved:(NSEvent *)theEvent { +- (void)mouseMoved:(NSEvent*)theEvent { [self mouseEvent:theEvent]; } -- (void)mouseDragged:(NSEvent *)theEvent { +- (void)mouseDragged:(NSEvent*)theEvent { [self mouseEvent:theEvent]; } -- (void)rightMouseDragged:(NSEvent *)theEvent { +- (void)rightMouseDragged:(NSEvent*)theEvent { [self mouseEvent:theEvent]; } -- (void)otherMouseDragged:(NSEvent *)theEvent { +- (void)otherMouseDragged:(NSEvent*)theEvent { [self mouseEvent:theEvent]; } -- (void)mouseEntered:(NSEvent *)theEvent { +- (void)mouseEntered:(NSEvent*)theEvent { if (pendingExitEvent_.get()) { pendingExitEvent_.reset(); return; @@ -107,7 +107,7 @@ NSString* kSelectionDirection = @"Chromium.kSelectionDirection"; [self mouseEvent:theEvent]; } -- (void)mouseExited:(NSEvent *)theEvent { +- (void)mouseExited:(NSEvent*)theEvent { // The tracking area will send an exit event even during a drag, which isn't // how the event flow for drags should work. This stores the exit event, and // sends it when the drag completes instead. @@ -119,15 +119,15 @@ NSString* kSelectionDirection = @"Chromium.kSelectionDirection"; [self mouseEvent:theEvent]; } -- (void)keyDown:(NSEvent *)theEvent { +- (void)keyDown:(NSEvent*)theEvent { [self keyEvent:theEvent]; } -- (void)keyUp:(NSEvent *)theEvent { +- (void)keyUp:(NSEvent*)theEvent { [self keyEvent:theEvent]; } -- (void)flagsChanged:(NSEvent *)theEvent { +- (void)flagsChanged:(NSEvent*)theEvent { [self keyEvent:theEvent]; } diff --git a/chrome/browser/ui/cocoa/base_view_unittest.mm b/ui/base/cocoa/base_view_unittest.mm index 1cc99d2..79a9f4a 100644 --- a/chrome/browser/ui/cocoa/base_view_unittest.mm +++ b/ui/base/cocoa/base_view_unittest.mm @@ -5,14 +5,14 @@ #import <Cocoa/Cocoa.h> #include "base/memory/scoped_nsobject.h" -#import "chrome/browser/ui/cocoa/base_view.h" -#import "chrome/browser/ui/cocoa/cocoa_test_helper.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/platform_test.h" +#include "ui/base/cocoa/base_view.h" +#import "ui/base/test/ui_cocoa_test_helper.h" namespace { -class BaseViewTest : public CocoaTest { +class BaseViewTest : public ui::CocoaTest { public: BaseViewTest() { NSRect frame = NSMakeRect(0, 0, 100, 100); diff --git a/ui/base/test/ui_cocoa_test_helper.h b/ui/base/test/ui_cocoa_test_helper.h new file mode 100644 index 0000000..925a3a8 --- /dev/null +++ b/ui/base/test/ui_cocoa_test_helper.h @@ -0,0 +1,149 @@ +// Copyright (c) 2011 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. + +#ifndef UI_BASE_TEST_BASE_UI_COCOA_TEST_HELPER_H_ +#define UI_BASE_TEST_BASE_UI_COCOA_TEST_HELPER_H_ +#pragma once + +#include <set> + +#import <Cocoa/Cocoa.h> + +#import "base/mac/scoped_nsautorelease_pool.h" +#include "testing/platform_test.h" + +// Background windows normally will not display things such as focus +// rings. This class allows -isKeyWindow to be manipulated to test +// such things. +@interface CocoaTestHelperWindow : NSWindow { + @private + BOOL pretendIsKeyWindow_; +} + +// Init a borderless non-deferred window with a backing store. +- (id)initWithContentRect:(NSRect)contentRect; + +// Init with a default frame. +- (id)init; + +// Sets the responder passed in as first responder, and sets the window +// so that it will return "YES" if asked if it key window. It does not actually +// make the window key. +- (void)makePretendKeyWindowAndSetFirstResponder:(NSResponder*)responder; + +// Clears the first responder duty for the window and returns the window +// to being non-key. +- (void)clearPretendKeyWindowAndFirstResponder; + +// Set value to return for -isKeyWindow. +- (void)setPretendIsKeyWindow:(BOOL)isKeyWindow; + +- (BOOL)isKeyWindow; + +@end + +namespace ui { + +// A test class that all tests that depend on AppKit should inherit from. +// Sets up paths correctly, and makes sure that any windows created in the test +// are closed down properly by the test. +class CocoaTest : public PlatformTest { + public: + CocoaTest(); + virtual ~CocoaTest(); + + // Must be called by subclasses that override TearDown. We verify that it + // is called in our destructor. Takes care of making sure that all windows + // are closed off correctly. If your tests open windows, they must be sure + // to close them before CocoaTest::TearDown is called. A standard way of doing + // this would be to create them in SetUp (after calling CocoaTest::Setup) and + // then close them in TearDown before calling CocoaTest::TearDown. + virtual void TearDown(); + + // Retuns a test window that can be used by views and other UI objects + // as part of their tests. Is created lazily, and will be closed correctly + // in CocoaTest::TearDown. Note that it is a CocoaTestHelperWindow which + // has special handling for being Key. + CocoaTestHelperWindow* test_window(); + + protected: + // Allows subclasses to do initialization before calling through to the base + // class's initialization. + void Init(); + + private: + // Return a set of currently open windows. Avoiding NSArray so + // contents aren't retained, the pointer values can only be used for + // comparison purposes. Using std::set to make progress-checking + // convenient. + static std::set<NSWindow*> ApplicationWindows(); + + // Return a set of windows which are in |ApplicationWindows()| but + // not |initial_windows_|. + std::set<NSWindow*> WindowsLeft(); + + bool called_tear_down_; + base::mac::ScopedNSAutoreleasePool pool_; + + // Windows which existed at the beginning of the test. + std::set<NSWindow*> initial_windows_; + + // Strong. Lazily created. This isn't wrapped in a scoped_nsobject because + // we want to call [close] to destroy it rather than calling [release]. We + // want to verify that [close] is actually removing our window and that it's + // not hanging around because releaseWhenClosed was set to "no" on the window. + // It isn't wrapped in a different wrapper class to close it because we + // need to close it at a very specific time; just before we enter our clean + // up loop in TearDown. + CocoaTestHelperWindow* test_window_; +}; + +} // namespace ui + +// A macro defining a standard set of tests to run on a view. Since we can't +// inherit tests, this macro saves us a lot of duplicate code. Handles simply +// displaying the view to make sure it won't crash, as well as removing it +// from a window. All tests that work with NSView subclasses and/or +// NSViewController subclasses should use it. +#define TEST_VIEW(test_fixture, test_view) \ + TEST_F(test_fixture, test_fixture##_TestViewMacroAddRemove) { \ + scoped_nsobject<NSView> view([test_view retain]); \ + EXPECT_EQ([test_window() contentView], [view superview]); \ + [view removeFromSuperview]; \ + EXPECT_FALSE([view superview]); \ + } \ + TEST_F(test_fixture, test_fixture##_TestViewMacroDisplay) { \ + [test_view display]; \ + } + +// A macro which determines the proper float epsilon for a CGFloat. +#if CGFLOAT_IS_DOUBLE +#define CGFLOAT_EPSILON DBL_EPSILON +#else +#define CGFLOAT_EPSILON FLT_EPSILON +#endif + +// A macro which which determines if two CGFloats are equal taking a +// proper epsilon into consideration. +#define CGFLOAT_EQ(expected, actual) \ + (actual >= (expected - CGFLOAT_EPSILON) && \ + actual <= (expected + CGFLOAT_EPSILON)) + +// A test support macro which ascertains if two CGFloats are equal. +#define EXPECT_CGFLOAT_EQ(expected, actual) \ + EXPECT_TRUE(CGFLOAT_EQ(expected, actual)) << \ + expected << " != " << actual + +// A test support macro which compares two NSRects for equality taking +// the float epsilon into consideration. +#define EXPECT_NSRECT_EQ(expected, actual) \ + EXPECT_TRUE(CGFLOAT_EQ(expected.origin.x, actual.origin.x) && \ + CGFLOAT_EQ(expected.origin.y, actual.origin.y) && \ + CGFLOAT_EQ(expected.size.width, actual.size.width) && \ + CGFLOAT_EQ(expected.size.height, actual.size.height)) << \ + "Rects do not match: " << \ + [NSStringFromRect(expected) UTF8String] << \ + " != " << [NSStringFromRect(actual) UTF8String] + +#endif // UI_BASE_TEST_BASE_UI_COCOA_TEST_HELPER_H_ diff --git a/ui/base/test/ui_cocoa_test_helper.mm b/ui/base/test/ui_cocoa_test_helper.mm new file mode 100644 index 0000000..adfb427 --- /dev/null +++ b/ui/base/test/ui_cocoa_test_helper.mm @@ -0,0 +1,201 @@ +// Copyright (c) 2011 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 "ui/base/test/ui_cocoa_test_helper.h" + +#include "base/debug/debugger.h" +#include "base/logging.h" +#include "base/test/test_timeouts.h" + +@implementation CocoaTestHelperWindow + +- (id)initWithContentRect:(NSRect)contentRect { + return [self initWithContentRect:contentRect + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:NO]; +} + +- (id)init { + return [self initWithContentRect:NSMakeRect(0, 0, 800, 600)]; +} + +- (void)dealloc { + // Just a good place to put breakpoints when having problems with + // unittests and CocoaTestHelperWindow. + [super dealloc]; +} + +- (void)makePretendKeyWindowAndSetFirstResponder:(NSResponder*)responder { + EXPECT_TRUE([self makeFirstResponder:responder]); + [self setPretendIsKeyWindow:YES]; +} + +- (void)clearPretendKeyWindowAndFirstResponder { + [self setPretendIsKeyWindow:NO]; + EXPECT_TRUE([self makeFirstResponder:NSApp]); +} + +- (void)setPretendIsKeyWindow:(BOOL)flag { + pretendIsKeyWindow_ = flag; +} + +- (BOOL)isKeyWindow { + return pretendIsKeyWindow_; +} + +@end + +namespace ui { + +CocoaTest::CocoaTest() : called_tear_down_(false), test_window_(nil) { + Init(); +} + +CocoaTest::~CocoaTest() { + // Must call CocoaTest's teardown from your overrides. + DCHECK(called_tear_down_); +} + +void CocoaTest::Init() { + // Set the duration of AppKit-evaluated animations (such as frame changes) + // to zero for testing purposes. That way they take effect immediately. + [[NSAnimationContext currentContext] setDuration:0.0]; + + // The above does not affect window-resize time, such as for an + // attached sheet dropping in. Set that duration for the current + // process (this is not persisted). Empirically, the value of 0.0 + // is ignored. + NSDictionary* dict = + [NSDictionary dictionaryWithObject:@"0.01" forKey:@"NSWindowResizeTime"]; + [[NSUserDefaults standardUserDefaults] registerDefaults:dict]; + + // Collect the list of windows that were open when the test started so + // that we don't wait for them to close in TearDown. Has to be done + // after BootstrapCocoa is called. + initial_windows_ = ApplicationWindows(); +} + +void CocoaTest::TearDown() { + called_tear_down_ = true; + // Call close on our test_window to clean it up if one was opened. + [test_window_ clearPretendKeyWindowAndFirstResponder]; + [test_window_ close]; + test_window_ = nil; + + // Recycle the pool to clean up any stuff that was put on the + // autorelease pool due to window or windowcontroller closures. + pool_.Recycle(); + + // Some controls (NSTextFields, NSComboboxes etc) use + // performSelector:withDelay: to clean up drag handlers and other + // things (Radar 5851458 "Closing a window with a NSTextView in it + // should get rid of it immediately"). The event loop must be spun + // to get everything cleaned up correctly. It normally only takes + // one to two spins through the event loop to see a change. + + // NOTE(shess): Under valgrind, -nextEventMatchingMask:* in one test + // needed to run twice, once taking .2 seconds, the next time .6 + // seconds. The loop exit condition attempts to be scalable. + + // Get the set of windows which weren't present when the test + // started. + std::set<NSWindow*> windows_left(WindowsLeft()); + + while (!windows_left.empty()) { + // Cover delayed actions by spinning the loop at least once after + // this timeout. + const NSTimeInterval kCloseTimeoutSeconds = + TestTimeouts::action_timeout_ms() / 1000.0; + + // Cover chains of delayed actions by spinning the loop at least + // this many times. + const int kCloseSpins = 3; + + // Track the set of remaining windows so that everything can be + // reset if progress is made. + std::set<NSWindow*> still_left = windows_left; + + NSDate* start_date = [NSDate date]; + bool one_more_time = true; + int spins = 0; + while (still_left.size() == windows_left.size() && + (spins < kCloseSpins || one_more_time)) { + // Check the timeout before pumping events, so that we'll spin + // the loop once after the timeout. + one_more_time = + ([start_date timeIntervalSinceNow] > -kCloseTimeoutSeconds); + + // Autorelease anything thrown up by the event loop. + { + base::mac::ScopedNSAutoreleasePool pool; + ++spins; + NSEvent *next_event = [NSApp nextEventMatchingMask:NSAnyEventMask + untilDate:nil + inMode:NSDefaultRunLoopMode + dequeue:YES]; + [NSApp sendEvent:next_event]; + [NSApp updateWindows]; + } + + // Refresh the outstanding windows. + still_left = WindowsLeft(); + } + + // If no progress is being made, log a failure and continue. + if (still_left.size() == windows_left.size()) { + // NOTE(shess): Failing this expectation means that the test + // opened windows which have not been fully released. Either + // there is a leak, or perhaps one of |kCloseTimeoutSeconds| or + // |kCloseSpins| needs adjustment. + EXPECT_EQ(0U, windows_left.size()); + for (std::set<NSWindow*>::iterator iter = windows_left.begin(); + iter != windows_left.end(); ++iter) { + const char* desc = [[*iter description] UTF8String]; + LOG(WARNING) << "Didn't close window " << desc; + } + break; + } + + windows_left = still_left; + } + PlatformTest::TearDown(); +} + +std::set<NSWindow*> CocoaTest::ApplicationWindows() { + // This must NOT retain the windows it is returning. + std::set<NSWindow*> windows; + + // Must create a pool here because [NSApp windows] has created an array + // with retains on all the windows in it. + base::mac::ScopedNSAutoreleasePool pool; + NSArray *appWindows = [NSApp windows]; + for (NSWindow *window in appWindows) { + windows.insert(window); + } + return windows; +} + +std::set<NSWindow*> CocoaTest::WindowsLeft() { + const std::set<NSWindow*> windows(ApplicationWindows()); + std::set<NSWindow*> windows_left; + std::set_difference(windows.begin(), windows.end(), + initial_windows_.begin(), initial_windows_.end(), + std::inserter(windows_left, windows_left.begin())); + return windows_left; +} + +CocoaTestHelperWindow* CocoaTest::test_window() { + if (!test_window_) { + test_window_ = [[CocoaTestHelperWindow alloc] init]; + if (base::debug::BeingDebugged()) { + [test_window_ orderFront:nil]; + } else { + [test_window_ orderBack:nil]; + } + } + return test_window_; +} + +} // namespace ui @@ -86,6 +86,8 @@ 'base/clipboard/clipboard_win.cc', 'base/clipboard/scoped_clipboard_writer.cc', 'base/clipboard/scoped_clipboard_writer.h', + 'base/cocoa/base_view.h', + 'base/cocoa/base_view.mm', 'base/dragdrop/drag_drop_types_gtk.cc', 'base/dragdrop/drag_drop_types.h', 'base/dragdrop/drag_drop_types_win.cc', diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi index 60ad9f6..5630aaa 100644 --- a/ui/ui_unittests.gypi +++ b/ui/ui_unittests.gypi @@ -5,6 +5,27 @@ { 'targets': [ { + 'target_name': 'ui_test_support', + 'dependencies': [ + '../base/base.gyp:base', + '../testing/gtest.gyp:gtest', + ], + 'sources': [ + 'base/test/ui_cocoa_test_helper.h', + 'base/test/ui_cocoa_test_helper.mm', + ], + 'include_dirs': [ + '../', + ], + 'conditions': [ + ['OS=="mac"', { + 'type': 'static_library', + }, { # OS != "mac" + 'type': 'none', + }], + ], + }, + { 'target_name': 'ui_unittests', 'type': 'executable', 'dependencies': [ @@ -16,8 +37,9 @@ '../testing/gtest.gyp:gtest', '../third_party/icu/icu.gyp:icui18n', '../third_party/icu/icu.gyp:icuuc', - 'ui', 'gfx_resources', + 'ui', + 'ui_test_support', ], 'sources': [ 'base/animation/animation_container_unittest.cc', @@ -25,6 +47,7 @@ 'base/animation/multi_animation_unittest.cc', 'base/animation/slide_animation_unittest.cc', 'base/clipboard/clipboard_unittest.cc', + 'base/cocoa/base_view_unittest.mm', 'base/gtk/gtk_expanded_container_unittest.cc', 'base/gtk/gtk_im_context_util_unittest.cc', 'base/l10n/l10n_util_mac_unittest.mm', |