chromium/chromecast/browser/cast_content_gesture_handler_test.cc

// 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