• 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.rearLocators_.empty()) {
32             error = ApiCallErr(USAGE_ERROR, 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.rearLocators_.empty()) {
41             error = ApiCallErr(USAGE_ERROR, 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         uint32_t offset = 0;
72         // check locators at each direction and filter out unsatisfied widgets
73         for (size_t idx = 0; idx < INDEX_TWO; idx++) {
74             discardWidgetOffsets.clear();
75             offset = 0;
76             for (auto &result:results) {
77                 const bool front = idx == 0;
78                 const auto &locators = front ? frontLocators_ : rearLocators_;
79                 for (auto &locator:locators) {
80                     auto locatorMatcher = All(locator.selfMatchers_);
81                     if (!CheckHasLocator(tree, result.get(), locatorMatcher, front)) {
82                         // this means not all the required front locator are found, exclude this candidate
83                         discardWidgetOffsets.emplace_back(offset);
84                         break;
85                     }
86                 }
87                 offset++;
88             }
89             // remove unsatisfied candidates, remove from last to first
90             reverse(discardWidgetOffsets.begin(), discardWidgetOffsets.end());
91             for (auto &off:discardWidgetOffsets) {
92                 results.erase(results.begin() + off);
93             }
94             if (results.empty()) {
95                 break;
96             }
97         }
98     }
99 
Describe() const100     string WidgetSelector::Describe() const
101     {
102         stringstream ss;
103         auto allSelfMatcher = All(selfMatchers_);
104         ss << "{";
105         ss << "selfMatcher=[" << allSelfMatcher.Describe() << "]";
106         if (!frontLocators_.empty()) {
107             ss << "; frontMatcher=";
108             for (auto &locator:frontLocators_) {
109                 ss << "[" << locator.Describe() << "]";
110             }
111         }
112         if (!rearLocators_.empty()) {
113             ss << "; rearMatcher=";
114             for (auto &locator:rearLocators_) {
115                 ss << "[" << locator.Describe() << "]";
116             }
117         }
118         ss << "}";
119         return ss.str();
120     }
121 
~WidgetSelector()122     WidgetSelector::~WidgetSelector()
123     {
124     }
125 
WriteIntoParcel(json & data) const126     void WidgetSelector::WriteIntoParcel(json &data) const
127     {
128         json selfMatcherList = json::array();
129         for (auto &matcher:selfMatchers_) {
130             json matcherSerialized;
131             matcher.WriteIntoParcel(matcherSerialized);
132             selfMatcherList.push_back(matcherSerialized);
133         }
134         data["self"] = selfMatcherList;
135 
136         json frontLocatorJsonList = json::array();
137         for (auto &locator:frontLocators_) {
138             json matcherSerialized;
139             locator.WriteIntoParcel(matcherSerialized);
140             frontLocatorJsonList.push_back(matcherSerialized);
141         }
142         data["front"] = frontLocatorJsonList;
143 
144         json rearLocatorJsonList = json::array();
145         for (auto &locator:rearLocators_) {
146             json matcherSerialized;
147             locator.WriteIntoParcel(matcherSerialized);
148             rearLocatorJsonList.push_back(matcherSerialized);
149         }
150         data["rear"] = rearLocatorJsonList;
151     }
152 
ReadFromParcel(const json & data)153     void WidgetSelector::ReadFromParcel(const json &data)
154     {
155         json selfMatcherJsonList = data["self"];
156         for (auto &selfMatcherJson:selfMatcherJsonList) {
157             auto matcher = WidgetAttrMatcher("", "", EQ);
158             matcher.ReadFromParcel(selfMatcherJson);
159             selfMatchers_.emplace_back(matcher);
160         }
161 
162         json frontLocatorJsonList = data["front"];
163         for (auto &frontLocatorJson:frontLocatorJsonList) {
164             auto locator = WidgetSelector();
165             locator.ReadFromParcel(frontLocatorJson);
166             frontLocators_.emplace_back(locator);
167         }
168 
169         json rearLocatorJsonList = data["rear"];
170         for (auto &rearLocatorJson:rearLocatorJsonList) {
171             auto locator = WidgetSelector();
172             locator.ReadFromParcel(rearLocatorJson);
173             rearLocators_.emplace_back(locator);
174         }
175     }
176 }