Initial InputMappers for evdev input HAL.

The previous design of the InputHost wrapper classes made it very
painful to do testing, so this change also reverts to a more classical
C++ pattern for non-copyable objects. The InputHost classes still simply
call through to the input_host_t and callbacks as before.

Updated unittests to use gmock for mocking the InputHost interactions.

Change-Id: I4b70df2c89ed48af77446b8f5b87a4bde94510bf
diff --git a/tests/input/evdev/Android.mk b/tests/input/evdev/Android.mk
index 544e5a8..a79de34 100644
--- a/tests/input/evdev/Android.mk
+++ b/tests/input/evdev/Android.mk
@@ -2,13 +2,17 @@
 include $(CLEAR_VARS)
 
 LOCAL_C_INCLUDES += hardware/libhardware/modules/input/evdev
+LOCAL_C_INCLUDES += $(TOP)/external/gmock/include
 
 LOCAL_SRC_FILES:= \
     InputDevice_test.cpp \
     InputHub_test.cpp \
     InputMocks.cpp \
+    SwitchInputMapper_test.cpp \
     TestHelpers.cpp
 
+LOCAL_STATIC_LIBRARIES := libgmock
+
 LOCAL_SHARED_LIBRARIES := \
     libinput_evdev \
     liblog \
diff --git a/tests/input/evdev/InputDevice_test.cpp b/tests/input/evdev/InputDevice_test.cpp
index 123f2b8..bed05b8 100644
--- a/tests/input/evdev/InputDevice_test.cpp
+++ b/tests/input/evdev/InputDevice_test.cpp
@@ -26,9 +26,9 @@
 #include <utils/Timers.h>
 
 #include "InputDevice.h"
-#include "InputHost.h"
 #include "InputHub.h"
 #include "InputMocks.h"
+#include "MockInputHost.h"
 
 // # of milliseconds to allow for timing measurements
 #define TIMING_TOLERANCE_MS 25
@@ -36,26 +36,41 @@
 #define MSC_ANDROID_TIME_SEC  0x6
 #define MSC_ANDROID_TIME_USEC 0x7
 
