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 }