Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e6512e16 authored by Harry Cutts's avatar Harry Cutts
Browse files

inputflinger_tests: Put `InputMapperTest` in its own file

I would like to be able to put automated tests for the new
`TouchpadEventMapper` in their own file, rather than
InputReader_tests.cpp. To do this I'll need some of the test utilities
in their own files, too.

Bug: 251196347
Test: atest inputflinger_tests
Change-Id: Ie524adb3431e4a0c59efe75be82abddacd676c21
parent 0cbe4654
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ cc_test {
        "FakeInputReaderPolicy.cpp",
        "FakePointerController.cpp",
        "FocusResolver_test.cpp",
        "InputMapperTest.cpp",
        "InputProcessor_test.cpp",
        "InputProcessorConverter_test.cpp",
        "InputDispatcher_test.cpp",
+176 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "InputMapperTest.h"

#include <InputReaderBase.h>
#include <gtest/gtest.h>
#include <ui/Rotation.h>

namespace android {

const char* InputMapperTest::DEVICE_NAME = "device";
const char* InputMapperTest::DEVICE_LOCATION = "USB1";
const ftl::Flags<InputDeviceClass> InputMapperTest::DEVICE_CLASSES =
        ftl::Flags<InputDeviceClass>(0); // not needed for current tests

void InputMapperTest::SetUp(ftl::Flags<InputDeviceClass> classes, int bus) {
    mFakeEventHub = std::make_unique<FakeEventHub>();
    mFakePolicy = sp<FakeInputReaderPolicy>::make();
    mFakeListener = std::make_unique<TestInputListener>();
    mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy, *mFakeListener);
    mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes, bus);
    // Consume the device reset notification generated when adding a new device.
    mFakeListener->assertNotifyDeviceResetWasCalled();
}

void InputMapperTest::SetUp() {
    SetUp(DEVICE_CLASSES);
}

void InputMapperTest::TearDown() {
    mFakeListener.reset();
    mFakePolicy.clear();
}

void InputMapperTest::addConfigurationProperty(const char* key, const char* value) {
    mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, key, value);
}

std::list<NotifyArgs> InputMapperTest::configureDevice(uint32_t changes) {
    if (!changes ||
        (changes &
         (InputReaderConfiguration::CHANGE_DISPLAY_INFO |
          InputReaderConfiguration::CHANGE_POINTER_CAPTURE))) {
        mReader->requestRefreshConfiguration(changes);
        mReader->loopOnce();
    }
    std::list<NotifyArgs> out =
            mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
    // Loop the reader to flush the input listener queue.
    for (const NotifyArgs& args : out) {
        mFakeListener->notify(args);
    }
    mReader->loopOnce();
    return out;
}

std::shared_ptr<InputDevice> InputMapperTest::newDevice(int32_t deviceId, const std::string& name,
                                                        const std::string& location,
                                                        int32_t eventHubId,
                                                        ftl::Flags<InputDeviceClass> classes,
                                                        int bus) {
    InputDeviceIdentifier identifier;
    identifier.name = name;
    identifier.location = location;
    identifier.bus = bus;
    std::shared_ptr<InputDevice> device =
            std::make_shared<InputDevice>(mReader->getContext(), deviceId, DEVICE_GENERATION,
                                          identifier);
    mReader->pushNextDevice(device);
    mFakeEventHub->addDevice(eventHubId, name, classes, bus);
    mReader->loopOnce();
    return device;
}

void InputMapperTest::setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
                                                   ui::Rotation orientation,
                                                   const std::string& uniqueId,
                                                   std::optional<uint8_t> physicalPort,
                                                   ViewportType viewportType) {
    mFakePolicy->addDisplayViewport(displayId, width, height, orientation, /* isActive= */ true,
                                    uniqueId, physicalPort, viewportType);
    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
}

void InputMapperTest::clearViewports() {
    mFakePolicy->clearViewports();
}

std::list<NotifyArgs> InputMapperTest::process(InputMapper& mapper, nsecs_t when, nsecs_t readTime,
                                               int32_t type, int32_t code, int32_t value) {
    RawEvent event;
    event.when = when;
    event.readTime = readTime;
    event.deviceId = mapper.getDeviceContext().getEventHubId();
    event.type = type;
    event.code = code;
    event.value = value;
    std::list<NotifyArgs> processArgList = mapper.process(&event);
    for (const NotifyArgs& args : processArgList) {
        mFakeListener->notify(args);
    }
    // Loop the reader to flush the input listener queue.
    mReader->loopOnce();
    return processArgList;
}

