notification_menu_controller_unittest.cc 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // Copyright 2018 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. #include "ash/app_menu/notification_menu_controller.h"
  5. #include "ash/app_menu/app_menu_model_adapter.h"
  6. #include "ash/test/ash_test_base.h"
  7. #include "base/callback.h"
  8. #include "base/strings/utf_string_conversions.h"
  9. #include "testing/gtest/include/gtest/gtest.h"
  10. #include "ui/base/models/simple_menu_model.h"
  11. #include "ui/views/controls/menu/menu_item_view.h"
  12. #include "ui/views/controls/menu/submenu_view.h"
  13. namespace ash {
  14. namespace {
  15. constexpr char kTestAppId[] = "test-app-id";
  16. void BuildAndSendNotification(const std::string& app_id,
  17. const std::string& notification_id) {
  18. const message_center::NotifierId notifier_id(
  19. message_center::NotifierType::APPLICATION, app_id);
  20. std::unique_ptr<message_center::Notification> notification =
  21. std::make_unique<message_center::Notification>(
  22. message_center::NOTIFICATION_TYPE_SIMPLE, notification_id,
  23. u"Test Web Notification", u"Notification message body.",
  24. ui::ImageModel(), u"www.test.org", GURL(), notifier_id,
  25. message_center::RichNotificationData(), nullptr /* delegate */);
  26. message_center::MessageCenter::Get()->AddNotification(
  27. std::move(notification));
  28. }
  29. class TestAppMenuModelAdapter : public AppMenuModelAdapter {
  30. public:
  31. TestAppMenuModelAdapter(const std::string& app_id,
  32. std::unique_ptr<ui::SimpleMenuModel> model)
  33. : AppMenuModelAdapter(app_id,
  34. std::move(model),
  35. nullptr,
  36. ui::MENU_SOURCE_TYPE_LAST,
  37. base::OnceClosure(),
  38. false /* is_tablet_mode */) {}
  39. TestAppMenuModelAdapter(const TestAppMenuModelAdapter&) = delete;
  40. TestAppMenuModelAdapter& operator=(const TestAppMenuModelAdapter&) = delete;
  41. private:
  42. // AppMenuModelAdapter overrides:
  43. void RecordHistogramOnMenuClosed() override {}
  44. };
  45. } // namespace
  46. class NotificationMenuControllerTest : public AshTestBase {
  47. public:
  48. NotificationMenuControllerTest() = default;
  49. NotificationMenuControllerTest(const NotificationMenuControllerTest&) =
  50. delete;
  51. NotificationMenuControllerTest& operator=(
  52. const NotificationMenuControllerTest&) = delete;
  53. ~NotificationMenuControllerTest() override {}
  54. // Overridden from AshTestBase:
  55. void TearDown() override {
  56. // NotificationMenuController removes itself from MessageCenter's observer
  57. // list in the dtor, so force it to happen first to prevent a crash. This
  58. // crash does not repro in production.
  59. notification_menu_controller_.reset();
  60. AshTestBase::TearDown();
  61. }
  62. void BuildMenu() {
  63. test_app_menu_model_adapter_ = std::make_unique<TestAppMenuModelAdapter>(
  64. kTestAppId,
  65. std::make_unique<ui::SimpleMenuModel>(
  66. nullptr /*ui::SimpleMenuModel::Delegate not required*/));
  67. test_app_menu_model_adapter_->model()->AddItem(0, u"item 0");
  68. test_app_menu_model_adapter_->model()->AddItem(1, u"item 1");
  69. root_menu_item_view_ =
  70. new views::MenuItemView(test_app_menu_model_adapter_.get());
  71. host_view_ = std::make_unique<views::View>();
  72. host_view_->AddChildView(root_menu_item_view_);
  73. test_app_menu_model_adapter_->BuildMenu(root_menu_item_view_);
  74. notification_menu_controller_ =
  75. std::make_unique<NotificationMenuController>(
  76. kTestAppId, root_menu_item_view_,
  77. test_app_menu_model_adapter_.get());
  78. }
  79. views::MenuItemView* root_menu_item_view() { return root_menu_item_view_; }
  80. private:
  81. // The root MenuItemView. Owned by |host_view_|.
  82. views::MenuItemView* root_menu_item_view_ = nullptr;
  83. // Allows the dtor to access the restricted views::MenuItemView dtor.
  84. std::unique_ptr<views::View> host_view_;
  85. std::unique_ptr<NotificationMenuController> notification_menu_controller_;
  86. std::unique_ptr<TestAppMenuModelAdapter> test_app_menu_model_adapter_;
  87. };
  88. // Tests that NotificationMenuController does not add the
  89. // NotificationMenuView container until a notification arrives.
  90. TEST_F(NotificationMenuControllerTest, NotificationsArriveAfterBuilt) {
  91. // Build the context menu without adding a notification for
  92. // kTestAppId.
  93. BuildMenu();
  94. // There should only be two items in the context menu.
  95. EXPECT_EQ(2u, root_menu_item_view()->GetSubmenu()->children().size());
  96. // Add a notification.
  97. BuildAndSendNotification(kTestAppId, std::string("notification_id"));
  98. // NotificationMenuController should have added a third item, the
  99. // container for NotificationMenuView, to the menu.
  100. EXPECT_EQ(3u, root_menu_item_view()->GetSubmenu()->children().size());
  101. }
  102. // Tests that NotificationMenuController adds and removes the container
  103. // MenuItemView when notifications come in before and after the menu has been
  104. // built.
  105. TEST_F(NotificationMenuControllerTest, NotificationsExistBeforeMenuIsBuilt) {
  106. // Add the notification before the menu is built.
  107. const std::string notification_id("notification_id");
  108. BuildAndSendNotification(kTestAppId, notification_id);
  109. // Build the menu, the container should be added.
  110. BuildMenu();
  111. EXPECT_EQ(3u, root_menu_item_view()->GetSubmenu()->children().size());
  112. // Remove the notification, this should result in the NotificationMenuView
  113. // container being removed.
  114. message_center::MessageCenter::Get()->RemoveNotification(notification_id,
  115. true);
  116. EXPECT_EQ(2u, root_menu_item_view()->GetSubmenu()->children().size());
  117. // Add the same notification.
  118. BuildAndSendNotification(kTestAppId, notification_id);
  119. // The container MenuItemView should be added again.
  120. EXPECT_EQ(3u, root_menu_item_view()->GetSubmenu()->children().size());
  121. }
  122. // Tests that adding multiple notifications for kTestAppId does not add
  123. // additional containers beyond the first.
  124. TEST_F(NotificationMenuControllerTest, MultipleNotifications) {
  125. // Add two notifications, then build the menu.
  126. const std::string notification_id_0("notification_id_0");
  127. BuildAndSendNotification(kTestAppId, notification_id_0);
  128. const std::string notification_id_1("notification_id_1");
  129. BuildAndSendNotification(kTestAppId, notification_id_1);
  130. BuildMenu();
  131. // Only one container MenuItemView should be added.
  132. EXPECT_EQ(3u, root_menu_item_view()->GetSubmenu()->children().size());
  133. message_center::MessageCenter* message_center =
  134. message_center::MessageCenter::Get();
  135. // Remove one of the notifications.
  136. message_center->RemoveNotification(notification_id_0, true);
  137. // The container should still exist.
  138. EXPECT_EQ(3u, root_menu_item_view()->GetSubmenu()->children().size());
  139. // Remove the final notification.
  140. message_center->RemoveNotification(notification_id_1, true);
  141. // The container should be removed.
  142. EXPECT_EQ(2u, root_menu_item_view()->GetSubmenu()->children().size());
  143. }
  144. } // namespace ash