1// Copyright 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.
4
5#include "ui/message_center/message_center_impl.h"
6
7#include "base/bind.h"
8#include "base/message_loop/message_loop.h"
9#include "base/run_loop.h"
10#include "base/strings/utf_string_conversions.h"
11#include "testing/gtest/include/gtest/gtest.h"
12#include "ui/gfx/canvas.h"
13#include "ui/gfx/size.h"
14#include "ui/message_center/message_center.h"
15#include "ui/message_center/message_center_types.h"
16#include "ui/message_center/notification_blocker.h"
17#include "ui/message_center/notification_types.h"
18#include "ui/message_center/notifier_settings.h"
19
20using base::UTF8ToUTF16;
21
22namespace message_center {
23namespace {
24
25class MessageCenterImplTest : public testing::Test,
26                              public MessageCenterObserver {
27 public:
28  MessageCenterImplTest() {}
29
30  virtual void SetUp() OVERRIDE {
31    MessageCenter::Initialize();
32    message_center_ = MessageCenter::Get();
33    loop_.reset(new base::MessageLoop);
34    run_loop_.reset(new base::RunLoop());
35    closure_ = run_loop_->QuitClosure();
36  }
37
38  virtual void TearDown() OVERRIDE {
39    run_loop_.reset();
40    loop_.reset();
41    message_center_ = NULL;
42    MessageCenter::Shutdown();
43  }
44
45  MessageCenter* message_center() const { return message_center_; }
46  NotifierSettingsObserver* notifier_settings_observer() const {
47    return static_cast<NotifierSettingsObserver*>(message_center_impl());
48  }
49  MessageCenterImpl* message_center_impl() const {
50    return reinterpret_cast<MessageCenterImpl*>(message_center_);
51  }
52
53  base::RunLoop* run_loop() const { return run_loop_.get(); }
54  base::Closure closure() const { return closure_; }
55
56 protected:
57  Notification* CreateSimpleNotification(const std::string& id) {
58    return CreateNotificationWithNotifierId(
59        id,
60        "app1",
61        NOTIFICATION_TYPE_SIMPLE);
62  }
63
64  Notification* CreateSimpleNotificationWithNotifierId(
65    const std::string& id, const std::string& notifier_id) {
66    return CreateNotificationWithNotifierId(
67        id,
68        notifier_id,
69        NOTIFICATION_TYPE_SIMPLE);
70  }
71
72  Notification* CreateNotification(const std::string& id,
73                                   message_center::NotificationType type) {
74    return CreateNotificationWithNotifierId(id, "app1", type);
75  }
76
77  Notification* CreateNotificationWithNotifierId(
78      const std::string& id,
79      const std::string& notifier_id,
80      message_center::NotificationType type) {
81    RichNotificationData optional_fields;
82    optional_fields.buttons.push_back(ButtonInfo(UTF8ToUTF16("foo")));
83    optional_fields.buttons.push_back(ButtonInfo(UTF8ToUTF16("foo")));
84    return new Notification(type,
85                            id,
86                            UTF8ToUTF16("title"),
87                            UTF8ToUTF16(id),
88                            gfx::Image() /* icon */,
89                            base::string16() /* display_source */,
90                            NotifierId(NotifierId::APPLICATION, notifier_id),
91                            optional_fields,
92                            NULL);
93  }
94
95
96 private:
97  MessageCenter* message_center_;
98  scoped_ptr<base::MessageLoop> loop_;
99  scoped_ptr<base::RunLoop> run_loop_;
100  base::Closure closure_;
101
102  DISALLOW_COPY_AND_ASSIGN(MessageCenterImplTest);
103};
104
105class ToggledNotificationBlocker : public NotificationBlocker {
106 public:
107  explicit ToggledNotificationBlocker(MessageCenter* message_center)
108      : NotificationBlocker(message_center),
109        notifications_enabled_(true) {}
110  virtual ~ToggledNotificationBlocker() {}
111
112  void SetNotificationsEnabled(bool enabled) {
113    if (notifications_enabled_ != enabled) {
114      notifications_enabled_ = enabled;
115      NotifyBlockingStateChanged();
116    }
117  }
118
119  // NotificationBlocker overrides:
120  virtual  bool ShouldShowNotificationAsPopup(
121      const message_center::NotifierId& notifier_id) const OVERRIDE {
122    return notifications_enabled_;
123  }
124
125 private:
126  bool notifications_enabled_;
127
128  DISALLOW_COPY_AND_ASSIGN(ToggledNotificationBlocker);
129};
130
131class PopupNotificationBlocker : public ToggledNotificationBlocker {
132 public:
133  PopupNotificationBlocker(MessageCenter* message_center,
134                           const NotifierId& allowed_notifier)
135      : ToggledNotificationBlocker(message_center),
136        allowed_notifier_(allowed_notifier) {}
137  virtual ~PopupNotificationBlocker() {}
138
139  // NotificationBlocker overrides:
140  virtual bool ShouldShowNotificationAsPopup(
141      const NotifierId& notifier_id) const OVERRIDE {
142    return (notifier_id == allowed_notifier_) ||
143        ToggledNotificationBlocker::ShouldShowNotificationAsPopup(notifier_id);
144  }
145
146 private:
147  NotifierId allowed_notifier_;
148
149  DISALLOW_COPY_AND_ASSIGN(PopupNotificationBlocker);
150};
151
152class TotalNotificationBlocker : public PopupNotificationBlocker {
153 public:
154  TotalNotificationBlocker(MessageCenter* message_center,
155                           const NotifierId& allowed_notifier)
156      : PopupNotificationBlocker(message_center, allowed_notifier) {}
157  virtual ~TotalNotificationBlocker() {}
158
159  // NotificationBlocker overrides:
160  virtual bool ShouldShowNotification(
161      const NotifierId& notifier_id) const OVERRIDE {
162    return ShouldShowNotificationAsPopup(notifier_id);
163  }
164
165 private:
166  DISALLOW_COPY_AND_ASSIGN(TotalNotificationBlocker);
167};
168
169bool PopupNotificationsContain(
170    const NotificationList::PopupNotifications& popups,
171    const std::string& id) {
172  for (NotificationList::PopupNotifications::const_iterator iter =
173           popups.begin(); iter != popups.end(); ++iter) {
174    if ((*iter)->id() == id)
175      return true;
176  }
177  return false;
178}
179
180// Right now, MessageCenter::HasNotification() returns regardless of blockers.
181bool NotificationsContain(
182    const NotificationList::Notifications& notifications,
183    const std::string& id) {
184  for (NotificationList::Notifications::const_iterator iter =
185           notifications.begin(); iter != notifications.end(); ++iter) {
186    if ((*iter)->id() == id)
187      return true;
188  }
189  return false;
190}
191
192}  // namespace
193
194namespace internal {
195
196class MockPopupTimersController : public PopupTimersController {
197 public:
198  MockPopupTimersController(MessageCenter* message_center,
199                            base::Closure quit_closure)
200      : PopupTimersController(message_center),
201        timer_finished_(false),
202        quit_closure_(quit_closure) {}
203  virtual ~MockPopupTimersController() {}
204
205  virtual void TimerFinished(const std::string& id) OVERRIDE {
206    base::MessageLoop::current()->PostTask(FROM_HERE, quit_closure_);
207    timer_finished_ = true;
208    last_id_ = id;
209  }
210
211  bool timer_finished() const { return timer_finished_; }
212  const std::string& last_id() const { return last_id_; }
213
214 private:
215  bool timer_finished_;
216  std::string last_id_;
217  base::Closure quit_closure_;
218};
219
220TEST_F(MessageCenterImplTest, PopupTimersEmptyController) {
221  scoped_ptr<PopupTimersController> popup_timers_controller =
222      make_scoped_ptr(new PopupTimersController(message_center()));
223
224  // Test that all functions succed without any timers created.
225  popup_timers_controller->PauseAll();
226  popup_timers_controller->StartAll();
227  popup_timers_controller->CancelAll();
228  popup_timers_controller->TimerFinished("unknown");
229  popup_timers_controller->PauseTimer("unknown");
230  popup_timers_controller->CancelTimer("unknown");
231}
232
233TEST_F(MessageCenterImplTest, PopupTimersControllerStartTimer) {
234  scoped_ptr<MockPopupTimersController> popup_timers_controller =
235      make_scoped_ptr(
236          new MockPopupTimersController(message_center(), closure()));
237  popup_timers_controller->StartTimer("test",
238                                      base::TimeDelta::FromMilliseconds(1));
239  run_loop()->Run();
240  EXPECT_TRUE(popup_timers_controller->timer_finished());
241}
242
243TEST_F(MessageCenterImplTest, PopupTimersControllerPauseTimer) {
244  scoped_ptr<MockPopupTimersController> popup_timers_controller =
245      make_scoped_ptr(
246          new MockPopupTimersController(message_center(), closure()));
247  popup_timers_controller->StartTimer("test",
248                                      base::TimeDelta::FromMilliseconds(1));
249  popup_timers_controller->PauseTimer("test");
250  run_loop()->RunUntilIdle();
251
252  EXPECT_FALSE(popup_timers_controller->timer_finished());
253}
254
255TEST_F(MessageCenterImplTest, PopupTimersControllerCancelTimer) {
256  scoped_ptr<MockPopupTimersController> popup_timers_controller =
257      make_scoped_ptr(
258          new MockPopupTimersController(message_center(), closure()));
259  popup_timers_controller->StartTimer("test",
260                                      base::TimeDelta::FromMilliseconds(1));
261  popup_timers_controller->CancelTimer("test");
262  run_loop()->RunUntilIdle();
263
264  EXPECT_FALSE(popup_timers_controller->timer_finished());
265}
266
267TEST_F(MessageCenterImplTest, PopupTimersControllerPauseAllTimers) {
268  scoped_ptr<MockPopupTimersController> popup_timers_controller =
269      make_scoped_ptr(
270          new MockPopupTimersController(message_center(), closure()));
271  popup_timers_controller->StartTimer("test",
272                                      base::TimeDelta::FromMilliseconds(1));
273  popup_timers_controller->PauseAll();
274  run_loop()->RunUntilIdle();
275
276  EXPECT_FALSE(popup_timers_controller->timer_finished());
277}
278
279TEST_F(MessageCenterImplTest, PopupTimersControllerStartAllTimers) {
280  scoped_ptr<MockPopupTimersController> popup_timers_controller =
281      make_scoped_ptr(
282          new MockPopupTimersController(message_center(), closure()));
283  popup_timers_controller->StartTimer("test",
284                                      base::TimeDelta::FromMilliseconds(1));
285  popup_timers_controller->PauseAll();
286  popup_timers_controller->StartAll();
287  run_loop()->Run();
288
289  EXPECT_TRUE(popup_timers_controller->timer_finished());
290}
291
292TEST_F(MessageCenterImplTest, PopupTimersControllerStartMultipleTimers) {
293  scoped_ptr<MockPopupTimersController> popup_timers_controller =
294      make_scoped_ptr(
295          new MockPopupTimersController(message_center(), closure()));
296  popup_timers_controller->StartTimer("test",
297                                      base::TimeDelta::FromMilliseconds(5));
298  popup_timers_controller->StartTimer("test2",
299                                      base::TimeDelta::FromMilliseconds(1));
300  popup_timers_controller->StartTimer("test3",
301                                      base::TimeDelta::FromMilliseconds(3));
302  popup_timers_controller->PauseAll();
303  popup_timers_controller->StartAll();
304  run_loop()->Run();
305
306  EXPECT_EQ(popup_timers_controller->last_id(), "test2");
307  EXPECT_TRUE(popup_timers_controller->timer_finished());
308}
309
310TEST_F(MessageCenterImplTest, PopupTimersControllerStartMultipleTimersPause) {
311  scoped_ptr<MockPopupTimersController> popup_timers_controller =
312      make_scoped_ptr(
313          new MockPopupTimersController(message_center(), closure()));
314  popup_timers_controller->StartTimer("test",
315                                      base::TimeDelta::FromMilliseconds(5));
316  popup_timers_controller->StartTimer("test2",
317                                      base::TimeDelta::FromMilliseconds(1));
318  popup_timers_controller->StartTimer("test3",
319                                      base::TimeDelta::FromMilliseconds(3));
320  popup_timers_controller->PauseTimer("test2");
321
322  run_loop()->Run();
323
324  EXPECT_EQ(popup_timers_controller->last_id(), "test3");
325  EXPECT_TRUE(popup_timers_controller->timer_finished());
326}
327
328TEST_F(MessageCenterImplTest, PopupTimersControllerResetTimer) {
329  scoped_ptr<MockPopupTimersController> popup_timers_controller =
330      make_scoped_ptr(
331          new MockPopupTimersController(message_center(), closure()));
332  popup_timers_controller->StartTimer("test",
333                                      base::TimeDelta::FromMilliseconds(5));
334  popup_timers_controller->StartTimer("test2",
335                                      base::TimeDelta::FromMilliseconds(1));
336  popup_timers_controller->StartTimer("test3",
337                                      base::TimeDelta::FromMilliseconds(3));
338  popup_timers_controller->PauseTimer("test2");
339  popup_timers_controller->ResetTimer("test",
340                                      base::TimeDelta::FromMilliseconds(2));
341
342  run_loop()->Run();
343
344  EXPECT_EQ(popup_timers_controller->last_id(), "test");
345  EXPECT_TRUE(popup_timers_controller->timer_finished());
346}
347
348TEST_F(MessageCenterImplTest, NotificationBlocker) {
349  NotifierId notifier_id(NotifierId::APPLICATION, "app1");
350  // Multiple blockers to verify the case that one blocker blocks but another
351  // doesn't.
352  ToggledNotificationBlocker blocker1(message_center());
353  ToggledNotificationBlocker blocker2(message_center());
354
355  message_center()->AddNotification(scoped_ptr<Notification>(new Notification(
356      NOTIFICATION_TYPE_SIMPLE,
357      "id1",
358      UTF8ToUTF16("title"),
359      UTF8ToUTF16("message"),
360      gfx::Image() /* icon */,
361      base::string16() /* display_source */,
362      notifier_id,
363      RichNotificationData(),
364      NULL)));
365  message_center()->AddNotification(scoped_ptr<Notification>(new Notification(
366      NOTIFICATION_TYPE_SIMPLE,
367      "id2",
368      UTF8ToUTF16("title"),
369      UTF8ToUTF16("message"),
370      gfx::Image() /* icon */,
371      base::string16() /* display_source */,
372      notifier_id,
373      RichNotificationData(),
374      NULL)));
375  EXPECT_EQ(2u, message_center()->GetPopupNotifications().size());
376  EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
377
378  // Block all notifications. All popups are gone and message center should be
379  // hidden.
380  blocker1.SetNotificationsEnabled(false);
381  EXPECT_TRUE(message_center()->GetPopupNotifications().empty());
382  EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
383
384  // Updates |blocker2| state, which doesn't affect the global state.
385  blocker2.SetNotificationsEnabled(false);
386  EXPECT_TRUE(message_center()->GetPopupNotifications().empty());
387  EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
388
389  blocker2.SetNotificationsEnabled(true);
390  EXPECT_TRUE(message_center()->GetPopupNotifications().empty());
391  EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
392
393  // If |blocker2| blocks, then unblocking blocker1 doesn't change the global
394  // state.
395  blocker2.SetNotificationsEnabled(false);
396  blocker1.SetNotificationsEnabled(true);
397  EXPECT_TRUE(message_center()->GetPopupNotifications().empty());
398  EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
399
400  // Unblock both blockers, which recovers the global state, but the popups
401  // aren't shown.
402  blocker2.SetNotificationsEnabled(true);
403  EXPECT_TRUE(message_center()->GetPopupNotifications().empty());
404  EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
405}
406
407TEST_F(MessageCenterImplTest, NotificationsDuringBlocked) {
408  NotifierId notifier_id(NotifierId::APPLICATION, "app1");
409  ToggledNotificationBlocker blocker(message_center());
410
411  message_center()->AddNotification(scoped_ptr<Notification>(new Notification(
412      NOTIFICATION_TYPE_SIMPLE,
413      "id1",
414      UTF8ToUTF16("title"),
415      UTF8ToUTF16("message"),
416      gfx::Image() /* icon */,
417      base::string16() /* display_source */,
418      notifier_id,
419      RichNotificationData(),
420      NULL)));
421  EXPECT_EQ(1u, message_center()->GetPopupNotifications().size());
422  EXPECT_EQ(1u, message_center()->GetVisibleNotifications().size());
423
424  // Create a notification during blocked. Still no popups.
425  blocker.SetNotificationsEnabled(false);
426  message_center()->AddNotification(scoped_ptr<Notification>(new Notification(
427      NOTIFICATION_TYPE_SIMPLE,
428      "id2",
429      UTF8ToUTF16("title"),
430      UTF8ToUTF16("message"),
431      gfx::Image() /* icon */,
432      base::string16() /* display_source */,
433      notifier_id,
434      RichNotificationData(),
435      NULL)));
436  EXPECT_TRUE(message_center()->GetPopupNotifications().empty());
437  EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
438
439  // Unblock notifications, the id1 should appear as a popup.
440  blocker.SetNotificationsEnabled(true);
441  NotificationList::PopupNotifications popups =
442      message_center()->GetPopupNotifications();
443  EXPECT_EQ(1u, popups.size());
444  EXPECT_TRUE(PopupNotificationsContain(popups, "id2"));
445  EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
446}
447
448// Similar to other blocker cases but this test case allows |notifier_id2| even
449// in blocked.
450TEST_F(MessageCenterImplTest, NotificationBlockerAllowsPopups) {
451  NotifierId notifier_id1(NotifierId::APPLICATION, "app1");
452  NotifierId notifier_id2(NotifierId::APPLICATION, "app2");
453  PopupNotificationBlocker blocker(message_center(), notifier_id2);
454
455  message_center()->AddNotification(scoped_ptr<Notification>(new Notification(
456      NOTIFICATION_TYPE_SIMPLE,
457      "id1",
458      UTF8ToUTF16("title"),
459      UTF8ToUTF16("message"),
460      gfx::Image() /* icon */,
461      base::string16() /* display_source */,
462      notifier_id1,
463      RichNotificationData(),
464      NULL)));
465  message_center()->AddNotification(scoped_ptr<Notification>(new Notification(
466      NOTIFICATION_TYPE_SIMPLE,
467      "id2",
468      UTF8ToUTF16("title"),
469      UTF8ToUTF16("message"),
470      gfx::Image() /* icon */,
471      base::string16() /* display_source */,
472      notifier_id2,
473      RichNotificationData(),
474      NULL)));
475
476  // "id1" is closed but "id2" is still visible as a popup.
477  blocker.SetNotificationsEnabled(false);
478  NotificationList::PopupNotifications popups =
479      message_center()->GetPopupNotifications();
480  EXPECT_EQ(1u, popups.size());
481  EXPECT_TRUE(PopupNotificationsContain(popups, "id2"));
482  EXPECT_EQ(2u, message_center()->GetVisibleNotifications().size());
483
484  message_center()->AddNotification(scoped_ptr<Notification>(new Notification(
485      NOTIFICATION_TYPE_SIMPLE,
486      "id3",
487      UTF8ToUTF16("title"),
488      UTF8ToUTF16("message"),
489      gfx::Image() /* icon */,
490      base::string16() /* display_source */,
491      notifier_id1,
492      RichNotificationData(),
493      NULL)));
494  message_center()->AddNotification(scoped_ptr<Notification>(new Notification(
495      NOTIFICATION_TYPE_SIMPLE,
496      "id4",
497      UTF8ToUTF16("title"),
498      UTF8ToUTF16("message"),
499      gfx::Image() /* icon */,
500      base::string16() /* display_source */,
501      notifier_id2,
502      RichNotificationData(),
503      NULL)));
504  popups = message_center()->GetPopupNotifications();
505  EXPECT_EQ(2u, popups.size());
506  EXPECT_TRUE(PopupNotificationsContain(popups, "id2"));
507  EXPECT_TRUE(PopupNotificationsContain(popups, "id4"));
508  EXPECT_EQ(4u, message_center()->GetVisibleNotifications().size());
509
510  blocker.SetNotificationsEnabled(true);
511  popups = message_center()->GetPopupNotifications();
512  EXPECT_EQ(3u, popups.size());
513  EXPECT_TRUE(PopupNotificationsContain(popups, "id2"));
514  EXPECT_TRUE(PopupNotificationsContain(popups, "id3"));
515  EXPECT_TRUE(PopupNotificationsContain(popups, "id4"));
516  EXPECT_EQ(4u, message_center()->GetVisibleNotifications().size());
517}
518
519// TotalNotificationBlocker suppresses showing notifications even from the list.
520// This would provide the feature to 'separated' message centers per-profile for
521// ChromeOS multi-login.
522TEST_F(MessageCenterImplTest, TotalNotificationBlocker) {
523  NotifierId notifier_id1(NotifierId::APPLICATION, "app1");
524  NotifierId notifier_id2(NotifierId::APPLICATION, "app2");
525  TotalNotificationBlocker blocker(message_center(), notifier_id2);
526
527  message_center()->AddNotification(scoped_ptr<Notification>(new Notification(
528      NOTIFICATION_TYPE_SIMPLE,
529      "id1",
530      UTF8ToUTF16("title"),
531      UTF8ToUTF16("message"),
532      gfx::Image() /* icon */,
533      base::string16() /* display_source */,
534      notifier_id1,
535      RichNotificationData(),
536      NULL)));
537  message_center()->AddNotification(scoped_ptr<Notification>(new Notification(
538      NOTIFICATION_TYPE_SIMPLE,
539      "id2",
540      UTF8ToUTF16("title"),
541      UTF8ToUTF16("message"),
542      gfx::Image() /* icon */,
543      base::string16() /* display_source */,
544      notifier_id2,
545      RichNotificationData(),
546      NULL)));
547
548  // "id1" becomes invisible while "id2" is still visible.
549  blocker.SetNotificationsEnabled(false);
550  EXPECT_EQ(1u, message_center()->NotificationCount());
551  NotificationList::Notifications notifications =
552      message_center()->GetVisibleNotifications();
553  EXPECT_FALSE(NotificationsContain(notifications, "id1"));
554  EXPECT_TRUE(NotificationsContain(notifications, "id2"));
555
556  message_center()->AddNotification(scoped_ptr<Notification>(new Notification(
557      NOTIFICATION_TYPE_SIMPLE,
558      "id3",
559      UTF8ToUTF16("title"),
560      UTF8ToUTF16("message"),
561      gfx::Image() /* icon */,
562      base::string16() /* display_source */,
563      notifier_id1,
564      RichNotificationData(),
565      NULL)));
566  message_center()->AddNotification(scoped_ptr<Notification>(new Notification(
567      NOTIFICATION_TYPE_SIMPLE,
568      "id4",
569      UTF8ToUTF16("title"),
570      UTF8ToUTF16("message"),
571      gfx::Image() /* icon */,
572      base::string16() /* display_source */,
573      notifier_id2,
574      RichNotificationData(),
575      NULL)));
576  EXPECT_EQ(2u, message_center()->NotificationCount());
577  notifications = message_center()->GetVisibleNotifications();
578  EXPECT_FALSE(NotificationsContain(notifications, "id1"));
579  EXPECT_TRUE(NotificationsContain(notifications, "id2"));
580  EXPECT_FALSE(NotificationsContain(notifications, "id3"));
581  EXPECT_TRUE(NotificationsContain(notifications, "id4"));
582
583  blocker.SetNotificationsEnabled(true);
584  EXPECT_EQ(4u, message_center()->NotificationCount());
585  notifications = message_center()->GetVisibleNotifications();
586  EXPECT_TRUE(NotificationsContain(notifications, "id1"));
587  EXPECT_TRUE(NotificationsContain(notifications, "id2"));
588  EXPECT_TRUE(NotificationsContain(notifications, "id3"));
589  EXPECT_TRUE(NotificationsContain(notifications, "id4"));
590
591  // RemoveAllVisibleNotifications should remove just visible notifications.
592  blocker.SetNotificationsEnabled(false);
593  message_center()->RemoveAllVisibleNotifications(false /* by_user */);
594  EXPECT_EQ(0u, message_center()->NotificationCount());
595  blocker.SetNotificationsEnabled(true);
596  EXPECT_EQ(2u, message_center()->NotificationCount());
597  notifications = message_center()->GetVisibleNotifications();
598  EXPECT_TRUE(NotificationsContain(notifications, "id1"));
599  EXPECT_FALSE(NotificationsContain(notifications, "id2"));
600  EXPECT_TRUE(NotificationsContain(notifications, "id3"));
601  EXPECT_FALSE(NotificationsContain(notifications, "id4"));
602
603  // And RemoveAllNotifications should remove all.
604  blocker.SetNotificationsEnabled(false);
605  message_center()->RemoveAllNotifications(false /* by_user */);
606  EXPECT_EQ(0u, message_center()->NotificationCount());
607}
608
609TEST_F(MessageCenterImplTest, QueueUpdatesWithCenterVisible) {
610  std::string id("id1");
611  std::string id2("id2");
612  NotifierId notifier_id1(NotifierId::APPLICATION, "app1");
613
614  // First, add and update a notification to ensure updates happen
615  // normally.
616  scoped_ptr<Notification> notification(CreateSimpleNotification(id));
617  message_center()->AddNotification(notification.Pass());
618  notification.reset(CreateSimpleNotification(id2));
619  message_center()->UpdateNotification(id, notification.Pass());
620  EXPECT_TRUE(message_center()->FindVisibleNotificationById(id2));
621  EXPECT_FALSE(message_center()->FindVisibleNotificationById(id));
622
623  // Then open the message center.
624  message_center()->SetVisibility(VISIBILITY_MESSAGE_CENTER);
625
626  // Then update a notification; nothing should have happened.
627  notification.reset(CreateSimpleNotification(id));
628  message_center()->UpdateNotification(id2, notification.Pass());
629  EXPECT_TRUE(message_center()->FindVisibleNotificationById(id2));
630  EXPECT_FALSE(message_center()->FindVisibleNotificationById(id));
631
632  // Close the message center; then the update should have propagated.
633  message_center()->SetVisibility(VISIBILITY_TRANSIENT);
634  EXPECT_FALSE(message_center()->FindVisibleNotificationById(id2));
635  EXPECT_TRUE(message_center()->FindVisibleNotificationById(id));
636}
637
638TEST_F(MessageCenterImplTest, ComplexQueueing) {
639  std::string ids[5] = {"0", "1", "2", "3", "4p"};
640  NotifierId notifier_id1(NotifierId::APPLICATION, "app1");
641
642  scoped_ptr<Notification> notification;
643  // Add some notifications
644  int i = 0;
645  for (; i < 3; i++) {
646    notification.reset(CreateSimpleNotification(ids[i]));
647    message_center()->AddNotification(notification.Pass());
648  }
649  for (i = 0; i < 3; i++) {
650    EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[i]));
651  }
652  for (; i < 5; i++) {
653    EXPECT_FALSE(message_center()->FindVisibleNotificationById(ids[i]));
654  }
655
656  notification.reset(CreateNotification(ids[4], NOTIFICATION_TYPE_PROGRESS));
657  message_center()->AddNotification(notification.Pass());
658
659  // Now start queueing.
660  // NL: ["0", "1", "2", "4p"]
661  message_center()->SetVisibility(VISIBILITY_MESSAGE_CENTER);
662
663  // This should update notification "1" to have id "3".
664  notification.reset(CreateSimpleNotification(ids[3]));
665  message_center()->UpdateNotification(ids[1], notification.Pass());
666
667  notification.reset(CreateSimpleNotification(ids[4]));
668  message_center()->UpdateNotification(ids[4], notification.Pass());
669
670  notification.reset(CreateNotification(ids[4], NOTIFICATION_TYPE_PROGRESS));
671  message_center()->UpdateNotification(ids[4], notification.Pass());
672
673  // This should update notification "3" to a new ID after we go TRANSIENT.
674  notification.reset(CreateSimpleNotification("New id"));
675  message_center()->UpdateNotification(ids[3], notification.Pass());
676
677  // This should create a new "3", that doesn't overwrite the update to 3
678  // before.
679  notification.reset(CreateSimpleNotification(ids[3]));
680  message_center()->AddNotification(notification.Pass());
681
682  // The NL should still be the same: ["0", "1", "2", "4p"]
683  EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[0]));
684  EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[1]));
685  EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[2]));
686  EXPECT_FALSE(message_center()->FindVisibleNotificationById(ids[3]));
687  EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[4]));
688  EXPECT_EQ(message_center()->GetVisibleNotifications().size(), 4u);
689  message_center()->SetVisibility(VISIBILITY_TRANSIENT);
690
691  EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[0]));
692  EXPECT_FALSE(message_center()->FindVisibleNotificationById(ids[1]));
693  EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[2]));
694  EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[3]));
695  EXPECT_TRUE(message_center()->FindVisibleNotificationById(ids[4]));
696  EXPECT_TRUE(message_center()->FindVisibleNotificationById("New id"));
697  EXPECT_EQ(message_center()->GetVisibleNotifications().size(), 5u);
698}
699
700TEST_F(MessageCenterImplTest, QueuedDirectUpdates) {
701  std::string id("id1");
702  std::string id2("id2");
703  NotifierId notifier_id1(NotifierId::APPLICATION, "app1");
704
705  gfx::Size original_size(0, 0);
706  // Open the message center to prevent adding notifications
707  message_center()->SetVisibility(VISIBILITY_MESSAGE_CENTER);
708
709  // Create new notification to be added to the queue; images all have the same
710  // original size.
711  scoped_ptr<Notification> notification(CreateSimpleNotification(id));
712
713  // Double-check that sizes all match.
714  const std::vector<ButtonInfo>& original_buttons = notification->buttons();
715  ASSERT_EQ(2u, original_buttons.size());
716
717  EXPECT_EQ(original_size, notification->icon().Size());
718  EXPECT_EQ(original_size, notification->image().Size());
719  EXPECT_EQ(original_size, original_buttons[0].icon.Size());
720  EXPECT_EQ(original_size, original_buttons[1].icon.Size());
721
722  message_center()->AddNotification(notification.Pass());
723
724  // The notification should be in the queue.
725  EXPECT_FALSE(message_center()->FindVisibleNotificationById(id));
726
727  // Now try setting the icon to a different size.
728  gfx::Size new_size(16, 16);
729  EXPECT_NE(original_size, new_size);
730
731  gfx::Canvas canvas(new_size, 1.0f, true);
732  canvas.DrawColor(SK_ColorBLUE);
733  gfx::Image testImage(gfx::Image(gfx::ImageSkia(canvas.ExtractImageRep())));
734  message_center()->SetNotificationIcon(id, testImage);
735  message_center()->SetNotificationImage(id, testImage);
736  message_center()->SetNotificationButtonIcon(id, 0, testImage);
737  message_center()->SetNotificationButtonIcon(id, 1, testImage);
738
739  // The notification should be in the queue.
740  EXPECT_FALSE(message_center()->FindVisibleNotificationById(id));
741
742  // Close the message center; then the update should have propagated.
743  message_center()->SetVisibility(VISIBILITY_TRANSIENT);
744  // The notification should no longer be in the queue.
745  EXPECT_TRUE(message_center()->FindVisibleNotificationById(id));
746
747  Notification* mc_notification =
748      *(message_center()->GetVisibleNotifications().begin());
749  const std::vector<ButtonInfo>& buttons = mc_notification->buttons();
750  ASSERT_EQ(2u, buttons.size());
751
752  EXPECT_EQ(new_size, mc_notification->icon().Size());
753  EXPECT_EQ(new_size, mc_notification->image().Size());
754  EXPECT_EQ(new_size, buttons[0].icon.Size());
755  EXPECT_EQ(new_size, buttons[1].icon.Size());
756}
757
758TEST_F(MessageCenterImplTest, CachedUnreadCount) {
759  message_center()->AddNotification(
760      scoped_ptr<Notification>(CreateSimpleNotification("id1")));
761  message_center()->AddNotification(
762      scoped_ptr<Notification>(CreateSimpleNotification("id2")));
763  message_center()->AddNotification(
764      scoped_ptr<Notification>(CreateSimpleNotification("id3")));
765  ASSERT_EQ(3u, message_center()->UnreadNotificationCount());
766
767  // Mark 'displayed' on all notifications by using for-loop. This shouldn't
768  // recreate |notifications| inside of the loop.
769  const NotificationList::Notifications& notifications =
770      message_center()->GetVisibleNotifications();
771  for (NotificationList::Notifications::const_iterator iter =
772           notifications.begin(); iter != notifications.end(); ++iter) {
773    message_center()->DisplayedNotification(
774        (*iter)->id(), message_center::DISPLAY_SOURCE_MESSAGE_CENTER);
775  }
776  EXPECT_EQ(0u, message_center()->UnreadNotificationCount());
777
778  // Imitate the timeout, which recovers the unread count. Again, this shouldn't
779  // recreate |notifications| inside of the loop.
780  for (NotificationList::Notifications::const_iterator iter =
781           notifications.begin(); iter != notifications.end(); ++iter) {
782    message_center()->MarkSinglePopupAsShown((*iter)->id(), false);
783  }
784  EXPECT_EQ(3u, message_center()->UnreadNotificationCount());
785
786  // Opening the message center will reset the unread count.
787  message_center()->SetVisibility(VISIBILITY_MESSAGE_CENTER);
788  EXPECT_EQ(0u, message_center()->UnreadNotificationCount());
789}
790
791TEST_F(MessageCenterImplTest, DisableNotificationsByNotifier) {
792  ASSERT_EQ(0u, message_center()->NotificationCount());
793  message_center()->AddNotification(
794      scoped_ptr<Notification>(
795          CreateSimpleNotificationWithNotifierId("id1-1", "app1")));
796  message_center()->AddNotification(
797      scoped_ptr<Notification>(
798          CreateSimpleNotificationWithNotifierId("id1-2", "app1")));
799  message_center()->AddNotification(
800      scoped_ptr<Notification>(
801          CreateSimpleNotificationWithNotifierId("id2-1", "app2")));
802  message_center()->AddNotification(
803      scoped_ptr<Notification>(
804          CreateSimpleNotificationWithNotifierId("id2-2", "app2")));
805  message_center()->AddNotification(
806      scoped_ptr<Notification>(
807          CreateSimpleNotificationWithNotifierId("id2-3", "app2")));
808  ASSERT_EQ(5u, message_center()->NotificationCount());
809
810  // Removing all of app1's notifications should only leave app2's.
811  message_center()->DisableNotificationsByNotifier(
812      NotifierId(NotifierId::APPLICATION, "app1"));
813  ASSERT_EQ(3u, message_center()->NotificationCount());
814
815  // Now we remove the remaining notifications.
816  message_center()->DisableNotificationsByNotifier(
817      NotifierId(NotifierId::APPLICATION, "app2"));
818  ASSERT_EQ(0u, message_center()->NotificationCount());
819}
820
821TEST_F(MessageCenterImplTest, NotifierEnabledChanged) {
822  ASSERT_EQ(0u, message_center()->NotificationCount());
823  message_center()->AddNotification(
824      scoped_ptr<Notification>(
825          CreateSimpleNotificationWithNotifierId("id1-1", "app1")));
826  message_center()->AddNotification(
827      scoped_ptr<Notification>(
828          CreateSimpleNotificationWithNotifierId("id1-2", "app1")));
829  message_center()->AddNotification(
830      scoped_ptr<Notification>(
831          CreateSimpleNotificationWithNotifierId("id1-3", "app1")));
832  message_center()->AddNotification(
833      scoped_ptr<Notification>(
834          CreateSimpleNotificationWithNotifierId("id2-1", "app2")));
835  message_center()->AddNotification(
836      scoped_ptr<Notification>(
837          CreateSimpleNotificationWithNotifierId("id2-2", "app2")));
838  message_center()->AddNotification(
839      scoped_ptr<Notification>(
840          CreateSimpleNotificationWithNotifierId("id2-3", "app2")));
841  message_center()->AddNotification(
842      scoped_ptr<Notification>(
843          CreateSimpleNotificationWithNotifierId("id2-4", "app2")));
844  message_center()->AddNotification(
845      scoped_ptr<Notification>(
846          CreateSimpleNotificationWithNotifierId("id2-5", "app2")));
847  ASSERT_EQ(8u, message_center()->NotificationCount());
848
849  // Enabling an extension should have no effect on the count.
850  notifier_settings_observer()->NotifierEnabledChanged(
851      NotifierId(NotifierId::APPLICATION, "app1"), true);
852  ASSERT_EQ(8u, message_center()->NotificationCount());
853
854  // Removing all of app2's notifications should only leave app1's.
855  notifier_settings_observer()->NotifierEnabledChanged(
856      NotifierId(NotifierId::APPLICATION, "app2"), false);
857  ASSERT_EQ(3u, message_center()->NotificationCount());
858
859  // Removal operations should be idempotent.
860  notifier_settings_observer()->NotifierEnabledChanged(
861      NotifierId(NotifierId::APPLICATION, "app2"), false);
862  ASSERT_EQ(3u, message_center()->NotificationCount());
863
864  // Now we remove the remaining notifications.
865  notifier_settings_observer()->NotifierEnabledChanged(
866      NotifierId(NotifierId::APPLICATION, "app1"), false);
867  ASSERT_EQ(0u, message_center()->NotificationCount());
868}
869
870}  // namespace internal
871}  // namespace message_center
872