Home | History | Annotate | Download | only in cocoa
      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
      3 // found in the LICENSE file.
      4 
      5 #include <Cocoa/Cocoa.h>
      6 
      7 #include "base/memory/scoped_nsobject.h"
      8 #include "base/memory/scoped_ptr.h"
      9 #include "base/utf_string_conversions.h"
     10 #import "chrome/browser/ui/cocoa/bubble_view.h"
     11 #import "chrome/browser/ui/cocoa/browser_test_helper.h"
     12 #import "chrome/browser/ui/cocoa/cocoa_test_helper.h"
     13 #import "chrome/browser/ui/cocoa/status_bubble_mac.h"
     14 #include "googleurl/src/gurl.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 #import "testing/gtest_mac.h"
     17 #include "testing/platform_test.h"
     18 
     19 // The test delegate records all of the status bubble object's state
     20 // transitions.
     21 @interface StatusBubbleMacTestDelegate : NSObject {
     22  @private
     23   NSWindow* window_;  // Weak.
     24   NSPoint baseFrameOffset_;
     25   std::vector<StatusBubbleMac::StatusBubbleState> states_;
     26 }
     27 - (id)initWithWindow:(NSWindow*)window;
     28 - (void)forceBaseFrameOffset:(NSPoint)baseFrameOffset;
     29 - (NSRect)statusBubbleBaseFrame;
     30 - (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state;
     31 @end
     32 @implementation StatusBubbleMacTestDelegate
     33 - (id)initWithWindow:(NSWindow*)window {
     34   if ((self = [super init])) {
     35     window_ = window;
     36     baseFrameOffset_ = NSMakePoint(0, 0);
     37   }
     38   return self;
     39 }
     40 - (void)forceBaseFrameOffset:(NSPoint)baseFrameOffset {
     41   baseFrameOffset_ = baseFrameOffset;
     42 }
     43 - (NSRect)statusBubbleBaseFrame {
     44   NSView* contentView = [window_ contentView];
     45   NSRect baseFrame = [contentView convertRect:[contentView frame] toView:nil];
     46   if (baseFrameOffset_.x > 0 || baseFrameOffset_.y > 0) {
     47     baseFrame = NSOffsetRect(baseFrame, baseFrameOffset_.x, baseFrameOffset_.y);
     48     baseFrame.size.width -= baseFrameOffset_.x;
     49     baseFrame.size.height -= baseFrameOffset_.y;
     50   }
     51   return baseFrame;
     52 }
     53 - (void)statusBubbleWillEnterState:(StatusBubbleMac::StatusBubbleState)state {
     54   states_.push_back(state);
     55 }
     56 - (std::vector<StatusBubbleMac::StatusBubbleState>*)states {
     57   return &states_;
     58 }
     59 @end
     60 
     61 // This class implements, for testing purposes, a subclass of |StatusBubbleMac|
     62 // whose |MouseMoved()| method does nothing. (Ideally, we'd have a way of
     63 // controlling the "mouse" location, but the current implementation of
     64 // |StatusBubbleMac| uses |[NSEvent mouseLocation]| directly.) Without this,
     65 // tests can be flaky since results may depend on the mouse location.
     66 class StatusBubbleMacIgnoreMouseMoved : public StatusBubbleMac {
     67  public:
     68   StatusBubbleMacIgnoreMouseMoved(NSWindow* parent, id delegate)
     69       : StatusBubbleMac(parent, delegate) {}
     70 
     71   virtual void MouseMoved(const gfx::Point& location, bool left_content) {}
     72 };
     73 
     74 class StatusBubbleMacTest : public CocoaTest {
     75  public:
     76   virtual void SetUp() {
     77     CocoaTest::SetUp();
     78     NSWindow* window = test_window();
     79     EXPECT_TRUE(window);
     80     delegate_.reset(
     81         [[StatusBubbleMacTestDelegate alloc] initWithWindow: window]);
     82     EXPECT_TRUE(delegate_.get());
     83     bubble_ = new StatusBubbleMacIgnoreMouseMoved(window, delegate_);
     84     EXPECT_TRUE(bubble_);
     85 
     86     // Turn off delays and transitions for test mode.  This doesn't just speed
     87     // things along, it's actually required to get StatusBubbleMac to behave
     88     // synchronously, because the tests here don't know how to wait for
     89     // results.  This allows these tests to be much more complete with a
     90     // minimal loss of coverage and without any heinous rearchitecting.
     91     bubble_->immediate_ = true;
     92 
     93     EXPECT_TRUE(bubble_->window_);  // immediately creates window
     94   }
     95 
     96   virtual void TearDown() {
     97     // Not using a scoped_ptr because bubble must be deleted before calling
     98     // TearDown to get rid of bubble's window.
     99     delete bubble_;
    100     CocoaTest::TearDown();
    101   }
    102 
    103   bool IsVisible() {
    104     if (![bubble_->window_ isVisible])
    105       return false;
    106     return [bubble_->window_ alphaValue] > 0.0;
    107   }
    108   NSString* GetText() {
    109     return bubble_->status_text_;
    110   }
    111   NSString* GetURLText() {
    112     return bubble_->url_text_;
    113   }
    114   NSString* GetBubbleViewText() {
    115     BubbleView* bubbleView = [bubble_->window_ contentView];
    116     return [bubbleView content];
    117   }
    118   NSWindow* GetWindow() {
    119     return bubble_->window_;
    120   }
    121   NSWindow* parent() {
    122     return bubble_->parent_;
    123   }
    124   StatusBubbleMac::StatusBubbleState GetState() {
    125     return bubble_->state_;
    126   }
    127   void SetState(StatusBubbleMac::StatusBubbleState state) {
    128     bubble_->SetState(state);
    129   }
    130   std::vector<StatusBubbleMac::StatusBubbleState>* States() {
    131     return [delegate_ states];
    132   }
    133   StatusBubbleMac::StatusBubbleState StateAt(int index) {
    134     return (*States())[index];
    135   }
    136   BrowserTestHelper browser_helper_;
    137   scoped_nsobject<StatusBubbleMacTestDelegate> delegate_;
    138   StatusBubbleMac* bubble_;  // Strong.
    139 };
    140 
    141 TEST_F(StatusBubbleMacTest, SetStatus) {
    142   bubble_->SetStatus(string16());
    143   bubble_->SetStatus(UTF8ToUTF16("This is a test"));
    144   EXPECT_NSEQ(@"This is a test", GetText());
    145   EXPECT_TRUE(IsVisible());
    146 
    147   // Set the status to the exact same thing again
    148   bubble_->SetStatus(UTF8ToUTF16("This is a test"));
    149   EXPECT_NSEQ(@"This is a test", GetText());
    150 
    151   // Hide it
    152   bubble_->SetStatus(string16());
    153   EXPECT_FALSE(IsVisible());
    154 }
    155 
    156 TEST_F(StatusBubbleMacTest, SetURL) {
    157   bubble_->SetURL(GURL(), string16());
    158   EXPECT_FALSE(IsVisible());
    159   bubble_->SetURL(GURL("bad url"), string16());
    160   EXPECT_FALSE(IsVisible());
    161   bubble_->SetURL(GURL("http://"), string16());
    162   EXPECT_TRUE(IsVisible());
    163   EXPECT_NSEQ(@"http:", GetURLText());
    164   bubble_->SetURL(GURL("about:blank"), string16());
    165   EXPECT_TRUE(IsVisible());
    166   EXPECT_NSEQ(@"about:blank", GetURLText());
    167   bubble_->SetURL(GURL("foopy://"), string16());
    168   EXPECT_TRUE(IsVisible());
    169   EXPECT_NSEQ(@"foopy://", GetURLText());
    170   bubble_->SetURL(GURL("http://www.cnn.com"), string16());
    171   EXPECT_TRUE(IsVisible());
    172   EXPECT_NSEQ(@"www.cnn.com", GetURLText());
    173 }
    174 
    175 // Test hiding bubble that's already hidden.
    176 TEST_F(StatusBubbleMacTest, Hides) {
    177   bubble_->SetStatus(UTF8ToUTF16("Showing"));
    178   EXPECT_TRUE(IsVisible());
    179   bubble_->Hide();
    180   EXPECT_FALSE(IsVisible());
    181   bubble_->Hide();
    182   EXPECT_FALSE(IsVisible());
    183 }
    184 
    185 // Test the "main"/"backup" behavior in StatusBubbleMac::SetText().
    186 TEST_F(StatusBubbleMacTest, SetStatusAndURL) {
    187   EXPECT_FALSE(IsVisible());
    188   bubble_->SetStatus(UTF8ToUTF16("Status"));
    189   EXPECT_TRUE(IsVisible());
    190   EXPECT_NSEQ(@"Status", GetBubbleViewText());
    191   bubble_->SetURL(GURL("http://www.nytimes.com"), string16());
    192   EXPECT_TRUE(IsVisible());
    193   EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
    194   bubble_->SetURL(GURL(), string16());
    195   EXPECT_TRUE(IsVisible());
    196   EXPECT_NSEQ(@"Status", GetBubbleViewText());
    197   bubble_->SetStatus(string16());
    198   EXPECT_FALSE(IsVisible());
    199   bubble_->SetURL(GURL("http://www.nytimes.com"), string16());
    200   EXPECT_TRUE(IsVisible());
    201   EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
    202   bubble_->SetStatus(UTF8ToUTF16("Status"));
    203   EXPECT_TRUE(IsVisible());
    204   EXPECT_NSEQ(@"Status", GetBubbleViewText());
    205   bubble_->SetStatus(string16());
    206   EXPECT_TRUE(IsVisible());
    207   EXPECT_NSEQ(@"www.nytimes.com", GetBubbleViewText());
    208   bubble_->SetURL(GURL(), string16());
    209   EXPECT_FALSE(IsVisible());
    210 }
    211 
    212 // Test that the status bubble goes through the correct delay and fade states.
    213 // The delay and fade duration are simulated and not actually experienced
    214 // during the test because StatusBubbleMacTest sets immediate_ mode.
    215 TEST_F(StatusBubbleMacTest, StateTransitions) {
    216   // First, some sanity
    217 
    218   EXPECT_FALSE(IsVisible());
    219   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
    220 
    221   States()->clear();
    222   EXPECT_TRUE(States()->empty());
    223 
    224   bubble_->SetStatus(string16());
    225   EXPECT_FALSE(IsVisible());
    226   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
    227   EXPECT_TRUE(States()->empty());  // no change from initial kBubbleHidden state
    228 
    229   // Next, a few ordinary cases
    230 
    231   // Test StartShowing from kBubbleHidden
    232   bubble_->SetStatus(UTF8ToUTF16("Status"));
    233   EXPECT_TRUE(IsVisible());
    234   // Check GetState before checking States to make sure that all state
    235   // transitions have been flushed to States.
    236   EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
    237   EXPECT_EQ(3u, States()->size());
    238   EXPECT_EQ(StatusBubbleMac::kBubbleShowingTimer, StateAt(0));
    239   EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(1));
    240   EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(2));
    241 
    242   // Test StartShowing from kBubbleShown with the same message
    243   States()->clear();
    244   bubble_->SetStatus(UTF8ToUTF16("Status"));
    245   EXPECT_TRUE(IsVisible());
    246   EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
    247   EXPECT_TRUE(States()->empty());
    248 
    249   // Test StartShowing from kBubbleShown with a different message
    250   bubble_->SetStatus(UTF8ToUTF16("New Status"));
    251   EXPECT_TRUE(IsVisible());
    252   EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
    253   EXPECT_TRUE(States()->empty());
    254 
    255   // Test StartHiding from kBubbleShown
    256   bubble_->SetStatus(string16());
    257   EXPECT_FALSE(IsVisible());
    258   // Check GetState before checking States to make sure that all state
    259   // transitions have been flushed to States.
    260   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
    261   EXPECT_EQ(3u, States()->size());
    262   EXPECT_EQ(StatusBubbleMac::kBubbleHidingTimer, StateAt(0));
    263   EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(1));
    264   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(2));
    265 
    266   // Test StartHiding from kBubbleHidden
    267   States()->clear();
    268   bubble_->SetStatus(string16());
    269   EXPECT_FALSE(IsVisible());
    270   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
    271   EXPECT_TRUE(States()->empty());
    272 
    273   // Now, the edge cases
    274 
    275   // Test StartShowing from kBubbleShowingTimer
    276   bubble_->SetStatus(UTF8ToUTF16("Status"));
    277   SetState(StatusBubbleMac::kBubbleShowingTimer);
    278   [GetWindow() setAlphaValue:0.0];
    279   States()->clear();
    280   EXPECT_TRUE(States()->empty());
    281   bubble_->SetStatus(UTF8ToUTF16("Status"));
    282   EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
    283   EXPECT_EQ(2u, States()->size());
    284   EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(0));
    285   EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(1));
    286 
    287   // Test StartShowing from kBubbleShowingFadeIn
    288   bubble_->SetStatus(UTF8ToUTF16("Status"));
    289   SetState(StatusBubbleMac::kBubbleShowingFadeIn);
    290   [GetWindow() setAlphaValue:0.5];
    291   States()->clear();
    292   EXPECT_TRUE(States()->empty());
    293   bubble_->SetStatus(UTF8ToUTF16("Status"));
    294   // The actual state values can't be tested in immediate_ mode because
    295   // the window wasn't actually fading in.  Without immediate_ mode,
    296   // expect kBubbleShown.
    297   bubble_->SetStatus(string16());  // Go back to a deterministic state.
    298 
    299   // Test StartShowing from kBubbleHidingTimer
    300   bubble_->SetStatus(string16());
    301   SetState(StatusBubbleMac::kBubbleHidingTimer);
    302   [GetWindow() setAlphaValue:1.0];
    303   States()->clear();
    304   EXPECT_TRUE(States()->empty());
    305   bubble_->SetStatus(UTF8ToUTF16("Status"));
    306   EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
    307   EXPECT_EQ(1u, States()->size());
    308   EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(0));
    309 
    310   // Test StartShowing from kBubbleHidingFadeOut
    311   bubble_->SetStatus(string16());
    312   SetState(StatusBubbleMac::kBubbleHidingFadeOut);
    313   [GetWindow() setAlphaValue:0.5];
    314   States()->clear();
    315   EXPECT_TRUE(States()->empty());
    316   bubble_->SetStatus(UTF8ToUTF16("Status"));
    317   EXPECT_EQ(StatusBubbleMac::kBubbleShown, GetState());
    318   EXPECT_EQ(2u, States()->size());
    319   EXPECT_EQ(StatusBubbleMac::kBubbleShowingFadeIn, StateAt(0));
    320   EXPECT_EQ(StatusBubbleMac::kBubbleShown, StateAt(1));
    321 
    322   // Test StartHiding from kBubbleShowingTimer
    323   bubble_->SetStatus(UTF8ToUTF16("Status"));
    324   SetState(StatusBubbleMac::kBubbleShowingTimer);
    325   [GetWindow() setAlphaValue:0.0];
    326   States()->clear();
    327   EXPECT_TRUE(States()->empty());
    328   bubble_->SetStatus(string16());
    329   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
    330   EXPECT_EQ(1u, States()->size());
    331   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
    332 
    333   // Test StartHiding from kBubbleShowingFadeIn
    334   bubble_->SetStatus(UTF8ToUTF16("Status"));
    335   SetState(StatusBubbleMac::kBubbleShowingFadeIn);
    336   [GetWindow() setAlphaValue:0.5];
    337   States()->clear();
    338   EXPECT_TRUE(States()->empty());
    339   bubble_->SetStatus(string16());
    340   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
    341   EXPECT_EQ(2u, States()->size());
    342   EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(0));
    343   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(1));
    344 
    345   // Test StartHiding from kBubbleHidingTimer
    346   bubble_->SetStatus(string16());
    347   SetState(StatusBubbleMac::kBubbleHidingTimer);
    348   [GetWindow() setAlphaValue:1.0];
    349   States()->clear();
    350   EXPECT_TRUE(States()->empty());
    351   bubble_->SetStatus(string16());
    352   // The actual state values can't be tested in immediate_ mode because
    353   // the timer wasn't actually running.  Without immediate_ mode, expect
    354   // kBubbleHidingFadeOut and kBubbleHidden.
    355   // Go back to a deterministic state.
    356   bubble_->SetStatus(UTF8ToUTF16("Status"));
    357 
    358   // Test StartHiding from kBubbleHidingFadeOut
    359   bubble_->SetStatus(string16());
    360   SetState(StatusBubbleMac::kBubbleHidingFadeOut);
    361   [GetWindow() setAlphaValue:0.5];
    362   States()->clear();
    363   EXPECT_TRUE(States()->empty());
    364   bubble_->SetStatus(string16());
    365   // The actual state values can't be tested in immediate_ mode because
    366   // the window wasn't actually fading out.  Without immediate_ mode, expect
    367   // kBubbleHidden.
    368   // Go back to a deterministic state.
    369   bubble_->SetStatus(UTF8ToUTF16("Status"));
    370 
    371   // Test Hide from kBubbleHidden
    372   bubble_->SetStatus(string16());
    373   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
    374   States()->clear();
    375   EXPECT_TRUE(States()->empty());
    376   bubble_->Hide();
    377   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
    378   EXPECT_TRUE(States()->empty());
    379 
    380   // Test Hide from kBubbleShowingTimer
    381   bubble_->SetStatus(UTF8ToUTF16("Status"));
    382   SetState(StatusBubbleMac::kBubbleShowingTimer);
    383   [GetWindow() setAlphaValue:0.0];
    384   States()->clear();
    385   EXPECT_TRUE(States()->empty());
    386   bubble_->Hide();
    387   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
    388   EXPECT_EQ(1u, States()->size());
    389   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
    390 
    391   // Test Hide from kBubbleShowingFadeIn
    392   bubble_->SetStatus(UTF8ToUTF16("Status"));
    393   SetState(StatusBubbleMac::kBubbleShowingFadeIn);
    394   [GetWindow() setAlphaValue:0.5];
    395   States()->clear();
    396   EXPECT_TRUE(States()->empty());
    397   bubble_->Hide();
    398   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
    399   EXPECT_EQ(2u, States()->size());
    400   EXPECT_EQ(StatusBubbleMac::kBubbleHidingFadeOut, StateAt(0));
    401   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(1));
    402 
    403   // Test Hide from kBubbleShown
    404   bubble_->SetStatus(UTF8ToUTF16("Status"));
    405   States()->clear();
    406   EXPECT_TRUE(States()->empty());
    407   bubble_->Hide();
    408   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
    409   EXPECT_EQ(1u, States()->size());
    410   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
    411 
    412   // Test Hide from kBubbleHidingTimer
    413   bubble_->SetStatus(UTF8ToUTF16("Status"));
    414   SetState(StatusBubbleMac::kBubbleHidingTimer);
    415   States()->clear();
    416   EXPECT_TRUE(States()->empty());
    417   bubble_->Hide();
    418   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
    419   EXPECT_EQ(1u, States()->size());
    420   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
    421 
    422   // Test Hide from kBubbleHidingFadeOut
    423   bubble_->SetStatus(UTF8ToUTF16("Status"));
    424   SetState(StatusBubbleMac::kBubbleHidingFadeOut);
    425   [GetWindow() setAlphaValue:0.5];
    426   States()->clear();
    427   EXPECT_TRUE(States()->empty());
    428   bubble_->Hide();
    429   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, GetState());
    430   EXPECT_EQ(1u, States()->size());
    431   EXPECT_EQ(StatusBubbleMac::kBubbleHidden, StateAt(0));
    432 }
    433 
    434 TEST_F(StatusBubbleMacTest, Delete) {
    435   NSWindow* window = test_window();
    436   // Create and delete immediately.
    437   StatusBubbleMac* bubble = new StatusBubbleMac(window, nil);
    438   delete bubble;
    439 
    440   // Create then delete while visible.
    441   bubble = new StatusBubbleMac(window, nil);
    442   bubble->SetStatus(UTF8ToUTF16("showing"));
    443   delete bubble;
    444 }
    445 
    446 TEST_F(StatusBubbleMacTest, UpdateSizeAndPosition) {
    447   // Test |UpdateSizeAndPosition()| when status bubble does not exist (shouldn't
    448   // crash; shouldn't create window).
    449   EXPECT_TRUE(GetWindow());
    450   bubble_->UpdateSizeAndPosition();
    451   EXPECT_TRUE(GetWindow());
    452 
    453   // Create a status bubble (with contents) and call resize (without actually
    454   // resizing); the frame size shouldn't change.
    455   bubble_->SetStatus(UTF8ToUTF16("UpdateSizeAndPosition test"));
    456   ASSERT_TRUE(GetWindow());
    457   NSRect rect_before = [GetWindow() frame];
    458   bubble_->UpdateSizeAndPosition();
    459   NSRect rect_after = [GetWindow() frame];
    460   EXPECT_TRUE(NSEqualRects(rect_before, rect_after));
    461 
    462   // Move the window and call resize; only the origin should change.
    463   NSWindow* window = test_window();
    464   ASSERT_TRUE(window);
    465   NSRect frame = [window frame];
    466   rect_before = [GetWindow() frame];
    467   frame.origin.x += 10.0;  // (fairly arbitrary nonzero value)
    468   frame.origin.y += 10.0;  // (fairly arbitrary nonzero value)
    469   [window setFrame:frame display:YES];
    470   bubble_->UpdateSizeAndPosition();
    471   rect_after = [GetWindow() frame];
    472   EXPECT_NE(rect_before.origin.x, rect_after.origin.x);
    473   EXPECT_NE(rect_before.origin.y, rect_after.origin.y);
    474   EXPECT_EQ(rect_before.size.width, rect_after.size.width);
    475   EXPECT_EQ(rect_before.size.height, rect_after.size.height);
    476 
    477   // Resize the window (without moving). The origin shouldn't change. The width
    478   // should change (in the current implementation), but not the height.
    479   frame = [window frame];
    480   rect_before = [GetWindow() frame];
    481   frame.size.width += 50.0;   // (fairly arbitrary nonzero value)
    482   frame.size.height += 50.0;  // (fairly arbitrary nonzero value)
    483   [window setFrame:frame display:YES];
    484   bubble_->UpdateSizeAndPosition();
    485   rect_after = [GetWindow() frame];
    486   EXPECT_EQ(rect_before.origin.x, rect_after.origin.x);
    487   EXPECT_EQ(rect_before.origin.y, rect_after.origin.y);
    488   EXPECT_NE(rect_before.size.width, rect_after.size.width);
    489   EXPECT_EQ(rect_before.size.height, rect_after.size.height);
    490 }
    491 
    492 TEST_F(StatusBubbleMacTest, MovingWindowUpdatesPosition) {
    493   NSWindow* window = test_window();
    494 
    495   // Show the bubble and make sure it has the same origin as |window|.
    496   bubble_->SetStatus(UTF8ToUTF16("Showing"));
    497   NSWindow* child = GetWindow();
    498   EXPECT_TRUE(NSEqualPoints([window frame].origin, [child frame].origin));
    499 
    500   // Hide the bubble, move the window, and show it again.
    501   bubble_->Hide();
    502   NSRect frame = [window frame];
    503   frame.origin.x += 50;
    504   [window setFrame:frame display:YES];
    505   bubble_->SetStatus(UTF8ToUTF16("Reshowing"));
    506 
    507   // The bubble should reattach in the correct location.
    508   child = GetWindow();
    509   EXPECT_TRUE(NSEqualPoints([window frame].origin, [child frame].origin));
    510 }
    511 
    512 TEST_F(StatusBubbleMacTest, StatuBubbleRespectsBaseFrameLimits) {
    513   NSWindow* window = test_window();
    514 
    515   // Show the bubble and make sure it has the same origin as |window|.
    516   bubble_->SetStatus(UTF8ToUTF16("Showing"));
    517   NSWindow* child = GetWindow();
    518   EXPECT_TRUE(NSEqualPoints([window frame].origin, [child frame].origin));
    519 
    520   // Hide the bubble, change base frame offset, and show it again.
    521   bubble_->Hide();
    522 
    523   NSPoint baseFrameOffset = NSMakePoint(0, [window frame].size.height / 3);
    524   EXPECT_GT(baseFrameOffset.y, 0);
    525   [delegate_ forceBaseFrameOffset:baseFrameOffset];
    526 
    527   bubble_->SetStatus(UTF8ToUTF16("Reshowing"));
    528 
    529   // The bubble should reattach in the correct location.
    530   child = GetWindow();
    531   NSPoint expectedOrigin = [window frame].origin;
    532   expectedOrigin.x += baseFrameOffset.x;
    533   expectedOrigin.y += baseFrameOffset.y;
    534   EXPECT_TRUE(NSEqualPoints(expectedOrigin, [child frame].origin));
    535 }
    536 
    537 TEST_F(StatusBubbleMacTest, ExpandBubble) {
    538   NSWindow* window = test_window();
    539   ASSERT_TRUE(window);
    540   NSRect window_frame = [window frame];
    541   window_frame.size.width = 600.0;
    542   [window setFrame:window_frame display:YES];
    543 
    544   // Check basic expansion
    545   bubble_->SetStatus(UTF8ToUTF16("Showing"));
    546   EXPECT_TRUE(IsVisible());
    547   bubble_->SetURL(GURL("http://www.battersbox.com/peter_paul_and_mary.html"),
    548                   string16());
    549   EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
    550   bubble_->ExpandBubble();
    551   EXPECT_TRUE(IsVisible());
    552   EXPECT_NSEQ(@"www.battersbox.com/peter_paul_and_mary.html", GetURLText());
    553   bubble_->Hide();
    554 
    555   // Make sure bubble resets after hide.
    556   bubble_->SetStatus(UTF8ToUTF16("Showing"));
    557   bubble_->SetURL(GURL("http://www.snickersnee.com/pioneer_fishstix.html"),
    558                   string16());
    559   EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
    560   // ...and that it expands again properly.
    561   bubble_->ExpandBubble();
    562   EXPECT_NSEQ(@"www.snickersnee.com/pioneer_fishstix.html", GetURLText());
    563   // ...again, again!
    564   bubble_->SetURL(GURL("http://www.battersbox.com/peter_paul_and_mary.html"),
    565                   string16());
    566   bubble_->ExpandBubble();
    567   EXPECT_NSEQ(@"www.battersbox.com/peter_paul_and_mary.html", GetURLText());
    568   bubble_->Hide();
    569 
    570   window_frame = [window frame];
    571   window_frame.size.width = 300.0;
    572   [window setFrame:window_frame display:YES];
    573 
    574   // Very long URL's will be cut off even in the expanded state.
    575   bubble_->SetStatus(UTF8ToUTF16("Showing"));
    576   const char veryLongUrl[] =
    577       "http://www.diewahrscheinlichlaengstepralinederwelt.com/duuuuplo.html";
    578   bubble_->SetURL(GURL(veryLongUrl), string16());
    579   EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
    580   bubble_->ExpandBubble();
    581   EXPECT_TRUE([GetURLText() hasSuffix:@"\u2026"]);
    582 }
    583 
    584 
    585