• 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 
WidgetSelector(bool addVisibleMatcher)24     WidgetSelector::WidgetSelector(bool addVisibleMatcher)
25     {
26         if (!addVisibleMatcher) {
27             return;
28         }
29         auto visibleMatcher = WidgetAttrMatcher(ATTR_NAMES[UiAttr::VISIBLE], "true", EQ);
30         selfMatchers_.emplace_back(visibleMatcher);
31     }
32 
AddMatcher(const WidgetAttrMatcher & matcher)33     void WidgetSelector::AddMatcher(const WidgetAttrMatcher &matcher)
34     {
35         selfMatchers_.emplace_back(matcher);
36     }
37 
AddFrontLocator(const WidgetSelector & selector,ApiCallErr & error)38     void WidgetSelector::AddFrontLocator(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         frontLocators_.emplace_back(selector);
45     }
46 
AddRearLocator(const WidgetSelector & selector,ApiCallErr & error)47     void WidgetSelector::AddRearLocator(const WidgetSelector &selector, ApiCallErr &error)
48     {
49         if (!selector.rearLocators_.empty() || !selector.frontLocators_.empty()) {
50             error = ApiCallErr(ERR_INVALID_INPUT, NEST_USAGE_ERROR);
51             return;
52         }
53         rearLocators_.emplace_back(selector);
54     }
55 
AddParentLocator(const WidgetSelector & selector,ApiCallErr & error)56     void WidgetSelector::AddParentLocator(const WidgetSelector &selector, ApiCallErr &error)
57     {
58         if (!selector.rearLocators_.empty() || !selector.frontLocators_.empty()) {
59             error = ApiCallErr(ERR_INVALID_INPUT, NEST_USAGE_ERROR);
60             return;
61         }
62         parentLocators_.emplace_back(selector);
63     }
64 
AddAppLocator(string app)65     void WidgetSelector::AddAppLocator(string app)
66     {
67         appLocator_ = app;
68     }
69 
GetAppLocator() const70     string WidgetSelector::GetAppLocator() const
71     {
72         return appLocator_;
73     }
74 
CheckHasLocator(const WidgetTree & tree,const Widget & widget,const WidgetMatcher & matcher,size_t idx)75     static bool CheckHasLocator(const WidgetTree &tree, const Widget &widget, const WidgetMatcher &matcher, size_t idx)
76     {
77         vector<reference_wrapper<const Widget>> locators;
78         locators.clear();
79         MatchedWidgetCollector collector(matcher, locators);
80         switch (idx) {
81             case INDEX_ZERO:
82                 tree.DfsTraverseFronts(collector, widget);
83                 break;
84             case INDEX_ONE:
85                 tree.DfsTraverseRears(collector, widget);
86                 break;
87             case INDEX_TWO:
88                 tree.DfsTraverseParents(collector, widget);
89                 break;
90             default:
91                 break;
92         }
93         return !locators.empty();
94     }
95 
Select(const WidgetTree & tree,vector<std::reference_wrapper<const Widget>> & results) const96     void WidgetSelector::Select(const WidgetTree &tree, vector<std::reference_wrapper<const Widget>> &results) const
97     {
98         auto allSelfMatcher = All(selfMatchers_);
99         MatchedWidgetCollector selfCollector(allSelfMatcher, results);
100         tree.DfsTraverse(selfCollector);
101         if (results.empty()) {
102             LOG_W("Self node not found matching:%{public}s", allSelfMatcher.Describe().c_str());
103             return;
104         }
105 
106         vector<uint32_t> discardWidgetOffsets;
107         // check locators at each direction and filter out unsatisfied widgets
108         std::vector<std::vector<WidgetSelector>> allLocators = {frontLocators_, rearLocators_, parentLocators_};
109         for (size_t idx = 0; idx < INDEX_THREE; idx++) {
110             discardWidgetOffsets.clear();
111             uint32_t offset = 0;
112             for (auto &result:results) {
113                 const auto &locators = allLocators[idx];
114                 for (auto &locator:locators) {
115                     auto locatorMatcher = All(locator.selfMatchers_);
116                     if (!CheckHasLocator(tree, result.get(), locatorMatcher, idx)) {
117                         // this means not all the required front locator are found, exclude this candidate
118                         discardWidgetOffsets.emplace_back(offset);
119                         break;
120                     }
121                 }
122                 offset++;
123             }
124             // remove unsatisfied candidates, remove from last to first
125             reverse(discardWidgetOffsets.begin(), discardWidgetOffsets.end());
126             for (auto &off:discardWidgetOffsets) {
127                 results.erase(results.begin() + off);
128             }
129             if (results.empty()) {
130                 break;
131             }
132         }
133     }
134 
Describe() const135     string WidgetSelector::Describe() const
136     {
137         stringstream ss;
138         auto allSelfMatcher = All(selfMatchers_);
139         ss << "{";
140         ss << "selfMatcher=[" << allSelfMatcher.Describe() << "]";
141         if (!frontLocators_.empty()) {
142             ss << "; frontMatcher=";
143             for (auto &locator:frontLocators_) {
144                 ss << "[" << locator.Describe() << "]";
145             }
146         }
147         if (!rearLocators_.empty()) {
148             ss << "; rearMatcher=";
149             for (auto &locator:rearLocators_) {
150                 ss << "[" << locator.Describe() << "]";
151             }
152         }
153         ss << "}";
154         return ss.str();
155     }
156 }