void InputMapperTest::resetMapper(InputMapper& mapper, nsecs_t when) {
    const auto resetArgs = mapper.reset(when);
    for (const auto args : resetArgs) {
        mFakeListener->notify(args);
    }
    // Loop the reader to flush the input listener queue.
    mReader->loopOnce();
}

std::list<NotifyArgs> InputMapperTest::handleTimeout(InputMapper& mapper, nsecs_t when) {
    std::list<NotifyArgs> generatedArgs = mapper.timeoutExpired(when);
    for (const NotifyArgs& args : generatedArgs) {
        mFakeListener->notify(args);
    }
    // Loop the reader to flush the input listener queue.
    mReader->loopOnce();
    return generatedArgs;
}

void InputMapperTest::assertMotionRange(const InputDeviceInfo& info, int32_t axis, uint32_t source,
                                        float min, float max, float flat, float fuzz) {
    const InputDeviceInfo::MotionRange* range = info.getMotionRange(axis, source);
    ASSERT_TRUE(range != nullptr) << "Axis: " << axis << " Source: " << source;
    ASSERT_EQ(axis, range->axis) << "Axis: " << axis << " Source: " << source;
    ASSERT_EQ(source, range->source) << "Axis: " << axis << " Source: " << source;
    ASSERT_NEAR(min, range->min, EPSILON) << "Axis: " << axis << " Source: " << source;
    ASSERT_NEAR(max, range->max, EPSILON) << "Axis: " << axis << " Source: " << source;
    ASSERT_NEAR(flat, range->flat, EPSILON) << "Axis: " << axis << " Source: " << source;
    ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Axis: " << axis << " Source: " << source;
}

void InputMapperTest::assertPointerCoords(const PointerCoords& coords, float x, float y,
                                          float pressure, float size, float touchMajor,
                                          float touchMinor, float toolMajor, float toolMinor,
                                          float orientation, float distance,
                                          float scaledAxisEpsilon) {
    ASSERT_NEAR(x, coords.getAxisValue(AMOTION_EVENT_AXIS_X), scaledAxisEpsilon);
    ASSERT_NEAR(y, coords.getAxisValue(AMOTION_EVENT_AXIS_Y), scaledAxisEpsilon);
    ASSERT_NEAR(pressure, coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), EPSILON);
    ASSERT_NEAR(size, coords.getAxisValue(AMOTION_EVENT_AXIS_SIZE), EPSILON);
    ASSERT_NEAR(touchMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), scaledAxisEpsilon);
    ASSERT_NEAR(touchMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), scaledAxisEpsilon);
    ASSERT_NEAR(toolMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), scaledAxisEpsilon);
    ASSERT_NEAR(toolMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), scaledAxisEpsilon);
    ASSERT_NEAR(orientation, coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), EPSILON);
    ASSERT_NEAR(distance, coords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), EPSILON);
}

void InputMapperTest::assertPosition(const FakePointerController& controller, float x, float y) {
    float actualX, actualY;
    controller.getPosition(&actualX, &actualY);
    ASSERT_NEAR(x, actualX, 1);
    ASSERT_NEAR(y, actualY, 1);
}

} // namespace android
+95 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <list>
#include <memory>

#include <InputDevice.h>
#include <InputMapper.h>
#include <NotifyArgs.h>
#include <ftl/flags.h>
#include <utils/StrongPointer.h>

#include "FakeEventHub.h"
#include "FakeInputReaderPolicy.h"
#include "InstrumentedInputReader.h"
#include "TestConstants.h"
#include "TestInputListener.h"

namespace android {

class InputMapperTest : public testing::Test {
protected:
    static const char* DEVICE_NAME;
    static const char* DEVICE_LOCATION;
    static constexpr int32_t DEVICE_ID = END_RESERVED_ID + 1000;
    static constexpr int32_t DEVICE_GENERATION = 2;
    static constexpr int32_t DEVICE_CONTROLLER_NUMBER = 0;
    static const ftl::Flags<InputDeviceClass> DEVICE_CLASSES;
    static constexpr int32_t EVENTHUB_ID = 1;

