blob: 1c52bf2d0ca7bc761b6f62cd1f1d352ae2eef2d9 [file] [log] [blame]
// Copyright 2018 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 "services/ws/drag_drop_delegate.h"
#include <memory>
#include <string>
#include <vector>
#include "base/files/file_path.h"
#include "base/macros.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "mojo/public/cpp/bindings/map.h"
#include "services/ws/test_change_tracker.h"
#include "services/ws/window_service_test_setup.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/client/drag_drop_client.h"
#include "ui/aura/mus/os_exchange_data_provider_mus.h"
#include "ui/aura/window.h"
#include "ui/base/dragdrop/drop_target_event.h"
#include "ui/base/dragdrop/file_info.h"
#include "ui/base/dragdrop/os_exchange_data.h"
#include "ui/wm/core/coordinate_conversion.h"
#include "ui/wm/core/default_screen_position_client.h"
#include "url/gurl.h"
namespace ws {
class DragDropDelegateTest : public testing::Test {
public:
DragDropDelegateTest() = default;
~DragDropDelegateTest() override = default;
// testing::Test
void SetUp() override {
window_ = window_tree_test_helper()->NewTopLevelWindow();
aura::client::SetScreenPositionClient(window_->GetRootWindow(),
&screen_position_client_);
}
void SetCanAcceptDrops(bool accepts_drops) {
window_tree_test_helper()->window_tree()->SetCanAcceptDrops(
window_tree_test_helper()->TransportIdForWindow(window_),
accepts_drops);
}
// Simulates drag starts with |data| at given |location| in |window_|. The
// drag is updated in UpdateDrag call before and should be completed with
// either PerformDrop or CancelDrag.
void StartDrag(const ui::OSExchangeData& data, const gfx::Point& location) {
DCHECK_EQ(nullptr, drag_data_);
drag_data_ = &data;
delegate()->OnDragEntered(ui::DropTargetEvent(
*drag_data_, gfx::PointF(location), gfx::PointF(location),
ui::DragDropTypes::DRAG_MOVE));
}
// Simulates drag moves at given |location| in |window_|.
void UpdateDrag(const gfx::Point& location) {
DCHECK_NE(nullptr, drag_data_);
delegate()->OnDragUpdated(ui::DropTargetEvent(
*drag_data_, gfx::PointF(location), gfx::PointF(location),
ui::DragDropTypes::DRAG_MOVE));
}
// Simulates drag finished with a drop at |location|.
void PerformDrop(const gfx::Point& location) {
DCHECK_NE(nullptr, drag_data_);
delegate()->OnPerformDrop(ui::DropTargetEvent(
*drag_data_, gfx::PointF(location), gfx::PointF(location),
ui::DragDropTypes::DRAG_MOVE));
drag_data_ = nullptr;
}
// Simulates a drag is canceled.
void EndDrag() {
DCHECK_NE(nullptr, drag_data_);
delegate()->OnDragExited();
drag_data_ = nullptr;
}
// Triggers a WindowTreeClient::OnDragDropStart and returns drag data.
using DragDataType = aura::OSExchangeDataProviderMus::Data;
DragDataType GetDragData(const ui::OSExchangeData& data) {
// A point in |window()|'s coordinates.
gfx::Point point = gfx::Rect(window()->bounds().size()).CenterPoint();
changes()->clear();
StartDrag(data, point);
EndDrag();
const Change& first_change = changes()->front();
DCHECK_EQ(CHANGE_TYPE_DRAG_DROP_START, first_change.type);
return mojo::FlatMapToMap(first_change.drag_data);
}
aura::client::DragDropDelegate* delegate() {
return aura::client::GetDragDropDelegate(window_);
}
aura::Window* window() { return window_; }
WindowTreeTestHelper* window_tree_test_helper() {
return setup_.window_tree_test_helper();
}
std::vector<Change>* changes() { return setup_.changes(); }
private:
wm::DefaultScreenPositionClient screen_position_client_;
WindowServiceTestSetup setup_;
aura::Window* window_ = nullptr;
const ui::OSExchangeData* drag_data_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(DragDropDelegateTest);
};
// Tests that DragDropDelegate is created when window can accept drops and
// destroyed otherwise.
TEST_F(DragDropDelegateTest, CreateAndReset) {
// No DragDropDelegate by default.
EXPECT_FALSE(delegate());
// DragDropDelegate is created when the window accepts drops.
SetCanAcceptDrops(true);
EXPECT_TRUE(delegate());
// DragDropDelegate is gone when the window accepts drops.
SetCanAcceptDrops(false);
EXPECT_FALSE(delegate());
}
// Tests that the window tree client gets correct drag data.
TEST_F(DragDropDelegateTest, DragData) {
SetCanAcceptDrops(true);
// String data.
{
const base::string16 kTestString = base::ASCIIToUTF16("dragged string");
ui::OSExchangeData data;
data.SetString(kTestString);
aura::OSExchangeDataProviderMus mus_provider(GetDragData(data));
base::string16 dropped_string;
EXPECT_TRUE(mus_provider.GetString(&dropped_string));
EXPECT_EQ(kTestString, dropped_string);
}
// URL data.
{
const GURL kTestURL("http://test.com");
const base::string16 kTestTitle = base::ASCIIToUTF16("test title");
ui::OSExchangeData data;
data.SetURL(kTestURL, kTestTitle);
aura::OSExchangeDataProviderMus mus_provider(GetDragData(data));
GURL dropped_url;
base::string16 dropped_title;
EXPECT_TRUE(mus_provider.GetURLAndTitle(
ui::OSExchangeData::DO_NOT_CONVERT_FILENAMES, &dropped_url,
&dropped_title));
EXPECT_EQ(kTestURL, dropped_url);
EXPECT_EQ(kTestTitle, dropped_title);
}
#if !defined(OS_WIN)
// File names.
// Exclude from Windows because OSExchangeDataProviderWin works in a different
// way and does not return the exactly the same filenames as the ones being
// set.
{
// No "display_name" since OSExchangeDataProviderMus does not support it.
const std::vector<ui::FileInfo> kTestFilenames = {
{base::FilePath(FILE_PATH_LITERAL("/tmp/test_file1")),
base::FilePath()},
{base::FilePath(FILE_PATH_LITERAL("/tmp/test_file2")),
base::FilePath()},
};
ui::OSExchangeData data;
data.SetFilenames(kTestFilenames);
aura::OSExchangeDataProviderMus mus_provider(GetDragData(data));
std::vector<ui::FileInfo> dropped_filenames;
EXPECT_TRUE(mus_provider.GetFilenames(&dropped_filenames));
EXPECT_EQ(kTestFilenames, dropped_filenames);
}
#endif
// HTML
{
const GURL kTestURL("http://test.com");
const base::string16 kTestHtml = base::ASCIIToUTF16(
"<HTML>\n<BODY>\n"
"<b>bold.</b> <i><b>This is bold italic.</b></i>\n"
"</BODY>\n</HTML>");
ui::OSExchangeData data;
data.SetHtml(kTestHtml, kTestURL);
aura::OSExchangeDataProviderMus mus_provider(GetDragData(data));
base::string16 dropped_html;
GURL dropped_url;
EXPECT_TRUE(mus_provider.GetHtml(&dropped_html, &dropped_url));
EXPECT_EQ(kTestHtml, dropped_html);
// Not testing url because OSExchangeDataProviderMus does not support it.
}
}
// Tests the window tree client sequence of drag enter and exit.
TEST_F(DragDropDelegateTest, EnterAndExit) {
SetCanAcceptDrops(true);
ui::OSExchangeData data;
data.SetString(base::ASCIIToUTF16("dragged string"));
// A point in |window()|'s coordinates.
gfx::Point point = gfx::Rect(window()->bounds().size()).CenterPoint();
changes()->clear();
StartDrag(data, point);
UpdateDrag(point);
EndDrag();
EXPECT_EQ(
std::vector<std::string>({"DragDropStart", "DragEnter window_id=0,1",
"DragOver window_id=0,1",
"DragLeave window_id=0,1", "DragDropDone"}),
ChangesToDescription1(*changes()));
}
// Tests the window tree client sequence of drag enter and drop.
TEST_F(DragDropDelegateTest, EnterAndDrop) {
SetCanAcceptDrops(true);
ui::OSExchangeData data;
data.SetString(base::ASCIIToUTF16("dragged string"));
// A point in |window()|'s coordinates.
gfx::Point point = gfx::Rect(window()->bounds().size()).CenterPoint();
changes()->clear();
StartDrag(data, point);
UpdateDrag(point);
PerformDrop(point);
EXPECT_EQ(
std::vector<std::string>({"DragDropStart", "DragEnter window_id=0,1",
"DragOver window_id=0,1",
"CompleteDrop window_id=0,1", "DragDropDone"}),
ChangesToDescription1(*changes()));
}
} // namespace ws