Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(43)

Side by Side Diff: chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm

Issue 2488833002: [Mac] Reverse tabs in RTL mode (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #import <Cocoa/Cocoa.h> 5 #import <Cocoa/Cocoa.h>
6 #include <stddef.h> 6 #include <stddef.h>
7 7
8 #import "base/mac/scoped_nsobject.h" 8 #import "base/mac/scoped_nsobject.h"
9 #include "base/macros.h" 9 #include "base/macros.h"
10 #include "base/message_loop/message_loop.h" 10 #include "base/message_loop/message_loop.h"
11 #include "base/strings/utf_string_conversions.h" 11 #include "base/strings/utf_string_conversions.h"
12 #include "base/test/scoped_feature_list.h"
12 #include "chrome/browser/ui/cocoa/cocoa_test_helper.h" 13 #include "chrome/browser/ui/cocoa/cocoa_test_helper.h"
14 #include "chrome/browser/ui/cocoa/l10n_util.h"
13 #import "chrome/browser/ui/cocoa/tabs/alert_indicator_button_cocoa.h" 15 #import "chrome/browser/ui/cocoa/tabs/alert_indicator_button_cocoa.h"
14 #import "chrome/browser/ui/cocoa/tabs/tab_controller.h" 16 #import "chrome/browser/ui/cocoa/tabs/tab_controller.h"
15 #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h" 17 #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h"
16 #import "chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.h" 18 #import "chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.h"
17 #import "chrome/browser/ui/cocoa/tabs/tab_view.h" 19 #import "chrome/browser/ui/cocoa/tabs/tab_view.h"
18 #include "testing/gtest/include/gtest/gtest.h" 20 #include "testing/gtest/include/gtest/gtest.h"
19 #import "testing/gtest_mac.h" 21 #import "testing/gtest_mac.h"
20 #include "testing/platform_test.h" 22 #include "testing/platform_test.h"
21 #include "ui/base/resource/resource_bundle.h" 23 #include "ui/base/resource/resource_bundle.h"
22 #include "ui/resources/grit/ui_resources.h" 24 #include "ui/resources/grit/ui_resources.h"
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
97 CGFloat RightMargin(NSRect superFrame, NSRect subFrame) { 99 CGFloat RightMargin(NSRect superFrame, NSRect subFrame) {
98 return NSMaxX(superFrame) - NSMaxX(subFrame); 100 return NSMaxX(superFrame) - NSMaxX(subFrame);
99 } 101 }
100 102
101 // The dragging code in TabView makes heavy use of autorelease pools so 103 // The dragging code in TabView makes heavy use of autorelease pools so
102 // inherit from CocoaTest to have one created for us. 104 // inherit from CocoaTest to have one created for us.
103 class TabControllerTest : public CocoaTest { 105 class TabControllerTest : public CocoaTest {
104 public: 106 public:
105 TabControllerTest() { } 107 TabControllerTest() { }
106 108
109 protected:
110 void CheckLayoutAndVisibilityOfSubviewsForAllStates(bool is_rtl) {
111 static const TabAlertState kAlertStatesToTest[] = {
112 TabAlertState::NONE, TabAlertState::TAB_CAPTURING,
113 TabAlertState::AUDIO_PLAYING, TabAlertState::AUDIO_MUTING};
114
115 NSWindow* const window = test_window();
116
117 // Create TabController instance and place its view into the test window.
118 base::scoped_nsobject<TabController> controller(
119 [[TabController alloc] init]);
120 [[window contentView] addSubview:[controller view]];
121
122 // Create favicon.
123 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
124 base::scoped_nsobject<NSImage> favicon(
125 rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON).CopyNSImage());
126
127 // Trigger TabController to auto-create the AlertIndicatorButton.
128 [controller setAlertState:TabAlertState::AUDIO_PLAYING];
129 [controller setAlertState:TabAlertState::NONE];
130 base::scoped_nsobject<AlertIndicatorButton> alertIndicatorButton(
131 [[controller alertIndicatorButton] retain]);
132 ASSERT_TRUE(alertIndicatorButton.get());
133
134 // Perform layout over all possible combinations, checking for correct
135 // results.
136 for (int isPinnedTab = 0; isPinnedTab < 2; ++isPinnedTab) {
137 for (int isActiveTab = 0; isActiveTab < 2; ++isActiveTab) {
138 for (size_t alertStateIndex = 0;
139 alertStateIndex < arraysize(kAlertStatesToTest);
140 ++alertStateIndex) {
141 const TabAlertState alertState = kAlertStatesToTest[alertStateIndex];
142 SCOPED_TRACE(::testing::Message()
143 << (isActiveTab ? "Active" : "Inactive") << ' '
144 << (isPinnedTab ? "Pinned " : "")
145 << "Tab with alert indicator state "
146 << static_cast<uint8_t>(alertState));
147
148 // Simulate what tab_strip_controller would do to set up the
149 // TabController state.
150 [controller setPinned:(isPinnedTab ? YES : NO)];
151 [controller setActive:(isActiveTab ? YES : NO)];
152 [controller setIconImage:favicon];
153 [controller setAlertState:alertState];
154 [controller updateVisibility];
155
156 // Test layout for every width from maximum to minimum.
157 NSRect tabFrame = [[controller view] frame];
158 int minWidth;
159 if (isPinnedTab) {
160 tabFrame.size.width = minWidth = [TabController pinnedTabWidth];
161 } else {
162 tabFrame.size.width = [TabController maxTabWidth];
163 minWidth = isActiveTab ? [TabController minActiveTabWidth]
164 : [TabController minTabWidth];
165 }
166 while (NSWidth(tabFrame) >= minWidth) {
167 SCOPED_TRACE(::testing::Message() << "width="
168 << tabFrame.size.width);
169 [[controller view] setFrame:tabFrame];
170 if (is_rtl)
171 CheckForExpectedLayoutAndVisibilityOfSubviewsRTL(controller);
172 else
173 CheckForExpectedLayoutAndVisibilityOfSubviews(controller);
174 --tabFrame.size.width;
175 }
176 }
177 }
178 }
179 }
180
181 private:
107 static void CheckForExpectedLayoutAndVisibilityOfSubviews( 182 static void CheckForExpectedLayoutAndVisibilityOfSubviews(
108 const TabController* controller) { 183 const TabController* controller) {
184 CheckVisibilityOfSubviews(controller);
185
186 // Check positioning of elements with respect to each other, and that they
187 // are fully within the tab frame.
188 const NSRect tabFrame = [[controller view] frame];
189 const NSRect titleFrame = [[controller tabView] titleFrame];
190 if ([controller shouldShowIcon]) {
191 const NSRect iconFrame = [[controller iconView] frame];
192 EXPECT_LE(NSMinX(tabFrame), NSMinX(iconFrame));
193 if (NSWidth(titleFrame) > 0)
194 EXPECT_LE(NSMaxX(iconFrame), NSMinX(titleFrame));
195 EXPECT_LE(NSMinY(tabFrame), NSMinY(iconFrame));
196 EXPECT_LE(NSMaxY(iconFrame), NSMaxY(tabFrame));
197 }
198 if ([controller shouldShowIcon] && [controller shouldShowAlertIndicator]) {
199 EXPECT_LE(NSMaxX([[controller iconView] frame]),
200 NSMinX([[controller alertIndicatorButton] frame]));
201 }
202 if ([controller shouldShowAlertIndicator]) {
203 const NSRect alertIndicatorFrame =
204 [[controller alertIndicatorButton] frame];
205 if (NSWidth(titleFrame) > 0)
206 EXPECT_LE(NSMaxX(titleFrame), NSMinX(alertIndicatorFrame));
207 EXPECT_LE(NSMaxX(alertIndicatorFrame), NSMaxX(tabFrame));
208 EXPECT_LE(NSMinY(tabFrame), NSMinY(alertIndicatorFrame));
209 EXPECT_LE(NSMaxY(alertIndicatorFrame), NSMaxY(tabFrame));
210 }
211 if ([controller shouldShowAlertIndicator] &&
212 [controller shouldShowCloseButton]) {
213 EXPECT_LE(NSMaxX([[controller alertIndicatorButton] frame]),
214 NSMinX([[controller closeButton] frame]));
215 }
216 if ([controller shouldShowCloseButton]) {
217 const NSRect closeButtonFrame = [[controller closeButton] frame];
218 if (NSWidth(titleFrame) > 0)
219 EXPECT_LE(NSMaxX(titleFrame), NSMinX(closeButtonFrame));
220 EXPECT_LE(NSMaxX(closeButtonFrame), NSMaxX(tabFrame));
221 EXPECT_LE(NSMinY(tabFrame), NSMinY(closeButtonFrame));
222 EXPECT_LE(NSMaxY(closeButtonFrame), NSMaxY(tabFrame));
223 }
224 }
225 static void CheckForExpectedLayoutAndVisibilityOfSubviewsRTL(
226 const TabController* controller) {
227 CheckVisibilityOfSubviews(controller);
228 // Check positioning of elements with respect to each other, and that they
229 // are fully within the tab frame.
230 const NSRect tabFrame = [[controller view] frame];
231 const NSRect titleFrame = [[controller tabView] titleFrame];
232 if ([controller shouldShowCloseButton]) {
233 const NSRect closeButtonFrame = [[controller closeButton] frame];
234 EXPECT_TRUE(NSContainsRect(tabFrame, closeButtonFrame));
235 if (NSWidth(titleFrame) > 0)
236 EXPECT_LE(NSMaxX(closeButtonFrame), NSMinX(titleFrame));
237 }
238 if ([controller shouldShowCloseButton] &&
239 [controller shouldShowAlertIndicator]) {
240 EXPECT_LE(NSMaxX([[controller closeButton] frame]),
241 NSMinX([[controller alertIndicatorButton] frame]));
242 }
243 if ([controller shouldShowAlertIndicator]) {
244 const NSRect alertIndicatorFrame =
245 [[controller alertIndicatorButton] frame];
246 EXPECT_TRUE(NSContainsRect(tabFrame, alertIndicatorFrame));
247 if (NSWidth(titleFrame) > 0)
248 EXPECT_LE(NSMaxX(alertIndicatorFrame), NSMinX(titleFrame));
249 }
250 if ([controller shouldShowAlertIndicator] && [controller shouldShowIcon]) {
251 EXPECT_LE(NSMaxX([[controller alertIndicatorButton] frame]),
252 NSMinX([[controller iconView] frame]));
253 }
254 if ([controller shouldShowIcon]) {
255 const NSRect iconFrame = [[controller iconView] frame];
256 EXPECT_TRUE(NSContainsRect(tabFrame, iconFrame));
257 if (NSWidth(titleFrame) > 0)
258 EXPECT_LE(NSMaxX(titleFrame), NSMinX(iconFrame));
259 }
260 }
261 // Common for RTL and LTR
262 static void CheckVisibilityOfSubviews(const TabController* controller) {
109 // Check whether subviews should be visible when they are supposed to be, 263 // Check whether subviews should be visible when they are supposed to be,
110 // given Tab size and TabRendererData state. 264 // given Tab size and TabRendererData state.
111 const TabAlertState indicatorState = 265 const TabAlertState indicatorState =
112 [[controller alertIndicatorButton] showingAlertState]; 266 [[controller alertIndicatorButton] showingAlertState];
113 if ([controller pinned]) { 267 if ([controller pinned]) {
114 EXPECT_EQ(1, [controller iconCapacity]); 268 EXPECT_EQ(1, [controller iconCapacity]);
115 if (indicatorState != TabAlertState::NONE) { 269 if (indicatorState != TabAlertState::NONE) {
116 EXPECT_FALSE([controller shouldShowIcon]); 270 EXPECT_FALSE([controller shouldShowIcon]);
117 EXPECT_TRUE([controller shouldShowAlertIndicator]); 271 EXPECT_TRUE([controller shouldShowAlertIndicator]);
118 } else { 272 } else {
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
166 default: 320 default:
167 EXPECT_LE(2, [controller iconCapacity]); 321 EXPECT_LE(2, [controller iconCapacity]);
168 EXPECT_TRUE([controller shouldShowIcon]); 322 EXPECT_TRUE([controller shouldShowIcon]);
169 if (indicatorState != TabAlertState::NONE) 323 if (indicatorState != TabAlertState::NONE)
170 EXPECT_TRUE([controller shouldShowAlertIndicator]); 324 EXPECT_TRUE([controller shouldShowAlertIndicator]);
171 else 325 else
172 EXPECT_FALSE([controller shouldShowAlertIndicator]); 326 EXPECT_FALSE([controller shouldShowAlertIndicator]);
173 break; 327 break;
174 } 328 }
175 } 329 }
176
177 // Make sure the NSView's "isHidden" state jives with the "shouldShowXXX."
178 EXPECT_TRUE([controller shouldShowIcon] ==
179 (!![controller iconView] && ![[controller iconView] isHidden]));
180 EXPECT_TRUE([controller pinned] == [[controller tabView] titleHidden]);
181 EXPECT_TRUE([controller shouldShowAlertIndicator] ==
182 ![[controller alertIndicatorButton] isHidden]);
183 EXPECT_TRUE([controller shouldShowCloseButton] !=
184 [[controller closeButton] isHidden]);
185
186 // Check positioning of elements with respect to each other, and that they
187 // are fully within the tab frame.
188 const NSRect tabFrame = [[controller view] frame];
189 const NSRect titleFrame = [[controller tabView] titleFrame];
190 if ([controller shouldShowIcon]) {
191 const NSRect iconFrame = [[controller iconView] frame];
192 EXPECT_LE(NSMinX(tabFrame), NSMinX(iconFrame));
193 if (NSWidth(titleFrame) > 0)
194 EXPECT_LE(NSMaxX(iconFrame), NSMinX(titleFrame));
195 EXPECT_LE(NSMinY(tabFrame), NSMinY(iconFrame));
196 EXPECT_LE(NSMaxY(iconFrame), NSMaxY(tabFrame));
197 }
198 if ([controller shouldShowIcon] && [controller shouldShowAlertIndicator]) {
199 EXPECT_LE(NSMaxX([[controller iconView] frame]),
200 NSMinX([[controller alertIndicatorButton] frame]));
201 }
202 if ([controller shouldShowAlertIndicator]) {
203 const NSRect alertIndicatorFrame =
204 [[controller alertIndicatorButton] frame];
205 if (NSWidth(titleFrame) > 0)
206 EXPECT_LE(NSMaxX(titleFrame), NSMinX(alertIndicatorFrame));
207 EXPECT_LE(NSMaxX(alertIndicatorFrame), NSMaxX(tabFrame));
208 EXPECT_LE(NSMinY(tabFrame), NSMinY(alertIndicatorFrame));
209 EXPECT_LE(NSMaxY(alertIndicatorFrame), NSMaxY(tabFrame));
210 }
211 if ([controller shouldShowAlertIndicator] &&
212 [controller shouldShowCloseButton]) {
213 EXPECT_LE(NSMaxX([[controller alertIndicatorButton] frame]),
214 NSMinX([[controller closeButton] frame]));
215 }
216 if ([controller shouldShowCloseButton]) {
217 const NSRect closeButtonFrame = [[controller closeButton] frame];
218 if (NSWidth(titleFrame) > 0)
219 EXPECT_LE(NSMaxX(titleFrame), NSMinX(closeButtonFrame));
220 EXPECT_LE(NSMaxX(closeButtonFrame), NSMaxX(tabFrame));
221 EXPECT_LE(NSMinY(tabFrame), NSMinY(closeButtonFrame));
222 EXPECT_LE(NSMaxY(closeButtonFrame), NSMaxY(tabFrame));
223 }
224 } 330 }
225 331
226 private:
227 base::MessageLoop message_loop_; 332 base::MessageLoop message_loop_;
228 }; 333 };
229 334
230 // Tests creating the controller, sticking it in a window, and removing it. 335 // Tests creating the controller, sticking it in a window, and removing it.
231 TEST_F(TabControllerTest, Creation) { 336 TEST_F(TabControllerTest, Creation) {
232 NSWindow* window = test_window(); 337 NSWindow* window = test_window();
233 base::scoped_nsobject<TabController> controller([[TabController alloc] init]); 338 base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
234 [[window contentView] addSubview:[controller view]]; 339 [[window contentView] addSubview:[controller view]];
235 EXPECT_TRUE([controller tabView]); 340 EXPECT_TRUE([controller tabView]);
236 EXPECT_EQ([[controller view] window], window); 341 EXPECT_EQ([[controller view] window], window);
(...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 NSWidth([[controller tabView] titleFrame])); 572 NSWidth([[controller tabView] titleFrame]));
468 EXPECT_EQ(LeftMargin(originalTabFrame, originalTitleFrame), 573 EXPECT_EQ(LeftMargin(originalTabFrame, originalTitleFrame),
469 LeftMargin([[controller view] frame], 574 LeftMargin([[controller view] frame],
470 [[controller tabView] titleFrame])); 575 [[controller tabView] titleFrame]));
471 EXPECT_EQ(RightMargin(originalTabFrame, originalTitleFrame), 576 EXPECT_EQ(RightMargin(originalTabFrame, originalTitleFrame),
472 RightMargin([[controller view] frame], 577 RightMargin([[controller view] frame],
473 [[controller tabView] titleFrame])); 578 [[controller tabView] titleFrame]));
474 } 579 }
475 580
476 TEST_F(TabControllerTest, LayoutAndVisibilityOfSubviews) { 581 TEST_F(TabControllerTest, LayoutAndVisibilityOfSubviews) {
477 static const TabAlertState kAlertStatesToTest[] = { 582 CheckLayoutAndVisibilityOfSubviewsForAllStates(false);
478 TabAlertState::NONE, TabAlertState::TAB_CAPTURING, 583 }
479 TabAlertState::AUDIO_PLAYING, TabAlertState::AUDIO_MUTING
480 };
481 584
482 NSWindow* const window = test_window(); 585 TEST_F(TabControllerTest, LayoutAndVisibilityOfSubviewsRTL) {
586 base::test::ScopedFeatureList scoped_feature_list;
587 scoped_feature_list.InitAndEnableFeature(
588 cocoa_l10n_util::kExperimentalMacRTL);
589 // TODO(lgrey): Create ScopedNSUserDefaults or similar to do
590 // this automatically.
591 NSString* const appleTextDirectionDefaultsKey = @"AppleTextDirection";
592 NSString* const forceRTLWritingDirectionDefaultsKey =
593 @"NSForceRightToLeftWritingDirection";
594 NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
595 BOOL oldTextDirection = [defaults boolForKey:appleTextDirectionDefaultsKey];
596 BOOL oldRTLWritingDirection =
597 [defaults boolForKey:forceRTLWritingDirectionDefaultsKey];
598 [defaults setBool:YES forKey:appleTextDirectionDefaultsKey];
599 [defaults setBool:YES forKey:forceRTLWritingDirectionDefaultsKey];
483 600
484 // Create TabController instance and place its view into the test window. 601 CheckLayoutAndVisibilityOfSubviewsForAllStates(true);
485 base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
486 [[window contentView] addSubview:[controller view]];
487 602
488 // Create favicon. 603 [defaults setBool:oldTextDirection forKey:appleTextDirectionDefaultsKey];
489 ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); 604 [defaults setBool:oldRTLWritingDirection
490 base::scoped_nsobject<NSImage> favicon( 605 forKey:forceRTLWritingDirectionDefaultsKey];
491 rb.GetNativeImageNamed(IDR_DEFAULT_FAVICON).CopyNSImage());
492
493 // Trigger TabController to auto-create the AlertIndicatorButton.
494 [controller setAlertState:TabAlertState::AUDIO_PLAYING];
495 [controller setAlertState:TabAlertState::NONE];
496 base::scoped_nsobject<AlertIndicatorButton> alertIndicatorButton(
497 [[controller alertIndicatorButton] retain]);
498 ASSERT_TRUE(alertIndicatorButton.get());
499
500 // Perform layout over all possible combinations, checking for correct
501 // results.
502 for (int isPinnedTab = 0; isPinnedTab < 2; ++isPinnedTab) {
503 for (int isActiveTab = 0; isActiveTab < 2; ++isActiveTab) {
504 for (size_t alertStateIndex = 0;
505 alertStateIndex < arraysize(kAlertStatesToTest);
506 ++alertStateIndex) {
507 const TabAlertState alertState = kAlertStatesToTest[alertStateIndex];
508 SCOPED_TRACE(::testing::Message()
509 << (isActiveTab ? "Active" : "Inactive") << ' '
510 << (isPinnedTab ? "Pinned " : "")
511 << "Tab with alert indicator state "
512 << static_cast<uint8_t>(alertState));
513
514 // Simulate what tab_strip_controller would do to set up the
515 // TabController state.
516 [controller setPinned:(isPinnedTab ? YES : NO)];
517 [controller setActive:(isActiveTab ? YES : NO)];
518 [controller setIconImage:favicon];
519 [controller setAlertState:alertState];
520 [controller updateVisibility];
521
522 // Test layout for every width from maximum to minimum.
523 NSRect tabFrame = [[controller view] frame];
524 int minWidth;
525 if (isPinnedTab) {
526 tabFrame.size.width = minWidth = [TabController pinnedTabWidth];
527 } else {
528 tabFrame.size.width = [TabController maxTabWidth];
529 minWidth = isActiveTab ? [TabController minActiveTabWidth] :
530 [TabController minTabWidth];
531 }
532 while (NSWidth(tabFrame) >= minWidth) {
533 SCOPED_TRACE(::testing::Message() << "width=" << tabFrame.size.width);
534 [[controller view] setFrame:tabFrame];
535 CheckForExpectedLayoutAndVisibilityOfSubviews(controller);
536 --tabFrame.size.width;
537 }
538 }
539 }
540 }
541 } 606 }
542 607
543 } // namespace 608 } // namespace
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698