+using ::testing::_;
+using ::testing::NiceMock;
+using ::testing::Return;
+using ::testing::ReturnNull;
+
 namespace android {
 namespace tests {
 
 class EvdevDeviceTest : public ::testing::Test {
 protected:
-     virtual void SetUp() override {
-         mMockHost.reset(new MockInputHost());
-     }
+    virtual void SetUp() {
+        // Creating device identifiers and definitions should always happen.
+        EXPECT_CALL(mHost, createDeviceIdentifier(_, _, _, _, _))
+            .WillOnce(ReturnNull());
+        EXPECT_CALL(mHost, createDeviceDefinition())
+            .WillOnce(Return(&mDeviceDef));
+        // InputMappers may cause any of these to be called, but we are not
+        // testing these here.
+        ON_CALL(mHost, createInputReportDefinition())
+            .WillByDefault(Return(&mReportDef));
+        ON_CALL(mHost, createOutputReportDefinition())
+            .WillByDefault(Return(&mReportDef));
+        ON_CALL(mHost, registerDevice(_, _))
+            .WillByDefault(ReturnNull());
+    }
 
-     virtual void TearDown() override {
-        ASSERT_TRUE(mMockHost->checkAllocations());
-     }
-
-    std::unique_ptr<MockInputHost> mMockHost;
+    MockInputHost mHost;
+    // Ignore uninteresting calls on the report definitions by using NiceMocks.
+    NiceMock<MockInputReportDefinition> mReportDef;
+    NiceMock<MockInputDeviceDefinition> mDeviceDef;
 };
 
 TEST_F(EvdevDeviceTest, testOverrideTime) {
-    InputHost host = {mMockHost.get(), kTestCallbacks};
     auto node = std::make_shared<MockInputDeviceNode>();
-    auto device = std::make_unique<EvdevDevice>(host, node);
+    auto device = std::make_unique<EvdevDevice>(&mHost, node);
     ASSERT_TRUE(device != nullptr);
 
     // Send two timestamp override events before an input event.
@@ -83,9 +98,8 @@
 }
 
 TEST_F(EvdevDeviceTest, testWrongClockCorrection) {
-    InputHost host = {mMockHost.get(), kTestCallbacks};
     auto node = std::make_shared<MockInputDeviceNode>();
-    auto device = std::make_unique<EvdevDevice>(host, node);
+    auto device = std::make_unique<EvdevDevice>(&mHost, node);
     ASSERT_TRUE(device != nullptr);
 
     auto now = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -100,9 +114,8 @@
 }
 
 TEST_F(EvdevDeviceTest, testClockCorrectionOk) {
-    InputHost host = {mMockHost.get(), kTestCallbacks};
     auto node = std::make_shared<MockInputDeviceNode>();
-    auto device = std::make_unique<EvdevDevice>(host, node);
+    auto device = std::make_unique<EvdevDevice>(&mHost, node);
     ASSERT_TRUE(device != nullptr);
 
     auto now = systemTime(SYSTEM_TIME_MONOTONIC);
@@ -118,68 +131,70 @@
 }
 
 TEST_F(EvdevDeviceTest, testN7v2Touchscreen) {
-    InputHost host = {mMockHost.get(), kTestCallbacks};
     auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getElanTouchscreen());
-    auto device = std::make_unique<EvdevDevice>(host, node);
+    auto device = std::make_unique<EvdevDevice>(&mHost, node);
     EXPECT_EQ(INPUT_DEVICE_CLASS_TOUCH|INPUT_DEVICE_CLASS_TOUCH_MT,
             device->getInputClasses());
 }
 
 TEST_F(EvdevDeviceTest, testN7v2ButtonJack) {
-    InputHost host = {mMockHost.get(), kTestCallbacks};
     auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getButtonJack());
-    auto device = std::make_unique<EvdevDevice>(host, node);
+    auto device = std::make_unique<EvdevDevice>(&mHost, node);
     EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
 }
 
 TEST_F(EvdevDeviceTest, testN7v2HeadsetJack) {
-    InputHost host = {mMockHost.get(), kTestCallbacks};
+    // Eventually these mock device tests will all expect these calls. For now
+    // only the SwitchInputMapper has been implemented.
+    // TODO: move this expectation out to a common function
+    EXPECT_CALL(mHost, createInputReportDefinition());
+    EXPECT_CALL(mHost, registerDevice(_, _));
+
     auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getHeadsetJack());
-    auto device = std::make_unique<EvdevDevice>(host, node);
+    auto device = std::make_unique<EvdevDevice>(&mHost, node);
     EXPECT_EQ(INPUT_DEVICE_CLASS_SWITCH, device->getInputClasses());
 }
 
 TEST_F(EvdevDeviceTest, testN7v2H2wButton) {
-    InputHost host = {mMockHost.get(), kTestCallbacks};
     auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getH2wButton());
-    auto device = std::make_unique<EvdevDevice>(host, node);
+    auto device = std::make_unique<EvdevDevice>(&mHost, node);
     EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
 }
 
 TEST_F(EvdevDeviceTest, testN7v2GpioKeys) {
-    InputHost host = {mMockHost.get(), kTestCallbacks};
     auto node = std::shared_ptr<MockInputDeviceNode>(MockNexus7v2::getGpioKeys());
-    auto device = std::make_unique<EvdevDevice>(host, node);
+    auto device = std::make_unique<EvdevDevice>(&mHost, node);
     EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
 }
 
 TEST_F(EvdevDeviceTest, testNexusPlayerGpioKeys) {
-    InputHost host = {mMockHost.get(), kTestCallbacks};
     auto node = std::shared_ptr<MockInputDeviceNode>(MockNexusPlayer::getGpioKeys());
-    auto device = std::make_unique<EvdevDevice>(host, node);
+    auto device = std::make_unique<EvdevDevice>(&mHost, node);
     EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
 }
 
 TEST_F(EvdevDeviceTest, testNexusPlayerMidPowerBtn) {
-    InputHost host = {mMockHost.get(), kTestCallbacks};
     auto node = std::shared_ptr<MockInputDeviceNode>(MockNexusPlayer::getMidPowerBtn());
-    auto device = std::make_unique<EvdevDevice>(host, node);
+    auto device = std::make_unique<EvdevDevice>(&mHost, node);
     EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
 }
 
 TEST_F(EvdevDeviceTest, testNexusRemote) {
-    InputHost host = {mMockHost.get(), kTestCallbacks};
     auto node = std::shared_ptr<MockInputDeviceNode>(MockNexusPlayer::getNexusRemote());
-    auto device = std::make_unique<EvdevDevice>(host, node);
+    auto device = std::make_unique<EvdevDevice>(&mHost, node);
     EXPECT_EQ(INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
 }
 
 TEST_F(EvdevDeviceTest, testAsusGamepad) {
-    InputHost host = {mMockHost.get(), kTestCallbacks};
     auto node = std::shared_ptr<MockInputDeviceNode>(MockNexusPlayer::getAsusGamepad());
-    auto device = std::make_unique<EvdevDevice>(host, node);
+    auto device = std::make_unique<EvdevDevice>(&mHost, node);
     EXPECT_EQ(INPUT_DEVICE_CLASS_JOYSTICK|INPUT_DEVICE_CLASS_KEYBOARD, device->getInputClasses());
 }
 
+TEST_F(EvdevDeviceTest, testMocks) {
+    auto node = std::make_shared<MockInputDeviceNode>();
+    auto device = std::make_unique<EvdevDevice>(&mHost, node);
+}
+
 }  // namespace tests
 }  // namespace android
