blob: 0e64c626c07268f553369b20250e9c01bb8757df [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// 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 <stddef.h>
#include <memory>
#include <utility>
#include "base/i18n/time_formatting.h"
#include "base/strings/string_number_conversions.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"
#if BUILDFLAG(IS_CHROMEOS_ASH)
#include "ash/constants/notifier_catalogs.h"
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
namespace message_center {
using NotificationState = NotificationList::NotificationState;
// A trivial blocker that allows all popups.
class NopNotificationBlocker : public NotificationBlocker {
public:
NopNotificationBlocker() : NotificationBlocker(/*message_center=*/nullptr) {}
NopNotificationBlocker(const NopNotificationBlocker&) = delete;
NopNotificationBlocker& operator=(const NopNotificationBlocker&) = delete;
~NopNotificationBlocker() override = default;
bool ShouldShowNotificationAsPopup(
const Notification& notification) const override {
return true;
}
};
class NotificationListTest : public testing::Test {
public:
NotificationListTest() {}
NotificationListTest(const NotificationListTest&) = delete;
NotificationListTest& operator=(const NotificationListTest&) = delete;
~NotificationListTest() override {}
void SetUp() override {
message_center_ = std::make_unique<FakeMessageCenter>();
notification_list_ =
std::make_unique<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> 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<Notification> MakeNotification(
const RichNotificationData& optional_fields,
std::string* id_out) {
*id_out = base::StringPrintf(kIdFormat, counter_);
std::unique_ptr<Notification> notification(
new Notification(NOTIFICATION_TYPE_SIMPLE, *id_out,
u"id" + base::NumberToString16(counter_),
u"message" + base::NumberToString16(counter_),
ui::ImageModel(), kDisplaySource, GURL(),
NotifierId(NotifierType::APPLICATION, kExtensionId),
optional_fields, nullptr));
return notification;
}
std::unique_ptr<Notification> 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_, nullptr);
}
size_t GetPopupCounts() {
return GetPopups().size();
}
size_t GetPopupForBlockersCounts() {
return notification_list_
->GetPopupNotificationsWithoutBlocker(blockers_,
NopNotificationBlocker())
.size();
}
Notification* GetNotification(const std::string& id) {
auto iter = notification_list_->GetNotification(id);
if (iter == notification_list_->notifications_.end())
return nullptr;
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 constexpr char kIdFormat[] = "id%zu";
static const char16_t kDisplaySource[];
static const char kExtensionId[];
std::unique_ptr<FakeMessageCenter> message_center_;
std::unique_ptr<NotificationList> notification_list_;
NotificationBlockers blockers_;
size_t counter_;
};
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 char16_t NotificationListTest::kDisplaySource[] = u"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_, nullptr);
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> notification(
new Notification(NOTIFICATION_TYPE_SIMPLE, replaced, u"newtitle",
u"newbody", ui::ImageModel(), kDisplaySource, GURL(),
NotifierId(NotifierType::APPLICATION, kExtensionId),
RichNotificationData(), nullptr));
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(u"newtitle", (*notifications.begin())->title());
EXPECT_EQ(u"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<bool>(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, ResetPopupInQuietMode) {
for (size_t quiet_mode = 0u; quiet_mode < 2u; ++quiet_mode) {
// Set Do Not Disturb mode.
notification_list_->SetQuietMode(static_cast<bool>(quiet_mode));
// Create notification.
std::string id;
auto old_notification = MakeNotification(&id);
notification_list_->AddNotification(std::move(old_notification));
EXPECT_EQ(1u, notification_list_->NotificationCount(blockers_));
// Reset single popup and make sure that the behavior is correct
// within/outside of quiet mode.
notification_list_->ResetSinglePopup(id);
// Normally, `shown_as_popup` should be reset in order to show the popup
// again. However, in quiet mode, `shown_as_popup` should not be reset since
// we don't want the popup to be shown.
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(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"));
#if BUILDFLAG(IS_CHROMEOS_ASH)
NotifierId id3(NotifierType::SYSTEM_COMPONENT, "system-notifier",
ash::NotificationCatalogName::kTestCatalogName);
#else
NotifierId id3(NotifierType::SYSTEM_COMPONENT, "system-notifier");
#endif // BUILDFLAG(IS_CHROMEOS_ASH)
std::unique_ptr<Notification> notification(new Notification(
NOTIFICATION_TYPE_SIMPLE, "id0", u"title0", u"message0", ui::ImageModel(),
u"source0", GURL(), id0, RichNotificationData(), nullptr));
notification_list_->AddNotification(std::move(notification));
notification = std::make_unique<Notification>(
NOTIFICATION_TYPE_SIMPLE, "id1", u"title1", u"message1", ui::ImageModel(),
u"source0", GURL(), id0, RichNotificationData(), nullptr);
notification_list_->AddNotification(std::move(notification));
notification = std::make_unique<Notification>(
NOTIFICATION_TYPE_SIMPLE, "id2", u"title1", u"message1", ui::ImageModel(),
u"source1", GURL(), id0, RichNotificationData(), nullptr);
notification_list_->AddNotification(std::move(notification));
notification = std::make_unique<Notification>(
NOTIFICATION_TYPE_SIMPLE, "id3", u"title1", u"message1", ui::ImageModel(),
u"source2", GURL(), id1, RichNotificationData(), nullptr);
notification_list_->AddNotification(std::move(notification));
notification = std::make_unique<Notification>(
NOTIFICATION_TYPE_SIMPLE, "id4", u"title1", u"message1", ui::ImageModel(),
u"source2", GURL(), id2, RichNotificationData(), nullptr);
notification_list_->AddNotification(std::move(notification));
notification = std::make_unique<Notification>(
NOTIFICATION_TYPE_SIMPLE, "id5", u"title1", u"message1", ui::ImageModel(),
u"source2", GURL(), id3, RichNotificationData(), nullptr);
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<std::string> 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* popup : popups) {
notification_list_->MarkSinglePopupAsShown(popup->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_, nullptr);
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());
}
TEST_F(NotificationListTest, WithoutOneBlocker) {
ASSERT_EQ(0u, notification_list_->NotificationCount(blockers_));
// Limit is not considered, even for default priority popups.
for (size_t i = 0; i <= kMaxVisiblePopupNotifications; ++i)
AddNotification();
EXPECT_EQ(kMaxVisiblePopupNotifications + 1,
notification_list_->NotificationCount(blockers_));
EXPECT_EQ(kMaxVisiblePopupNotifications + 1, GetPopupForBlockersCounts());
// Popups aren't marked as shown.
EXPECT_EQ(kMaxVisiblePopupNotifications + 1, GetPopupForBlockersCounts());
}
// Tests that GetNotificationsByAppId returns notifications regardless of their
// visibility.
TEST_F(NotificationListTest, GetNotificationsByAppId) {
const std::string app_id1("app_id1");
const std::string app_id2("app_id2");
{
// Add a notification for |app_id1|.
const std::string id1("id1");
std::unique_ptr<Notification> notification(
new Notification(NOTIFICATION_TYPE_PROGRESS, id1, u"updated",
u"updated", ui::ImageModel(), std::u16string(), GURL(),
NotifierId(NotifierType::APPLICATION, app_id1),
RichNotificationData(), nullptr));
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 = std::make_unique<Notification>(
NOTIFICATION_TYPE_PROGRESS, id1, u"updated", u"updated",
ui::ImageModel(), std::u16string(), GURL(),
NotifierId(NotifierType::APPLICATION, app_id1), RichNotificationData(),
nullptr);
notification_list_->AddNotification(std::move(notification));
const std::string id2("id2");
notification = std::make_unique<Notification>(
NOTIFICATION_TYPE_PROGRESS, id2, u"updated", u"updated",
ui::ImageModel(), std::u16string(), GURL(),
NotifierId(NotifierType::APPLICATION, app_id1), RichNotificationData(),
nullptr);
notification_list_->AddNotification(std::move(notification));
EXPECT_EQ(2u, notification_list_->GetNotificationsByAppId(app_id1).size());
const std::string id3("id3");
notification = std::make_unique<Notification>(
NOTIFICATION_TYPE_PROGRESS, id3, u"updated", u"updated",
ui::ImageModel(), std::u16string(), GURL(),
NotifierId(NotifierType::APPLICATION, app_id2), RichNotificationData(),
nullptr);
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 (Notification* notification :
notification_list_->GetNotificationsByAppId(app_id)) {
EXPECT_EQ(app_id, notification->notifier_id().id);
}
}
}
// Tests that GetNotificationsByOriginUrl returns notifications regardless of
// their visibility.
TEST_F(NotificationListTest, GetNotificationsByOriginUrl) {
const GURL kUrl1(u"http://www.kurl1.com");
const GURL kUrl2(u"http://www.kUrl2.com");
{
// Add a notification for `kurl1`.
const std::string id1("id1");
std::unique_ptr<Notification> notification(
new Notification(NOTIFICATION_TYPE_PROGRESS, id1, u"updated",
u"updated", ui::ImageModel(), std::u16string(), kUrl1,
NotifierId(), RichNotificationData(), nullptr));
notification_list_->AddNotification(std::move(notification));
EXPECT_EQ(1u,
notification_list_->GetNotificationsByOriginUrl(kUrl1).size());
// Mark the popup as shown but not read.
notification_list_->MarkSinglePopupAsShown(id1, false);
EXPECT_EQ(1u,
notification_list_->GetNotificationsByOriginUrl(kUrl1).size());
// Mark the popup as shown and read.
notification_list_->MarkSinglePopupAsShown(id1, true);
EXPECT_EQ(1u,
notification_list_->GetNotificationsByOriginUrl(kUrl1).size());
// Remove the notification.
notification_list_->RemoveNotification(id1);
EXPECT_EQ(0u,
notification_list_->GetNotificationsByOriginUrl(kUrl1).size());
// Add two notifications for `kurl1` and one for `kUrl2`.
notification = std::make_unique<Notification>(
NOTIFICATION_TYPE_PROGRESS, id1, u"updated", u"updated",
ui::ImageModel(), std::u16string(), kUrl1, NotifierId(),
RichNotificationData(), nullptr);
notification_list_->AddNotification(std::move(notification));
const std::string id2("id2");
notification = std::make_unique<Notification>(
NOTIFICATION_TYPE_PROGRESS, id2, u"updated", u"updated",
ui::ImageModel(), std::u16string(), kUrl1, NotifierId(),
RichNotificationData(), nullptr);
notification_list_->AddNotification(std::move(notification));
EXPECT_EQ(2u,
notification_list_->GetNotificationsByOriginUrl(kUrl1).size());
const std::string id3("id3");
notification = std::make_unique<Notification>(
NOTIFICATION_TYPE_PROGRESS, id3, u"updated", u"updated",
ui::ImageModel(), std::u16string(), kUrl2, NotifierId(),
RichNotificationData(), nullptr);
notification_list_->AddNotification(std::move(notification));
EXPECT_EQ(2u,
notification_list_->GetNotificationsByOriginUrl(kUrl1).size());
EXPECT_EQ(1u,
notification_list_->GetNotificationsByOriginUrl(kUrl2).size());
}
for (GURL url : {kUrl1, kUrl2}) {
for (Notification* notification :
notification_list_->GetNotificationsByOriginUrl(url)) {
EXPECT_EQ(url, notification->origin_url());
}
}
}
TEST_F(NotificationListTest, HasPopupsWithPriority) {
ASSERT_EQ(0u, notification_list_->NotificationCount(blockers_));
AddPriorityNotification(MIN_PRIORITY);
AddPriorityNotification(MAX_PRIORITY);
EXPECT_EQ(1u, GetPopupCounts());
}
TEST_F(NotificationListTest, AllPopupsDismissedWhenMarkedAsShown) {
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);
EXPECT_EQ(0u, GetPopupCounts());
}
TEST_F(NotificationListTest, GetNotifications) {
ASSERT_EQ(0u, notification_list_->NotificationCount(blockers_));
EXPECT_EQ(0u, notification_list_->GetNotifications().size());
AddPriorityNotification(MIN_PRIORITY);
AddPriorityNotification(MAX_PRIORITY);
EXPECT_EQ(1u, GetPopupCounts());
EXPECT_EQ(2u, notification_list_->GetNotifications().size());
}
// 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> notification(
new Notification(NOTIFICATION_TYPE_SIMPLE, replaced, u"newtitle",
u"newbody", ui::ImageModel(), kDisplaySource, GURL(),
NotifierId(NotifierType::APPLICATION, kExtensionId),
optional, nullptr));
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(u"newtitle", (*notifications.begin())->title());
EXPECT_EQ(u"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> notification(new Notification(
NOTIFICATION_TYPE_SIMPLE, replaced, u"newtitle", u"newbody",
ui::ImageModel(), kDisplaySource, GURL(),
NotifierId(NotifierType::APPLICATION, kExtensionId), optional, nullptr));
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(u"newtitle", (*notifications.begin())->title());
EXPECT_EQ(u"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> notification(new Notification(
NOTIFICATION_TYPE_SIMPLE, id0, u"newtitle", u"newbody", ui::ImageModel(),
kDisplaySource, GURL(),
NotifierId(NotifierType::APPLICATION, kExtensionId), priority, nullptr));
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 = std::make_unique<Notification>(
NOTIFICATION_TYPE_SIMPLE, id0, u"newtitle2", u"newbody2",
ui::ImageModel(), kDisplaySource, GURL(),
NotifierId(NotifierType::APPLICATION, kExtensionId), priority, nullptr);
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 = std::make_unique<Notification>(
NOTIFICATION_TYPE_SIMPLE, id1, u"newtitle", u"newbody", ui::ImageModel(),
kDisplaySource, GURL(),
NotifierId(NotifierType::APPLICATION, kExtensionId), priority, nullptr);
notification_list_->UpdateNotificationMessage(id1, std::move(notification));
EXPECT_EQ(0u, GetPopupCounts());
// |renotify| will make it reappear as a toast (popup).
priority.renotify = true;
notification = std::make_unique<Notification>(
NOTIFICATION_TYPE_SIMPLE, id1, u"newtitle", u"newbody", ui::ImageModel(),
kDisplaySource, GURL(),
NotifierId(NotifierType::APPLICATION, kExtensionId), priority, nullptr);
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::Seconds(1);
optional.timestamp = now;
optional.priority = 1;
std::string high_id = AddNotification(optional);
now += base::Seconds(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<size_t>(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> notification(
new Notification(NOTIFICATION_TYPE_SIMPLE, replaced, u"newtitle",
u"newbody", ui::ImageModel(), kDisplaySource, GURL(),
NotifierId(NotifierType::APPLICATION, kExtensionId),
RichNotificationData(), nullptr));
notification_list_->UpdateNotificationMessage(id1, std::move(notification));
Notification* n1 = GetNotification(id1);
EXPECT_TRUE(n1 == nullptr);
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<Notification> updated_notification(new Notification(
NOTIFICATION_TYPE_PROGRESS, id, u"updated", u"updated", ui::ImageModel(),
std::u16string(), GURL(), NotifierId(), RichNotificationData(), nullptr));
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