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