ozone/wayland: Deduplicate drag-and-drop test code

Factor out common helper test code into WaylandDragDropTest class, clean
up and re-use it in both data and window drag controller unit tests.

R=msisov@igalia.com, tonikitoo@igalia.com

Bug: 1163544
Test: ozone_unittest --gtest_filter='*WaylandDataDragControllerTest.*'
Change-Id: I91f34f2f189783472fb8aa20764da305a5cbe793
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2613684
Reviewed-by: Maksim Sisov <msisov@igalia.com>
Reviewed-by: Antonio Gomes <tonikitoo@igalia.com>
Commit-Queue: Nick Yamane <nickdiego@igalia.com>
Cr-Commit-Position: refs/heads/master@{#841563}
diff --git a/ui/ozone/platform/wayland/BUILD.gn b/ui/ozone/platform/wayland/BUILD.gn
index ac195b3..c8492d70 100644
--- a/ui/ozone/platform/wayland/BUILD.gn
+++ b/ui/ozone/platform/wayland/BUILD.gn
@@ -383,6 +383,8 @@
     "host/wayland_window_manager_unittests.cc",
     "host/wayland_window_unittest.cc",
     "host/wayland_zaura_shell_unittest.cc",
+    "test/wayland_drag_drop_test.cc",
+    "test/wayland_drag_drop_test.h",
     "test/wayland_test.cc",
     "test/wayland_test.h",
   ]
diff --git a/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc b/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
index f44eed4..860e66c 100644
--- a/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_data_drag_controller_unittest.cc
@@ -33,6 +33,7 @@
 #include "ui/ozone/platform/wayland/test/test_data_offer.h"
 #include "ui/ozone/platform/wayland/test/test_data_source.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
+#include "ui/ozone/platform/wayland/test/wayland_drag_drop_test.h"
 #include "ui/ozone/platform/wayland/test/wayland_test.h"
 #include "ui/ozone/public/platform_clipboard.h"
 #include "ui/platform_window/platform_window_init_properties.h"
@@ -128,17 +129,13 @@
   int available_operations_ = ui::DragDropTypes::DRAG_NONE;
 };
 