diff --git a/tests/input/evdev/InputMocks.cpp b/tests/input/evdev/InputMocks.cpp
index c316075..f4a341a 100644
--- a/tests/input/evdev/InputMocks.cpp
+++ b/tests/input/evdev/InputMocks.cpp
@@ -1,104 +1,7 @@
 #include "InputMocks.h"
 
-// Private test definitions of opaque HAL structs
-
-// Not used
-struct input_property_map {};
-
-// Holds the key and value from the mock host's PropertyMap
-struct input_property {
-    android::String8 key;
-    android::String8 value;
-};
-
 namespace android {
 
-bool MockInputHost::checkAllocations() const {
-    bool ret = true;
-    if (mMapAllocations != 0) {
-        ALOGE("Leaked %d device property map allocations", mMapAllocations);
-        ret = false;
-    }
-    for (auto entry : mPropertyAllocations) {
-        if (entry.second != 0) {
-            ALOGE("Leaked %d property allocation for %s", entry.second, entry.first.c_str());
-            ret = false;
-        }
-    }
-    return ret;
-}
-
-input_device_identifier_t* MockInputHost::createDeviceIdentifier(
-        const char* name, int32_t product_id, int32_t vendor_id,
-        input_bus_t bus, const char* unique_id) {
-    mDeviceId.reset(new input_device_identifier_t{
-            .name = name,
-            .productId = product_id,
-            .vendorId = vendor_id,
-            .bus = bus,
-            .uniqueId = unique_id
-            });
-    // Just return the raw pointer. We don't have a method for deallocating
-    // device identifiers yet, and they should exist throughout the lifetime of
-    // the input process for now.
-    return mDeviceId.get();
-}
-
-input_property_map_t* MockInputHost::getDevicePropertyMap(input_device_identifier_t* id) {
-    mMapAllocations++;
-    // Handled in the MockInputHost.
-    return nullptr;
-}
-
-input_property_t* MockInputHost::getDeviceProperty(input_property_map_t* map, const char* key) {
-    mPropertyAllocations[key]++;
-    return new input_property_t{.key = String8(key)};
-}
-
-const char* MockInputHost::getPropertyKey(input_property_t* property) {
-    return property->key.string();
-}
-
-const char* MockInputHost::getPropertyValue(input_property_t* property) {
-    if (!mDevicePropertyMap.tryGetProperty(property->key, property->value)) {
-        return nullptr;
-    }
-    return property->value.string();
-}
-
-void MockInputHost::freeDeviceProperty(input_property_t* property) {
-    if (property != nullptr) {
-        mPropertyAllocations[property->key.string()]--;
-        delete property;
-    }
-}
-
-void MockInputHost::freeDevicePropertyMap(input_property_map_t* map) {
-    mMapAllocations--;
-}
-
-input_host_callbacks_t kTestCallbacks = {
-    .create_device_identifier = create_device_identifier,
-    .create_device_definition = create_device_definition,
-    .create_input_report_definition = create_input_report_definition,
-    .create_output_report_definition = create_output_report_definition,
-    .input_device_definition_add_report = input_device_definition_add_report,
-    .input_report_definition_add_collection = input_report_definition_add_collection,
-    .input_report_definition_declare_usage_int = input_report_definition_declare_usage_int,
-    .input_report_definition_declare_usages_bool = input_report_definition_declare_usages_bool,
-    .register_device = register_device,
-    .input_allocate_report = input_allocate_report,
-    .input_report_set_usage_int = input_report_set_usage_int,
-    .input_report_set_usage_bool = input_report_set_usage_bool,
-    .report_event = report_event,
-    .input_get_device_property_map = input_get_device_property_map,
-    .input_get_device_property = input_get_device_property,
-    .input_get_property_key = input_get_property_key,
-    .input_get_property_value = input_get_property_value,
-    .input_free_device_property = input_free_device_property,
-    .input_free_device_property_map = input_free_device_property_map,
-};
-
 bool MockInputDeviceNode::hasKeyInRange(int32_t startKey, int32_t endKey) const {
     auto iter = mKeys.lower_bound(startKey);
     if (iter == mKeys.end()) return false;
@@ -321,86 +224,4 @@
 
 }  // namespace MockNexusPlayer
 
-::input_device_identifier_t* create_device_identifier(input_host_t* host,
-        const char* name, int32_t product_id, int32_t vendor_id,
-        input_bus_t bus, const char* unique_id) {
-    auto mockHost = static_cast<MockInputHost*>(host);
-    return mockHost->createDeviceIdentifier(name, product_id, vendor_id, bus, unique_id);
-}
-
-input_device_definition_t* create_device_definition(input_host_t* host) {
-    return nullptr;
-}
-
-input_report_definition_t* create_input_report_definition(input_host_t* host) {
-    return nullptr;
-}
-
-input_report_definition_t* create_output_report_definition(input_host_t* host) {
-    return nullptr;
-}
-
-void input_device_definition_add_report(input_host_t* host,
-        input_device_definition_t* d, input_report_definition_t* r) { }
-
-void input_report_definition_add_collection(input_host_t* host,
-        input_report_definition_t* report, input_collection_id_t id, int32_t arity) { }
-
-void input_report_definition_declare_usage_int(input_host_t* host,
-        input_report_definition_t* report, input_collection_id_t id,
-        input_usage_t usage, int32_t min, int32_t max, float resolution) { }
-
-void input_report_definition_declare_usages_bool(input_host_t* host,
-        input_report_definition_t* report, input_collection_id_t id,
-        input_usage_t* usage, size_t usage_count) { }
-
-
-input_device_handle_t* register_device(input_host_t* host,
-        input_device_identifier_t* id, input_device_definition_t* d) {
-    return nullptr;
-}
-
-input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r) {
-    return nullptr;
-}
-void input_report_set_usage_int(input_host_t* host, input_report_t* r,
-        input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) { }
-
-void input_report_set_usage_bool(input_host_t* host, input_report_t* r,
-        input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) { }
-
-void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report) { }
-
-input_property_map_t* input_get_device_property_map(input_host_t* host,
-        input_device_identifier_t* id) {
-    auto mockHost = static_cast<MockInputHost*>(host);
-    return mockHost->getDevicePropertyMap(id);
-}
-
-input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map,
-        const char* key) {
-    auto mockHost = static_cast<MockInputHost*>(host);
-    return mockHost->getDeviceProperty(map, key);
-}
-
-const char* input_get_property_key(input_host_t* host, input_property_t* property) {
-    auto mockHost = static_cast<MockInputHost*>(host);
-    return mockHost->getPropertyKey(property);
-}
-
-const char* input_get_property_value(input_host_t* host, input_property_t* property) {
-    auto mockHost = static_cast<MockInputHost*>(host);
-    return mockHost->getPropertyValue(property);
-}
-
-void input_free_device_property(input_host_t* host, input_property_t* property) {
-    auto mockHost = static_cast<MockInputHost*>(host);
-    return mockHost->freeDeviceProperty(property);
-}
-
-void input_free_device_property_map(input_host_t* host, input_property_map_t* map) {
-    auto mockHost = static_cast<MockInputHost*>(host);
-    return mockHost->freeDevicePropertyMap(map);
-}
-
 }  // namespace android
