// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chromecast/browser/cast_content_gesture_handler.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/weak_ptr.h"
#include "chromecast/base/chromecast_switches.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/browser_test_base.h"
#include "testing/gmock/include/gmock/gmock.h"
// Gmock matchers and actions that we use below.
using testing::_;
using testing::AnyOf;
using testing::Eq;
using testing::Return;
using testing::SetArgPointee;
using testing::WithArg;
namespace chromecast {
namespace {
constexpr gfx::Point kLeftSidePoint(5, 50);
constexpr gfx::Point kOngoingBackGesturePoint1(70, 50);
constexpr gfx::Point kOngoingBackGesturePoint2(75, 50);
constexpr gfx::Point kValidBackGestureEndPoint(90, 50);
constexpr gfx::Point kPastTheEndPoint1(105, 50);
constexpr gfx::Point kPastTheEndPoint2(200, 50);
constexpr gfx::Point kTopSidePoint(100, 5);
constexpr gfx::Point kOngoingTopGesturePoint1(100, 70);
constexpr gfx::Point kOngoingTopGesturePoint2(100, 75);
constexpr gfx::Point kTopGestureEndPoint(100, 90);
constexpr gfx::Point kRightSidePoint(500, 50);
constexpr gfx::Point kOngoingRightGesturePoint1(400, 50);
constexpr gfx::Point kRightGestureEndPoint(200, 60);
class MockGestureHandler : public mojom::GestureHandler {
public:
MockGestureHandler() = default;
~MockGestureHandler() override = default;
MOCK_METHOD(void, OnBackGesture, (OnBackGestureCallback), (override));
MOCK_METHOD(void, OnBackGestureProgress, (const gfx::Point&), (override));
MOCK_METHOD(void, OnTopDragGestureProgress, (const gfx::Point&), (override));
MOCK_METHOD(void, OnTopDragGestureDone, (), (override));
MOCK_METHOD(void,
OnRightDragGestureProgress,
(const gfx::Point&),
(override));
MOCK_METHOD(void, OnRightDragGestureDone, (), (override));
MOCK_METHOD(void, OnBackGestureCancel, (), (override));
MOCK_METHOD(void, OnTapGesture, (), (override));
MOCK_METHOD(void, OnTapDownGesture, (), (override));
};
} // namespace
class CastContentGestureHandlerTest : public testing::Test {
public:
CastContentGestureHandlerTest() {}
void SetUp() final {
gesture_router_ = std::make_unique<GestureRouter>();
dispatcher_ = std::make_unique<CastContentGestureHandler>(
gesture_router_.get(), true);
gesture_router_->SetHandler(&handler_);
}
protected:
std::unique_ptr<GestureRouter> gesture_router_;
std::unique_ptr<CastContentGestureHandler> dispatcher_;
MockGestureHandler handler_;
};
// Verify the simple case of a left swipe with the right horizontal leads to
// back.
TEST_F(CastContentGestureHandlerTest, VerifySimpleBackSuccess) {
gesture_router_->SetCanTopDrag(false);
gesture_router_->SetCanGoBack(true);
EXPECT_CALL(handler_, OnBackGestureProgress(Eq(kOngoingBackGesturePoint1)));
EXPECT_CALL(handler_, OnBackGesture(_));
ASSERT_TRUE(dispatcher_->CanHandleSwipe(CastSideSwipeOrigin::LEFT));
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::BEGIN,
CastSideSwipeOrigin::LEFT, kLeftSidePoint);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::CONTINUE,
CastSideSwipeOrigin::LEFT,
kOngoingBackGesturePoint1);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::END,
CastSideSwipeOrigin::LEFT,
kValidBackGestureEndPoint);
}
// Verify that if the finger is not lifted, that's not a back gesture.
TEST_F(CastContentGestureHandlerTest, VerifyNoDispatchOnNoLift) {
gesture_router_->SetCanTopDrag(false);
gesture_router_->SetCanGoBack(true);
EXPECT_CALL(handler_, OnBackGestureProgress(Eq(kValidBackGestureEndPoint)));
EXPECT_CALL(handler_, OnBackGesture(_)).Times(0);
EXPECT_CALL(handler_, OnBackGestureProgress(Eq(kPastTheEndPoint1)));
ASSERT_TRUE(dispatcher_->CanHandleSwipe(CastSideSwipeOrigin::LEFT));
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::BEGIN,
CastSideSwipeOrigin::LEFT, kLeftSidePoint);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::CONTINUE,
CastSideSwipeOrigin::LEFT,
kValidBackGestureEndPoint);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::CONTINUE,
CastSideSwipeOrigin::LEFT, kPastTheEndPoint1);
}
// Verify that multiple 'continue' events still only lead to one back
// invocation.
TEST_F(CastContentGestureHandlerTest, VerifyOnlySingleDispatch) {
gesture_router_->SetCanTopDrag(false);
gesture_router_->SetCanGoBack(true);
EXPECT_CALL(handler_, OnBackGestureProgress(Eq(kValidBackGestureEndPoint)));
EXPECT_CALL(handler_, OnBackGestureProgress(Eq(kPastTheEndPoint1)));
EXPECT_CALL(handler_, OnBackGesture(_));
ASSERT_TRUE(dispatcher_->CanHandleSwipe(CastSideSwipeOrigin::LEFT));
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::BEGIN,
CastSideSwipeOrigin::LEFT, kLeftSidePoint);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::CONTINUE,
CastSideSwipeOrigin::LEFT,
kValidBackGestureEndPoint);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::CONTINUE,
CastSideSwipeOrigin::LEFT, kPastTheEndPoint1);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::END,
CastSideSwipeOrigin::LEFT, kPastTheEndPoint2);
}
// Verify that if the delegate says it doesn't handle back that we won't try to
// ask them to consume it.
TEST_F(CastContentGestureHandlerTest, VerifyDelegateDoesNotConsumeUnwanted) {
gesture_router_->SetCanTopDrag(false);
gesture_router_->SetCanGoBack(false);
ASSERT_FALSE(dispatcher_->CanHandleSwipe(CastSideSwipeOrigin::LEFT));
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::BEGIN,
CastSideSwipeOrigin::LEFT, kLeftSidePoint);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::CONTINUE,
CastSideSwipeOrigin::LEFT,
kValidBackGestureEndPoint);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::END,
CastSideSwipeOrigin::LEFT, kPastTheEndPoint2);
}
// Verify that a not-left gesture doesn't lead to a swipe.
TEST_F(CastContentGestureHandlerTest, VerifyNotLeftSwipeIsNotBack) {
gesture_router_->SetCanTopDrag(false);
ASSERT_FALSE(dispatcher_->CanHandleSwipe(CastSideSwipeOrigin::TOP));
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::BEGIN,
CastSideSwipeOrigin::TOP, kTopSidePoint);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::CONTINUE,
CastSideSwipeOrigin::TOP,
kOngoingTopGesturePoint2);
}
// Verify that if the gesture doesn't go far enough horizontally that we will
// not consider it a swipe.
TEST_F(CastContentGestureHandlerTest, VerifyNotFarEnoughRightIsNotBack) {
gesture_router_->SetCanTopDrag(false);
gesture_router_->SetCanGoBack(true);
EXPECT_CALL(handler_, OnBackGestureProgress(Eq(kOngoingBackGesturePoint1)));
EXPECT_CALL(handler_, OnBackGestureCancel());
ASSERT_TRUE(dispatcher_->CanHandleSwipe(CastSideSwipeOrigin::LEFT));
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::BEGIN,
CastSideSwipeOrigin::LEFT, kLeftSidePoint);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::CONTINUE,
CastSideSwipeOrigin::LEFT,
kOngoingBackGesturePoint1);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::END,
CastSideSwipeOrigin::LEFT,
kOngoingBackGesturePoint2);
}
// Verify that if the gesture ends before going far enough, that's also not a
// swipe.
TEST_F(CastContentGestureHandlerTest, VerifyNotFarEnoughRightAndEndIsNotBack) {
gesture_router_->SetCanTopDrag(false);
gesture_router_->SetCanGoBack(true);
EXPECT_CALL(handler_, OnBackGestureProgress(Eq(kOngoingBackGesturePoint1)));
EXPECT_CALL(handler_, OnBackGestureCancel());
ASSERT_TRUE(dispatcher_->CanHandleSwipe(CastSideSwipeOrigin::LEFT));
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::BEGIN,
CastSideSwipeOrigin::LEFT, kLeftSidePoint);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::CONTINUE,
CastSideSwipeOrigin::LEFT,
kOngoingBackGesturePoint1);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::END,
CastSideSwipeOrigin::LEFT,
kOngoingBackGesturePoint2);
}
// Verify simple top-down drag.
TEST_F(CastContentGestureHandlerTest, VerifySimpleTopSuccess) {
gesture_router_->SetCanTopDrag(true);
gesture_router_->SetCanGoBack(false);
EXPECT_CALL(handler_, OnTopDragGestureProgress(Eq(kOngoingTopGesturePoint1)));
EXPECT_CALL(handler_, OnTopDragGestureDone());
ASSERT_TRUE(dispatcher_->CanHandleSwipe(CastSideSwipeOrigin::TOP));
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::BEGIN,
CastSideSwipeOrigin::TOP, kTopSidePoint);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::CONTINUE,
CastSideSwipeOrigin::TOP,
kOngoingTopGesturePoint1);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::END,
CastSideSwipeOrigin::TOP, kTopGestureEndPoint);
}
// Verify simple right-to-left drag.
TEST_F(CastContentGestureHandlerTest, VerifySimpleRightSuccess) {
gesture_router_->SetCanRightDrag(true);
gesture_router_->SetCanTopDrag(false);
gesture_router_->SetCanGoBack(false);
EXPECT_CALL(handler_,
OnRightDragGestureProgress(Eq(kOngoingRightGesturePoint1)));
EXPECT_CALL(handler_, OnRightDragGestureDone());
ASSERT_TRUE(dispatcher_->CanHandleSwipe(CastSideSwipeOrigin::RIGHT));
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::BEGIN,
CastSideSwipeOrigin::RIGHT, kRightSidePoint);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::CONTINUE,
CastSideSwipeOrigin::RIGHT,
kOngoingRightGesturePoint1);
dispatcher_->HandleSideSwipe(CastSideSwipeEvent::END,
CastSideSwipeOrigin::RIGHT,
kRightGestureEndPoint);
}
} // namespace chromecast