| Index: chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm
|
| diff --git a/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm b/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm
|
| index 0267e79c297c3b7402e505c3c5f73a62f1622777..ab58034023a490e7ace778017eb31daefa64bddb 100644
|
| --- a/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm
|
| +++ b/chrome/browser/ui/cocoa/tabs/tab_controller_unittest.mm
|
| @@ -10,9 +10,12 @@
|
| #import "chrome/browser/ui/cocoa/tabs/tab_controller.h"
|
| #import "chrome/browser/ui/cocoa/tabs/tab_controller_target.h"
|
| #import "chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.h"
|
| +#include "grit/theme_resources.h"
|
| +#include "grit/ui_resources.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
| #import "testing/gtest_mac.h"
|
| #include "testing/platform_test.h"
|
| +#include "ui/base/resource/resource_bundle.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.
|
| @@ -91,11 +94,137 @@ CGFloat RightMargin(NSRect superFrame, NSRect subFrame) {
|
| return NSMaxX(superFrame) - NSMaxX(subFrame);
|
| }
|
|
|
| +// Helper to create an NSImageView that contains an image fetched from
|
| +// ui::ResourceBundle.
|
| +NSImageView* CreateImageViewFromResourceBundle(int resource_id) {
|
| + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
|
| + NSImage* const image = rb.GetNativeImageNamed(resource_id).ToNSImage();
|
| + CHECK(!!image);
|
| + NSRect frame;
|
| + frame.size = [image size];
|
| + NSImageView* const view = [[NSImageView alloc] initWithFrame:frame];
|
| + [view setImage:image];
|
| + return view;
|
| +}
|
| +
|
| // The dragging code in TabView makes heavy use of autorelease pools so
|
| // inherit from CocoaTest to have one created for us.
|
| class TabControllerTest : public CocoaTest {
|
| public:
|
| TabControllerTest() { }
|
| +
|
| + static void CheckForExpectedLayoutAndVisibilityOfSubviews(
|
| + const TabController* controller) {
|
| + // Check whether subviews should be visible when they are supposed to be,
|
| + // given Tab size and TabRendererData state.
|
| + if ([controller mini]) {
|
| + if ([controller projecting])
|
| + EXPECT_TRUE([controller shouldShowIcon]);
|
| + else
|
| + EXPECT_TRUE([controller shouldShowIcon] !=
|
| + [controller shouldShowAudioIndicator]);
|
| + EXPECT_FALSE([controller shouldShowCloseButton]);
|
| + } else if ([controller selected]) {
|
| + EXPECT_TRUE([controller shouldShowCloseButton]);
|
| + switch ([controller iconCapacity]) {
|
| + case 0:
|
| + case 1:
|
| + EXPECT_FALSE([controller shouldShowIcon]);
|
| + EXPECT_FALSE([controller shouldShowAudioIndicator]);
|
| + break;
|
| + case 2:
|
| + if ([controller projecting])
|
| + EXPECT_TRUE([controller shouldShowIcon]);
|
| + else
|
| + EXPECT_TRUE([controller shouldShowIcon] !=
|
| + [controller shouldShowAudioIndicator]);
|
| + break;
|
| + default:
|
| + EXPECT_LE(3, [controller iconCapacity]);
|
| + EXPECT_TRUE([controller shouldShowIcon]);
|
| + if ([controller projecting])
|
| + EXPECT_FALSE([controller shouldShowAudioIndicator]);
|
| + else
|
| + EXPECT_TRUE(!![controller audioIndicatorView] ==
|
| + [controller shouldShowAudioIndicator]);
|
| + break;
|
| + }
|
| + } else { // Tab not selected/active and not mini tab.
|
| + switch ([controller iconCapacity]) {
|
| + case 0:
|
| + EXPECT_FALSE([controller shouldShowCloseButton]);
|
| + EXPECT_FALSE([controller shouldShowIcon]);
|
| + EXPECT_FALSE([controller shouldShowAudioIndicator]);
|
| + break;
|
| + case 1:
|
| + EXPECT_FALSE([controller shouldShowCloseButton]);
|
| + if ([controller projecting])
|
| + EXPECT_TRUE([controller shouldShowIcon]);
|
| + else
|
| + EXPECT_TRUE([controller shouldShowIcon] !=
|
| + [controller shouldShowAudioIndicator]);
|
| + break;
|
| + default:
|
| + EXPECT_LE(2, [controller iconCapacity]);
|
| + EXPECT_TRUE([controller shouldShowIcon]);
|
| + if ([controller projecting])
|
| + EXPECT_FALSE([controller shouldShowAudioIndicator]);
|
| + else
|
| + EXPECT_TRUE(!![controller audioIndicatorView] ==
|
| + [controller shouldShowAudioIndicator]);
|
| + break;
|
| + }
|
| + }
|
| +
|
| + // Make sure the NSView's "isHidden" state jives with the "shouldShowXXX."
|
| + EXPECT_TRUE([controller shouldShowIcon] ==
|
| + (!![controller iconView] && ![[controller iconView] isHidden]));
|
| + EXPECT_TRUE([controller mini] == [[controller titleView] isHidden]);
|
| + EXPECT_TRUE([controller shouldShowAudioIndicator] ==
|
| + (!![controller audioIndicatorView] &&
|
| + ![[controller audioIndicatorView] isHidden]));
|
| + EXPECT_TRUE([controller shouldShowCloseButton] !=
|
| + [[controller closeButton] isHidden]);
|
| +
|
| + // Check positioning of elements with respect to each other, and that they
|
| + // are fully within the tab frame.
|
| + const NSRect tabFrame = [[controller view] frame];
|
| + const NSRect titleFrame = [[controller titleView] frame];
|
| + if ([controller shouldShowIcon]) {
|
| + const NSRect iconFrame = [[controller iconView] frame];
|
| + EXPECT_LE(NSMinX(tabFrame), NSMinX(iconFrame));
|
| + if (NSWidth(titleFrame) > 0)
|
| + EXPECT_LE(NSMaxX(iconFrame), NSMinX(titleFrame));
|
| + EXPECT_LE(NSMinY(tabFrame), NSMinY(iconFrame));
|
| + EXPECT_LE(NSMaxY(iconFrame), NSMaxY(tabFrame));
|
| + }
|
| + if ([controller shouldShowIcon] && [controller shouldShowAudioIndicator]) {
|
| + EXPECT_LE(NSMaxX([[controller iconView] frame]),
|
| + NSMinX([[controller audioIndicatorView] frame]));
|
| + }
|
| + if ([controller shouldShowAudioIndicator]) {
|
| + const NSRect audioIndicatorFrame =
|
| + [[controller audioIndicatorView] frame];
|
| + if (NSWidth(titleFrame) > 0)
|
| + EXPECT_LE(NSMaxX(titleFrame), NSMinX(audioIndicatorFrame));
|
| + EXPECT_LE(NSMaxX(audioIndicatorFrame), NSMaxX(tabFrame));
|
| + EXPECT_LE(NSMinY(tabFrame), NSMinY(audioIndicatorFrame));
|
| + EXPECT_LE(NSMaxY(audioIndicatorFrame), NSMaxY(tabFrame));
|
| + }
|
| + if ([controller shouldShowAudioIndicator] &&
|
| + [controller shouldShowCloseButton]) {
|
| + EXPECT_LE(NSMaxX([[controller audioIndicatorView] frame]),
|
| + NSMinX([[controller closeButton] frame]));
|
| + }
|
| + if ([controller shouldShowCloseButton]) {
|
| + const NSRect closeButtonFrame = [[controller closeButton] frame];
|
| + if (NSWidth(titleFrame) > 0)
|
| + EXPECT_LE(NSMaxX(titleFrame), NSMinX(closeButtonFrame));
|
| + EXPECT_LE(NSMaxX(closeButtonFrame), NSMaxX(tabFrame));
|
| + EXPECT_LE(NSMinY(tabFrame), NSMinY(closeButtonFrame));
|
| + EXPECT_LE(NSMaxY(closeButtonFrame), NSMaxY(tabFrame));
|
| + }
|
| + }
|
| };
|
|
|
| // Tests creating the controller, sticking it in a window, and removing it.
|
| @@ -355,4 +484,73 @@ TEST_F(TabControllerTest, TitleViewLayout) {
|
| [[controller titleView] frame]));
|
| }
|
|
|
| +// A comprehensive test of the layout and visibility of all elements (favicon,
|
| +// throbber indicators, titile text, audio indicator, and close button) over all
|
| +// relevant combinations of tab state. This test overlaps with parts of the
|
| +// other tests above.
|
| +TEST_F(TabControllerTest, LayoutAndVisibilityOfSubviews) {
|
| + NSWindow* const window = test_window();
|
| +
|
| + // Create TabController instance and place its view into the test window.
|
| + base::scoped_nsobject<TabController> controller([[TabController alloc] init]);
|
| + [[window contentView] addSubview:[controller view]];
|
| +
|
| + // Create favicon and audio indicator icon views.
|
| + base::scoped_nsobject<NSImageView> faviconView(
|
| + CreateImageViewFromResourceBundle(IDR_DEFAULT_FAVICON));
|
| + base::scoped_nsobject<NSImageView> audioIndicatorView(
|
| + CreateImageViewFromResourceBundle(IDR_TAB_AUDIO_INDICATOR));
|
| +
|
| + [controller setIconView:faviconView];
|
| +
|
| + // Perform layout over all possible combinations, checking for correct
|
| + // results.
|
| + for (int is_mini_tab = 0; is_mini_tab < 2; ++is_mini_tab) {
|
| + for (int is_active_tab = 0; is_active_tab < 2; ++is_active_tab) {
|
| + for (int is_audio_playing = 0; is_audio_playing < 2; ++is_audio_playing) {
|
| + for (int is_capturing = 0; is_capturing < 2; ++is_capturing) {
|
| + SCOPED_TRACE(::testing::Message()
|
| + << (is_active_tab ? "Active" : "Inactive") << ' '
|
| + << (is_mini_tab ? "Mini " : "")
|
| + << "Tab with is_audio_playing=" << !!is_audio_playing
|
| + << " and is_capturing=" << !!is_capturing);
|
| +
|
| + // Simulate what tab_strip_controller would do to set up the
|
| + // TabController state.
|
| + [controller setMini:(is_mini_tab ? YES : NO)];
|
| + [controller setActive:(is_active_tab ? YES : NO)];
|
| + if (is_capturing) {
|
| + [controller setProjecting:YES];
|
| + [controller setAudioIndicatorView:nil];
|
| + } else {
|
| + [controller setProjecting:NO];
|
| + if (is_audio_playing)
|
| + [controller setAudioIndicatorView:audioIndicatorView];
|
| + else
|
| + [controller setAudioIndicatorView:nil];
|
| + }
|
| +
|
| + // Test layout for every width from maximum to minimum.
|
| + NSRect tabFrame = [[controller view] frame];
|
| + int min_width;
|
| + if (is_mini_tab) {
|
| + tabFrame.size.width = min_width = [TabController miniTabWidth];
|
| + } else {
|
| + tabFrame.size.width = [TabController maxTabWidth];
|
| + min_width = is_active_tab ? [TabController minSelectedTabWidth] :
|
| + [TabController minTabWidth];
|
| + }
|
| + while (NSWidth(tabFrame) >= min_width) {
|
| + SCOPED_TRACE(::testing::Message()
|
| + << "width=" << tabFrame.size.width);
|
| + [[controller view] setFrame:tabFrame];
|
| + CheckForExpectedLayoutAndVisibilityOfSubviews(controller);
|
| + --tabFrame.size.width;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| } // namespace
|
|
|