#include "device/gamepad/abstract_haptic_gamepad.h"
#include <memory>
#include "base/functional/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_runner.h"
#include "base/test/task_environment.h"
#include "device/gamepad/public/mojom/gamepad.mojom.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace device {
namespace {
constexpr double kDurationMillis = 1.0;
constexpr double kNonZeroStartDelayMillis = 1.0;
constexpr double kZeroStartDelayMillis = 0.0;
constexpr double kStrongMagnitude = 1.0;
constexpr double kWeakMagnitude = 0.5;
constexpr base::TimeDelta kPendingTaskDuration =
base::Milliseconds(kDurationMillis);
class FakeHapticGamepad final : public AbstractHapticGamepad {
public:
FakeHapticGamepad() : set_vibration_count_(0), set_zero_vibration_count_(0) {}
~FakeHapticGamepad() override = default;
void SetVibration(mojom::GamepadEffectParametersPtr params) override {
set_vibration_count_++;
}
void SetZeroVibration() override { set_zero_vibration_count_++; }
base::WeakPtr<AbstractHapticGamepad> GetWeakPtr() override {
return weak_factory_.GetWeakPtr();
}
int set_vibration_count_;
int set_zero_vibration_count_;
base::WeakPtrFactory<FakeHapticGamepad> weak_factory_{this};
};
class AbstractHapticGamepadTest : public testing::Test {
public:
AbstractHapticGamepadTest()
: first_callback_count_(0),
second_callback_count_(0),
first_callback_result_(
mojom::GamepadHapticsResult::GamepadHapticsResultError),
second_callback_result_(
mojom::GamepadHapticsResult::GamepadHapticsResultError),
gamepad_(std::make_unique<FakeHapticGamepad>()) {}
AbstractHapticGamepadTest(const AbstractHapticGamepadTest&) = delete;
AbstractHapticGamepadTest& operator=(const AbstractHapticGamepadTest&) =
delete;
void TearDown() override { gamepad_->Shutdown(); }
void PostPlayEffect(
mojom::GamepadHapticEffectType type,
double duration,
double start_delay,
mojom::GamepadHapticsManager::PlayVibrationEffectOnceCallback callback) {
gamepad_->PlayEffect(
type,
mojom::GamepadEffectParameters::New(
duration, start_delay, kStrongMagnitude, kWeakMagnitude,
0, 0),
std::move(callback), base::SingleThreadTaskRunner::GetCurrentDefault());
}
void PostResetVibration(
mojom::GamepadHapticsManager::ResetVibrationActuatorCallback callback) {
gamepad_->ResetVibration(std::move(callback),
base::SingleThreadTaskRunner::GetCurrentDefault());
}
void FirstCallback(mojom::GamepadHapticsResult result) {
first_callback_count_++;
first_callback_result_ = result;
}
void SecondCallback(mojom::GamepadHapticsResult result) {
second_callback_count_++;
second_callback_result_ = result;
}
int first_callback_count_;
int second_callback_count_;
mojom::GamepadHapticsResult first_callback_result_;
mojom::GamepadHapticsResult second_callback_result_;
std::unique_ptr<FakeHapticGamepad> gamepad_;
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
};
TEST_F(AbstractHapticGamepadTest, PlayEffectTest) {
EXPECT_EQ(0, gamepad_->set_vibration_count_);
EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(0, first_callback_count_);
PostPlayEffect(
mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble,
kDurationMillis, kZeroStartDelayMillis,
base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
base::Unretained(this)));
task_environment_.RunUntilIdle();
EXPECT_EQ(1, gamepad_->set_vibration_count_);
EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(0, first_callback_count_);
EXPECT_TRUE(task_environment_.NextTaskIsDelayed());
task_environment_.FastForwardBy(kPendingTaskDuration);
EXPECT_EQ(1, gamepad_->set_vibration_count_);
EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(1, first_callback_count_);
EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
first_callback_result_);
EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 0u);
}
TEST_F(AbstractHapticGamepadTest, ResetVibrationTest) {
EXPECT_EQ(0, gamepad_->set_vibration_count_);
EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(0, first_callback_count_);
PostResetVibration(base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
base::Unretained(this)));
task_environment_.RunUntilIdle();
EXPECT_EQ(0, gamepad_->set_vibration_count_);
EXPECT_EQ(1, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(1, first_callback_count_);
EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
first_callback_result_);
EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 0u);
}
TEST_F(AbstractHapticGamepadTest, UnsupportedEffectTypeTest) {
EXPECT_EQ(0, gamepad_->set_vibration_count_);
EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(0, first_callback_count_);
mojom::GamepadHapticEffectType unsupported_effect_type =
static_cast<mojom::GamepadHapticEffectType>(123);
PostPlayEffect(unsupported_effect_type, kDurationMillis,
kZeroStartDelayMillis,
base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
base::Unretained(this)));
task_environment_.RunUntilIdle();
EXPECT_EQ(0, gamepad_->set_vibration_count_);
EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(1, first_callback_count_);
EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultNotSupported,
first_callback_result_);
EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 0u);
}
TEST_F(AbstractHapticGamepadTest, StartDelayTest) {
EXPECT_EQ(0, gamepad_->set_vibration_count_);
EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(0, first_callback_count_);
PostPlayEffect(
mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble,
kDurationMillis, kNonZeroStartDelayMillis,
base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
base::Unretained(this)));
task_environment_.RunUntilIdle();
EXPECT_EQ(0, gamepad_->set_vibration_count_);
EXPECT_EQ(1, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(0, first_callback_count_);
EXPECT_TRUE(task_environment_.NextTaskIsDelayed());
task_environment_.FastForwardBy(kPendingTaskDuration);
EXPECT_EQ(1, gamepad_->set_vibration_count_);
EXPECT_EQ(1, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(0, first_callback_count_);
EXPECT_TRUE(task_environment_.NextTaskIsDelayed());
task_environment_.FastForwardBy(kPendingTaskDuration);
EXPECT_EQ(1, gamepad_->set_vibration_count_);
EXPECT_EQ(1, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(1, first_callback_count_);
EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
first_callback_result_);
EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 0u);
}
TEST_F(AbstractHapticGamepadTest, ZeroStartDelayPreemptionTest) {
EXPECT_EQ(0, gamepad_->set_vibration_count_);
EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(0, first_callback_count_);
EXPECT_EQ(0, second_callback_count_);
PostPlayEffect(
mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble,
kDurationMillis, kZeroStartDelayMillis,
base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
base::Unretained(this)));
PostPlayEffect(
mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble,
kDurationMillis, kZeroStartDelayMillis,
base::BindOnce(&AbstractHapticGamepadTest::SecondCallback,
base::Unretained(this)));
task_environment_.RunUntilIdle();
EXPECT_EQ(1, gamepad_->set_vibration_count_);
EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(1, first_callback_count_);
EXPECT_EQ(0, second_callback_count_);
EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultPreempted,
first_callback_result_);
EXPECT_TRUE(task_environment_.NextTaskIsDelayed());
task_environment_.FastForwardBy(kPendingTaskDuration);
EXPECT_EQ(1, gamepad_->set_vibration_count_);
EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(1, first_callback_count_);
EXPECT_EQ(1, second_callback_count_);
EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
second_callback_result_);
EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 0u);
}
TEST_F(AbstractHapticGamepadTest, NonZeroStartDelayPreemptionTest) {
EXPECT_EQ(0, gamepad_->set_vibration_count_);
EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(0, first_callback_count_);
EXPECT_EQ(0, second_callback_count_);
PostPlayEffect(
mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble,
kDurationMillis, kZeroStartDelayMillis,
base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
base::Unretained(this)));
PostPlayEffect(
mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble,
kDurationMillis, kNonZeroStartDelayMillis,
base::BindOnce(&AbstractHapticGamepadTest::SecondCallback,
base::Unretained(this)));
task_environment_.RunUntilIdle();
EXPECT_EQ(0, gamepad_->set_vibration_count_);
EXPECT_EQ(1, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(1, first_callback_count_);
EXPECT_EQ(0, second_callback_count_);
EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultPreempted,
first_callback_result_);
EXPECT_TRUE(task_environment_.NextTaskIsDelayed());
task_environment_.FastForwardBy(kPendingTaskDuration);
EXPECT_EQ(1, gamepad_->set_vibration_count_);
EXPECT_EQ(1, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(1, first_callback_count_);
EXPECT_EQ(0, second_callback_count_);
EXPECT_TRUE(task_environment_.NextTaskIsDelayed());
task_environment_.FastForwardBy(kPendingTaskDuration);
EXPECT_EQ(1, gamepad_->set_vibration_count_);
EXPECT_EQ(1, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(1, first_callback_count_);
EXPECT_EQ(1, second_callback_count_);
EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultPreempted,
first_callback_result_);
EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
second_callback_result_);
EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 0u);
}
TEST_F(AbstractHapticGamepadTest, ResetVibrationPreemptionTest) {
EXPECT_EQ(0, gamepad_->set_vibration_count_);
EXPECT_EQ(0, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(0, first_callback_count_);
EXPECT_EQ(0, second_callback_count_);
PostPlayEffect(
mojom::GamepadHapticEffectType::GamepadHapticEffectTypeDualRumble,
kDurationMillis, kZeroStartDelayMillis,
base::BindOnce(&AbstractHapticGamepadTest::FirstCallback,
base::Unretained(this)));
PostResetVibration(base::BindOnce(&AbstractHapticGamepadTest::SecondCallback,
base::Unretained(this)));
task_environment_.RunUntilIdle();
EXPECT_EQ(0, gamepad_->set_vibration_count_);
EXPECT_EQ(1, gamepad_->set_zero_vibration_count_);
EXPECT_EQ(1, first_callback_count_);
EXPECT_EQ(1, second_callback_count_);
EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultPreempted,
first_callback_result_);
EXPECT_EQ(mojom::GamepadHapticsResult::GamepadHapticsResultComplete,
second_callback_result_);
EXPECT_EQ(task_environment_.GetPendingMainThreadTaskCount(), 0u);
}
}
}