1 /*
2 * Copyright (c) 2021-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
16 #include "gtest/gtest.h"
17 #include "widget_selector.h"
18
19 using namespace OHOS::uitest;
20 using namespace std;
21
22 static constexpr char DOM_TEXT[] = R"({
23 "attributes": {
24 "rotation": "0"
25 },
26 "children": [
27 {
28 "attributes": {
29 "resource-id": "id1",
30 "text": ""
31 },
32 "children": [
33 {
34 "attributes": {
35 "resource-id": "id2",
36 "text": ""
37 },
38 "children": [
39 {
40 "attributes": {
41 "resource-id": "id3",
42 "text": ""
43 },
44 "children": [
45 {
46 "attributes": {
47 "resource-id": "id4",
48 "text": "Use USB to"
49 },
50 "children": []
51 }
52 ]
53 }
54 ]
55 },
56 {
57 "attributes": {
58 "resource-id": "id5",
59 "text": "wyz"
60 },
61 "children": [
62 {
63 "attributes": {
64 "resource-id": "id6",
65 "text": ""
66 },
67 "children": [
68 {
69 "attributes": {
70 "resource-id": "id7",
71 "text": ""
72 },
73 "children": [
74 {
75 "attributes": {
76 "resource-id": "id8",
77 "text": "Transfer photos"
78 },
79 "children": []
80 }
81 ]
82 },
83 {
84 "attributes": {
85 "resource-id": "id9",
86 "text": ""
87 },
88 "children": [
89 {
90 "attributes": {
91 "resource-id": "id10",
92 "text": "Transfer files"
93 },
94 "children": []
95 }
96 ]
97 }
98 ]
99 }
100 ]
101 }
102 ]
103 }
104 ]
105 }
106 )";
107
108 static constexpr auto ATTR_TEXT = "text";
109
110 class WidgetSelectorTest : public testing::Test {
111 protected:
112 WidgetTree tree_ = WidgetTree("dummy_tree");
113
SetUp()114 void SetUp() override
115 {
116 auto data = nlohmann::json::parse(DOM_TEXT);
117 tree_.ConstructFromDom(data, false);
118 }
119 };
120
TEST_F(WidgetSelectorTest,signleMatcherWithoutLocatorAndExistsNoTarget)121 TEST_F(WidgetSelectorTest, signleMatcherWithoutLocatorAndExistsNoTarget)
122 {
123 auto selector = WidgetSelector();
124 auto matcher = WidgetAttrMatcher(ATTR_TEXT, "WLJ", EQ);
125 selector.AddMatcher(matcher);
126
127 vector<reference_wrapper<const Widget>> receiver;
128 selector.Select(tree_, receiver);
129
130 ASSERT_EQ(0, receiver.size());
131 }
132
TEST_F(WidgetSelectorTest,signleMatcherWithoutLocatorAndExistsSingleTarget)133 TEST_F(WidgetSelectorTest, signleMatcherWithoutLocatorAndExistsSingleTarget)
134 {
135 auto selector = WidgetSelector();
136 auto matcher = WidgetAttrMatcher(ATTR_TEXT, "wyz", EQ);
137 selector.AddMatcher(matcher);
138
139 vector<reference_wrapper<const Widget>> receiver;
140 selector.Select(tree_, receiver);
141
142 ASSERT_EQ(1, receiver.size());
143 // check the result widget
144 ASSERT_EQ("id5", receiver.at(0).get().GetAttr("resource-id", ""));
145 }
146
TEST_F(WidgetSelectorTest,multiMatcherWithoutLocatorAndExistsSingleTarget)147 TEST_F(WidgetSelectorTest, multiMatcherWithoutLocatorAndExistsSingleTarget)
148 {
149 auto selector = WidgetSelector();
150 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "Transfer", CONTAINS);
151 auto matcher1 = WidgetAttrMatcher("resource-id", "8", CONTAINS);
152 selector.AddMatcher(matcher0);
153 selector.AddMatcher(matcher1);
154
155 vector<reference_wrapper<const Widget>> receiver;
156 selector.Select(tree_, receiver);
157
158 ASSERT_EQ(1, receiver.size());
159 // check the result widget
160 ASSERT_EQ("id8", receiver.at(0).get().GetAttr("resource-id", ""));
161 }
162
TEST_F(WidgetSelectorTest,multiMatcherWithoutLocatorAndExistMultiTargets)163 TEST_F(WidgetSelectorTest, multiMatcherWithoutLocatorAndExistMultiTargets)
164 {
165 auto selector = WidgetSelector();
166 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "Transfer", CONTAINS);
167 selector.AddMatcher(matcher0);
168
169 vector<reference_wrapper<const Widget>> receiver;
170 selector.Select(tree_, receiver);
171
172 ASSERT_EQ(2, receiver.size());
173 // check the result widgets and the order, should arranges in DFS order
174 ASSERT_EQ("id8", receiver.at(0).get().GetAttr("resource-id", ""));
175 ASSERT_EQ("id10", receiver.at(1).get().GetAttr("resource-id", ""));
176 }
177
TEST_F(WidgetSelectorTest,singleFrontLocatorAndExistsNoTarget)178 TEST_F(WidgetSelectorTest, singleFrontLocatorAndExistsNoTarget)
179 {
180 ApiCallErr err(NO_ERROR);
181 auto selector = WidgetSelector();
182 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "Transfer", CONTAINS);
183 selector.AddMatcher(matcher0);
184
185 auto frontMatcher = WidgetAttrMatcher("resource-id", "id10", EQ);
186 auto frontLocator = WidgetSelector();
187 frontLocator.AddMatcher(frontMatcher);
188 selector.AddFrontLocator(frontLocator, err);
189 ASSERT_EQ(NO_ERROR, err.code_);
190
191 vector<reference_wrapper<const Widget>> receiver;
192 selector.Select(tree_, receiver);
193 // "id10" is not in front of "*Transfer*", so no widget should be selected
194 ASSERT_EQ(0, receiver.size());
195 }
196
TEST_F(WidgetSelectorTest,singleFrontLocatorAndExistsSingleTarget)197 TEST_F(WidgetSelectorTest, singleFrontLocatorAndExistsSingleTarget)
198 {
199 ApiCallErr err(NO_ERROR);
200 auto selector = WidgetSelector();
201 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "Transfer", CONTAINS);
202 selector.AddMatcher(matcher0);
203
204 auto frontMatcher = WidgetAttrMatcher("resource-id", "id9", EQ);
205 auto frontLocator = WidgetSelector();
206 frontLocator.AddMatcher(frontMatcher);
207 selector.AddFrontLocator(frontLocator, err);
208 ASSERT_EQ(NO_ERROR, err.code_);
209
210 vector<reference_wrapper<const Widget>> receiver;
211 selector.Select(tree_, receiver);
212 // "id9" is not in front of "Transfer files" but not "Transfer photos", so one widget should be selected
213 ASSERT_EQ(1, receiver.size());
214 ASSERT_EQ("Transfer files", receiver.at(0).get().GetAttr(ATTR_TEXT, ""));
215 }
216
TEST_F(WidgetSelectorTest,singleFrontLocatorAndExistMultiTargets)217 TEST_F(WidgetSelectorTest, singleFrontLocatorAndExistMultiTargets)
218 {
219 ApiCallErr err(NO_ERROR);
220 auto selector = WidgetSelector();
221 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "Transfer", CONTAINS);
222 selector.AddMatcher(matcher0);
223
224 auto frontMatcher = WidgetAttrMatcher("resource-id", "id7", EQ);
225 auto frontLocator = WidgetSelector();
226 frontLocator.AddMatcher(frontMatcher);
227 selector.AddFrontLocator(frontLocator, err);
228 ASSERT_EQ(NO_ERROR, err.code_);
229
230 vector<reference_wrapper<const Widget>> receiver;
231 selector.Select(tree_, receiver);
232 // "id9" is not in front of "Transfer files" and "Transfer photos", so two widgets should be selected
233 ASSERT_EQ(2, receiver.size());
234 // check the result widgets and the order, should arranges in DFS order
235 ASSERT_EQ("Transfer photos", receiver.at(0).get().GetAttr(ATTR_TEXT, ""));
236 ASSERT_EQ("Transfer files", receiver.at(1).get().GetAttr(ATTR_TEXT, ""));
237 }
238
TEST_F(WidgetSelectorTest,multiFrontLocatorAndExistsNoTarget)239 TEST_F(WidgetSelectorTest, multiFrontLocatorAndExistsNoTarget)
240 {
241 ApiCallErr err(NO_ERROR);
242 auto selector = WidgetSelector();
243 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "Transfer", CONTAINS);
244 selector.AddMatcher(matcher0);
245
246 auto frontMatcher0 = WidgetAttrMatcher("resource-id", "id1", EQ);
247 auto frontLocator0 = WidgetSelector();
248 frontLocator0.AddMatcher(frontMatcher0);
249 selector.AddFrontLocator(frontLocator0, err);
250 ASSERT_EQ(NO_ERROR, err.code_);
251 auto frontMatcher1 = WidgetAttrMatcher("resource-id", "id10", EQ);
252 auto frontLocator1 = WidgetSelector();
253 frontLocator1.AddMatcher(frontMatcher1);
254 selector.AddFrontLocator(frontLocator1, err);
255 ASSERT_EQ(NO_ERROR, err.code_);
256
257 vector<reference_wrapper<const Widget>> receiver;
258 selector.Select(tree_, receiver);
259 // "id1" is in front of "*Transfer*" but "id10" isn't, so no widget should be selected
260 ASSERT_EQ(0, receiver.size());
261 }
262
TEST_F(WidgetSelectorTest,multiFrontLocatorAndExistsSingleTarget)263 TEST_F(WidgetSelectorTest, multiFrontLocatorAndExistsSingleTarget)
264 {
265 ApiCallErr err(NO_ERROR);
266 auto selector = WidgetSelector();
267 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "Transfer", CONTAINS);
268 selector.AddMatcher(matcher0);
269
270 auto frontMatcher0 = WidgetAttrMatcher("resource-id", "id8", EQ);
271 auto frontLocator0 = WidgetSelector();
272 frontLocator0.AddMatcher(frontMatcher0);
273 selector.AddFrontLocator(frontLocator0, err);
274 ASSERT_EQ(NO_ERROR, err.code_);
275 auto frontMatcher1 = WidgetAttrMatcher("resource-id", "id9", EQ);
276 auto frontLocator1 = WidgetSelector();
277 frontLocator1.AddMatcher(frontMatcher1);
278 selector.AddFrontLocator(frontLocator1, err);
279 ASSERT_EQ(NO_ERROR, err.code_);
280
281 vector<reference_wrapper<const Widget>> receiver;
282 selector.Select(tree_, receiver);
283 // both "id8" and "id9" are in front of "Transfer files" but not "Transfer photos", so one widget should be selected
284 ASSERT_EQ(1, receiver.size());
285 ASSERT_EQ("Transfer files", receiver.at(0).get().GetAttr(ATTR_TEXT, ""));
286 }
287
TEST_F(WidgetSelectorTest,multiFrontLocatorAndExistMultiTargets)288 TEST_F(WidgetSelectorTest, multiFrontLocatorAndExistMultiTargets)
289 {
290 ApiCallErr err(NO_ERROR);
291 auto selector = WidgetSelector();
292 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "Transfer", CONTAINS);
293 selector.AddMatcher(matcher0);
294
295 auto frontMatcher0 = WidgetAttrMatcher("resource-id", "id6", EQ);
296 auto frontLocator0 = WidgetSelector();
297 frontLocator0.AddMatcher(frontMatcher0);
298 selector.AddFrontLocator(frontLocator0, err);
299 ASSERT_EQ(NO_ERROR, err.code_);
300 auto frontMatcher1 = WidgetAttrMatcher("resource-id", "id7", EQ);
301 auto frontLocator1 = WidgetSelector();
302 frontLocator1.AddMatcher(frontMatcher1);
303 selector.AddFrontLocator(frontLocator1, err);
304 ASSERT_EQ(NO_ERROR, err.code_);
305
306 vector<reference_wrapper<const Widget>> receiver;
307 selector.Select(tree_, receiver);
308
309 // both "id8" and "id9" are in front of "Transfer files" but not "*Transfer*", two widgets should be selected
310 ASSERT_EQ(2, receiver.size());
311 // check the result widgets and the order, should arranges in DFS order
312 ASSERT_EQ("Transfer photos", receiver.at(0).get().GetAttr(ATTR_TEXT, ""));
313 ASSERT_EQ("Transfer files", receiver.at(1).get().GetAttr(ATTR_TEXT, ""));
314 }
315
TEST_F(WidgetSelectorTest,singleRearLocatorAndExistsNoTarget)316 TEST_F(WidgetSelectorTest, singleRearLocatorAndExistsNoTarget)
317 {
318 ApiCallErr err(NO_ERROR);
319 auto selector = WidgetSelector();
320 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "Transfer", CONTAINS);
321 selector.AddMatcher(matcher0);
322
323 auto rearMatcher = WidgetAttrMatcher("resource-id", "id7", EQ);
324 auto rearLocator = WidgetSelector();
325 rearLocator.AddMatcher(rearMatcher);
326 selector.AddRearLocator(rearLocator, err);
327 ASSERT_EQ(NO_ERROR, err.code_);
328
329 vector<reference_wrapper<const Widget>> receiver;
330 selector.Select(tree_, receiver);
331 // "id10" is not in rear of "*Transfer*", so no widget should be selected
332 ASSERT_EQ(0, receiver.size());
333 }
334
TEST_F(WidgetSelectorTest,singleRearLocatorAndExistsSingleTarget)335 TEST_F(WidgetSelectorTest, singleRearLocatorAndExistsSingleTarget)
336 {
337 ApiCallErr err(NO_ERROR);
338 auto selector = WidgetSelector();
339 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "Transfer", CONTAINS);
340 selector.AddMatcher(matcher0);
341
342 auto rearMatcher = WidgetAttrMatcher("resource-id", "id9", EQ);
343 auto rearLocator = WidgetSelector();
344 rearLocator.AddMatcher(rearMatcher);
345 selector.AddRearLocator(rearLocator, err);
346 ASSERT_EQ(NO_ERROR, err.code_);
347
348 vector<reference_wrapper<const Widget>> receiver;
349 selector.Select(tree_, receiver);
350 // "id9" is not in rear of "Transfer photos" but not "Transfer files", so one widget should be selected
351 ASSERT_EQ(1, receiver.size());
352 ASSERT_EQ("Transfer photos", receiver.at(0).get().GetAttr(ATTR_TEXT, ""));
353 }
354
TEST_F(WidgetSelectorTest,singleRearLocatorAndExistMultiTargets)355 TEST_F(WidgetSelectorTest, singleRearLocatorAndExistMultiTargets)
356 {
357 ApiCallErr err(NO_ERROR);
358 auto selector = WidgetSelector();
359 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "s", CONTAINS);
360 selector.AddMatcher(matcher0);
361
362 auto rearMatcher = WidgetAttrMatcher("resource-id", "id10", EQ);
363 auto rearLocator = WidgetSelector();
364 rearLocator.AddMatcher(rearMatcher);
365 selector.AddRearLocator(rearLocator, err);
366 ASSERT_EQ(NO_ERROR, err.code_);
367
368 vector<reference_wrapper<const Widget>> receiver;
369 selector.Select(tree_, receiver);
370 // "id10" is rear in front of "Use USB to" and "Transfer photos", so two widgets should be selected
371 ASSERT_EQ(2, receiver.size());
372 // check the result widgets and the order, should arranges in DFS order
373 ASSERT_EQ("Use USB to", receiver.at(0).get().GetAttr(ATTR_TEXT, ""));
374 ASSERT_EQ("Transfer photos", receiver.at(1).get().GetAttr(ATTR_TEXT, ""));
375 }
376
TEST_F(WidgetSelectorTest,frontAndRearLocatorsAndExistsNoTarget)377 TEST_F(WidgetSelectorTest, frontAndRearLocatorsAndExistsNoTarget)
378 {
379 ApiCallErr err(NO_ERROR);
380 auto selector = WidgetSelector();
381 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "Transfer", CONTAINS);
382 selector.AddMatcher(matcher0);
383
384 auto frontMatcher = WidgetAttrMatcher("resource-id", "id8", EQ);
385 auto frontLocator = WidgetSelector();
386 frontLocator.AddMatcher(frontMatcher);
387 selector.AddFrontLocator(frontLocator, err);
388 ASSERT_EQ(NO_ERROR, err.code_);
389 auto rearMatcher = WidgetAttrMatcher("resource-id", "id10", EQ);
390 auto rearLocator = WidgetSelector();
391 rearLocator.AddMatcher(rearMatcher);
392 selector.AddRearLocator(rearLocator, err);
393 ASSERT_EQ(NO_ERROR, err.code_);
394
395 vector<reference_wrapper<const Widget>> receiver;
396 selector.Select(tree_, receiver);
397 // no "*Transfer*" is between "id8" and "id10", so no widget should be selected
398 ASSERT_EQ(0, receiver.size());
399 }
400
TEST_F(WidgetSelectorTest,frontAndRearLocatorsAndExistsSingleTarget)401 TEST_F(WidgetSelectorTest, frontAndRearLocatorsAndExistsSingleTarget)
402 {
403 ApiCallErr err(NO_ERROR);
404 auto selector = WidgetSelector();
405 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "Transfer", CONTAINS);
406 selector.AddMatcher(matcher0);
407
408 auto frontMatcher = WidgetAttrMatcher("resource-id", "id7", EQ);
409 auto frontLocator = WidgetSelector();
410 frontLocator.AddMatcher(frontMatcher);
411 selector.AddFrontLocator(frontLocator, err);
412 ASSERT_EQ(NO_ERROR, err.code_);
413 auto rearMatcher = WidgetAttrMatcher("resource-id", "id10", EQ);
414 auto rearLocator = WidgetSelector();
415 rearLocator.AddMatcher(rearMatcher);
416 selector.AddRearLocator(rearLocator, err);
417 ASSERT_EQ(NO_ERROR, err.code_);
418
419 vector<reference_wrapper<const Widget>> receiver;
420 selector.Select(tree_, receiver);
421
422 // only "Transfer photos" is between "id7" and "id10", one widget should be selected
423 ASSERT_EQ(1, receiver.size());
424 ASSERT_EQ("Transfer photos", receiver.at(0).get().GetAttr(ATTR_TEXT, ""));
425 }
426
TEST_F(WidgetSelectorTest,frontAndRearLocatorsAndExistMultiTargets)427 TEST_F(WidgetSelectorTest, frontAndRearLocatorsAndExistMultiTargets)
428 {
429 ApiCallErr err(NO_ERROR);
430 auto selector = WidgetSelector();
431 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "s", CONTAINS);
432 selector.AddMatcher(matcher0);
433
434 auto frontMatcher = WidgetAttrMatcher("resource-id", "id3", EQ);
435 auto frontLocator = WidgetSelector();
436 frontLocator.AddMatcher(frontMatcher);
437 selector.AddFrontLocator(frontLocator, err);
438 ASSERT_EQ(NO_ERROR, err.code_);
439 auto rearMatcher = WidgetAttrMatcher("resource-id", "id9", EQ);
440 auto rearLocator = WidgetSelector();
441 rearLocator.AddMatcher(rearMatcher);
442 selector.AddRearLocator(rearLocator, err);
443 ASSERT_EQ(NO_ERROR, err.code_);
444
445 vector<reference_wrapper<const Widget>> receiver;
446 selector.Select(tree_, receiver);
447
448 // both of "Use USB to" and "Transfer photos" are between "id3" and "id9", so two widgets should be selected
449 ASSERT_EQ(2, receiver.size());
450 // check the result widgets and the order, should arranges in DFS order
451 ASSERT_EQ("Use USB to", receiver.at(0).get().GetAttr(ATTR_TEXT, ""));
452 ASSERT_EQ("Transfer photos", receiver.at(1).get().GetAttr(ATTR_TEXT, ""));
453 }
454
TEST_F(WidgetSelectorTest,nestingUsageDetect)455 TEST_F(WidgetSelectorTest, nestingUsageDetect)
456 {
457 ApiCallErr err(NO_ERROR);
458 auto selector = WidgetSelector();
459 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "s", CONTAINS);
460 selector.AddMatcher(matcher0);
461
462 auto frontMatcher = WidgetAttrMatcher("resource-id", "id3", EQ);
463 auto frontLocator = WidgetSelector();
464 frontLocator.AddMatcher(frontMatcher);
465 ASSERT_EQ(NO_ERROR, err.code_);
466 frontLocator.AddRearLocator(frontLocator, err);
467 ASSERT_EQ(NO_ERROR, err.code_);
468
469 // make the front locator nesting
470 selector.AddFrontLocator(frontLocator, err);
471 ASSERT_EQ(ERR_INVALID_INPUT, err.code_);
472 }
473
TEST_F(WidgetSelectorTest,selectorDescription)474 TEST_F(WidgetSelectorTest, selectorDescription)
475 {
476 ApiCallErr err(NO_ERROR);
477 auto selector = WidgetSelector();
478 auto matcher0 = WidgetAttrMatcher(ATTR_TEXT, "s", CONTAINS);
479 selector.AddMatcher(matcher0);
480
481 auto frontMatcher = WidgetAttrMatcher("resource-id", "id3", EQ);
482 auto frontLocator = WidgetSelector();
483 frontLocator.AddMatcher(frontMatcher);
484 selector.AddFrontLocator(frontLocator, err);
485 ASSERT_EQ(NO_ERROR, err.code_);
486 auto rearMatcher = WidgetAttrMatcher("resource-id", "id9", EQ);
487 auto rearLocator = WidgetSelector();
488 rearLocator.AddMatcher(rearMatcher);
489 selector.AddRearLocator(rearLocator, err);
490 ASSERT_EQ(NO_ERROR, err.code_);
491
492 auto description = selector.Describe();
493 auto pos0 = description.find("selfMatcher");
494 auto pos1 = description.find(matcher0.Describe());
495 auto pos2 = description.find("frontMatcher");
496 auto pos3 = description.find(frontMatcher.Describe());
497 auto pos4 = description.find("rearMatcher");
498 auto pos5 = description.find(rearMatcher.Describe());
499 ASSERT_TRUE(pos0 != string::npos && pos0 > 0);
500 ASSERT_TRUE(pos1 != string::npos && pos1 > pos0);
501 ASSERT_TRUE(pos2 != string::npos && pos2 > pos1);
502 ASSERT_TRUE(pos3 != string::npos && pos3 > pos2);
503 ASSERT_TRUE(pos4 != string::npos && pos4 > pos3);
504 ASSERT_TRUE(pos5 != string::npos && pos5 > pos4);
505 }