// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/message_center/notification_list.h" #include #include #include "base/i18n/time_formatting.h" #include "base/macros.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/message_center/fake_message_center.h" #include "ui/message_center/notification_blocker.h" #include "ui/message_center/public/cpp/message_center_constants.h" #include "ui/message_center/public/cpp/notification_types.h" #include "ui/message_center/public/cpp/notifier_id.h" using base::UTF8ToUTF16; namespace message_center { using NotificationState = NotificationList::NotificationState; class NotificationListTest : public testing::Test { public: NotificationListTest() {} ~NotificationListTest() override {} void SetUp() override { message_center_.reset(new FakeMessageCenter()); notification_list_.reset(new NotificationList(message_center_.get())); counter_ = 0; } protected: // Currently NotificationListTest doesn't care about some fields like title or // message, so put a simple template on it. Returns the id of the new // notification. std::string AddNotification(const RichNotificationData& optional_fields) { std::string new_id; std::unique_ptr notification( MakeNotification(optional_fields, &new_id)); notification_list_->AddNotification(std::move(notification)); counter_++; return new_id; } std::string AddNotification() { return AddNotification(RichNotificationData()); } // Construct a new notification for testing, but don't add it to the list yet. std::unique_ptr MakeNotification( const RichNotificationData& optional_fields, std::string* id_out) { *id_out = base::StringPrintf(kIdFormat, counter_); std::unique_ptr notification(new Notification( NOTIFICATION_TYPE_SIMPLE, *id_out, UTF8ToUTF16(base::StringPrintf(kTitleFormat, counter_)), UTF8ToUTF16(base::StringPrintf(kMessageFormat, counter_)), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierType::APPLICATION, kExtensionId), optional_fields, NULL)); return notification; } std::unique_ptr MakeNotification(std::string* id_out) { return MakeNotification(RichNotificationData(), id_out); } // Utility methods of AddNotification. std::string AddPriorityNotification(NotificationPriority priority) { RichNotificationData optional; optional.priority = priority; return AddNotification(optional); } NotificationList::PopupNotifications GetPopups() { return notification_list_->GetPopupNotifications(blockers_, NULL); } size_t GetPopupCounts() { return GetPopups().size(); } Notification* GetNotification(const std::string& id) { auto iter = notification_list_->GetNotification(id); if (iter == notification_list_->notifications_.end()) return NULL; return iter->first.get(); } NotificationState GetNotificationState(const std::string& id) { auto iter = notification_list_->GetNotification(id); EXPECT_FALSE(iter == notification_list_->notifications_.end()); return iter->second; } static const char kIdFormat[]; static const char kTitleFormat[]; static const char kMessageFormat[]; static const char kDisplaySource[]; static const char kExtensionId[]; std::unique_ptr message_center_; std::unique_ptr notification_list_; NotificationBlockers blockers_; size_t counter_; private: DISALLOW_COPY_AND_ASSIGN(NotificationListTest); }; bool IsInNotifications(const NotificationList::Notifications& notifications, const std::string& id) { for (auto iter = notifications.begin(); iter != notifications.end(); ++iter) { if ((*iter)->id() == id) return true; } return false; } const char NotificationListTest::kIdFormat[] = "id%ld"; const char NotificationListTest::kTitleFormat[] = "id%ld"; const char NotificationListTest::kMessageFormat[] = "message%ld"; const char NotificationListTest::kDisplaySource[] = "source"; const char NotificationListTest::kExtensionId[] = "ext"; TEST_F(NotificationListTest, Basic) { ASSERT_EQ(0u, notification_list_->NotificationCount(blockers_)); std::string id0 = AddNotification(); EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_)); std::string id1 = AddNotification(); EXPECT_EQ(2u, notification_list_->NotificationCount(blockers_)); EXPECT_TRUE(notification_list_->HasPopupNotifications(blockers_)); EXPECT_TRUE(notification_list_->GetNotificationById(id0)); EXPECT_TRUE(notification_list_->GetNotificationById(id1)); EXPECT_FALSE(notification_list_->GetNotificationById(id1 + "foo")); EXPECT_EQ(2u, GetPopupCounts()); notification_list_->MarkSinglePopupAsShown(id0, true); notification_list_->MarkSinglePopupAsShown(id1, true); EXPECT_EQ(2u, notification_list_->NotificationCount(blockers_)); EXPECT_EQ(0u, GetPopupCounts()); notification_list_->RemoveNotification(id0); EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_)); AddNotification(); EXPECT_EQ(2u, notification_list_->NotificationCount(blockers_)); } TEST_F(NotificationListTest, MessageCenterVisible) { AddNotification(); EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_)); ASSERT_EQ(1u, GetPopupCounts()); // Resets the unread count and popup counts. notification_list_->SetNotificationsShown(blockers_, NULL); ASSERT_EQ(0u, GetPopupCounts()); } TEST_F(NotificationListTest, UpdateNotification) { std::string id0 = AddNotification(); std::string replaced = id0 + "_replaced"; EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_)); std::unique_ptr notification(new Notification( NOTIFICATION_TYPE_SIMPLE, replaced, UTF8ToUTF16("newtitle"), UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierType::APPLICATION, kExtensionId), RichNotificationData(), NULL)); notification_list_->UpdateNotificationMessage(id0, std::move(notification)); EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_)); const NotificationList::Notifications notifications = notification_list_->GetVisibleNotifications(blockers_); EXPECT_EQ(replaced, (*notifications.begin())->id()); EXPECT_EQ(UTF8ToUTF16("newtitle"), (*notifications.begin())->title()); EXPECT_EQ(UTF8ToUTF16("newbody"), (*notifications.begin())->message()); } TEST_F(NotificationListTest, UpdateNotificationWithRenotifyAndQuietMode) { for (size_t quiet_mode = 0u; quiet_mode < 2u; ++quiet_mode) { // Set Do Not Disturb mode. notification_list_->SetQuietMode(static_cast(quiet_mode)); // Create notification. std::string old_id; auto old_notification = MakeNotification(&old_id); notification_list_->AddNotification(std::move(old_notification)); notification_list_->MarkSinglePopupAsShown(old_id, true); EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_)); std::string new_id; auto new_notification = MakeNotification(&new_id); // Set the renotify flag and update. new_notification->set_renotify(true); notification_list_->UpdateNotificationMessage(old_id, std::move(new_notification)); const NotificationList::Notifications notifications = notification_list_->GetVisibleNotifications(blockers_); EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_)); EXPECT_EQ(new_id, (*notifications.begin())->id()); // Normally, |shown_as_popup| should be reset in order to show the popup // again. // In quiet mode, |shown_as_popup| should not be reset, as popup should not // be shown even though renotify was set. const NotificationList::PopupNotifications popup_notifications = notification_list_->GetPopupNotifications(blockers_, nullptr); if (quiet_mode) { ASSERT_EQ(0U, popup_notifications.size()); } else { ASSERT_EQ(1U, popup_notifications.size()); EXPECT_EQ(new_id, (*popup_notifications.begin())->id()); } } } TEST_F(NotificationListTest, GetNotificationsByNotifierId) { NotifierId id0(NotifierType::APPLICATION, "ext0"); NotifierId id1(NotifierType::APPLICATION, "ext1"); NotifierId id2(GURL("http://example.com")); NotifierId id3(NotifierType::SYSTEM_COMPONENT, "system-notifier"); std::unique_ptr notification(new Notification( NOTIFICATION_TYPE_SIMPLE, "id0", UTF8ToUTF16("title0"), UTF8ToUTF16("message0"), gfx::Image(), UTF8ToUTF16("source0"), GURL(), id0, RichNotificationData(), NULL)); notification_list_->AddNotification(std::move(notification)); notification.reset(new Notification( NOTIFICATION_TYPE_SIMPLE, "id1", UTF8ToUTF16("title1"), UTF8ToUTF16("message1"), gfx::Image(), UTF8ToUTF16("source0"), GURL(), id0, RichNotificationData(), NULL)); notification_list_->AddNotification(std::move(notification)); notification.reset(new Notification( NOTIFICATION_TYPE_SIMPLE, "id2", UTF8ToUTF16("title1"), UTF8ToUTF16("message1"), gfx::Image(), UTF8ToUTF16("source1"), GURL(), id0, RichNotificationData(), NULL)); notification_list_->AddNotification(std::move(notification)); notification.reset(new Notification( NOTIFICATION_TYPE_SIMPLE, "id3", UTF8ToUTF16("title1"), UTF8ToUTF16("message1"), gfx::Image(), UTF8ToUTF16("source2"), GURL(), id1, RichNotificationData(), NULL)); notification_list_->AddNotification(std::move(notification)); notification.reset(new Notification( NOTIFICATION_TYPE_SIMPLE, "id4", UTF8ToUTF16("title1"), UTF8ToUTF16("message1"), gfx::Image(), UTF8ToUTF16("source2"), GURL(), id2, RichNotificationData(), NULL)); notification_list_->AddNotification(std::move(notification)); notification.reset(new Notification( NOTIFICATION_TYPE_SIMPLE, "id5", UTF8ToUTF16("title1"), UTF8ToUTF16("message1"), gfx::Image(), UTF8ToUTF16("source2"), GURL(), id3, RichNotificationData(), NULL)); notification_list_->AddNotification(std::move(notification)); NotificationList::Notifications by_notifier_id = notification_list_->GetNotificationsByNotifierId(id0); EXPECT_TRUE(IsInNotifications(by_notifier_id, "id0")); EXPECT_TRUE(IsInNotifications(by_notifier_id, "id1")); EXPECT_TRUE(IsInNotifications(by_notifier_id, "id2")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id3")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id4")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id5")); by_notifier_id = notification_list_->GetNotificationsByNotifierId(id1); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id0")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id1")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id2")); EXPECT_TRUE(IsInNotifications(by_notifier_id, "id3")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id4")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id5")); by_notifier_id = notification_list_->GetNotificationsByNotifierId(id2); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id0")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id1")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id2")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id3")); EXPECT_TRUE(IsInNotifications(by_notifier_id, "id4")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id5")); by_notifier_id = notification_list_->GetNotificationsByNotifierId(id3); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id0")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id1")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id2")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id3")); EXPECT_FALSE(IsInNotifications(by_notifier_id, "id4")); EXPECT_TRUE(IsInNotifications(by_notifier_id, "id5")); } TEST_F(NotificationListTest, OldPopupShouldNotBeHidden) { std::vector ids; for (size_t i = 0; i <= kMaxVisiblePopupNotifications; i++) ids.push_back(AddNotification()); NotificationList::PopupNotifications popups = GetPopups(); // The popup should contain the oldest kMaxVisiblePopupNotifications. Newer // one should come earlier in the popup list. It means, the last element // of |popups| should be the firstly added one, and so on. EXPECT_EQ(kMaxVisiblePopupNotifications, popups.size()); auto iter = popups.rbegin(); for (size_t i = 0; i < kMaxVisiblePopupNotifications; ++i, ++iter) { EXPECT_EQ(ids[i], (*iter)->id()) << i; } for (auto iter = popups.begin(); iter != popups.end(); ++iter) { notification_list_->MarkSinglePopupAsShown((*iter)->id(), false); } popups.clear(); popups = GetPopups(); ASSERT_EQ(1u, popups.size()); EXPECT_EQ(ids.back(), (*popups.begin())->id()); } TEST_F(NotificationListTest, Priority) { ASSERT_EQ(0u, notification_list_->NotificationCount(blockers_)); // Default priority has the limit on the number of the popups. for (size_t i = 0; i <= kMaxVisiblePopupNotifications; ++i) AddNotification(); EXPECT_EQ(kMaxVisiblePopupNotifications + 1, notification_list_->NotificationCount(blockers_)); EXPECT_EQ(kMaxVisiblePopupNotifications, GetPopupCounts()); // Low priority: not visible to popups. notification_list_->SetNotificationsShown(blockers_, NULL); AddPriorityNotification(LOW_PRIORITY); EXPECT_EQ(kMaxVisiblePopupNotifications + 2, notification_list_->NotificationCount(blockers_)); EXPECT_EQ(0u, GetPopupCounts()); // Minimum priority: doesn't update the unread count. AddPriorityNotification(MIN_PRIORITY); EXPECT_EQ(kMaxVisiblePopupNotifications + 3, notification_list_->NotificationCount(blockers_)); EXPECT_EQ(0u, GetPopupCounts()); NotificationList::Notifications notifications = notification_list_->GetVisibleNotifications(blockers_); for (auto iter = notifications.begin(); iter != notifications.end(); ++iter) { notification_list_->RemoveNotification((*iter)->id()); } // Higher priority: no limits to the number of popups. for (size_t i = 0; i < kMaxVisiblePopupNotifications * 2; ++i) AddPriorityNotification(HIGH_PRIORITY); for (size_t i = 0; i < kMaxVisiblePopupNotifications * 2; ++i) AddPriorityNotification(MAX_PRIORITY); EXPECT_EQ(kMaxVisiblePopupNotifications * 4, notification_list_->NotificationCount(blockers_)); EXPECT_EQ(kMaxVisiblePopupNotifications * 4, GetPopupCounts()); } // Tests that GetNotificationsByAppId returns notifications regardless of their // visibility. TEST_F(NotificationListTest, GetNotificationsByAppId) { // Add a notification for |app_id1|. const std::string app_id1("app_id1"); const std::string id1("id1"); std::unique_ptr notification( new Notification(NOTIFICATION_TYPE_PROGRESS, id1, UTF8ToUTF16("updated"), UTF8ToUTF16("updated"), gfx::Image(), base::string16(), GURL(), NotifierId(NotifierType::APPLICATION, app_id1), RichNotificationData(), NULL)); notification_list_->AddNotification(std::move(notification)); EXPECT_EQ(1u, notification_list_->GetNotificationsByAppId(app_id1).size()); // Mark the popup as shown but not read. notification_list_->MarkSinglePopupAsShown(id1, false); EXPECT_EQ(1u, notification_list_->GetNotificationsByAppId(app_id1).size()); // Mark the popup as shown and read. notification_list_->MarkSinglePopupAsShown(id1, true); EXPECT_EQ(1u, notification_list_->GetNotificationsByAppId(app_id1).size()); // Remove the notification. notification_list_->RemoveNotification(id1); EXPECT_EQ(0u, notification_list_->GetNotificationsByAppId(app_id1).size()); // Add two notifications for |app_id1| and one for |app_id2|. notification.reset( new Notification(NOTIFICATION_TYPE_PROGRESS, id1, UTF8ToUTF16("updated"), UTF8ToUTF16("updated"), gfx::Image(), base::string16(), GURL(), NotifierId(NotifierType::APPLICATION, app_id1), RichNotificationData(), NULL)); notification_list_->AddNotification(std::move(notification)); const std::string id2("id2"); notification.reset( new Notification(NOTIFICATION_TYPE_PROGRESS, id2, UTF8ToUTF16("updated"), UTF8ToUTF16("updated"), gfx::Image(), base::string16(), GURL(), NotifierId(NotifierType::APPLICATION, app_id1), RichNotificationData(), NULL)); notification_list_->AddNotification(std::move(notification)); EXPECT_EQ(2u, notification_list_->GetNotificationsByAppId(app_id1).size()); const std::string id3("id3"); const std::string app_id2("app_id2"); notification.reset( new Notification(NOTIFICATION_TYPE_PROGRESS, id3, UTF8ToUTF16("updated"), UTF8ToUTF16("updated"), gfx::Image(), base::string16(), GURL(), NotifierId(NotifierType::APPLICATION, app_id2), RichNotificationData(), NULL)); notification_list_->AddNotification(std::move(notification)); EXPECT_EQ(2u, notification_list_->GetNotificationsByAppId(app_id1).size()); EXPECT_EQ(1u, notification_list_->GetNotificationsByAppId(app_id2).size()); for (std::string app_id : {app_id1, app_id2}) { for (auto* notification : notification_list_->GetNotificationsByAppId(app_id)) { EXPECT_EQ(app_id, notification->notifier_id().id); } } } TEST_F(NotificationListTest, HasPopupsWithPriority) { ASSERT_EQ(0u, notification_list_->NotificationCount(blockers_)); AddPriorityNotification(MIN_PRIORITY); AddPriorityNotification(MAX_PRIORITY); EXPECT_EQ(1u, GetPopupCounts()); } TEST_F(NotificationListTest, HasPopupsWithSystemPriority) { ASSERT_EQ(0u, notification_list_->NotificationCount(blockers_)); std::string normal_id = AddPriorityNotification(DEFAULT_PRIORITY); std::string system_id = AddNotification(); GetNotification(system_id)->SetSystemPriority(); EXPECT_EQ(2u, GetPopupCounts()); notification_list_->MarkSinglePopupAsDisplayed(normal_id); notification_list_->MarkSinglePopupAsDisplayed(system_id); notification_list_->MarkSinglePopupAsShown(normal_id, false); notification_list_->MarkSinglePopupAsShown(system_id, false); notification_list_->SetNotificationsShown(blockers_, NULL); EXPECT_EQ(1u, GetPopupCounts()); // Mark as read -- emulation of mouse click. notification_list_->MarkSinglePopupAsShown(system_id, true); EXPECT_EQ(0u, GetPopupCounts()); } // Verifies that notification updates will re-show the toast when there is no // message center view (i.e. the bubble anchored to the status bar). TEST_F(NotificationListTest, UpdateWithoutMessageCenterView) { auto run_test = [this](bool has_message_center_view) { message_center_->SetHasMessageCenterView(has_message_center_view); std::string id0 = AddNotification(); std::string replaced = id0 + "_replaced"; notification_list_->MarkSinglePopupAsShown(id0, false); EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_)); EXPECT_EQ(0u, GetPopupCounts()); RichNotificationData optional; std::unique_ptr notification(new Notification( NOTIFICATION_TYPE_SIMPLE, replaced, UTF8ToUTF16("newtitle"), UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierType::APPLICATION, kExtensionId), optional, NULL)); notification_list_->UpdateNotificationMessage(id0, std::move(notification)); EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_)); EXPECT_EQ(has_message_center_view ? 0U : 1U, GetPopupCounts()); const NotificationList::Notifications notifications = notification_list_->GetVisibleNotifications(blockers_); EXPECT_EQ(replaced, (*notifications.begin())->id()); EXPECT_EQ(UTF8ToUTF16("newtitle"), (*notifications.begin())->title()); EXPECT_EQ(UTF8ToUTF16("newbody"), (*notifications.begin())->message()); notification_list_->RemoveNotification(replaced); EXPECT_EQ(0U, notification_list_->GetVisibleNotifications(blockers_).size()); }; run_test(false); run_test(true); } TEST_F(NotificationListTest, Renotify) { std::string id0 = AddNotification(); std::string replaced = id0 + "_replaced"; notification_list_->MarkSinglePopupAsShown(id0, false); EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_)); EXPECT_EQ(0u, GetPopupCounts()); RichNotificationData optional; optional.renotify = true; std::unique_ptr notification(new Notification( NOTIFICATION_TYPE_SIMPLE, replaced, UTF8ToUTF16("newtitle"), UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierType::APPLICATION, kExtensionId), optional, NULL)); notification_list_->UpdateNotificationMessage(id0, std::move(notification)); EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_)); EXPECT_EQ(1u, GetPopupCounts()); const NotificationList::Notifications notifications = notification_list_->GetVisibleNotifications(blockers_); EXPECT_EQ(replaced, (*notifications.begin())->id()); EXPECT_EQ(UTF8ToUTF16("newtitle"), (*notifications.begin())->title()); EXPECT_EQ(UTF8ToUTF16("newbody"), (*notifications.begin())->message()); } TEST_F(NotificationListTest, PriorityAndRenotify) { std::string id0 = AddPriorityNotification(LOW_PRIORITY); std::string id1 = AddPriorityNotification(DEFAULT_PRIORITY); EXPECT_EQ(1u, GetPopupCounts()); notification_list_->MarkSinglePopupAsShown(id1, true); EXPECT_EQ(0u, GetPopupCounts()); // id0 promoted to LOW->DEFAULT, it'll appear as toast (popup). RichNotificationData priority; priority.priority = DEFAULT_PRIORITY; std::unique_ptr notification(new Notification( NOTIFICATION_TYPE_SIMPLE, id0, UTF8ToUTF16("newtitle"), UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierType::APPLICATION, kExtensionId), priority, NULL)); notification_list_->UpdateNotificationMessage(id0, std::move(notification)); EXPECT_EQ(1u, GetPopupCounts()); notification_list_->MarkSinglePopupAsShown(id0, true); EXPECT_EQ(0u, GetPopupCounts()); // update with no promotion change for id0, it won't appear as a toast. notification.reset(new Notification( NOTIFICATION_TYPE_SIMPLE, id0, UTF8ToUTF16("newtitle2"), UTF8ToUTF16("newbody2"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierType::APPLICATION, kExtensionId), priority, NULL)); notification_list_->UpdateNotificationMessage(id0, std::move(notification)); EXPECT_EQ(0u, GetPopupCounts()); // id1 promoted to DEFAULT->HIGH, it won't reappear as a toast (popup). priority.priority = HIGH_PRIORITY; notification.reset(new Notification( NOTIFICATION_TYPE_SIMPLE, id1, UTF8ToUTF16("newtitle"), UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierType::APPLICATION, kExtensionId), priority, NULL)); notification_list_->UpdateNotificationMessage(id1, std::move(notification)); EXPECT_EQ(0u, GetPopupCounts()); // |renotify| will make it reappear as a toast (popup). priority.renotify = true; notification.reset(new Notification( NOTIFICATION_TYPE_SIMPLE, id1, UTF8ToUTF16("newtitle"), UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierType::APPLICATION, kExtensionId), priority, NULL)); notification_list_->UpdateNotificationMessage(id1, std::move(notification)); EXPECT_EQ(1u, GetPopupCounts()); notification_list_->MarkSinglePopupAsShown(id1, true); EXPECT_EQ(0u, GetPopupCounts()); } TEST_F(NotificationListTest, NotificationOrderAndPriority) { base::Time now = base::Time::Now(); RichNotificationData optional; optional.timestamp = now; optional.priority = 2; std::string max_id = AddNotification(optional); now += base::TimeDelta::FromSeconds(1); optional.timestamp = now; optional.priority = 1; std::string high_id = AddNotification(optional); now += base::TimeDelta::FromSeconds(1); optional.timestamp = now; optional.priority = 0; std::string default_id = AddNotification(optional); { // Popups: latest comes first. NotificationList::PopupNotifications popups = GetPopups(); EXPECT_EQ(3u, popups.size()); auto iter = popups.begin(); EXPECT_EQ(default_id, (*iter)->id()); iter++; EXPECT_EQ(high_id, (*iter)->id()); iter++; EXPECT_EQ(max_id, (*iter)->id()); } { // Notifications: high priority comes earlier. const NotificationList::Notifications notifications = notification_list_->GetVisibleNotifications(blockers_); EXPECT_EQ(3u, notifications.size()); auto iter = notifications.begin(); EXPECT_EQ(max_id, (*iter)->id()); iter++; EXPECT_EQ(high_id, (*iter)->id()); iter++; EXPECT_EQ(default_id, (*iter)->id()); } } TEST_F(NotificationListTest, MarkSinglePopupAsShown) { std::string id1 = AddNotification(); std::string id2 = AddNotification(); std::string id3 = AddNotification(); ASSERT_EQ(3u, notification_list_->NotificationCount(blockers_)); ASSERT_EQ(std::min(static_cast(3u), kMaxVisiblePopupNotifications), GetPopupCounts()); notification_list_->MarkSinglePopupAsDisplayed(id1); notification_list_->MarkSinglePopupAsDisplayed(id2); notification_list_->MarkSinglePopupAsDisplayed(id3); notification_list_->MarkSinglePopupAsShown(id2, true); notification_list_->MarkSinglePopupAsShown(id3, false); EXPECT_EQ(3u, notification_list_->NotificationCount(blockers_)); EXPECT_EQ(1u, GetPopupCounts()); NotificationList::PopupNotifications popups = GetPopups(); EXPECT_EQ(id1, (*popups.begin())->id()); // The notifications in the NotificationCenter are unaffected by popups shown. NotificationList::Notifications notifications = notification_list_->GetVisibleNotifications(blockers_); auto iter = notifications.begin(); EXPECT_EQ(id3, (*iter)->id()); iter++; EXPECT_EQ(id2, (*iter)->id()); iter++; EXPECT_EQ(id1, (*iter)->id()); } TEST_F(NotificationListTest, UpdateAfterMarkedAsShown) { std::string id1 = AddNotification(); std::string id2 = AddNotification(); notification_list_->MarkSinglePopupAsDisplayed(id1); notification_list_->MarkSinglePopupAsDisplayed(id2); EXPECT_EQ(2u, GetPopupCounts()); NotificationState n1_state = GetNotificationState(id1); EXPECT_FALSE(n1_state.shown_as_popup); EXPECT_TRUE(n1_state.is_read); notification_list_->MarkSinglePopupAsShown(id1, true); n1_state = GetNotificationState(id1); EXPECT_TRUE(n1_state.shown_as_popup); EXPECT_TRUE(n1_state.is_read); const std::string replaced("test-replaced-id"); std::unique_ptr notification(new Notification( NOTIFICATION_TYPE_SIMPLE, replaced, UTF8ToUTF16("newtitle"), UTF8ToUTF16("newbody"), gfx::Image(), UTF8ToUTF16(kDisplaySource), GURL(), NotifierId(NotifierType::APPLICATION, kExtensionId), RichNotificationData(), NULL)); notification_list_->UpdateNotificationMessage(id1, std::move(notification)); Notification* n1 = GetNotification(id1); EXPECT_TRUE(n1 == NULL); const NotificationState nr_state = GetNotificationState(replaced); EXPECT_TRUE(nr_state.shown_as_popup); EXPECT_TRUE(nr_state.is_read); } TEST_F(NotificationListTest, QuietMode) { notification_list_->SetQuietMode(true); AddNotification(); AddPriorityNotification(HIGH_PRIORITY); AddPriorityNotification(MAX_PRIORITY); EXPECT_EQ(3u, notification_list_->NotificationCount(blockers_)); EXPECT_EQ(0u, GetPopupCounts()); notification_list_->SetQuietMode(false); AddNotification(); EXPECT_EQ(4u, notification_list_->NotificationCount(blockers_)); EXPECT_EQ(1u, GetPopupCounts()); // TODO(mukai): Add test of quiet mode with expiration. } TEST_F(NotificationListTest, TestHasNotificationOfType) { std::string id = AddNotification(); EXPECT_TRUE( notification_list_->HasNotificationOfType(id, NOTIFICATION_TYPE_SIMPLE)); EXPECT_FALSE(notification_list_->HasNotificationOfType( id, NOTIFICATION_TYPE_PROGRESS)); std::unique_ptr updated_notification( new Notification(NOTIFICATION_TYPE_PROGRESS, id, UTF8ToUTF16("updated"), UTF8ToUTF16("updated"), gfx::Image(), base::string16(), GURL(), NotifierId(), RichNotificationData(), NULL)); notification_list_->AddNotification(std::move(updated_notification)); EXPECT_FALSE( notification_list_->HasNotificationOfType(id, NOTIFICATION_TYPE_SIMPLE)); EXPECT_TRUE(notification_list_->HasNotificationOfType( id, NOTIFICATION_TYPE_PROGRESS)); } } // namespace message_center