-class WaylandDataDragControllerTest : public WaylandTest {
+class WaylandDataDragControllerTest : public WaylandDragDropTest {
  public:
   WaylandDataDragControllerTest() = default;
+  ~WaylandDataDragControllerTest() override = default;
 
   void SetUp() override {
-    WaylandTest::SetUp();
-
-    Sync();
-
-    data_device_manager_ = server_.data_device_manager();
-    DCHECK(data_device_manager_);
+    WaylandDragDropTest::SetUp();
 
     drag_handler_delegate_ = std::make_unique<MockDragHandlerDelegate>();
     drop_handler_ = std::make_unique<MockDropHandler>();
@@ -168,9 +165,14 @@
     return text;
   }
 
-  uint32_t NextSerial() const {
-    static uint32_t serial = 0;
-    return ++serial;
+  void RunDragLoopWithSampleData(WaylandWindow* origin_window, int operations) {
+    ASSERT_TRUE(origin_window);
+    OSExchangeData os_exchange_data;
+    os_exchange_data.SetString(sample_text_for_dnd());
+    origin_window->StartDrag(os_exchange_data, operations, /*cursor=*/{},
+                             /*can_grab_pointer=*/true,
+                             drag_handler_delegate_.get());
+    Sync();
   }
 
   std::unique_ptr<WaylandWindow> CreateTestWindow(
@@ -189,66 +191,6 @@
     return window;
   }
 
-  // TODO(crbug.com/1163544): Deduplicate DnD test helper code.
-  void SendDndEnter(WaylandWindow* window, const gfx::Point& location) {
-    EXPECT_TRUE(data_device_manager_->data_source());
-
-    auto* surface = server_.GetObject<wl::MockSurface>(
-        window->root_surface()->GetSurfaceId());
-
-    // Emulate server sending an wl_data_device::offer event.
-    auto* data_offer = data_device_manager_->data_device()->OnDataOffer();
-    data_offer->OnOffer(
-        kMimeTypeText, ToClipboardData(std::string(kSampleTextForDragAndDrop)));
-
-    // Emulate server sending an wl_data_device::enter event.
-    data_device_manager_->data_device()->OnEnter(
-        NextSerial(), surface->resource(), wl_fixed_from_int(location.x()),
-        wl_fixed_from_int(location.y()), data_offer);
-  }
-
-  void SendDndLeave() {
-    EXPECT_TRUE(data_device_manager_->data_source());
-    data_device_manager_->data_device()->OnLeave();
-  }
-
-  void SendDndCancelled() {
-    EXPECT_TRUE(data_device_manager_->data_source());
-    data_device_manager_->data_source()->OnCancelled();
-  }
-
-  void ReadDataWhenSourceIsReady() {
-    Sync();
-
-    if (!data_device_manager_->data_source()) {
-      // The data source is created asynchronously via the window's data drag
-      // controller.  If it is null now, it means that the task for that has not
-      // yet executed, and we have to come later.
-      base::ThreadTaskRunnerHandle::Get()->PostTask(
-          FROM_HERE,
-          base::BindOnce(
-              &WaylandDataDragControllerTest::ReadDataWhenSourceIsReady,
-              base::Unretained(this)));
-      return;
-    }
-
-    // Now the server can read the data and give it to our callback.
-    base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
-    auto callback = base::BindOnce(
-        [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
-          std::string result(data.begin(), data.end());
-          EXPECT_EQ(kSampleTextForDragAndDrop, result);
-          loop->Quit();
-        },
-        &run_loop);
-    data_device_manager_->data_source()->ReadData(kMimeTypeTextUtf8,
-                                                  std::move(callback));
-    run_loop.Run();
-
-    data_device_manager_->data_source()->OnCancelled();
-    Sync();
-  }
-
   void ScheduleDragCancel() {
     ScheduleTestTask(base::BindOnce(
         [](WaylandDataDragControllerTest* self) {
@@ -265,29 +207,7 @@
         base::Unretained(this)));
   }
 
-  void ScheduleTestTask(base::OnceClosure test_task) {
-    base::ThreadTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE,
-        base::BindOnce(&WaylandDataDragControllerTest::RunTestTask,
-                       base::Unretained(this), std::move(test_task)));
-  }
-
-  void RunTestTask(base::OnceClosure test_task) {
-    Sync();
-
-    // The data source is created asynchronously by the data drag controller. If
-    // it is null at this point, it means that the task for that has not yet
-    // executed, and we have to try again a bit later.
-    if (!data_device_manager_->data_source()) {
-      ScheduleTestTask(std::move(test_task));
-      return;
-    }
-
-    std::move(test_task).Run();
-  }
-
  protected:
-  wl::TestDataDeviceManager* data_device_manager_;
   std::unique_ptr<MockDropHandler> drop_handler_;
   std::unique_ptr<MockDragHandlerDelegate> drag_handler_delegate_;
 };
@@ -296,21 +216,31 @@
   const bool restored_focus = window_->has_pointer_focus();
   window_->SetPointerFocus(true);
 
-  // The client starts dragging.
-  ASSERT_EQ(PlatformWindowType::kWindow, window_->type());
-  OSExchangeData os_exchange_data;
-  os_exchange_data.SetString(sample_text_for_dnd());
+  auto test = [](WaylandDataDragControllerTest* self) {
+    // Now the server can read the data and give it to our callback.
+    base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed);
+    auto read_callback = base::BindOnce(
+        [](base::RunLoop* loop, std::vector<uint8_t>&& data) {
+          std::string result(data.begin(), data.end());
+          EXPECT_EQ(kSampleTextForDragAndDrop, result);
+          loop->Quit();
+        },
+        &run_loop);
+    self->ReadData(kMimeTypeTextUtf8, std::move(read_callback));
+    run_loop.Run();
 
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&WaylandDataDragControllerTest::ReadDataWhenSourceIsReady,
-                     base::Unretained(this)));
+    self->SendDndCancelled();
+    self->Sync();
+  };
 
-  window_->StartDrag(os_exchange_data,
-                     DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE, {},
-                     /*can_grab_pointer=*/true, drag_handler_delegate_.get());
-  Sync();
+  // Post test task to be performed asynchronously once the dnd-related protocol
+  // objects are ready.
+  ScheduleTestTask(base::BindOnce(test, base::Unretained(this)));
 
+  RunDragLoopWithSampleData(
+      window_.get(), DragDropTypes::DRAG_COPY | DragDropTypes::DRAG_MOVE);
+
+  // Ensure drag delegate it properly reset when the drag loop quits.
   EXPECT_FALSE(data_device()->drag_delegate_);
 
   window_->SetPointerFocus(restored_focus);
