From 23c3002873a87b3e1bb06fa92b5e93779a5bb712 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20M=C3=B6slinger?= <dominik.moeslinger@univie.ac.at> Date: Thu, 19 Aug 2021 07:56:57 +0200 Subject: [PATCH] TST: Json to Csv converter implemented Json to small script generator implemeted loading test specs implemented unsaved changes question implemented Adding IASW Version --- .gitignore | 3 + Ccs/editor.py | 11 +- Ccs/getting_started.py | 1 - Tst/json_to_barescript.py | 77 ++-- Tst/json_to_csv.py | 54 ++- Tst/progress_view/progress_view.py | 47 ++- Tst/spec_to_json.py | 25 +- .../testlib/analyse_command_log.py | 5 +- .../testlib/analyse_test_run.py | 42 +- .../testlib/analyse_verification_log.py | 2 +- Tst/testing_library/testlib/report.py | 19 +- Tst/tst/data_model.py | 44 ++- Tst/tst/file_management.py | 5 + Tst/tst/generator.py | 5 +- Tst/tst/generator_templates/co_class.py | 6 +- .../generator_templates/co_pre_condition.py | 5 +- Tst/tst/generator_templates/ver_class.py | 4 +- Tst/tst/tst.py | 360 +++++++++++++++--- Tst/tst/view.py | 56 ++- Tst/tst_template_empty.json | 4 +- 20 files changed, 571 insertions(+), 204 deletions(-) diff --git a/.gitignore b/.gitignore index 1412f3b..c6169d2 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,9 @@ /Tst/tst/install-sh /Tst/tst/missing /Tst/tst/tst.desktop +/Tst/confignator/confignator/confignator.log +/Tst/test_specs/ +/Tst/logs_test_runs/ ### Example user template !.gitkeep diff --git a/Ccs/editor.py b/Ccs/editor.py index 6b3af4c..586f48b 100644 --- a/Ccs/editor.py +++ b/Ccs/editor.py @@ -1015,6 +1015,7 @@ class CcsEditor(Gtk.Window): def _check_unsaved_buffers(self): for page in self.editor_notebook: label = self.editor_notebook.get_tab_label(page).get_children()[0] + save_as = False if label.get_text()[0] == '*': ask = UnsavedBufferDialog(parent=self, msg='Unsaved changes in {}. Save?'.format(label.get_text()[1:])) response = ask.run() @@ -1022,13 +1023,19 @@ class CcsEditor(Gtk.Window): if response == Gtk.ResponseType.YES: buf = page.get_child().get_buffer() text = buf.get_text(*buf.get_bounds(), True) - with open(label.get_tooltip_text(), 'w') as fdesc: - fdesc.write(text) + if label.get_tooltip_text(): + with open(label.get_tooltip_text(), 'w') as fdesc: + fdesc.write(text) + else: + save_as = True elif response == Gtk.ResponseType.CANCEL: ask.destroy() return False ask.destroy() + if save_as: + self.on_menu_file_saveas(label=label) + return True """ save the buffer and reconnect the "changed" signal signal """ diff --git a/Ccs/getting_started.py b/Ccs/getting_started.py index e840c1a..b0c1500 100644 --- a/Ccs/getting_started.py +++ b/Ccs/getting_started.py @@ -1,4 +1,3 @@ - # This File gives a basic overview on the most important Functions to use the CCS # If it is not already running start the ccs.py file, this file will appear there automatically diff --git a/Tst/json_to_barescript.py b/Tst/json_to_barescript.py index 48cb0e2..7ca49e2 100755 --- a/Tst/json_to_barescript.py +++ b/Tst/json_to_barescript.py @@ -1,40 +1,67 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 +""" +Generates a small Test Script from an existing json Test Specification, mostly used during internal testing and +debugging Process, For the real tests the more extensive Test Scripts are generated by the TST (included logging, +step id, run id,...) +author: Marko Mecina +date: 01.08.2021 +edited: Dominik Möslinger +""" import datetime +import os import json import sys -jfile = sys.argv[1] -# = 'IASW-FFT-1-TS-1.csv.json' -data = json.load(open(jfile, 'r')) -date = datetime.datetime.now().strftime('%Y-%m-%d') +def run(jfile, outfile): + data = json.load(open(jfile, 'r')) + date = datetime.datetime.now().strftime('%Y-%m-%d') -script = '' + script = '' -script += '#--------------------------------------------\n' -script += '# ' + data['_name'] + '\n' -script += '# ' + data['_description'] + '\n' -script += '# Version: ' + data['_version'] + '\n' -script += '# Author: UVIE\n# Date: {}\n'.format(date) -script += '#--------------------------------------------\n\n\n' + script += '#--------------------------------------------\n' + script += '# ' + data['_name'] + '\n' + script += '# ' + data['_description'] + '\n' + script += '# Specification Version: ' + data['_spec_version'] + '\n' + script += '# Software Version: ' + data['sw_version'] + '\n' + script += '# Author: UVIE\n# Date: {}\n'.format(date) + script += '#--------------------------------------------\n\n\n' -script += '# Precond.\n# {}\n\n\n'.format(data['_precon_descr']) + script += '# Precond.\n# {}\n'.format(data['_precon_descr']) + # script += '{}\n\n\n'.format(data['_precon_code'].strip()) # Add the precondition code -for step in data['sequences'][0]['steps']: - comment = '# COMMENT: {}\n'.format(step['_step_comment'].strip()) if step['_step_comment'] != '' else '' + for step in data['sequences'][0]['steps']: + comment = '# COMMENT: {}\n'.format(step['_step_comment'].strip()) if step['_step_comment'] != '' else '' - txt = '# STEP {}\n' \ - '# {}\n' \ - '{}\n' \ - '# VERIFICATION: {}\n{}\n\n'.format(step['_step_number'], step['_description'].strip(), step['_command_code'].strip(), step['_verification_description'].strip(), comment) + txt = '# STEP {}\n' \ + '# {}\n' \ + '{}\n' \ + '# VERIFICATION: {}\n{}\n\n'.format(step['_step_number'], step['_description'].strip(), + step['_command_code'].strip(), + step['_verification_description'].strip(), + # step['_verification_code'].strip(), # Add verification code + comment) - script += txt + script += txt -script += '# Postcond.\n# {}\n'.format(data['_postcon_descr']) + script += '# Postcond.\n# {}\n'.format(data['_postcon_descr']) + # script += data['_postcon_code'].strip() # Add the postcondition code -outpath = '/'.join(jfile.split('/')[:-1]) + '/' -outfile = outpath + data['_name'] + '-' + '-'.join(data['_version'].split('-')[-2:]) + '.py' + if outfile[-1] == '/': # If path is given not the actual filename + outfile = outfile + data['_name'] + '-TS' + '-'.join(data['_spec_version']) + '.py' -with open(outfile, 'w') as fd: - fd.write(script) + with open(outfile, 'w') as fd: + fd.write(script) + + +if __name__ == '__main__': + json_file_path = sys.argv[1] + + if len(sys.argv) > 1: # If filename is given + outputfile = sys.argv[2] + else: # If no filename is given take the working directory path, filename is used from the json file + outputfile = os.getcwd() + '/' + #outputfile = '/'.join(json_file_path[:-len(json_file_path.split('/')[-1])-1]) + '/' # This would take the json File path + + run(json_file_path, outputfile) diff --git a/Tst/json_to_csv.py b/Tst/json_to_csv.py index 33a044c..3243f68 100755 --- a/Tst/json_to_csv.py +++ b/Tst/json_to_csv.py @@ -2,34 +2,46 @@ import datetime import json +import os import sys -jfile = sys.argv[1] -# = 'IASW-FFT-1-TS-1.csv.json' +def run(jfile, outfile): -data = json.load(open(jfile, 'r')) + data = json.load(open(jfile, 'r')) -header = 'Item|Description|Verification|TestResult' -name = '{}|{}|Test spec. version: {}|'.format(data['_name'], data['_description'], data['_version']) -date = 'Date||{}|'.format(datetime.datetime.now().strftime('%Y-%m-%d')) -precond = 'Precond.|{}||'.format(data['_precon_descr']) -postcond = 'Postcond.|{}||'.format(data['_postcon_descr']) -steps = [] + header = 'Item|Description|Verification|TestResult' + name = '{}|{}|Test spec. version: {}| IASW-{}'.format(data['_name'], data['_description'], data['_spec_version'], data['_sw_version']) + # Date from last time the json file was changed + current date + date = 'Date||{}|{}'.format(datetime.datetime.strftime(datetime.datetime.fromtimestamp(os.stat(jfile).st_mtime), '%Y-%m-%d'), datetime.datetime.now().strftime('%Y-%m-%d')) + precond = 'Precond.|{}||'.format(data['_precon_descr']) + postcond = 'Postcond.|{}||'.format(data['_postcon_descr']) + steps = [] -for step in data['sequences'][0]['steps']: + for step in data['sequences'][0]['steps']: - line = 'Step {}|{}|{}|'.format(step['_step_number'], step['_description'], step['_verification_description']) - steps.append(line) + line = 'Step {}|{}|{}|'.format(step['_step_number'], step['_description'], step['_verification_description']) + steps.append(line) - if step['_step_comment'] != '': - comment = 'Comment|{}||'.format(step['_step_comment']) - steps.append(comment) + if step['_step_comment'] != '': + comment = 'Comment|{}||'.format(step['_step_comment']) + steps.append(comment) + if outfile[-1] == '/': # If only path is given but no filename + outfile = outfile + data['_name'] + '-' + '-'.join(data['_spec_version'].split('-')[-2:]) + '.csv_PIPE' -outpath = '/'.join(jfile.split('/')[:-1]) + '/' -outfile = outpath + data['_name'] + '-' + '-'.join(data['_version'].split('-')[-2:]) + '.csv_PIPE' + with open(outfile, 'w') as fd: + buf = '\n'.join([header, name, date, precond] + steps + [postcond]) + buf = buf.replace('_', '\\_') + fd.write(buf) -with open(outfile, 'w') as fd: - buf = '\n'.join([header, name, date, precond] + steps + [postcond]) - buf = buf.replace('_', '\\_') - fd.write(buf) + +if __name__ == '__main__': + json_file_path = sys.argv[1] + + if len(sys.argv) > 1: # If filename is given + outputfile = sys.argv[2] + else: # If no filename is given take the working directory path, filename is used from the json file + outputfile = os.getcwd() + '/' + # outputfile = '/'.join(json_file_path[:-len(json_file_path.split('/')[-1])-1]) + '/' # This would take the json File path + + run(json_file_path, outputfile) diff --git a/Tst/progress_view/progress_view.py b/Tst/progress_view/progress_view.py index 2eb9336..f17d756 100644 --- a/Tst/progress_view/progress_view.py +++ b/Tst/progress_view/progress_view.py @@ -228,6 +228,7 @@ class TestProgressView(Gtk.ApplicationWindow): self.resize( int(confignator.get_option(section='progress-viewer-window-size', option='basic-width-step-mode')), int(confignator.get_option(section='progress-viewer-window-size', option='basic-height'))) + self.sort_button.set_active(True) self.show_all() logger.debug('__init__ succeeded') @@ -292,7 +293,6 @@ class TestProgressView(Gtk.ApplicationWindow): self.sort_button = Gtk.Switch() self.sort_button.connect("notify::active", self.on_remake_treeview) - self.sort_button.set_active(True) self.box_buttons.pack_end(self.sort_button, False, True, 0) self.sort_label2 = Gtk.Label() @@ -341,7 +341,7 @@ class TestProgressView(Gtk.ApplicationWindow): # column 4 renderer_cmd_version = Gtk.CellRendererText(xalign=0.5) - column_cmd_version = Gtk.TreeViewColumn('Version', renderer_cmd_version, text=3, background=7) + column_cmd_version = Gtk.TreeViewColumn('Spec. Version', renderer_cmd_version, text=3, background=7) column_cmd_version.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) column_cmd_version.set_resizable(True) column_cmd_version.set_min_width(50) @@ -607,7 +607,7 @@ class TestProgressView(Gtk.ApplicationWindow): if not test_name and self.path_json: test_name = self.path_json.split('/')[-1].split('.')[0] - dialog = Save_to_File_Dialog(parent=self) + dialog = Save_to_File_Dialog(parent=self) # Look were the output file should be saved and which files (log, json) should be used response = dialog.run() if response == Gtk.ResponseType.OK: if not test_name: @@ -623,7 +623,7 @@ class TestProgressView(Gtk.ApplicationWindow): sent_run_id = None if run_count: for run_id in self.run_count.keys(): - if self.run_count[run_id] == run_count: + if self.run_count[run_id] == str(run_count): sent_run_id = run_id if not log_file_path: if not dialog.log_file_path_check.get_active(): @@ -641,7 +641,7 @@ class TestProgressView(Gtk.ApplicationWindow): return dialog.destroy() - if log_file_path == 'FIND': + if log_file_path == 'FIND': # Get the log file path if they are not already given dialog = File_Path_Dialog(parent=self, file='Command or Verification Log File', is_json=False) response = dialog.run() if response == Gtk.ResponseType.OK: @@ -651,7 +651,7 @@ class TestProgressView(Gtk.ApplicationWindow): return dialog.destroy() - if json_file_path == 'FIND': + if json_file_path == 'FIND': # Get the json file if it is not already given dialog = File_Path_Dialog(parent=self, file='the Json File', is_json=True) response = dialog.run() if response == Gtk.ResponseType.OK: @@ -674,7 +674,7 @@ class TestProgressView(Gtk.ApplicationWindow): # ------------------- model functions ---------------------- @staticmethod - def build_row_list(row=None, step_number=None, exec_date=None, entry_type=None, version=None, status=None, tcs=None, + def build_row_list(row=None, step_number=None, exec_date=None, entry_type=None, spec_version=None, status=None, tcs=None, result=None, step_desc=None, tooltip_text=None, exec_int=None, exec_desc=None, sort_button_active=False): """ Builds or updates a row of the TreeStore. For a new row, the argument 'row' is expected to be None. @@ -682,7 +682,7 @@ class TestProgressView(Gtk.ApplicationWindow): :param str step_number: :param datetime.datetime exec_date: :param str entry_type: - :param str version: + :param str spec_version: :param str status: :param str tcs: :param boolean result: @@ -729,8 +729,8 @@ class TestProgressView(Gtk.ApplicationWindow): row[1] = exec_date if entry_type is not None: row[2] = entry_type - if version is not None: - row[3] = version + if spec_version is not None: + row[3] = spec_version if status is not None: row[4] = status if tcs is not None: @@ -747,7 +747,7 @@ class TestProgressView(Gtk.ApplicationWindow): step_number, exec_date, entry_type, - version, + spec_version, status, tcs, result_value, @@ -763,7 +763,7 @@ class TestProgressView(Gtk.ApplicationWindow): step_number, exec_date, entry_type, - version, + spec_version, status, tcs, result_value, @@ -907,7 +907,7 @@ class TestProgressView(Gtk.ApplicationWindow): # for item in row.iterchildren(): # if item[2] == 'specification': # tree_store.remove(item.iter) - # # add a row for (**each version of**) the step specification + # # add a row for (**each spec version of**) the step specification # for row in tree_store: # step_number_tree_store = int(row[0:1][0]) # for key in test_model.steps_dict: @@ -1014,7 +1014,7 @@ class TestProgressView(Gtk.ApplicationWindow): for item in cmd_steps: if item['run_id'] == exec_num and item['step'] == step_num: new_row_list = self.build_row_list(entry_type='command', - version=item['version'], + spec_version=item['spec_version'], exec_date=item['exec_date'], sort_button_active=self.sort_button.get_active(), tooltip_text=item['descr']) @@ -1085,7 +1085,7 @@ class TestProgressView(Gtk.ApplicationWindow): # # add a new row # if not already_exists: new_row_list = self.build_row_list(entry_type='command', - version=item['version'], + spec_version=item['spec_version'], exec_date=item['exec_date'], sort_button_active=self.sort_button.get_active(), tooltip_text=item['descr']) @@ -1196,7 +1196,7 @@ class TestProgressView(Gtk.ApplicationWindow): for item in vrc_steps: if item['run_id'] == exec_num and item['step'] == step_num: new_row_list = self.build_row_list(entry_type='verification', - version=item['version'], + spec_version=item['spec_version'], exec_date=item['exec_date'], sort_button_active=self.sort_button.get_active(), tooltip_text=item['descr']) @@ -1262,7 +1262,7 @@ class TestProgressView(Gtk.ApplicationWindow): # # add a new row # if not already_exists: new_row_list = self.build_row_list(entry_type='verification', - version=item['version'], + spec_version=item['spec_version'], exec_date=item['exec_date'], sort_button_active=self.sort_button.get_active(), tooltip_text=item['descr']) @@ -1295,11 +1295,12 @@ class Save_to_File_Dialog(Gtk.FileChooserDialog): def __init__(self, parent=None): super(Save_to_File_Dialog, self).__init__(title='Please choose a Folder to save the Test Run', parent=parent, - action=Gtk.FileChooserAction.SELECT_FOLDER) + action=Gtk.FileChooserAction.OPEN_FOLDER) self.win = parent self.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.OK) self.set_current_folder(confignator.get_option(section='tst-logging', option='output-file-path')) + #self.set_current_name('{}-IASW-{}TS-{}TR-{}'.format()) area = self.get_content_area() @@ -1343,11 +1344,17 @@ class Save_to_File_Dialog(Gtk.FileChooserDialog): if iter: # If a selection is made try to set it as active row, otherwise Whole file is active row selected_step_id = model.get_value(iter, 12) # Get the value if not selected_step_id: # Only execution rows ('Run X') have entry at coloumn 12, others dont - self.run_id_selection.set_active(0) + try: + self.run_id_selection.set_active(1) + except: + self.run_id_selection.set_active(0) else: self.run_id_selection.set_active(int(self.win.run_count[selected_step_id])) else: - self.run_id_selection.set_active(0) + try: + self.run_id_selection.set_active(1) + except: + self.run_id_selection.set_active(0) self.run_id_selection.set_tooltip_text('Define which Run should be saved or the whole Log File') test_report_label = Gtk.Label(label='Test Report: ') diff --git a/Tst/spec_to_json.py b/Tst/spec_to_json.py index bf33d3f..5b8aaf3 100755 --- a/Tst/spec_to_json.py +++ b/Tst/spec_to_json.py @@ -7,16 +7,20 @@ sys.path.append('../Ccs') import ccs_function_lib as cfl -def run(specfile, gen_cmd): +def run(specfile, gen_cmd, save_json): tmp = json.load(open('tst_template_empty.json', 'r')) jspec = tmp.copy() specs = open(specfile, 'r').read().split('\n') - name, descr, *_ = specs[1].split('|') + name, descr, spec_version_entry, sw_version_entry = specs[1].split('|') + spec_version = spec_version_entry.split('version: ')[-1] + sw_version = sw_version_entry.split('IASW-')[-1] jspec['_name'] = name jspec['_description'] = descr - jspec['_version'] = '' + jspec['_spec_version'] = spec_version + jspec['_sw_version'] = sw_version + jspec['_primary_counter_locked'] = False steps = jspec['sequences'][0]['steps'] step_temp = steps[0].copy() @@ -37,8 +41,10 @@ def run(specfile, gen_cmd): step['_step_comment'] = descr continue - step_temp['_step_number'] = n.replace('Step ', '') + '.0' - step_temp['_primary_counter'] = int(n.replace('Step ', '')) + step_num = n.replace('Step ', '') + step_temp['_step_number'] = step_num + step_temp['_primary_counter'] = int(step_num.split('.')[0]) + step_temp['_secondary_counter'] = int(step_num.split('.')[1]) step_temp['_description'] = descr step_temp['_verification_description'] = ver @@ -67,7 +73,11 @@ def run(specfile, gen_cmd): steps.append(step_temp.copy()) jspec['sequences'][0]['steps'] = steps - json.dump(jspec, open(specfile + '.json', 'w'), indent=4) + if save_json: + json.dump(jspec, open(specfile + '.json', 'w'), indent=4) + else: + json_data = json.dumps(jspec) + return jspec if __name__ == "__main__": @@ -78,4 +88,5 @@ if __name__ == "__main__": gen_cmd = True specfile = sys.argv[1] - run(specfile, gen_cmd) + save = True + run(specfile, gen_cmd, save) diff --git a/Tst/testing_library/testlib/analyse_command_log.py b/Tst/testing_library/testlib/analyse_command_log.py index d61d4ed..3fb6af5 100644 --- a/Tst/testing_library/testlib/analyse_command_log.py +++ b/Tst/testing_library/testlib/analyse_command_log.py @@ -114,7 +114,7 @@ def get_steps_and_commands(filename): steps_end = [] def new_step_template_start(): - return {'step': None, 'version': '', 'tcs': [], 'date': ''} + return {'step': None, 'spec_version': '', 'tcs': [], 'date': ''} def new_step_template_end(): return {'step': None, 'timestamp': '', 'step_id': ''} @@ -140,7 +140,8 @@ def get_steps_and_commands(filename): if step_start_info is not None: new_step['step'] = step_start_info['step'] new_step['start_timestamp'] = step_start_info['timestamp'] - new_step['version'] = step_start_info['version'] + new_step['spec_version'] = step_start_info['spec_version'] + new_step['iasw_version'] = step_start_info['iasw_version'] new_step['descr'] = step_start_info['descr'] new_step['run_id'] = step_start_info['run_id'] new_step['step_id'] = step_start_info['step_id'] diff --git a/Tst/testing_library/testlib/analyse_test_run.py b/Tst/testing_library/testlib/analyse_test_run.py index a64a7f8..e72bcc1 100644 --- a/Tst/testing_library/testlib/analyse_test_run.py +++ b/Tst/testing_library/testlib/analyse_test_run.py @@ -87,7 +87,7 @@ def save_result_to_file(test_name, log_file_path=None, output_file_path=None, js general_run_infos, precon_info, postcon_info = analyse_command_log.get_general_run_info(cmd_log_file, run_id=run_id) # Give the output file its name, consits of test name, the specification nbr (version) - name_start = '{}-TS-{}-TR-'.format(test_name, cmd_steps[0]['version']) + name_start = '{}-TS-{}-TR-'.format(test_name, cmd_steps[0]['spec_version']) # Check if output folder exists otherwise make it if not os.path.isdir(output_file_path): @@ -115,9 +115,9 @@ def save_result_to_file(test_name, log_file_path=None, output_file_path=None, js writer.writerow(output_file_header) # write the general info line, if multiple descriptions/versions are found all are written to the output file - version = get_version(cmd_steps, logger) + spec_version, iasw_version = get_version(cmd_steps, logger) description = get_general_run_info_info(general_run_infos, 'descr', logger) - writer.writerow([test_name, description, 'Test Spec. Version: ' + version, 'Test Rep. Version: ' + f'{test_report:03d}']) + writer.writerow([test_name, description, 'Test Spec. Version: ' + 'IASW-{}TS-{}'.format(iasw_version, spec_version), 'Test Rep. Version: ' + f'{test_report:03d}']) # write date line, first Date (Specification Date) is the last time the json file was changed or None if no json file was given # second Date (Execution Date), Is the execution Date of the first step @@ -182,21 +182,37 @@ def get_version(steps, logger): :param list of dicts steps: all the steps from the log file :return str version_final: A string that contains all found versions """ - version_list = [] - version_final = '' + spec_version_list = [] + spec_version_final = '' + iasw_version_list = [] + iasw_version_final = '' for step in steps: - if step['version'] not in version_list: - version_list.append(step['version']) - for count, version in enumerate(version_list): + if step['spec_version'] not in spec_version_list: + spec_version_list.append(step['spec_version']) + if step['iasw_version'] not in iasw_version_list: + iasw_version_list.append(step['iasw_version']) + + for count, version in enumerate(spec_version_list): if count == 0: - version_final = version + spec_version_final = version else: - version_final += ' / ' + version + spec_version_final += ' / ' + version if logger: - logger.warning('More than one Version was found in the command log File') + logger.warning('More than one Specification Version was found in the command log File') else: - print('More than one Version was found in the command log File') - return version_final + print('More than one Specification Version was found in the command log File') + + for count, version in enumerate(iasw_version_list): + if count == 0: + iasw_version_final = version + else: + iasw_version_final += ' / ' + version + if logger: + logger.warning('More than one IASW Version was found in the command log File') + else: + print('More than one IASW Version was found in the command log File') + + return spec_version_final, iasw_version_final def show_basic_results(test_name, log_file_path=None): """ diff --git a/Tst/testing_library/testlib/analyse_verification_log.py b/Tst/testing_library/testlib/analyse_verification_log.py index 1340f4b..75f9074 100644 --- a/Tst/testing_library/testlib/analyse_verification_log.py +++ b/Tst/testing_library/testlib/analyse_verification_log.py @@ -55,7 +55,7 @@ def get_verification_steps(filename): new_vrc_step['step'] = item['step'] new_vrc_step['start_timestamp'] = item['timestamp'] new_vrc_step['exec_date'] = item['exec_date'] - new_vrc_step['version'] = item['version'] + new_vrc_step['spec_version'] = item['spec_version'] new_vrc_step['vrc_descr'] = item['vrc_descr'] new_vrc_step['descr'] = item['descr'] new_vrc_step['run_id'] = item['run_id'] diff --git a/Tst/testing_library/testlib/report.py b/Tst/testing_library/testlib/report.py index ac6920e..f7abc97 100644 --- a/Tst/testing_library/testlib/report.py +++ b/Tst/testing_library/testlib/report.py @@ -49,7 +49,7 @@ def key_word_found(line, key_word): return found -def encode_to_json_string(step_number, timestamp, step_version=None, step_result=None, descr=None, run_id=None, step_id=None, comment=None, vrc_descr=None): +def encode_to_json_string(step_number, timestamp, spec_version=None, iasw_version=None, step_result=None, descr=None, run_id=None, step_id=None, comment=None, vrc_descr=None): """ Make a JSON string out of the step number and timestamp :param step_number: number of the step @@ -59,8 +59,10 @@ def encode_to_json_string(step_number, timestamp, step_version=None, step_result """ od = collections.OrderedDict([('step', step_number), ('timestamp', timestamp)]) - if step_version is not None: - od['version'] = step_version + if spec_version is not None: + od['spec_version'] = spec_version + if iasw_version is not None: + od['iasw_version'] = iasw_version if step_result is not None: od['result'] = step_result if vrc_descr is not None: @@ -110,12 +112,12 @@ def parse_step_from_json_string(line, key_word): logger.error('parse_tc_id_from_json_string: parsing of the TC JSON string failed!') -def command_step_begin(step_param, script_version, pool_name, step_start_cuc, run_id, step_id): +def command_step_begin(step_param, spec_version, iasw_version, pool_name, step_start_cuc, run_id, step_id): """ Builds a string and writes it into the logging file. A keyword is set to enable a machine read out of the log file. All information of the step is written in a JSON string. :param step_param: - :param script_version: + :param spec__version: :param pool_name: :param step_start_cuc: :return: @@ -125,7 +127,8 @@ def command_step_begin(step_param, script_version, pool_name, step_start_cuc, ru step_param['step_no'], encode_to_json_string(step_number=step_param['step_no'], timestamp=step_start_cuc, - step_version=script_version, + spec_version=spec_version, + iasw_version=iasw_version, run_id=run_id, step_id=step_id, descr=step_param['descr'], @@ -145,13 +148,13 @@ def command_step_end(step_param, step_end_cuc, step_id): logger.info('{} {}\n'.format(cmd_step_keyword_done, encode_to_json_string(step_param['step_no'], step_end_cuc, step_id=step_id))) -def verification_step_begin(step_param, script_version, pool_name, step_start_cuc, run_id, step_id): +def verification_step_begin(step_param, spec_version, pool_name, step_start_cuc, run_id, step_id): logger.info('{} {} {}'.format(vrc_step_keyword, step_param['step_no'], encode_to_json_string(step_number=step_param['step_no'], timestamp=step_start_cuc, - step_version=script_version, + spec_version=spec_version, vrc_descr=step_param['vrc_descr'], run_id=run_id, step_id=step_id, diff --git a/Tst/tst/data_model.py b/Tst/tst/data_model.py index 24ea10b..2c795ea 100644 --- a/Tst/tst/data_model.py +++ b/Tst/tst/data_model.py @@ -339,7 +339,7 @@ class TestSequence: self._sequence = sequence self._name = '' self._description = '' - self._version = '' + self._spec_version = '' self._primary_counter_locked = False self.steps = [] @@ -354,7 +354,7 @@ class TestSequence: new_test_seq.sequence = copy.copy(self.sequence) new_test_seq.name = copy.copy(self.name) new_test_seq.description = copy.copy(self.description) - new_test_seq.version = copy.copy(self.version) + new_test_seq.spec_version = copy.copy(self.spec_version) new_test_seq.primary_counter_locked = copy.copy(self.primary_counter_locked) new_test_seq.steps = copy.deepcopy(self.steps) @@ -397,13 +397,13 @@ class TestSequence: self._description = value @property - def version(self): - return self._version + def spec_version(self): + return self._spec_version - @version.setter - def version(self, value: str): + @spec_version.setter + def spec_version(self, value: str): assert isinstance(value, str) - self._version = value + self._spec_version = value def verify_step_list_consistency(self) -> bool: """ @@ -863,7 +863,7 @@ class TestSequence: try: self.name = json_data['_name'] self.description = json_data['_description'] - self.version = json_data['_version'] + self.spec_version = json_data['_spec_version'] self.sequence = json_data['_sequence'] except KeyError as keyerror: self.logger.error('KeyError: no {} could be found in the loaded data'.format(keyerror)) @@ -900,7 +900,8 @@ class TestSpecification: self.logger = logger self._name = '' self._description = '' - self._version = '' + self._spec_version = '' + self._iasw_version = '' self._primary_counter_locked = False self._precon_name = '' self._precon_code = '' @@ -920,7 +921,8 @@ class TestSpecification: new_testspec.sequences = copy.copy(self.sequences) new_testspec.name = copy.copy(self.name) new_testspec.description = copy.copy(self.description) - new_testspec.version = copy.copy(self.version) + new_testspec.spec_version = copy.copy(self.spec_version) + new_testspec.iasw_version = copy.copy(self.iasw_version) new_testspec.primary_counter_locked = copy.copy(self.primary_counter_locked) new_testspec.precon_name = copy.copy(self.precon_name) new_testspec.precon_code = copy.copy(self.precon_code) @@ -964,13 +966,22 @@ class TestSpecification: self._description = value @property - def version(self): - return self._version + def spec_version(self): + return self._spec_version - @version.setter - def version(self, value: str): + @spec_version.setter + def spec_version(self, value: str): assert isinstance(value, str) - self._version = value + self._spec_version = value + + @property + def iasw_version(self): + return self._iasw_version + + @iasw_version.setter + def iasw_version(self, value: str): + assert isinstance(value, str) + self._iasw_version = value @property def precon_name(self): @@ -1050,7 +1061,8 @@ class TestSpecification: try: self.name = json_data['_name'] self.description = json_data['_description'] - self.version = json_data['_version'] + self.spec_version = json_data['_spec_version'] + self.iasw_version = json_data['_iasw_version'] self.primary_counter_locked = json_data['_primary_counter_locked'] self.precon_name = json_data['_precon_name'] self.precon_code = json_data['_precon_code'] diff --git a/Tst/tst/file_management.py b/Tst/tst/file_management.py index 55005a6..9157043 100644 --- a/Tst/tst/file_management.py +++ b/Tst/tst/file_management.py @@ -36,6 +36,7 @@ def save_file(file_path, test_spec, file_extension=None, logger=module_logger, * logger.exception(e) logger.error('Failed to json-dump the instance into a file') + return def _to_json_string(test_to_save): assert isinstance(test_to_save, data_model.TestSequence) @@ -55,3 +56,7 @@ def _from_json(text_io): data = text_io.read() decoded_data = json.loads(data) return decoded_data + + +def from_json(text_io): + return _from_json(text_io) diff --git a/Tst/tst/generator.py b/Tst/tst/generator.py index f68a538..76cea11 100644 --- a/Tst/tst/generator.py +++ b/Tst/tst/generator.py @@ -109,7 +109,8 @@ def make_command_script(model, model_spec): testSpecFileName=create_file_name(model_spec.name), testSpecName=model_spec.name, testSpecDescription=model_spec.description, - testSpecVersion=model_spec.version, + testSpecVersion=model_spec.spec_version, + testIaswVersion=model_spec.iasw_version, testPreCondition=model_spec.precon_name, testPostCondition=model_spec.postcon_name, testComment=test_comment_w_indent) @@ -277,7 +278,7 @@ def make_verification_script(model, model_spec): testSpecFileName=create_file_name(model_spec.name), testSpecName=model_spec.name, testSpecDescription=model_spec.description, - testSpecVersion=model_spec.version) + testSpecVersion=model_spec.spec_version) # add the header string content += '\n\n' + cls diff --git a/Tst/tst/generator_templates/co_class.py b/Tst/tst/generator_templates/co_class.py index 5138db8..70d63d3 100644 --- a/Tst/tst/generator_templates/co_class.py +++ b/Tst/tst/generator_templates/co_class.py @@ -2,6 +2,8 @@ class ${testSpecClassName}: def __init__(self, do_verification=False): self.id = '${testSpecFileName}' self.name = '${testSpecName}' + self.spec_version = '${testSpecVersion}' + self.iasw_version = '${testIaswVersion}' self.description = '${testSpecDescription}' self.precondition = '${testPreCondition}' self.postcondition = '${testPostCondition}' @@ -19,7 +21,3 @@ class ${testSpecClassName}: # some tests are depended on other tests, thus information is stored on class level # insert class variables here - - @staticmethod - def version(): - return '${testSpecVersion}' diff --git a/Tst/tst/generator_templates/co_pre_condition.py b/Tst/tst/generator_templates/co_pre_condition.py index c4ca548..b21e30d 100644 --- a/Tst/tst/generator_templates/co_pre_condition.py +++ b/Tst/tst/generator_templates/co_pre_condition.py @@ -35,8 +35,9 @@ testing_logger.cmd_log_handler(__name__) step_id = self.check_run_and_step_id(pool_name=pool_name) step_start_cuc = cfl.get_last_pckt_time(pool_name=pool_name, string=False) - report.command_step_begin(step_param=param, script_version=self.version(), pool_name=pool_name, - step_start_cuc=step_start_cuc, run_id=self.run_id, step_id=step_id) + report.command_step_begin(step_param=param, spec_version=self.spec_version, iasw_version=self.iasw_version, + pool_name=pool_name, step_start_cuc=step_start_cuc, run_id=self.run_id, + step_id=step_id) summary = report.StepSummary(step_number=param['step_no']) return step_start_cuc, summary, step_id diff --git a/Tst/tst/generator_templates/ver_class.py b/Tst/tst/generator_templates/ver_class.py index 4e380dd..e04cc3a 100644 --- a/Tst/tst/generator_templates/ver_class.py +++ b/Tst/tst/generator_templates/ver_class.py @@ -18,7 +18,7 @@ class ${testSpecClassName}Verification: # insert class variables here @staticmethod - def version(): + def spec_version(): return '${testSpecVersion}' def verify(self, command_log_file, saved_pool_file): @@ -57,5 +57,5 @@ class ${testSpecClassName}Verification: self.run_id = now.strftime("%Y%m%d%H%M%S") step_start_cuc = cfl.get_last_pckt_time(pool_name=pool_name, string=False) - report.verification_step_begin(step_param=param, script_version=self.version(), pool_name=pool_name, + report.verification_step_begin(step_param=param, spec_version=self.spec_version(), pool_name=pool_name, step_start_cuc=step_start_cuc, run_id=self.run_id, step_id=step_id) diff --git a/Tst/tst/tst.py b/Tst/tst/tst.py index b8d4741..42be742 100755 --- a/Tst/tst/tst.py +++ b/Tst/tst/tst.py @@ -4,13 +4,16 @@ import os import logging import time import gi + gi.require_version('Gtk', '3.0') gi.require_version('GtkSource', '3.0') from gi.repository import Gtk, Gdk, Gio, GtkSource, GLib import confignator import sys + sys.path.append(confignator.get_option('paths', 'ccs')) import ccs_function_lib as cfl + cfl.add_tst_import_paths() import view import data_model @@ -22,15 +25,11 @@ import connect_apps import dbus import toolbox import tc_management as tcm - - +import json_to_barescript +import json_to_csv +import spec_to_json # creating lists for type and subtype to get rid of duplicate entries, for TC List - - - - - path_icon = os.path.join(os.path.dirname(__file__), 'style/tst.svg') menu_xml = os.path.join(os.path.dirname(__file__), 'app_menu.xml') css_file = os.path.join(os.path.dirname(__file__), 'style/style.css') @@ -126,7 +125,9 @@ class TstApp(Gtk.Application): return def _on_quit(self, action, param): - self.window.on_delete_event() + response = self.window.on_delete_event() + if response: + return self.quit() return @@ -179,7 +180,6 @@ class TestInstance: def filename(self, value): self._filename = value - class TstAppWindow(Gtk.ApplicationWindow): def __init__(self, logger=logger, *args, **kwargs): @@ -205,12 +205,17 @@ class TstAppWindow(Gtk.ApplicationWindow): action.connect('activate', self.on_save_as) self.add_action(action) + action = Gio.SimpleAction.new('csv_to_json', None) + action.connect('activate', self.on_csv_to_json) + self.add_action(action) + action = Gio.SimpleAction.new('close', None) action.connect('activate', self.on_close) self.add_action(action) show_json_view = confignator.get_bool_option('tst-preferences', 'show-json-view') - action = Gio.SimpleAction.new_stateful('model_viewer_toggle_hide', None, GLib.Variant.new_boolean(show_json_view)) + action = Gio.SimpleAction.new_stateful('model_viewer_toggle_hide', None, + GLib.Variant.new_boolean(show_json_view)) action.connect('change-state', self.model_viewer_toggle_hide) self.add_action(action) @@ -218,6 +223,8 @@ class TstAppWindow(Gtk.ApplicationWindow): action.connect('activate', self.on_apply_css) self.add_action(action) + self.create_make_menu() + self.set_icon_from_file(path_icon) # GUI @@ -241,10 +248,6 @@ class TstAppWindow(Gtk.ApplicationWindow): self.btn_save.set_icon_name('document-save') self.btn_save.set_tooltip_text('Save') self.btn_save.connect('clicked', self.on_save) - self.btn_show_model_viewer = Gtk.ToolButton() - self.btn_show_model_viewer.set_icon_name('accessories-dictionary-symbolic') - self.btn_show_model_viewer.set_tooltip_text('Show/hide model viewer') - self.btn_show_model_viewer.connect('clicked', self.model_viewer_toggle_hide) self.btn_generate_products = Gtk.ToolButton() self.btn_generate_products.set_label('Generate scripts') # self.btn_generate_products.set_icon_name('printer-printing-symbolic') @@ -264,7 +267,6 @@ class TstAppWindow(Gtk.ApplicationWindow): self.toolbar.insert(self.btn_new_file, 0) self.toolbar.insert(self.btn_open_file, 1) self.toolbar.insert(self.btn_save, 2) - # self.toolbar.insert(self.btn_show_model_viewer, 2) self.toolbar.insert(self.btn_generate_products, 3) self.toolbar.insert(self.btn_start_ccs_editor, 4) self.toolbar.insert(self.btn_open_progress_view, 5) @@ -307,7 +309,6 @@ class TstAppWindow(Gtk.ApplicationWindow): self.label_widget_tcm.set_text('TC Table') self.feature_area.append_page(child=self.tcm, tab_label=self.label_widget_tcm) - """ self.tcm = TCTableClass() self.label_widget_tcm = Gtk.Label() @@ -315,8 +316,6 @@ class TstAppWindow(Gtk.ApplicationWindow): self.feature_area.append_page(child=self.tcm, tab_label=self.label_widget_tcm) """ - - self.box.pack_start(self.work_desk, True, True, 0) # # panes for the step grid an so on @@ -367,6 +366,19 @@ class TstAppWindow(Gtk.ApplicationWindow): Gtk.StyleContext.add_class(context, 'tst-css') self.on_apply_css() + def create_make_menu(self): + action = Gio.SimpleAction.new('generate_scripts', None) + action.connect('activate', self.on_generate_products) + self.add_action(action) + + action = Gio.SimpleAction.new('generate_barescript', None) + action.connect('activate', self.on_generate_barescript) + self.add_action(action) + + action = Gio.SimpleAction.new('generate_csv', None) + action.connect('activate', self.on_generate_csv) + self.add_action(action) + def add_info_bar(self, message_type, message): """ Adds a InfoBar and moves it below the toolbar @@ -449,11 +461,11 @@ class TstAppWindow(Gtk.ApplicationWindow): def model_viewer_toggle_hide(self, action, value): visible = self.json_view.is_visible() - action.set_state(GLib.Variant.new_boolean(visible)) + action.set_state(GLib.Variant.new_boolean(not visible)) if visible: - self.json_view.show() - else: self.json_view.hide() + else: + self.json_view.show() def on_new_test(self, *args): # create a new test instance and add a sequence + first step @@ -483,18 +495,19 @@ class TstAppWindow(Gtk.ApplicationWindow): Closing the page on which was clicked """ for i in range(0, self.notebook.get_n_pages()): # Loop over all availabe page numbers - page = self.notebook.get_nth_page(i) # Get page widget - if self.notebook.get_tab_label(page) == widget.get_parent(): # Check if the label widget is the same as for the given widget - self.notebook.remove_page(i) # If so close the page + page = self.notebook.get_nth_page(i) # Get page widget + if self.notebook.get_tab_label( + page) == widget.get_parent(): # Check if the label widget is the same as for the given widget + self.notebook.remove_page(i) # If so close the page return - #self.notebook.remove_page(widget.get_parent()) + # self.notebook.remove_page(widget.get_parent()) def on_open(self, *args): dialog = Gtk.FileChooserDialog('Please choose a file', self, Gtk.FileChooserAction.OPEN, - (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) + (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) # using the last folder from history last_folder = confignator.get_option('tst-history', 'last-folder') if os.path.isdir(last_folder): @@ -504,28 +517,52 @@ class TstAppWindow(Gtk.ApplicationWindow): if response == Gtk.ResponseType.OK: file_selected = dialog.get_filename() confignator.save_option('tst-history', 'last-folder', os.path.dirname(file_selected)) - data_from_file = file_management.open_file(file_name=file_selected) + try: + json_type = True + data_from_file = file_management.open_file(file_name=file_selected) + filename = file_selected + except json.decoder.JSONDecodeError: + # data_from_file = file_management.from_json(spec_to_json.run(specfile=file_selected, gen_cmd=True, save_json=False)) + data_from_file = spec_to_json.run(specfile=file_selected, gen_cmd=True, save_json=False) + filename = file_selected.replace('.' + file_selected.split('.')[-1], '.json') + json_type = False + if os.path.exists(filename): + self.existing_json_warn_dialog(filename) + if data_from_file is not None: - # make a new test instance and notebook page - self.logger.info('make a new test instance and notebook page for: {}'.format(file_selected)) - new_test = self.new_test() - new_test.model.decode_from_json(json_data=data_from_file) - new_test.filename = file_selected - new_page_index = self.new_page(test_instance=new_test) - self.update_model_viewer() - new_test.view.update_widget_data() - self.notebook.set_current_page(new_page_index) - elif response == Gtk.ResponseType.CANCEL: - pass + self.on_open_create_tab(data_from_file, filename, json_type) + dialog.destroy() + return + + def on_open_create_tab(self, data_from_file, filename, json_type): + # make a new test instance and notebook page + self.logger.info('make a new test instance and notebook page for: {}'.format(filename)) + new_test = self.new_test() + new_test.model.decode_from_json(json_data=data_from_file) + new_test.filename = filename + if not json: + new_test.ask_overwrite = True + else: + new_test.ask_overwrite = True + new_page_index = self.new_page(test_instance=new_test) + self.update_model_viewer() + new_test.view.update_widget_data() + self.notebook.set_current_page(new_page_index) + return def on_save(self, *args): # get the data model of the current notebook page current_test = self.current_test_instance() current_model = self.current_model() - #current_model2=current_model.serialize(current_model) + # current_model2=current_model.serialize(current_model) if current_model is not None and current_test.filename is None: self.save_as_file_dialog() + elif current_test and current_test.ask_overwrite and current_test.filename: + if os.path.exists(current_test.filename): + self.overwrite_dialog(current_test) + else: + self.save_as_file_dialog() elif current_model is not None: file_management.save_file(file_path=current_test.filename, test_spec=current_model, logger=self.logger) @@ -541,38 +578,151 @@ class TstAppWindow(Gtk.ApplicationWindow): Gtk.FileChooserAction.SAVE, (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_SAVE, Gtk.ResponseType.OK)) dialog.set_current_folder(confignator.get_option(section='tst-history', option='last-folder')) - dialog.set_current_name(current_name+'.json') + dialog.set_current_name('{}-TS-{}.json'.format(current_name, current_model.spec_version)) self.add_filters(dialog) + dialog.set_do_overwrite_confirmation(True) response = dialog.run() if response == Gtk.ResponseType.OK: file_selected = dialog.get_filename() confignator.save_option('tst-history', 'last-folder', os.path.dirname(file_selected)) - if '-v_' in file_selected: - test_name = file_selected.split('-v_')[0] - filename = file_selected - else: - test_name = file_selected.split('.json')[0] - filename = '{}-v_{}.json'.format(test_name, current_model.version) - - file_management.save_file(file_path=filename, test_spec=current_model, file_extension='json', logger=self.logger) - current_test.filename = filename.split('/')[-1] - current_model.name = test_name.split('/')[-1] - elif response == Gtk.ResponseType.CANCEL: - pass - dialog.destroy() - - def add_filters(self, dialog): - filter_text = Gtk.FileFilter() - filter_text.set_name('JSON format') - filter_text.add_mime_type('application/json') - filter_text.add_pattern('.json') - dialog.add_filter(filter_text) + file_management.save_file(file_path=file_selected, test_spec=current_model, file_extension='json', + logger=self.logger) + current_test.filename = file_selected + file_name = file_selected.split('/')[-1] + #current_model.name = file_selected.split('/')[-1].split('.')[0].split('-TS-')[0] # Get only the name + current_test.update_widget_data() + self.notebook.set_tab_label(current_test, self.notebook_page_label(file_name)) # Update tab label + self.show_all() + dialog.destroy() + return True + else: + dialog.destroy() + return False + + def add_filters(self, dialog, filter_json=True): + if json: + filter_text = Gtk.FileFilter() + filter_text.set_name('JSON format') + filter_text.add_mime_type('application/json') + filter_text.add_pattern('.json') + dialog.add_filter(filter_text) + else: + filter_text = Gtk.FileFilter() + filter_text.set_name('Spec Files') + filter_text.add_mime_type('text/csv') + filter_text.add_pattern('.csv*') + dialog.add_filter(filter_text) filter_any = Gtk.FileFilter() filter_any.set_name('Any files') filter_any.add_pattern('*') dialog.add_filter(filter_any) + def on_csv_to_json(self, *args): + dialog = Gtk.FileChooserDialog('Please choose a CSV File', + self, + Gtk.FileChooserAction.OPEN, + (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK)) + # using the last folder from history + last_folder = confignator.get_option('tst-history', 'last-folder') + if os.path.isdir(last_folder): + dialog.set_current_folder(last_folder) + response = dialog.run() + self.add_filter_csv(dialog, filter_json=False) + if response == Gtk.ResponseType.OK: + confignator.save_option('tst-history', 'last-folder', dialog.get_current_folder()) + file_selected = dialog.get_filename() + filename = file_selected.replace('.' + file_selected.split('.')[-1], '.json') + data_from_file = spec_to_json.run(specfile=file_selected, gen_cmd=True, save_json=False) + self.on_open_create_tab(data_from_file, filename, json_type=False) + self.on_open_create_tab(data_from_file, filename, json_type=False) + dialog.destroy() + + self.save_as_file_dialog() + else: + dialog.destroy() + + return + + def overwrite_dialog(self, current_test): + filepath = current_test.filename + filename = filepath.split('/')[-1] + folder = filepath[:-len(filename)-1] + dialog = Gtk.MessageDialog() + dialog.add_buttons(Gtk.STOCK_YES, Gtk.ResponseType.YES, Gtk.STOCK_NO, Gtk.ResponseType.NO) + dialog.set_markup('Overwrite existing File?') + dialog.format_secondary_text('{} at {} already exists'.format(filename, folder)) + response = dialog.run() + + if response == Gtk.ResponseType.YES: + current_test.ask_overwrite = False + dialog.destroy() + self.on_save() + else: + dialog.destroy() + + return + + def existing_json_warn_dialog(self, filepath): + filename = filepath.split('/')[-1] + folder = filepath[:-len(filename)-1] + dialog = Gtk.MessageDialog() + dialog.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.OK) + dialog.set_markup('CSV converted Json File already Exists'.format(filename)) + dialog.format_secondary_text('{} at {} already exists, temporarily saved in TST \nBe careful during saving'.format(filename, folder)) + dialog.run() + dialog.destroy() + return True + + def unsaved_changes_overwrite_dialog(self, current_test): + filepath = current_test.filename + filename = filepath.split('/')[-1] + folder = filepath[:-len(filename)-1] + dialog = Gtk.MessageDialog() + dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_YES, Gtk.ResponseType.YES, Gtk.STOCK_NO, Gtk.ResponseType.NO) + dialog.set_markup('Unsaved changes in {}, Overwrite?'.format(filename)) + dialog.format_secondary_text('{} at {} already exists'.format(filename, folder)) + response = dialog.run() + if response == Gtk.ResponseType.YES: + current_test.ask_overwrite = False + dialog.destroy() + self.on_save() + elif response == Gtk.ResponseType.CANCEL: + dialog.destroy() + return False + else: + dialog.destroy() + + return True + + def unsaved_changes_newfile_dialog(self, current_test): + filepath = current_test.filename + if filepath: + filename = filepath.split('/')[-1] + else: + filename = 'New Test' + dialog = Gtk.MessageDialog() + dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_YES, Gtk.ResponseType.YES, Gtk.STOCK_NO, Gtk.ResponseType.NO) + dialog.set_markup('Unsaved File {}, Save?'.format(filename)) + #dialog.format_secondary_text('{} at {} is unsaved'.format(filename, folder)) + response = dialog.run() + + if response == Gtk.ResponseType.YES: + current_test.ask_overwrite = False + dialog.destroy() + response = self.save_as_file_dialog() + if response: + return True + else: + return False + elif response == Gtk.ResponseType.CANCEL: + dialog.destroy() + return False + else: + dialog.destroy() + + return True + def on_delete_event(self, *args): self.logger.info('save preferences') # saving the height and width of the main window @@ -582,6 +732,28 @@ class TstAppWindow(Gtk.ApplicationWindow): confignator.save_option('tst-preferences', 'paned-position', str(self.work_desk.get_position())) # save the preferences of the CodeReuseFeature self.codeblockreuse.save_panes_positions() + self.logger.info('Check for Unsaved Buffer') + response = self._check_unsaved_buffer() + if not response: + return True + return False + + def _check_unsaved_buffer(self): + for test_instance in self.notebook: + filename = test_instance.filename + tst_json = json.loads(test_instance.model.encode_to_json()) + if filename and os.path.exists(filename): + file_json = file_management.open_file(filename) + if not tst_json == file_json: + response = self.unsaved_changes_overwrite_dialog(test_instance) + if not response: + return False + else: + response = self.unsaved_changes_newfile_dialog(test_instance) + if not response: + return False + + return True def on_generate_products(self, *args): """ @@ -604,6 +776,70 @@ class TstAppWindow(Gtk.ApplicationWindow): # triggering the dialog after generation self.on_generate_products_message_dialog(paths=self.product_paths) + def on_generate_barescript(self, *args): + """ + Generates a small python test file without all the additional staff from on_generate_scripts + """ + dialog = Gtk.FileChooserDialog( + title="Save Script AS", parent=self, action=Gtk.FileChooserAction.SAVE) + dialog.add_buttons( + Gtk.STOCK_CANCEL, + Gtk.ResponseType.CANCEL, + Gtk.STOCK_SAVE, + Gtk.ResponseType.OK, ) + + if self.current_test_instance(): + current_json_filename = self.current_test_instance().filename + current_model = self.current_model() + else: + logger.info('Small Script can not be generated without jsonfile') + print('Small Script can not be generated without json file') + return + + outfile_basic = '{}-TS-{}.py'.format(current_model.name, current_model.spec_version) + dialog.set_current_name(outfile_basic) + dialog.set_current_folder(confignator.get_option('tst-history', 'last-folder')) + + response = dialog.run() + if response == Gtk.ResponseType.OK: + json_to_barescript.run(current_json_filename, dialog.get_filename()) + confignator.save_option('tst-history', 'last-folder', dialog.get_current_folder()) + + dialog.destroy() + return + + def on_generate_csv(self, *args): + """ + Generates a CSV Test Specification file + """ + dialog = Gtk.FileChooserDialog( + title="Save CSV AS", parent=self, action=Gtk.FileChooserAction.SAVE) + dialog.add_buttons( + Gtk.STOCK_CANCEL, + Gtk.ResponseType.CANCEL, + Gtk.STOCK_SAVE, + Gtk.ResponseType.OK, ) + + if self.current_test_instance(): + current_json_filename = self.current_test_instance().filename + current_model = self.current_model() + else: + logger.info('CSV File can not be generated without json file') + print('CSV File can not be generated without json file') + return + + outfile_basic = '{}-IASW-{}-TS-{}.csv_PIPE'.format(current_model.name, current_model.iasw_version, current_model.spec_version) + dialog.set_current_name(outfile_basic) + dialog.set_current_folder(confignator.get_option('tst-history', 'last-folder')) + + response = dialog.run() + if response == Gtk.ResponseType.OK: + json_to_csv.run(current_json_filename, dialog.get_filename()) + confignator.save_option('tst-history', 'last-folder', dialog.get_current_folder()) + + dialog.destroy() + return + def connect_to_ccs_editor(self): # get the DBus connection to the CCS-Editor editor = connect_apps.connect_to_editor() @@ -717,7 +953,7 @@ class TstAppWindow(Gtk.ApplicationWindow): return paths def on_make_desktop_entry(self): - #ToDo: create a file for the desktop entry + # ToDo: create a file for the desktop entry pass def on_start_progress_viewer(self, *args): @@ -815,7 +1051,7 @@ class ViewModelAsJson(Gtk.Box): """ Gets the data of the model and makes a JSON string out of it. Intended to display the model data as plain JSON :param data_model.TestSpecification model: a instance of the TestSpecification class - # param data_model.TestSequence model: a instance of the TestSpecification class + :param data_model.TestSequence model: a instance of the TestSpecification class """ assert isinstance(model, data_model.TestSpecification) or model is None if model is not None: diff --git a/Tst/tst/view.py b/Tst/tst/view.py index e5360f9..ae636b3 100644 --- a/Tst/tst/view.py +++ b/Tst/tst/view.py @@ -84,6 +84,8 @@ class Board(Gtk.Box): self.logger = logger self._test_is_locked = None + # Save Button in TST clicked for first time, Always do save_as to not overwrite something, used in tst.py + self._ask_overwrite = True Gtk.Box.__init__(self) self.set_orientation(Gtk.Orientation.VERTICAL) @@ -113,13 +115,20 @@ class Board(Gtk.Box): self.test_meta_data_desc = Gtk.Entry() self.test_meta_data_desc.set_placeholder_text('< description of the test>') self.test_meta_data_entries.pack_start(self.test_meta_data_desc, True, True, 0) - # version - self.test_meta_data_version_label = Gtk.Label() - self.test_meta_data_version_label.set_text('Version:') - self.test_meta_data_labels.pack_start(self.test_meta_data_version_label, True, True, 0) - self.test_meta_data_version = Gtk.Entry() - self.test_meta_data_version.set_placeholder_text('< version >') - self.test_meta_data_entries.pack_start(self.test_meta_data_version, True, True, 0) + # spec_version + self.test_meta_data_spec_version_label = Gtk.Label() + self.test_meta_data_spec_version_label.set_text('Spec Version:') + self.test_meta_data_labels.pack_start(self.test_meta_data_spec_version_label, True, True, 0) + self.test_meta_data_spec_version = Gtk.Entry() + self.test_meta_data_spec_version.set_placeholder_text('< spec version >') + self.test_meta_data_entries.pack_start(self.test_meta_data_spec_version, True, True, 0) + # IASW Software Version + self.test_meta_data_iasw_version_label = Gtk.Label() + self.test_meta_data_iasw_version_label.set_text('IASW Version:') + self.test_meta_data_labels.pack_start(self.test_meta_data_iasw_version_label, True, True, 0) + self.test_meta_data_iasw_version = Gtk.Entry() + self.test_meta_data_iasw_version.set_placeholder_text('< IASW version >') + self.test_meta_data_entries.pack_start(self.test_meta_data_iasw_version, True, True, 0) # checkbox for locking the step numbers self.test_is_locked_label = Gtk.Label() self.test_is_locked_label.set_text(_('Lock step numeration:')) @@ -217,7 +226,8 @@ class Board(Gtk.Box): # connect signals self.test_meta_data_name.connect('changed', self.on_test_name_change) self.test_meta_data_desc.connect('changed', self.on_test_desc_change) - self.test_meta_data_version.connect('changed', self.on_test_version_change) + self.test_meta_data_spec_version.connect('changed', self.on_test_spec_version_change) + self.test_meta_data_iasw_version.connect('changed', self.on_test_iasw_version_change) self.text_meta_data_test_is_locked.connect('toggled', self.on_test_locked_toggled) self.test_meta_data_comment.get_buffer().connect('changed', self.on_comment_change) @@ -238,6 +248,14 @@ class Board(Gtk.Box): def filename(self, value): self._filename = value + @property + def ask_overwrite(self): + return self._ask_overwrite + + @ask_overwrite.setter + def ask_overwrite(self, value): + self._ask_overwrite = value + def update_widget_data(self): """ Updates the grid with the steps. All widgets of the grid are destroyed. The grid is build new from the model. @@ -256,8 +274,10 @@ class Board(Gtk.Box): self.test_meta_data_name.set_text(self.model.name) # set the description of the test specification using the data from the model self.test_meta_data_desc.set_text(self.model.description) - # set the version of the test specification from the data model - self.test_meta_data_version.set_text(self.model.version) + # set the Specification version of the test specification from the data model + self.test_meta_data_spec_version.set_text(self.model.spec_version) + # set the Software version of the test specification from the data model + self.test_meta_data_iasw_version.set_text(self.model.iasw_version) # set the pre-condition name if self.model.precon_name: found = False @@ -443,11 +463,19 @@ class Board(Gtk.Box): # update the data model viewer self.app.update_model_viewer() - def on_test_version_change(self, widget): - # get the version out of the text buffer of the widget - version = widget.get_text() + def on_test_spec_version_change(self, widget): + # get the Specification Version out of the text buffer of the widget + spec_version = widget.get_text() + # update the model + self.model.spec_version = spec_version + # update the data model viewer + self.app.update_model_viewer() + + def on_test_iasw_version_change(self, widget): + # get the IASW Version out of the text buffer of the widget + iasw_version = widget.get_text() # update the model - self.model.version = version + self.model.iasw_version = iasw_version # update the data model viewer self.app.update_model_viewer() diff --git a/Tst/tst_template_empty.json b/Tst/tst_template_empty.json index 5f9b979..e89169b 100644 --- a/Tst/tst_template_empty.json +++ b/Tst/tst_template_empty.json @@ -9,14 +9,14 @@ "_precon_descr": "", "_precon_name": "", "_primary_counter_locked": false, - "_version": "", + "_spec_version": "", "sequences": [ { "_description": "", "_name": "", "_primary_counter_locked": false, "_sequence": 0, - "_version": "", + "_spec_version": "", "steps": [ { "_command_code": "", -- GitLab