1 /*
2  * Copyright (c) 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 #include "json.hpp"
17 #include "ui_model.h"
18 
19 namespace OHOS::uitest {
20     using namespace std;
21     using namespace nlohmann;
22 
23     struct DumperCache {
24         std::map<std::string, int> visitWidgetMap_;
25         std::map<std::string, int> widgetCountMap_;
26         std::set<std::string> visibleWidgetHies_;
27     };
28 
GetMiddleStr(string_view str, size_t &index, string_view startStr, string_view endStr)29     static string_view GetMiddleStr(string_view str, size_t &index, string_view startStr, string_view endStr)
30     {
31         size_t ori = index;
32         auto begin = str.find(startStr, index);
33         if (begin != string::npos) {
34             index = begin + startStr.size();
35             auto end = str.find(endStr, index);
36             if (end != string::npos) {
37                 string_view result = str.substr(index, end - index);
38                 index = end;
39                 return result;
40             }
41         }
42         index = ori;
43         return "";
44     }
45 
HasVisibleChild(const std::set<std::string> &visibleWidgetHies, const string &hie)46     static bool HasVisibleChild(const std::set<std::string> &visibleWidgetHies, const string &hie)
47     {
48         for (auto visibleHie : visibleWidgetHies) {
49             if (visibleHie.find(hie) != string::npos) {
50                 return true;
51             }
52         }
53         return false;
54     }
55 
DFSMarshalWidget(std::vector<Widget> &allWidget, int index, nlohmann::json &dom, const DumperCache &cache)56     static void DFSMarshalWidget(std::vector<Widget> &allWidget, int index, nlohmann::json &dom,
57         const DumperCache &cache)
58     {
59         auto attrData = json();
60         allWidget.at(index).WrapperWidgetToJson(attrData);
61         auto childrenData = json::array();
62         int childIndex = 0;
63         int childCount = 0;
64         int childVisit = 0;
65         auto hierarchy = allWidget.at(index).GetHierarchy();
66         if (cache.widgetCountMap_.find(hierarchy) != cache.widgetCountMap_.cend()) {
67             childCount = cache.widgetCountMap_.at(hierarchy);
68         }
69         while (childVisit < childCount) {
70             auto tempChildHierarchy = WidgetHierarchyBuilder::GetChildHierarchy(hierarchy, childIndex);
71             ++childIndex;
72             if (cache.visitWidgetMap_.find(tempChildHierarchy) == cache.visitWidgetMap_.cend()) {
73                 continue;
74             }
75             auto childWidIndex = cache.visitWidgetMap_.at(tempChildHierarchy);
76             if (!allWidget.at(childWidIndex).IsVisible()) {
77                 if (!HasVisibleChild(cache.visibleWidgetHies_, tempChildHierarchy)) {
78                     ++childVisit;
79                     continue;
80                 }
81             }
82             auto childData = json();
83             DFSMarshalWidget(allWidget, childWidIndex, childData, cache);
84             childrenData.emplace_back(childData);
85             ++childVisit;
86         }
87         dom["attributes"] = attrData;
88         dom["children"] = childrenData;
89     }
90 
AddExtraAttrs(nlohmann::json &root, const map<int32_t, string_view> &elementTrees, size_t index)91     void DumpHandler::AddExtraAttrs(nlohmann::json &root, const map<int32_t, string_view> &elementTrees, size_t index)
92     {
93         auto windowIdValue = root["attributes"]["hostWindowId"].dump();
94         auto windowId = atoi(windowIdValue.substr(1, windowIdValue.size() - 2).c_str());
95         auto find = elementTrees.find(windowId);
96         auto elementTree = (find != elementTrees.end()) ? find->second : "";
97         string_view nodeEndStr = "|->";
98         auto accessibilityIdInfo = root["attributes"]["accessibilityId"].dump();
99         auto accessibilityId = accessibilityIdInfo.substr(1, accessibilityIdInfo.size() - 2);
100         string_view accessibilityIdStr = "AccessibilityId: " + accessibilityId;
101         string_view nodeAttrStr = GetMiddleStr(elementTree, index, accessibilityIdStr, nodeEndStr);
102         auto extraAttrs = json();
103         size_t nodeAttrTraverlIndex = 0;
104         auto backgroundColor = GetMiddleStr(nodeAttrStr, nodeAttrTraverlIndex, "BackgroundColor: ", "\n");
105         auto content = GetMiddleStr(nodeAttrStr, nodeAttrTraverlIndex, "Content: ", "\n");
106         auto fontColor = GetMiddleStr(nodeAttrStr, nodeAttrTraverlIndex, "FontColor: ", "\n");
107         auto fontSize = GetMiddleStr(nodeAttrStr, nodeAttrTraverlIndex, "FontSize: ", "\n");
108         if (!backgroundColor.empty()) {
109             extraAttrs["BackgroundColor"] = backgroundColor;
110         }
111         if (!content.empty()) {
112             extraAttrs["Content"] = move(content);
113         }
114         if (!fontColor.empty()) {
115             extraAttrs["FontColor"] = move(fontColor);
116         }
117         if (!fontSize.empty()) {
118             extraAttrs["FontSize"] = move(fontSize);
119         }
120         if (!extraAttrs.empty()) {
121             root["extraAttrs"] = extraAttrs;
122         }
123         auto &childrenData = root["children"];
124         auto childCount = childrenData.size();
125         for (size_t idx = 0; idx < childCount; idx++) {
126             auto &child = childrenData.at(idx);
127             AddExtraAttrs(child, elementTrees, index);
128         }
129     }
130 
DumpWindowInfoToJson(vector<Widget> &allWidget, nlohmann::json &root)131     void DumpHandler::DumpWindowInfoToJson(vector<Widget> &allWidget, nlohmann::json &root)
132     {
133         DumperCache cache;
134         for (size_t i = 0; i < allWidget.size(); ++i) {
135             const Widget &wid = allWidget.at(i);
136             std::string hie = wid.GetHierarchy();
137             cache.visitWidgetMap_.emplace(hie, i);
138             std::string parentHie = WidgetHierarchyBuilder::GetParentWidgetHierarchy(hie);
139             if (cache.widgetCountMap_.find(parentHie) == cache.widgetCountMap_.cend()) {
140                 cache.widgetCountMap_[parentHie] = 1;
141             } else {
142                 cache.widgetCountMap_[parentHie] = cache.widgetCountMap_[parentHie] + 1;
143             }
144             if (wid.IsVisible()) {
145                 cache.visibleWidgetHies_.insert(hie);
146             }
147         }
148         DFSMarshalWidget(allWidget, 0, root, cache);
149     }
150 } // namespace OHOS::uitest