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 }