diff --git a/tests/input/evdev/InputMocks.h b/tests/input/evdev/InputMocks.h
index 5c6eb80..78e0279 100644
--- a/tests/input/evdev/InputMocks.h
+++ b/tests/input/evdev/InputMocks.h
@@ -18,72 +18,15 @@
 #define ANDROID_INPUT_MOCKS_H_
 
 #include <map>
-#include <memory>
 #include <set>
 #include <string>
-#include <unordered_map>
 
 #include <linux/input.h>
 
-#include <hardware/input.h>
-#include <utils/PropertyMap.h>
-
 #include "InputHub.h"
 
-// Test definitions of opaque HAL structs
-struct input_host {};
-struct input_device_identifier {
-    const char* name;
-    const char* uniqueId;
-    input_bus_t bus;
-    int32_t     vendorId;
-    int32_t     productId;
-    int32_t     version;
-};
-
-
 namespace android {
 
-extern input_host_callbacks_t kTestCallbacks;
-
-class MockInputHost : public ::input_host_t {
-public:
-    virtual ~MockInputHost() = default;
-
-    void addDeviceProperty(const std::string& key, const std::string& value) {
-        mDevicePropertyMap.addProperty(String8(key.c_str()), String8(value.c_str()));
-    }
-
-    /**
-     * Call this at the end of a test to verify that any allocations made
-     * during the test were freed.
-     */
-    bool checkAllocations() const;
-
-    // Callbacks
-    input_device_identifier_t* createDeviceIdentifier(
-            const char* name, int32_t product_id, int32_t vendor_id,
-            input_bus_t bus, const char* unique_id);
-
-    input_property_map_t* getDevicePropertyMap(input_device_identifier_t* id);
-
-    input_property_t* getDeviceProperty(input_property_map_t* map, const char* key);
-
-    const char* getPropertyKey(input_property_t* property);
-
-    const char* getPropertyValue(input_property_t* property);
-
-    void freeDeviceProperty(input_property_t* property);
-
-    void freeDevicePropertyMap(input_property_map_t* map);
-
-private:
-    PropertyMap mDevicePropertyMap;
-    std::unique_ptr<input_device_identifier_t> mDeviceId;
-    int32_t mMapAllocations = 0;
-    std::unordered_map<std::string, int32_t> mPropertyAllocations;
-};
-
 class MockInputDeviceNode : public InputDeviceNode {
 public:
     MockInputDeviceNode() = default;
@@ -194,63 +137,6 @@
 MockInputDeviceNode* getAsusGamepad();
 }  // namespace MockNexusPlayer
 
-// HAL method prototypes used in mock callbacks
-extern "C" {
-input_device_identifier_t* create_device_identifier(input_host_t* host,
-        const char* name, int32_t product_id, int32_t vendor_id,
-        input_bus_t bus, const char* unique_id);
-
-input_device_definition_t* create_device_definition(input_host_t* host);
-
-input_report_definition_t* create_input_report_definition(input_host_t* host);
-
-input_report_definition_t* create_output_report_definition(input_host_t* host);
-
-void input_device_definition_add_report(input_host_t* host,
-        input_device_definition_t* d, input_report_definition_t* r);
-
-void input_report_definition_add_collection(input_host_t* host,
-        input_report_definition_t* report, input_collection_id_t id, int32_t arity);
-
-void input_report_definition_declare_usage_int(input_host_t* host,
-        input_report_definition_t* report, input_collection_id_t id,
-        input_usage_t usage, int32_t min, int32_t max, float resolution);
-
-void input_report_definition_declare_usages_bool(input_host_t* host,
-        input_report_definition_t* report, input_collection_id_t id,
-        input_usage_t* usage, size_t usage_count);
-
-
-input_device_handle_t* register_device(input_host_t* host,
-        input_device_identifier_t* id, input_device_definition_t* d);
-
-void unregister_device(input_host_t* host, input_device_handle_t* handle);
-
-input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r);
-
-void input_report_set_usage_int(input_host_t* host, input_report_t* r,
-        input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index);
-
-void input_report_set_usage_bool(input_host_t* host, input_report_t* r,
-        input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index);
-
-void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report);
-
-input_property_map_t* input_get_device_property_map(input_host_t* host,
-        input_device_identifier_t* id);
-
-input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map,
-        const char* key);
-
-const char* input_get_property_key(input_host_t* host, input_property_t* property);
-
-const char* input_get_property_value(input_host_t* host, input_property_t* property);
-
-void input_free_device_property(input_host_t* host, input_property_t* property);
-
-void input_free_device_property_map(input_host_t* host, input_property_map_t* map);
-}  // extern "C"
-
 }  // namespace android
 
 #endif  // ANDROID_INPUT_MOCKS_H_
