• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "widget_selector.h"
17 
18 namespace OHOS::uitest {
19     using namespace std;
20     using namespace nlohmann;
21 
22     static constexpr auto NEST_USAGE_ERROR = "Nesting By usage like 'BY.before(BY.after(...))' is not supported";
23 
AddMatcher(const WidgetAttrMatcher & matcher)24     void WidgetSelector::AddMatcher(const WidgetAttrMatcher &matcher)
25     {
26         selfMatchers_.emplace_back(matcher);
27     }
28 
AddFrontLocator(const WidgetSelector & selector,ApiCallErr & error)29     void WidgetSelector::AddFrontLocator(const WidgetSelector &selector, ApiCallErr &error)
30     {
31         if (!selector.rearLocators_.empty() || !selector.frontLocators_.empty()) {
32             error = ApiCallErr(ERR_INVALID_INPUT, NEST_USAGE_ERROR);
33             return;
34         }
35         frontLocators_.emplace_back(selector);
36     }
37 
AddRearLocator(const WidgetSelector & selector,ApiCallErr & error)38     void WidgetSelector::AddRearLocator(const WidgetSelector &selector, ApiCallErr &error)
39     {
40         if (!selector.rearLocators_.empty() || !selector.frontLocators_.empty()) {
41             error = ApiCallErr(ERR_INVALID_INPUT, NEST_USAGE_ERROR);
42             return;
43         }
44         rearLocators_.emplace_back(selector);
45     }
46 
CheckHasLocator(const WidgetTree & tree,const Widget & widget,const WidgetMatcher & matcher,bool front)47     static bool CheckHasLocator(const WidgetTree &tree, const Widget &widget, const WidgetMatcher &matcher, bool front)
48     {
49         vector<reference_wrapper<const Widget>> locators;
50         locators.clear();
51         MatchedWidgetCollector collector(matcher, locators);
52         if (front) {
53             tree.DfsTraverseFronts(collector, widget);
54         } else {
55             tree.DfsTraverseRears(collector, widget);
56         }
57         return !locators.empty();
58     }
59 
Select(const WidgetTree & tree,vector<std::reference_wrapper<const Widget>> & results) const60     void WidgetSelector::Select(const WidgetTree &tree, vector<std::reference_wrapper<const Widget>> &results) const
61     {
62         auto allSelfMatcher = All(selfMatchers_);
63         MatchedWidgetCollector selfCollector(allSelfMatcher, results);
64         tree.DfsTraverse(selfCollector);
65         if (results.empty()) {
66             LOG_W("Self node not found matching:%{public}s", allSelfMatcher.Describe().c_str());
67             return;
68         }
69 
70         vector<uint32_t> discardWidgetOffsets;
71         // check locators at each direction and filter out unsatisfied widgets
72         for (size_t idx = 0; idx < INDEX_TWO; idx++) {
73             discardWidgetOffsets.clear();
74             uint32_t offset = 0;
75             for (auto &result:results) {
76                 const bool front = idx == 0;
77                 const auto &locators = front ? frontLocators_ : rearLocators_;
78                 for (auto &locator:locators) {
79                     auto locatorMatcher = All(locator.selfMatchers_);
80                     if (!CheckHasLocator(tree, result.get(), locatorMatcher, front)) {
81                         // this means not all the required front locator are found, exclude this candidate
82                         discardWidgetOffsets.emplace_back(offset);
83                         break;
84                     }
85                 }
86                 offset++;
87             }
88             // remove unsatisfied candidates, remove from last to first
89             reverse(discardWidgetOffsets.begin(), discardWidgetOffsets.end());
90             for (auto &off:discardWidgetOffsets) {
91                 results.erase(results.begin() + off);
92             }
93             if (results.empty()) {
94                 break;
95             }
96         }
97     }
98 
Describe() const99     string WidgetSelector::Describe() const
100     {
101         stringstream ss;
102         auto allSelfMatcher = All(selfMatchers_);
103         ss << "{";
104         ss << "selfMatcher=[" << allSelfMatcher.Describe() << "]";
105         if (!frontLocators_.empty()) {
106             ss << "; frontMatcher=";
107             for (auto &locator:frontLocators_) {
108                 ss << "[" << locator.Describe() << "]";
109             }
110         }
111         if (!rearLocators_.empty()) {
112             ss << "; rearMatcher=";
113             for (auto &locator:rearLocators_) {
114                 ss << "[" << locator.Describe() << "]";
115             }
116         }
117         ss << "}";
118         return ss.str();
119     }
120 }