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.
5 #include "ui/message_center/notification_list.h"
7 #include "base/basictypes.h"
8 #include "base/i18n/time_formatting.h"
9 #include "base/stringprintf.h"
10 #include "base/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_types.h"
16 namespace message_center
{
19 class NotificationListTest
: public testing::Test
{
21 NotificationListTest() {}
22 virtual ~NotificationListTest() {}
24 virtual void SetUp() {
25 notification_list_
.reset(new NotificationList());
30 // Currently NotificationListTest doesn't care about some fields like title or
31 // message, so put a simple template on it. Returns the id of the new
33 std::string
AddNotification(const base::DictionaryValue
* optional_fields
) {
34 std::string new_id
= base::StringPrintf(kIdFormat
, counter_
);
35 notification_list_
->AddNotification(
36 message_center::NOTIFICATION_TYPE_SIMPLE
,
38 UTF8ToUTF16(base::StringPrintf(kTitleFormat
, counter_
)),
39 UTF8ToUTF16(base::StringPrintf(kMessageFormat
, counter_
)),
40 UTF8ToUTF16(kDisplaySource
),
48 // Utility methods of AddNotification.
49 std::string
AddPriorityNotification(NotificationPriority priority
) {
50 base::DictionaryValue optional
;
51 optional
.SetInteger(message_center::kPriorityKey
,
52 static_cast<int>(priority
));
53 return AddNotification(&optional
);
55 void SetupTimestampKey(const base::Time
& time
,
56 base::DictionaryValue
* optional
) {
57 string16 time_formatted
= base::TimeFormatShortDateAndTime(time
);
58 optional
->SetString(message_center::kTimestampKey
, time_formatted
);
61 size_t GetPopupCounts() {
62 return notification_list()->GetPopupNotifications().size();
65 Notification
* GetNotification(const std::string
& id
) {
66 NotificationList::Notifications::iterator iter
=
67 notification_list()->GetNotification(id
);
68 if (iter
== notification_list()->GetNotifications().end())
73 NotificationList
* notification_list() { return notification_list_
.get(); }
76 static const char kIdFormat
[];
77 static const char kTitleFormat
[];
78 static const char kMessageFormat
[];
79 static const char kDisplaySource
[];
80 static const char kExtensionId
[];
82 scoped_ptr
<NotificationList
> notification_list_
;
85 DISALLOW_COPY_AND_ASSIGN(NotificationListTest
);
88 bool IsInNotifications(const NotificationList::Notifications
& notifications
,
89 const std::string
& id
) {
90 for (NotificationList::Notifications::const_iterator iter
=
91 notifications
.begin(); iter
!= notifications
.end(); ++iter
) {
92 if ((*iter
)->id() == id
)
98 const char NotificationListTest::kIdFormat
[] = "id%ld";
99 const char NotificationListTest::kTitleFormat
[] = "id%ld";
100 const char NotificationListTest::kMessageFormat
[] = "message%ld";
101 const char NotificationListTest::kDisplaySource
[] = "source";
102 const char NotificationListTest::kExtensionId
[] = "ext";
104 TEST_F(NotificationListTest
, Basic
) {
105 ASSERT_EQ(0u, notification_list()->NotificationCount());
106 ASSERT_EQ(0u, notification_list()->unread_count());
108 std::string id0
= AddNotification(NULL
);
109 EXPECT_EQ(1u, notification_list()->NotificationCount());
110 std::string id1
= AddNotification(NULL
);
111 EXPECT_EQ(2u, notification_list()->NotificationCount());
112 EXPECT_EQ(2u, notification_list()->unread_count());
114 EXPECT_TRUE(notification_list()->HasPopupNotifications());
115 EXPECT_TRUE(notification_list()->HasNotification(id0
));
116 EXPECT_TRUE(notification_list()->HasNotification(id1
));
117 EXPECT_FALSE(notification_list()->HasNotification(id1
+ "foo"));
119 EXPECT_EQ(2u, GetPopupCounts());
121 notification_list()->MarkPopupsAsShown(0);
122 EXPECT_EQ(2u, notification_list()->NotificationCount());
123 EXPECT_EQ(0u, GetPopupCounts());
125 notification_list()->RemoveNotification(id0
);
126 EXPECT_EQ(1u, notification_list()->NotificationCount());
127 EXPECT_EQ(1u, notification_list()->unread_count());
129 AddNotification(NULL
);
130 EXPECT_EQ(2u, notification_list()->NotificationCount());
132 notification_list()->RemoveAllNotifications();
133 EXPECT_EQ(0u, notification_list()->NotificationCount());
134 EXPECT_EQ(0u, notification_list()->unread_count());
137 TEST_F(NotificationListTest
, MessageCenterVisible
) {
138 AddNotification(NULL
);
139 EXPECT_EQ(1u, notification_list()->NotificationCount());
140 ASSERT_EQ(1u, notification_list()->unread_count());
141 ASSERT_EQ(1u, GetPopupCounts());
143 // Make the message center visible. It resets the unread count and popup
145 notification_list()->SetMessageCenterVisible(true, NULL
);
146 ASSERT_EQ(0u, notification_list()->unread_count());
147 ASSERT_EQ(0u, GetPopupCounts());
150 TEST_F(NotificationListTest
, UnreadCount
) {
151 std::string id0
= AddNotification(NULL
);
152 std::string id1
= AddNotification(NULL
);
153 ASSERT_EQ(2u, notification_list()->unread_count());
155 notification_list()->MarkSinglePopupAsDisplayed(id0
);
156 EXPECT_EQ(1u, notification_list()->unread_count());
157 notification_list()->MarkSinglePopupAsDisplayed(id0
);
158 EXPECT_EQ(1u, notification_list()->unread_count());
159 notification_list()->MarkSinglePopupAsDisplayed(id1
);
160 EXPECT_EQ(0u, notification_list()->unread_count());
163 TEST_F(NotificationListTest
, UpdateNotification
) {
164 std::string id0
= AddNotification(NULL
);
165 std::string replaced
= id0
+ "_replaced";
166 EXPECT_EQ(1u, notification_list()->NotificationCount());
167 notification_list()->UpdateNotificationMessage(id0
,
169 UTF8ToUTF16("newtitle"),
170 UTF8ToUTF16("newbody"),
173 EXPECT_EQ(1u, notification_list()->NotificationCount());
174 const NotificationList::Notifications
& notifications
=
175 notification_list()->GetNotifications();
176 EXPECT_EQ(replaced
, (*notifications
.begin())->id());
177 EXPECT_EQ(UTF8ToUTF16("newtitle"), (*notifications
.begin())->title());
178 EXPECT_EQ(UTF8ToUTF16("newbody"), (*notifications
.begin())->message());
181 TEST_F(NotificationListTest
, GetNotificationsBySourceOrExtensions
) {
182 notification_list()->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE
,
184 UTF8ToUTF16("title0"),
185 UTF8ToUTF16("message0"),
186 UTF8ToUTF16("source0"),
190 notification_list()->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE
,
192 UTF8ToUTF16("title1"),
193 UTF8ToUTF16("message1"),
194 UTF8ToUTF16("source0"),
198 notification_list()->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE
,
200 UTF8ToUTF16("title1"),
201 UTF8ToUTF16("message1"),
202 UTF8ToUTF16("source1"),
206 notification_list()->AddNotification(message_center::NOTIFICATION_TYPE_SIMPLE
,
208 UTF8ToUTF16("title1"),
209 UTF8ToUTF16("message1"),
210 UTF8ToUTF16("source2"),
215 NotificationList::Notifications by_source
=
216 notification_list()->GetNotificationsBySource("id0");
217 EXPECT_TRUE(IsInNotifications(by_source
, "id0"));
218 EXPECT_TRUE(IsInNotifications(by_source
, "id1"));
219 EXPECT_FALSE(IsInNotifications(by_source
, "id2"));
220 EXPECT_FALSE(IsInNotifications(by_source
, "id3"));
222 NotificationList::Notifications by_extension
=
223 notification_list()->GetNotificationsByExtension("id0");
224 EXPECT_TRUE(IsInNotifications(by_extension
, "id0"));
225 EXPECT_TRUE(IsInNotifications(by_extension
, "id1"));
226 EXPECT_TRUE(IsInNotifications(by_extension
, "id2"));
227 EXPECT_FALSE(IsInNotifications(by_extension
, "id3"));
230 TEST_F(NotificationListTest
, OldPopupShouldNotBeHidden
) {
231 std::vector
<std::string
> ids
;
232 for (size_t i
= 0; i
<= kMaxVisiblePopupNotifications
; i
++)
233 ids
.push_back(AddNotification(NULL
));
235 NotificationList::PopupNotifications popups
=
236 notification_list()->GetPopupNotifications();
237 // The popup should contain the oldest kMaxVisiblePopupNotifications. Newer
238 // one should come earlier in the popup list. It means, the last element
239 // of |popups| should be the firstly added one, and so on.
240 EXPECT_EQ(kMaxVisiblePopupNotifications
, popups
.size());
241 NotificationList::PopupNotifications::const_reverse_iterator iter
=
243 for (size_t i
= 0; i
< kMaxVisiblePopupNotifications
; ++i
, ++iter
) {
244 EXPECT_EQ(ids
[i
], (*iter
)->id()) << i
;
247 notification_list()->MarkPopupsAsShown(message_center::DEFAULT_PRIORITY
);
249 popups
= notification_list()->GetPopupNotifications();
250 EXPECT_EQ(1u, popups
.size());
251 EXPECT_EQ(ids
[ids
.size() - 1], (*popups
.begin())->id());
254 TEST_F(NotificationListTest
, Priority
) {
255 ASSERT_EQ(0u, notification_list()->NotificationCount());
256 ASSERT_EQ(0u, notification_list()->unread_count());
258 // Default priority has the limit on the number of the popups.
259 for (size_t i
= 0; i
<= kMaxVisiblePopupNotifications
; ++i
)
260 AddNotification(NULL
);
261 EXPECT_EQ(kMaxVisiblePopupNotifications
+ 1,
262 notification_list()->NotificationCount());
263 EXPECT_EQ(kMaxVisiblePopupNotifications
, GetPopupCounts());
265 // Low priority: not visible to popups.
266 notification_list()->SetMessageCenterVisible(true, NULL
);
267 notification_list()->SetMessageCenterVisible(false, NULL
);
268 EXPECT_EQ(0u, notification_list()->unread_count());
269 AddPriorityNotification(LOW_PRIORITY
);
270 EXPECT_EQ(kMaxVisiblePopupNotifications
+ 2,
271 notification_list()->NotificationCount());
272 EXPECT_EQ(1u, notification_list()->unread_count());
273 EXPECT_EQ(0u, GetPopupCounts());
275 // Minimum priority: doesn't update the unread count.
276 AddPriorityNotification(MIN_PRIORITY
);
277 EXPECT_EQ(kMaxVisiblePopupNotifications
+ 3,
278 notification_list()->NotificationCount());
279 EXPECT_EQ(1u, notification_list()->unread_count());
280 EXPECT_EQ(0u, GetPopupCounts());
282 notification_list()->RemoveAllNotifications();
284 // Higher priority: no limits to the number of popups.
285 for (size_t i
= 0; i
< kMaxVisiblePopupNotifications
* 2; ++i
)
286 AddPriorityNotification(HIGH_PRIORITY
);
287 for (size_t i
= 0; i
< kMaxVisiblePopupNotifications
* 2; ++i
)
288 AddPriorityNotification(MAX_PRIORITY
);
289 EXPECT_EQ(kMaxVisiblePopupNotifications
* 4,
290 notification_list()->NotificationCount());
291 EXPECT_EQ(kMaxVisiblePopupNotifications
* 4, GetPopupCounts());
294 TEST_F(NotificationListTest
, HasPopupsWithPriority
) {
295 ASSERT_EQ(0u, notification_list()->NotificationCount());
296 ASSERT_EQ(0u, notification_list()->unread_count());
298 AddPriorityNotification(MIN_PRIORITY
);
299 AddPriorityNotification(MAX_PRIORITY
);
301 EXPECT_EQ(1u, GetPopupCounts());
304 TEST_F(NotificationListTest
, PriorityPromotion
) {
305 std::string id0
= AddPriorityNotification(LOW_PRIORITY
);
306 std::string replaced
= id0
+ "_replaced";
307 EXPECT_EQ(1u, notification_list()->NotificationCount());
308 EXPECT_EQ(0u, GetPopupCounts());
309 base::DictionaryValue optional
;
310 optional
.SetInteger(message_center::kPriorityKey
, 1);
311 notification_list()->UpdateNotificationMessage(id0
,
313 UTF8ToUTF16("newtitle"),
314 UTF8ToUTF16("newbody"),
317 EXPECT_EQ(1u, notification_list()->NotificationCount());
318 EXPECT_EQ(1u, GetPopupCounts());
319 const NotificationList::Notifications
& notifications
=
320 notification_list()->GetNotifications();
321 EXPECT_EQ(replaced
, (*notifications
.begin())->id());
322 EXPECT_EQ(UTF8ToUTF16("newtitle"), (*notifications
.begin())->title());
323 EXPECT_EQ(UTF8ToUTF16("newbody"), (*notifications
.begin())->message());
324 EXPECT_EQ(1, (*notifications
.begin())->priority());
327 TEST_F(NotificationListTest
, PriorityPromotionWithPopups
) {
328 std::string id0
= AddPriorityNotification(LOW_PRIORITY
);
329 std::string id1
= AddPriorityNotification(DEFAULT_PRIORITY
);
330 EXPECT_EQ(1u, GetPopupCounts());
331 notification_list()->MarkSinglePopupAsShown(id1
, true);
332 EXPECT_EQ(0u, GetPopupCounts());
334 // id0 promoted to LOW->DEFAULT, it'll appear as toast (popup).
335 base::DictionaryValue priority_default
;
336 priority_default
.SetInteger(message_center::kPriorityKey
,
337 static_cast<int>(DEFAULT_PRIORITY
));
338 notification_list()->UpdateNotificationMessage(id0
,
340 UTF8ToUTF16("newtitle"),
341 UTF8ToUTF16("newbody"),
344 EXPECT_EQ(1u, GetPopupCounts());
345 notification_list()->MarkSinglePopupAsShown(id0
, true);
346 EXPECT_EQ(0u, GetPopupCounts());
348 // update with no promotion change for id0, it won't appear as a toast.
349 notification_list()->UpdateNotificationMessage(
350 id0
, id0
, UTF8ToUTF16("newtitle2"), UTF8ToUTF16("newbody2"), NULL
, NULL
);
351 EXPECT_EQ(0u, GetPopupCounts());
353 // id1 promoted to DEFAULT->HIGH, it'll appear as toast (popup).
354 base::DictionaryValue priority_high
;
355 priority_high
.SetInteger(message_center::kPriorityKey
,
356 static_cast<int>(HIGH_PRIORITY
));
357 notification_list()->UpdateNotificationMessage(id1
,
359 UTF8ToUTF16("newtitle"),
360 UTF8ToUTF16("newbody"),
363 EXPECT_EQ(1u, GetPopupCounts());
364 notification_list()->MarkSinglePopupAsShown(id1
, true);
365 EXPECT_EQ(0u, GetPopupCounts());
367 // id1 promoted to HIGH->MAX, it'll appear as toast again.
368 base::DictionaryValue priority_max
;
369 priority_max
.SetInteger(message_center::kPriorityKey
,
370 static_cast<int>(MAX_PRIORITY
));
371 notification_list()->UpdateNotificationMessage(id1
,
373 UTF8ToUTF16("newtitle2"),
374 UTF8ToUTF16("newbody2"),
377 EXPECT_EQ(1u, GetPopupCounts());
378 notification_list()->MarkSinglePopupAsShown(id1
, true);
379 EXPECT_EQ(0u, GetPopupCounts());
381 // id1 demoted to MAX->DEFAULT, no appearing as toast.
382 notification_list()->UpdateNotificationMessage(id1
,
384 UTF8ToUTF16("newtitle3"),
385 UTF8ToUTF16("newbody3"),
388 EXPECT_EQ(0u, GetPopupCounts());
391 TEST_F(NotificationListTest
, NotificationOrderAndPriority
) {
392 base::Time now
= base::Time::Now();
393 base::DictionaryValue optional
;
394 SetupTimestampKey(now
, &optional
);
395 optional
.SetInteger(message_center::kPriorityKey
, 2);
396 std::string max_id
= AddNotification(&optional
);
397 now
+= base::TimeDelta::FromSeconds(1);
398 SetupTimestampKey(now
, &optional
);
399 optional
.SetInteger(message_center::kPriorityKey
, 1);
400 std::string high_id
= AddNotification(&optional
);
401 now
+= base::TimeDelta::FromSeconds(1);
402 SetupTimestampKey(now
, &optional
);
403 optional
.SetInteger(message_center::kPriorityKey
, 0);
404 std::string default_id
= AddNotification(&optional
);
407 // Popups: latest comes first.
408 NotificationList::PopupNotifications popups
=
409 notification_list()->GetPopupNotifications();
410 EXPECT_EQ(3u, popups
.size());
411 NotificationList::PopupNotifications::const_iterator iter
= popups
.begin();
412 EXPECT_EQ(default_id
, (*iter
)->id());
414 EXPECT_EQ(high_id
, (*iter
)->id());
416 EXPECT_EQ(max_id
, (*iter
)->id());
419 // Notifications: high priority comes ealier.
420 const NotificationList::Notifications
& notifications
=
421 notification_list()->GetNotifications();
422 EXPECT_EQ(3u, notifications
.size());
423 NotificationList::Notifications::const_iterator iter
=
424 notifications
.begin();
425 EXPECT_EQ(max_id
, (*iter
)->id());
427 EXPECT_EQ(high_id
, (*iter
)->id());
429 EXPECT_EQ(default_id
, (*iter
)->id());
433 TEST_F(NotificationListTest
, MarkSinglePopupAsShown
) {
434 std::string id1
= AddNotification(NULL
);
435 std::string id2
= AddNotification(NULL
);
436 std::string id3
= AddNotification(NULL
);
437 ASSERT_EQ(3u, notification_list()->NotificationCount());
438 ASSERT_EQ(std::min(static_cast<size_t>(3u), kMaxVisiblePopupNotifications
),
440 notification_list()->MarkSinglePopupAsDisplayed(id1
);
441 notification_list()->MarkSinglePopupAsDisplayed(id2
);
442 notification_list()->MarkSinglePopupAsDisplayed(id3
);
444 notification_list()->MarkSinglePopupAsShown(id2
, true);
445 notification_list()->MarkSinglePopupAsShown(id3
, false);
446 EXPECT_EQ(3u, notification_list()->NotificationCount());
447 EXPECT_EQ(1u, notification_list()->unread_count());
448 EXPECT_EQ(1u, GetPopupCounts());
449 NotificationList::PopupNotifications popups
=
450 notification_list()->GetPopupNotifications();
451 EXPECT_EQ(id1
, (*popups
.begin())->id());
453 // The notifications in the NotificationCenter are unaffected by popups shown.
454 NotificationList::Notifications notifications
=
455 notification_list()->GetNotifications();
456 NotificationList::Notifications::const_iterator iter
= notifications
.begin();
457 EXPECT_EQ(id3
, (*iter
)->id());
459 EXPECT_EQ(id2
, (*iter
)->id());
461 EXPECT_EQ(id1
, (*iter
)->id());
463 // Trickier scenario.
464 notification_list()->MarkPopupsAsShown(message_center::DEFAULT_PRIORITY
);
465 std::string id4
= AddNotification(NULL
);
466 std::string id5
= AddNotification(NULL
);
467 std::string id6
= AddNotification(NULL
);
468 notification_list()->MarkSinglePopupAsShown(id5
, true);
472 popups
= notification_list()->GetPopupNotifications();
473 EXPECT_EQ(2u, popups
.size());
474 NotificationList::PopupNotifications::const_iterator iter
= popups
.begin();
475 EXPECT_EQ(id6
, (*iter
)->id());
477 EXPECT_EQ(id4
, (*iter
)->id());
480 notifications
.clear();
481 notifications
= notification_list()->GetNotifications();
482 EXPECT_EQ(6u, notifications
.size());
483 iter
= notifications
.begin();
484 EXPECT_EQ(id6
, (*iter
)->id());
486 EXPECT_EQ(id5
, (*iter
)->id());
488 EXPECT_EQ(id4
, (*iter
)->id());
490 EXPECT_EQ(id3
, (*iter
)->id());
492 EXPECT_EQ(id2
, (*iter
)->id());
494 EXPECT_EQ(id1
, (*iter
)->id());
497 TEST_F(NotificationListTest
, UpdateAfterMarkedAsShown
) {
498 std::string id1
= AddNotification(NULL
);
499 std::string id2
= AddNotification(NULL
);
500 notification_list()->MarkSinglePopupAsDisplayed(id1
);
501 notification_list()->MarkSinglePopupAsDisplayed(id2
);
503 EXPECT_EQ(2u, GetPopupCounts());
505 const Notification
* n1
= GetNotification(id1
);
506 EXPECT_FALSE(n1
->shown_as_popup());
507 EXPECT_TRUE(n1
->is_read());
509 notification_list()->MarkSinglePopupAsShown(id1
, true);
511 n1
= GetNotification(id1
);
512 EXPECT_TRUE(n1
->shown_as_popup());
513 EXPECT_TRUE(n1
->is_read());
515 const std::string
replaced("test-replaced-id");
516 notification_list()->UpdateNotificationMessage(id1
,
518 UTF8ToUTF16("newtitle"),
519 UTF8ToUTF16("newbody"),
522 n1
= GetNotification(id1
);
523 EXPECT_TRUE(n1
== NULL
);
524 const Notification
* nr
= GetNotification(replaced
);
525 EXPECT_TRUE(nr
->shown_as_popup());
526 EXPECT_TRUE(nr
->is_read());
529 TEST_F(NotificationListTest
, QuietMode
) {
530 notification_list()->SetQuietMode(true);
531 AddNotification(NULL
);
532 AddPriorityNotification(HIGH_PRIORITY
);
533 AddPriorityNotification(MAX_PRIORITY
);
534 EXPECT_EQ(3u, notification_list()->NotificationCount());
535 EXPECT_EQ(0u, GetPopupCounts());
536 // TODO(mukai): fix here when notification_list distinguish dismiss by quiet
537 // mode and by user operation.
538 EXPECT_EQ(0u, notification_list()->unread_count());
540 notification_list()->SetQuietMode(false);
541 AddNotification(NULL
);
542 EXPECT_EQ(4u, notification_list()->NotificationCount());
543 EXPECT_EQ(1u, GetPopupCounts());
545 // TODO(mukai): Add test of quiet mode with expiration.
549 } // namespace message_center