Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / browser / ui / cocoa / constrained_window / constrained_window_sheet_controller_unittest.mm
blobefa051f2fab393da5ae5f614cc36dc4e3c1e74a7
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.
5 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_sheet_controller.h"
7 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
8 #import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
9 #import "testing/gtest_mac.h"
11 namespace {
13 const int kSystemSheetReturnCode = 77;
15 }  // namespace
17 @interface ConstrainedWindowSystemSheetTest
18     : NSObject <ConstrainedWindowSheet> {
19   int returnCode_;
20   NSAlert* alert_;  // weak
23 @property(nonatomic, readonly) int returnCode;
24 @property(nonatomic, assign) NSAlert* alert;
26 @end
28 @implementation ConstrainedWindowSystemSheetTest
30 @synthesize returnCode = returnCode_;
31 @synthesize alert = alert_;
33 - (void)showSheetForWindow:(NSWindow*)window {
34   [alert_ beginSheetModalForWindow:window
35                      modalDelegate:self
36                     didEndSelector:@selector(alertDidEnd:returnCode:ctxInfo:)
37                        contextInfo:NULL];
40 - (void)closeSheetWithAnimation:(BOOL)withAnimation {
41   [NSApp endSheet:[alert_ window] returnCode:kSystemSheetReturnCode];
44 - (void)hideSheet {
47 - (void)unhideSheet {
50 - (void)pulseSheet {
53 - (void)makeSheetKeyAndOrderFront {
56 - (void)updateSheetPosition {
59 - (NSWindow*)sheetWindow {
60   return [alert_ window];
63 - (void)alertDidEnd:(NSAlert *)alert
64          returnCode:(NSInteger)returnCode
65             ctxInfo:(void *)contextInfo {
66   returnCode_ = returnCode;
69 @end
71 class ConstrainedWindowSheetControllerTest : public CocoaTest {
72  protected:
73   void SetUp() override {
74     CocoaTest::SetUp();
76     // Center the window so that the sheet doesn't go offscreen.
77     [test_window() center];
79     // The real view setup is quite a few levels deep; recreate something
80     // similar.
81     NSRect dummy_rect = NSMakeRect(0, 0, 50, 50);
82     tab_view_parent_ = [test_window() contentView];
83     for (int i = 0; i < 3; ++i) {
84       base::scoped_nsobject<NSView> new_view(
85           [[NSView alloc] initWithFrame:dummy_rect]);
86       [tab_view_parent_ addSubview:new_view.get()];
87       tab_view_parent_ = new_view.get();
88     }
90     controller_.reset([[ConstrainedWindowSheetController
91             controllerForParentWindow:test_window()] retain]);
92     EXPECT_TRUE(controller_);
94     // Create two dummy tabs and make the first one active.
95     tab_views_.reset([[NSMutableArray alloc] init]);
96     sheet_windows_.reset([[NSMutableArray alloc] init]);
97     sheets_.reset([[NSMutableArray alloc] init]);
98     for (int i = 0; i < 2; ++i) {
99       base::scoped_nsobject<NSView> view(
100           [[NSView alloc] initWithFrame:dummy_rect]);
101       base::scoped_nsobject<NSWindow> sheet_window(
102           [[NSWindow alloc]
103             initWithContentRect:dummy_rect
104                       styleMask:NSTitledWindowMask
105                         backing:NSBackingStoreBuffered
106                           defer:NO]);
107       [sheet_window setReleasedWhenClosed:NO];
108       base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
109           [[CustomConstrainedWindowSheet alloc]
110               initWithCustomWindow:sheet_window]);
111       EXPECT_FALSE([ConstrainedWindowSheetController controllerForSheet:sheet]);
112       [tab_views_ addObject:view];
113       [sheet_windows_ addObject:sheet_window];
114       [sheets_ addObject:sheet];
115     }
116     tab0_ = [tab_views_ objectAtIndex:0];
117     tab1_ = [tab_views_ objectAtIndex:1];
118     sheet_window0_ = [sheet_windows_ objectAtIndex:0];
119     sheet_window1_ = [sheet_windows_ objectAtIndex:1];
120     sheet_window_ = sheet_window0_;
121     sheet0_ = [sheets_ objectAtIndex:0];
122     sheet1_ = [sheets_ objectAtIndex:1];
123     sheet_ = sheet0_;
125     active_tab_view_ = tab0_;
126     [tab_view_parent_ addSubview:active_tab_view_];
127   }
129   void TearDown() override {
130     sheets_.reset();
131     sheet_windows_.reset();
132     CocoaTest::TearDown();
133   }
135   void ActivateTabView(NSView* tab_view) {
136     for (NSView* view in tab_views_.get())
137       [view removeFromSuperview];
138     [tab_view_parent_ addSubview:tab_view];
139     active_tab_view_ = tab_view;
141     ConstrainedWindowSheetController* controller =
142         [ConstrainedWindowSheetController
143             controllerForParentWindow:test_window()];
144     EXPECT_TRUE(controller);
146     [controller hideSheet];
147     CustomConstrainedWindowSheet* sheet =
148         [sheets_ objectAtIndex:[tab_views_ indexOfObject:active_tab_view_]];
149     EXPECT_TRUE(sheet);
150     [controller showSheet:sheet forParentView:active_tab_view_];
151   }
153   NSRect GetViewFrameInScreenCoordinates(NSView* view) {
154     NSRect rect = [view convertRect:[view bounds] toView:nil];
155     rect.origin = [[view window] convertBaseToScreen:rect.origin];
156     return rect;
157   }
159   void VerifySheetXPosition(NSRect sheet_frame, NSView* parent_view) {
160     NSRect parent_frame = GetViewFrameInScreenCoordinates(parent_view);
161     CGFloat expected_x = NSMinX(parent_frame) +
162         (NSWidth(parent_frame) - NSWidth(sheet_frame)) / 2.0;
163     EXPECT_EQ(expected_x, NSMinX(sheet_frame));
164   }
166   CGFloat GetSheetYOffset(NSRect sheet_frame, NSView* parent_view) {
167     return NSMaxY(sheet_frame) -
168            NSMaxY(GetViewFrameInScreenCoordinates(parent_view));
169   }
171   base::scoped_nsobject<NSMutableArray> sheet_windows_;
172   NSWindow* sheet_window0_;
173   NSWindow* sheet_window1_;
174   NSWindow* sheet_window_;
175   base::scoped_nsobject<NSMutableArray> sheets_;
176   CustomConstrainedWindowSheet* sheet0_;
177   CustomConstrainedWindowSheet* sheet1_;
178   CustomConstrainedWindowSheet* sheet_;
179   base::scoped_nsobject<ConstrainedWindowSheetController> controller_;
180   base::scoped_nsobject<NSMutableArray> tab_views_;
181   NSView* tab_view_parent_;
182   NSView* active_tab_view_;
183   NSView* tab0_;
184   NSView* tab1_;
187 // Test showing then hiding the sheet.
188 TEST_F(ConstrainedWindowSheetControllerTest, ShowHide) {
189   EXPECT_FALSE([sheet_window_ isVisible]);
190   [controller_ showSheet:sheet_ forParentView:active_tab_view_];
191   EXPECT_TRUE([ConstrainedWindowSheetController controllerForSheet:sheet_]);
192   EXPECT_TRUE([sheet_window_ isVisible]);
194   [controller_ closeSheet:sheet_];
195   EXPECT_FALSE([ConstrainedWindowSheetController controllerForSheet:sheet_]);
196   EXPECT_FALSE([sheet_window_ isVisible]);
199 // Test that switching tabs correctly hides the inactive tab's sheet.
200 TEST_F(ConstrainedWindowSheetControllerTest, SwitchTabs) {
201   [controller_ showSheet:sheet_ forParentView:active_tab_view_];
203   EXPECT_TRUE([sheet_window_ isVisible]);
204   EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
205   ActivateTabView([tab_views_ objectAtIndex:1]);
206   EXPECT_TRUE([sheet_window_ isVisible]);
207   EXPECT_EQ(0.0, [sheet_window_ alphaValue]);
208   ActivateTabView([tab_views_ objectAtIndex:0]);
209   EXPECT_TRUE([sheet_window_ isVisible]);
210   EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
213 // Test that two parent windows with two sheet controllers don't conflict.
214 TEST_F(ConstrainedWindowSheetControllerTest, TwoParentWindows) {
215   base::scoped_nsobject<NSWindow> parent_window2(
216       [[NSWindow alloc] initWithContentRect:NSMakeRect(0, 0, 30, 30)
217                                   styleMask:NSTitledWindowMask
218                                     backing:NSBackingStoreBuffered
219                                       defer:NO]);
220   [parent_window2 setReleasedWhenClosed:NO];
222   ConstrainedWindowSheetController* controller2 =
223       [ConstrainedWindowSheetController
224           controllerForParentWindow:parent_window2];
225   EXPECT_TRUE(controller2);
226   EXPECT_NSNE(controller_, controller2);
228   [controller2 showSheet:sheet_ forParentView:[parent_window2 contentView]];
229   EXPECT_NSEQ(controller2,
230               [ConstrainedWindowSheetController controllerForSheet:sheet_]);
232   [parent_window2 close];
235 // Test that resizing sheet works.
236 TEST_F(ConstrainedWindowSheetControllerTest, Resize) {
237   [controller_ showSheet:sheet_ forParentView:active_tab_view_];
239   NSRect old_frame = [sheet_window_ frame];
241   NSRect sheet_frame;
242   sheet_frame.size = NSMakeSize(NSWidth(old_frame) + 100,
243                                 NSHeight(old_frame) + 50);
244   sheet_frame.origin = [controller_ originForSheet:sheet_
245                                     withWindowSize:sheet_frame.size];
247   // Y pos should not have changed.
248   EXPECT_EQ(NSMaxY(sheet_frame), NSMaxY(old_frame));
250   // X pos should be centered on parent view.
251   VerifySheetXPosition(sheet_frame, active_tab_view_);
254 // Test that resizing a hidden sheet works.
255 TEST_F(ConstrainedWindowSheetControllerTest, ResizeHiddenSheet) {
256   [controller_ showSheet:sheet_ forParentView:tab0_];
257   EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
258   ActivateTabView(tab1_);
259   EXPECT_EQ(0.0, [sheet_window_ alphaValue]);
261   NSRect old_frame = [sheet_window_ frame];
262   NSRect new_inactive_frame = NSInsetRect(old_frame, -30, -40);
263   [sheet_window_ setFrame:new_inactive_frame display:YES];
265   ActivateTabView(tab0_);
266   EXPECT_EQ(1.0, [sheet_window_ alphaValue]);
268   NSRect new_active_frame = [sheet_window_ frame];
269   EXPECT_EQ(NSWidth(new_inactive_frame), NSWidth(new_active_frame));
270   EXPECT_EQ(NSHeight(new_inactive_frame), NSHeight(new_active_frame));
273 // Test resizing parent window keeps the sheet anchored.
274 TEST_F(ConstrainedWindowSheetControllerTest, ResizeParentWindow) {
275   [controller_ showSheet:sheet_ forParentView:active_tab_view_];
276   CGFloat sheet_offset =
277       GetSheetYOffset([sheet_window_ frame], active_tab_view_);
279   // Test 3x3 different parent window sizes.
280   CGFloat insets[] = {-10, 0, 10};
281   NSRect old_frame = [test_window() frame];
283   for (size_t x = 0; x < arraysize(insets); x++) {
284     for (size_t y = 0; y < arraysize(insets); y++) {
285       NSRect resized_frame = NSInsetRect(old_frame, insets[x], insets[y]);
286       [test_window() setFrame:resized_frame display:YES];
287       NSRect sheet_frame = [sheet_window_ frame];
289       // Y pos should track parent view's position.
290       EXPECT_EQ(sheet_offset, GetSheetYOffset(sheet_frame, active_tab_view_));
292       // X pos should be centered on parent view.
293       VerifySheetXPosition(sheet_frame, active_tab_view_);
294     }
295   }
298 // Test system sheets.
299 TEST_F(ConstrainedWindowSheetControllerTest, SystemSheet) {
300   base::scoped_nsobject<ConstrainedWindowSystemSheetTest> system_sheet(
301       [[ConstrainedWindowSystemSheetTest alloc] init]);
302   base::scoped_nsobject<NSAlert> alert([[NSAlert alloc] init]);
303   [system_sheet setAlert:alert];
305   EXPECT_FALSE([[alert window] isVisible]);
306   [controller_ showSheet:system_sheet forParentView:active_tab_view_];
307   EXPECT_TRUE([[alert window] isVisible]);
309   [controller_ closeSheet:system_sheet];
310   EXPECT_FALSE([[alert window] isVisible]);
311   EXPECT_EQ(kSystemSheetReturnCode, [system_sheet returnCode]);