• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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