1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "gtest/gtest.h"
16 #include "widget_operator.h"
17 #include "mock_element_node_iterator.h"
18 #include "mock_controller.h"
19
20 using namespace OHOS::uitest;
21 using namespace std;
22
23 unique_ptr<PointerMatrix> MockController::touch_event_records_ = nullptr;
24
25 class WidgetOperatorTest : public testing::Test {
26 protected:
SetUp()27 void SetUp() override
28 {
29 auto mockController = std::make_unique<MockController>();
30 controller_ = mockController.get();
31 UiDriver::RegisterController(std::move(mockController));
32 driver_ = make_unique<UiDriver>();
33 ResetWindowAndNode(w1_, eles_);
34 }
35
36 // Reset Window and node
ResetWindowAndNode(Window & w,std::vector<MockAccessibilityElementInfo> & eles)37 void ResetWindowAndNode(Window &w, std::vector<MockAccessibilityElementInfo> &eles)
38 {
39 std::string domJson = R"(
40 {
41 "attributes":{
42 "windowId":"12",
43 "componentType":"List",
44 "accessibilityId":"1",
45 "content":"Text List",
46 "rectInScreen":"0,1000,0,1200"
47 },
48 "children":[
49 {
50 "attributes":{
51 "windowId":"12",
52 "accessibilityId":"2",
53 "componentType":"Scroll",
54 "content":"Text List Scroll",
55 "rectInScreen":"0,600,0,1000"
56 },
57 "children":[
58 {
59 "attributes":{
60 "windowId":"12",
61 "accessibilityId":"3",
62 "componentType":"Image",
63 "content":"Button",
64 "rectInScreen":"30,40,10,20"
65 },
66 "children":[
67 {
68 "attributes":{
69 "windowId":"12",
70 "accessibilityId":"4",
71 "componentType":"Text",
72 "content":"Text One",
73 "rectInScreen":"30,40,10,20"
74 },
75 "children":[]
76 }
77 ]
78 },
79 {
80 "attributes":{
81 "windowId":"12",
82 "componentType":"List",
83 "accessibilityId":"5",
84 "content":"Text List12",
85 "rectInScreen":"40,60,10,20"
86 },
87 "children":[
88 {
89 "attributes":{
90 "windowId":"12",
91 "accessibilityId":"6",
92 "componentType":"Text",
93 "content":"Text One",
94 "rectInScreen":"40,50,10,20"
95 },
96 "children":[]
97 },
98 {
99 "attributes":{
100 "windowId":"12",
101 "accessibilityId":"8",
102 "componentType":"Text",
103 "content":"Text Two",
104 "rectInScreen":"50,60,10,20"
105 },
106 "children":[]
107 }
108 ]
109 }
110 ]
111 },
112 {
113 "attributes":{
114 "windowId":"12",
115 "accessibilityId":"10",
116 "componentType":"Image",
117 "content":"Button",
118 "rectInScreen":"10,20,20,100"
119 },
120 "children":[]
121 },
122 {
123 "attributes":{
124 "windowId":"12",
125 "accessibilityId":"11",
126 "componentType":"List",
127 "content":"Button",
128 "rectInScreen":"20,100,20,100"
129 },
130 "children":[
131 {
132 "attributes":{
133 "windowId":"12",
134 "accessibilityId":"12",
135 "componentType":"Image",
136 "content":"",
137 "rectInScreen":"20,100,20,100"
138 },
139 "children":[]
140 },
141 {
142 "attributes":{
143 "windowId":"12",
144 "accessibilityId":"14",
145 "componentType":"Button",
146 "content":"Text End Button",
147 "rectInScreen":"20,100,20,100"
148 },
149 "children":[
150 {
151 "attributes":{
152 "windowId":"12",
153 "accessibilityId":"15",
154 "componentType":"Text",
155 "content":"Text End",
156 "rectInScreen":"20,100,20,100"
157 },
158 "children":[]
159 }
160 ]
161 }
162 ]
163 }
164 ]
165 }
166 )";
167 eles_ = MockElementNodeIterator::ConstructIteratorByJson(domJson)->elementInfoLists_;
168 w.windowLayer_ = 2;
169 w.bounds_ = Rect{0, 1000, 0, 1200};
170 w.bundleName_ = "test1";
171 }
TearDown()172 void TearDown() override
173 {
174 controller_ = nullptr;
175 }
176
177 MockController *controller_ = nullptr;
178 unique_ptr<UiDriver> driver_ = nullptr;
179 UiOpArgs opt_;
180 Window w1_{12};
181 std::vector<MockAccessibilityElementInfo> eles_;
182 ~WidgetOperatorTest() override = default;
183 };
184
TEST_F(WidgetOperatorTest,scrollSearchNoTarget)185 TEST_F(WidgetOperatorTest, scrollSearchNoTarget)
186 {
187 auto error = ApiCallErr(NO_ERROR);
188 auto scrollWidgetSelector = WidgetSelector();
189 auto matcher = WidgetMatchModel(UiAttr::TEXT, "Text List Scroll", EQ);
190 scrollWidgetSelector.AddMatcher(matcher);
191 vector<unique_ptr<Widget>> widgets;
192 controller_->AddWindowsAndNode(w1_, eles_);
193 scrollWidgetSelector.SetWantMulti(false);
194 driver_->FindWidgets(scrollWidgetSelector, widgets, error, true);
195
196 ASSERT_EQ(1, widgets.size());
197
198 // mock another dom on which the scroll-widget is missing, and perform scroll-search
199
200 auto targetWidgetSelector = WidgetSelector();
201 auto wOp = WidgetOperator(*driver_, *widgets.at(0), opt_);
202 auto matcher0 = WidgetMatchModel(UiAttr::TEXT, "Text End", EQ);
203 targetWidgetSelector.AddMatcher(matcher0);
204 ASSERT_EQ(nullptr, wOp.ScrollFindWidget(targetWidgetSelector, true, error));
205 }
206
TEST_F(WidgetOperatorTest,scrollSearchWithTarget)207 TEST_F(WidgetOperatorTest, scrollSearchWithTarget)
208 {
209 auto error = ApiCallErr(NO_ERROR);
210 auto scrollWidgetSelector = WidgetSelector();
211 auto matcher = WidgetMatchModel(UiAttr::TEXT, "Text List Scroll", EQ);
212 scrollWidgetSelector.AddMatcher(matcher);
213 vector<unique_ptr<Widget>> widgets;
214 controller_->AddWindowsAndNode(w1_, eles_);
215 scrollWidgetSelector.SetWantMulti(false);
216 driver_->FindWidgets(scrollWidgetSelector, widgets, error, true);
217
218 ASSERT_EQ(1, widgets.size());
219 auto targetWidgetSelector = WidgetSelector();
220 auto wOp = WidgetOperator(*driver_, *widgets.at(0), opt_);
221 auto matcher0 = WidgetMatchModel(UiAttr::TEXT, "Text List12", EQ);
222 targetWidgetSelector.AddMatcher(matcher0);
223 auto rev = wOp.ScrollFindWidget(targetWidgetSelector, true, error);
224 ASSERT_FALSE(rev == nullptr);
225 ASSERT_EQ("5", rev->GetAttr(UiAttr::ACCESSIBILITY_ID));
226 }
227
TEST_F(WidgetOperatorTest,scrollSearchCheckSubjectWidget)228 TEST_F(WidgetOperatorTest, scrollSearchCheckSubjectWidget)
229 {
230 auto error = ApiCallErr(NO_ERROR);
231 auto scrollWidgetSelector = WidgetSelector();
232 auto matcher = WidgetMatchModel(UiAttr::TEXT, "Text List Scroll", EQ);
233 scrollWidgetSelector.AddMatcher(matcher);
234 vector<unique_ptr<Widget>> images;
235 controller_->AddWindowsAndNode(w1_, eles_);
236 scrollWidgetSelector.SetWantMulti(false);
237 driver_->FindWidgets(scrollWidgetSelector, images, error, true);
238
239 ASSERT_EQ(1, images.size());
240
241 auto targetWidgetMatcher = WidgetMatchModel(UiAttr::TEXT, "Text End", EQ);
242 auto targetWidgetSelector = WidgetSelector();
243 targetWidgetSelector.AddMatcher(targetWidgetMatcher);
244 opt_.scrollWidgetDeadZone_ = 0; // set deadzone to 0 for easy computation
245 auto wOp = WidgetOperator(*driver_, *images.at(0), opt_);
246 ASSERT_EQ(nullptr, wOp.ScrollFindWidget(targetWidgetSelector, true, error));
247 // check the scroll action events, should be acted on the subject node specified by WidgetMatcher
248 ASSERT_TRUE(!MockController::touch_event_records_->Empty());
249 auto &firstEvent = MockController::touch_event_records_->At(0, 0);
250 auto fin = MockController::touch_event_records_->GetFingers() - 1;
251 auto ste = MockController::touch_event_records_->GetSteps() - 1;
252 auto &lastEvent = MockController::touch_event_records_->At(fin, ste);
253 // check scroll event pointer_x
254 int32_t subjectCx = (0 + 600) / 2;
255 ASSERT_NEAR(firstEvent.point_.px_, subjectCx, 5);
256 ASSERT_NEAR(lastEvent.point_.px_, subjectCx, 5);
257
258 // check scroll event pointer_y
259 constexpr int32_t subjectWidgetHeight = 1000 - 0;
260 int32_t maxCy = 0;
261 int32_t minCy = 1E5;
262 for (uint32_t finger = 0; finger < MockController::touch_event_records_->GetFingers(); finger++) {
263 for (uint32_t step = 0; step < MockController::touch_event_records_->GetSteps(); step++) {
264 if (MockController::touch_event_records_->At(finger, step).point_.py_ > maxCy) {
265 maxCy = MockController::touch_event_records_->At(finger, step).point_.py_;
266 }
267 if (MockController::touch_event_records_->At(finger, step).point_.py_ < minCy) {
268 minCy = MockController::touch_event_records_->At(finger, step).point_.py_;
269 }
270 }
271 }
272
273 int32_t scrollDistanceY = maxCy - minCy;
274 ASSERT_TRUE(abs(scrollDistanceY - subjectWidgetHeight) < 5);
275 }
276
TEST_F(WidgetOperatorTest,scrollSearchCheckDirection)277 TEST_F(WidgetOperatorTest, scrollSearchCheckDirection)
278 {
279 auto error = ApiCallErr(NO_ERROR);
280 auto scrollWidgetSelector = WidgetSelector();
281 auto matcher = WidgetMatchModel(UiAttr::TEXT, "Text List Scroll", EQ);
282 scrollWidgetSelector.AddMatcher(matcher);
283 vector<unique_ptr<Widget>> widgets;
284 controller_->AddWindowsAndNode(w1_, eles_);
285 scrollWidgetSelector.SetWantMulti(false);
286 driver_->FindWidgets(scrollWidgetSelector, widgets, error, true);
287 ASSERT_EQ(1, widgets.size());
288
289 error = ApiCallErr(NO_ERROR);
290 auto targetWidgetMatcher = WidgetMatchModel(UiAttr::TEXT, "Text End", EQ);
291 auto targetWidgetSelector = WidgetSelector();
292 targetWidgetSelector.AddMatcher(targetWidgetMatcher);
293 opt_.scrollWidgetDeadZone_ = 0; // set deadzone to 0 for easy computation
294 auto wOp = WidgetOperator(*driver_, *widgets.at(0), opt_);
295 ASSERT_EQ(nullptr, wOp.ScrollFindWidget(targetWidgetSelector, true, error));
296 // check the scroll action events, should be acted on the specified node
297 ASSERT_TRUE(!MockController::touch_event_records_->Empty());
298 // should scroll-search upward (cy_from<cy_to) then downward (cy_from>cy_to)
299 uint32_t maxCyEventIndex = 0;
300 uint32_t index = 0;
301 for (uint32_t event = 0; event < MockController::touch_event_records_->GetSize() - 1; event++) {
302 if (MockController::touch_event_records_->At(0, event).point_.py_ >
303 MockController::touch_event_records_->At(0, maxCyEventIndex).point_.py_) {
304 maxCyEventIndex = index;
305 }
306 index++;
307 }
308
309 for (uint32_t idx = 0; idx < MockController::touch_event_records_->GetSize() - 1; idx++) {
310 if (idx < maxCyEventIndex) {
311 ASSERT_LT(MockController::touch_event_records_->At(0, idx).point_.py_,
312 MockController::touch_event_records_->At(0, idx + 1).point_.py_);
313 } else if (idx > maxCyEventIndex) {
314 ASSERT_GT(MockController::touch_event_records_->At(0, idx).point_.py_,
315 MockController::touch_event_records_->At(0, idx + 1).point_.py_);
316 }
317 }
318 }
319