status_bubble_mac_unittest.mm revision dc0f95d653279beabeb9817299e2902918ba123e
1// Copyright (c) 2010 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/scoped_nsobject.h"
8#include "base/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.
66class 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
74class 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* GetParent() {
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
141TEST_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
156TEST_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.
176TEST_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().
186TEST_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.
215TEST_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
434TEST_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
446TEST_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
492TEST_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
512TEST_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
537TEST_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