| 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
 | 
| 
 |