| #!/usr/bin/env python3 |
| # -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*- |
| # |
| # This file is part of the LibreOffice project. |
| # |
| # This Source Code Form is subject to the terms of the Mozilla Public |
| # License, v. 2.0. If a copy of the MPL was not distributed with this |
| # file, You can obtain one at http://mozilla.org/MPL/2.0/. |
| # |
| |
| import os |
| import sys |
| import argparse |
| |
| def parse_line(line): |
| """ |
| This function parses a line from log file |
| and returns the parsed values as a python dictionary |
| """ |
| if (line == ""): |
| return |
| dict = {} |
| if "{" in line: |
| start_index_of_parameters = line.find("{") |
| end_index_of_parameters = line.find("}") + 1 |
| parameters = line[start_index_of_parameters:end_index_of_parameters] |
| if parameters != "": |
| dict["parameters"] = parameters |
| line = line[:start_index_of_parameters-1] |
| word_list = line.split() |
| dict["keyword"] = word_list[0] |
| |
| for index in range(1,len(word_list)): |
| key, val = word_list[index].split(":",1) |
| dict[key] = val |
| return dict |
| |
| def parse_args(): |
| """ |
| This function parses the command-line arguments |
| to get the input and output file details |
| """ |
| parser = argparse.ArgumentParser(description = "Generate a UI test file from log") |
| parser.add_argument("input_address", type = str, help = "The log file address") |
| parser.add_argument("output_address", type = str, help = "The test file address") |
| parser.add_argument("-d", "--document", metavar = "", help = "Address of the document to be opened") |
| args = parser.parse_args() |
| return args |
| |
| def get_log_file(input_address): |
| try: |
| with open(input_address) as f: |
| content = f.readlines() |
| except IOError as err: |
| print("IO error: {0}".format(err)) |
| print("Use " + os.path.basename(sys.argv[0]) + " -h to get usage instructions") |
| sys.exit(1) |
| |
| content = [x.strip() for x in content if not x.startswith("Action on element")] |
| return content |
| |
| def initiate_test_generation(address): |
| try: |
| f = open(address,"w") |
| except IOError as err: |
| print("IO error: {0}".format(err)) |
| print("Use " + os.path.basename(sys.argv[0]) + " -h to get usage instructions") |
| sys.exit(1) |
| initial_text = \ |
| "# -*- tab-width: 4; indent-tabs-mode: nil; py-indent-offset: 4 -*-\n\n" + \ |
| "from uitest.framework import UITestCase\n" + \ |
| "from libreoffice.uno.propertyvalue import mkPropertyValues\n" + \ |
| "import importlib\n\n" + \ |
| "class TestClass(UITestCase):\n" + \ |
| " def test_function(self):\n" |
| f.write(initial_text) |
| return f |
| |
| def get_coupling_type(line1, line2): |
| """ |
| This function checks if two consecutive lines of log file |
| refer to the same event |
| """ |
| action_dict1 = parse_line(line1) |
| action_dict2 = parse_line(line2) |
| |
| if action_dict1["keyword"] == "CommandSent" and \ |
| action_dict2["keyword"] == "ModalDialogExecuted": |
| return "COMMAND_MODAL_COUPLE" |
| |
| elif action_dict1["keyword"] == "CommandSent" and \ |
| action_dict2["keyword"] == "ModelessDialogConstructed": |
| return "COMMAND_MODELESS_COUPLE" |
| |
| elif action_dict1["keyword"] == "ButtonUIObject" and \ |
| action_dict2["keyword"] == "DialogClosed": |
| return "BUTTON_DIALOGCLOSE_COUPLE" |
| |
| elif "parameters" in action_dict1 and \ |
| "KEYCODE" in action_dict1["parameters"] and \ |
| action_dict2["keyword"] == "CommandSent": |
| return "REDUNDANT_COUPLE" |
| |
| return "NOT_A_COUPLE" |
| |
| def check_app_starting_action(action_dict): |
| app_starter_button_ids = \ |
| set(["draw_all", "impress_all", "calc_all" , "writer_all", "database_all", "math_all"]) |
| |
| if action_dict["keyword"] == "ButtonUIObject" and action_dict["Action"] == "CLICK" and \ |
| action_dict["Id"] in app_starter_button_ids: |
| return True |
| return False |
| |
| def get_test_line_from_one_log_line(log_line): |
| action_dict = parse_line(log_line) |
| test_line = " " |
| if action_dict["keyword"].endswith("UIObject"): |
| parent = action_dict["Parent"] |
| if (check_app_starting_action(action_dict)): |
| test_line +=\ |
| "MainDoc = self.ui_test.create_doc_in_start_center(\"" + \ |
| action_dict["Id"][:-4] +"\")\n MainWindow = " + \ |
| "self.xUITest.getTopFocusWindow()\n" |
| return test_line |
| else: |
| if (parent == ""): |
| parent = "MainWindow" |
| test_line += \ |
| action_dict["Id"] + " = " + parent + ".getChild(\"" + \ |
| action_dict["Id"] + "\")\n " + \ |
| action_dict["Id"] + ".executeAction(\"" + \ |
| action_dict["Action"] + "\"" |
| if "parameters" in action_dict: |
| test_line += ", mkPropertyValues(" + \ |
| action_dict["parameters"] + "))\n" |
| else: |
| test_line += ",tuple())\n" |
| return test_line |
| elif action_dict["keyword"] == "CommandSent": |
| if "parameters" not in action_dict: |
| test_line += "self.xUITest.executeCommand(\"" + \ |
| action_dict["Name"] + "\")\n" |
| return test_line |
| else: |
| test_line += "self.xUITest.executeCommandWithParameters(\"" + \ |
| action_dict["Name"] + "\", mkPropertyValues(" + action_dict["parameters"] + \ |
| "))\n" |
| return test_line |
| elif action_dict["keyword"] == "ModalDialogExecuted" or \ |
| action_dict["keyword"] == "ModelessDialogConstructed": |
| test_line += action_dict["Id"] + " = " + "self.xUITest.getTopFocusWindow()\n" |
| return test_line |
| |
| return "" |
| |
| def get_test_line_from_two_log_lines(log_line1,log_line2): |
| coupling_type = get_coupling_type(log_line1, log_line2) |
| action_dict1 = parse_line(log_line1) |
| action_dict2 = parse_line(log_line2) |
| test_line = " " |
| if coupling_type == "COMMAND_MODAL_COUPLE": |
| test_line += \ |
| "self.ui_test.execute_dialog_through_command(\"" + \ |
| action_dict1["Name"] + "\")\n " + \ |
| action_dict2["Id"] + " = self.xUITest.getTopFocusWindow()\n" |
| elif coupling_type == "COMMAND_MODELESS_COUPLE": |
| test_line += \ |
| "self.ui_test.execute_modeless_dialog_through_command(\"" + \ |
| action_dict1["Name"] + "\")\n " + \ |
| action_dict2["Id"] + " = self.xUITest.getTopFocusWindow()\n" |
| elif coupling_type == "BUTTON_DIALOGCLOSE_COUPLE": |
| test_line += \ |
| action_dict1["Id"] + " = " + action_dict1["Parent"] + ".getChild(\"" + \ |
| action_dict1["Id"] + "\")\n self.ui_test.close_dialog_through_button(" + \ |
| action_dict1["Id"] + ")\n" |
| return test_line |
| |
| def main(): |
| args = parse_args() |
| log_lines = get_log_file(args.input_address) |
| output_stream = initiate_test_generation(args.output_address) |
| if args.document is not None: |
| output_line = " pathmodule = importlib.import_module(\"uitest.path\")\n" + \ |
| " doc_path = pathmodule.get_srcdir_url() + \"" + args.document + "\"\n" + \ |
| " MainDoc = self.ui_test.load_file(doc_path)\n" + \ |
| " MainWindow = self.xUITest.getTopFocusWindow()\n" |
| output_stream.write(output_line) |
| line_number = 0 |
| while line_number < len(log_lines): |
| if line_number == len(log_lines)-1 or \ |
| get_coupling_type(log_lines[line_number],log_lines[line_number + 1]) == "NOT_A_COUPLE": |
| test_line = get_test_line_from_one_log_line(log_lines[line_number]) |
| output_stream.write(test_line) |
| line_number += 1 |
| elif get_coupling_type(log_lines[line_number],log_lines[line_number + 1]) == "REDUNDANT_COUPLE": |
| line_number += 1 |
| else: |
| test_line = get_test_line_from_two_log_lines(log_lines[line_number],log_lines[line_number + 1]) |
| output_stream.write(test_line) |
| line_number += 2 |
| output_stream.write(" self.ui_test.close_doc()") |
| output_stream.write("\n\n# vim: set shiftwidth=4 softtabstop=4 expandtab:") |
| output_stream.close() |
| |
| if __name__ == '__main__': |
| main() |
| |
| # vim: set shiftwidth=4 softtabstop=4 expandtab: |