@@ -564,13 +494,11 @@
   const bool restored_focus = window_->has_pointer_focus();
   window_->SetPointerFocus(true);
 
+  // Schedule a wl_data_source::cancelled event to be sent asynchronously
+  // once the drag session gets started.
   ScheduleDragCancel();
 
-  OSExchangeData os_exchange_data;
-  os_exchange_data.SetString(sample_text_for_dnd());
-  window_->StartDrag(os_exchange_data, DragDropTypes::DRAG_COPY, {},
-                     /*can_grab_pointer=*/true, drag_handler_delegate_.get());
-  Sync();
+  RunDragLoopWithSampleData(window_.get(), DragDropTypes::DRAG_COPY);
 
   window_->SetPointerFocus(restored_focus);
 }
@@ -616,9 +544,6 @@
   ASSERT_EQ(PlatformWindowType::kWindow, window_1->type());
 
   auto test = [](WaylandDataDragControllerTest* self) {
-    // Emulate server sending an dnd offer + enter events for |window_1|.
-    self->SendDndEnter(self->window(), gfx::Point(10, 10));
-
     // Init and open |target_window|.
     MockPlatformWindowDelegate delegate_2;
     auto window_2 = self->CreateTestWindow(PlatformWindowType::kWindow,
@@ -645,12 +570,8 @@
   // started.
   ScheduleTestTask(base::BindOnce(test, base::Unretained(this)));
 
-  // Request to start the drag session, which spins a nested run loop.
-  OSExchangeData os_exchange_data;
-  os_exchange_data.SetString(sample_text_for_dnd());
-  window_1->StartDrag(os_exchange_data, DragDropTypes::DRAG_COPY, {}, true,
-                      drag_handler_delegate_.get());
-  Sync();
+  RunDragLoopWithSampleData(window_.get(), DragDropTypes::DRAG_COPY);
+
   window_1->SetPointerFocus(restored_focus);
 }
 
@@ -662,29 +583,31 @@
 
   auto test = [](WaylandDataDragControllerTest* self,
                  PlatformWindowType window_type) {
-    // Emulate server sending an dnd offer + enter events for |origin_window|.
-    self->SendDndEnter(self->window(), gfx::Point(10, 10));
-    EXPECT_CALL(*self->drop_handler(), MockOnDragEnter()).Times(1);
-    EXPECT_CALL(*self->drop_handler(), MockDragMotion(_, _, _)).Times(1);
-    self->Sync();
-
     // Init and open |target_window|.
-    MockPlatformWindowDelegate delegate_2;
-    auto window_2 =
-        self->CreateTestWindow(window_type, gfx::Size(100, 40), &delegate_2);
+    MockPlatformWindowDelegate aux_window_delegate;
+    auto aux_window = self->CreateTestWindow(window_type, gfx::Size(100, 40),
+                                             &aux_window_delegate);
 
-    // Leave |origin_window| and enter non-toplevel |window_2|.
+    // Leave |origin_window| and enter non-toplevel |aux_window|.
     self->SendDndLeave();
     EXPECT_CALL(*self->drop_handler(), OnDragLeave).Times(1);
+    self->Sync();
 
-    self->SendDndEnter(window_2.get(), {});
+    self->SendDndEnter(aux_window.get(), {});
     EXPECT_CALL(*self->drop_handler(), MockOnDragEnter()).Times(1);
     EXPECT_CALL(*self->drop_handler(), MockDragMotion(_, _, _)).Times(1);
     self->Sync();
 
+    // Goes back to |origin_window|, as |aux_window| is going to get destroyed
+    // once this test task finishes.
     self->SendDndLeave();
     EXPECT_CALL(*self->drop_handler(), OnDragLeave).Times(1);
     self->Sync();
+
+    self->SendDndEnter(self->window(), {});
+    EXPECT_CALL(*self->drop_handler(), MockOnDragEnter()).Times(1);
+    EXPECT_CALL(*self->drop_handler(), MockDragMotion(_, _, _)).Times(1);
+    self->Sync();
   };
 
   // Post test tasks, for each non-toplevel window type, to be performed
@@ -700,11 +623,8 @@
   ScheduleDragCancel();
 
   // Request to start the drag session, which spins a nested run loop.
-  OSExchangeData os_exchange_data;
-  os_exchange_data.SetString(sample_text_for_dnd());
-  origin_window->StartDrag(os_exchange_data, DragDropTypes::DRAG_COPY, {}, true,
-                           drag_handler_delegate_.get());
-  Sync();
+  RunDragLoopWithSampleData(origin_window, DragDropTypes::DRAG_COPY);
+
   origin_window->SetPointerFocus(restored_focus);
 }
 
