1 /* 2 * Copyright (c) 2022-2023 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 #ifndef MOCK_ELEMENT_NODE_ITERATOR_H 17 #define MOCK_ELEMENT_NODE_ITERATOR_H 18 19 #include <iostream> 20 #include "element_node_iterator.h" 21 #include "nlohmann/json.hpp" 22 23 using json = nlohmann::json; 24 25 namespace OHOS::uitest { 26 27 struct MockAccessibilityElementInfo { 28 std::string accessibilityId = "-1"; 29 std::string inspectorKey = ""; 30 std::string content = ""; 31 std::string componentType = ""; 32 std::string bundleName = ""; 33 std::string hierarchy = ""; 34 bool enabled = true; 35 bool focused = true; 36 bool selected = true; 37 bool checkable = true; 38 bool checked = true; 39 std::string windowId = "12"; 40 Rect rectInScreen = Rect{0, 0, 0, 0}; 41 int parentIndex = -1; 42 std::vector<int> childIndexVec; 43 }; 44 StringSplit(const string & str,const char split,std::vector<string> & res)45 static void StringSplit(const string &str, const char split, std::vector<string> &res) 46 { 47 if (str == "") { 48 return; 49 } 50 string strs = str + split; 51 size_t pos = strs.find(split); 52 53 while (pos != strs.npos) { 54 std::string temp = strs.substr(0, pos); 55 res.emplace_back(temp); 56 strs = strs.substr(pos + 1, strs.size()); 57 pos = strs.find(split); 58 } 59 } 60 WrapperJsonToElement(const json & obj)61 static MockAccessibilityElementInfo WrapperJsonToElement(const json &obj) 62 { 63 MockAccessibilityElementInfo eleRoot; 64 if (obj.find("accessibilityId") != obj.end()) { 65 eleRoot.accessibilityId = obj["accessibilityId"]; 66 } 67 if (obj.find("inspectorKey") != obj.end()) { 68 eleRoot.inspectorKey = obj["inspectorKey"]; 69 } 70 if (obj.find("content") != obj.end()) { 71 eleRoot.content = obj["content"]; 72 } 73 if (obj.find("componentType") != obj.end()) { 74 eleRoot.componentType = obj["componentType"]; 75 } 76 if (obj.find("bundleName") != obj.end()) { 77 eleRoot.bundleName = obj["bundleName"]; 78 } 79 if (obj.find("hierarchy") != obj.end()) { 80 eleRoot.hierarchy = obj["hierarchy"]; 81 } 82 if (obj.find("enabled") != obj.end()) { 83 eleRoot.enabled = obj["enabled"] == "true" ? true : false; 84 } 85 if (obj.find("focused") != obj.end()) { 86 eleRoot.focused = obj["focused"] == "true" ? true : false; 87 } 88 if (obj.find("selected") != obj.end()) { 89 eleRoot.selected = obj["selected"] == "true" ? true : false; 90 } 91 if (obj.find("checkable") != obj.end()) { 92 eleRoot.checkable = obj["checkable"] == "true" ? true : false; 93 } 94 if (obj.find("checked") != obj.end()) { 95 eleRoot.checked = obj["checked"] == "true" ? true : false; 96 } 97 if (obj.find("windowId") != obj.end()) { 98 eleRoot.windowId = obj["windowId"]; 99 } 100 if (obj.find("rectInScreen") != obj.end()) { 101 // 12,12,12,12 102 std::string rectStr = obj["rectInScreen"]; 103 std::vector<std::string> rectStrVec; 104 StringSplit(rectStr, ',', rectStrVec); 105 eleRoot.rectInScreen.left_ = std::stoi(rectStrVec[0]); 106 eleRoot.rectInScreen.right_ = std::stoi(rectStrVec[1]); 107 eleRoot.rectInScreen.top_ = std::stoi(rectStrVec[2]); 108 eleRoot.rectInScreen.bottom_ = std::stoi(rectStrVec[3]); 109 } 110 return eleRoot; 111 } 112 DFSVisitJson(std::vector<MockAccessibilityElementInfo> & eles,const json & obj,string hierarchy)113 static void DFSVisitJson(std::vector<MockAccessibilityElementInfo> &eles, const json &obj, string hierarchy) 114 { 115 auto attributes = obj["attributes"]; 116 auto child = obj["children"]; 117 const size_t childCount = child.size(); 118 MockAccessibilityElementInfo info = WrapperJsonToElement(attributes); 119 info.hierarchy = hierarchy; 120 eles.emplace_back(info); 121 for (size_t idx = 0; idx < childCount; idx++) { 122 string childHierachy = WidgetHierarchyBuilder::Build(hierarchy, idx); 123 DFSVisitJson(eles, child.at(idx), childHierachy); 124 } 125 } 126 127 class MockElementNodeIterator : public ElementNodeIterator { 128 public: ConstructIteratorByJson(std::string domStr)129 static std::unique_ptr<MockElementNodeIterator> ConstructIteratorByJson(std::string domStr) 130 { 131 auto data = json::parse(domStr); 132 auto attributes = data["attributes"]; 133 auto child = data["children"]; 134 std::vector<MockAccessibilityElementInfo> eles; 135 DFSVisitJson(eles, data, "ROOT"); 136 for (int index = 0; index < eles.size(); ++index) { 137 std::vector<int> childVec; 138 for (int childIndex = index + 1; childIndex < eles.size(); ++childIndex) { 139 auto childHierarchy = eles[childIndex].hierarchy; 140 auto parentHie = WidgetHierarchyBuilder::GetParentWidgetHierarchy(childHierarchy); 141 if (parentHie == eles[index].hierarchy) { 142 eles[childIndex].parentIndex = index; 143 childVec.emplace_back(childIndex); 144 } 145 } 146 eles[index].childIndexVec = childVec; 147 } 148 return std::make_unique<MockElementNodeIterator>(eles); 149 } MockElementNodeIterator()150 MockElementNodeIterator() : ElementNodeIterator() {} MockElementNodeIterator(const std::vector<MockAccessibilityElementInfo> & elements)151 MockElementNodeIterator(const std::vector<MockAccessibilityElementInfo> &elements) : ElementNodeIterator() 152 { 153 elementInfoLists_ = std::move(elements); 154 } 155 156 ~MockElementNodeIterator() = default; 157 DFSNextWithInTarget(Widget & widget)158 bool DFSNextWithInTarget(Widget &widget) override 159 { 160 if (elementInfoLists_[currentIndex_ + 1].parentIndex == elementInfoLists_[topIndex_].parentIndex) { 161 return false; 162 } 163 if (currentIndex_ >= elementInfoLists_.size() - 1) { 164 return false; 165 } 166 ++currentIndex_; 167 WrapperElement(widget); 168 return true; 169 } 170 DFSNext(Widget & widget,uint32_t windowId)171 bool DFSNext(Widget &widget, uint32_t windowId) override 172 { 173 ++currentIndex_; 174 if (currentIndex_ < elementInfoLists_.size()) { 175 WrapperElement(widget); 176 return true; 177 } 178 return false; 179 } 180 IsVisitFinish()181 bool IsVisitFinish() const override 182 { 183 return elementInfoLists_.size() == elementToParentIndexMap_.size(); 184 } RestoreNodeIndexByAnchor()185 void RestoreNodeIndexByAnchor() override 186 { 187 topIndex_ = currentIndex_; 188 } ResetNodeIndexToAnchor()189 void ResetNodeIndexToAnchor() override 190 { 191 topIndex_ = 0; 192 } ClearDFSNext()193 void ClearDFSNext() override 194 { 195 elementToParentIndexMap_.clear(); 196 elementIndexToHierarch_.clear(); 197 visitAndVisibleIndexSet_.clear(); 198 currentIndex_ = -1; 199 topIndex_ = 0; 200 } 201 RemoveInvisibleWidget()202 void RemoveInvisibleWidget() override 203 { 204 visitAndVisibleIndexSet_.erase(currentIndex_); 205 } 206 207 std::vector<MockAccessibilityElementInfo> elementInfoLists_; 208 209 protected: GenerateNodeHashCode(const MockAccessibilityElementInfo & element)210 std::string GenerateNodeHashCode(const MockAccessibilityElementInfo &element) 211 { 212 std::string winId = element.windowId; 213 std::string accessId = element.accessibilityId; 214 std::stringstream hashcodeStr; 215 hashcodeStr << winId; 216 hashcodeStr << ":"; 217 hashcodeStr << accessId; 218 return hashcodeStr.str(); 219 } WrapperNodeAttrToVec(Widget & widget,const MockAccessibilityElementInfo & element)220 void WrapperNodeAttrToVec(Widget &widget, const MockAccessibilityElementInfo &element) 221 { 222 Rect nodeOriginRect = element.rectInScreen; 223 widget.SetBounds(nodeOriginRect); 224 225 // mock hierarchy 226 widget.SetHierarchy(element.hierarchy); 227 widget.SetAttr(UiAttr::ACCESSIBILITY_ID, element.accessibilityId); 228 widget.SetAttr(UiAttr::ID, element.inspectorKey); 229 widget.SetAttr(UiAttr::BUNDLENAME, element.bundleName); 230 widget.SetAttr(UiAttr::TEXT, element.content); 231 widget.SetAttr(UiAttr::KEY, element.inspectorKey); 232 widget.SetAttr(UiAttr::TYPE, element.componentType); 233 if (element.inspectorKey == "rootdecortag" || element.inspectorKey == "ContainerModalTitleRow") { 234 widget.SetAttr(UiAttr::TYPE, "DecorBar"); 235 } 236 // [left,top][right, bottom] 237 stringstream boundStream; 238 boundStream << "[" << nodeOriginRect.left_ << "," << nodeOriginRect.top_ << "][" << nodeOriginRect.right_ 239 << "," << nodeOriginRect.bottom_ << "]"; 240 widget.SetAttr(UiAttr::ENABLED, element.enabled ? "true" : "false"); 241 widget.SetAttr(UiAttr::FOCUSED, element.focused ? "true" : "false"); 242 widget.SetAttr(UiAttr::SELECTED, element.selected ? "true" : "false"); 243 widget.SetAttr(UiAttr::CLICKABLE, "false"); 244 widget.SetAttr(UiAttr::LONG_CLICKABLE, "false"); 245 widget.SetAttr(UiAttr::SCROLLABLE, "false"); 246 widget.SetAttr(UiAttr::CHECKABLE, element.checkable ? "true" : "false"); 247 widget.SetAttr(UiAttr::CHECKED, element.checked ? "true" : "false"); 248 widget.SetAttr(UiAttr::HOST_WINDOW_ID, element.windowId); 249 widget.SetAttr(UiAttr::ORIGBOUNDS, boundStream.str()); 250 widget.SetAttr(UiAttr::HASHCODE, GenerateNodeHashCode(element)); 251 widget.SetAttr(UiAttr::VISIBLE, 252 nodeOriginRect.GetHeight() > 0 && nodeOriginRect.GetWidth() > 0 ? "true" : "false"); 253 } WrapperElement(Widget & widget)254 void WrapperElement(Widget &widget) override 255 { 256 MockAccessibilityElementInfo element = elementInfoLists_[currentIndex_]; 257 WrapperNodeAttrToVec(widget, element); 258 } 259 }; 260 } // namespace OHOS::uitest 261 #endif