Create TestInputChannel and TestLooper to better test InputConsumerNoResampling

Created TestInputChannel and TestLooper to control how InputMessages are
batched in InputConsumerNoResampling_test

Bug: 297226446
Flag: EXEMPT refactor
Test: TEST=libinput_tests; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST --gtest_filter="InputConsumerTest*"
Change-Id: I036593b311a93ec301e8b9776b461505e853119f
diff --git a/libs/input/tests/InputConsumer_test.cpp b/libs/input/tests/InputConsumer_test.cpp
new file mode 100644
index 0000000..c30f243
--- /dev/null
+++ b/libs/input/tests/InputConsumer_test.cpp
@@ -0,0 +1,123 @@
+/**
+ * Copyright 2024 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 <input/InputConsumerNoResampling.h>
+
+#include <memory>
+#include <optional>
+#include <utility>
+
+#include <TestInputChannel.h>
+#include <TestLooper.h>
+#include <android-base/logging.h>
+#include <gtest/gtest.h>
+#include <input/BlockingQueue.h>
+#include <input/InputEventBuilders.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+
+class InputConsumerTest : public testing::Test, public InputConsumerCallbacks {
+protected:
+    InputConsumerTest()
+          : mClientTestChannel{std::make_shared<TestInputChannel>("TestChannel")},
+            mTestLooper{std::make_shared<TestLooper>()} {
+        Looper::setForThread(mTestLooper->getLooper());
+        mConsumer = std::make_unique<InputConsumerNoResampling>(mClientTestChannel, mTestLooper,
+                                                                *this, /*resampler=*/nullptr);
+    }
+
+    void assertOnBatchedInputEventPendingWasCalled();
+
+    std::shared_ptr<TestInputChannel> mClientTestChannel;
+    std::shared_ptr<TestLooper> mTestLooper;
+    std::unique_ptr<InputConsumerNoResampling> mConsumer;
+
+    BlockingQueue<std::unique_ptr<KeyEvent>> mKeyEvents;
+    BlockingQueue<std::unique_ptr<MotionEvent>> mMotionEvents;
+    BlockingQueue<std::unique_ptr<FocusEvent>> mFocusEvents;
+    BlockingQueue<std::unique_ptr<CaptureEvent>> mCaptureEvents;
+    BlockingQueue<std::unique_ptr<DragEvent>> mDragEvents;
+    BlockingQueue<std::unique_ptr<TouchModeEvent>> mTouchModeEvents;
+
+private:
+    size_t onBatchedInputEventPendingInvocationCount{0};
+
+    // InputConsumerCallbacks interface
+    void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) override {
+        mKeyEvents.push(std::move(event));
+        mConsumer->finishInputEvent(seq, true);
+    }
+    void onMotionEvent(std::unique_ptr<MotionEvent> event, uint32_t seq) override {
+        mMotionEvents.push(std::move(event));
+        mConsumer->finishInputEvent(seq, true);
+    }
+    void onBatchedInputEventPending(int32_t pendingBatchSource) override {
+        if (!mConsumer->probablyHasInput()) {
+            ADD_FAILURE() << "should deterministically have input because there is a batch";
+        }
+        ++onBatchedInputEventPendingInvocationCount;
+    };
+    void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) override {
+        mFocusEvents.push(std::move(event));
+        mConsumer->finishInputEvent(seq, true);
+    };
+    void onCaptureEvent(std::unique_ptr<CaptureEvent> event, uint32_t seq) override {
+        mCaptureEvents.push(std::move(event));
+        mConsumer->finishInputEvent(seq, true);
+    };
+    void onDragEvent(std::unique_ptr<DragEvent> event, uint32_t seq) override {
+        mDragEvents.push(std::move(event));
+        mConsumer->finishInputEvent(seq, true);
+    }
+    void onTouchModeEvent(std::unique_ptr<TouchModeEvent> event, uint32_t seq) override {
+        mTouchModeEvents.push(std::move(event));
+        mConsumer->finishInputEvent(seq, true);
+    };
+};
+
+void InputConsumerTest::assertOnBatchedInputEventPendingWasCalled() {
+    ASSERT_GT(onBatchedInputEventPendingInvocationCount, 0UL)
+            << "onBatchedInputEventPending has not been called.";
+    --onBatchedInputEventPendingInvocationCount;
+}
+
+TEST_F(InputConsumerTest, MessageStreamBatchedInMotionEvent) {
+    mClientTestChannel->enqueueMessage(
+            InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/0}.build());
+    mClientTestChannel->enqueueMessage(
+            InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/1}.build());
+    mClientTestChannel->enqueueMessage(
+            InputMessageBuilder{InputMessage::Type::MOTION, /*seq=*/2}.build());
+
+    mClientTestChannel->assertNoSentMessages();
+
+    mTestLooper->invokeCallback(mClientTestChannel->getFd(), ALOOPER_EVENT_INPUT);
+
+    assertOnBatchedInputEventPendingWasCalled();
+
+    mConsumer->consumeBatchedInputEvents(std::nullopt);
+
+    std::unique_ptr<MotionEvent> batchedMotionEvent = mMotionEvents.pop();
+    ASSERT_NE(batchedMotionEvent, nullptr);
+
+    mClientTestChannel->assertFinishMessage(/*seq=*/0, /*handled=*/true);
+    mClientTestChannel->assertFinishMessage(/*seq=*/1, /*handled=*/true);
+    mClientTestChannel->assertFinishMessage(/*seq=*/2, /*handled=*/true);
+
+    EXPECT_EQ(batchedMotionEvent->getHistorySize() + 1, 3UL);
+}
+} // namespace android