    std::shared_ptr<FakeEventHub> mFakeEventHub;
    sp<FakeInputReaderPolicy> mFakePolicy;
    std::unique_ptr<TestInputListener> mFakeListener;
    std::unique_ptr<InstrumentedInputReader> mReader;
    std::shared_ptr<InputDevice> mDevice;

    virtual void SetUp(ftl::Flags<InputDeviceClass> classes, int bus = 0);
    void SetUp() override;
    void TearDown() override;

    void addConfigurationProperty(const char* key, const char* value);
    std::list<NotifyArgs> configureDevice(uint32_t changes);
    std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
                                           const std::string& location, int32_t eventHubId,
                                           ftl::Flags<InputDeviceClass> classes, int bus = 0);
    template <class T, typename... Args>
    T& addMapperAndConfigure(Args... args) {
        T& mapper = mDevice->addMapper<T>(EVENTHUB_ID, args...);
        configureDevice(0);
        std::list<NotifyArgs> resetArgList = mDevice->reset(ARBITRARY_TIME);
        resetArgList += mapper.reset(ARBITRARY_TIME);
        // Loop the reader to flush the input listener queue.
        for (const NotifyArgs& loopArgs : resetArgList) {
            mFakeListener->notify(loopArgs);
        }
        mReader->loopOnce();
        return mapper;
    }

    void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
                                      ui::Rotation orientation, const std::string& uniqueId,
                                      std::optional<uint8_t> physicalPort,
                                      ViewportType viewportType);
    void clearViewports();
    std::list<NotifyArgs> process(InputMapper& mapper, nsecs_t when, nsecs_t readTime, int32_t type,
                                  int32_t code, int32_t value);
    void resetMapper(InputMapper& mapper, nsecs_t when);

    std::list<NotifyArgs> handleTimeout(InputMapper& mapper, nsecs_t when);

    static void assertMotionRange(const InputDeviceInfo& info, int32_t axis, uint32_t source,
                                  float min, float max, float flat, float fuzz);
    static void assertPointerCoords(const PointerCoords& coords, float x, float y, float pressure,
                                    float size, float touchMajor, float touchMinor, float toolMajor,
                                    float toolMinor, float orientation, float distance,
                                    float scaledAxisEpsilon = 1.f);
    static void assertPosition(const FakePointerController& controller, float x, float y);
};

} // namespace android
+1 −192
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include "FakeEventHub.h"
#include "FakeInputReaderPolicy.h"
#include "FakePointerController.h"
#include "InputMapperTest.h"
#include "InstrumentedInputReader.h"
#include "TestConstants.h"
#include "android/hardware/input/InputDeviceCountryCode.h"
@@ -92,9 +93,6 @@ static constexpr int32_t ACTION_POINTER_1_DOWN =
static constexpr int32_t ACTION_POINTER_1_UP =
        AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);

// Error tolerance for floating point assertions.
static const float EPSILON = 0.001f;

// Minimum timestamp separation between subsequent input events from a Bluetooth device.
static constexpr nsecs_t MIN_BLUETOOTH_TIMESTAMP_DELTA = ms2ns(4);
// Maximum smoothing time delta so that we don't generate events too far into the future.
@@ -2507,195 +2505,6 @@ TEST_F(InputDeviceTest, GetBluetoothAddress) {
    ASSERT_EQ(DEVICE_BLUETOOTH_ADDRESS, *address);
}

// --- InputMapperTest ---

class InputMapperTest : public testing::Test {
protected:
    static const char* DEVICE_NAME;
    static const char* DEVICE_LOCATION;
    static const int32_t DEVICE_ID;
    static const int32_t DEVICE_GENERATION;
    static const int32_t DEVICE_CONTROLLER_NUMBER;
    static const ftl::Flags<InputDeviceClass> DEVICE_CLASSES;
    static const int32_t EVENTHUB_ID;

    std::shared_ptr<FakeEventHub> mFakeEventHub;
    sp<FakeInputReaderPolicy> mFakePolicy;
    std::unique_ptr<TestInputListener> mFakeListener;
    std::unique_ptr<InstrumentedInputReader> mReader;
    std::shared_ptr<InputDevice> mDevice;

