#include "ui/events/ozone/evdev/numberpad_metrics.h"
#include <linux/input.h>
#include <iostream>
#include <memory>
#include <string>
#include <tuple>
#include <vector>
#include "base/functional/bind.h"
#include "base/run_loop.h"
#include "base/test/metrics/histogram_tester.h"
#include "base/test/task_environment.h"
#include "base/time/time.h"
#include "chromeos/ash/components/feature_usage/feature_usage_metrics.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/events/ozone/device/device_manager.h"
#include "ui/events/ozone/evdev/event_converter_evdev_impl.h"
#include "ui/events/ozone/evdev/event_converter_test_util.h"
#include "ui/events/ozone/evdev/event_device_info.h"
#include "ui/events/ozone/evdev/event_device_test_util.h"
#include "ui/events/ozone/evdev/event_factory_evdev.h"
#include "ui/events/ozone/evdev/numberpad_metrics.h"
#include "ui/events/ozone/evdev/testing/fake_cursor_delegate_evdev.h"
#include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
namespace ui {
namespace {
using FeatureUsageEvent = ::ash::feature_usage::FeatureUsageMetrics::Event;
constexpr char kFeatureUsageMetricPrefix[] = "ChromeOS.FeatureUsage.";
#define OUTERMOST_SCOPED_TRACE(code) \
do { \
if (scope_level_++ == 0) { \
SCOPED_TRACE("Caller of failed expectation"); \
code; \
} else { \
code; \
} \
scope_level_--; \
} while (0)
}
class NumberpadMetricsTest : public ::testing::Test {
struct DynamicMetricsExpectations {
int enter_keys = 0;
int non_enter_keys = 0;
int activations = 0;
int cancellations = 0;
bool eligible = false;
bool enabled = false;
};
struct InternalMetricsExpectations {
int enter_keys = 0;
int non_enter_keys = 0;
bool eligible = false;
bool enabled = false;
};
struct ExternalMetricsExpectations {
int enter_keys = 0;
int non_enter_keys = 0;
bool eligible = false;
bool enabled = false;
};
public:
NumberpadMetricsTest() = default;
NumberpadMetricsTest(const NumberpadMetricsTest&) = delete;
NumberpadMetricsTest& operator=(const NumberpadMetricsTest&) = delete;
~NumberpadMetricsTest() override = default;
ui::InputDevice InputDeviceFromCapabilities(
const ui::DeviceCapabilities& capabilities) {
ui::EventDeviceInfo device_info = {};
ui::CapabilitiesToDeviceInfo(capabilities, &device_info);
device_id_++;
return ui::InputDevice(device_id_, device_info.device_type(),
device_info.name(), device_info.phys(),
base::FilePath(capabilities.path),
device_info.vendor_id(), device_info.product_id(),
device_info.version());
}
#define EXPECT_METRIC(...) OUTERMOST_SCOPED_TRACE((ExpectMetric(__VA_ARGS__)))
void ExpectMetric(const std::string& core_metric_name,
int success_count,
int failure_count,
bool eligible,
bool enabled) {
std::string metric_name =
std::string(kFeatureUsageMetricPrefix) + core_metric_name;
EXPECT_EQ(
histogram_tester_.GetBucketCount(
metric_name, static_cast<int>(FeatureUsageEvent::kUsedWithSuccess)),
success_count)
<< "Expected BucketCount == " << success_count << " for " << metric_name
<< ".kUsedWithSuccess";
EXPECT_EQ(
histogram_tester_.GetBucketCount(
metric_name, static_cast<int>(FeatureUsageEvent::kUsedWithFailure)),
failure_count)
<< "Expected BucketCount == " << success_count << " for " << metric_name
<< ".kUsedWithFailure";
if (eligible) {
EXPECT_GE(
histogram_tester_.GetBucketCount(
metric_name, static_cast<int>(FeatureUsageEvent::kEligible)),
1)
<< "Expected BucketCount >= 1 for " << metric_name << ".kEligible";
} else {
EXPECT_EQ(
histogram_tester_.GetBucketCount(
metric_name, static_cast<int>(FeatureUsageEvent::kEligible)),
0)
<< "Expected BucketCount == 0 for " << metric_name << ".kEligible";
}
if (enabled) {
EXPECT_GE(histogram_tester_.GetBucketCount(
metric_name, static_cast<int>(FeatureUsageEvent::kEnabled)),
1)
<< "Expected BucketCount >= 1 for " << metric_name << ".kEnabled";
} else {
EXPECT_EQ(histogram_tester_.GetBucketCount(
metric_name, static_cast<int>(FeatureUsageEvent::kEnabled)),
0)
<< "Expected BucketCount == 0 for " << metric_name << ".kEnabled";
}
}
#define EXPECT_DYNAMIC_PRESENT(...) \
OUTERMOST_SCOPED_TRACE((ExpectDynamicPresent(__VA_ARGS__)))
void ExpectDynamicPresent(bool desired_state) {
EXPECT_EQ(
numberpad_metrics_.dynamic_activations_metrics_delegate_.IsEnabled(),
desired_state);
EXPECT_EQ(
numberpad_metrics_.dynamic_activations_metrics_delegate_.IsEligible(),
desired_state);
EXPECT_EQ(
numberpad_metrics_.dynamic_cancellations_metrics_delegate_.IsEligible(),
desired_state);
EXPECT_EQ(
numberpad_metrics_.dynamic_cancellations_metrics_delegate_.IsEnabled(),
desired_state);
EXPECT_EQ(numberpad_metrics_.dynamic_enter_keystrokes_metrics_delegate_
.IsEligible(),
desired_state);
EXPECT_EQ(numberpad_metrics_.dynamic_enter_keystrokes_metrics_delegate_
.IsEnabled(),
desired_state);
EXPECT_EQ(numberpad_metrics_.dynamic_non_enter_keystrokes_metrics_delegate_
.IsEligible(),
desired_state);
EXPECT_EQ(numberpad_metrics_.dynamic_non_enter_keystrokes_metrics_delegate_
.IsEnabled(),
desired_state);
}
#define EXPECT_INTERNAL_PRESENT(...) \
OUTERMOST_SCOPED_TRACE((ExpectInternalPresent(__VA_ARGS__)))
void ExpectInternalPresent(bool desired_state) {
EXPECT_EQ(numberpad_metrics_.internal_enter_keystrokes_metrics_delegate_
.IsEligible(),
desired_state);
EXPECT_EQ(numberpad_metrics_.internal_enter_keystrokes_metrics_delegate_
.IsEnabled(),
desired_state);
EXPECT_EQ(numberpad_metrics_.internal_non_enter_keystrokes_metrics_delegate_
.IsEligible(),
desired_state);
EXPECT_EQ(numberpad_metrics_.internal_non_enter_keystrokes_metrics_delegate_
.IsEnabled(),
desired_state);
}
#define EXPECT_EXTERNAL_PRESENT(...) \
OUTERMOST_SCOPED_TRACE((ExpectExternalPresent(__VA_ARGS__)))
void ExpectExternalPresent(bool desired_state) {
EXPECT_EQ(numberpad_metrics_.external_enter_keystrokes_metrics_delegate_
.IsEligible(),
true);
EXPECT_EQ(numberpad_metrics_.external_enter_keystrokes_metrics_delegate_
.IsEnabled(),
desired_state);
EXPECT_EQ(numberpad_metrics_.external_non_enter_keystrokes_metrics_delegate_
.IsEligible(),
true);
EXPECT_EQ(numberpad_metrics_.external_non_enter_keystrokes_metrics_delegate_
.IsEnabled(),
desired_state);
}
#define EXPECT_EXTERNAL_METRICS(...) \
OUTERMOST_SCOPED_TRACE((ExpectExternalMetrics(__VA_ARGS__)))
void ExpectExternalMetrics(ExternalMetricsExpectations expect) {
EXPECT_METRIC(NumberpadMetricsRecorder::kFeatureExternalEnterKeystrokes,
expect.enter_keys, 0, expect.eligible, expect.enabled);
EXPECT_METRIC(NumberpadMetricsRecorder::kFeatureExternalNonEnterKeystrokes,
expect.non_enter_keys, 0, expect.eligible, expect.enabled);
}
#define EXPECT_INTERNAL_METRICS(...) \
OUTERMOST_SCOPED_TRACE((ExpectInternalMetrics(__VA_ARGS__)))
void ExpectInternalMetrics(InternalMetricsExpectations expect) {
EXPECT_METRIC(NumberpadMetricsRecorder::kFeatureInternalEnterKeystrokes,
expect.enter_keys, 0, expect.eligible, expect.enabled);
EXPECT_METRIC(NumberpadMetricsRecorder::kFeatureInternalNonEnterKeystrokes,
expect.non_enter_keys, 0, expect.eligible, expect.enabled);
}
#define EXPECT_DYNAMIC_METRICS(...) \
OUTERMOST_SCOPED_TRACE((ExpectDynamicMetrics(__VA_ARGS__)))
void ExpectDynamicMetrics(DynamicMetricsExpectations expect) {
EXPECT_METRIC(NumberpadMetricsRecorder::kFeatureDynamicEnterKeystrokes,
expect.enter_keys, 0, expect.eligible, expect.enabled);
EXPECT_METRIC(NumberpadMetricsRecorder::kFeatureDynamicNonEnterKeystrokes,
expect.non_enter_keys, 0, expect.eligible, expect.enabled);
EXPECT_METRIC(NumberpadMetricsRecorder::kFeatureDynamicActivations,
expect.activations, 0, expect.eligible, expect.enabled);
EXPECT_METRIC(NumberpadMetricsRecorder::kFeatureDynamicCancellations,
expect.cancellations, 0, expect.eligible, expect.enabled);
}
void ProcessKey(const ui::InputDevice& input_device,
unsigned int key,
bool down) {
numberpad_metrics_.ProcessKey(key, down, input_device);
}
void ProcessKey(const ui::InputDevice& input_device, unsigned int key) {
numberpad_metrics_.ProcessKey(key, true, input_device);
numberpad_metrics_.ProcessKey(key, false, input_device);
}
void ProcessKeys(const ui::InputDevice& input_device,
const std::vector<unsigned int>& keys) {
for (auto key : keys)
ProcessKey(input_device, key);
}
void DelayForPeriodicMetrics() {
task_environment_.AdvanceClock(
ash::feature_usage::FeatureUsageMetrics::kRepeatedInterval +
base::Seconds(30));
base::RunLoop().RunUntilIdle();
}
protected:
int scope_level_ = 0;
int device_id_ = 0;
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME,
base::test::TaskEnvironment::MainThreadType::UI};
base::RunLoop run_loop_;
base::HistogramTester histogram_tester_;
ui::NumberpadMetricsRecorder numberpad_metrics_;
};
class NumberpadMetricsTestParam
: public NumberpadMetricsTest,
public testing::WithParamInterface<std::tuple<int, int, bool, int, int>> {
public:
};
TEST_F(NumberpadMetricsTest, ObservationBaselineNoDevices) {
EXPECT_DYNAMIC_PRESENT(false);
EXPECT_INTERNAL_PRESENT(false);
EXPECT_EXTERNAL_PRESENT(false);
}
TEST_F(NumberpadMetricsTest, ObservationOnlyExternalWideKeyboard) {
ui::InputDevice external_wide_keyboard =
InputDeviceFromCapabilities(ui::kLogitechKeyboardK120);
numberpad_metrics_.AddDevice(external_wide_keyboard);
EXPECT_DYNAMIC_PRESENT(false);
EXPECT_INTERNAL_PRESENT(false);
EXPECT_EXTERNAL_PRESENT(true);
}
TEST_F(NumberpadMetricsTest, ObservationOnlyInternalWideKeyboard) {
ui::InputDevice internal_wide_keyboard =
InputDeviceFromCapabilities(ui::kWoomaxKeyboard);
numberpad_metrics_.AddDevice(internal_wide_keyboard);
EXPECT_DYNAMIC_PRESENT(false);
EXPECT_INTERNAL_PRESENT(true);
EXPECT_EXTERNAL_PRESENT(false);
}
TEST_F(NumberpadMetricsTest, ObservationOnlyInternalDynamicNumberpad) {
ui::InputDevice dynamic_numberpad =
InputDeviceFromCapabilities(ui::kDrobitNumberpad);
numberpad_metrics_.AddDevice(dynamic_numberpad);
EXPECT_DYNAMIC_PRESENT(true);
EXPECT_INTERNAL_PRESENT(false);
EXPECT_EXTERNAL_PRESENT(false);
}
TEST_F(NumberpadMetricsTest, ObservationEverythingAtOnce) {
ui::InputDevice internal_wide_keyboard =
InputDeviceFromCapabilities(ui::kWoomaxKeyboard);
numberpad_metrics_.AddDevice(internal_wide_keyboard);
ui::InputDevice external_wide_keyboard =
InputDeviceFromCapabilities(ui::kLogitechKeyboardK120);
numberpad_metrics_.AddDevice(external_wide_keyboard);
ui::InputDevice dynamic_numberpad =
InputDeviceFromCapabilities(ui::kDrobitNumberpad);
numberpad_metrics_.AddDevice(dynamic_numberpad);
EXPECT_DYNAMIC_PRESENT(true);
EXPECT_INTERNAL_PRESENT(true);
EXPECT_EXTERNAL_PRESENT(true);
}
TEST_F(NumberpadMetricsTest, ObservationDynamicExternalKeyboards) {
const ui::InputDevice external_wide_keyboard =
InputDeviceFromCapabilities(ui::kLogitechKeyboardK120);
ui::InputDevice dynamic_numberpad =
InputDeviceFromCapabilities(ui::kDrobitNumberpad);
numberpad_metrics_.AddDevice(dynamic_numberpad);
EXPECT_DYNAMIC_PRESENT(true);
EXPECT_INTERNAL_PRESENT(false);
EXPECT_EXTERNAL_PRESENT(false);
numberpad_metrics_.AddDevice(external_wide_keyboard);
EXPECT_DYNAMIC_PRESENT(true);
EXPECT_INTERNAL_PRESENT(false);
EXPECT_EXTERNAL_PRESENT(true);
numberpad_metrics_.RemoveDevice(external_wide_keyboard);
EXPECT_DYNAMIC_PRESENT(true);
EXPECT_INTERNAL_PRESENT(false);
EXPECT_EXTERNAL_PRESENT(false);
}
TEST_F(NumberpadMetricsTest, ObservationDynamicMultipleExternalKeyboards) {
const ui::InputDevice external_wide_keyboard_1 =
InputDeviceFromCapabilities(ui::kLogitechKeyboardK120);
const ui::InputDevice external_wide_keyboard_2 =
InputDeviceFromCapabilities(ui::kLogitechKeyboardK120);
const ui::InputDevice external_wide_keyboard_3 =
InputDeviceFromCapabilities(ui::kHpUsbKeyboard);
EXPECT_DYNAMIC_PRESENT(false);
EXPECT_INTERNAL_PRESENT(false);
EXPECT_EXTERNAL_PRESENT(false);
numberpad_metrics_.AddDevice(external_wide_keyboard_1);
EXPECT_EXTERNAL_PRESENT(true);
numberpad_metrics_.AddDevice(external_wide_keyboard_2);
EXPECT_EXTERNAL_PRESENT(true);
numberpad_metrics_.AddDevice(external_wide_keyboard_3);
EXPECT_EXTERNAL_PRESENT(true);
numberpad_metrics_.RemoveDevice(external_wide_keyboard_1);
EXPECT_EXTERNAL_PRESENT(true);
numberpad_metrics_.RemoveDevice(external_wide_keyboard_2);
EXPECT_EXTERNAL_PRESENT(true);
numberpad_metrics_.RemoveDevice(external_wide_keyboard_3);
EXPECT_EXTERNAL_PRESENT(false);
}
TEST_F(NumberpadMetricsTest, ObservationBluetoothNumericPad) {
numberpad_metrics_.AddDevice(
InputDeviceFromCapabilities(ui::kDrobitNumberpad));
numberpad_metrics_.AddDevice(
InputDeviceFromCapabilities(ui::kWoomaxKeyboard));
numberpad_metrics_.AddDevice(
InputDeviceFromCapabilities(ui::kMicrosoftBluetoothNumberPad));
EXPECT_DYNAMIC_PRESENT(true);
EXPECT_INTERNAL_PRESENT(true);
EXPECT_EXTERNAL_PRESENT(true);
}
TEST_F(NumberpadMetricsTest, ObservationPluggingInBluetoothNumericPad) {
numberpad_metrics_.AddDevice(
InputDeviceFromCapabilities(ui::kDrobitNumberpad));
numberpad_metrics_.AddDevice(
InputDeviceFromCapabilities(ui::kWoomaxKeyboard));
EXPECT_DYNAMIC_PRESENT(true);
EXPECT_INTERNAL_PRESENT(true);
EXPECT_EXTERNAL_PRESENT(false);
numberpad_metrics_.AddDevice(
InputDeviceFromCapabilities(ui::kMicrosoftBluetoothNumberPad));
EXPECT_EXTERNAL_PRESENT(true);
}
TEST_F(NumberpadMetricsTest, MetricsBaseline) {
EXPECT_DYNAMIC_PRESENT(false);
EXPECT_INTERNAL_PRESENT(false);
EXPECT_EXTERNAL_PRESENT(false);
DelayForPeriodicMetrics();
EXPECT_DYNAMIC_METRICS({.enter_keys = 0,
.non_enter_keys = 0,
.activations = 0,
.cancellations = 0,
.eligible = false,
.enabled = false});
EXPECT_INTERNAL_METRICS({.enter_keys = 0,
.non_enter_keys = 0,
.eligible = false,
.enabled = false});
EXPECT_EXTERNAL_METRICS({.enter_keys = 0,
.non_enter_keys = 0,
.eligible = true,
.enabled = false});
}
TEST_F(NumberpadMetricsTest, MetricsWideExternalKeyboardBasics) {
ui::InputDevice external_wide_keyboard =
InputDeviceFromCapabilities(ui::kLogitechKeyboardK120);
numberpad_metrics_.AddDevice(external_wide_keyboard);
EXPECT_DYNAMIC_PRESENT(false);
EXPECT_INTERNAL_PRESENT(false);
EXPECT_EXTERNAL_PRESENT(true);
int total_enter = 0;
int total_non_enter = 0;
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = total_enter,
.non_enter_keys = total_non_enter,
.eligible = true,
.enabled = true});
EXPECT_INTERNAL_METRICS({.eligible = false, .enabled = false});
EXPECT_DYNAMIC_METRICS({.eligible = false, .enabled = false});
ProcessKeys(external_wide_keyboard, {KEY_KP0});
total_non_enter++;
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = total_enter,
.non_enter_keys = total_non_enter,
.eligible = true,
.enabled = true});
ProcessKeys(external_wide_keyboard, {KEY_KPENTER});
total_enter++;
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = total_enter,
.non_enter_keys = total_non_enter,
.eligible = true,
.enabled = true});
ProcessKeys(external_wide_keyboard, {KEY_KP1, KEY_KP2, KEY_KP2});
total_non_enter += 3;
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = total_enter,
.non_enter_keys = total_non_enter,
.eligible = true,
.enabled = true});
}
TEST_F(NumberpadMetricsTest, MetricsWideExternalKeyboardNonKeypad) {
ui::InputDevice external_wide_keyboard =
InputDeviceFromCapabilities(ui::kLogitechKeyboardK120);
numberpad_metrics_.AddDevice(external_wide_keyboard);
EXPECT_DYNAMIC_PRESENT(false);
EXPECT_INTERNAL_PRESENT(false);
EXPECT_EXTERNAL_PRESENT(true);
int total_enter = 0;
int total_non_enter = 0;
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = total_enter,
.non_enter_keys = total_non_enter,
.eligible = true,
.enabled = true});
EXPECT_INTERNAL_METRICS({.eligible = false, .enabled = false});
EXPECT_DYNAMIC_METRICS({.eligible = false, .enabled = false});
ProcessKeys(external_wide_keyboard, {KEY_KP0});
total_non_enter++;
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = total_enter,
.non_enter_keys = total_non_enter,
.eligible = true,
.enabled = true});
ProcessKeys(external_wide_keyboard, {KEY_Q, KEY_A});
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = total_enter,
.non_enter_keys = total_non_enter,
.eligible = true,
.enabled = true});
ProcessKeys(external_wide_keyboard, {KEY_KP1, KEY_KP2, KEY_KP2});
total_non_enter += 3;
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = total_enter,
.non_enter_keys = total_non_enter,
.eligible = true,
.enabled = true});
ProcessKeys(external_wide_keyboard, {KEY_0, KEY_1, KEY_2});
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = total_enter,
.non_enter_keys = total_non_enter,
.eligible = true,
.enabled = true});
ProcessKeys(external_wide_keyboard, {KEY_KPENTER});
total_enter++;
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = total_enter,
.non_enter_keys = total_non_enter,
.eligible = true,
.enabled = true});
ProcessKeys(external_wide_keyboard, {KEY_ENTER});
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = total_enter,
.non_enter_keys = total_non_enter,
.eligible = true,
.enabled = true});
}
TEST_F(NumberpadMetricsTest, MetricsWideExternalKeyboardVsOtherKeyboards) {
ui::InputDevice external_wide_keyboard =
InputDeviceFromCapabilities(ui::kLogitechKeyboardK120);
ui::InputDevice internal_wide_keyboard =
InputDeviceFromCapabilities(ui::kWoomaxKeyboard);
ui::InputDevice dynamic_numberpad =
InputDeviceFromCapabilities(ui::kDrobitNumberpad);
numberpad_metrics_.AddDevice(internal_wide_keyboard);
numberpad_metrics_.AddDevice(external_wide_keyboard);
numberpad_metrics_.AddDevice(dynamic_numberpad);
EXPECT_DYNAMIC_PRESENT(true);
EXPECT_INTERNAL_PRESENT(true);
EXPECT_EXTERNAL_PRESENT(true);
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = 0,
.non_enter_keys = 0,
.eligible = true,
.enabled = true});
EXPECT_INTERNAL_METRICS({.eligible = true, .enabled = true});
EXPECT_DYNAMIC_METRICS({.eligible = true, .enabled = true});
ProcessKeys(internal_wide_keyboard,
{KEY_A, KEY_0, KEY_KP0, KEY_ENTER, KEY_KPENTER});
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = 0,
.non_enter_keys = 0,
.eligible = true,
.enabled = true});
ProcessKeys(dynamic_numberpad, {KEY_KP0, KEY_KPENTER, KEY_5});
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = 0,
.non_enter_keys = 0,
.eligible = true,
.enabled = true});
}
TEST_F(NumberpadMetricsTest, MetricsInternalKeyboardVsOtherKeyboards) {
ui::InputDevice external_wide_keyboard =
InputDeviceFromCapabilities(ui::kLogitechKeyboardK120);
ui::InputDevice internal_wide_keyboard =
InputDeviceFromCapabilities(ui::kWoomaxKeyboard);
ui::InputDevice dynamic_numberpad =
InputDeviceFromCapabilities(ui::kDrobitNumberpad);
numberpad_metrics_.AddDevice(internal_wide_keyboard);
numberpad_metrics_.AddDevice(external_wide_keyboard);
numberpad_metrics_.AddDevice(dynamic_numberpad);
EXPECT_DYNAMIC_PRESENT(true);
EXPECT_INTERNAL_PRESENT(true);
EXPECT_EXTERNAL_PRESENT(true);
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = 0,
.non_enter_keys = 0,
.eligible = true,
.enabled = true});
EXPECT_INTERNAL_METRICS({.eligible = true, .enabled = true});
EXPECT_DYNAMIC_METRICS({.eligible = true, .enabled = true});
ProcessKeys(external_wide_keyboard,
{KEY_A, KEY_0, KEY_KP0, KEY_NUMLOCK, KEY_ENTER, KEY_KPENTER});
DelayForPeriodicMetrics();
EXPECT_INTERNAL_METRICS({.enter_keys = 0,
.non_enter_keys = 0,
.eligible = true,
.enabled = true});
ProcessKeys(dynamic_numberpad, {KEY_KP0, KEY_KPENTER, KEY_5});
DelayForPeriodicMetrics();
EXPECT_INTERNAL_METRICS({.enter_keys = 0,
.non_enter_keys = 0,
.eligible = true,
.enabled = true});
}
TEST_F(NumberpadMetricsTest, MetricsDynamicNumerpadVsOtherKeyboards) {
ui::InputDevice external_wide_keyboard =
InputDeviceFromCapabilities(ui::kLogitechKeyboardK120);
ui::InputDevice internal_wide_keyboard =
InputDeviceFromCapabilities(ui::kWoomaxKeyboard);
ui::InputDevice dynamic_numberpad =
InputDeviceFromCapabilities(ui::kDrobitNumberpad);
numberpad_metrics_.AddDevice(internal_wide_keyboard);
numberpad_metrics_.AddDevice(external_wide_keyboard);
numberpad_metrics_.AddDevice(dynamic_numberpad);
EXPECT_DYNAMIC_PRESENT(true);
EXPECT_INTERNAL_PRESENT(true);
EXPECT_EXTERNAL_PRESENT(true);
DelayForPeriodicMetrics();
EXPECT_EXTERNAL_METRICS({.enter_keys = 0,
.non_enter_keys = 0,
.eligible = true,
.enabled = true});
EXPECT_INTERNAL_METRICS({.eligible = true, .enabled = true});
EXPECT_DYNAMIC_METRICS({.eligible = true, .enabled = true});
ProcessKeys(external_wide_keyboard,
{KEY_A, KEY_0, KEY_KP0, KEY_NUMLOCK, KEY_ENTER, KEY_KPENTER});
DelayForPeriodicMetrics();
EXPECT_DYNAMIC_METRICS({.eligible = true, .enabled = true});
ProcessKeys(external_wide_keyboard, {KEY_NUMLOCK, KEY_NUMLOCK, KEY_KP0,
KEY_NUMLOCK, KEY_NUMLOCK, KEY_NUMLOCK});
DelayForPeriodicMetrics();
EXPECT_DYNAMIC_METRICS({.eligible = true, .enabled = true});
ProcessKeys(internal_wide_keyboard,
{KEY_A, KEY_0, KEY_KP0, KEY_ENTER, KEY_KPENTER, KEY_HOME});
DelayForPeriodicMetrics();
EXPECT_DYNAMIC_METRICS({.eligible = true, .enabled = true});
DelayForPeriodicMetrics();
EXPECT_DYNAMIC_METRICS({.eligible = true, .enabled = true});
}
TEST_F(NumberpadMetricsTest, MetricsWideInternalKeyboard) {
ui::InputDevice internal_wide_keyboard =
InputDeviceFromCapabilities(ui::kWoomaxKeyboard);
numberpad_metrics_.AddDevice(internal_wide_keyboard);
EXPECT_DYNAMIC_PRESENT(false);
EXPECT_INTERNAL_PRESENT(true);
EXPECT_EXTERNAL_PRESENT(false);
ProcessKeys(internal_wide_keyboard, {KEY_KP0});
DelayForPeriodicMetrics();
EXPECT_INTERNAL_METRICS({.enter_keys = 0,
.non_enter_keys = 1,
.eligible = true,
.enabled = true});
EXPECT_EXTERNAL_METRICS({.eligible = true, .enabled = false});
EXPECT_DYNAMIC_METRICS({.eligible = false, .enabled = false});
ProcessKeys(internal_wide_keyboard, {KEY_KP1, KEY_KP2, KEY_KP2});
DelayForPeriodicMetrics();
EXPECT_INTERNAL_METRICS({.enter_keys = 0,
.non_enter_keys = 4,
.eligible = true,
.enabled = true});
ProcessKeys(internal_wide_keyboard, {KEY_KPENTER});
DelayForPeriodicMetrics();
EXPECT_INTERNAL_METRICS({.enter_keys = 1,
.non_enter_keys = 4,
.eligible = true,
.enabled = true});
}
TEST_F(NumberpadMetricsTest, MetricsDynamicNumberpadBasics) {
ui::InputDevice dynamic_numberpad =
InputDeviceFromCapabilities(ui::kDrobitNumberpad);
numberpad_metrics_.AddDevice(dynamic_numberpad);
EXPECT_DYNAMIC_PRESENT(true);
EXPECT_INTERNAL_PRESENT(false);
EXPECT_EXTERNAL_PRESENT(false);
ProcessKeys(dynamic_numberpad, {KEY_NUMLOCK, KEY_KP0});
DelayForPeriodicMetrics();
EXPECT_DYNAMIC_METRICS({.enter_keys = 0,
.non_enter_keys = 1,
.activations = 1,
.cancellations = 0,
.eligible = true,
.enabled = true});
ProcessKeys(dynamic_numberpad, {KEY_NUMLOCK, KEY_NUMLOCK, KEY_NUMLOCK});
DelayForPeriodicMetrics();
EXPECT_DYNAMIC_METRICS({.enter_keys = 0,
.non_enter_keys = 1,
.activations = 2,
.cancellations = 1,
.eligible = true,
.enabled = true});
}
TEST_F(NumberpadMetricsTest, MetricsDynamicNumberpadAutoActivation) {
ui::InputDevice dynamic_numberpad =
InputDeviceFromCapabilities(ui::kDrobitNumberpad);
numberpad_metrics_.AddDevice(dynamic_numberpad);
ProcessKeys(dynamic_numberpad, {KEY_KP0});
DelayForPeriodicMetrics();
EXPECT_DYNAMIC_METRICS({.enter_keys = 0,
.non_enter_keys = 1,
.activations = 0,
.cancellations = 0,
.eligible = true,
.enabled = true});
ProcessKeys(dynamic_numberpad, {KEY_NUMLOCK, KEY_NUMLOCK, KEY_NUMLOCK});
DelayForPeriodicMetrics();
EXPECT_DYNAMIC_METRICS({.enter_keys = 0,
.non_enter_keys = 1,
.activations = 1,
.cancellations = 1,
.eligible = true,
.enabled = true});
ProcessKeys(dynamic_numberpad, {KEY_KP0});
DelayForPeriodicMetrics();
EXPECT_DYNAMIC_METRICS({.enter_keys = 0,
.non_enter_keys = 2,
.activations = 2,
.cancellations = 1,
.eligible = true,
.enabled = true});
}
TEST_F(NumberpadMetricsTest, MetricsDynamicNumberpadPressRelease) {
ui::InputDevice dynamic_numberpad =
InputDeviceFromCapabilities(ui::kDrobitNumberpad);
numberpad_metrics_.AddDevice(dynamic_numberpad);
ProcessKey(dynamic_numberpad, KEY_NUMLOCK, true);
ProcessKey(dynamic_numberpad, KEY_KP0, true);
DelayForPeriodicMetrics();
EXPECT_DYNAMIC_METRICS({.enter_keys = 0,
.non_enter_keys = 1,
.activations = 1,
.cancellations = 0,
.eligible = true,
.enabled = true});
ProcessKey(dynamic_numberpad, KEY_NUMLOCK, false);
ProcessKey(dynamic_numberpad, KEY_KP0, false);
DelayForPeriodicMetrics();
EXPECT_DYNAMIC_METRICS({.enter_keys = 0,
.non_enter_keys = 1,
.activations = 1,
.cancellations = 0,
.eligible = true,
.enabled = true});
}
TEST_P(NumberpadMetricsTestParam, CheckDeduction) {
ui::InputDevice dynamic_numberpad =
InputDeviceFromCapabilities(ui::kDrobitNumberpad);
numberpad_metrics_.AddDevice(dynamic_numberpad);
int numlock_count_prior = std::get<0>(GetParam());
int numlock_count_post = std::get<1>(GetParam());
bool enter_key = std::get<2>(GetParam());
int activations = std::get<3>(GetParam());
int cancellations = std::get<4>(GetParam());
for (int i = 0; i < numlock_count_prior; i++)
ProcessKey(dynamic_numberpad, KEY_NUMLOCK);
if (enter_key)
ProcessKey(dynamic_numberpad, KEY_KPENTER);
for (int i = 0; i < numlock_count_post; i++)
ProcessKey(dynamic_numberpad, KEY_NUMLOCK);
DelayForPeriodicMetrics();
EXPECT_DYNAMIC_METRICS({.enter_keys = enter_key ? 1 : 0,
.non_enter_keys = 0,
.activations = activations,
.cancellations = cancellations,
.eligible = true,
.enabled = true});
}
INSTANTIATE_TEST_SUITE_P(
NumberpadMetricsDynamicNumberpadStateDeduction,
NumberpadMetricsTestParam,
::testing::Values(
std::make_tuple(0, 0, false, 0, 0),
std::make_tuple(1, 0, false, 0, 0),
std::make_tuple(2, 0, false, 1, 0),
std::make_tuple(3, 0, false, 1, 1),
std::make_tuple(4, 0, false, 2, 1),
std::make_tuple(5, 0, false, 2, 2),
std::make_tuple(6, 0, false, 3, 2),
std::make_tuple(7, 0, false, 3, 3),
std::make_tuple(2 * 7, 0, false, 7, 7 - 1),
std::make_tuple(2 * 7 + 1, 0, false, 7, 7),
std::make_tuple(2 * 24, 0, false, 24, 24 - 1),
std::make_tuple(2 * 24 + 1, 0, false, 24, 24),
std::make_tuple(0, 0, true, 0, 0),
std::make_tuple(1, 0, true, 1, 0),
std::make_tuple(2, 0, true, 1, 0),
std::make_tuple(3, 0, true, 2, 1),
std::make_tuple(4, 0, true, 2, 1),
std::make_tuple(5, 0, true, 3, 2),
std::make_tuple(6, 0, true, 3, 2),
std::make_tuple(7, 0, true, 4, 3),
std::make_tuple(8, 0, true, 4, 3),
std::make_tuple(1, 1, true, 1, 0),
std::make_tuple(1, 2, true, 2, 0),
std::make_tuple(1, 3, true, 2, 1),
std::make_tuple(1, 4, true, 3, 1),
std::make_tuple(1, 5, true, 3, 2),
std::make_tuple(1, 6, true, 4, 2),
std::make_tuple(1, 7, true, 4, 3),
std::make_tuple(1, 8, true, 5, 3)));
}