xref: /aosp_15_r20/frameworks/native/libs/input/tests/TestEventMatchers.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /**
2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <chrono>
20 #include <cmath>
21 #include <ostream>
22 #include <vector>
23 
24 #include <android-base/logging.h>
25 #include <gtest/gtest.h>
26 #include <input/Input.h>
27 
28 namespace android {
29 
30 namespace {
31 
32 using ::testing::Matcher;
33 
34 } // namespace
35 
36 /**
37  * This file contains a copy of Matchers from .../inputflinger/tests/TestEventMatchers.h. Ideally,
38  * implementations must not be duplicated.
39  * TODO(b/365606513): Find a way to share TestEventMatchers.h between inputflinger and libinput.
40  */
41 
42 struct PointerArgs {
43     float x{0.0f};
44     float y{0.0f};
45     bool isResampled{false};
46 };
47 
48 struct Sample {
49     std::chrono::nanoseconds eventTime{0};
50     std::vector<PointerArgs> pointers{};
51 };
52 
53 class WithDeviceIdMatcher {
54 public:
55     using is_gtest_matcher = void;
WithDeviceIdMatcher(DeviceId deviceId)56     explicit WithDeviceIdMatcher(DeviceId deviceId) : mDeviceId(deviceId) {}
57 
MatchAndExplain(const InputEvent & event,std::ostream *)58     bool MatchAndExplain(const InputEvent& event, std::ostream*) const {
59         return mDeviceId == event.getDeviceId();
60     }
61 
DescribeTo(std::ostream * os)62     void DescribeTo(std::ostream* os) const { *os << "with device id " << mDeviceId; }
63 
DescribeNegationTo(std::ostream * os)64     void DescribeNegationTo(std::ostream* os) const { *os << "wrong device id"; }
65 
66 private:
67     const DeviceId mDeviceId;
68 };
69 
WithDeviceId(int32_t deviceId)70 inline WithDeviceIdMatcher WithDeviceId(int32_t deviceId) {
71     return WithDeviceIdMatcher(deviceId);
72 }
73 
74 class WithMotionActionMatcher {
75 public:
76     using is_gtest_matcher = void;
WithMotionActionMatcher(int32_t action)77     explicit WithMotionActionMatcher(int32_t action) : mAction(action) {}
78 
MatchAndExplain(const MotionEvent & event,testing::MatchResultListener * listener)79     bool MatchAndExplain(const MotionEvent& event, testing::MatchResultListener* listener) const {
80         if (mAction != event.getAction()) {
81             *listener << "expected " << MotionEvent::actionToString(mAction) << ", but got "
82                       << MotionEvent::actionToString(event.getAction());
83             return false;
84         }
85         if (event.getAction() == AMOTION_EVENT_ACTION_CANCEL &&
86             (event.getFlags() & AMOTION_EVENT_FLAG_CANCELED) == 0) {
87             *listener << "event with CANCEL action is missing FLAG_CANCELED";
88             return false;
89         }
90         return true;
91     }
92 
DescribeTo(std::ostream * os)93     void DescribeTo(std::ostream* os) const {
94         *os << "with motion action " << MotionEvent::actionToString(mAction);
95         if (mAction == AMOTION_EVENT_ACTION_CANCEL) {
96             *os << " and FLAG_CANCELED";
97         }
98     }
99 
DescribeNegationTo(std::ostream * os)100     void DescribeNegationTo(std::ostream* os) const { *os << "wrong action"; }
101 
102 private:
103     const int32_t mAction;
104 };
105 
WithMotionAction(int32_t action)106 inline WithMotionActionMatcher WithMotionAction(int32_t action) {
107     return WithMotionActionMatcher(action);
108 }
109 
110 class WithSampleCountMatcher {
111 public:
112     using is_gtest_matcher = void;
WithSampleCountMatcher(size_t sampleCount)113     explicit WithSampleCountMatcher(size_t sampleCount) : mExpectedSampleCount{sampleCount} {}
114 
MatchAndExplain(const MotionEvent & motionEvent,std::ostream *)115     bool MatchAndExplain(const MotionEvent& motionEvent, std::ostream*) const {
116         return (motionEvent.getHistorySize() + 1) == mExpectedSampleCount;
117     }
118 
DescribeTo(std::ostream * os)119     void DescribeTo(std::ostream* os) const { *os << "sample count " << mExpectedSampleCount; }
120 
DescribeNegationTo(std::ostream * os)121     void DescribeNegationTo(std::ostream* os) const { *os << "different sample count"; }
122 
123 private:
124     const size_t mExpectedSampleCount;
125 };
126 
WithSampleCount(size_t sampleCount)127 inline WithSampleCountMatcher WithSampleCount(size_t sampleCount) {
128     return WithSampleCountMatcher(sampleCount);
129 }
130 
131 class WithSampleMatcher {
132 public:
133     using is_gtest_matcher = void;
WithSampleMatcher(size_t sampleIndex,const Sample & sample)134     explicit WithSampleMatcher(size_t sampleIndex, const Sample& sample)
135           : mSampleIndex{sampleIndex}, mSample{sample} {}
136 
MatchAndExplain(const MotionEvent & motionEvent,std::ostream * os)137     bool MatchAndExplain(const MotionEvent& motionEvent, std::ostream* os) const {
138         if (motionEvent.getHistorySize() < mSampleIndex) {
139             *os << "sample index out of bounds";
140             return false;
141         }
142 
143         if (motionEvent.getHistoricalEventTime(mSampleIndex) != mSample.eventTime.count()) {
144             *os << "event time mismatch. sample: "
145                 << motionEvent.getHistoricalEventTime(mSampleIndex)
146                 << " expected: " << mSample.eventTime.count();
147             return false;
148         }
149 
150         if (motionEvent.getPointerCount() != mSample.pointers.size()) {
151             *os << "pointer count mismatch. sample: " << motionEvent.getPointerCount()
152                 << " expected: " << mSample.pointers.size();
153             return false;
154         }
155 
156         for (size_t pointerIndex = 0; pointerIndex < motionEvent.getPointerCount();
157              ++pointerIndex) {
158             const PointerCoords& pointerCoords =
159                     *(motionEvent.getHistoricalRawPointerCoords(pointerIndex, mSampleIndex));
160 
161             if ((std::abs(pointerCoords.getX() - mSample.pointers[pointerIndex].x) >
162                  MotionEvent::ROUNDING_PRECISION) ||
163                 (std::abs(pointerCoords.getY() - mSample.pointers[pointerIndex].y) >
164                  MotionEvent::ROUNDING_PRECISION)) {
165                 *os << "sample coordinates mismatch at pointer index " << pointerIndex
166                     << ". sample: (" << pointerCoords.getX() << ", " << pointerCoords.getY()
167                     << ") expected: (" << mSample.pointers[pointerIndex].x << ", "
168                     << mSample.pointers[pointerIndex].y << ")";
169                 return false;
170             }
171 
172             if (motionEvent.isResampled(pointerIndex, mSampleIndex) !=
173                 mSample.pointers[pointerIndex].isResampled) {
174                 *os << "resampling flag mismatch. sample: "
175                     << motionEvent.isResampled(pointerIndex, mSampleIndex)
176                     << " expected: " << mSample.pointers[pointerIndex].isResampled;
177                 return false;
178             }
179         }
180         return true;
181     }
182 
DescribeTo(std::ostream * os)183     void DescribeTo(std::ostream* os) const { *os << "motion event sample properties match."; }
184 
DescribeNegationTo(std::ostream * os)185     void DescribeNegationTo(std::ostream* os) const {
186         *os << "motion event sample properties do not match expected properties.";
187     }
188 
189 private:
190     const size_t mSampleIndex;
191     const Sample mSample;
192 };
193 
WithSample(size_t sampleIndex,const Sample & sample)194 inline WithSampleMatcher WithSample(size_t sampleIndex, const Sample& sample) {
195     return WithSampleMatcher(sampleIndex, sample);
196 }
197 
198 } // namespace android
199