| // Copyright 2023 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ash/drag_drop/scoped_drag_drop_observer.h" |
| |
| #include "ash/drag_drop/drag_drop_controller.h" |
| #include "ash/drag_drop/draggable_test_view.h" |
| #include "ash/public/cpp/holding_space/holding_space_item.h" |
| #include "ash/public/cpp/test/shell_test_api.h" |
| #include "ash/test/ash_test_base.h" |
| #include "base/test/mock_callback.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/aura/client/drag_drop_client.h" |
| #include "ui/aura/window.h" |
| #include "ui/views/widget/widget.h" |
| |
| namespace ash { |
| |
| // Aliases. |
| using EventCallback = ScopedDragDropObserver::EventCallback; |
| using EventType = ScopedDragDropObserver::EventType; |
| using testing::AtLeast; |
| using testing::Conditional; |
| using testing::Eq; |
| using testing::IsNull; |
| using testing::NotNull; |
| |
| // ScopedDragDropObserverTest -------------------------------------------------- |
| |
| // Base class for tests of `ScopedDragDropObserver` parameterized by whether to |
| // test (a) `EventType::kDragCompleted` or (b) `EventType::kDragCancelled`. |
| class ScopedDragDropObserverTest |
| : public AshTestBase, |
| public testing::WithParamInterface</*test_scenario=*/EventType> { |
| public: |
| ScopedDragDropObserverTest() { |
| // Sanity check parameterization. |
| EXPECT_TRUE(GetTestScenario() == EventType::kDragCompleted || |
| GetTestScenario() == EventType::kDragCancelled); |
| } |
| |
| // Returns (a) `EventType::kDragCompleted` or (b) `EventType::kDragCancelled` |
| // depending on test parameterization. |
| EventType GetTestScenario() const { return GetParam(); } |
| |
| // Returns a `ScopedDragDropObserver` with the specified `event_callback`. |
| std::unique_ptr<ScopedDragDropObserver> CreateScopedDragDropObserver( |
| EventCallback event_callback) { |
| return std::make_unique<ScopedDragDropObserver>( |
| aura::client::GetDragDropClient( |
| widget_->GetNativeWindow()->GetRootWindow()), |
| std::move(event_callback)); |
| } |
| |
| // Moves the mouse to the center of the specified `widget`. |
| void MoveMouseTo(views::Widget* widget) { |
| GetEventGenerator()->MoveMouseTo( |
| widget->GetWindowBoundsInScreen().CenterPoint()); |
| } |
| |
| // Moves the mouse by the specified `x` and `y` offsets. |
| void MoveMouseBy(int x, int y) { |
| auto* event_generator = GetEventGenerator(); |
| event_generator->MoveMouseTo( |
| event_generator->current_screen_location() + gfx::Vector2d(x, y), |
| /*count=*/10); |
| } |
| |
| // Presses/releases the left button. |
| void PressLeftButton() { GetEventGenerator()->PressLeftButton(); } |
| void ReleaseLeftButton() { GetEventGenerator()->ReleaseLeftButton(); } |
| |
| // Returns the `widget_` with draggable contents. |
| views::Widget* widget() { return widget_.get(); } |
| |
| private: |
| // AshTestBase: |
| void SetUp() override { |
| AshTestBase::SetUp(); |
| |
| // Prevent blocking during drag-and-drop sequences. |
| ShellTestApi().drag_drop_controller()->SetDisableNestedLoopForTesting(true); |
| |
| // Create and show a `widget_` with draggable contents. |
| widget_ = CreateFramelessTestWidget(); |
| widget_->SetContentsView(std::make_unique<DraggableTestView>()); |
| widget_->CenterWindow(gfx::Size(100, 100)); |
| widget_->Show(); |
| } |
| |
| // Widget with draggable contents. |
| std::unique_ptr<views::Widget> widget_; |
| }; |
| |
| INSTANTIATE_TEST_SUITE_P(All, |
| ScopedDragDropObserverTest, |
| /*test_scenario=*/ |
| testing::Values(EventType::kDragCompleted, |
| EventType::kDragCancelled)); |
| |
| // Tests ----------------------------------------------------------------------- |
| |
| // Verifies that `EventCallback`s are run as expected. |
| TEST_P(ScopedDragDropObserverTest, EventCallback) { |
| base::MockCallback<EventCallback> event_callback; |
| |
| // Create observer. |
| auto scoped_drag_drop_observer = |
| CreateScopedDragDropObserver(event_callback.Get()); |
| |
| { |
| testing::InSequence sequence; |
| |
| // Expect one or more drag update events... |
| EXPECT_CALL(event_callback, |
| Run(Eq(EventType::kDragUpdated), /*event=*/NotNull())) |
| .Times(AtLeast(1)); |
| |
| // ...followed by a single drag completed or cancelled event. |
| EXPECT_CALL(event_callback, |
| Run(Eq(GetTestScenario()), |
| Conditional(GetTestScenario() == EventType::kDragCompleted, |
| /*event=*/NotNull(), /*event=*/IsNull()))); |
| } |
| |
| // Drag contents from `widget()`... |
| MoveMouseTo(widget()); |
| PressLeftButton(); |
| MoveMouseBy(/*x=*/100, /*y=*/100); |
| |
| // ...then cancel drag... |
| if (GetTestScenario() == EventType::kDragCancelled) { |
| PressAndReleaseKey(ui::VKEY_ESCAPE); |
| } |
| |
| // ...or complete drag. |
| ReleaseLeftButton(); |
| } |
| |
| } // namespace ash |