diff --git a/tests/input/evdev/MockInputHost.h b/tests/input/evdev/MockInputHost.h
new file mode 100644
index 0000000..a91f95c
--- /dev/null
+++ b/tests/input/evdev/MockInputHost.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#ifndef ANDROID_MOCK_INPUT_HOST_H_
+#define ANDROID_MOCK_INPUT_HOST_H_
+
+#include "gmock/gmock.h"
+
+#include "InputHost.h"
+
+namespace android {
+namespace tests {
+
+class MockInputReport : public InputReport {
+public:
+    MockInputReport() : InputReport(nullptr, {}, nullptr) {}
+    MOCK_METHOD4(setIntUsage, void(InputCollectionId id, InputUsage usage, int32_t value,
+                int32_t arityIndex));
+    MOCK_METHOD4(setBoolUsage, void(InputCollectionId id, InputUsage usage, bool value,
+                int32_t arityIndex));
+    MOCK_METHOD1(reportEvent, void(InputDeviceHandle* d));
+};
+
+class MockInputReportDefinition : public InputReportDefinition {
+public:
+    MockInputReportDefinition() : InputReportDefinition(nullptr, {}, nullptr) {}
+    MOCK_METHOD2(addCollection, void(InputCollectionId id, int32_t arity));
+    MOCK_METHOD5(declareUsage, void(InputCollectionId id, InputUsage usage, int32_t min,
+                int32_t max, float resolution));
+    MOCK_METHOD3(declareUsages, void(InputCollectionId id, InputUsage* usage, size_t usageCount));
+    MOCK_METHOD0(allocateReport, InputReport*());
+};
+
+class MockInputDeviceDefinition : public InputDeviceDefinition {
+public:
+    MockInputDeviceDefinition() : InputDeviceDefinition(nullptr, {}, nullptr) {}
+    MOCK_METHOD1(addReport, void(InputReportDefinition* r));
+};
+
+class MockInputProperty : public InputProperty {
+public:
+    MockInputProperty() : InputProperty(nullptr, {}, nullptr) {}
+    virtual ~MockInputProperty() {}
+    MOCK_CONST_METHOD0(getKey, const char*());
+    MOCK_CONST_METHOD0(getValue, const char*());
+};
+
+class MockInputPropertyMap : public InputPropertyMap {
+public:
+    MockInputPropertyMap() : InputPropertyMap(nullptr, {}, nullptr) {}
+    virtual ~MockInputPropertyMap() {}
+    MOCK_CONST_METHOD1(getDeviceProperty, InputProperty*(const char* key));
+    MOCK_CONST_METHOD1(freeDeviceProperty, void(InputProperty* property));
+};
+
+class MockInputHost : public InputHostInterface {
+public:
+    MOCK_METHOD5(createDeviceIdentifier, InputDeviceIdentifier*(
+                const char* name, int32_t productId, int32_t vendorId, InputBus bus,
+                const char* uniqueId));
+    MOCK_METHOD0(createDeviceDefinition, InputDeviceDefinition*());
+    MOCK_METHOD0(createInputReportDefinition, InputReportDefinition*());
+    MOCK_METHOD0(createOutputReportDefinition, InputReportDefinition*());
+    MOCK_METHOD1(freeReportDefinition, void(InputReportDefinition* reportDef));
+    MOCK_METHOD2(registerDevice, InputDeviceHandle*(InputDeviceIdentifier* id,
+                InputDeviceDefinition* d));
+    MOCK_METHOD1(unregisterDevice, void(InputDeviceHandle* handle));
+    MOCK_METHOD1(getDevicePropertyMap, InputPropertyMap*(InputDeviceIdentifier* id));
+    MOCK_METHOD1(freeDevicePropertyMap, void(InputPropertyMap* propertyMap));
+};
+
+}  // namespace tests
+}  // namespace android
+
+#endif  // ANDROID_MOCK_INPUT_HOST_H_
diff --git a/tests/input/evdev/SwitchInputMapper_test.cpp b/tests/input/evdev/SwitchInputMapper_test.cpp
new file mode 100644
index 0000000..f93041b
--- /dev/null
+++ b/tests/input/evdev/SwitchInputMapper_test.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 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 <memory>
+
+#include <linux/input.h>
+
+#include <gtest/gtest.h>
+
+#include "InputMocks.h"
+#include "MockInputHost.h"
+#include "SwitchInputMapper.h"
+
+using ::testing::_;
+using ::testing::Args;
+using ::testing::InSequence;
+using ::testing::Return;
+using ::testing::UnorderedElementsAre;
+
+namespace android {
+namespace tests {
+
+class SwitchInputMapperTest : public ::testing::Test {
+protected:
+     virtual void SetUp() override {
+         mMapper = std::make_unique<SwitchInputMapper>();
+     }
+
+     MockInputHost mHost;
+     std::unique_ptr<SwitchInputMapper> mMapper;
+};
+
+TEST_F(SwitchInputMapperTest, testConfigureDevice) {
+    MockInputReportDefinition reportDef;
+    MockInputDeviceNode deviceNode;
+    deviceNode.addSwitch(SW_LID);
+    deviceNode.addSwitch(SW_CAMERA_LENS_COVER);
+
+    EXPECT_CALL(reportDef, addCollection(INPUT_COLLECTION_ID_SWITCH, 1));
+    EXPECT_CALL(reportDef, declareUsages(INPUT_COLLECTION_ID_SWITCH, _, 2))
+        .With(Args<1,2>(UnorderedElementsAre(INPUT_USAGE_SWITCH_LID,
+                        INPUT_USAGE_SWITCH_CAMERA_LENS_COVER)));
+
+    mMapper->configureInputReport(&deviceNode, &reportDef);
+}
+
+TEST_F(SwitchInputMapperTest, testConfigureDevice_noSwitches) {
+    MockInputReportDefinition reportDef;
+    MockInputDeviceNode deviceNode;
+
+    EXPECT_CALL(reportDef, addCollection(_, _)).Times(0);
+    EXPECT_CALL(reportDef, declareUsages(_, _, _)).Times(0);
+
+    mMapper->configureInputReport(&deviceNode, &reportDef);
+}
+
+TEST_F(SwitchInputMapperTest, testProcessInput) {
+    MockInputReportDefinition reportDef;
+    MockInputDeviceNode deviceNode;
+    deviceNode.addSwitch(SW_LID);
+
+    EXPECT_CALL(reportDef, addCollection(_, _));
+    EXPECT_CALL(reportDef, declareUsages(_, _, _));
+
+    mMapper->configureInputReport(&deviceNode, &reportDef);
+
+    MockInputReport report;
+    EXPECT_CALL(reportDef, allocateReport())
+        .WillOnce(Return(&report));
+
+    {
+        // Test two switch events in order
+        InSequence s;
+        EXPECT_CALL(report, setBoolUsage(INPUT_COLLECTION_ID_SWITCH, INPUT_USAGE_SWITCH_LID, 1, 0));
+        EXPECT_CALL(report, reportEvent(_));
+        EXPECT_CALL(report, setBoolUsage(INPUT_COLLECTION_ID_SWITCH, INPUT_USAGE_SWITCH_LID, 0, 0));
+        EXPECT_CALL(report, reportEvent(_));
+    }
+
+    InputEvent events[] = {
+        {0, EV_SW, SW_LID, 1},
+        {1, EV_SYN, SYN_REPORT, 0},
+        {2, EV_SW, SW_LID, 0},
+        {3, EV_SYN, SYN_REPORT, 0},
+    };
+    for (auto e : events) {
+        mMapper->process(e);
+    }
+}
+
+}  // namespace tests
+}  // namespace android
+