1// Copyright (c) 2012 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/notification_list.h"
6
7#include "base/basictypes.h"
8#include "base/i18n/time_formatting.h"
9#include "base/strings/stringprintf.h"
10#include "base/strings/utf_string_conversions.h"
11#include "base/values.h"
12#include "testing/gtest/include/gtest/gtest.h"
13#include "ui/message_center/message_center_style.h"
14#include "ui/message_center/notification_blocker.h"
15#include "ui/message_center/notification_types.h"
16#include "ui/message_center/notifier_settings.h"
17
18namespace message_center {
19
20class NotificationListTest : public testing::Test {
21 public:
22  NotificationListTest() {}
23  virtual ~NotificationListTest() {}
24
25  virtual void SetUp() {
26    notification_list_.reset(new NotificationList());
27    counter_ = 0;
28  }
29
30 protected:
31  // Currently NotificationListTest doesn't care about some fields like title or
32  // message, so put a simple template on it. Returns the id of the new
33  // notification.
34  std::string AddNotification(
35      const message_center::RichNotificationData& optional_fields) {
36    std::string new_id;
37    scoped_ptr<Notification> notification(
38        MakeNotification(optional_fields, &new_id));
39    notification_list_->AddNotification(notification.Pass());
40    counter_++;
41    return new_id;
42  }
43
44  std::string AddNotification() {
45    return AddNotification(message_center::RichNotificationData());
46  }
47
48  // Construct a new notification for testing, but don't add it to the list yet.
49  scoped_ptr<Notification> MakeNotification(
50      const message_center::RichNotificationData& optional_fields,
51      std::string* id_out) {
52    *id_out = base::StringPrintf(kIdFormat, counter_);
53    scoped_ptr<Notification> notification(new Notification(
54        message_center::NOTIFICATION_TYPE_SIMPLE,
55        *id_out,
56        UTF8ToUTF16(base::StringPrintf(kTitleFormat, counter_)),
57        UTF8ToUTF16(base::StringPrintf(kMessageFormat, counter_)),
58        gfx::Image(),
59        UTF8ToUTF16(kDisplaySource),
60        NotifierId(NotifierId::APPLICATION, kExtensionId),
61        optional_fields,
62        NULL));
63    return notification.Pass();
64  }
65
66  scoped_ptr<Notification> MakeNotification(std::string* id_out) {
67    return MakeNotification(message_center::RichNotificationData(), id_out);
68  }
69
70  // Utility methods of AddNotification.
71  std::string AddPriorityNotification(NotificationPriority priority) {
72    message_center::RichNotificationData optional;
73    optional.priority = priority;
74    return AddNotification(optional);
75  }
76
77  NotificationList::PopupNotifications GetPopups() {
78    return notification_list()->GetPopupNotifications(blockers_, NULL);
79  }
80
81  size_t GetPopupCounts() {
82    return GetPopups().size();
83  }
84
85  Notification* GetNotification(const std::string& id) {
86    NotificationList::Notifications::iterator iter =
87        notification_list()->GetNotification(id);
88    if (iter == notification_list()->notifications_.end())
89      return NULL;
90    return *iter;
91  }
92
93  NotificationList* notification_list() { return notification_list_.get(); }
94  const NotificationBlockers& blockers() const { return blockers_; }
95
96  static const char kIdFormat[];
97  static const char kTitleFormat[];
98  static const char kMessageFormat[];
99  static const char kDisplaySource[];
100  static const char kExtensionId[];
101
102 private:
103  scoped_ptr<NotificationList> notification_list_;
104  NotificationBlockers blockers_;
105  size_t counter_;
106
107  DISALLOW_COPY_AND_ASSIGN(NotificationListTest);
108};
109
110bool IsInNotifications(const NotificationList::Notifications& notifications,
111                       const std::string& id) {
112  for (NotificationList::Notifications::const_iterator iter =
113           notifications.begin(); iter != notifications.end(); ++iter) {
114    if ((*iter)->id() == id)
115      return true;
116  }
117  return false;
118}
119
120const char NotificationListTest::kIdFormat[] = "id%ld";
121const char NotificationListTest::kTitleFormat[] = "id%ld";
122const char NotificationListTest::kMessageFormat[] = "message%ld";
123const char NotificationListTest::kDisplaySource[] = "source";
124const char NotificationListTest::kExtensionId[] = "ext";
125
126TEST_F(NotificationListTest, Basic) {
127  ASSERT_EQ(0u, notification_list()->NotificationCount(blockers()));
128  ASSERT_EQ(0u, notification_list()->UnreadCount(blockers()));
129
130  std::string id0 = AddNotification();
131  EXPECT_EQ(1u, notification_list()->NotificationCount(blockers()));
132  std::string id1 = AddNotification();
133  EXPECT_EQ(2u, notification_list()->NotificationCount(blockers()));
134  EXPECT_EQ(2u, notification_list()->UnreadCount(blockers()));
135
136  EXPECT_TRUE(notification_list()->HasPopupNotifications(blockers()));
137  EXPECT_TRUE(notification_list()->HasNotification(id0));
138  EXPECT_TRUE(notification_list()->HasNotification(id1));
139  EXPECT_FALSE(notification_list()->HasNotification(id1 + "foo"));
140
141  EXPECT_EQ(2u, GetPopupCounts());
142
143  notification_list()->MarkSinglePopupAsShown(id0, true);
144  notification_list()->MarkSinglePopupAsShown(id1, true);
145  EXPECT_EQ(2u, notification_list()->NotificationCount(blockers()));
146  EXPECT_EQ(0u, GetPopupCounts());
147
148  notification_list()->RemoveNotification(id0);
149  EXPECT_EQ(1u, notification_list()->NotificationCount(blockers()));
150  EXPECT_EQ(1u, notification_list()->UnreadCount(blockers()));
151
152  AddNotification();
153  EXPECT_EQ(2u, notification_list()->NotificationCount(blockers()));
154}
155
156TEST_F(NotificationListTest, MessageCenterVisible) {
157  AddNotification();
158  EXPECT_EQ(1u, notification_list()->NotificationCount(blockers()));
159  ASSERT_EQ(1u, notification_list()->UnreadCount(blockers()));
160  ASSERT_EQ(1u, GetPopupCounts());
161
162  // Make the message center visible. It resets the unread count and popup
163  // counts.
164  notification_list()->SetMessageCenterVisible(true, NULL);
165  ASSERT_EQ(0u, notification_list()->UnreadCount(blockers()));
166  ASSERT_EQ(0u, GetPopupCounts());
167}
168
169TEST_F(NotificationListTest, UnreadCount) {
170  std::string id0 = AddNotification();
171  std::string id1 = AddNotification();
172  ASSERT_EQ(2u, notification_list()->UnreadCount(blockers()));
173
174  notification_list()->MarkSinglePopupAsDisplayed(id0);
175  EXPECT_EQ(1u, notification_list()->UnreadCount(blockers()));
176  notification_list()->MarkSinglePopupAsDisplayed(id0);
177  EXPECT_EQ(1u, notification_list()->UnreadCount(blockers()));
178  notification_list()->MarkSinglePopupAsDisplayed(id1);
179  EXPECT_EQ(0u, notification_list()->UnreadCount(blockers()));
180}
181
182TEST_F(NotificationListTest, UpdateNotification) {
183  std::string id0 = AddNotification();
184  std::string replaced = id0 + "_replaced";
185  EXPECT_EQ(1u, notification_list()->NotificationCount(blockers()));
186  scoped_ptr<Notification> notification(
187      new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
188                       replaced,
189                       UTF8ToUTF16("newtitle"),
190                       UTF8ToUTF16("newbody"),
191                       gfx::Image(),
192                       UTF8ToUTF16(kDisplaySource),
193                       NotifierId(NotifierId::APPLICATION, kExtensionId),
194                       message_center::RichNotificationData(),
195                       NULL));
196  notification_list()->UpdateNotificationMessage(id0, notification.Pass());
197  EXPECT_EQ(1u, notification_list()->NotificationCount(blockers()));
198  const NotificationList::Notifications notifications =
199      notification_list()->GetVisibleNotifications(blockers());
200  EXPECT_EQ(replaced, (*notifications.begin())->id());
201  EXPECT_EQ(UTF8ToUTF16("newtitle"), (*notifications.begin())->title());
202  EXPECT_EQ(UTF8ToUTF16("newbody"), (*notifications.begin())->message());
203}
204
205TEST_F(NotificationListTest, GetNotificationsByNotifierId) {
206  NotifierId id0(NotifierId::APPLICATION, "ext0");
207  NotifierId id1(NotifierId::APPLICATION, "ext1");
208  NotifierId id2(GURL("http://example.com"));
209  NotifierId id3(NotifierId::SYSTEM_COMPONENT, "system-notifier");
210  scoped_ptr<Notification> notification(
211      new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
212                       "id0",
213                       UTF8ToUTF16("title0"),
214                       UTF8ToUTF16("message0"),
215                       gfx::Image(),
216                       UTF8ToUTF16("source0"),
217                       id0,
218                       message_center::RichNotificationData(),
219                       NULL));
220  notification_list()->AddNotification(notification.Pass());
221  notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
222                                      "id1",
223                                      UTF8ToUTF16("title1"),
224                                      UTF8ToUTF16("message1"),
225                                      gfx::Image(),
226                                      UTF8ToUTF16("source0"),
227                                      id0,
228                                      message_center::RichNotificationData(),
229                                      NULL));
230  notification_list()->AddNotification(notification.Pass());
231  notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
232                                      "id2",
233                                      UTF8ToUTF16("title1"),
234                                      UTF8ToUTF16("message1"),
235                                      gfx::Image(),
236                                      UTF8ToUTF16("source1"),
237                                      id0,
238                                      message_center::RichNotificationData(),
239                                      NULL));
240  notification_list()->AddNotification(notification.Pass());
241  notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
242                                      "id3",
243                                      UTF8ToUTF16("title1"),
244                                      UTF8ToUTF16("message1"),
245                                      gfx::Image(),
246                                      UTF8ToUTF16("source2"),
247                                      id1,
248                                      message_center::RichNotificationData(),
249                                      NULL));
250  notification_list()->AddNotification(notification.Pass());
251  notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
252                                      "id4",
253                                      UTF8ToUTF16("title1"),
254                                      UTF8ToUTF16("message1"),
255                                      gfx::Image(),
256                                      UTF8ToUTF16("source2"),
257                                      id2,
258                                      message_center::RichNotificationData(),
259                                      NULL));
260  notification_list()->AddNotification(notification.Pass());
261  notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
262                                      "id5",
263                                      UTF8ToUTF16("title1"),
264                                      UTF8ToUTF16("message1"),
265                                      gfx::Image(),
266                                      UTF8ToUTF16("source2"),
267                                      id3,
268                                      message_center::RichNotificationData(),
269                                      NULL));
270  notification_list()->AddNotification(notification.Pass());
271
272  NotificationList::Notifications by_notifier_id =
273      notification_list()->GetNotificationsByNotifierId(id0);
274  EXPECT_TRUE(IsInNotifications(by_notifier_id, "id0"));
275  EXPECT_TRUE(IsInNotifications(by_notifier_id, "id1"));
276  EXPECT_TRUE(IsInNotifications(by_notifier_id, "id2"));
277  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id3"));
278  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id4"));
279  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id5"));
280
281  by_notifier_id = notification_list()->GetNotificationsByNotifierId(id1);
282  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id0"));
283  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id1"));
284  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id2"));
285  EXPECT_TRUE(IsInNotifications(by_notifier_id, "id3"));
286  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id4"));
287  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id5"));
288
289  by_notifier_id = notification_list()->GetNotificationsByNotifierId(id2);
290  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id0"));
291  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id1"));
292  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id2"));
293  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id3"));
294  EXPECT_TRUE(IsInNotifications(by_notifier_id, "id4"));
295  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id5"));
296
297  by_notifier_id = notification_list()->GetNotificationsByNotifierId(id3);
298  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id0"));
299  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id1"));
300  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id2"));
301  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id3"));
302  EXPECT_FALSE(IsInNotifications(by_notifier_id, "id4"));
303  EXPECT_TRUE(IsInNotifications(by_notifier_id, "id5"));
304}
305
306TEST_F(NotificationListTest, OldPopupShouldNotBeHidden) {
307  std::vector<std::string> ids;
308  for (size_t i = 0; i <= kMaxVisiblePopupNotifications; i++)
309    ids.push_back(AddNotification());
310
311  NotificationList::PopupNotifications popups = GetPopups();
312  // The popup should contain the oldest kMaxVisiblePopupNotifications. Newer
313  // one should come earlier in the popup list. It means, the last element
314  // of |popups| should be the firstly added one, and so on.
315  EXPECT_EQ(kMaxVisiblePopupNotifications, popups.size());
316  NotificationList::PopupNotifications::const_reverse_iterator iter =
317      popups.rbegin();
318  for (size_t i = 0; i < kMaxVisiblePopupNotifications; ++i, ++iter) {
319    EXPECT_EQ(ids[i], (*iter)->id()) << i;
320  }
321
322  for (NotificationList::PopupNotifications::const_iterator iter =
323           popups.begin(); iter != popups.end(); ++iter) {
324    notification_list()->MarkSinglePopupAsShown((*iter)->id(), false);
325  }
326  popups.clear();
327  popups = GetPopups();
328  EXPECT_EQ(1u, popups.size());
329  EXPECT_EQ(ids[ids.size() - 1], (*popups.begin())->id());
330}
331
332TEST_F(NotificationListTest, Priority) {
333  ASSERT_EQ(0u, notification_list()->NotificationCount(blockers()));
334  ASSERT_EQ(0u, notification_list()->UnreadCount(blockers()));
335
336  // Default priority has the limit on the number of the popups.
337  for (size_t i = 0; i <= kMaxVisiblePopupNotifications; ++i)
338    AddNotification();
339  EXPECT_EQ(kMaxVisiblePopupNotifications + 1,
340            notification_list()->NotificationCount(blockers()));
341  EXPECT_EQ(kMaxVisiblePopupNotifications, GetPopupCounts());
342
343  // Low priority: not visible to popups.
344  notification_list()->SetMessageCenterVisible(true, NULL);
345  notification_list()->SetMessageCenterVisible(false, NULL);
346  EXPECT_EQ(0u, notification_list()->UnreadCount(blockers()));
347  AddPriorityNotification(LOW_PRIORITY);
348  EXPECT_EQ(kMaxVisiblePopupNotifications + 2,
349            notification_list()->NotificationCount(blockers()));
350  EXPECT_EQ(1u, notification_list()->UnreadCount(blockers()));
351  EXPECT_EQ(0u, GetPopupCounts());
352
353  // Minimum priority: doesn't update the unread count.
354  AddPriorityNotification(MIN_PRIORITY);
355  EXPECT_EQ(kMaxVisiblePopupNotifications + 3,
356            notification_list()->NotificationCount(blockers()));
357  EXPECT_EQ(1u, notification_list()->UnreadCount(blockers()));
358  EXPECT_EQ(0u, GetPopupCounts());
359
360  NotificationList::Notifications notifications =
361      notification_list()->GetVisibleNotifications(blockers());
362  for (NotificationList::Notifications::const_iterator iter =
363           notifications.begin(); iter != notifications.end(); ++iter) {
364    notification_list()->RemoveNotification((*iter)->id());
365  }
366
367  // Higher priority: no limits to the number of popups.
368  for (size_t i = 0; i < kMaxVisiblePopupNotifications * 2; ++i)
369    AddPriorityNotification(HIGH_PRIORITY);
370  for (size_t i = 0; i < kMaxVisiblePopupNotifications * 2; ++i)
371    AddPriorityNotification(MAX_PRIORITY);
372  EXPECT_EQ(kMaxVisiblePopupNotifications * 4,
373            notification_list()->NotificationCount(blockers()));
374  EXPECT_EQ(kMaxVisiblePopupNotifications * 4, GetPopupCounts());
375}
376
377TEST_F(NotificationListTest, HasPopupsWithPriority) {
378  ASSERT_EQ(0u, notification_list()->NotificationCount(blockers()));
379  ASSERT_EQ(0u, notification_list()->UnreadCount(blockers()));
380
381  AddPriorityNotification(MIN_PRIORITY);
382  AddPriorityNotification(MAX_PRIORITY);
383
384  EXPECT_EQ(1u, GetPopupCounts());
385}
386
387TEST_F(NotificationListTest, HasPopupsWithSystemPriority) {
388  ASSERT_EQ(0u, notification_list()->NotificationCount(blockers()));
389  ASSERT_EQ(0u, notification_list()->UnreadCount(blockers()));
390
391  std::string normal_id = AddPriorityNotification(DEFAULT_PRIORITY);
392  std::string system_id = AddNotification();
393  GetNotification(system_id)->SetSystemPriority();
394
395  EXPECT_EQ(2u, GetPopupCounts());
396
397  notification_list()->MarkSinglePopupAsDisplayed(normal_id);
398  notification_list()->MarkSinglePopupAsDisplayed(system_id);
399
400  notification_list()->MarkSinglePopupAsShown(normal_id, false);
401  notification_list()->MarkSinglePopupAsShown(system_id, false);
402
403  notification_list()->SetMessageCenterVisible(true, NULL);
404  notification_list()->SetMessageCenterVisible(false, NULL);
405  EXPECT_EQ(1u, GetPopupCounts());
406
407  // Mark as read -- emulation of mouse click.
408  notification_list()->MarkSinglePopupAsShown(system_id, true);
409  EXPECT_EQ(0u, GetPopupCounts());
410}
411
412TEST_F(NotificationListTest, PriorityPromotion) {
413  std::string id0 = AddPriorityNotification(LOW_PRIORITY);
414  std::string replaced = id0 + "_replaced";
415  EXPECT_EQ(1u, notification_list()->NotificationCount(blockers()));
416  EXPECT_EQ(0u, GetPopupCounts());
417  message_center::RichNotificationData optional;
418  optional.priority = 1;
419  scoped_ptr<Notification> notification(
420      new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
421                       replaced,
422                       UTF8ToUTF16("newtitle"),
423                       UTF8ToUTF16("newbody"),
424                       gfx::Image(),
425                       UTF8ToUTF16(kDisplaySource),
426                       NotifierId(NotifierId::APPLICATION, kExtensionId),
427                       optional,
428                       NULL));
429  notification_list()->UpdateNotificationMessage(id0, notification.Pass());
430  EXPECT_EQ(1u, notification_list()->NotificationCount(blockers()));
431  EXPECT_EQ(1u, GetPopupCounts());
432  const NotificationList::Notifications notifications =
433      notification_list()->GetVisibleNotifications(blockers());
434  EXPECT_EQ(replaced, (*notifications.begin())->id());
435  EXPECT_EQ(UTF8ToUTF16("newtitle"), (*notifications.begin())->title());
436  EXPECT_EQ(UTF8ToUTF16("newbody"), (*notifications.begin())->message());
437  EXPECT_EQ(1, (*notifications.begin())->priority());
438}
439
440TEST_F(NotificationListTest, PriorityPromotionWithPopups) {
441  std::string id0 = AddPriorityNotification(LOW_PRIORITY);
442  std::string id1 = AddPriorityNotification(DEFAULT_PRIORITY);
443  EXPECT_EQ(1u, GetPopupCounts());
444  notification_list()->MarkSinglePopupAsShown(id1, true);
445  EXPECT_EQ(0u, GetPopupCounts());
446
447  // id0 promoted to LOW->DEFAULT, it'll appear as toast (popup).
448  message_center::RichNotificationData priority;
449  priority.priority = DEFAULT_PRIORITY;
450  scoped_ptr<Notification> notification(
451      new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
452                       id0,
453                       UTF8ToUTF16("newtitle"),
454                       UTF8ToUTF16("newbody"),
455                       gfx::Image(),
456                       UTF8ToUTF16(kDisplaySource),
457                       NotifierId(NotifierId::APPLICATION, kExtensionId),
458                       priority,
459                       NULL));
460  notification_list()->UpdateNotificationMessage(id0, notification.Pass());
461  EXPECT_EQ(1u, GetPopupCounts());
462  notification_list()->MarkSinglePopupAsShown(id0, true);
463  EXPECT_EQ(0u, GetPopupCounts());
464
465  // update with no promotion change for id0, it won't appear as a toast.
466  notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
467                                      id0,
468                                      UTF8ToUTF16("newtitle2"),
469                                      UTF8ToUTF16("newbody2"),
470                                      gfx::Image(),
471                                      UTF8ToUTF16(kDisplaySource),
472                                      NotifierId(NotifierId::APPLICATION,
473                                                 kExtensionId),
474                                      priority,
475                                      NULL));
476  notification_list()->UpdateNotificationMessage(id0, notification.Pass());
477  EXPECT_EQ(0u, GetPopupCounts());
478
479  // id1 promoted to DEFAULT->HIGH, it'll appear as toast (popup).
480  priority.priority = HIGH_PRIORITY;
481  notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
482                                      id1,
483                                      UTF8ToUTF16("newtitle"),
484                                      UTF8ToUTF16("newbody"),
485                                      gfx::Image(),
486                                      UTF8ToUTF16(kDisplaySource),
487                                      NotifierId(NotifierId::APPLICATION,
488                                                 kExtensionId),
489                                      priority,
490                                      NULL));
491  notification_list()->UpdateNotificationMessage(id1, notification.Pass());
492  EXPECT_EQ(1u, GetPopupCounts());
493  notification_list()->MarkSinglePopupAsShown(id1, true);
494  EXPECT_EQ(0u, GetPopupCounts());
495
496  // id1 promoted to HIGH->MAX, it'll appear as toast again.
497  priority.priority = MAX_PRIORITY;
498  notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
499                                      id1,
500                                      UTF8ToUTF16("newtitle2"),
501                                      UTF8ToUTF16("newbody2"),
502                                      gfx::Image(),
503                                      UTF8ToUTF16(kDisplaySource),
504                                      NotifierId(NotifierId::APPLICATION,
505                                                 kExtensionId),
506                                      priority,
507                                      NULL));
508  notification_list()->UpdateNotificationMessage(id1, notification.Pass());
509  EXPECT_EQ(1u, GetPopupCounts());
510  notification_list()->MarkSinglePopupAsShown(id1, true);
511  EXPECT_EQ(0u, GetPopupCounts());
512
513  // id1 demoted to MAX->DEFAULT, no appearing as toast.
514  priority.priority = DEFAULT_PRIORITY;
515  notification.reset(new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
516                                      id1,
517                                      UTF8ToUTF16("newtitle3"),
518                                      UTF8ToUTF16("newbody3"),
519                                      gfx::Image(),
520                                      UTF8ToUTF16(kDisplaySource),
521                                      NotifierId(NotifierId::APPLICATION,
522                                                 kExtensionId),
523                                      priority,
524                                      NULL));
525  notification_list()->UpdateNotificationMessage(id1, notification.Pass());
526  EXPECT_EQ(0u, GetPopupCounts());
527}
528
529TEST_F(NotificationListTest, NotificationOrderAndPriority) {
530  base::Time now = base::Time::Now();
531  message_center::RichNotificationData optional;
532  optional.timestamp = now;
533  optional.priority = 2;
534  std::string max_id = AddNotification(optional);
535
536  now += base::TimeDelta::FromSeconds(1);
537  optional.timestamp = now;
538  optional.priority = 1;
539  std::string high_id = AddNotification(optional);
540
541  now += base::TimeDelta::FromSeconds(1);
542  optional.timestamp = now;
543  optional.priority = 0;
544  std::string default_id = AddNotification(optional);
545
546  {
547    // Popups: latest comes first.
548    NotificationList::PopupNotifications popups = GetPopups();
549    EXPECT_EQ(3u, popups.size());
550    NotificationList::PopupNotifications::const_iterator iter = popups.begin();
551    EXPECT_EQ(default_id, (*iter)->id());
552    iter++;
553    EXPECT_EQ(high_id, (*iter)->id());
554    iter++;
555    EXPECT_EQ(max_id, (*iter)->id());
556  }
557  {
558    // Notifications: high priority comes ealier.
559    const NotificationList::Notifications notifications =
560        notification_list()->GetVisibleNotifications(blockers());
561    EXPECT_EQ(3u, notifications.size());
562    NotificationList::Notifications::const_iterator iter =
563        notifications.begin();
564    EXPECT_EQ(max_id, (*iter)->id());
565    iter++;
566    EXPECT_EQ(high_id, (*iter)->id());
567    iter++;
568    EXPECT_EQ(default_id, (*iter)->id());
569  }
570}
571
572TEST_F(NotificationListTest, MarkSinglePopupAsShown) {
573  std::string id1 = AddNotification();
574  std::string id2 = AddNotification();
575  std::string id3 = AddNotification();
576  ASSERT_EQ(3u, notification_list()->NotificationCount(blockers()));
577  ASSERT_EQ(std::min(static_cast<size_t>(3u), kMaxVisiblePopupNotifications),
578            GetPopupCounts());
579  notification_list()->MarkSinglePopupAsDisplayed(id1);
580  notification_list()->MarkSinglePopupAsDisplayed(id2);
581  notification_list()->MarkSinglePopupAsDisplayed(id3);
582
583  notification_list()->MarkSinglePopupAsShown(id2, true);
584  notification_list()->MarkSinglePopupAsShown(id3, false);
585  EXPECT_EQ(3u, notification_list()->NotificationCount(blockers()));
586  EXPECT_EQ(1u, notification_list()->UnreadCount(blockers()));
587  EXPECT_EQ(1u, GetPopupCounts());
588  NotificationList::PopupNotifications popups = GetPopups();
589  EXPECT_EQ(id1, (*popups.begin())->id());
590
591  // The notifications in the NotificationCenter are unaffected by popups shown.
592  NotificationList::Notifications notifications =
593      notification_list()->GetVisibleNotifications(blockers());
594  NotificationList::Notifications::const_iterator iter = notifications.begin();
595  EXPECT_EQ(id3, (*iter)->id());
596  iter++;
597  EXPECT_EQ(id2, (*iter)->id());
598  iter++;
599  EXPECT_EQ(id1, (*iter)->id());
600}
601
602TEST_F(NotificationListTest, UpdateAfterMarkedAsShown) {
603  std::string id1 = AddNotification();
604  std::string id2 = AddNotification();
605  notification_list()->MarkSinglePopupAsDisplayed(id1);
606  notification_list()->MarkSinglePopupAsDisplayed(id2);
607
608  EXPECT_EQ(2u, GetPopupCounts());
609
610  const Notification* n1 = GetNotification(id1);
611  EXPECT_FALSE(n1->shown_as_popup());
612  EXPECT_TRUE(n1->IsRead());
613
614  notification_list()->MarkSinglePopupAsShown(id1, true);
615
616  n1 = GetNotification(id1);
617  EXPECT_TRUE(n1->shown_as_popup());
618  EXPECT_TRUE(n1->IsRead());
619
620  const std::string replaced("test-replaced-id");
621  scoped_ptr<Notification> notification(
622      new Notification(message_center::NOTIFICATION_TYPE_SIMPLE,
623                       replaced,
624                       UTF8ToUTF16("newtitle"),
625                       UTF8ToUTF16("newbody"),
626                       gfx::Image(),
627                       UTF8ToUTF16(kDisplaySource),
628                       NotifierId(NotifierId::APPLICATION, kExtensionId),
629                       message_center::RichNotificationData(),
630                       NULL));
631  notification_list()->UpdateNotificationMessage(id1, notification.Pass());
632  n1 = GetNotification(id1);
633  EXPECT_TRUE(n1 == NULL);
634  const Notification* nr = GetNotification(replaced);
635  EXPECT_TRUE(nr->shown_as_popup());
636  EXPECT_TRUE(nr->IsRead());
637}
638
639TEST_F(NotificationListTest, QuietMode) {
640  notification_list()->SetQuietMode(true);
641  AddNotification();
642  AddPriorityNotification(HIGH_PRIORITY);
643  AddPriorityNotification(MAX_PRIORITY);
644  EXPECT_EQ(3u, notification_list()->NotificationCount(blockers()));
645  EXPECT_EQ(0u, GetPopupCounts());
646
647  notification_list()->SetQuietMode(false);
648  AddNotification();
649  EXPECT_EQ(4u, notification_list()->NotificationCount(blockers()));
650  EXPECT_EQ(1u, GetPopupCounts());
651
652  // TODO(mukai): Add test of quiet mode with expiration.
653}
654
655// Verifies that unread_count doesn't become negative.
656TEST_F(NotificationListTest, UnreadCountNoNegative) {
657  std::string id = AddNotification();
658  EXPECT_EQ(1u, notification_list()->UnreadCount(blockers()));
659
660  notification_list()->MarkSinglePopupAsDisplayed(id);
661  EXPECT_EQ(0u, notification_list()->UnreadCount(blockers()));
662  notification_list()->MarkSinglePopupAsShown(
663      id, false /* mark_notification_as_read */);
664  EXPECT_EQ(1u, notification_list()->UnreadCount(blockers()));
665
666  // Updates the notification  and verifies unread_count doesn't change.
667  scoped_ptr<Notification> updated_notification(new Notification(
668      message_center::NOTIFICATION_TYPE_SIMPLE,
669      id,
670      UTF8ToUTF16("updated"),
671      UTF8ToUTF16("updated"),
672      gfx::Image(),
673      base::string16(),
674      NotifierId(),
675      RichNotificationData(),
676      NULL));
677  notification_list()->AddNotification(updated_notification.Pass());
678  EXPECT_EQ(1u, notification_list()->UnreadCount(blockers()));
679}
680
681TEST_F(NotificationListTest, TestPushingShownNotification) {
682  // Create a notification and mark it as shown.
683  std::string id1;
684  scoped_ptr<Notification> notification(MakeNotification(&id1));
685  notification->set_shown_as_popup(true);
686
687  // Call PushNotification on this notification.
688  notification_list()->PushNotification(notification.Pass());
689
690  // Ensure it is still marked as shown.
691  EXPECT_TRUE(GetNotification(id1)->shown_as_popup());
692}
693
694TEST_F(NotificationListTest, TestHasNotificationOfType) {
695  std::string id = AddNotification();
696
697  EXPECT_TRUE(notification_list()->HasNotificationOfType(
698      id, message_center::NOTIFICATION_TYPE_SIMPLE));
699  EXPECT_FALSE(notification_list()->HasNotificationOfType(
700      id, message_center::NOTIFICATION_TYPE_PROGRESS));
701
702  scoped_ptr<Notification> updated_notification(new Notification(
703      message_center::NOTIFICATION_TYPE_PROGRESS,
704      id,
705      UTF8ToUTF16("updated"),
706      UTF8ToUTF16("updated"),
707      gfx::Image(),
708      base::string16(),
709      NotifierId(),
710      RichNotificationData(),
711      NULL));
712  notification_list()->AddNotification(updated_notification.Pass());
713
714  EXPECT_FALSE(notification_list()->HasNotificationOfType(
715      id, message_center::NOTIFICATION_TYPE_SIMPLE));
716  EXPECT_TRUE(notification_list()->HasNotificationOfType(
717      id, message_center::NOTIFICATION_TYPE_PROGRESS));
718}
719
720}  // namespace message_center
721