diff options
-rw-r--r-- | chrome/browser/cocoa/bookmark_bar_controller_unittest.mm | 17 | ||||
-rw-r--r-- | chrome/browser/cocoa/cocoa_test_helper.h | 59 | ||||
-rw-r--r-- | chrome/browser/cocoa/status_bubble_mac_unittest.mm | 21 | ||||
-rw-r--r-- | chrome/browser/cocoa/tab_controller.h | 2 | ||||
-rw-r--r-- | chrome/browser/cocoa/tab_controller.mm | 3 | ||||
-rw-r--r-- | chrome/browser/cocoa/tab_controller_unittest.mm | 178 | ||||
-rw-r--r-- | chrome/chrome.gyp | 7 |
7 files changed, 258 insertions, 29 deletions
diff --git a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm index 6d6e2daa..f9abec5 100644 --- a/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm +++ b/chrome/browser/cocoa/bookmark_bar_controller_unittest.mm @@ -7,6 +7,7 @@ #include "base/scoped_nsobject.h" #import "chrome/browser/cocoa/bookmark_bar_controller.h" #include "chrome/browser/cocoa/browser_test_helper.h" +#import "chrome/browser/cocoa/cocoa_test_helper.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -16,25 +17,17 @@ static const int kContentAreaHeight = 500; class BookmarkBarControllerTest : public testing::Test { public: BookmarkBarControllerTest() { - // Bootstrap Cocoa. It's very unhappy without this. - [NSApplication sharedApplication]; - - // Create a window and put a content view in it that's slightly smaller in - // height. - NSRect frame = NSMakeRect(0, 0, 800, 600); - window_.reset([[NSWindow alloc] initWithContentRect:frame - styleMask:0 - backing:NSBackingStoreBuffered - defer:NO]); - [window_ orderFront:nil]; NSRect content_frame = NSMakeRect(0, 0, 800, kContentAreaHeight); content_area_.reset([[NSView alloc] initWithFrame:content_frame]); bar_.reset( [[BookmarkBarController alloc] initWithProfile:helper_.GetProfile() contentArea:content_area_.get()]); + NSView* parent = [cocoa_helper_.window() contentView]; + [parent addSubview:content_area_.get()]; + [parent addSubview:[bar_ view]]; } - scoped_nsobject<NSWindow> window_; + CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc... scoped_nsobject<NSView> content_area_; BrowserTestHelper helper_; scoped_nsobject<BookmarkBarController> bar_; diff --git a/chrome/browser/cocoa/cocoa_test_helper.h b/chrome/browser/cocoa/cocoa_test_helper.h new file mode 100644 index 0000000..04fd2de5 --- /dev/null +++ b/chrome/browser/cocoa/cocoa_test_helper.h @@ -0,0 +1,59 @@ +// Copyright (c) 2009 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 CHROME_BROWSER_COCOA_COCOA_TEST_HELPER +#define CHROME_BROWSER_COCOA_COCOA_TEST_HELPER + +#import <Cocoa/Cocoa.h> + +#include "base/file_path.h" +#include "base/mac_util.h" +#include "base/path_service.h" + +#if defined(GOOGLE_CHROME_BUILD) +#define APP_NAME "Chrome.app" +#else +#define APP_NAME "Chromium.app" +#endif + +// A class that initializes Cocoa and sets up resources for many of our +// Cocoa controller unit tests. It does several key things: +// - Creates and displays an empty Cocoa window for views to live in +// - Loads the appropriate bundle so nib loading works. When loading the +// nib in the class being tested, your must use |mac_util::MainAppBundle()| +// as the bundle. If you do not specify a bundle, your test will likely +// fail. +// It currently does not create an autorelease pool, though that can easily be +// added. If your test wants one, it can derrive from PlatformTest instead of +// testing::Test. + +class CocoaTestHelper { + public: + CocoaTestHelper() { + // Look in the Chromium app bundle for resources. + FilePath path; + PathService::Get(base::DIR_EXE, &path); + path = path.AppendASCII(APP_NAME); + mac_util::SetOverrideAppBundlePath(path); + + // Bootstrap Cocoa. It's very unhappy without this. + [NSApplication sharedApplication]; + + // Create a window. + NSRect frame = NSMakeRect(0, 0, 800, 600); + window_.reset([[NSWindow alloc] initWithContentRect:frame + styleMask:0 + backing:NSBackingStoreBuffered + defer:NO]); + [window_ orderFront:nil]; + } + + // Access the Cocoa window created for the test. + NSWindow* window() const { return window_.get(); } + + private: + scoped_nsobject<NSWindow> window_; +}; + +#endif // CHROME_BROWSER_COCOA_COCOA_TEST_HELPER diff --git a/chrome/browser/cocoa/status_bubble_mac_unittest.mm b/chrome/browser/cocoa/status_bubble_mac_unittest.mm index df7df2f..9f59148 100644 --- a/chrome/browser/cocoa/status_bubble_mac_unittest.mm +++ b/chrome/browser/cocoa/status_bubble_mac_unittest.mm @@ -6,6 +6,7 @@ #include "base/scoped_nsobject.h" #include "base/scoped_ptr.h" +#import "chrome/browser/cocoa/cocoa_test_helper.h" #include "chrome/browser/cocoa/status_bubble_mac.h" #include "googleurl/src/gurl.h" #include "testing/gtest/include/gtest/gtest.h" @@ -13,17 +14,8 @@ class StatusBubbleMacTest : public testing::Test { public: StatusBubbleMacTest() { - // Bootstrap Cocoa. It's very unhappy without this. - [NSApplication sharedApplication]; - - NSRect frame = NSMakeRect(0, 0, 800, 600); - window_.reset([[NSWindow alloc] initWithContentRect:frame - styleMask:0 - backing:NSBackingStoreBuffered - defer:NO]); - [window_ orderFront:nil]; - bubble_.reset(new StatusBubbleMac(window_.get())); - EXPECT_TRUE(window_.get()); + NSWindow* window = cocoa_helper_.window(); + bubble_.reset(new StatusBubbleMac(window)); EXPECT_TRUE(bubble_.get()); EXPECT_FALSE(bubble_->window_); // lazily creates window } @@ -38,7 +30,7 @@ class StatusBubbleMacTest : public testing::Test { return bubble_->url_text_; } - scoped_nsobject<NSWindow> window_; + CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc... scoped_ptr<StatusBubbleMac> bubble_; }; @@ -93,12 +85,13 @@ TEST_F(StatusBubbleMacTest, MouseMove) { } TEST_F(StatusBubbleMacTest, Delete) { + NSWindow* window = cocoa_helper_.window(); // Create and delete immediately. - StatusBubbleMac* bubble = new StatusBubbleMac(window_); + StatusBubbleMac* bubble = new StatusBubbleMac(window); delete bubble; // Create then delete while visible. - bubble = new StatusBubbleMac(window_); + bubble = new StatusBubbleMac(window); bubble->SetStatus(L"showing"); delete bubble; } diff --git a/chrome/browser/cocoa/tab_controller.h b/chrome/browser/cocoa/tab_controller.h index 82f3bb5..45d93ab 100644 --- a/chrome/browser/cocoa/tab_controller.h +++ b/chrome/browser/cocoa/tab_controller.h @@ -23,7 +23,7 @@ BOOL loading_; NSImage *image_; id<TabControllerTarget> target_; // weak, where actions are sent - SEL action_; // selector sent when tab is seleted by clicking + SEL action_; // selector sent when tab is selected by clicking } @property(retain, nonatomic) NSImage *image; diff --git a/chrome/browser/cocoa/tab_controller.mm b/chrome/browser/cocoa/tab_controller.mm index 09eb5c6..027f709 100644 --- a/chrome/browser/cocoa/tab_controller.mm +++ b/chrome/browser/cocoa/tab_controller.mm @@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/mac_util.h" #import "chrome/browser/cocoa/tab_controller.h" #import "chrome/browser/cocoa/tab_controller_target.h" @@ -20,7 +21,7 @@ } - (id)init { - self = [super initWithNibName:@"TabView" bundle:nil]; + self = [super initWithNibName:@"TabView" bundle:mac_util::MainAppBundle()]; if (self != nil) { [self setImage:[NSImage imageNamed:@"nav"]]; } diff --git a/chrome/browser/cocoa/tab_controller_unittest.mm b/chrome/browser/cocoa/tab_controller_unittest.mm new file mode 100644 index 0000000..d568dcb --- /dev/null +++ b/chrome/browser/cocoa/tab_controller_unittest.mm @@ -0,0 +1,178 @@ +// Copyright (c) 2009 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_nsautorelease_pool.h" +#import "base/scoped_nsobject.h" +#import "chrome/browser/cocoa/tab_controller.h" +#import "chrome/browser/cocoa/tab_controller_target.h" +#include "chrome/browser/cocoa/cocoa_test_helper.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "testing/platform_test.h" + +// Implements the target interface for the tab, which gets sent messages when +// the tab is clicked on by the user and when its close box is clicked. +@interface TabControllerTestTarget : NSObject<TabControllerTarget> { + @private + bool selected_; + bool closed_; +} +- (bool)selected; +- (bool)closed; +@end + +@implementation TabControllerTestTarget +- (bool)selected { + return selected_; +} +- (bool)closed { + return closed_; +} +- (void)selectTab:(id)sender { + selected_ = true; +} +- (void)closeTab:(id)sender { + closed_ = true; +} +- (void)mouseTimer:(NSTimer*)timer { + // Fire the mouseUp to break the TabView drag loop. + NSEvent* current = [[NSApplication sharedApplication] currentEvent]; + NSWindow* window = [timer userInfo]; + NSEvent* up = [NSEvent mouseEventWithType:NSLeftMouseUp + location:[current locationInWindow] + modifierFlags:0 + timestamp:[current timestamp] + windowNumber:[window windowNumber] + context:nil + eventNumber:0 + clickCount:1 + pressure:1.0]; + [window postEvent:up atStart:YES]; +} +@end + +namespace { + +// The dragging code in TabView makes heavy use of autorelease pools so +// inherit from Platform test to have one created for us. +class TabControllerTest : public PlatformTest { + public: + TabControllerTest() { } + + CocoaTestHelper cocoa_helper_; // Inits Cocoa, creates window, etc... +}; + +// Tests creating the controller, sticking it in a window, and removing it. +TEST_F(TabControllerTest, Creation) { + NSWindow* window = cocoa_helper_.window(); + scoped_nsobject<TabController> controller([[TabController alloc] init]); + [[window contentView] addSubview:[controller view]]; + EXPECT_TRUE([controller tabView]); + EXPECT_EQ([[controller view] window], window); + [[controller view] removeFromSuperview]; +} + +// Tests sending it a close message and ensuring that the target/action get +// called. Mimics the user clicking on the close button in the tab. +TEST_F(TabControllerTest, Close) { + NSWindow* window = cocoa_helper_.window(); + scoped_nsobject<TabController> controller([[TabController alloc] init]); + [[window contentView] addSubview:[controller view]]; + + scoped_nsobject<TabControllerTestTarget> target( + [[TabControllerTestTarget alloc] init]); + EXPECT_FALSE([target closed]); + [controller setTarget:target]; + EXPECT_EQ(target.get(), [controller target]); + + [controller closeTab:nil]; + EXPECT_TRUE([target closed]); + + [[controller view] removeFromSuperview]; +} + +// Tests setting the |selected| property via code. +TEST_F(TabControllerTest, APISelection) { + NSWindow* window = cocoa_helper_.window(); + scoped_nsobject<TabController> controller([[TabController alloc] init]); + [[window contentView] addSubview:[controller view]]; + + EXPECT_FALSE([controller selected]); + [controller setSelected:YES]; + EXPECT_TRUE([controller selected]); + + [[controller view] removeFromSuperview]; +} + +// Tests setting the |loading| property via code. +TEST_F(TabControllerTest, Loading) { + NSWindow* window = cocoa_helper_.window(); + scoped_nsobject<TabController> controller([[TabController alloc] init]); + [[window contentView] addSubview:[controller view]]; + + EXPECT_FALSE([controller loading]); + [controller setLoading:YES]; + EXPECT_TRUE([controller loading]); + + [[controller view] removeFromSuperview]; +} + +// Tests selecting the tab with the mouse click and ensuring the target/action +// get called. +// TODO(pinkerton): It's yucky that TabView bakes in the dragging so that we +// can't test this class w/out lots of extra effort. When cole finishes the +// rewrite, we should move all that logic out into a separate controller which +// we can dependency-inject/mock so it has very simple click behavior for unit +// testing. +TEST_F(TabControllerTest, UserSelection) { + NSWindow* window = cocoa_helper_.window(); + + // Create a tab at a known location in the window that we can click on + // to activate selection. + scoped_nsobject<TabController> controller([[TabController alloc] init]); + [[window contentView] addSubview:[controller view]]; + NSRect frame = [[controller view] frame]; + frame.size.width = [TabController minTabWidth]; + frame.origin = NSMakePoint(0, 0); + [[controller view] setFrame:frame]; + + // Set the target and action. + scoped_nsobject<TabControllerTestTarget> target( + [[TabControllerTestTarget alloc] init]); + EXPECT_FALSE([target selected]); + [controller setTarget:target]; + [controller setAction:@selector(selectTab:)]; + EXPECT_EQ(target.get(), [controller target]); + EXPECT_EQ(@selector(selectTab:), [controller action]); + + // In order to track a click, we have to fake a mouse down and a mouse + // up, but the down goes into a tight drag loop. To break the loop, we have + // to fire a timer that sends a mouse up event while the "drag" is ongoing. + [NSTimer scheduledTimerWithTimeInterval:0.1 + target:target.get() + selector:@selector(mouseTimer:) + userInfo:window + repeats:NO]; + NSEvent* current = [[NSApplication sharedApplication] currentEvent]; + NSPoint click_point = NSMakePoint(frame.size.width / 2, + frame.size.height / 2); + NSEvent* down = [NSEvent mouseEventWithType:NSLeftMouseDown + location:click_point + modifierFlags:0 + timestamp:[current timestamp] + windowNumber:[window windowNumber] + context:nil + eventNumber:0 + clickCount:1 + pressure:1.0]; + [[controller view] mouseDown:down]; + + // Check our target was told the tab got selected. + EXPECT_TRUE([target selected]); + + [[controller view] removeFromSuperview]; +} + +} // namespace diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 350d84f..1ccb9d8 100644 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -530,6 +530,7 @@ 'browser/cocoa/browser_window_cocoa.mm', 'browser/cocoa/browser_window_controller.h', 'browser/cocoa/browser_window_controller.mm', + 'browser/cocoa/cocoa_test_helper.h', 'browser/cocoa/command_observer_bridge.h', 'browser/cocoa/command_observer_bridge.mm', 'browser/cocoa/grow_box_view.h', @@ -2095,7 +2096,6 @@ '..', ], 'sources': [ - '../third_party/GTM/AppKit/GTMNSBezierPath+RoundRect.m', 'app/breakpad_mac.mm', # All unittests in browser, common, and renderer. 'browser/autocomplete/autocomplete_unittest.cc', @@ -2125,6 +2125,7 @@ 'browser/cocoa/command_observer_bridge_unittest.mm', 'browser/cocoa/location_bar_view_mac_unittest.mm', 'browser/cocoa/status_bubble_mac_unittest.mm', + 'browser/cocoa/tab_controller_unittest.mm', 'browser/command_updater_unittest.cc', 'browser/debugger/devtools_manager_unittest.cc', 'browser/dom_ui/dom_ui_unittest.cc', @@ -2299,6 +2300,10 @@ 'test/test_notification_tracker.cc', 'test/test_notification_tracker.h', ], + # TODO(mark): We really want this for all non-static library targets, + # but when we tried to pull it up to the common.gypi level, it broke + # other things like the ui, startup, and page_cycler tests. *shrug* + 'xcode_settings': {'OTHER_LDFLAGS': ['-Wl,-ObjC']}, }], ['OS=="win"', { 'defines': [ |