Get foreground tab on Android
[chromium-blink-merge.git] / ui / message_center / cocoa / popup_collection_unittest.mm
blob3ec7c3318f23ba2adc8b1c0dd7ea1b437748559f
1 // Copyright (c) 2013 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.
5 #import "ui/message_center/cocoa/popup_collection.h"
7 #include "base/mac/scoped_nsobject.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/message_loop/message_loop.h"
10 #include "base/run_loop.h"
11 #include "base/strings/sys_string_conversions.h"
12 #include "base/strings/utf_string_conversions.h"
13 #import "ui/base/test/ui_cocoa_test_helper.h"
14 #import "ui/message_center/cocoa/notification_controller.h"
15 #import "ui/message_center/cocoa/popup_controller.h"
16 #include "ui/message_center/message_center.h"
17 #include "ui/message_center/message_center_style.h"
18 #include "ui/message_center/notification.h"
20 class PopupCollectionTest : public ui::CocoaTest {
21  public:
22   PopupCollectionTest()
23     : message_loop_(base::MessageLoop::TYPE_UI) {
24     message_center::MessageCenter::Initialize();
25     center_ = message_center::MessageCenter::Get();
26     collection_.reset(
27         [[MCPopupCollection alloc] initWithMessageCenter:center_]);
28     [collection_ setAnimationDuration:0.001];
29     [collection_ setAnimationEndedCallback:^{
30         if (nested_run_loop_.get())
31           nested_run_loop_->Quit();
32     }];
33   }
35   virtual void TearDown() OVERRIDE {
36     collection_.reset();  // Close all popups.
37     ui::CocoaTest::TearDown();
38   }
40   virtual ~PopupCollectionTest() {
41     message_center::MessageCenter::Shutdown();
42   }
44   void AddThreeNotifications() {
45     scoped_ptr<message_center::Notification> notification;
46     notification.reset(new message_center::Notification(
47         message_center::NOTIFICATION_TYPE_SIMPLE,
48         "1",
49         ASCIIToUTF16("One"),
50         ASCIIToUTF16("This is the first notification to"
51                      " be displayed"),
52         gfx::Image(),
53         string16(),
54         message_center::NotifierId(),
55         message_center::RichNotificationData(),
56         NULL));
57     center_->AddNotification(notification.Pass());
59     notification.reset(new message_center::Notification(
60         message_center::NOTIFICATION_TYPE_SIMPLE,
61         "2",
62         ASCIIToUTF16("Two"),
63         ASCIIToUTF16("This is the second notification."),
64         gfx::Image(),
65         string16(),
66         message_center::NotifierId(),
67         message_center::RichNotificationData(),
68         NULL));
69     center_->AddNotification(notification.Pass());
71     notification.reset(new message_center::Notification(
72         message_center::NOTIFICATION_TYPE_SIMPLE,
73         "3",
74         ASCIIToUTF16("Three"),
75         ASCIIToUTF16("This is the third notification "
76                      "that has a much longer body "
77                      "than the other notifications. It "
78                      "may not fit on the screen if we "
79                      "set the screen size too small or "
80                      "if the notification is way too big"),
81         gfx::Image(),
82         string16(),
83         message_center::NotifierId(),
84         message_center::RichNotificationData(),
85         NULL));
86     center_->AddNotification(notification.Pass());
87     WaitForAnimationEnded();
88   }
90   bool CheckSpacingBetween(MCPopupController* upper, MCPopupController* lower) {
91     CGFloat minY = NSMinY([[upper window] frame]);
92     CGFloat maxY = NSMaxY([[lower window] frame]);
93     CGFloat delta = minY - maxY;
94     EXPECT_EQ(message_center::kMarginBetweenItems, delta);
95     return delta == message_center::kMarginBetweenItems;
96   }
98   void WaitForAnimationEnded() {
99     if (![collection_ isAnimating])
100       return;
101     nested_run_loop_.reset(new base::RunLoop());
102     nested_run_loop_->Run();
103     nested_run_loop_.reset();
104   }
106   base::MessageLoop message_loop_;
107   scoped_ptr<base::RunLoop> nested_run_loop_;
108   message_center::MessageCenter* center_;
109   base::scoped_nsobject<MCPopupCollection> collection_;
112 TEST_F(PopupCollectionTest, AddThreeCloseOne) {
113   EXPECT_EQ(0u, [[collection_ popups] count]);
114   AddThreeNotifications();
115   EXPECT_EQ(3u, [[collection_ popups] count]);
117   center_->RemoveNotification("2", true);
118   WaitForAnimationEnded();
119   EXPECT_EQ(2u, [[collection_ popups] count]);
122 TEST_F(PopupCollectionTest, AttemptFourOneOffscreen) {
123   [collection_ setScreenFrame:NSMakeRect(0, 0, 800, 300)];
125   EXPECT_EQ(0u, [[collection_ popups] count]);
126   AddThreeNotifications();
127   EXPECT_EQ(2u, [[collection_ popups] count]);  // "3" does not fit on screen.
129   scoped_ptr<message_center::Notification> notification;
131   notification.reset(new message_center::Notification(
132       message_center::NOTIFICATION_TYPE_SIMPLE,
133       "4",
134       ASCIIToUTF16("Four"),
135       ASCIIToUTF16("This is the fourth notification."),
136       gfx::Image(),
137       string16(),
138       message_center::NotifierId(),
139       message_center::RichNotificationData(),
140       NULL));
141   center_->AddNotification(notification.Pass());
142   WaitForAnimationEnded();
144   // Remove "1" and "3" should fit on screen.
145   center_->RemoveNotification("1", true);
146   WaitForAnimationEnded();
147   ASSERT_EQ(2u, [[collection_ popups] count]);
149   EXPECT_EQ("2", [[[collection_ popups] objectAtIndex:0] notificationID]);
150   EXPECT_EQ("3", [[[collection_ popups] objectAtIndex:1] notificationID]);
152   // Remove "2" and "4" should fit on screen.
153   center_->RemoveNotification("2", true);
154   WaitForAnimationEnded();
155   ASSERT_EQ(2u, [[collection_ popups] count]);
157   EXPECT_EQ("3", [[[collection_ popups] objectAtIndex:0] notificationID]);
158   EXPECT_EQ("4", [[[collection_ popups] objectAtIndex:1] notificationID]);
161 TEST_F(PopupCollectionTest, LayoutSpacing) {
162   const CGFloat kScreenSize = 500;
163   [collection_ setScreenFrame:NSMakeRect(0, 0, kScreenSize, kScreenSize)];
165   AddThreeNotifications();
166   NSArray* popups = [collection_ popups];
168   EXPECT_EQ(message_center::kMarginBetweenItems,
169             kScreenSize - NSMaxY([[[popups objectAtIndex:0] window] frame]));
171   EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:0],
172                                   [popups objectAtIndex:1]));
173   EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:1],
174                                   [popups objectAtIndex:2]));
176   // Set priority so that kMaxVisiblePopupNotifications does not hide it.
177   message_center::RichNotificationData optional;
178   optional.priority = message_center::HIGH_PRIORITY;
179   scoped_ptr<message_center::Notification> notification;
180   notification.reset(new message_center::Notification(
181       message_center::NOTIFICATION_TYPE_SIMPLE,
182       "4",
183       ASCIIToUTF16("Four"),
184       ASCIIToUTF16("This is the fourth notification."),
185       gfx::Image(),
186       string16(),
187       message_center::NotifierId(),
188       optional,
189       NULL));
190   center_->AddNotification(notification.Pass());
191   WaitForAnimationEnded();
192   EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:2],
193                                   [popups objectAtIndex:3]));
195   // Remove "2".
196   center_->RemoveNotification("2", true);
197   WaitForAnimationEnded();
198   EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:0],
199                                   [popups objectAtIndex:1]));
200   EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:1],
201                                   [popups objectAtIndex:2]));
203   // Remove "1".
204   center_->RemoveNotification("2", true);
205   WaitForAnimationEnded();
206   EXPECT_EQ(message_center::kMarginBetweenItems,
207             kScreenSize - NSMaxY([[[popups objectAtIndex:0] window] frame]));
208   EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:0],
209                                   [popups objectAtIndex:1]));
212 TEST_F(PopupCollectionTest, TinyScreen) {
213   [collection_ setScreenFrame:NSMakeRect(0, 0, 800, 100)];
215   EXPECT_EQ(0u, [[collection_ popups] count]);
216   scoped_ptr<message_center::Notification> notification;
217   notification.reset(new message_center::Notification(
218       message_center::NOTIFICATION_TYPE_SIMPLE,
219       "1",
220       ASCIIToUTF16("One"),
221       ASCIIToUTF16("This is the first notification to"
222               " be displayed"),
223       gfx::Image(),
224       string16(),
225       message_center::NotifierId(),
226       message_center::RichNotificationData(),
227       NULL));
228   center_->AddNotification(notification.Pass());
229   WaitForAnimationEnded();
230   EXPECT_EQ(1u, [[collection_ popups] count]);
232   // Now give the notification a longer message so that it no longer fits.
233   notification.reset(new message_center::Notification(
234       message_center::NOTIFICATION_TYPE_SIMPLE,
235       "1",
236       ASCIIToUTF16("One"),
237       ASCIIToUTF16("This is now a very very very very "
238               "very very very very very very very "
239               "very very very very very very very "
240               "very very very very very very very "
241               "very very very very very very very "
242               "very very very very very very very "
243               "very very very very very very very "
244               "long notification."),
245       gfx::Image(),
246       string16(),
247       message_center::NotifierId(),
248       message_center::RichNotificationData(),
249       NULL));
250   center_->UpdateNotification("1", notification.Pass());
251   WaitForAnimationEnded();
252   EXPECT_EQ(0u, [[collection_ popups] count]);
255 TEST_F(PopupCollectionTest, UpdateIconAndBody) {
256   AddThreeNotifications();
257   NSArray* popups = [collection_ popups];
259   EXPECT_EQ(3u, [popups count]);
261   // Update "2" icon.
262   MCNotificationController* controller =
263       [[popups objectAtIndex:1] notificationController];
264   EXPECT_FALSE([[controller iconView] image]);
265   center_->SetNotificationIcon("2",
266       gfx::Image([[NSImage imageNamed:NSImageNameUser] retain]));
267   WaitForAnimationEnded();
268   EXPECT_TRUE([[controller iconView] image]);
270   EXPECT_EQ(3u, [popups count]);
271   EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:0],
272                                   [popups objectAtIndex:1]));
273   EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:1],
274                                   [popups objectAtIndex:2]));
276   // Replace "1".
277   controller = [[popups objectAtIndex:0] notificationController];
278   NSRect old_frame = [[controller view] frame];
279   scoped_ptr<message_center::Notification> notification;
280   notification.reset(new message_center::Notification(
281       message_center::NOTIFICATION_TYPE_SIMPLE,
282       "1",
283       ASCIIToUTF16("One is going to get a much longer "
284               "title than it previously had."),
285       ASCIIToUTF16("This is the first notification to "
286               "be displayed, but it will also be "
287               "updated to have a significantly "
288               "longer body"),
289       gfx::Image(),
290       string16(),
291       message_center::NotifierId(),
292       message_center::RichNotificationData(),
293       NULL));
294   center_->AddNotification(notification.Pass());
295   WaitForAnimationEnded();
296   EXPECT_GT(NSHeight([[controller view] frame]), NSHeight(old_frame));
298   // Test updated spacing.
299   EXPECT_EQ(3u, [popups count]);
300   EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:0],
301                                   [popups objectAtIndex:1]));
302   EXPECT_TRUE(CheckSpacingBetween([popups objectAtIndex:1],
303                                   [popups objectAtIndex:2]));
304   EXPECT_EQ("1", [[popups objectAtIndex:0] notificationID]);
305   EXPECT_EQ("2", [[popups objectAtIndex:1] notificationID]);
306   EXPECT_EQ("3", [[popups objectAtIndex:2] notificationID]);
309 TEST_F(PopupCollectionTest, CloseCollectionBeforeNewPopupAnimationEnds) {
310   // Add a notification and don't wait for the animation to finish.
311   scoped_ptr<message_center::Notification> notification;
312   notification.reset(new message_center::Notification(
313       message_center::NOTIFICATION_TYPE_SIMPLE,
314       "1",
315       ASCIIToUTF16("One"),
316       ASCIIToUTF16("This is the first notification to"
317                    " be displayed"),
318       gfx::Image(),
319       string16(),
320       message_center::NotifierId(),
321       message_center::RichNotificationData(),
322       NULL));
323   center_->AddNotification(notification.Pass());
325   // Release the popup collection before the animation ends. No crash should
326   // be expected.
327   collection_.reset();
330 TEST_F(PopupCollectionTest, CloseCollectionBeforeClosePopupAnimationEnds) {
331   AddThreeNotifications();
333   // Remove a notification and don't wait for the animation to finish.
334   center_->RemoveNotification("1", true);
336   // Release the popup collection before the animation ends. No crash should
337   // be expected.
338   collection_.reset();
341 TEST_F(PopupCollectionTest, CloseCollectionBeforeUpdatePopupAnimationEnds) {
342   AddThreeNotifications();
344   // Update a notification and don't wait for the animation to finish.
345   scoped_ptr<message_center::Notification> notification;
346   notification.reset(new message_center::Notification(
347       message_center::NOTIFICATION_TYPE_SIMPLE,
348       "1",
349       ASCIIToUTF16("One"),
350       ASCIIToUTF16("New message."),
351       gfx::Image(),
352       string16(),
353       message_center::NotifierId(),
354       message_center::RichNotificationData(),
355       NULL));
356   center_->UpdateNotification("1", notification.Pass());
358   // Release the popup collection before the animation ends. No crash should
359   // be expected.
360   collection_.reset();