1 // Copyright 2019 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 "chrome/browser/ui/global_media_controls/cast_media_notification_provider.h"
6
7 #include "chrome/test/base/testing_profile.h"
8 #include "components/media_message_center/media_notification_controller.h"
9 #include "components/media_message_center/media_notification_view.h"
10 #include "components/media_router/browser/test/mock_media_router.h"
11 #include "components/media_router/common/media_route.h"
12 #include "content/public/test/browser_task_environment.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "ui/gfx/vector_icon_types.h"
16
17 using media_router::MediaRoute;
18 using media_router::RouteControllerType;
19 using testing::_;
20
21 namespace {
22
CreateRoute(const std::string & route_id,const std::string & source_id="source_id")23 MediaRoute CreateRoute(const std::string& route_id,
24 const std::string& source_id = "source_id") {
25 media_router::MediaRoute route(route_id, media_router::MediaSource(source_id),
26 "sink_id", "description", true, true);
27 route.set_controller_type(media_router::RouteControllerType::kGeneric);
28 return route;
29 }
30
31 class MockMediaNotificationController
32 : public media_message_center::MediaNotificationController {
33 public:
34 MockMediaNotificationController() = default;
35 ~MockMediaNotificationController() = default;
36
37 MOCK_METHOD(void, ShowNotification, (const std::string& id));
38 MOCK_METHOD(void, HideNotification, (const std::string& id));
39 MOCK_METHOD(void, RemoveItem, (const std::string& id));
GetTaskRunner() const40 scoped_refptr<base::SequencedTaskRunner> GetTaskRunner() const override {
41 return nullptr;
42 }
43 MOCK_METHOD(void,
44 LogMediaSessionActionButtonPressed,
45 (const std::string& id,
46 media_session::mojom::MediaSessionAction action));
47 };
48
49 class MockMediaNotificationView
50 : public media_message_center::MediaNotificationView {
51 public:
52 MOCK_METHOD1(SetExpanded, void(bool));
53 MOCK_METHOD2(UpdateCornerRadius, void(int, int));
54 MOCK_METHOD1(SetForcedExpandedState, void(bool*));
55 MOCK_METHOD1(UpdateWithMediaSessionInfo,
56 void(const media_session::mojom::MediaSessionInfoPtr&));
57 MOCK_METHOD1(UpdateWithMediaMetadata,
58 void(const media_session::MediaMetadata&));
59 MOCK_METHOD1(
60 UpdateWithMediaActions,
61 void(const base::flat_set<media_session::mojom::MediaSessionAction>&));
62 MOCK_METHOD1(UpdateWithMediaArtwork, void(const gfx::ImageSkia&));
63 MOCK_METHOD1(UpdateWithFavicon, void(const gfx::ImageSkia&));
64 MOCK_METHOD1(UpdateWithVectorIcon, void(const gfx::VectorIcon& vector_icon));
65 MOCK_METHOD1(UpdateDeviceSelectorAvailability, void(bool availability));
66 };
67
68 class MockClosure {
69 public:
70 MOCK_METHOD0(Run, void());
71 };
72
73 } // namespace
74
75 class CastMediaNotificationProviderTest : public testing::Test {
76 public:
SetUp()77 void SetUp() override {
78 notification_provider_ = std::make_unique<CastMediaNotificationProvider>(
79 &profile_, &router_, ¬ification_controller_,
80 base::BindRepeating(&MockClosure::Run,
81 base::Unretained(&items_changed_callback_)));
82 }
83
TearDown()84 void TearDown() override { notification_provider_.reset(); }
85
86 protected:
87 content::BrowserTaskEnvironment task_environment_;
88 TestingProfile profile_;
89 std::unique_ptr<CastMediaNotificationProvider> notification_provider_;
90 MockMediaNotificationController notification_controller_;
91 media_router::MockMediaRouter router_;
92 MockClosure items_changed_callback_;
93 };
94
TEST_F(CastMediaNotificationProviderTest,AddAndRemoveRoute)95 TEST_F(CastMediaNotificationProviderTest, AddAndRemoveRoute) {
96 const std::string route_id = "route-id-1";
97 MediaRoute route = CreateRoute(route_id);
98
99 EXPECT_CALL(items_changed_callback_, Run());
100 notification_provider_->OnRoutesUpdated({route}, {});
101 testing::Mock::VerifyAndClearExpectations(&items_changed_callback_);
102 EXPECT_TRUE(notification_provider_->HasItems());
103 EXPECT_NE(nullptr, notification_provider_->GetNotificationItem(route_id));
104
105 EXPECT_CALL(items_changed_callback_, Run());
106 notification_provider_->OnRoutesUpdated({}, {});
107 testing::Mock::VerifyAndClearExpectations(&items_changed_callback_);
108 EXPECT_FALSE(notification_provider_->HasItems());
109 }
110
TEST_F(CastMediaNotificationProviderTest,UpdateRoute)111 TEST_F(CastMediaNotificationProviderTest, UpdateRoute) {
112 const std::string route_id = "route-id-1";
113 MediaRoute route = CreateRoute(route_id);
114
115 notification_provider_->OnRoutesUpdated({route}, {});
116 auto* item = static_cast<CastMediaNotificationItem*>(
117 notification_provider_->GetNotificationItem(route_id).get());
118 MockMediaNotificationView view;
119 item->SetView(&view);
120
121 const std::string new_sink = "new sink";
122 const std::string new_description = "new description";
123 route.set_media_sink_name(new_sink);
124 route.set_description(new_description);
125
126 EXPECT_CALL(view, UpdateWithMediaMetadata(_))
127 .WillOnce([&](const media_session::MediaMetadata& metadata) {
128 const std::string separator = " \xC2\xB7 ";
129 EXPECT_EQ(base::UTF8ToUTF16(new_description + separator + new_sink),
130 metadata.source_title);
131 });
132 notification_provider_->OnRoutesUpdated({route}, {});
133 }
134
TEST_F(CastMediaNotificationProviderTest,RoutesWithoutNotifications)135 TEST_F(CastMediaNotificationProviderTest, RoutesWithoutNotifications) {
136 // These routes should not have notification items created for them.
137 MediaRoute non_display_route = CreateRoute("route-1");
138 non_display_route.set_for_display(false);
139 MediaRoute no_controller_route = CreateRoute("route-2");
140 no_controller_route.set_controller_type(RouteControllerType::kNone);
141 MediaRoute multizone_member_route = CreateRoute("route-3", "cast:705D30C6");
142
143 notification_provider_->OnRoutesUpdated(
144 {non_display_route, no_controller_route, multizone_member_route}, {});
145 EXPECT_FALSE(notification_provider_->HasItems());
146 }
147