blob: 576ad26ebbc336b22ab7ec3425d44a3ba9f5d0c0 [file] [log] [blame]
// Copyright 2019 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/views/sharing/sharing_dialog_view.h"
#include <map>
#include <memory>
#include <string>
#include "base/strings/strcat.h"
#include "base/strings/utf_string_conversions.h"
#include "base/test/simple_test_clock.h"
#include "chrome/browser/sharing/click_to_call/click_to_call_ui_controller.h"
#include "chrome/browser/sharing/sharing_app.h"
#include "chrome/browser/sharing/sharing_metrics.h"
#include "chrome/browser/ui/views/hover_button.h"
#include "chrome/test/base/testing_profile.h"
#include "chrome/test/views/chrome_views_test_base.h"
#include "components/send_tab_to_self/target_device_info.h"
#include "components/sync_device_info/device_info.h"
#include "components/vector_icons/vector_icons.h"
#include "content/public/test/web_contents_tester.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/event_utils.h"
namespace {
class ClickToCallUiControllerMock : public ClickToCallUiController {
public:
explicit ClickToCallUiControllerMock(content::WebContents* web_contents)
: ClickToCallUiController(web_contents) {}
~ClickToCallUiControllerMock() override = default;
MOCK_METHOD1(OnDeviceChosen, void(const syncer::DeviceInfo& device));
MOCK_METHOD1(OnAppChosen, void(const SharingApp& app));
MOCK_METHOD1(OnHelpTextClicked, void(SharingDialogType dialog_type));
};
class SharingDialogViewMock : public SharingDialogView {
public:
SharingDialogViewMock(views::View* anchor_view,
content::WebContents* web_contents,
ClickToCallUiController* controller)
: SharingDialogView(anchor_view, web_contents, controller) {}
~SharingDialogViewMock() override = default;
// The delegate cannot find widget since it is created from a null profile.
// This method will be called inside ButtonPressed(). Unit tests will
// crash without mocking.
MOCK_METHOD0(CloseBubble, void());
};
} // namespace
MATCHER_P(DeviceEquals, device, "") {
return device->guid() == arg.guid();
}
MATCHER_P(AppEquals, app, "") {
return app->name == arg.name;
}
class SharingDialogViewTest : public ChromeViewsTestBase {
protected:
void SetUp() override {
ChromeViewsTestBase::SetUp();
profile_ = std::make_unique<TestingProfile>();
web_contents_ = content::WebContentsTester::CreateTestWebContents(
profile_.get(), nullptr);
// Create an anchor for the bubble.
views::Widget::InitParams params =
CreateParams(views::Widget::InitParams::TYPE_WINDOW);
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
anchor_widget_ = std::make_unique<views::Widget>();
anchor_widget_->Init(std::move(params));
controller_ =
std::make_unique<ClickToCallUiControllerMock>(web_contents_.get());
}
void TearDown() override {
anchor_widget_.reset();
ChromeViewsTestBase::TearDown();
}
std::vector<std::unique_ptr<syncer::DeviceInfo>> CreateDevices(int count) {
std::vector<std::unique_ptr<syncer::DeviceInfo>> devices;
for (int i = 0; i < count; i++) {
devices.emplace_back(std::make_unique<syncer::DeviceInfo>(
base::StrCat({"device_guid_", base::NumberToString(i)}),
base::StrCat({"device", base::NumberToString(i)}), "chrome_version",
"user_agent", sync_pb::SyncEnums_DeviceType_TYPE_PHONE, "device_id",
/*last_updated_timestamp=*/base::Time::Now(),
/*send_tab_to_self_receiving_enabled=*/false,
/*sharing_info=*/base::nullopt));
}
return devices;
}
std::vector<SharingApp> CreateApps(int count) {
std::vector<SharingApp> apps;
for (int i = 0; i < count; i++) {
apps.emplace_back(
&vector_icons::kOpenInNewIcon, gfx::Image(),
base::UTF8ToUTF16(base::StrCat({"app", base::NumberToString(i)})),
base::StrCat({"app_id_", base::NumberToString(i)}));
}
return apps;
}
std::unique_ptr<SharingDialogView> CreateDialogView(int devices, int apps) {
controller_->set_devices_for_testing(CreateDevices(devices));
controller_->set_apps_for_testing(CreateApps(apps));
auto dialog = std::make_unique<SharingDialogViewMock>(
anchor_widget_->GetContentsView(), /*web_contents=*/nullptr,
controller_.get());
dialog->Init();
return dialog;
}
std::unique_ptr<TestingProfile> profile_;
std::unique_ptr<content::WebContents> web_contents_;
std::unique_ptr<views::Widget> anchor_widget_;
std::unique_ptr<ClickToCallUiControllerMock> controller_;
};
TEST_F(SharingDialogViewTest, PopulateDialogView) {
auto dialog = CreateDialogView(/*devices=*/3, /*apps=*/2);
EXPECT_EQ(5UL, dialog->dialog_buttons_.size());
}
TEST_F(SharingDialogViewTest, DevicePressed) {
syncer::DeviceInfo device_info(
"device_guid_1", "device1", "chrome_version", "user_agent",
sync_pb::SyncEnums_DeviceType_TYPE_PHONE, "device_id",
/*last_updated_timestamp=*/base::Time::Now(),
/*send_tab_to_self_receiving_enabled=*/false,
/*sharing_info=*/base::nullopt);
EXPECT_CALL(*controller_.get(), OnDeviceChosen(DeviceEquals(&device_info)));
auto dialog = CreateDialogView(/*devices=*/3, /*apps=*/2);
const ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), 0, 0);
// Choose second device: device0(tag=0), device1(tag=1)
dialog->ButtonPressed(dialog->dialog_buttons_[1], event);
}
TEST_F(SharingDialogViewTest, AppPressed) {
SharingApp app(&vector_icons::kOpenInNewIcon, gfx::Image(),
base::UTF8ToUTF16("app0"), std::string());
EXPECT_CALL(*controller_.get(), OnAppChosen(AppEquals(&app)));
auto dialog = CreateDialogView(/*devices=*/3, /*apps=*/2);
const ui::MouseEvent event(ui::ET_MOUSE_PRESSED, gfx::Point(), gfx::Point(),
ui::EventTimeForNow(), 0, 0);
// Choose first app: device0(tag=0), device1(tag=1), device2(tag=2),
// app0(tag=3)
dialog->ButtonPressed(dialog->dialog_buttons_[3], event);
}
TEST_F(SharingDialogViewTest, HelpTextClickedEmpty) {
EXPECT_CALL(*controller_.get(),
OnHelpTextClicked(SharingDialogType::kEducationalDialog));
auto dialog = CreateDialogView(/*devices=*/0, /*apps=*/0);
dialog->StyledLabelLinkClicked(/*label=*/nullptr, /*range=*/{},
/*event_flags=*/0);
}
TEST_F(SharingDialogViewTest, HelpTextClickedOnlyApps) {
EXPECT_CALL(
*controller_.get(),
OnHelpTextClicked(SharingDialogType::kDialogWithoutDevicesWithApp));
auto dialog = CreateDialogView(/*devices=*/0, /*apps=*/1);
dialog->StyledLabelLinkClicked(/*label=*/nullptr, /*range=*/{},
/*event_flags=*/0);
}
TEST_F(SharingDialogViewTest, ThemeChangedEmptyList) {
controller_->set_send_result_for_testing(
SharingSendMessageResult::kDeviceNotFound);
auto dialog = CreateDialogView(/*devices=*/1, /*apps=*/1);
EXPECT_EQ(SharingDialogType::kErrorDialog, dialog->GetDialogType());
// Regression test for crbug.com/1001112
dialog->OnThemeChanged();
}