base_bubble_controller_unittest.mm revision f2477e01787aa58f445919b809d89e252beef54f
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 "chrome/browser/ui/cocoa/base_bubble_controller.h" 6 7#include "base/mac/mac_util.h" 8#import "base/mac/scoped_nsobject.h" 9#import "chrome/browser/ui/cocoa/cocoa_test_helper.h" 10#import "chrome/browser/ui/cocoa/info_bubble_view.h" 11#import "chrome/browser/ui/cocoa/run_loop_testing.h" 12#import "ui/base/test/cocoa_test_event_utils.h" 13 14namespace { 15const CGFloat kBubbleWindowWidth = 100; 16const CGFloat kBubbleWindowHeight = 50; 17const CGFloat kAnchorPointX = 400; 18const CGFloat kAnchorPointY = 300; 19} // namespace 20 21class BaseBubbleControllerTest : public CocoaTest { 22 public: 23 virtual void SetUp() OVERRIDE { 24 bubbleWindow_.reset([[NSWindow alloc] 25 initWithContentRect:NSMakeRect(0, 0, kBubbleWindowWidth, 26 kBubbleWindowHeight) 27 styleMask:NSBorderlessWindowMask 28 backing:NSBackingStoreBuffered 29 defer:YES]); 30 31 // The bubble controller will release itself when the window closes. 32 controller_ = [[BaseBubbleController alloc] 33 initWithWindow:bubbleWindow_.get() 34 parentWindow:test_window() 35 anchoredAt:NSMakePoint(kAnchorPointX, kAnchorPointY)]; 36 EXPECT_TRUE([controller_ bubble]); 37 } 38 39 virtual void TearDown() OVERRIDE { 40 // Close our windows. 41 [controller_ close]; 42 bubbleWindow_.reset(NULL); 43 CocoaTest::TearDown(); 44 } 45 46 public: 47 base::scoped_nsobject<NSWindow> bubbleWindow_; 48 BaseBubbleController* controller_; 49}; 50 51// Test that kAlignEdgeToAnchorEdge and a left bubble arrow correctly aligns the 52// left edge of the buble to the anchor point. 53TEST_F(BaseBubbleControllerTest, LeftAlign) { 54 [[controller_ bubble] setArrowLocation:info_bubble::kTopLeft]; 55 [[controller_ bubble] setAlignment:info_bubble::kAlignEdgeToAnchorEdge]; 56 [controller_ showWindow:nil]; 57 58 NSRect frame = [[controller_ window] frame]; 59 // Make sure the bubble size hasn't changed. 60 EXPECT_EQ(frame.size.width, kBubbleWindowWidth); 61 EXPECT_EQ(frame.size.height, kBubbleWindowHeight); 62 // Make sure the bubble is left aligned. 63 EXPECT_EQ(NSMinX(frame), kAnchorPointX); 64 EXPECT_GE(NSMaxY(frame), kAnchorPointY); 65} 66 67// Test that kAlignEdgeToAnchorEdge and a right bubble arrow correctly aligns 68// the right edge of the buble to the anchor point. 69TEST_F(BaseBubbleControllerTest, RightAlign) { 70 [[controller_ bubble] setArrowLocation:info_bubble::kTopRight]; 71 [[controller_ bubble] setAlignment:info_bubble::kAlignEdgeToAnchorEdge]; 72 [controller_ showWindow:nil]; 73 74 NSRect frame = [[controller_ window] frame]; 75 // Make sure the bubble size hasn't changed. 76 EXPECT_EQ(frame.size.width, kBubbleWindowWidth); 77 EXPECT_EQ(frame.size.height, kBubbleWindowHeight); 78 // Make sure the bubble is left aligned. 79 EXPECT_EQ(NSMaxX(frame), kAnchorPointX); 80 EXPECT_GE(NSMaxY(frame), kAnchorPointY); 81} 82 83// Test that kAlignArrowToAnchor and a left bubble arrow correctly aligns 84// the bubble arrow to the anchor point. 85TEST_F(BaseBubbleControllerTest, AnchorAlignLeftArrow) { 86 [[controller_ bubble] setArrowLocation:info_bubble::kTopLeft]; 87 [[controller_ bubble] setAlignment:info_bubble::kAlignArrowToAnchor]; 88 [controller_ showWindow:nil]; 89 90 NSRect frame = [[controller_ window] frame]; 91 // Make sure the bubble size hasn't changed. 92 EXPECT_EQ(frame.size.width, kBubbleWindowWidth); 93 EXPECT_EQ(frame.size.height, kBubbleWindowHeight); 94 // Make sure the bubble arrow points to the anchor. 95 EXPECT_EQ(NSMinX(frame) + info_bubble::kBubbleArrowXOffset + 96 roundf(info_bubble::kBubbleArrowWidth / 2.0), kAnchorPointX); 97 EXPECT_GE(NSMaxY(frame), kAnchorPointY); 98} 99 100// Test that kAlignArrowToAnchor and a right bubble arrow correctly aligns 101// the bubble arrow to the anchor point. 102TEST_F(BaseBubbleControllerTest, AnchorAlignRightArrow) { 103 [[controller_ bubble] setArrowLocation:info_bubble::kTopRight]; 104 [[controller_ bubble] setAlignment:info_bubble::kAlignArrowToAnchor]; 105 [controller_ showWindow:nil]; 106 107 NSRect frame = [[controller_ window] frame]; 108 // Make sure the bubble size hasn't changed. 109 EXPECT_EQ(frame.size.width, kBubbleWindowWidth); 110 EXPECT_EQ(frame.size.height, kBubbleWindowHeight); 111 // Make sure the bubble arrow points to the anchor. 112 EXPECT_EQ(NSMaxX(frame) - info_bubble::kBubbleArrowXOffset - 113 floorf(info_bubble::kBubbleArrowWidth / 2.0), kAnchorPointX); 114 EXPECT_GE(NSMaxY(frame), kAnchorPointY); 115} 116 117// Test that kAlignArrowToAnchor and a center bubble arrow correctly align 118// the bubble towards the anchor point. 119TEST_F(BaseBubbleControllerTest, AnchorAlignCenterArrow) { 120 [[controller_ bubble] setArrowLocation:info_bubble::kTopCenter]; 121 [[controller_ bubble] setAlignment:info_bubble::kAlignArrowToAnchor]; 122 [controller_ showWindow:nil]; 123 124 NSRect frame = [[controller_ window] frame]; 125 // Make sure the bubble size hasn't changed. 126 EXPECT_EQ(frame.size.width, kBubbleWindowWidth); 127 EXPECT_EQ(frame.size.height, kBubbleWindowHeight); 128 // Make sure the bubble arrow points to the anchor. 129 EXPECT_EQ(NSMidX(frame), kAnchorPointX); 130 EXPECT_GE(NSMaxY(frame), kAnchorPointY); 131} 132 133// Tests that when a new window gets key state (and the bubble resigns) that 134// the key window changes. 135TEST_F(BaseBubbleControllerTest, ResignKeyCloses) { 136 // Closing the bubble will autorelease the controller. 137 base::scoped_nsobject<BaseBubbleController> keep_alive([controller_ retain]); 138 139 NSWindow* bubble_window = [controller_ window]; 140 EXPECT_FALSE([bubble_window isVisible]); 141 142 base::scoped_nsobject<NSWindow> other_window( 143 [[NSWindow alloc] initWithContentRect:NSMakeRect(500, 500, 500, 500) 144 styleMask:NSTitledWindowMask 145 backing:NSBackingStoreBuffered 146 defer:YES]); 147 EXPECT_FALSE([other_window isVisible]); 148 149 [controller_ showWindow:nil]; 150 EXPECT_TRUE([bubble_window isVisible]); 151 EXPECT_FALSE([other_window isVisible]); 152 153 [other_window makeKeyAndOrderFront:nil]; 154 // Fake the key state notification. Because unit_tests is a "daemon" process 155 // type, its windows can never become key (nor can the app become active). 156 // Instead of the hacks below, one could make a browser_test or transform the 157 // process type, but this seems easiest and is best suited to a unit test. 158 // 159 // On Lion and above, which have the event taps, simply post a notification 160 // that will cause the controller to call |-windowDidResignKey:|. Earlier 161 // OSes can call through directly. 162 NSNotification* notif = 163 [NSNotification notificationWithName:NSWindowDidResignKeyNotification 164 object:bubble_window]; 165 if (base::mac::IsOSLionOrLater()) 166 [[NSNotificationCenter defaultCenter] postNotification:notif]; 167 else 168 [controller_ windowDidResignKey:notif]; 169 170 171 EXPECT_FALSE([bubble_window isVisible]); 172 EXPECT_TRUE([other_window isVisible]); 173} 174 175// Test that clicking outside the window causes the bubble to close if 176// shouldCloseOnResignKey is YES. 177TEST_F(BaseBubbleControllerTest, LionClickOutsideCloses) { 178 // The event tap is only installed on 10.7+. 179 if (!base::mac::IsOSLionOrLater()) 180 return; 181 182 // Closing the bubble will autorelease the controller. 183 base::scoped_nsobject<BaseBubbleController> keep_alive([controller_ retain]); 184 NSWindow* window = [controller_ window]; 185 186 EXPECT_TRUE([controller_ shouldCloseOnResignKey]); // Verify default value. 187 EXPECT_FALSE([window isVisible]); 188 189 [controller_ showWindow:nil]; 190 191 EXPECT_TRUE([window isVisible]); 192 193 [controller_ setShouldCloseOnResignKey:NO]; 194 NSEvent* event = cocoa_test_event_utils::LeftMouseDownAtPointInWindow( 195 NSMakePoint(10, 10), test_window()); 196 [NSApp sendEvent:event]; 197 chrome::testing::NSRunLoopRunAllPending(); 198 199 EXPECT_TRUE([window isVisible]); 200 201 [controller_ setShouldCloseOnResignKey:YES]; 202 event = cocoa_test_event_utils::LeftMouseDownAtPointInWindow( 203 NSMakePoint(10, 10), test_window()); 204 [NSApp sendEvent:event]; 205 chrome::testing::NSRunLoopRunAllPending(); 206 207 EXPECT_FALSE([window isVisible]); 208} 209