From 4c3180edfec91c6483b71f070ce1fb1cfb727219 Mon Sep 17 00:00:00 2001 From: piggyguy Date: Sun, 7 Jul 2024 05:57:15 +0800 Subject: [PATCH] add event graph tool Signed-off-by: jiadexiang --- test/tools/event_tree_to_graph/README.md | 11 ++ test/tools/event_tree_to_graph/main.py | 63 ++++++ .../tools/event_tree_to_graph/src/__init__.py | 17 ++ .../event_tree_to_graph/src/beans/README.md | 63 ++++++ .../event_tree_to_graph/src/beans/__init__.py | 17 ++ .../src/beans/base_bean.py | 39 ++++ .../src/beans/dump_result.py | 87 +++++++++ .../src/beans/event_node.py | 155 +++++++++++++++ .../src/beans/event_procedures.py | 75 ++++++++ .../src/beans/event_scope.py | 105 ++++++++++ .../src/beans/event_tree.py | 127 ++++++++++++ .../src/beans/frame_node.py | 76 ++++++++ .../src/beans/procedure_step.py | 71 +++++++ .../src/beans/state_history.py | 67 +++++++ .../src/beans/touch_point.py | 71 +++++++ .../event_tree_to_graph/src/content_parser.py | 63 ++++++ .../event_tree_to_graph/src/graph/__init__.py | 17 ++ .../src/graph/graph_converter.py | 137 +++++++++++++ .../tools/event_tree_to_graph/src/keywords.py | 136 +++++++++++++ .../event_tree_to_graph/src/pre_process.py | 51 +++++ .../event_tree_to_graph/src/test/__init__.py | 17 ++ .../src/test/beans_test.py | 182 ++++++++++++++++++ .../src/test/keyword_test.py | 44 +++++ .../event_tree_to_graph/src/utils/__init__.py | 17 ++ .../src/utils/log_wrapper.py | 69 +++++++ .../src/utils/value_parser.py | 100 ++++++++++ 26 files changed, 1877 insertions(+) create mode 100644 test/tools/event_tree_to_graph/README.md create mode 100644 test/tools/event_tree_to_graph/main.py create mode 100644 test/tools/event_tree_to_graph/src/__init__.py create mode 100644 test/tools/event_tree_to_graph/src/beans/README.md create mode 100644 test/tools/event_tree_to_graph/src/beans/__init__.py create mode 100644 test/tools/event_tree_to_graph/src/beans/base_bean.py create mode 100644 test/tools/event_tree_to_graph/src/beans/dump_result.py create mode 100644 test/tools/event_tree_to_graph/src/beans/event_node.py create mode 100644 test/tools/event_tree_to_graph/src/beans/event_procedures.py create mode 100644 test/tools/event_tree_to_graph/src/beans/event_scope.py create mode 100644 test/tools/event_tree_to_graph/src/beans/event_tree.py create mode 100644 test/tools/event_tree_to_graph/src/beans/frame_node.py create mode 100644 test/tools/event_tree_to_graph/src/beans/procedure_step.py create mode 100644 test/tools/event_tree_to_graph/src/beans/state_history.py create mode 100644 test/tools/event_tree_to_graph/src/beans/touch_point.py create mode 100644 test/tools/event_tree_to_graph/src/content_parser.py create mode 100644 test/tools/event_tree_to_graph/src/graph/__init__.py create mode 100644 test/tools/event_tree_to_graph/src/graph/graph_converter.py create mode 100644 test/tools/event_tree_to_graph/src/keywords.py create mode 100644 test/tools/event_tree_to_graph/src/pre_process.py create mode 100644 test/tools/event_tree_to_graph/src/test/__init__.py create mode 100644 test/tools/event_tree_to_graph/src/test/beans_test.py create mode 100644 test/tools/event_tree_to_graph/src/test/keyword_test.py create mode 100644 test/tools/event_tree_to_graph/src/utils/__init__.py create mode 100644 test/tools/event_tree_to_graph/src/utils/log_wrapper.py create mode 100644 test/tools/event_tree_to_graph/src/utils/value_parser.py diff --git a/test/tools/event_tree_to_graph/README.md b/test/tools/event_tree_to_graph/README.md new file mode 100644 index 00000000000..997a69e1f32 --- /dev/null +++ b/test/tools/event_tree_to_graph/README.md @@ -0,0 +1,11 @@ +#### 使用方法: +> 1. 在本地python环境中运行`python -m pip install graphviz`,确保安装成功; +> 2. 将手势树dump从日志或命令行中保存在一个文本文件中(示例可参考:./resources/dumpfile目录下的`input.txt`文件); +> 3. cmd中执行`python3 main.py -i ./resources/dumpfile/input.txt`; +> 4. 生成的手势树 SVG 图像文件输出在制定`./output`目录中; +> 5. 使用浏览器查看即可; +> 6. 默认只展示简易内容,如果需要展示完整内容,请将`python main.py -m`; + +【Note】:如果遇到提示 dot 可执行文件无法找到,则需要本地安装 [Graphviz](https://graphviz.org/download/), +并将其bin目录路径添加到环境变量中。 + diff --git a/test/tools/event_tree_to_graph/main.py b/test/tools/event_tree_to_graph/main.py new file mode 100644 index 00000000000..be2c8537fbc --- /dev/null +++ b/test/tools/event_tree_to_graph/main.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +import argparse + +from src.content_parser import ContentParser +from src.graph.graph_converter import generate_event_trees_graph +from src.pre_process import handle_file_preprocess +from src.utils.log_wrapper import log_info, log_error + + +def usage(): + print("python main.py -i input.txt") + print('\n Usage: main.py ') + print(' : TODO') + print(' : input dump file') + print(' : ouput image file\n') + return + +def parse_args(): + parser = argparse.ArgumentParser(description="") + parser.add_argument("-i", type=str, default="input.txt", help="input the dump source file") + parser.add_argument("-o", type=str, default="dump_temp.txt", help="output the generated image") + parser.add_argument("-m", action='store_true', default=False, help="是否生成详细信息") + argument = parser.parse_args() + argument.input_file = argument.i + argument.output_file = argument.o + argument.detailed = argument.m + return argument + + +""" +python main.py -i input.txt -o dump_temp.txt +""" +if __name__ == '__main__': + # 解析参数 + args = parse_args() + # 预处理 + handle_file_preprocess(args.input_file, args.output_file) + # 读取文件,并解析 + dump_result = ContentParser(args.output_file).do_parse() + if dump_result.is_succeed(): + log_info("解析成功") + dump_result.dump() + else: + log_error("解析失败") + generate_event_trees_graph(dump_result, args.detailed) diff --git a/test/tools/event_tree_to_graph/src/__init__.py b/test/tools/event_tree_to_graph/src/__init__.py new file mode 100644 index 00000000000..f4a09b9384d --- /dev/null +++ b/test/tools/event_tree_to_graph/src/__init__.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# \ No newline at end of file diff --git a/test/tools/event_tree_to_graph/src/beans/README.md b/test/tools/event_tree_to_graph/src/beans/README.md new file mode 100644 index 00000000000..275cf979cc0 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/beans/README.md @@ -0,0 +1,63 @@ +# the data structure relationship + +``` +DumpResult + |--EventTree(0) + |--EventScope(0) + |--finger: 0 + |--EventNode(0) + |--type + |--address + |--StateHistory + |--procedure(0) + |--procedure(1) + |--EventNode(1) + |--type + |--address + |--StateHistory + |--procedure(0) + |--procedure(1) + |--EventScope(1) + |--finger: 0 + |--EventNode(0) + |--type + |--address + |--StateHistory + |--procedure(0) + |--procedure(1) + |--EventNode(1) + |--type + |--address + |--StateHistory + |--procedure(0) + |--procedure(1) + |--EventTree(1) + |--EventScope(0) + |--finger: 0 + |--EventNode(0) + |--type + |--address + |--StateHistory + |--procedure(0) + |--procedure(1) + |--EventNode(1) + |--type + |--address + |--StateHistory + |--procedure(0) + |--procedure(1) + |--EventScope(1) + |--finger: 0 + |--EventNode(0) + |--type + |--address + |--StateHistory + |--procedure(0) + |--procedure(1) + |--EventNode(1) + |--type + |--address + |--StateHistory + |--procedure(0) + |--procedure(1) +``` \ No newline at end of file diff --git a/test/tools/event_tree_to_graph/src/beans/__init__.py b/test/tools/event_tree_to_graph/src/beans/__init__.py new file mode 100644 index 00000000000..3dd1e6d3a26 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/beans/__init__.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/test/tools/event_tree_to_graph/src/beans/base_bean.py b/test/tools/event_tree_to_graph/src/beans/base_bean.py new file mode 100644 index 00000000000..deb73233188 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/beans/base_bean.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from abc import abstractmethod + + +class BaseBean: + parse_result = False + + def __init__(self): + pass + + def is_succeed(self): + return self.parse_result + + def parse_succeed(self): + self.parse_result = True + + def parse_failed(self): + self.parse_result = False + + @abstractmethod + def check_parse_result(self): + pass diff --git a/test/tools/event_tree_to_graph/src/beans/dump_result.py b/test/tools/event_tree_to_graph/src/beans/dump_result.py new file mode 100644 index 00000000000..4efd74ee25c --- /dev/null +++ b/test/tools/event_tree_to_graph/src/beans/dump_result.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from src.beans.base_bean import BaseBean +from src.beans.event_tree import EventTree +from src.keywords import keywords_dict +from src.utils.log_wrapper import log_info +from src.utils.value_parser import pack_string_until_next_keyword + + +class DumpResult(BaseBean): + event_trees = [] + + def __init__(self, input_str): + super().__init__() + self.event_trees = [] + self.parse_event_trees(input_str) + self.check_parse_result() + if self.is_succeed(): + self.update_tree_info() + print('parse result: ' + self.to_string()) + + def parse_event_trees(self, input_str): + if input_str is None or len(input_str) == 0: + return + spliced_lines = input_str.split('\n') + current_index = 0 + start_keyword = keywords_dict['event tree'] + end_keywords = [keywords_dict['event tree']] + while current_index < len(spliced_lines): + line = spliced_lines[current_index] + if line.find(keywords_dict['event tree']) == -1: + # not found, try next line + current_index += 1 + continue + # found, pack one event tree str + packed_result = pack_string_until_next_keyword(spliced_lines, current_index, start_keyword, end_keywords) + if packed_result is None: + # parse end + return + packed_str = packed_result[0] + current_index = packed_result[1] + if packed_result is None or packed_str is None or len(packed_str) == 0: + self.parse_failed() + return + event_tree = EventTree(packed_str) + if event_tree.is_succeed(): + self.event_trees.append(event_tree) + + def update_tree_info(self): + for event_tree in self.event_trees: + event_tree.update_event_nodes() + + def get_tree_count(self): + return len(self.event_trees) + + def check_parse_result(self): + if self.event_trees is None or len(self.event_trees) == 0: + self.parse_failed() + else: + self.parse_succeed() + + def to_string(self): + result_str = 'DumpResult:' + index = 0 + for event_tree in self.event_trees: + result_str += '\nevent tree ' + str(event_tree.tree_id) + '\n' + event_tree.to_string() + index += 1 + return result_str + + def dump(self): + log_info(self.to_string()) diff --git a/test/tools/event_tree_to_graph/src/beans/event_node.py b/test/tools/event_tree_to_graph/src/beans/event_node.py new file mode 100644 index 00000000000..fbadd02a7ca --- /dev/null +++ b/test/tools/event_tree_to_graph/src/beans/event_node.py @@ -0,0 +1,155 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from typing import List + +from src.beans.base_bean import BaseBean +from src.beans.frame_node import FrameNode +from src.beans.state_history import StateHistory +# frameNodeId: 84, type: TouchEventActuator, depth: 0, id: 0xf072b240, parentId: 0x0 +# stateHistory: +# procedure: HandleTouchDown, timestamp: 2017-08-25 15:00:22.247 +# procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.295 + +from src.keywords import event_procedure_keyword +from src.utils.log_wrapper import log_info, log_error +from src.utils.value_parser import get_value_as_int, get_value_as_str, get_value_as_float +from typing import List + + +# frameNodeId: 84, type: PanRecognizer, depth: 1, id: 0xf3d6bfc0, parentId: 0xf063eed0, customInfo: direction: 3, +# isForDrag: 0, distance: 7.5, fingers: 1 +class EventNode(BaseBean): + frameNodeId = 0 + type = '' + depth = '' + address = '' # id + parentId = '' + + # optional info + custom_info = None + direction = None + duration = None + isForDrag = None + distance = None + repeat = None + fingers = None + + state_history = None + + original_str = '' + + # updated after parsing done + tag = '' + + def __init__(self, input_str): + super().__init__() + texts = input_str.split('\n') + if len(texts) < 2: + log_error('EventNode: input_str is invalid') + return + self.original_str = input_str + # parse frame node info + # frameNodeId: 84, type: TouchEventActuator, depth: 0, id: 0xf072b240, parentId: 0x0 + frame_node_str = texts[0] + self.frameNodeId = get_value_as_int(frame_node_str, event_procedure_keyword['frameNodeId'].key, + event_procedure_keyword['frameNodeId'].value_separator_count) + self.type = get_value_as_str(frame_node_str, event_procedure_keyword['type'].key, + event_procedure_keyword['type'].value_separator_count) + self.depth = get_value_as_int(frame_node_str, event_procedure_keyword['depth'].key, + event_procedure_keyword['depth'].value_separator_count) + self.address = get_value_as_str(frame_node_str, event_procedure_keyword['id'].key, + event_procedure_keyword['id'].value_separator_count) + self.parentId = get_value_as_str(frame_node_str, event_procedure_keyword['parentId'].key, + event_procedure_keyword['parentId'].value_separator_count) + self.duration = get_value_as_int(frame_node_str, event_procedure_keyword['duration'].key, + event_procedure_keyword['duration'].value_separator_count) + self.custom_info = get_value_as_str(frame_node_str, event_procedure_keyword['customInfo'].key, + event_procedure_keyword['customInfo'].value_separator_count) + self.direction = get_value_as_int(frame_node_str, event_procedure_keyword['direction'].key, + event_procedure_keyword['direction'].value_separator_count) + self.distance = get_value_as_float(frame_node_str, event_procedure_keyword['distance'].key, + event_procedure_keyword['distance'].value_separator_count) + self.isForDrag = get_value_as_int(frame_node_str, event_procedure_keyword['isForDrag'].key, + event_procedure_keyword['isForDrag'].value_separator_count) + self.repeat = get_value_as_int(frame_node_str, event_procedure_keyword['repeat'].key, + event_procedure_keyword['repeat'].value_separator_count) + self.fingers = get_value_as_int(frame_node_str, event_procedure_keyword['fingers'].key, + event_procedure_keyword['fingers'].value_separator_count) + # parse state history + self.parse_state_history(texts, 1) + self.check_parse_result() + + def check_parse_result(self): + # check the necessary field.s + if (self.frameNodeId is None or self.type is None or self.depth is None or self.address is None or + self.parentId is None): + self.parse_failed() + return + if self.state_history is None: + self.parse_failed() + return + self.parse_succeed() + + def parse_state_history(self, text_array, start_index): + if len(text_array) <= start_index: + return + # skip stateHistory itself + procedures_str = '' + for i in range(start_index + 1, len(text_array)): + procedures_str += (text_array[i] + '\n') + self.state_history = StateHistory(procedures_str) + + def update_tag_from_frame_nodes_info(self, frame_nodes: List[FrameNode]): + if frame_nodes is None or len(frame_nodes) == 0: + return + for frame_node in frame_nodes: + if frame_node.nodeId == self.frameNodeId: + self.tag = frame_node.tag + break + + def get_summary_string(self): + return self.tag + '(' + str(self.frameNodeId) + ')\n' + self.type + '\n' + self.address + + def get_detailed_summary_string(self): + return (self.tag + '(' + str( + self.frameNodeId) + ') ' + self.type + ' ' + self.address + '\n' + + self.state_history.get_detailed_summary_string()) + + def to_string(self): + result_str = ' frameNodeId: ' + str(self.frameNodeId) + ', type: ' + self.type + ', depth: ' + str( + self.depth) + ', id: ' + self.address + ', parentId: ' + self.parentId + if self.custom_info is not None: + result_str += ',' + ' customInfo: ' + self.custom_info + if self.direction is not None: + result_str += ',' + ' direction: ' + str(self.direction) + if self.distance is not None: + result_str += ',' + ' distance: ' + str(self.distance) + if self.duration is not None: + result_str += ',' + ' duration: ' + str(self.duration) + if self.repeat is not None: + result_str += ',' + ' repeat: ' + str(self.repeat) + if self.isForDrag is not None: + result_str += ',' + ' isForDrag: ' + str(self.isForDrag) + if self.fingers is not None: + result_str += ',' + ' fingers: ' + str(self.fingers) + result_str += '\n' + self.state_history.to_string() + return result_str + + def dump(self): + log_info(self.to_string()) diff --git a/test/tools/event_tree_to_graph/src/beans/event_procedures.py b/test/tools/event_tree_to_graph/src/beans/event_procedures.py new file mode 100644 index 00000000000..5917e2c3e67 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/beans/event_procedures.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from typing import List + +from src.beans.base_bean import BaseBean +from src.beans.event_scope import EventScope +from src.beans.frame_node import FrameNode +from src.utils.log_wrapper import log_info +from src.utils.value_parser import pack_string_until_next_keyword + + +class EventProcedures(BaseBean): + event_scopes = [] + + def __init__(self, input_str): + super().__init__() + self.event_scopes = [] + self.parse_event_scopes(input_str) + self.check_parse_result() + + def parse_event_scopes(self, input_str): + spliced_lines = input_str.split('\n') + start_keyword = 'finger:' + end_keywords = ['finger:', 'event tree =>'] + current_index = 0 + while current_index < len(spliced_lines): + current_line = spliced_lines[current_index] + if current_line.find('finger:') != -1: + packed_result = pack_string_until_next_keyword(spliced_lines, current_index, start_keyword, + end_keywords) + packed_str = packed_result[0] + if packed_str is None or len(packed_str) == 0: + current_index += 1 + continue + current_index = packed_result[1] + event_scope = EventScope(packed_str) + if event_scope.is_succeed(): + self.event_scopes.append(event_scope) + else: + current_index += 1 + + def update_event_nodes_with_frame_nodes(self, frame_nodes: List[FrameNode]): + for scope in self.event_scopes: + scope.update_event_nodes_with_frame_nodes(frame_nodes) + + def check_parse_result(self): + if self.event_scopes is None or len(self.event_scopes) == 0: + self.parse_failed() + else: + self.parse_succeed() + + def to_string(self): + result_str = 'event procedures: ' + for scope in self.event_scopes: + result_str += '\n' + scope.to_string() + return result_str + + def dump(self): + log_info(self.to_string()) diff --git a/test/tools/event_tree_to_graph/src/beans/event_scope.py b/test/tools/event_tree_to_graph/src/beans/event_scope.py new file mode 100644 index 00000000000..dedd7f4fc26 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/beans/event_scope.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from typing import List + +from src.beans.base_bean import BaseBean +from src.beans.event_node import EventNode +from src.beans.frame_node import FrameNode +from src.keywords import event_procedure_keyword, keywords_dict +from src.utils.log_wrapper import log_info +from src.utils.value_parser import get_value_as_int, pack_string_until_next_keyword + + +class EventScope(BaseBean): + finger = 0 + event_nodes = [] + + def __init__(self, input_str): + super().__init__() + self.event_nodes = [] + texts = input_str.split('\n') + if texts is None or len(texts) == 0: + self.parse_failed() + return + finger_str = texts[0] + self.finger = get_value_as_int(finger_str, event_procedure_keyword['finger'].key, + event_procedure_keyword['finger'].value_separator_count, True) + self.parse_event_nodes(texts, 1) + self.check_parse_result() + + # finger:0 + # frameNodeId: 84, type: TouchEventActuator, depth: 0, id: 0xf072b240, parentId: 0x0 + # stateHistory: + # procedure: HandleTouchDown, timestamp: 2017-08-25 15:00:22.247 + # procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.295 + # frameNodeId: 84, type: ExclusiveRecognizer, depth: 0, id: 0xf063eed0, parentId: 0x0 + # stateHistory: + # procedure: HandleTouchDown, state: READY, disposal: NONE, timestamp: 2017-08-25 15:00:22.247 + # procedure: HandleTouchUp, state: FAIL, disposal: REJECT, timestamp: 2017-08-25 15:00:22.295 + # frameNodeId: 88, type: LongPressRecognizer, depth: 1, id: 0xef748aa0, parentId: 0xf063eed0, customInfo: + # duration: 500, isForDrag: 0, repeat: 0, fingers: 1 + # stateHistory: + # procedure: HandleTouchDown, state: DETECTING, disposal: NONE, timestamp: 2017-08-25 15:00:22.247 + # procedure: HandleTouchUp, state: FAIL, disposal: REJECT, timestamp: 2017-08-25 15:00:22.295 + # frameNodeId: 84, type: PanRecognizer, depth: 1, id: 0xf3d6bfc0, parentId: 0xf063eed0, customInfo: + # direction: 3, isForDrag: 0, distance: 7.5, fingers: 1 + # stateHistory: + # procedure: HandleTouchDown, state: DETECTING, disposal: NONE, timestamp: 2017-08-25 15:00:22.247 + # procedure: HandleTouchUp, state: FAIL, disposal: REJECT, timestamp: 2017-08-25 15:00:22.295 + def parse_event_nodes(self, spliced_lines, start_index): + start_keyword = event_procedure_keyword['frameNodeId'].key + end_keywords = [event_procedure_keyword['frameNodeId'].key, keywords_dict['event tree']] + current_index = 0 + while current_index < len(spliced_lines): + if current_index < start_index: + current_index += 1 + continue + current_line = spliced_lines[current_index] + if current_line.find('frameNodeId') != -1: + packed_result = pack_string_until_next_keyword(spliced_lines, current_index, start_keyword, + end_keywords) + packed_str = packed_result[0] + if packed_str is None or len(packed_str) == 0: + current_index += 1 + continue + current_index = packed_result[1] + event_node = EventNode(packed_str) + if event_node is not None: + self.event_nodes.append(event_node) + else: + current_index += 1 + + def check_parse_result(self): + if self.finger is None or self.event_nodes is None or len(self.event_nodes) == 0: + self.parse_failed() + else: + self.parse_succeed() + + def to_string(self): + result_str = ' finger: ' + str(self.finger) + for event_node in self.event_nodes: + result_str += '\n' + event_node.to_string() + return result_str + + def dump(self): + log_info(self.to_string()) + + def update_event_nodes_with_frame_nodes(self, frame_nodes: List[FrameNode]): + for event_node in self.event_nodes: + event_node.update_tag_from_frame_nodes_info(frame_nodes) diff --git a/test/tools/event_tree_to_graph/src/beans/event_tree.py b/test/tools/event_tree_to_graph/src/beans/event_tree.py new file mode 100644 index 00000000000..20763cd1ac8 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/beans/event_tree.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from src.beans.base_bean import BaseBean +from src.beans.event_procedures import EventProcedures +from src.beans.frame_node import FrameNode +from src.beans.touch_point import TouchPoint +from src.utils.log_wrapper import log_info, log_error +from src.utils.value_parser import pack_string_until_next_keyword, get_value_as_int + + +# includes touch points and frame nodes(hittest) and event procedures +class EventTree(BaseBean): + tree_id = -1 # the index in dump + touch_points = [] + frame_nodes = [] + event_procedures = None + + def __init__(self, input_str): + super().__init__() + self.tree_id = -1 + self.touch_points = [] + self.frame_nodes = [] + self.event_procedures = None + self.parse_event_tree(input_str) + self.check_parse_result() + + def parse_event_tree(self, input_str): + spliced_lines = input_str.split('\n') + self.parse_tree_index(spliced_lines) + current_index = self.parse_touch_points(spliced_lines, 0) + current_index = self.parse_hit_tests(spliced_lines, current_index) + current_index = self.parse_event_procedures(spliced_lines, current_index) + return current_index + + def parse_tree_index(self, lines): + if lines is None or len(lines) == 0: + return + tree_index_str = lines[0] + spliced_tree_lines = tree_index_str.split(': ') + if len(spliced_tree_lines) != 2: + log_error('parse tree index failed, input str: ' + tree_index_str) + return + self.tree_id = int(spliced_tree_lines[0]) + + def parse_touch_points(self, texts, start_index): + start_keyword = 'touch points:' + end_keywords = ['hittest:'] + packed_result = pack_string_until_next_keyword(texts, start_index, start_keyword, end_keywords) + packed_str = packed_result[0] + if packed_str is None or len(packed_str) == 0: + return packed_result[1] + spliced_touch_points = packed_str.split('\n') + for touch_point_str in spliced_touch_points: + if touch_point_str.find('id: ') == -1: + continue + touch_point = TouchPoint(touch_point_str) + if touch_point is not None and touch_point.is_succeed(): + self.touch_points.append(touch_point) + return packed_result[1] + + def parse_hit_tests(self, texts, start_index): + start_keyword = 'hittest:' + end_keywords = ['event procedures:'] + packed_result = pack_string_until_next_keyword(texts, start_index, start_keyword, end_keywords) + packed_str = packed_result[0] + if packed_str is None or len(packed_str) == 0: + return packed_result[1] + spliced_frame_nodes = packed_str.split('\n') + for frame_node_str in spliced_frame_nodes: + if frame_node_str.find('nodeId: ') == -1: + continue + frame_node = FrameNode(frame_node_str) + if frame_node is not None and frame_node.is_succeed(): + self.frame_nodes.append(frame_node) + return packed_result[1] + + def parse_event_procedures(self, texts, start_index): + start_keyword = 'event procedures:' + end_keywords = ['event tree =>'] + packed_result = pack_string_until_next_keyword(texts, start_index, start_keyword, end_keywords) + packed_str = packed_result[0] + if packed_str is None or len(packed_str) == 0: + return packed_result[1] + self.event_procedures = EventProcedures(packed_str) + return packed_result[1] + + def check_parse_result(self): + if self.tree_id == -1 or self.touch_points is None or len(self.touch_points) == 0 or self.frame_nodes is None \ + or len( + self.frame_nodes) == 0 or self.event_procedures is None: + self.parse_failed() + else: + self.parse_succeed() + + def to_string(self): + result_str = 'touch points: ' + for touch_point in self.touch_points: + result_str += '\n' + touch_point.to_string() + result_str += '\n' + 'hittest: ' + for frame_node in self.frame_nodes: + result_str += '\n' + frame_node.to_string() + result_str += '\n' + self.event_procedures.to_string() + return result_str + + def dump(self): + log_info(self.to_string()) + + def update_event_nodes(self): + if self.event_procedures is None or self.frame_nodes is None or len(self.frame_nodes) == 0: + return + self.event_procedures.update_event_nodes_with_frame_nodes(self.frame_nodes) diff --git a/test/tools/event_tree_to_graph/src/beans/frame_node.py b/test/tools/event_tree_to_graph/src/beans/frame_node.py new file mode 100644 index 00000000000..21e9d3d3e36 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/beans/frame_node.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from src.beans.base_bean import BaseBean +from src.keywords import hittest_node_keyword +from src.utils.log_wrapper import log_info +from src.utils.value_parser import get_value_as_int, get_value_as_str + + +# nodeId: 0, parentId: -1, tag: root, monopolizeEvents: 0, isHit: 1, hitTestMode: 0, responseRegion: RectT (0.00, +# 0.00) - [720.00 x 1280.00] +class FrameNode(BaseBean): + nodeId = 0 + parentId = -1 + tag = '' + com_id = '' + monopolizeEvents = 0 + isHit = 1 + hitTestMode = 0 + responseRegion = '' + + original_str = '' + + def __init__(self, node_dump_str): + super().__init__() + self.original_str = node_dump_str + self.nodeId = get_value_as_int(node_dump_str, hittest_node_keyword['nodeId'].key, + hittest_node_keyword['nodeId'].value_separator_count) + self.parentId = get_value_as_int(node_dump_str, hittest_node_keyword['parentId'].key, + hittest_node_keyword['parentId'].value_separator_count) + self.tag = get_value_as_str(node_dump_str, hittest_node_keyword['tag'].key, + hittest_node_keyword['tag'].value_separator_count) + self.com_id = get_value_as_str(node_dump_str, hittest_node_keyword['comId'].key, + hittest_node_keyword['comId'].value_separator_count) + self.monopolizeEvents = get_value_as_int(node_dump_str, hittest_node_keyword['monopolizeEvents'].key, + hittest_node_keyword['monopolizeEvents'].value_separator_count) + self.isHit = get_value_as_int(node_dump_str, hittest_node_keyword['isHit'].key, + hittest_node_keyword['isHit'].value_separator_count) + self.hitTestMode = get_value_as_int(node_dump_str, hittest_node_keyword['hitTestMode'].key, + hittest_node_keyword['hitTestMode'].value_separator_count) + self.responseRegion = get_value_as_str(node_dump_str, hittest_node_keyword['responseRegion'].key, + hittest_node_keyword['responseRegion'].value_separator_count, True) + self.check_parse_result() + + def check_parse_result(self): + if (self.nodeId is None or self.parentId is None or self.tag is None or self.monopolizeEvents is None or + self.isHit is None or self.hitTestMode is None or self.responseRegion is None): + self.parse_failed() + else: + self.parse_succeed() + + def to_string(self): + result_str = ' nodeId: ' + str(self.nodeId) + ', parentId: ' + str(self.parentId) + ', tag: ' + self.tag + if self.com_id is not None: + result_str += ', comId: ' + self.com_id + result_str += ', monopolizeEvents: ' + str(self.monopolizeEvents) + ', isHit: ' + str( + self.isHit) + ', hitTestMode: ' + str(self.hitTestMode) + ', responseRegion: ' + self.responseRegion + return result_str + + def dump(self): + log_info(self.to_string()) diff --git a/test/tools/event_tree_to_graph/src/beans/procedure_step.py b/test/tools/event_tree_to_graph/src/beans/procedure_step.py new file mode 100644 index 00000000000..e193f6552ce --- /dev/null +++ b/test/tools/event_tree_to_graph/src/beans/procedure_step.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from src.beans.base_bean import BaseBean +from src.keywords import event_procedure_keyword +from src.utils.log_wrapper import log_info +from src.utils.value_parser import get_value_as_str + + +# procedure: HandleTouchDown, state: READY, disposal: NONE, timestamp: 2017-08-25 15:00:20.177 +class ProcedureStep(BaseBean): + procedure = '' + state = '' + disposal = '' + timestamp = '' + + original_str = '' + + def __init__(self, input_str): + super().__init__() + self.original_str = input_str + self.procedure = get_value_as_str(input_str, event_procedure_keyword['procedure'].key, + event_procedure_keyword['procedure'].value_separator_count) + self.state = get_value_as_str(input_str, event_procedure_keyword['state'].key, + event_procedure_keyword['state'].value_separator_count) + self.disposal = get_value_as_str(input_str, event_procedure_keyword['disposal'].key, + event_procedure_keyword['disposal'].value_separator_count) + self.timestamp = get_value_as_str(input_str, event_procedure_keyword['timestamp'].key, + event_procedure_keyword['timestamp'].value_separator_count, True) + self.check_parse_result() + + def check_parse_result(self): + if self.procedure is None or self.timestamp is None: + self.parse_failed() + else: + self.parse_succeed() + + def get_detailed_summary_string(self): + result_str = self.procedure + if self.state is not None: + result_str += ', state(' + self.state + ')' + if self.disposal is not None: + result_str += ', disposal(' + self.disposal + ')' + return result_str + + def to_string(self): + result_str = ' procedure: ' + self.procedure + if self.state is not None: + result_str += ', state: ' + self.state + if self.disposal is not None: + result_str += ', disposal: ' + self.disposal + result_str += ', timestamp: ' + self.timestamp + return result_str + + def dump(self): + log_info(self.to_string()) diff --git a/test/tools/event_tree_to_graph/src/beans/state_history.py b/test/tools/event_tree_to_graph/src/beans/state_history.py new file mode 100644 index 00000000000..e55a9d9a554 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/beans/state_history.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from src.beans.base_bean import BaseBean +# stateHistory: +# procedure: HandleTouchDown, timestamp: 2017-08-25 15:00:22.247 +# procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.295 + +from src.beans.procedure_step import ProcedureStep +from src.utils.log_wrapper import log_info + + +class StateHistory(BaseBean): + event_procedures = [] + original_str = '' + + def __init__(self, input_str): + super().__init__() + self.original_str = input_str + self.event_procedures = [] + self.splice_event_procedure(input_str) + self.check_parse_result() + + def splice_event_procedure(self, input_str): + for line in input_str.split('\n'): + if line.find('procedure: ') == -1: + continue + event_procedure = ProcedureStep(line) + if event_procedure is not None: + self.event_procedures.append(event_procedure) + + def check_parse_result(self): + if self.event_procedures is None or len(self.event_procedures) == 0: + self.parse_failed() + else: + self.parse_succeed() + + def get_detailed_summary_string(self): + result_str = '' + for procedure_step in self.event_procedures: + result_str += procedure_step.get_detailed_summary_string() + '\n' + result_str.rstrip('\n') + return result_str + + def to_string(self): + result_str = ' stateHistory:' + for event_procedure in self.event_procedures: + result_str += '\n' + event_procedure.to_string() + return result_str + + def dump(self): + log_info(self.to_string()) diff --git a/test/tools/event_tree_to_graph/src/beans/touch_point.py b/test/tools/event_tree_to_graph/src/beans/touch_point.py new file mode 100644 index 00000000000..859d7762513 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/beans/touch_point.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from src.beans.base_bean import BaseBean +from src.keywords import touch_point_keyword +from src.utils.log_wrapper import log_info +from src.utils.value_parser import get_value_as_int, get_value_as_str + + +# id: 0, point: Offset (278.00, 551.00), screenPoint: Offset (278.00, 551.00), type: TouchUp, timestamp: 2017-08-25 +# 15:00:22.295, isInjected: 0 +class TouchPoint(BaseBean): + id = 0 + point = '' + screenPoint = '' + type = '' + timestamp = '' + isInjected = 0 + original_str = '' + + def __init__(self, input_str): + super().__init__() + self.original_str = input_str + self.id = get_value_as_int(input_str, touch_point_keyword['id'].key, + touch_point_keyword['id'].value_separator_count) + self.point = get_value_as_str(input_str, touch_point_keyword['point'].key, + touch_point_keyword['point'].value_separator_count) + self.screenPoint = get_value_as_str(input_str, touch_point_keyword['screenPoint'].key, + touch_point_keyword['screenPoint'].value_separator_count) + self.type = get_value_as_str(input_str, touch_point_keyword['type'].key, + touch_point_keyword['type'].value_separator_count) + self.timestamp = get_value_as_str(input_str, touch_point_keyword['timestamp'].key, + touch_point_keyword['timestamp'].value_separator_count) + self.isInjected = get_value_as_int(input_str, touch_point_keyword['isInjected'].key, + touch_point_keyword['isInjected'].value_separator_count, True) + self.check_parse_result() + + def check_parse_result(self): + if (self.id is None or self.point is None or self.screenPoint is None or self.type is None or self.timestamp + is None or self.isInjected is None): + self.parse_failed() + else: + self.parse_succeed() + + def to_string(self): + return ' id: ' + str( + self.id) + ', point: ' + self.point + ', screenPoint: ' + self.screenPoint + ', type: ' + self.type + ( + ', timestamp: ') + self.timestamp + ', isInjected: ' + str( + self.isInjected) + + def to_summary_string(self): + return 'id: ' + str(self.id) + ', ' + self.point + ', ' + self.screenPoint + ', ' + self.type + ( + ', ') + self.timestamp + + def dump(self): + log_info(self.to_string()) diff --git a/test/tools/event_tree_to_graph/src/content_parser.py b/test/tools/event_tree_to_graph/src/content_parser.py new file mode 100644 index 00000000000..27130e29111 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/content_parser.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# 读取预处理后的文件,将内容解析为对象待用 + +import os + +from src.beans.dump_result import DumpResult +from src.keywords import keywords_dict +from src.utils.log_wrapper import log_warning, log_info, log_error + + +class ContentParser: + file_path = "" + parse_result = None + + def __init__(self, path): + self.file_path = path + + def is_succeed(self): + return self.parse_result is not None + + def do_parse(self): + file_content = self.load_file() + if file_content is None or file_content == '': + log_error('文件不存在') + return None + event_tree_count = self.pre_check_event_tree_count(file_content) + if event_tree_count == 0: + log_error('没有找到任何 event tree') + return None + self.parse_result = DumpResult(file_content) + return self.parse_result + + def load_file(self): + if os.path.exists(self.file_path): + with open(self.file_path, 'r') as f: + return f.read() + else: + return None + + def pre_check_event_tree_count(self, file_content): + event_tree_count = 0 + for line in file_content.split('\n'): + index = line.find(keywords_dict['event tree']) + if index != -1: + event_tree_count += 1 + return event_tree_count diff --git a/test/tools/event_tree_to_graph/src/graph/__init__.py b/test/tools/event_tree_to_graph/src/graph/__init__.py new file mode 100644 index 00000000000..3dd1e6d3a26 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/graph/__init__.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/test/tools/event_tree_to_graph/src/graph/graph_converter.py b/test/tools/event_tree_to_graph/src/graph/graph_converter.py new file mode 100644 index 00000000000..b4bd5bd722e --- /dev/null +++ b/test/tools/event_tree_to_graph/src/graph/graph_converter.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from typing import List + +# convert the dump result into graphical representation + +from graphviz import Digraph + +from src.beans.event_node import EventNode +from src.beans.event_procedures import EventProcedures +from src.beans.event_scope import EventScope +from src.beans.event_tree import EventTree + +output_folder = 'output' + + +def reset_output_dir(): + import os + if os.path.exists(output_folder): + import shutil + shutil.rmtree(output_folder) + os.mkdir(output_folder) + + +def draw_title_and_touch_points(tree: EventTree, tree_name, dot): + touch_points = tree.touch_points + current_index = 0 + touch_points_info = "event tree " + str(tree.tree_id) + '\n' + for touch_point in touch_points: + touch_points_info += touch_point.to_summary_string() + '\n' + current_index += 1 + touch_points_info.rstrip('\n') + if current_index != 0: + sub_graph = Digraph(comment='touch points') + sub_graph.node(tree_name, touch_points_info, shape='box') + dot.subgraph(sub_graph) + + +class ParentChildrenPair: + item_self: EventNode = None # parent + children: List['ParentChildrenPair'] = [] + + def __init__(self, item): + self.item_self = item + self.children = [] + + def append_child(self, child): + self.children.append(child) + + def get_address(self): + return self.item_self.address + + +def build_event_node_tree(scope: EventScope): + result = [] + node_map = {} + flatten_frame_nodes: List[EventNode] = scope.event_nodes + # make a mapping table + for item in flatten_frame_nodes: + node_map[item.address] = ParentChildrenPair(item) + # # append child nodes to their parent's `children` attribute based on `parentId` + for item in flatten_frame_nodes: + if item.parentId is not None and item.parentId != 0 and len(item.parentId) > 6: + node_map[item.parentId].append_child(node_map[item.address]) + else: + result.append(node_map[item.address]) + return result + + +# draw node relationships recursively +def draw_event_scop_tree_recursively(node_tree: List[ParentChildrenPair], parent_node_name: str, graph: Digraph, + is_show_detail): + for item in node_tree: + node_name = item.get_address() + node_label = item.item_self.get_summary_string() + if is_show_detail: + node_label = item.item_self.get_detailed_summary_string() + graph.node(node_name, node_label) + if parent_node_name is not None: + graph.edge(parent_node_name, node_name) + if len(item.children) > 0: + draw_event_scop_tree_recursively(item.children, node_name, graph, is_show_detail) + + +def draw_event_procedures(tree: EventTree, tree_name, dot, is_show_detail): + event_procedures: EventProcedures = tree.event_procedures + if event_procedures is None: + return + tag = str(tree.tree_id) + ' event procedures' + sub_graph = Digraph(comment=tag) + for scope in event_procedures.event_scopes: + sub_scope_graph = Digraph(comment=tag + ' event scope ' + str(scope.finger)) + node_tree = build_event_node_tree(scope) + # treat finger as root node of subgraph + scope_root_node_name = 'finger ' + str(scope.finger) + sub_scope_graph.node(scope_root_node_name, scope_root_node_name) + dot.edge(tree_name, scope_root_node_name) + draw_event_scop_tree_recursively(node_tree, scope_root_node_name, sub_scope_graph, is_show_detail) + sub_graph.subgraph(sub_scope_graph) + dot.subgraph(sub_graph) + + +def generate_event_trees_graph(dump_result, is_show_detail): + # delete all history files before generate new ones + reset_output_dir() + current_index = 0 + # draw every event tree into file + for tree in dump_result.event_trees: + # create a graph + dot = Digraph(comment='event dump' + str(current_index)) + # draw touch points info + tree_name = 'event tree ' + str(tree.tree_id) + draw_title_and_touch_points(tree, tree_name, dot) + # draw event procedures + draw_event_procedures(tree, tree_name, dot, is_show_detail) + # save or show directly + # dot.view() + # or save to file + out_graph_file_name = output_folder + '/view_tree_' + str(tree.tree_id) + dot.render(out_graph_file_name, format='svg', cleanup=True, view=False) + current_index += 1 diff --git a/test/tools/event_tree_to_graph/src/keywords.py b/test/tools/event_tree_to_graph/src/keywords.py new file mode 100644 index 00000000000..53ce8d57c86 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/keywords.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# 定义所有关键词 +# 结构: 每个event tree 按照如下结构解析 +# 2: event tree => +# touch points: +# id: 0, point: Offset (278.00, 551.00), screenPoint: Offset (278.00, 551.00), type: TouchDown, timestamp: +# 2017-08-25 15:00:22.244, isInjected: 0 +# id: 0, point: Offset (278.00, 551.00), screenPoint: Offset (278.00, 551.00), type: TouchUp, timestamp: 2017-08-25 +# 15:00:22.295, isInjected: 0 +# hittest: +# nodeId: 0, parentId: -1, tag: root, monopolizeEvents: 0, isHit: 1, hitTestMode: 0, responseRegion: RectT (0.00, +# 0.00) - [720.00 x 1280.00] +# nodeId: 1, parentId: 0, tag: stage, monopolizeEvents: 0, isHit: 1, hitTestMode: 0, responseRegion: RectT (0.00, +# 0.00) - [720.00 x 1280.00] +# event procedures: +# finger:0 +# frameNodeId: 84, type: TouchEventActuator, depth: 0, id: 0xf072b240, parentId: 0x0 +# stateHistory: +# procedure: HandleTouchDown, timestamp: 2017-08-25 15:00:22.247 +# procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.295 +# finger:1 +# frameNodeId: 84, type: TouchEventActuator, depth: 0, id: 0xf072b240, parentId: 0x0 +# stateHistory: +# procedure: HandleTouchDown, timestamp: 2017-08-25 15:00:22.247 +# procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.295 + + +class KeyValueSample: + key = "" + value = "" + value_separator_count = 0 + + def __init__(self, key_and_value, force_no_space=False): + if force_no_space: + texts = key_and_value.split(":") + else: + texts = key_and_value.split(": ") + if len(texts) != 2: + if len(texts) == 1: + self.key = texts[0] + self.value = "" + else: + self.key = "" + self.value = "" + else: + self.key = texts[0] + (": " if not force_no_space else ":") + self.value = texts[1] + self.value_separator_count = self.value.count(", ") + + +# level 1 keywords +keywords_dict = { + "EventTreeDumpInfo": " EventTreeDumpInfo: ", + "event tree": "event tree =>", +} + +# touch point keywords +# touch points: +# id: 0, point: Offset (278.00, 551.00), screenPoint: Offset (278.00, 551.00), type: TouchDown, timestamp: +# 2017-08-25 15:00:22.244, isInjected: 0 +# id: 0, point: Offset (278.00, 551.00), screenPoint: Offset (278.00, 551.00), type: TouchUp, timestamp: 2017-08-25 +# 15:00:22.295, isInjected: 0 +touch_point_keyword = { + "touch points": KeyValueSample("touch points:"), + "id": KeyValueSample("id: 0"), + "point": KeyValueSample("point: Offset (278.00, 551.00)"), + "screenPoint": KeyValueSample("screenPoint: Offset (278.00, 551.00)"), + "type": KeyValueSample("type: TouchDown,"), + "timestamp": KeyValueSample("timestamp: 2017-08-25 15:00:22.244"), + "isInjected": KeyValueSample("isInjected: 0"), +} + +# nodeId: 0, parentId: -1, tag: root, monopolizeEvents: 0, isHit: 1, hitTestMode: 0, responseRegion: RectT (0.00, +# 0.00) - [720.00 x 1280.00] +hittest_node_keyword = { + "hittest": KeyValueSample("hittest:"), + "nodeId": KeyValueSample("nodeId: 0"), + "parentId": KeyValueSample("parentId: -1"), + "tag": KeyValueSample("tag: root"), + "comId": KeyValueSample("comId: PageDesktopLayout"), + "monopolizeEvents": KeyValueSample("monopolizeEvents: 0"), + "isHit": KeyValueSample("isHit: 1"), + "hitTestMode": KeyValueSample("hitTestMode: 0"), + "responseRegion": KeyValueSample("responseRegion: RectT (0.00, 0.00) - [720.00 x 1280.00]"), +} + +# event procedure keywords +# event procedures: +# finger:0 +# frameNodeId: 84, type: TouchEventActuator, depth: 0, id: 0xf072b240, parentId: 0xf072b240 +# stateHistory: +# procedure: HandleTouchDown, timestamp: 2017-08-25 15:00:22.247 +# procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.295 +# finger:1 +# frameNodeId: 84, type: TouchEventActuator, depth: 0, id: 0xf072b240, parentId: 0xf072b240 +# stateHistory: +# procedure: HandleTouchDown, timestamp: 2017-08-25 15:00:22.247 +# procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.295 +event_procedure_keyword = { + "event procedures": KeyValueSample("event procedures:"), + "finger": KeyValueSample("finger:0", True), + "frameNodeId": KeyValueSample("frameNodeId: 84"), + "type": KeyValueSample("type: TouchEventActuator"), + "depth": KeyValueSample("depth: 0"), + "id": KeyValueSample("id: 0xf072b240"), + "parentId": KeyValueSample("parentId: 0xf072b240"), + "stateHistory": KeyValueSample("stateHistory:"), + "procedure": KeyValueSample("procedure: HandleTouchDown"), + "state": KeyValueSample("state: READY"), + "disposal": KeyValueSample("disposal: NONE"), + "timestamp": KeyValueSample("timestamp: 2017-08-25 15:00:22.247"), + "duration": KeyValueSample("duration: 500"), + "isForDrag": KeyValueSample("isForDrag: 0"), + "repeat": KeyValueSample("repeat: 0"), + "customInfo": KeyValueSample("customInfo: "), + "direction": KeyValueSample("direction: 3"), + "distance": KeyValueSample("distance: 7.5"), + "fingers": KeyValueSample("fingers: 1") +} diff --git a/test/tools/event_tree_to_graph/src/pre_process.py b/test/tools/event_tree_to_graph/src/pre_process.py new file mode 100644 index 00000000000..3047ec6fa8e --- /dev/null +++ b/test/tools/event_tree_to_graph/src/pre_process.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# 预处理输入文件,去除多余信息,生成一个中间文件 +import os +from src.keywords import keywords_dict +from src.utils.log_wrapper import log_info + + +def handle_file_preprocess(input_file, output_file): + # 检查输出文件路径的文件是否存在,存在则先删除 + if os.path.exists(output_file): + try: + os.remove(output_file) + except Exception as e: + # 删除文件时发生错误 + print(f"删除文件 {output_file} 时发生错误:{e}") + + # 打开原始文件和目标文件 + with open(input_file, 'r', encoding='utf-8') as infile, open(output_file, 'w', encoding='utf-8') as outfile: + # 遍历输入文件的每一行 + for line in infile: + # 查找'EventTreeDumpInfo'的位置 + index = line.find(keywords_dict['EventTreeDumpInfo']) + # 如果找到了'EventTreeDumpInfo: ' + if index != -1: + new_index = index + len(keywords_dict['EventTreeDumpInfo']) + # 从'EventTreeDumpInfo'开始截取直到行末 + newline = line[new_index:] + # 将处理后的行写入临时文件 + outfile.write(newline) + else: + # 否则直接写入临时文件 + outfile.write(line) + log_info("输入文件预处理完成:" + input_file + "->" + output_file) + diff --git a/test/tools/event_tree_to_graph/src/test/__init__.py b/test/tools/event_tree_to_graph/src/test/__init__.py new file mode 100644 index 00000000000..3dd1e6d3a26 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/test/__init__.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# diff --git a/test/tools/event_tree_to_graph/src/test/beans_test.py b/test/tools/event_tree_to_graph/src/test/beans_test.py new file mode 100644 index 00000000000..9087353ac53 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/test/beans_test.py @@ -0,0 +1,182 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from src.beans.event_node import EventNode +from src.beans.event_procedures import EventProcedures +from src.beans.event_scope import EventScope +from src.beans.event_tree import EventTree +from src.beans.frame_node import FrameNode +from src.beans.procedure_step import ProcedureStep +from src.beans.state_history import StateHistory +from src.beans.touch_point import TouchPoint +from src.utils.log_wrapper import log_info, log_error + + +def test_begin(test_info): + log_info("# " + test_info + " == test == begin") + + +def test_end(test_info, result): + if result: + log_info("# " + test_info + " == test PASSED == end") + else: + log_error("# " + test_info + " == test FAILED == end") + + +def test_frame_node(): + test_begin("test_frame_node") + node_str = (" nodeId: 0, parentId: -1, tag: root, monopolizeEvents: 0, isHit: 1, hitTestMode: 0, responseRegion: " + "RectT (0.00, 0.00) - [720.00 x 1280.00]\n") + frame_node = FrameNode(node_str) + frame_node.dump() + test_end("test_frame_node", frame_node.is_succeed()) + + +def test_touch_point(): + test_begin("test_touch_point") + touch_point_str = ( + "id: 0, point: (123.12, 56.00), screenPoint: (45.00, 280.30), type: down, timestamp: 2017-08-25 15:00:22.295, " + "isInjected: 0\n") + touch_point = TouchPoint(touch_point_str) + touch_point.dump() + test_end("test_touch_point", touch_point.is_succeed()) + + +def test_procedure_step(): + test_begin("test_procedure_step") + procedure_step_str = "procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.295" + procedure_step = ProcedureStep(procedure_step_str) + procedure_step.dump() + test_end("test_procedure_step", procedure_step.is_succeed()) + + +def test_state_history(): + test_begin("test_state_history") + state_history = "stateHistory:\n" + \ + " procedure: HandleTouchDown, timestamp: 2017-08-20 15:00:22.247\n" + \ + " procedure: HandleTouchUp, timestamp: 2017-08-20 15:00:22.295\n" + state_history = StateHistory(state_history) + state_history.dump() + test_end("test_state_history", state_history.is_succeed()) + + +def test_event_node(): + test_begin("test_event_node") + event_node_str = ( + "frameNodeId: 88, type: LongPressRecognizer, depth: 1, id: 0xef748aa0, parentId: 0xf063eed0, customInfo: " + "duration: 500, isForDrag: 0, repeat: 0, fingers: 1\n" + "stateHistory:\n" + " procedure: HandleTouchDown, timestamp: 2017-08-25 15:00:22.247\n" + " procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.295\n") + event_node = EventNode(event_node_str) + event_node.dump() + test_end("test_event_node", event_node.is_succeed()) + + +def test_event_scope(): + test_begin("test_event_scope") + event_scope_str = ("finger: 0\n" + " frameNodeId: 0, type: root, depth: 0, id: 0, parentId: -1\n" + " stateHistory:\n" + " procedure: HandleTouchDown, timestamp: 2017-08-25 15:00:22.247\n" + " procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.295\n" + " frameNodeId: 88, type: LongPressRecognizer, depth: 1, id: 0xef748aa0, parentId: " + "0xf063eed0, customInfo: duration: 500, isForDrag: 0, repeat: 0, fingers: 1\n" + " stateHistory:\n" + " procedure: HandleTouchDown, state: DETECTING, disposal: NONE, timestamp: 2017-08-25 " + "15:00:22.247\n" + " procedure: HandleTouchUp, state: FAIL, disposal: REJECT, timestamp: 2017-08-25 " + "15:00:22.295\n") + event_scope = EventScope(event_scope_str) + event_scope.dump() + test_end("test_event_scope", event_scope.is_succeed()) + + +def test_event_procedures(): + test_begin("test_event_procedures") + event_procedures_str = ("extra text\n" + "finger: 0\n" + " frameNodeId: 0, type: root, depth: 0, id: 0, parentId: -1\n" + " stateHistory:\n" + " procedure: HandleTouchDown, timestamp: 2017-08-25 15:00:22.247\n" + " procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.295\n" + " frameNodeId: 88, type: LongPressRecognizer, depth: 1, id: 0xef748aa0, parentId: " + "0xf063eed0, customInfo: duration: 500, isForDrag: 0, repeat: 0, fingers: 1\n" + " stateHistory:\n" + " procedure: HandleTouchDown, state: DETECTING, disposal: NONE, timestamp: 2017-08-25 " + "15:00:22.247\n" + " procedure: HandleTouchUp, state: FAIL, disposal: REJECT, timestamp: 2017-08-25 " + "15:00:22.295\n" + "finger: 1\n" + " frameNodeId: 22, type: root, depth: 0, id: 0, parentId: -1\n" + " stateHistory:\n" + " procedure: HandleTouchDown, timestamp: 2017-08-25 15:00:22.247\n" + " procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.295\n" + " frameNodeId: 66, type: LongPressRecognizer, depth: 3, id: 0xef748aa0, parentId: " + "0xf063eed0, customInfo: duration: 500, isForDrag: 0, repeat: 0, fingers: 1\n" + " stateHistory:\n" + " procedure: HandleTouchDown, state: DETECTING, disposal: NONE, timestamp: 2017-08-25 " + "15:00:22.247\n" + " procedure: HandleTouchUp, state: FAIL, disposal: REJECT, timestamp: 2017-08-25 " + "15:00:22.295\n" + "hello world") + event_procedures = EventProcedures(event_procedures_str) + event_procedures.dump() + test_end("test_event_procedures", event_procedures.is_succeed()) + + +def test_event_tree(): + test_begin("test_event_tree") + event_tree_str = ("1: event tree =>\n" + " touch points:\n" + " id: 0, point: Offset (288.00, 530.00), screenPoint: Offset (288.00, 530.00), " + "type: TouchDown, timestamp: 2017-08-25 15:00:22.043, isInjected: 0\n" + " id: 0, point: Offset (288.00, 536.00), screenPoint: Offset (288.00, 536.00), type: TouchUp, " + "timestamp: 2017-08-25 15:00:22.130, isInjected: 0\n" + " hittest:\n" + " nodeId: 0, parentId: -1, tag: root, monopolizeEvents: 0, isHit: 1, hitTestMode: 0, " + "responseRegion: RectT (0.00, 0.00) - [720.00 x 1280.00]\n" + " nodeId: 1, parentId: 0, tag: stage, monopolizeEvents: 0, isHit: 1, hitTestMode: 0, " + "responseRegion: RectT (0.00, 0.00) - [720.00 x 1280.00]\n" + " event procedures:\n" + " finger:0\n" + " frameNodeId: 84, type: TouchEventActuator, depth: 0, id: 0xf072b240, parentId: 0x0\n" + " stateHistory:\n" + " procedure: HandleTouchDown, timestamp: 2017-08-25 15:00:22.046\n" + " procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.130\n" + " frameNodeId: 84, type: ExclusiveRecognizer, depth: 0, id: 0xf063eed0, parentId: 0x0\n" + " stateHistory:\n" + " procedure: HandleTouchDown, state: READY, disposal: NONE, timestamp: 2017-08-25 " + "15:00:22.046\n" + " procedure: HandleTouchUp, state: FAIL, disposal: REJECT, timestamp: 2017-08-25 " + "15:00:22.131\n" + "2: event tree =>\n") + event_tree = EventTree(event_tree_str) + event_tree.dump() + test_end("test_event_tree", event_tree.is_succeed()) + + +if __name__ == '__main__': + test_frame_node() + test_touch_point() + test_procedure_step() + test_state_history() + test_event_node() + test_event_scope() + test_event_procedures() + test_event_tree() diff --git a/test/tools/event_tree_to_graph/src/test/keyword_test.py b/test/tools/event_tree_to_graph/src/test/keyword_test.py new file mode 100644 index 00000000000..9b29e6409a7 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/test/keyword_test.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from src.keywords import KeyValueSample + + +# 2: event tree => +# touch points: +# id: 0, point: Offset (278.00, 551.00), screenPoint: Offset (278.00, 551.00), type: TouchDown, timestamp: 2017-08-25 15:00:22.244, isInjected: 0 +# id: 0, point: Offset (278.00, 551.00), screenPoint: Offset (278.00, 551.00), type: TouchUp, timestamp: 2017-08-25 15:00:22.295, isInjected: 0 +# hittest: +# nodeId: 0, parentId: -1, tag: root, monopolizeEvents: 0, isHit: 1, hitTestMode: 0, responseRegion: RectT (0.00, 0.00) - [720.00 x 1280.00] +# nodeId: 1, parentId: 0, tag: stage, monopolizeEvents: 0, isHit: 1, hitTestMode: 0, responseRegion: RectT (0.00, 0.00) - [720.00 x 1280.00] +# event procedures: +# finger:0 +# frameNodeId: 84, type: TouchEventActuator, depth: 0, id: 0xf072b240, parentId: 0x0 +# stateHistory: +# procedure: HandleTouchDown, timestamp: 2017-08-25 15:00:22.247 +# procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.295 +# finger:1 +# frameNodeId: 84, type: TouchEventActuator, depth: 0, id: 0xf072b240, parentId: 0x0 +# stateHistory: +# procedure: HandleTouchDown, timestamp: 2017-08-25 15:00:22.247 +# procedure: HandleTouchUp, timestamp: 2017-08-25 15:00:22.295 +if __name__ == '__main__': + KeyValueSample("touch points:") + KeyValueSample("id: 0") + KeyValueSample("screenPoint: Offset (278.00, 551.00)") + KeyValueSample("responseRegion: RectT (0.00, 0.00) - [720.00 x 1280.00]") diff --git a/test/tools/event_tree_to_graph/src/utils/__init__.py b/test/tools/event_tree_to_graph/src/utils/__init__.py new file mode 100644 index 00000000000..f4a09b9384d --- /dev/null +++ b/test/tools/event_tree_to_graph/src/utils/__init__.py @@ -0,0 +1,17 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# \ No newline at end of file diff --git a/test/tools/event_tree_to_graph/src/utils/log_wrapper.py b/test/tools/event_tree_to_graph/src/utils/log_wrapper.py new file mode 100644 index 00000000000..4d6363e377f --- /dev/null +++ b/test/tools/event_tree_to_graph/src/utils/log_wrapper.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import logging +from logging import handlers + + +class LogWrapper: + logger = None + + # log levels definition + log_levels = { + 'debug': logging.DEBUG, + 'info': logging.INFO, + 'warning': logging.WARNING, + 'error': logging.ERROR, + 'critical': logging.CRITICAL + } + + def __init__(self): + self.logger = logging.getLogger('log.txt') + self.logger.setLevel(self.log_levels['debug']) + # max 1M + file_handler = handlers.RotatingFileHandler(filename='log.txt', maxBytes=1 * 1024 * 1024, backupCount=3, + encoding='utf-8') + format_str = logging.Formatter('%(asctime)s - %(levelname)s: %(message)s') + file_handler.setFormatter(format_str) + self.logger.addHandler(file_handler) + console_handler = logging.StreamHandler() + console_handler.setFormatter(format_str) + self.logger.addHandler(console_handler) + + +logWrapper = LogWrapper() + + +def log_debug(msg): + logWrapper.logger.debug(msg) + + +def log_info(msg): + logWrapper.logger.info(msg) + + +def log_warning(msg): + logWrapper.logger.warning(msg) + + +def log_error(msg): + logWrapper.logger.error(msg) + + +def log_critical(msg): + logWrapper.logger.critical(msg) diff --git a/test/tools/event_tree_to_graph/src/utils/value_parser.py b/test/tools/event_tree_to_graph/src/utils/value_parser.py new file mode 100644 index 00000000000..1e327f94505 --- /dev/null +++ b/test/tools/event_tree_to_graph/src/utils/value_parser.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- + +# +# Copyright (c) 2024 Huawei Device Co., Ltd. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +def get_sub_str(input_str, keyword, value_separator_count=0, is_last=False): + if input_str is None or keyword is None: + return None + index = input_str.find(keyword) + if index == -1: + return None + start_index = index + len(keyword) + if is_last: + end_index = input_str.find("\n", start_index) + if end_index == -1: + end_index = len(input_str) + else: + if value_separator_count == 0: + end_index = input_str.find(",", start_index) + if end_index == -1: + # we are reaching the end + end_index = len(input_str) + else: + # 查找 value_separator_count 数量的逗号 + temp_start_index = start_index + for i in range(value_separator_count): + temp_start_index = input_str.find(",", temp_start_index) + 1 + end_index = input_str.find(",", temp_start_index) + if end_index == -1: + print("no result for ", keyword, " in input string: ", input_str) + return None + sub_str = input_str[start_index:end_index] + return sub_str + + +# 从给定的字符串中查找给定的关键字,并将该关键字后面直到逗号或行尾之前的内容转换为数字之后返回 +# value_separator_count: the count of comma in value +def get_value_as_int(input_str, keyword, value_separator_count=0, is_last=False): + sub_str = get_sub_str(input_str, keyword, value_separator_count, is_last) + if sub_str is None: + return None + return int(sub_str) + + +def get_value_as_float(input_str, keyword, value_separator_count=0, is_last=False): + sub_str = get_sub_str(input_str, keyword, value_separator_count, is_last) + if sub_str is None: + return None + return float(sub_str) + +def get_value_as_str(input_str, keyword, value_separator_count=0, is_last=False): + sub_str = get_sub_str(input_str, keyword, value_separator_count, is_last) + if sub_str is None: + return None + return sub_str + + +def pack_string_until_next_keyword(texts, start_index, start_keyword, end_keywords): + if texts is None or start_keyword is None or end_keywords is None: + return None + if len(texts) == 0 or len(start_keyword) == 0 or len(end_keywords) == 0: + return None + if start_index < 0 or start_index >= len(texts): + return None + current_index = 0 + pack_result = "" + is_start_found = False + for line in texts: + if current_index < start_index: + current_index += 1 + continue + reach_end = False + line = line.rstrip("\n") + if (is_start_found == False) and line.find(start_keyword) != -1: + is_start_found = True + pack_result = line + current_index += 1 + continue + for keyword in end_keywords: + if line.find(keyword) != -1: + reach_end = True + break + if reach_end: + break + pack_result += "\n" + line + current_index += 1 + return [pack_result, current_index] -- Gitee