diff --git a/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc b/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
index db39448..55e173de 100644
--- a/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
+++ b/ui/ozone/platform/wayland/host/wayland_window_drag_controller_unittest.cc
@@ -30,7 +30,7 @@
 #include "ui/ozone/platform/wayland/test/test_data_offer.h"
 #include "ui/ozone/platform/wayland/test/test_data_source.h"
 #include "ui/ozone/platform/wayland/test/test_wayland_server_thread.h"
-#include "ui/ozone/platform/wayland/test/wayland_test.h"
+#include "ui/ozone/platform/wayland/test/wayland_drag_drop_test.h"
 #include "ui/ozone/test/mock_platform_window_delegate.h"
 #include "ui/platform_window/extensions/wayland_extension.h"
 #include "ui/platform_window/platform_window_delegate.h"
@@ -41,14 +41,14 @@
 
 namespace ui {
 
-class WaylandWindowDragControllerTest : public WaylandTest,
-                                        public wl::TestDataDevice::Delegate {
+class WaylandWindowDragControllerTest : public WaylandDragDropTest {
  public:
   WaylandWindowDragControllerTest() = default;
   ~WaylandWindowDragControllerTest() override = default;
 
   void SetUp() override {
-    WaylandTest::SetUp();
+    WaylandDragDropTest::SetUp();
+
     screen_ = std::make_unique<WaylandScreen>(connection_.get());
 
     wl_seat_send_capabilities(server_.seat()->resource(),
@@ -59,16 +59,6 @@
 
     EXPECT_FALSE(window_->has_pointer_focus());
     EXPECT_EQ(State::kIdle, drag_controller()->state());
-
-    data_device_manager_ = server_.data_device_manager();
-    DCHECK(data_device_manager_);
-
-    source_ = nullptr;
-    data_device_manager_->data_device()->set_delegate(this);
-  }
-
-  void TearDown() override {
-    data_device_manager_->data_device()->set_delegate(nullptr);
   }
 
   WaylandWindowDragController* drag_controller() const {
@@ -79,52 +69,9 @@
     return connection_->wayland_window_manager();
   }
 
-  uint32_t NextSerial() const {
-    static uint32_t serial = 0;
-    return ++serial;
-  }
-
-  uint32_t NextTime() const {
-    static uint32_t timestamp = 0;
-    return ++timestamp;
-  }
-
  protected:
   using State = WaylandWindowDragController::State;
 
-  // wl::TestDataDevice::Delegate:
-  void StartDrag(wl::TestDataSource* source,
-                 wl::MockSurface* origin,
-                 uint32_t serial) override {
-    EXPECT_FALSE(source_);
-    source_ = source;
-    OfferAndEnter(origin);
-  }
-
-  // Helper functions
-  void SendDndMotion(const gfx::Point& location) {
-    EXPECT_TRUE(source_);
-    wl_fixed_t x = wl_fixed_from_int(location.x());
-    wl_fixed_t y = wl_fixed_from_int(location.y());
-    data_device_manager_->data_device()->OnMotion(NextTime(), x, y);
-  }
-
-  void SendDndEnter(WaylandWindow* window) {
-    EXPECT_TRUE(window);
-    OfferAndEnter(server_.GetObject<wl::MockSurface>(
-        window->root_surface()->GetSurfaceId()));
-  }
-
-  void SendDndLeave() {
-    EXPECT_TRUE(source_);
-    data_device_manager_->data_device()->OnLeave();
-  }
-
-  void SendDndDrop() {
-    EXPECT_TRUE(source_);
-    source_->OnCancelled();
-  }
-
   void SendPointerEnter(WaylandWindow* window,
                         MockPlatformWindowDelegate* delegate) {
     auto* surface = server_.GetObject<wl::MockSurface>(
@@ -181,24 +128,17 @@
               screen_->GetLocalProcessWidgetAtPoint(location, {}));
   }
 
-  void OfferAndEnter(wl::MockSurface* surface) {
-    EXPECT_TRUE(source_);
-    auto* data_device = data_device_manager_->data_device();
-    auto* offer = data_device->OnDataOffer();
-    EXPECT_EQ(1u, source_->mime_types().size());
-    for (const auto& mime_type : source_->mime_types())
-      offer->OnOffer(mime_type, {});
-
-    wl_data_device_send_enter(data_device->resource(), NextSerial(),
-                              surface->resource(), 0, 0, offer->resource());
-  }
+  // For the context of window drag, "drop" is detected through
+  // wl_data_source::cancelled in the regular case. Unless extended-drag
+  // protocol is available.
+  //
+  // TODO(crbug.com/1116431): Support extended-drag in test compositor.
+  void SendDndDrop() { SendDndCancelled(); }
 
   // client objects
   std::unique_ptr<WaylandScreen> screen_;
 
   // server objects
-  wl::TestDataDeviceManager* data_device_manager_;
-  wl::TestDataSource* source_;
   wl::MockPointer* pointer_;
 };
 
@@ -471,7 +411,7 @@
 
         // Exit |source_window| and enter the |target_window|.
         SendDndLeave();
-        SendDndEnter(target_window);
+        SendDndEnter(target_window, {});
         test_step = kEnteredTarget;
       });
 
diff --git a/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc b/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc
new file mode 100644
index 0000000..259e8541
--- /dev/null
+++ b/ui/ozone/platform/wayland/test/wayland_drag_drop_test.cc
@@ -0,0 +1,127 @@
+// Copyright 2021 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 "ui/ozone/platform/wayland/test/wayland_drag_drop_test.h"
+
+#include <wayland-util.h>
+
+#include <cstdint>
+
+#include "base/callback.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gfx/geometry/point.h"
+#include "ui/ozone/platform/wayland/host/wayland_window.h"
+#include "ui/ozone/platform/wayland/test/mock_surface.h"
+#include "ui/ozone/platform/wayland/test/test_data_device.h"
+#include "ui/ozone/platform/wayland/test/test_data_device_manager.h"
+#include "ui/ozone/platform/wayland/test/test_data_offer.h"
+#include "ui/ozone/platform/wayland/test/test_data_source.h"
+
+namespace ui {
+
+WaylandDragDropTest::WaylandDragDropTest() = default;
+
+void WaylandDragDropTest::SendDndEnter(WaylandWindow* window,
+                                       const gfx::Point& location) {
+  auto* surface = server_.GetObject<wl::MockSurface>(
+      window->root_surface()->GetSurfaceId());
+  OfferAndEnter(surface, location);
+}
+
+void WaylandDragDropTest::SendDndLeave() {
+  data_device_manager_->data_device()->OnLeave();
+}
+
+void WaylandDragDropTest::SendDndMotion(const gfx::Point& location) {
+  EXPECT_TRUE(data_source_);
+  wl_fixed_t x = wl_fixed_from_int(location.x());
+  wl_fixed_t y = wl_fixed_from_int(location.y());
+  data_device_manager_->data_device()->OnMotion(NextTime(), x, y);
+}
+
+void WaylandDragDropTest::SendDndCancelled() {
+  EXPECT_TRUE(data_source_);
+  data_source_->OnCancelled();
+}
+
+void WaylandDragDropTest::ReadData(
+    const std::string& mime_type,
+    wl::TestDataSource::ReadDataCallback callback) {
+  ASSERT_TRUE(data_source_);
+  data_source_->ReadData(mime_type, std::move(callback));
+}
+
+void WaylandDragDropTest::SetUp() {
+  WaylandTest::SetUp();
+  Sync();
+
+  data_device_manager_ = server_.data_device_manager();
+  ASSERT_TRUE(data_device_manager_);
+
+  data_source_ = nullptr;
+  data_device_manager_->data_device()->set_delegate(this);
+}
+
+void WaylandDragDropTest::TearDown() {
+  data_device_manager_->data_device()->set_delegate(nullptr);
+  data_device_manager_ = nullptr;
+}
+
+// wl::TestDataDevice::Delegate:
+void WaylandDragDropTest::StartDrag(wl::TestDataSource* source,
+                                    wl::MockSurface* origin,
+                                    uint32_t serial) {
+  EXPECT_FALSE(data_source_);
+  data_source_ = source;
+  OfferAndEnter(origin, {});
+}
+
+uint32_t WaylandDragDropTest::NextSerial() const {
+  static uint32_t serial = 0;
+  return ++serial;
+}
+
+uint32_t WaylandDragDropTest::NextTime() const {
+  static uint32_t timestamp = 0;
+  return ++timestamp;
+}
+
+void WaylandDragDropTest::OfferAndEnter(wl::MockSurface* surface,
+                                        const gfx::Point& location) {
+  ASSERT_TRUE(data_source_);
+  auto* data_device = data_device_manager_->data_device();
+
+  // Emulate server sending an wl_data_device::offer event.
+  auto* data_offer = data_device->OnDataOffer();
+  for (const auto& mime_type : data_source_->mime_types())
+    data_offer->OnOffer(mime_type, {});
+
+  // Emulate server sending an wl_data_device::enter event.
+  wl_data_device_send_enter(
+      data_device->resource(), NextSerial(), surface->resource(),
+      wl_fixed_from_int(location.x()), wl_fixed_from_int(location.y()),
+      data_offer->resource());
+}
+
+void WaylandDragDropTest::ScheduleTestTask(base::OnceClosure test_task) {
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE, base::BindOnce(&WaylandDragDropTest::RunTestTask,
+                                base::Unretained(this), std::move(test_task)));
+}
+
+void WaylandDragDropTest::RunTestTask(base::OnceClosure test_task) {
+  Sync();
+
+  // The data source is created asynchronously by the drag controller. If it is
+  // null at this point, it means that the task for that has not yet executed,
+  // so try again a bit later.
+  if (!data_device_manager_->data_source()) {
+    ScheduleTestTask(std::move(test_task));
+    return;
+  }
+
+  std::move(test_task).Run();
+}
+
+}  // namespace ui
diff --git a/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h b/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h
new file mode 100644
index 0000000..3455909
--- /dev/null
+++ b/ui/ozone/platform/wayland/test/wayland_drag_drop_test.h
@@ -0,0 +1,68 @@
+// Copyright 2021 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.
+
+#ifndef UI_OZONE_PLATFORM_WAYLAND_TEST_WAYLAND_DRAG_DROP_TEST_H_
+#define UI_OZONE_PLATFORM_WAYLAND_TEST_WAYLAND_DRAG_DROP_TEST_H_
+
+#include "base/callback_forward.h"
+#include "ui/ozone/platform/wayland/test/test_data_device.h"
+#include "ui/ozone/platform/wayland/test/test_data_source.h"
+#include "ui/ozone/platform/wayland/test/wayland_test.h"
+
+namespace gfx {
+class Point;
+}
+
+namespace wl {
+class MockSurface;
+class TestDataDeviceManager;
+}  // namespace wl
+
+namespace ui {
+
+class WaylandWindow;
+
+// Base class for Wayland drag-and-drop tests. Public methods allow test code to
+// emulate dnd-related events from the test compositor and can be used in both
+// data and window dragging test cases.
+class WaylandDragDropTest : public WaylandTest,
+                            public wl::TestDataDevice::Delegate {
+ public:
+  WaylandDragDropTest();
+  WaylandDragDropTest(const WaylandDragDropTest&) = delete;
+  WaylandDragDropTest& operator=(const WaylandDragDropTest&) = delete;
+
+  // These are public for convenience, as they must be callable from lambda
+  // functions, usually posted to task queue while the drag loop runs.
+  void SendDndEnter(WaylandWindow* window, const gfx::Point& location);
+  void SendDndLeave();
+  void SendDndMotion(const gfx::Point& location);
+  void SendDndCancelled();
+  void ReadData(const std::string& mime_type,
+                wl::TestDataSource::ReadDataCallback callback);
+
+ protected:
+  // WaylandTest:
+  void SetUp() override;
+  void TearDown() override;
+
+  // wl::TestDataDevice::Delegate:
+  void StartDrag(wl::TestDataSource* source,
+                 wl::MockSurface* origin,
+                 uint32_t serial) override;
+
+  void OfferAndEnter(wl::MockSurface* surface, const gfx::Point& location);
+  uint32_t NextSerial() const;
+  uint32_t NextTime() const;
+  void ScheduleTestTask(base::OnceClosure test_task);
+  void RunTestTask(base::OnceClosure test_task);
+
+  // Server objects
+  wl::TestDataDeviceManager* data_device_manager_;
+  wl::TestDataSource* data_source_;
+};
+
+}  // namespace ui
+
+#endif  // UI_OZONE_PLATFORM_WAYLAND_TEST_WAYLAND_DRAG_DROP_TEST_H_