    virtual void SetUp(ftl::Flags<InputDeviceClass> classes, int bus = 0) {
        mFakeEventHub = std::make_unique<FakeEventHub>();
        mFakePolicy = sp<FakeInputReaderPolicy>::make();
        mFakeListener = std::make_unique<TestInputListener>();
        mReader = std::make_unique<InstrumentedInputReader>(mFakeEventHub, mFakePolicy,
                                                            *mFakeListener);
        mDevice = newDevice(DEVICE_ID, DEVICE_NAME, DEVICE_LOCATION, EVENTHUB_ID, classes, bus);
        // Consume the device reset notification generated when adding a new device.
        mFakeListener->assertNotifyDeviceResetWasCalled();
    }

    void SetUp() override {
        SetUp(DEVICE_CLASSES);
    }

    void TearDown() override {
        mFakeListener.reset();
        mFakePolicy.clear();
    }

    void addConfigurationProperty(const char* key, const char* value) {
        mFakeEventHub->addConfigurationProperty(EVENTHUB_ID, key, value);
    }

    std::list<NotifyArgs> configureDevice(uint32_t changes) {
        if (!changes ||
            (changes &
             (InputReaderConfiguration::CHANGE_DISPLAY_INFO |
              InputReaderConfiguration::CHANGE_POINTER_CAPTURE))) {
            mReader->requestRefreshConfiguration(changes);
            mReader->loopOnce();
        }
        std::list<NotifyArgs> out =
                mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(), changes);
        // Loop the reader to flush the input listener queue.
        for (const NotifyArgs& args : out) {
            mFakeListener->notify(args);
        }
        mReader->loopOnce();
        return out;
    }

    std::shared_ptr<InputDevice> newDevice(int32_t deviceId, const std::string& name,
                                           const std::string& location, int32_t eventHubId,
                                           ftl::Flags<InputDeviceClass> classes, int bus = 0) {
        InputDeviceIdentifier identifier;
        identifier.name = name;
        identifier.location = location;
        identifier.bus = bus;
        std::shared_ptr<InputDevice> device =
                std::make_shared<InputDevice>(mReader->getContext(), deviceId, DEVICE_GENERATION,
                                              identifier);
        mReader->pushNextDevice(device);
        mFakeEventHub->addDevice(eventHubId, name, classes, bus);
        mReader->loopOnce();
        return device;
    }

    template <class T, typename... Args>
    T& addMapperAndConfigure(Args... args) {
        T& mapper = mDevice->addMapper<T>(EVENTHUB_ID, args...);
        configureDevice(0);
        std::list<NotifyArgs> resetArgList = mDevice->reset(ARBITRARY_TIME);
        resetArgList += mapper.reset(ARBITRARY_TIME);
        // Loop the reader to flush the input listener queue.
        for (const NotifyArgs& loopArgs : resetArgList) {
            mFakeListener->notify(loopArgs);
        }
        mReader->loopOnce();
        return mapper;
    }

    void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
                                      ui::Rotation orientation, const std::string& uniqueId,
                                      std::optional<uint8_t> physicalPort,
                                      ViewportType viewportType) {
        mFakePolicy->addDisplayViewport(displayId, width, height, orientation, true /*isActive*/,
                                        uniqueId, physicalPort, viewportType);
        configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
    }

    void clearViewports() {
        mFakePolicy->clearViewports();
    }

    std::list<NotifyArgs> process(InputMapper& mapper, nsecs_t when, nsecs_t readTime, int32_t type,
                                  int32_t code, int32_t value) {
        RawEvent event;
        event.when = when;
        event.readTime = readTime;
        event.deviceId = mapper.getDeviceContext().getEventHubId();
        event.type = type;
        event.code = code;
        event.value = value;
        std::list<NotifyArgs> processArgList = mapper.process(&event);
        for (const NotifyArgs& args : processArgList) {
            mFakeListener->notify(args);
        }
        // Loop the reader to flush the input listener queue.
        mReader->loopOnce();
        return processArgList;
    }

    void resetMapper(InputMapper& mapper, nsecs_t when) {
        const auto resetArgs = mapper.reset(when);
        for (const auto& args : resetArgs) {
            mFakeListener->notify(args);
        }
        // Loop the reader to flush the input listener queue.
        mReader->loopOnce();
    }

    std::list<NotifyArgs> handleTimeout(InputMapper& mapper, nsecs_t when) {
        std::list<NotifyArgs> generatedArgs = mapper.timeoutExpired(when);
        for (const NotifyArgs& args : generatedArgs) {
            mFakeListener->notify(args);
        }
        // Loop the reader to flush the input listener queue.
        mReader->loopOnce();
        return generatedArgs;
    }

    static void assertMotionRange(const InputDeviceInfo& info,
            int32_t axis, uint32_t source, float min, float max, float flat, float fuzz) {
        const InputDeviceInfo::MotionRange* range = info.getMotionRange(axis, source);
        ASSERT_TRUE(range != nullptr) << "Axis: " << axis << " Source: " << source;
        ASSERT_EQ(axis, range->axis) << "Axis: " << axis << " Source: " << source;
        ASSERT_EQ(source, range->source) << "Axis: " << axis << " Source: " << source;
        ASSERT_NEAR(min, range->min, EPSILON) << "Axis: " << axis << " Source: " << source;
        ASSERT_NEAR(max, range->max, EPSILON) << "Axis: " << axis << " Source: " << source;
        ASSERT_NEAR(flat, range->flat, EPSILON) << "Axis: " << axis << " Source: " << source;
        ASSERT_NEAR(fuzz, range->fuzz, EPSILON) << "Axis: " << axis << " Source: " << source;
    }

    static void assertPointerCoords(const PointerCoords& coords, float x, float y, float pressure,
                                    float size, float touchMajor, float touchMinor, float toolMajor,
                                    float toolMinor, float orientation, float distance,
                                    float scaledAxisEpsilon = 1.f) {
        ASSERT_NEAR(x, coords.getAxisValue(AMOTION_EVENT_AXIS_X), scaledAxisEpsilon);
        ASSERT_NEAR(y, coords.getAxisValue(AMOTION_EVENT_AXIS_Y), scaledAxisEpsilon);
        ASSERT_NEAR(pressure, coords.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), EPSILON);
        ASSERT_NEAR(size, coords.getAxisValue(AMOTION_EVENT_AXIS_SIZE), EPSILON);
        ASSERT_NEAR(touchMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
                    scaledAxisEpsilon);
        ASSERT_NEAR(touchMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
                    scaledAxisEpsilon);
        ASSERT_NEAR(toolMajor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
                    scaledAxisEpsilon);
        ASSERT_NEAR(toolMinor, coords.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
                    scaledAxisEpsilon);
        ASSERT_NEAR(orientation, coords.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), EPSILON);
        ASSERT_NEAR(distance, coords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), EPSILON);
    }

    static void assertPosition(const FakePointerController& controller, float x, float y) {
        float actualX, actualY;
        controller.getPosition(&actualX, &actualY);
        ASSERT_NEAR(x, actualX, 1);
        ASSERT_NEAR(y, actualY, 1);
    }
};

const char* InputMapperTest::DEVICE_NAME = "device";
const char* InputMapperTest::DEVICE_LOCATION = "USB1";
const int32_t InputMapperTest::DEVICE_ID = END_RESERVED_ID + 1000;
const int32_t InputMapperTest::DEVICE_GENERATION = 2;
const int32_t InputMapperTest::DEVICE_CONTROLLER_NUMBER = 0;
const ftl::Flags<InputDeviceClass> InputMapperTest::DEVICE_CLASSES =
        ftl::Flags<InputDeviceClass>(0); // not needed for current tests
const int32_t InputMapperTest::EVENTHUB_ID = 1;

// --- SwitchInputMapperTest ---

class SwitchInputMapperTest : public InputMapperTest {
+3 −0
Original line number Diff line number Diff line
@@ -27,4 +27,7 @@ static constexpr std::chrono::duration WAIT_TIMEOUT = 100ms;
static constexpr nsecs_t ARBITRARY_TIME = 1234;
static constexpr nsecs_t READ_TIME = 4321;

// Error tolerance for floating point assertions.
static const float EPSILON = 0.001f;

} // namespace android