blob: 57df58579c73d498d17e624657cc367f6ac9be94 [file] [log] [blame]
// Copyright 2015 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 "chrome/browser/ui/webui/media_router/media_router_webui_message_handler.h"
#include <memory>
#include <set>
#include <utility>
#include "base/macros.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/media/router/test/media_router_mojo_test.h"
#include "chrome/browser/media/router/test/mock_media_router.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/webui/media_router/media_router_ui.h"
#include "chrome/browser/ui/webui/media_router/media_router_web_ui_test.h"
#include "content/public/browser/browser_context.h"
#include "content/public/test/test_web_ui.h"
#include "extensions/common/constants.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::Return;
using testing::ReturnRef;
namespace media_router {
namespace {
const char kUserEmailForTesting[] = "nobody@example.com";
const char kUserDomainForTesting[] = "example.com";
bool GetBooleanFromDict(const base::DictionaryValue* dict,
const std::string& key) {
bool value = false;
EXPECT_TRUE(dict->GetBoolean(key, &value));
return value;
}
double GetDoubleFromDict(const base::DictionaryValue* dict,
const std::string& key) {
double value = 0;
EXPECT_TRUE(dict->GetDouble(key, &value));
return value;
}
int GetIntegerFromDict(const base::DictionaryValue* dict,
const std::string& key) {
int value = 0;
EXPECT_TRUE(dict->GetInteger(key, &value));
return value;
}
std::string GetStringFromDict(const base::DictionaryValue* dict,
const std::string& key) {
std::string value;
EXPECT_TRUE(dict->GetString(key, &value));
return value;
}
// Creates a local route for display.
MediaRoute CreateRoute() {
MediaRoute::Id route_id("routeId123");
MediaSink::Id sink_id("sinkId123");
MediaSink sink(sink_id, "The sink", SinkIconType::CAST);
std::string description("This is a route");
bool is_local = true;
bool is_for_display = true;
MediaRoute route(route_id, MediaSource("mediaSource"), sink_id, description,
is_local, is_for_display);
return route;
}
MediaSinkWithCastModes CreateMediaSinkWithCastMode(const std::string& sink_id,
MediaCastMode cast_mode) {
std::string sink_name("The sink");
MediaSinkWithCastModes media_sink_with_cast_modes(
MediaSink(sink_id, sink_name, SinkIconType::CAST));
media_sink_with_cast_modes.cast_modes.insert(cast_mode);
return media_sink_with_cast_modes;
}
} // namespace
class MockMediaRouterUI : public MediaRouterUI {
public:
explicit MockMediaRouterUI(content::WebUI* web_ui)
: MediaRouterUI(web_ui) {}
~MockMediaRouterUI() override {}
MOCK_METHOD0(OnUIInitialized, void());
MOCK_CONST_METHOD0(UserSelectedTabMirroringForCurrentOrigin, bool());
MOCK_METHOD1(RecordCastModeSelection, void(MediaCastMode cast_mode));
MOCK_CONST_METHOD0(GetPresentationRequestSourceName, std::string());
MOCK_CONST_METHOD0(GetCastModes, const std::set<MediaCastMode>&());
MOCK_METHOD1(OnMediaControllerUIAvailable,
void(const MediaRoute::Id& route_id));
MOCK_METHOD0(OnMediaControllerUIClosed, void());
MOCK_METHOD0(PlayRoute, void());
MOCK_METHOD0(PauseRoute, void());
MOCK_METHOD1(SeekRoute, void(base::TimeDelta time));
MOCK_METHOD1(SetRouteMute, void(bool mute));
MOCK_METHOD1(SetRouteVolume, void(float volume));
MOCK_CONST_METHOD0(GetMediaRouteController, MediaRouteController*());
};
class TestMediaRouterWebUIMessageHandler
: public MediaRouterWebUIMessageHandler {
public:
explicit TestMediaRouterWebUIMessageHandler(MediaRouterUI* media_router_ui)
: MediaRouterWebUIMessageHandler(media_router_ui),
email_(kUserEmailForTesting),
domain_(kUserDomainForTesting) {}
~TestMediaRouterWebUIMessageHandler() override = default;
AccountInfo GetAccountInfo() override {
AccountInfo info = AccountInfo();
info.account_id = info.gaia = info.email = email_;
info.hosted_domain = domain_;
info.full_name = info.given_name = "name";
info.locale = "locale";
info.picture_url = "picture";
return info;
}
void SetEmailAndDomain(const std::string& email, const std::string& domain) {
email_ = email;
domain_ = domain;
}
private:
std::string email_;
std::string domain_;
};
class MediaRouterWebUIMessageHandlerTest : public MediaRouterWebUITest {
public:
MediaRouterWebUIMessageHandlerTest()
: web_ui_(std::make_unique<content::TestWebUI>()) {}
~MediaRouterWebUIMessageHandlerTest() override {}
// BrowserWithTestWindowTest:
void SetUp() override {
BrowserWithTestWindowTest::SetUp();
chrome::NewTab(browser());
web_ui_->set_web_contents(
browser()->tab_strip_model()->GetActiveWebContents());
mock_media_router_ui_ = std::make_unique<MockMediaRouterUI>(web_ui_.get());
handler_ = std::make_unique<TestMediaRouterWebUIMessageHandler>(
mock_media_router_ui_.get());
handler_->SetWebUIForTest(web_ui_.get());
}
void TearDown() override {
handler_.reset();
mock_media_router_ui_.reset();
web_ui_.reset();
BrowserWithTestWindowTest::TearDown();
}
const std::string& provider_extension_id() const {
return provider_extension_id_;
}
// Gets the call data for the function call made to |web_ui_|. There needs
// to be one call made, and its function name must be |function_name|.
const base::Value* GetCallData(const std::string& function_name) {
CHECK_EQ(1u, web_ui_->call_data().size());
const content::TestWebUI::CallData& call_data = *web_ui_->call_data()[0];
CHECK(function_name == call_data.function_name());
return call_data.arg1();
}
// Gets the dictionary passed into a call to the |web_ui_| as the argument.
// There needs to be one call made, and its function name must be
// |function_name|.
const base::DictionaryValue* ExtractDictFromCallArg(
const std::string& function_name) {
const base::DictionaryValue* dict_value = nullptr;
CHECK(GetCallData(function_name)->GetAsDictionary(&dict_value));
return dict_value;
}
// Gets the list passed into a call to the |web_ui_| as the argument.
// There needs to be one call made, and its function name must be
// |function_name|.
const base::ListValue* ExtractListFromCallArg(
const std::string& function_name) {
const base::ListValue* list_value = nullptr;
CHECK(GetCallData(function_name)->GetAsList(&list_value));
return list_value;
}
// Gets the first element of the list passed in as the argument to a call to
// the |web_ui_| as a dictionary. There needs to be one call made, and its
// function name must be |function_name|.
const base::DictionaryValue* ExtractDictFromListFromCallArg(
const std::string& function_name) {
const base::ListValue* list_value = nullptr;
CHECK(GetCallData(function_name)->GetAsList(&list_value));
const base::DictionaryValue* dict_value = nullptr;
CHECK(list_value->GetDictionary(0, &dict_value));
return dict_value;
}
MockMediaRouter* router() { return &router_; }
protected:
std::unique_ptr<content::TestWebUI> web_ui_;
MockMediaRouter router_;
std::unique_ptr<MockMediaRouterUI> mock_media_router_ui_;
std::unique_ptr<TestMediaRouterWebUIMessageHandler> handler_;
const std::string provider_extension_id_;
};
TEST_F(MediaRouterWebUIMessageHandlerTest, UpdateSinks) {
MediaSink::Id sink_id("sinkId123");
MediaSinkWithCastModes media_sink_with_cast_modes =
CreateMediaSinkWithCastMode(sink_id, MediaCastMode::TAB_MIRROR);
handler_->UpdateSinks({media_sink_with_cast_modes});
const base::DictionaryValue* sinks_with_identity_value =
ExtractDictFromCallArg("media_router.ui.setSinkListAndIdentity");
// Email is not displayed if there is no sinks with domain.
EXPECT_FALSE(GetBooleanFromDict(sinks_with_identity_value, "showEmail"));
// Domain is not displayed if there is no sinks with domain.
EXPECT_FALSE(GetBooleanFromDict(sinks_with_identity_value, "showDomain"));
const base::ListValue* sinks_list_value = nullptr;
ASSERT_TRUE(sinks_with_identity_value->GetList("sinks", &sinks_list_value));
const base::DictionaryValue* sink_value = nullptr;
ASSERT_TRUE(sinks_list_value->GetDictionary(0, &sink_value));
EXPECT_EQ(sink_id, GetStringFromDict(sink_value, "id"));
EXPECT_EQ(media_sink_with_cast_modes.sink.name(),
GetStringFromDict(sink_value, "name"));
EXPECT_EQ(static_cast<int>(MediaCastMode::TAB_MIRROR),
GetIntegerFromDict(sink_value, "castModes"));
}
TEST_F(MediaRouterWebUIMessageHandlerTest, UpdateSinksWithIdentity) {
MediaSinkWithCastModes media_sink_with_cast_modes =
CreateMediaSinkWithCastMode("sinkId123", MediaCastMode::TAB_MIRROR);
media_sink_with_cast_modes.sink.set_domain(kUserDomainForTesting);
handler_->UpdateSinks({media_sink_with_cast_modes});
const base::DictionaryValue* sinks_with_identity_value =
ExtractDictFromCallArg("media_router.ui.setSinkListAndIdentity");
EXPECT_TRUE(GetBooleanFromDict(sinks_with_identity_value, "showEmail"));
// Sink domain is not displayed if it matches user domain.
EXPECT_FALSE(GetBooleanFromDict(sinks_with_identity_value, "showDomain"));
EXPECT_EQ(kUserEmailForTesting,
GetStringFromDict(sinks_with_identity_value, "userEmail"));
}
TEST_F(MediaRouterWebUIMessageHandlerTest,
UpdateSinksWithIdentityAndPseudoSink) {
MediaSinkWithCastModes media_sink_with_cast_modes =
CreateMediaSinkWithCastMode("pseudo:sinkId1", MediaCastMode::TAB_MIRROR);
media_sink_with_cast_modes.sink.set_domain(kUserDomainForTesting);
handler_->UpdateSinks({media_sink_with_cast_modes});
const base::DictionaryValue* sinks_with_identity_value =
ExtractDictFromCallArg("media_router.ui.setSinkListAndIdentity");
EXPECT_FALSE(GetBooleanFromDict(sinks_with_identity_value, "showEmail"));
}
TEST_F(MediaRouterWebUIMessageHandlerTest, UpdateSinksWithIdentityAndDomain) {
MediaSinkWithCastModes media_sink_with_cast_modes =
CreateMediaSinkWithCastMode("sinkId123", MediaCastMode::TAB_MIRROR);
std::string domain_name("google.com");
media_sink_with_cast_modes.sink.set_domain(domain_name);
handler_->UpdateSinks({media_sink_with_cast_modes});
const base::DictionaryValue* sinks_with_identity_value =
ExtractDictFromCallArg("media_router.ui.setSinkListAndIdentity");
// Domain is displayed for sinks with domains that are not the user domain.
EXPECT_TRUE(GetBooleanFromDict(sinks_with_identity_value, "showDomain"));
}
TEST_F(MediaRouterWebUIMessageHandlerTest, UpdateSinksWithNoDomain) {
MediaSinkWithCastModes media_sink_with_cast_modes =
CreateMediaSinkWithCastMode("sinkId123", MediaCastMode::TAB_MIRROR);
std::string user_email("nobody@gmail.com");
std::string user_domain("NO_HOSTED_DOMAIN");
std::string domain_name("default");
media_sink_with_cast_modes.sink.set_domain(domain_name);
handler_->SetEmailAndDomain(user_email, user_domain);
handler_->UpdateSinks({media_sink_with_cast_modes});
const base::DictionaryValue* sinks_with_identity_value =
ExtractDictFromCallArg("media_router.ui.setSinkListAndIdentity");
const base::ListValue* sinks_list_value = nullptr;
ASSERT_TRUE(sinks_with_identity_value->GetList("sinks", &sinks_list_value));
const base::DictionaryValue* sink_value = nullptr;
ASSERT_TRUE(sinks_list_value->GetDictionary(0, &sink_value));
// Domain should not be shown if there were only default sink domains.
EXPECT_FALSE(GetBooleanFromDict(sinks_with_identity_value, "showDomain"));
// Sink domain should be empty if user has no hosted domain.
EXPECT_EQ(std::string(), GetStringFromDict(sink_value, "domain"));
}
TEST_F(MediaRouterWebUIMessageHandlerTest, UpdateSinksWithDefaultDomain) {
MediaSinkWithCastModes media_sink_with_cast_modes =
CreateMediaSinkWithCastMode("sinkId123", MediaCastMode::TAB_MIRROR);
std::string domain_name("default");
media_sink_with_cast_modes.sink.set_domain(domain_name);
handler_->UpdateSinks({media_sink_with_cast_modes});
const base::DictionaryValue* sinks_with_identity_value =
ExtractDictFromCallArg("media_router.ui.setSinkListAndIdentity");
const base::ListValue* sinks_list_value = nullptr;
ASSERT_TRUE(sinks_with_identity_value->GetList("sinks", &sinks_list_value));
const base::DictionaryValue* sink_value = nullptr;
ASSERT_TRUE(sinks_list_value->GetDictionary(0, &sink_value));
// Domain should not be shown if there were only default sink domains.
EXPECT_FALSE(GetBooleanFromDict(sinks_with_identity_value, "showDomain"));
// Sink domain should be updated from 'default' to user domain.
EXPECT_EQ(kUserDomainForTesting, GetStringFromDict(sink_value, "domain"));
}
TEST_F(MediaRouterWebUIMessageHandlerTest, UpdateRoutes) {
const MediaRoute route = CreateRoute();
std::vector<MediaRoute::Id> joinable_route_ids = {route.media_route_id()};
std::unordered_map<MediaRoute::Id, MediaCastMode> current_cast_modes;
current_cast_modes.insert(
std::make_pair(route.media_route_id(), MediaCastMode::PRESENTATION));
handler_->UpdateRoutes({route}, joinable_route_ids, current_cast_modes);
const base::DictionaryValue* route_value =
ExtractDictFromListFromCallArg("media_router.ui.setRouteList");
EXPECT_EQ(route.media_route_id(), GetStringFromDict(route_value, "id"));
EXPECT_EQ(route.media_sink_id(), GetStringFromDict(route_value, "sinkId"));
EXPECT_EQ(route.description(), GetStringFromDict(route_value, "description"));
EXPECT_EQ(route.is_local(), GetBooleanFromDict(route_value, "isLocal"));
EXPECT_TRUE(GetBooleanFromDict(route_value, "canJoin"));
EXPECT_EQ(MediaCastMode::PRESENTATION,
GetIntegerFromDict(route_value, "currentCastMode"));
}
TEST_F(MediaRouterWebUIMessageHandlerTest, UpdateRoutesIncognito) {
handler_->set_incognito_for_test(true);
const MediaRoute route = CreateRoute();
handler_->UpdateRoutes({route}, std::vector<MediaRoute::Id>(),
std::unordered_map<MediaRoute::Id, MediaCastMode>());
const base::DictionaryValue* route_value =
ExtractDictFromListFromCallArg("media_router.ui.setRouteList");
EXPECT_EQ(route.media_route_id(), GetStringFromDict(route_value, "id"));
EXPECT_EQ(route.media_sink_id(), GetStringFromDict(route_value, "sinkId"));
EXPECT_EQ(route.description(), GetStringFromDict(route_value, "description"));
EXPECT_EQ(route.is_local(), GetBooleanFromDict(route_value, "isLocal"));
EXPECT_FALSE(GetBooleanFromDict(route_value, "canJoin"));
int actual_current_cast_mode = -1;
EXPECT_FALSE(
route_value->GetInteger("currentCastMode", &actual_current_cast_mode));
}
TEST_F(MediaRouterWebUIMessageHandlerTest, SetCastModesList) {
CastModeSet cast_modes({MediaCastMode::PRESENTATION,
MediaCastMode::TAB_MIRROR,
MediaCastMode::DESKTOP_MIRROR});
handler_->UpdateCastModes(cast_modes, "www.host.com",
MediaCastMode::PRESENTATION);
const base::ListValue* set_cast_mode_list =
ExtractListFromCallArg("media_router.ui.setCastModeList");
const base::DictionaryValue* cast_mode = nullptr;
size_t index = 0;
for (auto i = cast_modes.begin(); i != cast_modes.end(); i++) {
CHECK(set_cast_mode_list->GetDictionary(index++, &cast_mode));
EXPECT_EQ(static_cast<int>(*i), GetIntegerFromDict(cast_mode, "type"));
EXPECT_EQ(MediaCastModeToDescription(*i, "www.host.com"),
GetStringFromDict(cast_mode, "description"));
EXPECT_EQ("www.host.com", GetStringFromDict(cast_mode, "host"));
EXPECT_EQ(*i == MediaCastMode::PRESENTATION,
GetBooleanFromDict(cast_mode, "isForced"));
}
}
TEST_F(MediaRouterWebUIMessageHandlerTest, UpdateMediaRouteStatus) {
MediaStatus status;
status.title = "test title";
status.can_play_pause = true;
status.can_set_volume = true;
status.play_state = MediaStatus::PlayState::BUFFERING;
status.duration = base::TimeDelta::FromSeconds(90);
status.current_time = base::TimeDelta::FromSeconds(80);
status.volume = 0.9;
// |status.hangouts_extra_data->local_present| defaults to |false|.
status.hangouts_extra_data.emplace();
status.mirroring_extra_data.emplace(true);
handler_->UpdateMediaRouteStatus(status);
const base::DictionaryValue* status_value =
ExtractDictFromCallArg("media_router.ui.updateRouteStatus");
EXPECT_EQ(status.title, GetStringFromDict(status_value, "title"));
EXPECT_EQ(status.can_play_pause,
GetBooleanFromDict(status_value, "canPlayPause"));
EXPECT_EQ(status.can_mute, GetBooleanFromDict(status_value, "canMute"));
EXPECT_EQ(status.can_set_volume,
GetBooleanFromDict(status_value, "canSetVolume"));
EXPECT_EQ(status.can_seek, GetBooleanFromDict(status_value, "canSeek"));
EXPECT_EQ(static_cast<int>(status.play_state),
GetIntegerFromDict(status_value, "playState"));
EXPECT_EQ(status.is_muted, GetBooleanFromDict(status_value, "isMuted"));
EXPECT_EQ(status.duration.InSeconds(),
GetIntegerFromDict(status_value, "duration"));
EXPECT_EQ(status.current_time.InSeconds(),
GetIntegerFromDict(status_value, "currentTime"));
EXPECT_EQ(status.volume, GetDoubleFromDict(status_value, "volume"));
const base::Value* hangouts_extra_data = status_value->FindKeyOfType(
"hangoutsExtraData", base::Value::Type::DICTIONARY);
ASSERT_TRUE(hangouts_extra_data);
const base::Value* local_present_value = hangouts_extra_data->FindKeyOfType(
"localPresent", base::Value::Type::BOOLEAN);
ASSERT_TRUE(local_present_value);
EXPECT_FALSE(local_present_value->GetBool());
const base::Value* mirroring_extra_data = status_value->FindKeyOfType(
"mirroringExtraData", base::Value::Type::DICTIONARY);
ASSERT_TRUE(mirroring_extra_data);
const base::Value* media_remoting_value = mirroring_extra_data->FindKeyOfType(
"mediaRemotingEnabled", base::Value::Type::BOOLEAN);
ASSERT_TRUE(media_remoting_value);
EXPECT_TRUE(media_remoting_value->GetBool());
}
TEST_F(MediaRouterWebUIMessageHandlerTest, OnCreateRouteResponseReceived) {
MediaRoute route = CreateRoute();
bool incognito = false;
route.set_incognito(incognito);
handler_->OnCreateRouteResponseReceived(route.media_sink_id(), &route);
const content::TestWebUI::CallData& call_data = *web_ui_->call_data()[0];
EXPECT_EQ("media_router.ui.onCreateRouteResponseReceived",
call_data.function_name());
std::string sink_id_value;
ASSERT_TRUE(call_data.arg1()->GetAsString(&sink_id_value));
EXPECT_EQ(route.media_sink_id(), sink_id_value);
const base::DictionaryValue* route_value = nullptr;
ASSERT_TRUE(call_data.arg2()->GetAsDictionary(&route_value));
EXPECT_EQ(route.media_route_id(), GetStringFromDict(route_value, "id"));
EXPECT_EQ(route.media_sink_id(), GetStringFromDict(route_value, "sinkId"));
EXPECT_EQ(route.description(), GetStringFromDict(route_value, "description"));
EXPECT_EQ(route.is_local(), GetBooleanFromDict(route_value, "isLocal"));
bool route_for_display = false;
ASSERT_TRUE(call_data.arg3()->GetAsBoolean(&route_for_display));
EXPECT_TRUE(route_for_display);
}
TEST_F(MediaRouterWebUIMessageHandlerTest,
OnCreateRouteResponseReceivedIncognito) {
handler_->set_incognito_for_test(true);
MediaRoute route = CreateRoute();
bool incognito = true;
route.set_incognito(incognito);
handler_->OnCreateRouteResponseReceived(route.media_sink_id(), &route);
const content::TestWebUI::CallData& call_data = *web_ui_->call_data()[0];
EXPECT_EQ("media_router.ui.onCreateRouteResponseReceived",
call_data.function_name());
std::string sink_id_value;
ASSERT_TRUE(call_data.arg1()->GetAsString(&sink_id_value));
EXPECT_EQ(route.media_sink_id(), sink_id_value);
const base::DictionaryValue* route_value = nullptr;
ASSERT_TRUE(call_data.arg2()->GetAsDictionary(&route_value));
EXPECT_EQ(route.media_route_id(), GetStringFromDict(route_value, "id"));
EXPECT_EQ(route.media_sink_id(), GetStringFromDict(route_value, "sinkId"));
EXPECT_EQ(route.description(), GetStringFromDict(route_value, "description"));
EXPECT_EQ(route.is_local(), GetBooleanFromDict(route_value, "isLocal"));
bool route_for_display = false;
ASSERT_TRUE(call_data.arg3()->GetAsBoolean(&route_for_display));
EXPECT_TRUE(route_for_display);
}
TEST_F(MediaRouterWebUIMessageHandlerTest, UpdateIssue) {
std::string issue_title("An issue");
std::string issue_message("This is an issue");
IssueInfo::Action default_action = IssueInfo::Action::LEARN_MORE;
std::vector<IssueInfo::Action> secondary_actions;
secondary_actions.push_back(IssueInfo::Action::DISMISS);
MediaRoute::Id route_id("routeId123");
IssueInfo info(issue_title, default_action, IssueInfo::Severity::FATAL);
info.message = issue_message;
info.secondary_actions = secondary_actions;
info.route_id = route_id;
Issue issue(info);
const Issue::Id& issue_id = issue.id();
handler_->UpdateIssue(issue);
const base::DictionaryValue* issue_value =
ExtractDictFromCallArg("media_router.ui.setIssue");
// Initialized to invalid issue id.
EXPECT_EQ(issue_id, GetIntegerFromDict(issue_value, "id"));
EXPECT_EQ(issue_title, GetStringFromDict(issue_value, "title"));
EXPECT_EQ(issue_message, GetStringFromDict(issue_value, "message"));
// Initialized to invalid action type.
EXPECT_EQ(static_cast<int>(default_action),
GetIntegerFromDict(issue_value, "defaultActionType"));
EXPECT_EQ(static_cast<int>(secondary_actions[0]),
GetIntegerFromDict(issue_value, "secondaryActionType"));
EXPECT_EQ(route_id, GetStringFromDict(issue_value, "routeId"));
// The issue is blocking since it is FATAL.
EXPECT_TRUE(GetBooleanFromDict(issue_value, "isBlocking"));
}
TEST_F(MediaRouterWebUIMessageHandlerTest, RecordCastModeSelection) {
base::ListValue args;
args.AppendInteger(MediaCastMode::PRESENTATION);
EXPECT_CALL(*mock_media_router_ui_,
RecordCastModeSelection(MediaCastMode::PRESENTATION))
.Times(1);
handler_->OnReportSelectedCastMode(&args);
args.Clear();
args.AppendInteger(MediaCastMode::TAB_MIRROR);
EXPECT_CALL(*mock_media_router_ui_,
RecordCastModeSelection(MediaCastMode::TAB_MIRROR))
.Times(1);
handler_->OnReportSelectedCastMode(&args);
}
TEST_F(MediaRouterWebUIMessageHandlerTest, RetrieveCastModeSelection) {
base::ListValue args;
std::set<MediaCastMode> cast_modes = {MediaCastMode::TAB_MIRROR};
EXPECT_CALL(*mock_media_router_ui_, GetCastModes())
.WillRepeatedly(ReturnRef(cast_modes));
EXPECT_CALL(*mock_media_router_ui_, GetPresentationRequestSourceName())
.WillRepeatedly(Return("source"));
EXPECT_CALL(*mock_media_router_ui_,
UserSelectedTabMirroringForCurrentOrigin())
.WillOnce(Return(true));
handler_->OnRequestInitialData(&args);
const content::TestWebUI::CallData& call_data1 = *web_ui_->call_data()[0];
ASSERT_EQ("media_router.ui.setInitialData", call_data1.function_name());
const base::DictionaryValue* initial_data = nullptr;
ASSERT_TRUE(call_data1.arg1()->GetAsDictionary(&initial_data));
EXPECT_TRUE(GetBooleanFromDict(initial_data, "useTabMirroring"));
EXPECT_CALL(*mock_media_router_ui_,
UserSelectedTabMirroringForCurrentOrigin())
.WillOnce(Return(false));
handler_->OnRequestInitialData(&args);
const content::TestWebUI::CallData& call_data2 = *web_ui_->call_data()[1];
ASSERT_EQ("media_router.ui.setInitialData", call_data2.function_name());
ASSERT_TRUE(call_data2.arg1()->GetAsDictionary(&initial_data));
EXPECT_FALSE(GetBooleanFromDict(initial_data, "useTabMirroring"));
}
TEST_F(MediaRouterWebUIMessageHandlerTest, OnRouteDetailsOpenedAndClosed) {
const std::string route_id = "routeId123";
base::ListValue args_list;
base::DictionaryValue* args;
args_list.Append(std::make_unique<base::DictionaryValue>());
args_list.GetDictionary(0, &args);
args->SetString("routeId", route_id);
EXPECT_CALL(*mock_media_router_ui_, OnMediaControllerUIAvailable(route_id));
handler_->OnMediaControllerAvailable(&args_list);
args_list.Clear();
EXPECT_CALL(*mock_media_router_ui_, OnMediaControllerUIClosed());
handler_->OnMediaControllerClosed(&args_list);
}
TEST_F(MediaRouterWebUIMessageHandlerTest, OnMediaCommandsReceived) {
auto controller = base::MakeRefCounted<MockMediaRouteController>(
"routeId", profile(), router());
EXPECT_CALL(*mock_media_router_ui_, GetMediaRouteController())
.WillRepeatedly(Return(controller.get()));
MediaStatus status;
status.duration = base::TimeDelta::FromSeconds(100);
handler_->UpdateMediaRouteStatus(status);
base::ListValue args_list;
EXPECT_CALL(*controller, Play());
handler_->OnPlayCurrentMedia(&args_list);
EXPECT_CALL(*controller, Pause());
handler_->OnPauseCurrentMedia(&args_list);
base::DictionaryValue* args;
args_list.Append(std::make_unique<base::DictionaryValue>());
args_list.GetDictionary(0, &args);
const double time = 50.1;
args->SetDouble("time", time);
EXPECT_CALL(*controller, Seek(base::TimeDelta::FromSecondsD(time)));
handler_->OnSeekCurrentMedia(&args_list);
args->Clear();
args->SetBoolean("mute", true);
EXPECT_CALL(*controller, SetMute(true));
handler_->OnSetCurrentMediaMute(&args_list);
const double volume = 0.4;
args->Clear();
args->SetDouble("volume", volume);
EXPECT_CALL(*controller, SetVolume(volume));
handler_->OnSetCurrentMediaVolume(&args_list);
}
TEST_F(MediaRouterWebUIMessageHandlerTest, OnSetMediaRemotingEnabled) {
auto controller = base::MakeRefCounted<MirroringMediaRouteController>(
"routeId", profile(), router());
EXPECT_CALL(*mock_media_router_ui_, GetMediaRouteController())
.WillRepeatedly(Return(controller.get()));
base::ListValue args_list;
args_list.GetList().emplace_back(false);
handler_->OnSetMediaRemotingEnabled(&args_list);
EXPECT_FALSE(controller->media_remoting_enabled());
}
TEST_F(MediaRouterWebUIMessageHandlerTest, OnInvalidMediaCommandsReceived) {
auto controller = base::MakeRefCounted<MockMediaRouteController>(
"routeId", profile(), router());
EXPECT_CALL(*mock_media_router_ui_, GetMediaRouteController())
.WillRepeatedly(Return(controller.get()));
MediaStatus status;
status.duration = base::TimeDelta::FromSeconds(100);
handler_->UpdateMediaRouteStatus(status);
EXPECT_CALL(*controller, Seek(_)).Times(0);
EXPECT_CALL(*controller, SetVolume(_)).Times(0);
base::ListValue args_list;
base::DictionaryValue* args;
args_list.Append(std::make_unique<base::DictionaryValue>());
args_list.GetDictionary(0, &args);
// Seek positions greater than the duration or negative should be ignored.
args->SetDouble("time", 101);
handler_->OnSeekCurrentMedia(&args_list);
args->SetDouble("time", -10);
handler_->OnSeekCurrentMedia(&args_list);
args->Clear();
// Volumes outside of the [0, 1] range should be ignored.
args->SetDouble("volume", 1.5);
handler_->OnSetCurrentMediaVolume(&args_list);
args->SetDouble("volume", 1.5);
handler_->OnSetCurrentMediaVolume(&args_list);
}
TEST_F(MediaRouterWebUIMessageHandlerTest, OnRouteControllerInvalidated) {
handler_->OnRouteControllerInvalidated();
EXPECT_EQ(1u, web_ui_->call_data().size());
const content::TestWebUI::CallData& call_data = *web_ui_->call_data()[0];
EXPECT_EQ("media_router.ui.onRouteControllerInvalidated",
call_data.function_name());
}
} // namespace media_router