From 9567d1a80d1a0d2f74d817f48ad1e90695170587 Mon Sep 17 00:00:00 2001 From: Vandlik Viktor Date: Fri, 28 Mar 2025 09:51:00 +0100 Subject: [PATCH 01/13] barinel --- .idea/CharmFL.iml | 11 ++++++ .idea/inspectionProfiles/Project_Default.xml | 12 ++++++ .../inspectionProfiles/profiles_settings.xml | 6 +++ .idea/misc.xml | 5 ++- .idea/modules.xml | 8 ++++ src/main/python/faultloc/Metrics.py | 20 +++++++++- src/main/python/faultloc/Spectra.py | 38 ++++++++++++++++++- src/main/python/main.py | 2 +- src/main/python/testing/Use_PyTest.py | 4 +- src/main/python/utils/Result_Builder.py | 17 ++++++--- 10 files changed, 110 insertions(+), 13 deletions(-) create mode 100644 .idea/CharmFL.iml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/modules.xml diff --git a/.idea/CharmFL.iml b/.idea/CharmFL.iml new file mode 100644 index 0000000..2191d23 --- /dev/null +++ b/.idea/CharmFL.iml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..7e97281 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 49504ef..3e7da09 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,5 +1,8 @@ + + - + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..1de5de2 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/src/main/python/faultloc/Metrics.py b/src/main/python/faultloc/Metrics.py index def482e..f396a20 100644 --- a/src/main/python/faultloc/Metrics.py +++ b/src/main/python/faultloc/Metrics.py @@ -18,8 +18,10 @@ def create_scores_from(self, spectra_object): ochiai_score = self.ochiai(stats["ef"], stats["ep"], stats["nf"], stats["np"]) wong2_score = self.wong2(stats["ef"], stats["ep"], stats["nf"], stats["np"]) dstar_score = self.dstar(stats["ef"], stats["ep"], stats["nf"], stats["np"]) + barinel_score = self.barinel(stats["ef"], stats["ep"], stats["nf"], stats["np"]) self.scores_for_code_elements[code_element] = {"tar": tarantula_score, "och": ochiai_score, - "wong2": wong2_score, "dstar": dstar_score} + "wong2": wong2_score, "dstar": dstar_score, + "barinel": barinel_score} def get_scores(self): return self.scores_for_code_elements @@ -75,4 +77,18 @@ def dstar(self, ef, ep, nf, np): score = 0.0 if score is None: return 0.0 - return round(score, 2) \ No newline at end of file + return round(score, 2) + + def barinel(self, ef, ep, nf, np): + ef = float(ef) + ep = float(ep) + nf = float(nf) + np = float(np) + try: + score = abs(ef) / (abs(ef) + abs(ep)) + + except ZeroDivisionError: + score = 0.0 + if score is None: + return 0.0 + return round(score, 2) diff --git a/src/main/python/faultloc/Spectra.py b/src/main/python/faultloc/Spectra.py index 523eede..e44fd44 100644 --- a/src/main/python/faultloc/Spectra.py +++ b/src/main/python/faultloc/Spectra.py @@ -21,11 +21,12 @@ def create_spectrum_from(self, coverage_object, test_object): for code_element, covered_tests in cov_elements.items(): ef, ep = 0, 0 for test in covered_tests: + h = self.heuristic_analyzer(test) #if test in test_result: counted_tests = [t for t in test_result if str(t).endswith(test)] if len(counted_tests) == 1: ef = ef + 1 if test_result[counted_tests[0]] == "FAILED" else ef - ep = ep + 1 if test_result[counted_tests[0]] == "PASSED" else ep + ep = ep + 1 if test_result[counted_tests[0]] == "PASSED" and h != "put" else ep else: print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") print(test) @@ -33,6 +34,40 @@ def create_spectrum_from(self, coverage_object, test_object): np = number_of_pass - ep self.spectrum[str(file)+self.SEPARATOR_CHARACTER+str(code_element)] = {"ef": ef, "ep":ep, "nf":nf,"np":np} + def heuristic_analyzer(self,test): + #chains from JSON + project_path = os.path.abspath("callchains.json") + + with open(project_path) as file: + # print(f"{os.path.dirname(os.path.abspath(projectdir))}/D4J/{project}" + str(bugid) + "heuristics.txt") + data = file.read() + call_chains = json.loads(data) + + chains = call_chains[test] + # Flatten the list of chains and count their occurrences + + chain_lengths = len(chains) + + # Rule 1: A test with only one chain of any length is a unit test + if all([len(elem) == 1 for elem in chains]) and 0 < chain_lengths <= 1: + return "put" + + if all([len(elem) <= 2 for elem in chains]) and chain_lengths > 0: + return "smt" + + # # Rule 2: If a test has multiple chains but they are consistent in length except for the last method + # if len(length_counts) > 1: + # unique_lengths = sorted(length_counts.keys()) + # if len(unique_lengths) == 2 and unique_lengths[1] - unique_lengths[0] == 1: + # unit_tests.append(test_name) + # continue + + if chain_lengths == 1: + if all([len(elem) <= 3 for elem in chains]): + # Rule 2: Single chain but not longer than 3 + return "lmc" + # Rule 3: Single chain from test + return "smc" def get_spectrum(self): return self.spectrum @@ -40,3 +75,4 @@ def get_spectrum(self): # def dump_json(self): # output = open('spectrum.json', 'w') # json.dump(self.spectrum, output) + diff --git a/src/main/python/main.py b/src/main/python/main.py index 9b1b23f..e68fec3 100644 --- a/src/main/python/main.py +++ b/src/main/python/main.py @@ -46,7 +46,7 @@ def main(): if (platform.system() == "Linux"): venv_path = venv_path + "/venv/bin" + os.path.sep if(platform.system() == "Windows"): - venv_path = venv_path + "/venv" + os.path.sep + "Scripts" + os.path.sep + venv_path = venv_path + "\\.venv" + os.path.sep + "Scripts" + os.path.sep project_path = args["directory"] os.chdir(project_path) if (args["FaultLoc"] == True): diff --git a/src/main/python/testing/Use_PyTest.py b/src/main/python/testing/Use_PyTest.py index fde188e..083f16c 100644 --- a/src/main/python/testing/Use_PyTest.py +++ b/src/main/python/testing/Use_PyTest.py @@ -29,7 +29,7 @@ def run_tests(self, venv_path): pytest_args.append(self.project_path + os.path.sep + test_folder + os.path.sep + file) current_test_folder = test_folder if test_folder != '' else tests_folder - cmd = self.project_path + venv_path + "coverage run -m pytest --json-report "+str(current_test_folder) + cmd = self.project_path + venv_path + "python -m coverage run -m pytest --json-report "+str(current_test_folder) print("-------------> ", current_test_folder) print("-------------> ", cmd) sp.call(cmd, shell=True) @@ -42,7 +42,7 @@ def run_tests(self, venv_path): # cov.save() # sp.call("coverage combine") - sp.call(self.project_path + venv_path +"coverage combine", shell=True) + sp.call(self.project_path + venv_path +"python -m coverage combine", shell=True) self.__get_test_results_from_json(self.results_dict) diff --git a/src/main/python/utils/Result_Builder.py b/src/main/python/utils/Result_Builder.py index ea3e837..b6890d8 100644 --- a/src/main/python/utils/Result_Builder.py +++ b/src/main/python/utils/Result_Builder.py @@ -38,18 +38,18 @@ def produce_results(self): file_name = str(key).split(self.SEPARATOR_CHARACTER)[self.FILE_NAME_INDEX] absolute_path_to_root, relative_path = self.__separate_absolute_and_relative_path(file_name) line_num = str(key).split(self.SEPARATOR_CHARACTER)[LINE_NUMBER_INDEX] - class_name, class_start_line_num, class_tar, class_och, class_wong2, class_dstar = self.__get_lines_context_info( + class_name, class_start_line_num, class_tar, class_och, class_wong2, class_dstar, class_barinel = self.__get_lines_context_info( self.class_scores, file_name, line_num) - method_name, method_start_line_num, method_tar, method_och, method_wong2, method_dstar = self.__get_lines_context_info( + method_name, method_start_line_num, method_tar, method_och, method_wong2, method_dstar, method_barinel = self.__get_lines_context_info( self.method_scores, file_name, line_num) context_scores_and_info = {"absolute_path_to_root": absolute_path_to_root, "relative_path": relative_path, "line_num": line_num, "class_name": class_name, "class_start_line_num": class_start_line_num, "class_tar": class_tar, - "class_och": class_och, "class_wong2": class_wong2, "class_dstar": class_dstar, + "class_och": class_och, "class_wong2": class_wong2, "class_dstar": class_dstar, "class_barinel": class_barinel, "method_name": method_name, "method_start_line_num": method_start_line_num, "method_tar": method_tar, "method_och": method_och, "method_wong2": method_wong2, - "method_dstar": method_dstar} + "method_dstar": method_dstar, "method_barinel": method_barinel} self.__put_line_scores_to_place(context_scores_and_info, line_scores) return self @@ -105,6 +105,7 @@ def __get_class_scores_dictionary(self, context_scores_and_info, line_scores): "line": context_scores_and_info["class_start_line_num"], "tar": context_scores_and_info["class_tar"], "och": context_scores_and_info["class_och"], "wong2": context_scores_and_info["class_wong2"], "dstar": context_scores_and_info["class_dstar"], + "barinel": context_scores_and_info["class_barinel"], "methods": [self.__get_method_scores_dictionary(context_scores_and_info, line_scores) ]} @@ -115,6 +116,7 @@ def __get_method_scores_dictionary(self, context_scores_and_info, line_scores): "och": context_scores_and_info["method_och"], "wong2": context_scores_and_info["method_wong2"], "dstar": context_scores_and_info["method_dstar"], + "barinel": context_scores_and_info["method_barinel"], "statements": [self.__get_line_scores_dictionary(context_scores_and_info, line_scores) ]} @@ -123,6 +125,7 @@ def __get_line_scores_dictionary(self, context_scores_and_info, line_scores): "och": line_scores["och"], "wong2": line_scores["wong2"], "dstar": line_scores["dstar"], + "barinel": line_scores["barinel"], "faulty": "false"} def __get_index_of_context_containing_property(self, list_in_dict, property_name, context_value): @@ -141,10 +144,11 @@ def __get_lines_context_info(self, context_scores, file_name, line_number): och_score = context_scores[key]["och"] wong2_score = context_scores[key]["wong2"] dstar_score = context_scores[key]["dstar"] + barinel_score = context_scores[key]["barinel"] if context_file_name == file_name and int(context_start_line_number) < int(line_number) <= int( context_end_line_number): - return context_name, context_start_line_number, tar_score, och_score, wong2_score, dstar_score + return context_name, context_start_line_number, tar_score, och_score, wong2_score, dstar_score, barinel_score context_name = "" context_start_line_number = 0 @@ -152,4 +156,5 @@ def __get_lines_context_info(self, context_scores, file_name, line_number): och_score = 0 wong2_score = 0 dstar_score = 0 - return context_name, context_start_line_number, tar_score, och_score, wong2_score, dstar_score + barinel_score = 0 + return context_name, context_start_line_number, tar_score, och_score, wong2_score, dstar_score, barinel_score From da32cf1ae0006b1127b8deb88d915585b0f8205b Mon Sep 17 00:00:00 2001 From: Vandlik Viktor Date: Fri, 28 Mar 2025 19:13:28 +0100 Subject: [PATCH 02/13] barinel, modified barinel in metrics and spectra --- src/main/python/faultloc/Metrics.py | 4 +++- src/main/python/faultloc/Spectra.py | 18 +++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/main/python/faultloc/Metrics.py b/src/main/python/faultloc/Metrics.py index f396a20..8526205 100644 --- a/src/main/python/faultloc/Metrics.py +++ b/src/main/python/faultloc/Metrics.py @@ -19,9 +19,11 @@ def create_scores_from(self, spectra_object): wong2_score = self.wong2(stats["ef"], stats["ep"], stats["nf"], stats["np"]) dstar_score = self.dstar(stats["ef"], stats["ep"], stats["nf"], stats["np"]) barinel_score = self.barinel(stats["ef"], stats["ep"], stats["nf"], stats["np"]) + modified_barinel_score = self.barinel(stats["efmod"], stats["epmod"], stats["nf"], stats["np"]) self.scores_for_code_elements[code_element] = {"tar": tarantula_score, "och": ochiai_score, "wong2": wong2_score, "dstar": dstar_score, - "barinel": barinel_score} + "barinel": barinel_score, + "modified_barinel": modified_barinel_score} def get_scores(self): return self.scores_for_code_elements diff --git a/src/main/python/faultloc/Spectra.py b/src/main/python/faultloc/Spectra.py index e44fd44..f84129b 100644 --- a/src/main/python/faultloc/Spectra.py +++ b/src/main/python/faultloc/Spectra.py @@ -15,24 +15,24 @@ def create_spectrum_from(self, coverage_object, test_object): number_of_fails = test_object.get_number_of_failed_test_cases() number_of_pass = test_object.get_number_of_passed_test_cases() - - for file, cov_elements in coverage_result.items(): for code_element, covered_tests in cov_elements.items(): ef, ep = 0, 0 + ef_mod, ep_mod = 0, 0 for test in covered_tests: - h = self.heuristic_analyzer(test) - #if test in test_result: counted_tests = [t for t in test_result if str(t).endswith(test)] if len(counted_tests) == 1: ef = ef + 1 if test_result[counted_tests[0]] == "FAILED" else ef - ep = ep + 1 if test_result[counted_tests[0]] == "PASSED" and h != "put" else ep - else: - print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA") - print(test) + ep = ep + 1 if test_result[counted_tests[0]] == "PASSED" else ep + + h = self.heuristic_analyzer(test) + ef_mod = ef_mod + 1 if test_result[counted_tests[0]] == "FAILED" else ef_mod + ep_mod = ep_mod + 1 if test_result[counted_tests[0]] == "PASSED" and h != "put" else ep_mod + nf = number_of_fails - ef np = number_of_pass - ep - self.spectrum[str(file)+self.SEPARATOR_CHARACTER+str(code_element)] = {"ef": ef, "ep":ep, "nf":nf,"np":np} + + self.spectrum[str(file)+self.SEPARATOR_CHARACTER+str(code_element)] = {"ef": ef, "ep":ep, "nf":nf,"np":np, "efmod": ef_mod, "epmod" : ep_mod} def heuristic_analyzer(self,test): #chains from JSON From 4c27c8777e4eda0a794c238ca0b4cfe15a9e6450 Mon Sep 17 00:00:00 2001 From: Vandlik Viktor Date: Fri, 28 Mar 2025 20:04:16 +0100 Subject: [PATCH 03/13] barinel, modified barinel in resultbuilder --- src/main/python/utils/Result_Builder.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/python/utils/Result_Builder.py b/src/main/python/utils/Result_Builder.py index b6890d8..fc5a301 100644 --- a/src/main/python/utils/Result_Builder.py +++ b/src/main/python/utils/Result_Builder.py @@ -38,18 +38,22 @@ def produce_results(self): file_name = str(key).split(self.SEPARATOR_CHARACTER)[self.FILE_NAME_INDEX] absolute_path_to_root, relative_path = self.__separate_absolute_and_relative_path(file_name) line_num = str(key).split(self.SEPARATOR_CHARACTER)[LINE_NUMBER_INDEX] - class_name, class_start_line_num, class_tar, class_och, class_wong2, class_dstar, class_barinel = self.__get_lines_context_info( + (class_name, class_start_line_num, class_tar, class_och, class_wong2, class_dstar, class_barinel, + class_modified_barinel) = self.__get_lines_context_info( self.class_scores, file_name, line_num) - method_name, method_start_line_num, method_tar, method_och, method_wong2, method_dstar, method_barinel = self.__get_lines_context_info( + (method_name, method_start_line_num, method_tar, method_och, method_wong2, method_dstar, method_barinel, + method_modified_barinel) = self.__get_lines_context_info( self.method_scores, file_name, line_num) context_scores_and_info = {"absolute_path_to_root": absolute_path_to_root, "relative_path": relative_path, "line_num": line_num, "class_name": class_name, "class_start_line_num": class_start_line_num, "class_tar": class_tar, - "class_och": class_och, "class_wong2": class_wong2, "class_dstar": class_dstar, "class_barinel": class_barinel, + "class_och": class_och, "class_wong2": class_wong2, "class_dstar": class_dstar, + "class_barinel": class_barinel, "class_modified_barinel": class_modified_barinel, "method_name": method_name, "method_start_line_num": method_start_line_num, "method_tar": method_tar, "method_och": method_och, "method_wong2": method_wong2, - "method_dstar": method_dstar, "method_barinel": method_barinel} + "method_dstar": method_dstar, "method_barinel": method_barinel, + "method_modified_barinel": method_modified_barinel} self.__put_line_scores_to_place(context_scores_and_info, line_scores) return self @@ -106,6 +110,7 @@ def __get_class_scores_dictionary(self, context_scores_and_info, line_scores): "tar": context_scores_and_info["class_tar"], "och": context_scores_and_info["class_och"], "wong2": context_scores_and_info["class_wong2"], "dstar": context_scores_and_info["class_dstar"], "barinel": context_scores_and_info["class_barinel"], + "modified_barinel": context_scores_and_info["class_modified_barinel"], "methods": [self.__get_method_scores_dictionary(context_scores_and_info, line_scores) ]} @@ -117,6 +122,7 @@ def __get_method_scores_dictionary(self, context_scores_and_info, line_scores): "wong2": context_scores_and_info["method_wong2"], "dstar": context_scores_and_info["method_dstar"], "barinel": context_scores_and_info["method_barinel"], + "modified_barinel": context_scores_and_info["method_modified_barinel"], "statements": [self.__get_line_scores_dictionary(context_scores_and_info, line_scores) ]} @@ -126,6 +132,7 @@ def __get_line_scores_dictionary(self, context_scores_and_info, line_scores): "wong2": line_scores["wong2"], "dstar": line_scores["dstar"], "barinel": line_scores["barinel"], + "modified_barinel": line_scores["modified_barinel"], "faulty": "false"} def __get_index_of_context_containing_property(self, list_in_dict, property_name, context_value): @@ -145,10 +152,12 @@ def __get_lines_context_info(self, context_scores, file_name, line_number): wong2_score = context_scores[key]["wong2"] dstar_score = context_scores[key]["dstar"] barinel_score = context_scores[key]["barinel"] + modified_barinel_score = context_scores[key]["modified_barinel"] if context_file_name == file_name and int(context_start_line_number) < int(line_number) <= int( context_end_line_number): - return context_name, context_start_line_number, tar_score, och_score, wong2_score, dstar_score, barinel_score + return (context_name, context_start_line_number, tar_score, och_score, wong2_score, dstar_score, + barinel_score, modified_barinel_score) context_name = "" context_start_line_number = 0 @@ -157,4 +166,6 @@ def __get_lines_context_info(self, context_scores, file_name, line_number): wong2_score = 0 dstar_score = 0 barinel_score = 0 - return context_name, context_start_line_number, tar_score, och_score, wong2_score, dstar_score, barinel_score + modified_barinel_score = 0 + return (context_name, context_start_line_number, tar_score, och_score, wong2_score, dstar_score, + barinel_score, modified_barinel_score) From 40b5593b7ceacde29c4062bd81db58a4f23f0ad0 Mon Sep 17 00:00:00 2001 From: Vandlik Viktor Date: Mon, 14 Apr 2025 15:50:30 +0200 Subject: [PATCH 04/13] . --- src/main/python/faultloc/Spectra.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/main/python/faultloc/Spectra.py b/src/main/python/faultloc/Spectra.py index f84129b..7c7e009 100644 --- a/src/main/python/faultloc/Spectra.py +++ b/src/main/python/faultloc/Spectra.py @@ -35,38 +35,25 @@ def create_spectrum_from(self, coverage_object, test_object): self.spectrum[str(file)+self.SEPARATOR_CHARACTER+str(code_element)] = {"ef": ef, "ep":ep, "nf":nf,"np":np, "efmod": ef_mod, "epmod" : ep_mod} def heuristic_analyzer(self,test): - #chains from JSON project_path = os.path.abspath("callchains.json") with open(project_path) as file: - # print(f"{os.path.dirname(os.path.abspath(projectdir))}/D4J/{project}" + str(bugid) + "heuristics.txt") data = file.read() call_chains = json.loads(data) chains = call_chains[test] - # Flatten the list of chains and count their occurrences chain_lengths = len(chains) - # Rule 1: A test with only one chain of any length is a unit test if all([len(elem) == 1 for elem in chains]) and 0 < chain_lengths <= 1: return "put" if all([len(elem) <= 2 for elem in chains]) and chain_lengths > 0: return "smt" - # # Rule 2: If a test has multiple chains but they are consistent in length except for the last method - # if len(length_counts) > 1: - # unique_lengths = sorted(length_counts.keys()) - # if len(unique_lengths) == 2 and unique_lengths[1] - unique_lengths[0] == 1: - # unit_tests.append(test_name) - # continue - if chain_lengths == 1: if all([len(elem) <= 3 for elem in chains]): - # Rule 2: Single chain but not longer than 3 return "lmc" - # Rule 3: Single chain from test return "smc" def get_spectrum(self): From 65571165e432e54f08b738a37abdc89975e39410 Mon Sep 17 00:00:00 2001 From: Vandlik Viktor Date: Tue, 15 Apr 2025 15:19:10 +0200 Subject: [PATCH 05/13] barinel button, barinel score, modified barinel score --- .idea/CharmFL.iml | 7 +----- .idea/compiler.xml | 2 +- .idea/kotlinc.xml | 2 +- .idea/misc.xml | 5 ++++- .idea/modules.xml | 8 ------- .../java/actions/PluginAdvancedOptions.java | 1 + src/main/java/models/bean/ClassTestData.java | 22 +++++++++++++++++++ src/main/java/models/bean/Formula.java | 2 +- src/main/java/models/bean/ITestData.java | 5 +++++ src/main/java/models/bean/MethodTestData.java | 19 ++++++++++++++++ .../java/models/bean/StatementTestData.java | 16 ++++++++++++++ src/main/java/models/bean/TableData.java | 20 +++++++++++++++++ src/main/java/modules/PluginModule.java | 15 +++++++++++-- src/main/java/services/FlServiceImpl.java | 15 ++++++++++++- src/main/java/ui/AdvancedOptions.java | 9 +++++++- src/main/java/ui/ViewResult.java | 16 +++++++++----- .../ClassTableModel.java | 18 ++++++++++++--- .../MethodTableModel.java | 22 ++++++++++++++++--- .../StatementTableModel.java | 18 ++++++++++++--- src/main/resources/titles.properties | 1 + 20 files changed, 187 insertions(+), 36 deletions(-) delete mode 100644 .idea/modules.xml diff --git a/.idea/CharmFL.iml b/.idea/CharmFL.iml index 2191d23..9d38f51 100644 --- a/.idea/CharmFL.iml +++ b/.idea/CharmFL.iml @@ -1,10 +1,5 @@ - - - - - - + diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 202173e..fd9390f 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,7 +1,7 @@ - + - + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 1de5de2..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/src/main/java/actions/PluginAdvancedOptions.java b/src/main/java/actions/PluginAdvancedOptions.java index bd40677..189c4ae 100644 --- a/src/main/java/actions/PluginAdvancedOptions.java +++ b/src/main/java/actions/PluginAdvancedOptions.java @@ -26,6 +26,7 @@ public void actionPerformed(@NotNull AnActionEvent e) { FlServiceImpl flService = new FlServiceImpl(); if (dialog.showAndGet()) { + PluginModule.setBarinelSelected(dialog.isBarinelRadioButtonSelected()); PluginModule.setTarantulaSelected(dialog.isTarantulaRadioButtonSelected()); PluginModule.setOchiaiSelected(dialog.isOchiaiRadioButtonSelected()); PluginModule.setDStarSelected(dialog.isDStarRadioButtonSelected()); diff --git a/src/main/java/models/bean/ClassTestData.java b/src/main/java/models/bean/ClassTestData.java index f5e9e53..258ce43 100644 --- a/src/main/java/models/bean/ClassTestData.java +++ b/src/main/java/models/bean/ClassTestData.java @@ -13,6 +13,8 @@ public class ClassTestData implements ITestData{ private double ochiai; private double wong2; private double dstar; + private double barinel; + private double barinelModified; private int rank; private boolean faulty; private String relativePath; @@ -27,6 +29,8 @@ public ClassTestData() { ochiai = 0; wong2 = 0; dstar = 0; + barinel = 0; + barinelModified = 0; rank = 0; faulty = false; relativePath = ""; @@ -63,6 +67,24 @@ public void setLine(int line) { this.line = line; } + @Override + public double getBarinel() { + return barinel; + } + + @Override + public void setBarinel(double barinel) { + this.barinel = barinel; + } + + public double getBarinelModified() { + return barinelModified; + } + + public void setBarinelModified(double barinelModified) { + this.barinelModified = barinelModified; + } + /** * This provides the tarantula score of the class. * @return the score diff --git a/src/main/java/models/bean/Formula.java b/src/main/java/models/bean/Formula.java index 76c3c40..b842a9c 100644 --- a/src/main/java/models/bean/Formula.java +++ b/src/main/java/models/bean/Formula.java @@ -1,5 +1,5 @@ package models.bean; public enum Formula { - TARANTULA, OCHIAI, DSTAR, WONG2; + TARANTULA, OCHIAI, DSTAR, WONG2, BARINEL, BARINEL_MODIFIED; } diff --git a/src/main/java/models/bean/ITestData.java b/src/main/java/models/bean/ITestData.java index d3c0202..7a039b4 100644 --- a/src/main/java/models/bean/ITestData.java +++ b/src/main/java/models/bean/ITestData.java @@ -12,6 +12,11 @@ public interface ITestData { void setLine(int line); + double getBarinel(); + void setBarinel(double barinel); + + double getBarinelModified(); + void setBarinelModified(double barinelModified); double getTarantula(); void setTarantula(double tarantula); diff --git a/src/main/java/models/bean/MethodTestData.java b/src/main/java/models/bean/MethodTestData.java index 811ddba..d1de930 100644 --- a/src/main/java/models/bean/MethodTestData.java +++ b/src/main/java/models/bean/MethodTestData.java @@ -17,6 +17,8 @@ public class MethodTestData implements ITestData { private double ochiai; private double wong2; private double dstar; + private double barinel; + private double barinelModified; private int rank; private boolean faulty; private ArrayList statements; @@ -36,6 +38,8 @@ public MethodTestData() { ochiai = 0; wong2 = 0; dstar = 0; + barinel = 0; + barinelModified = 0; rank = 0; faulty = false; statements = new ArrayList<>(); @@ -176,6 +180,21 @@ public void setDstar(double wong2) { this.dstar = dstar; } + public double getBarinel() { + return barinel; + } + + public void setBarinel(double barinel) { + this.barinel = barinel; + } + + public double getBarinelModified() { + return barinelModified; + } + + public void setBarinelModified(double barinelModified) { + this.barinelModified = barinelModified; + } public int getRank() { return rank; diff --git a/src/main/java/models/bean/StatementTestData.java b/src/main/java/models/bean/StatementTestData.java index 1e6d3c4..53a226f 100644 --- a/src/main/java/models/bean/StatementTestData.java +++ b/src/main/java/models/bean/StatementTestData.java @@ -15,6 +15,8 @@ public class StatementTestData implements ITestData { private double ochiai; private double wong2; private double dstar; + private double barinel; + private double barinelModified; private int rank; private boolean faulty; private CloseContext closeContext; @@ -31,6 +33,8 @@ public StatementTestData() { ochiai = 0; wong2 = 0; dstar = 0; + barinel = 0; + barinelModified = 0; rank = 0; faulty = false; closeContext = new CloseContext(this); @@ -98,6 +102,18 @@ public void setLine(int line) { this.line = line; } + public double getBarinel() { + return barinel; + } + public void setBarinel(double barinel) { + this.barinel = barinel; + } + public double getBarinelModified() { + return barinelModified; + } + public void setBarinelModified(double barinelModified) { + this.barinelModified = barinelModified; + } /** * This provides the tarantula score of the class. * diff --git a/src/main/java/models/bean/TableData.java b/src/main/java/models/bean/TableData.java index e318070..72b5e94 100644 --- a/src/main/java/models/bean/TableData.java +++ b/src/main/java/models/bean/TableData.java @@ -16,6 +16,8 @@ public class TableData { private double tarantulaScore; private double ochiaiScore; private double wong2Score; + private double barinelScore; + private double barinelModifiedScore; private double minRank; private double maxRank; private double avgRank; @@ -31,6 +33,8 @@ public TableData() { tarantulaScore = 0; ochiaiScore = 0; wong2Score = 0; + barinelScore = 0; + barinelModifiedScore = 0; minRank = 0; maxRank = 0; avgRank = 0; @@ -88,6 +92,22 @@ public void setWong2Score(double wong2Score) { this.wong2Score = wong2Score; } + public double getBarinelScore() { + return barinelScore; + } + + public void setBarinelScore(double barinelScore) { + this.barinelScore = barinelScore; + } + + public double getBarinelModifiedScore() { + return barinelModifiedScore; + } + + public void setBarinelModifiedScore(double barinelModifiedScore) { + this.barinelModifiedScore = barinelModifiedScore; + } + public double getMinRank() { return minRank; } diff --git a/src/main/java/modules/PluginModule.java b/src/main/java/modules/PluginModule.java index 6a9733c..ae4050b 100644 --- a/src/main/java/modules/PluginModule.java +++ b/src/main/java/modules/PluginModule.java @@ -13,7 +13,9 @@ public class PluginModule { private static final String CHECK_PIP_BIN = "check_pip.py"; private static final String PIP_BIN = "pip"; private static final String REQUIREMENTS_FILE_NAME = "requirements.txt"; - private static final String RESULTS_JSON_FILE_NAME = "results.json"; + + private static final String RESULTS_JSON_FILE_NAME = "CharmFL"+File.separator+"results.json"; + private static final String PROMOTED_RESULTS_JSON_FILE_NAME = "CharmFL"+File.separator+"promoted_results.json"; private static PluginId pluginId = null; private static String pluginPath = ""; private static String pyflBinPath = ""; @@ -27,7 +29,8 @@ public class PluginModule { private static String pythonBinPath; private static String pipBinPath; - private static boolean tarantulaSelected = true; + private static boolean barinelSelected = true; + private static boolean tarantulaSelected = false; private static boolean ochiaiSelected = false; private static boolean dStarSelected = false; private static boolean wongIISelected = false; @@ -147,6 +150,14 @@ public static void setPythonBinPath(String pythonBinPath) { PluginModule.pythonBinPath = pythonBinPath; } + public static boolean isBarinelSelected() { + return barinelSelected; + } + + public static void setBarinelSelected(boolean barinelSelected) { + PluginModule.barinelSelected = barinelSelected; + } + /** * Returns whether Tarantula score calculation is the selected approach * @return true if tarantula is selected diff --git a/src/main/java/services/FlServiceImpl.java b/src/main/java/services/FlServiceImpl.java index 083d7df..8d35664 100644 --- a/src/main/java/services/FlServiceImpl.java +++ b/src/main/java/services/FlServiceImpl.java @@ -221,7 +221,7 @@ public TestData parseTestDataJSON(ArrayList lines) { JSONObject fileObject, classObject, methodObject, statementObject; String name; int line; - double tarantula, ochiai, wong2, dstar; + double tarantula, ochiai, wong2, dstar, barinel, barinelModified; int rank; boolean faulty; String relativePath = ""; @@ -313,6 +313,17 @@ public TestData parseTestDataJSON(ArrayList lines) { } else { dstar = 0; } + if (methodObject.has("barinel")){ + barinel = methodObject.getDouble("barinel"); + } else { + barinel = 0; + } + if (methodObject.has("modified_barinel")){ + barinelModified = methodObject.getDouble("modified_barinel"); + } else{ + barinelModified = 0; + } + if (methodObject.has("rank")) { rank = methodObject.getInt("rank"); } else { @@ -334,6 +345,8 @@ public TestData parseTestDataJSON(ArrayList lines) { methodTestData.setOchiai(ochiai); methodTestData.setWong2(wong2); methodTestData.setDstar(dstar); + methodTestData.setBarinel(barinel); + methodTestData.setBarinelModified(barinelModified); methodTestData.setRank(rank); methodTestData.setFaulty(faulty); diff --git a/src/main/java/ui/AdvancedOptions.java b/src/main/java/ui/AdvancedOptions.java index b87d70a..755e099 100644 --- a/src/main/java/ui/AdvancedOptions.java +++ b/src/main/java/ui/AdvancedOptions.java @@ -13,11 +13,11 @@ * This class represents the Options window. */ public class AdvancedOptions extends DialogWrapper { + private JRadioButton barinelRadioButton; private JRadioButton tarantulaRadioButton; private JRadioButton ochiaiRadioButton; private JRadioButton dStarRadioButton; private JRadioButton wong2RadioButton; - private JRadioButton minimumRadioButton; private JRadioButton maximumRadioButton; private JRadioButton averageRadioButton; @@ -44,18 +44,21 @@ protected JComponent createCenterPanel() { JLabel spectraMetricsLabel = new JLabel(Resources.get("titles", "spectra_metrics_label")); spectraMetricsLabel.setBorder(new EmptyBorder(0, 0, 5, 0)); + barinelRadioButton = new JRadioButton(Resources.get("titles", "barinel_button")); tarantulaRadioButton = new JRadioButton(Resources.get("titles", "tarantula_button")); ochiaiRadioButton = new JRadioButton(Resources.get("titles", "ochiai_button")); dStarRadioButton = new JRadioButton(Resources.get("titles", "dstar_button")); wong2RadioButton = new JRadioButton(Resources.get("titles", "wong_button")); ButtonGroup spectraMetricsButtonGroup = new ButtonGroup(); + spectraMetricsButtonGroup.add(barinelRadioButton); spectraMetricsButtonGroup.add(tarantulaRadioButton); spectraMetricsButtonGroup.add(ochiaiRadioButton); spectraMetricsButtonGroup.add(dStarRadioButton); spectraMetricsButtonGroup.add(wong2RadioButton); dialogPanel.add(spectraMetricsLabel); + dialogPanel.add(barinelRadioButton); dialogPanel.add(tarantulaRadioButton); dialogPanel.add(ochiaiRadioButton); //dialogPanel.add(dStarRadioButton); @@ -77,6 +80,7 @@ protected JComponent createCenterPanel() { dialogPanel.add(maximumRadioButton); dialogPanel.add(averageRadioButton); + barinelRadioButton.setSelected(PluginModule.isBarinelSelected()); tarantulaRadioButton.setSelected(PluginModule.isTarantulaSelected()); ochiaiRadioButton.setSelected(PluginModule.isOchiaiSelected()); dStarRadioButton.setSelected(PluginModule.isDStarSelected()); @@ -89,6 +93,9 @@ protected JComponent createCenterPanel() { return dialogPanel; } + public boolean isBarinelRadioButtonSelected(){ + return barinelRadioButton.isSelected(); + } /** * Tells you whether the button was selected * @return true if it is diff --git a/src/main/java/ui/ViewResult.java b/src/main/java/ui/ViewResult.java index 48fdca4..429edc9 100644 --- a/src/main/java/ui/ViewResult.java +++ b/src/main/java/ui/ViewResult.java @@ -81,6 +81,8 @@ public ViewResult() { spectraMetrics = " (WongII)"; } else if (PluginModule.isDStarSelected()) { spectraMetrics = " (DStar)"; + } else if (PluginModule.isBarinelSelected()) { + spectraMetrics = " (Barinel)"; } title += spectraMetrics; @@ -192,18 +194,21 @@ protected JComponent createCenterPanel() { ClassTableModel.FILE_NAME_COLUMN_INDEX, ClassTableModel.NAME_COLUMN_INDEX, ClassTableModel.SCORE_COLUMN_INDEX, + ClassTableModel.MODIFIED_SCORE_COLUMN_INDEX, ClassTableModel.LINE_COLUMN_INDEX); this.methodViewTable = createSubViewTable( methodTableModel, - methodTableModel.FILE_NAME_COLUMN_INDEX, + MethodTableModel.FILE_NAME_COLUMN_INDEX, MethodTableModel.NAME_COLUMN_INDEX, MethodTableModel.SCORE_COLUMN_INDEX, + MethodTableModel.MODIFIED_SCORE_COLUMN_INDEX, MethodTableModel.LINE_COLUMN_INDEX); this.statementViewTable = createSubViewTable( statementTableModel, - statementTableModel.NAME_COLUMN_INDEX, + StatementTableModel.NAME_COLUMN_INDEX, StatementTableModel.LINE_COLUMN_INDEX, StatementTableModel.SCORE_COLUMN_INDEX, + StatementTableModel.MODIFIED_SCORE_COLUMN_INDEX, StatementTableModel.RANK_COLUMN_INDEX); statementViewTable.addMouseListener(new StatementTableMouseListener(statementViewTable, testData)); @@ -220,13 +225,14 @@ protected JComponent createCenterPanel() { return tabsPane; } - private JBTable createSubViewTable(TableModel tableModel, int fileNameIndex, int nameColumnIndex, int scoreColumnIndex, int rankColumnIndex) { + private JBTable createSubViewTable(TableModel tableModel, int fileNameIndex, int nameColumnIndex, int scoreColumnIndex, int modifiedScoreColumnIndex, int rankColumnIndex) { JBTable table = new JBTable(tableModel); table.setAutoCreateRowSorter(true); - table.getColumnModel().getColumn(nameColumnIndex).setPreferredWidth(120); - table.getColumnModel().getColumn(fileNameIndex).setPreferredWidth(120); + table.getColumnModel().getColumn(nameColumnIndex).setPreferredWidth(80); + table.getColumnModel().getColumn(fileNameIndex).setPreferredWidth(115); table.getColumnModel().getColumn(scoreColumnIndex).setPreferredWidth(5); + table.getColumnModel().getColumn(modifiedScoreColumnIndex).setPreferredWidth(80); table.getColumnModel().getColumn(rankColumnIndex).setPreferredWidth(5); return table; diff --git a/src/main/java/ui/viewResultTableModels/ClassTableModel.java b/src/main/java/ui/viewResultTableModels/ClassTableModel.java index f192971..374ffaf 100644 --- a/src/main/java/ui/viewResultTableModels/ClassTableModel.java +++ b/src/main/java/ui/viewResultTableModels/ClassTableModel.java @@ -14,12 +14,13 @@ import services.Resources; public class ClassTableModel extends AbstractTableModel { - private static final String[] columnNames = {"File name", "Class name", "Score", "Line"}; + private static final String[] columnNames = {"File name", "Class name", "Score", "Modified Score", "Line"}; public static final int FILE_NAME_COLUMN_INDEX = 0; public static final int NAME_COLUMN_INDEX = 1; public static final int SCORE_COLUMN_INDEX = 2; - public static final int LINE_COLUMN_INDEX = 3; + public static final int MODIFIED_SCORE_COLUMN_INDEX = 3; + public static final int LINE_COLUMN_INDEX = 4; private final ArrayList tableDataList = new ArrayList<>(); @@ -47,6 +48,7 @@ private void parseData(TestData data) { classTableData.setName(classData.getName()); classTableData.setPath(relativePath); classTableData.setLine(classData.getLine()); + classTableData.setBarinelScore(classData.getBarinel()); classTableData.setTarantulaScore(classData.getTarantula()); classTableData.setOchiaiScore(classData.getOchiai()); classTableData.setWong2Score(classData.getWong2()); @@ -71,6 +73,8 @@ private void setRanks(){ scoreList.add(tableData.getOchiaiScore()); } else if (PluginModule.isWongIISelected() || PluginModule.isDStarSelected()) { scoreList.add(tableData.getWong2Score()); + } else if (PluginModule.isBarinelSelected()){ + scoreList.add(tableData.getBarinelScore()); } } @@ -113,6 +117,7 @@ public Class getColumnClass(int columnIndex) { case NAME_COLUMN_INDEX: return String.class; case SCORE_COLUMN_INDEX: + case MODIFIED_SCORE_COLUMN_INDEX: case LINE_COLUMN_INDEX: return Double.class; default: @@ -150,9 +155,16 @@ public Object getValueAt(int rowIndex, int columnIndex) { return tableDataAtRowIndex.getOchiaiScore(); } else if (spectraMetrics.equals(" (WongII)") || spectraMetrics.equals(" (DStar)")) { return tableDataAtRowIndex.getWong2Score(); - } else { + } else if (spectraMetrics.equals(" (Barinel)")){ + return tableDataAtRowIndex.getBarinelScore(); + } + else { return -1; } + case MODIFIED_SCORE_COLUMN_INDEX: + if (spectraMetrics.equals(" (Barinel)")){ + return tableDataAtRowIndex.getBarinelModifiedScore(); + } case LINE_COLUMN_INDEX: // if(selectedRankType.equals(Resources.get("titles", "average_button"))){ // return tableDataAtRowIndex.getAvgRank(); diff --git a/src/main/java/ui/viewResultTableModels/MethodTableModel.java b/src/main/java/ui/viewResultTableModels/MethodTableModel.java index 9043812..84e1f7d 100644 --- a/src/main/java/ui/viewResultTableModels/MethodTableModel.java +++ b/src/main/java/ui/viewResultTableModels/MethodTableModel.java @@ -13,12 +13,13 @@ import services.RankingService; public class MethodTableModel extends AbstractTableModel { - private static final String[] columnNames = {"File name", "Method name", "Score", "Line"}; + private static final String[] columnNames = {"File name", "Method name", "Score", "Modified Score", "Line"}; public static final int FILE_NAME_COLUMN_INDEX = 0; public static final int NAME_COLUMN_INDEX = 1; public static final int SCORE_COLUMN_INDEX = 2; - public static final int LINE_COLUMN_INDEX = 3; + public static final int MODIFIED_SCORE_COLUMN_INDEX = 3; + public static final int LINE_COLUMN_INDEX = 4; private final ArrayList tableDataList = new ArrayList<>(); @@ -43,6 +44,8 @@ private void parseData(TestData data) { methodTableData.setName(methodData.getSuperName() + File.separator + methodData.getName()); methodTableData.setPath(relativePath); methodTableData.setLine(methodData.getLine()); + methodTableData.setBarinelScore(methodData.getBarinel()); + methodTableData.setBarinelModifiedScore(methodData.getBarinelModified()); methodTableData.setTarantulaScore(methodData.getTarantula()); methodTableData.setOchiaiScore(methodData.getOchiai()); methodTableData.setWong2Score(methodData.getWong2()); @@ -64,6 +67,8 @@ private void setRanks(){ scoreList.add(tableData.getOchiaiScore()); } else if (PluginModule.isWongIISelected() || PluginModule.isDStarSelected()) { scoreList.add(tableData.getWong2Score()); + } else if (PluginModule.isBarinelSelected()){ + scoreList.add(tableData.getBarinelScore()); } } @@ -101,6 +106,7 @@ public Class getColumnClass(int columnIndex) { case NAME_COLUMN_INDEX: return String.class; case SCORE_COLUMN_INDEX: + case MODIFIED_SCORE_COLUMN_INDEX: case LINE_COLUMN_INDEX: return Double.class; default: @@ -132,7 +138,17 @@ public Object getValueAt(int rowIndex, int columnIndex) { return tableDataAtRowIndex.getOchiaiScore(); } else if (spectraMetrics.equals(" (WongII)") || spectraMetrics.equals(" (DStar)")) { return tableDataAtRowIndex.getWong2Score(); - } else { + } else if (spectraMetrics.equals(" (Barinel)")){ + return tableDataAtRowIndex.getBarinelScore(); + } + else { + return -1; + } + case MODIFIED_SCORE_COLUMN_INDEX: + if (spectraMetrics.equals(" (Barinel)")){ + return tableDataAtRowIndex.getBarinelModifiedScore(); + } + else { return -1; } case LINE_COLUMN_INDEX: diff --git a/src/main/java/ui/viewResultTableModels/StatementTableModel.java b/src/main/java/ui/viewResultTableModels/StatementTableModel.java index 1ba8b2a..13fd491 100644 --- a/src/main/java/ui/viewResultTableModels/StatementTableModel.java +++ b/src/main/java/ui/viewResultTableModels/StatementTableModel.java @@ -13,12 +13,13 @@ import services.Resources; public class StatementTableModel extends AbstractTableModel { - private static final String[] columnNames = {"File name", "Line", "Score", "Rank"}; + private static final String[] columnNames = {"File name", "Line", "Score", "Modified Score", "Rank"}; public static final int NAME_COLUMN_INDEX = 0; public static final int LINE_COLUMN_INDEX = 1; public static final int SCORE_COLUMN_INDEX = 2; - public static final int RANK_COLUMN_INDEX = 3; + public static final int MODIFIED_SCORE_COLUMN_INDEX = 3; + public static final int RANK_COLUMN_INDEX = 4; private final ArrayList tableDataList = new ArrayList<>(); @@ -42,6 +43,7 @@ private void parseData(TestData data) { thirdData.setName(""); thirdData.setPath(relativePath); thirdData.setLine(statementData.getLine()); + thirdData.setBarinelScore(statementData.getBarinel()); thirdData.setTarantulaScore(statementData.getTarantula()); thirdData.setOchiaiScore(statementData.getOchiai()); thirdData.setWong2Score(statementData.getWong2()); @@ -66,6 +68,8 @@ public void setRanks(){ scoreList.add(tableData.getOchiaiScore()); } else if (PluginModule.isWongIISelected() || PluginModule.isDStarSelected()) { scoreList.add(tableData.getWong2Score()); + } else if (PluginModule.isBarinelSelected()){ + scoreList.add(tableData.getBarinelScore()); } } @@ -106,6 +110,7 @@ public Class getColumnClass(int columnIndex) { case LINE_COLUMN_INDEX: return Integer.class; case SCORE_COLUMN_INDEX: + case MODIFIED_SCORE_COLUMN_INDEX: case RANK_COLUMN_INDEX: return Double.class; default: @@ -137,9 +142,16 @@ public Object getValueAt(int rowIndex, int columnIndex) { return tableDataAtRowIndex.getOchiaiScore(); } else if (selectedSpectraMetric.equals(" (WongII)") || selectedSpectraMetric.equals(" (DStar)")) { return tableDataAtRowIndex.getWong2Score(); - } else { + } else if (selectedSpectraMetric.equals(" (Barinel)")){ + return tableDataAtRowIndex.getBarinelScore(); + } + else { return -1; } + case MODIFIED_SCORE_COLUMN_INDEX: + if (selectedSpectraMetric.equals(" (Barinel)")){ + return tableDataAtRowIndex.getBarinelModifiedScore(); + } case RANK_COLUMN_INDEX: if(selectedRankType.equals(Resources.get("titles", "average_button"))){ return tableDataAtRowIndex.getAvgRank(); diff --git a/src/main/resources/titles.properties b/src/main/resources/titles.properties index 3e6aad6..ffe2e66 100644 --- a/src/main/resources/titles.properties +++ b/src/main/resources/titles.properties @@ -27,6 +27,7 @@ spectra_metrics_label=Spectra metrics: ranks_label=Tie Ranks: #Radio button and button titles in the ui +barinel_button=Barinel tarantula_button=Tarantula ochiai_button=Ochiai dstar_button=DStar From 64e9b92f7263e1f83c964793f2cad6ad1a4afd00 Mon Sep 17 00:00:00 2001 From: Vandlik Viktor Date: Wed, 16 Apr 2025 14:38:03 +0200 Subject: [PATCH 06/13] show call chains menubutton, make json --- .idea/CharmFL.iml | 4 ++++ .idea/misc.xml | 2 +- src/main/java/actions/PluginCallGraph.java | 5 ++++- src/main/python/faultloc/Spectra.py | 12 ++++++++++++ src/main/resources/META-INF/plugin.xml | 3 ++- 5 files changed, 23 insertions(+), 3 deletions(-) diff --git a/.idea/CharmFL.iml b/.idea/CharmFL.iml index 9d38f51..aad402c 100644 --- a/.idea/CharmFL.iml +++ b/.idea/CharmFL.iml @@ -1,5 +1,9 @@ + + diff --git a/.idea/misc.xml b/.idea/misc.xml index d498b57..92410fa 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -7,5 +7,5 @@ - + \ No newline at end of file diff --git a/src/main/java/actions/PluginCallGraph.java b/src/main/java/actions/PluginCallGraph.java index 945fe7e..f02fd12 100644 --- a/src/main/java/actions/PluginCallGraph.java +++ b/src/main/java/actions/PluginCallGraph.java @@ -1,5 +1,6 @@ package actions; +import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import modules.ProjectModule; import org.apache.commons.lang3.SystemUtils; @@ -35,7 +36,7 @@ public void actionPerformed(@NotNull AnActionEvent e) { FlServiceImpl flService = new FlServiceImpl(); if (flService.isTestDataCollected()) { - + /* File file = new File(ProjectModule.getProjectPath() + File.separator + "static_call_graph.html"); Writer fileWriter; @@ -92,7 +93,9 @@ public void actionPerformed(@NotNull AnActionEvent e) { } JOptionPane.showMessageDialog(null, "Creating call graph was successful.\nYou may open the generated html file in any browser." + "\nThe file is located at " + ProjectModule.getProjectPath() + File.separator + "static_call_graph.html", "Call Graph is ready", JOptionPane.PLAIN_MESSAGE); + */ //new PopUpView("static_call_graph.html").show(); + new CallGraphView("callchains.html", e.getProject()).show(); } else { Messages.showMessageDialog( e.getProject(), diff --git a/src/main/python/faultloc/Spectra.py b/src/main/python/faultloc/Spectra.py index 7c7e009..d958d8d 100644 --- a/src/main/python/faultloc/Spectra.py +++ b/src/main/python/faultloc/Spectra.py @@ -9,6 +9,8 @@ def __init__(self): def create_spectrum_from(self, coverage_object, test_object): + project_path = os.path.abspath("cc.json") + call_chains = {} test_result = test_object.get_tests_results() coverage_result = coverage_object.get_coverage_with_context() @@ -26,6 +28,12 @@ def create_spectrum_from(self, coverage_object, test_object): ep = ep + 1 if test_result[counted_tests[0]] == "PASSED" else ep h = self.heuristic_analyzer(test) + + test_name = counted_tests[0] + status = test_result[test_name] + call_chains[test_name] = [status, h] + + ef_mod = ef_mod + 1 if test_result[counted_tests[0]] == "FAILED" else ef_mod ep_mod = ep_mod + 1 if test_result[counted_tests[0]] == "PASSED" and h != "put" else ep_mod @@ -34,6 +42,9 @@ def create_spectrum_from(self, coverage_object, test_object): self.spectrum[str(file)+self.SEPARATOR_CHARACTER+str(code_element)] = {"ef": ef, "ep":ep, "nf":nf,"np":np, "efmod": ef_mod, "epmod" : ep_mod} + with open(project_path, "w") as f: + json.dump(call_chains, f) + def heuristic_analyzer(self,test): project_path = os.path.abspath("callchains.json") @@ -55,6 +66,7 @@ def heuristic_analyzer(self,test): if all([len(elem) <= 3 for elem in chains]): return "lmc" return "smc" + return "other" def get_spectrum(self): return self.spectrum diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index b7d259a..d361181 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -14,7 +14,8 @@ Visualization - + + Settings From e5b49ab72f562253fab8e9e04b7a06cd7dc95a94 Mon Sep 17 00:00:00 2001 From: Vandlik Viktor Date: Wed, 16 Apr 2025 18:57:47 +0200 Subject: [PATCH 07/13] . --- src/main/java/actions/PluginTestView.java | 32 +++ src/main/java/models/bean/TableData.java | 33 +++ src/main/java/models/bean/TestResultData.java | 25 ++ src/main/java/models/bean/ViewTestData.java | 33 +++ src/main/java/modules/PluginModule.java | 5 + src/main/java/services/FlServiceImpl.java | 47 ++++ .../runnables/EditorColorRunnable.java | 1 + .../services/runnables/RunTestRunnable.java | 7 +- src/main/java/ui/ViewTest.java | 223 ++++++++++++++++++ .../viewResultTableModels/TestTableModel.java | 51 ++++ src/main/resources/META-INF/plugin.xml | 2 +- 11 files changed, 457 insertions(+), 2 deletions(-) create mode 100644 src/main/java/actions/PluginTestView.java create mode 100644 src/main/java/models/bean/TestResultData.java create mode 100644 src/main/java/models/bean/ViewTestData.java create mode 100644 src/main/java/ui/ViewTest.java create mode 100644 src/main/java/ui/viewResultTableModels/TestTableModel.java diff --git a/src/main/java/actions/PluginTestView.java b/src/main/java/actions/PluginTestView.java new file mode 100644 index 0000000..befb4d1 --- /dev/null +++ b/src/main/java/actions/PluginTestView.java @@ -0,0 +1,32 @@ +package actions; + +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.openapi.ui.Messages; +import org.jetbrains.annotations.NotNull; +import services.FlServiceImpl; +import services.Resources; +import ui.ViewTest; + +public class PluginTestView extends DumbAwareAction { + /** + * When you click on the menu item, then this will show the table data. + * If the Fault localization has been run, then it will just open the data with the results + * Otherwise it presents an error message. + * @param e + */ + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + FlServiceImpl flService = new FlServiceImpl(); + if (flService.isTestDataCollected()) { + flService.setViewTestTableDialogOpened(true); + new ViewTest().show(); + } else { + Messages.showMessageDialog( + e.getProject(), + Resources.get("errors", "run_tests_error"), + Resources.get("titles", "data_not_collected_title"), + Messages.getErrorIcon()); + } + } +} \ No newline at end of file diff --git a/src/main/java/models/bean/TableData.java b/src/main/java/models/bean/TableData.java index 72b5e94..9af818a 100644 --- a/src/main/java/models/bean/TableData.java +++ b/src/main/java/models/bean/TableData.java @@ -26,6 +26,12 @@ public class TableData { private int level; private boolean hide; + private String testName; + + private String testResult; + + private String testHeuristic; + public TableData() { name = ""; path = ""; @@ -42,6 +48,9 @@ public TableData() { icon = null; level = 0; hide = false; + testName = ""; + testResult = ""; + testHeuristic = ""; } public String getName() { @@ -156,6 +165,30 @@ public void setLevel(int level) { this.level = level; } + public String getTestName() { + return testName; + } + + public void setTestName(String testName) { + this.testName = testName; + } + + public String getTestResult() { + return testResult; + } + + public void setTestResult(String testResult) { + this.testResult = testResult; + } + + public String getTestHeuristic() { + return testHeuristic; + } + + public void setTestHeuristic(String testHeuristic) { + this.testHeuristic = testHeuristic; + } + /** * Tells you whether the row is hidden or not * @return true if the row is hidden diff --git a/src/main/java/models/bean/TestResultData.java b/src/main/java/models/bean/TestResultData.java new file mode 100644 index 0000000..1d62d1c --- /dev/null +++ b/src/main/java/models/bean/TestResultData.java @@ -0,0 +1,25 @@ +package models.bean; + +import java.util.ArrayList; + +public class TestResultData{ + String testname; + ArrayList list; + + + public String getTestname() { + return testname; + } + + public void setTestname(String testname) { + this.testname = testname; + } + + public ArrayList getList() { + return list; + } + + public void setList(ArrayList list) { + this.list = list; + } +} diff --git a/src/main/java/models/bean/ViewTestData.java b/src/main/java/models/bean/ViewTestData.java new file mode 100644 index 0000000..ed3407e --- /dev/null +++ b/src/main/java/models/bean/ViewTestData.java @@ -0,0 +1,33 @@ +package models.bean; + +import java.util.ArrayList; +import java.util.HashMap; + +public class ViewTestData { +//cc.json-t reprezentálja + private static ViewTestData instance; + + private HashMap tests; + + public static ViewTestData getInstance() { + if (instance == null) { + instance = new ViewTestData(); + } + return instance; + } + + public static ViewTestData getInstance(String relativePath) { + if (instance == null) { + instance = new ViewTestData(); + } + return instance; + } + + public HashMap getTests() { + return tests; + } + + public void setTests(HashMap tests) { + this.tests = tests; + } +} diff --git a/src/main/java/modules/PluginModule.java b/src/main/java/modules/PluginModule.java index ae4050b..85f6432 100644 --- a/src/main/java/modules/PluginModule.java +++ b/src/main/java/modules/PluginModule.java @@ -15,6 +15,7 @@ public class PluginModule { private static final String REQUIREMENTS_FILE_NAME = "requirements.txt"; private static final String RESULTS_JSON_FILE_NAME = "CharmFL"+File.separator+"results.json"; + private static final String CC_JSON_FILE_NAME = "cc.json"; private static final String PROMOTED_RESULTS_JSON_FILE_NAME = "CharmFL"+File.separator+"promoted_results.json"; private static PluginId pluginId = null; private static String pluginPath = ""; @@ -146,6 +147,10 @@ public static final String getResultsJsonFileName() { return RESULTS_JSON_FILE_NAME; } + public static final String getCcJsonFileName() { + return CC_JSON_FILE_NAME; + } + public static void setPythonBinPath(String pythonBinPath) { PluginModule.pythonBinPath = pythonBinPath; } diff --git a/src/main/java/services/FlServiceImpl.java b/src/main/java/services/FlServiceImpl.java index 8d35664..a17712f 100644 --- a/src/main/java/services/FlServiceImpl.java +++ b/src/main/java/services/FlServiceImpl.java @@ -2,6 +2,7 @@ import java.io.*; import java.util.ArrayList; +import java.util.HashMap; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.fileEditor.FileEditorManagerEvent; @@ -23,9 +24,11 @@ public class FlServiceImpl { private static TestData testData = null; + private static ViewTestData viewTestData = null; private static boolean testDataCollected = false; private static boolean fileEditorColoringEnabled = false; private static boolean viewResultTableDialogOpened = false; + private static boolean viewTestTableDialogOpened = false; private static boolean testDataCollecting = false; /** @@ -391,6 +394,42 @@ public TestData parseTestDataJSON(ArrayList lines) { return testData; } + + public ViewTestData parseViewTestDataJSON(ArrayList lines) { + ViewTestData viewTestData = ViewTestData.getInstance(); + String json = String.join(" ", lines); + JSONObject jsonObject = new JSONObject(json); + + for (String testname : jsonObject.keySet()) { + JSONArray arr = jsonObject.getJSONArray(testname); + String result = arr.optString(0); + String heuristic = arr.optString(1); + + TestResultData testResult = new TestResultData(); + testResult.setTestname(testname); + ArrayList list = new ArrayList<>(); + list.add(result); + list.add(heuristic); + testResult.setList(list); + + HashMap hash= new HashMap<>(); + hash.put(testResult.getTestname(), testResult.getList()); + + viewTestData.setTests(hash); + } + + return viewTestData; + } + + + public static ViewTestData getViewTestData() { + return viewTestData; + } + + public static void setViewTestData(ViewTestData viewTestData) { + FlServiceImpl.viewTestData = viewTestData; + } + public TestData getTestData() { return FlServiceImpl.testData; } @@ -470,6 +509,14 @@ public void setViewResultTableDialogOpened(boolean viewResultTableDialogOpened) FlServiceImpl.viewResultTableDialogOpened = viewResultTableDialogOpened; } + public static boolean isViewTestTableDialogOpened() { + return viewTestTableDialogOpened; + } + + public static void setViewTestTableDialogOpened(boolean viewTestTableDialogOpened) { + FlServiceImpl.viewTestTableDialogOpened = viewTestTableDialogOpened; + } + public boolean isTestDataCollecting() { return testDataCollecting; } diff --git a/src/main/java/services/runnables/EditorColorRunnable.java b/src/main/java/services/runnables/EditorColorRunnable.java index 5aad7a5..28e316d 100644 --- a/src/main/java/services/runnables/EditorColorRunnable.java +++ b/src/main/java/services/runnables/EditorColorRunnable.java @@ -47,6 +47,7 @@ public void run() { flService.startFileEditorManagerListener(ProjectModule.getProject()); flService.setViewResultTableDialogOpened(true); + flService.setViewTestTableDialogOpened(true); flService.setTestDataCollecting(false); //new ViewResult().show(); ViewResultHolder.reOpen(); diff --git a/src/main/java/services/runnables/RunTestRunnable.java b/src/main/java/services/runnables/RunTestRunnable.java index 5fb493a..93ab1df 100644 --- a/src/main/java/services/runnables/RunTestRunnable.java +++ b/src/main/java/services/runnables/RunTestRunnable.java @@ -400,7 +400,11 @@ public void parseResults(FlServiceImpl flService, ProgressIndicator progressIndi ArrayList lines = flService.readTextFile( ProjectModule.getProjectPath() + File.separator + PluginModule.getResultsJsonFileName()); - if (lines.size() == 0) { + + ArrayList lines2 = flService.readTextFile( + ProjectModule.getProjectPath() + File.separator + PluginModule.getCcJsonFileName()); + + if (lines.isEmpty() || lines2.isEmpty()) { ApplicationManager.getApplication().invokeLater(() -> { Messages.showMessageDialog( ProjectModule.getProject(), @@ -413,6 +417,7 @@ public void parseResults(FlServiceImpl flService, ProgressIndicator progressIndi } flService.clearTestData(); flService.setTestData(flService.parseTestDataJSON(lines)); + flService.setViewTestData(flService.parseViewTestDataJSON(lines2)); } diff --git a/src/main/java/ui/ViewTest.java b/src/main/java/ui/ViewTest.java new file mode 100644 index 0000000..b8f7ffd --- /dev/null +++ b/src/main/java/ui/ViewTest.java @@ -0,0 +1,223 @@ +package ui; + +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.ui.JBColor; +import com.intellij.ui.SearchTextField; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.ui.table.JBTable; +import models.bean.ViewTestData; +import modules.PluginModule; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import services.FlServiceImpl; +import services.Resources; +import ui.viewResultTableModels.*; + +import javax.swing.*; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.table.TableModel; +import javax.swing.table.TableRowSorter; +import java.awt.*; +import java.awt.event.*; + +public class ViewTest extends DialogWrapper { + + private final FlServiceImpl flService = null; + private final ViewTestData viewTestData = null; + private TestTableModel testViewTableModel; + private JTable testViewTable; + private JTable treeViewTable; + private JTabbedPane tabsPane; + + public ViewTest() { + super(true); + tabsPane = new JTabbedPane(); + String rankType = ""; + if (PluginModule.isAverageSelected()) { + rankType = Resources.get("titles", "average_button"); + } else if (PluginModule.isMinimumSelected()) { + rankType = Resources.get("titles", "minimum_button"); + } else if (PluginModule.isMaximumSelected()) { + rankType = Resources.get("titles", "maximum_button"); + } + + String title = "Test Call Chains"; + String spectraMetrics = ""; + if (PluginModule.isTarantulaSelected()) { + spectraMetrics = " (Tarantula)"; + } else if (PluginModule.isOchiaiSelected()) { + spectraMetrics = " (Ochiai)"; + } else if (PluginModule.isWongIISelected()) { + spectraMetrics = " (WongII)"; + } else if (PluginModule.isDStarSelected()) { + spectraMetrics = " (DStar)"; + } else if (PluginModule.isBarinelSelected()) { + spectraMetrics = " (Barinel)"; + } + title += spectraMetrics; + + setTitle(title); + + + setModal(false); + getWindow().addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent we) { + closeWindow(); + } + }); + init(); + } + + public int getSelectedIndex(){return tabsPane.getSelectedIndex();} + public void setSelectedIndex(int index){tabsPane.setSelectedIndex(index);} + + private static class SearchField { + + SearchTextField searchTextField; + String placeholderText; + + public SearchField(String placeholderText) { + this.searchTextField = new SearchTextField(); + this.placeholderText = placeholderText; + setPlaceholder(); + } + + private void setPlaceholder() { + this.searchTextField.setText(this.placeholderText); + this.searchTextField.getTextEditor().setForeground(JBColor.GRAY); + + this.searchTextField.getTextEditor().addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + if (searchTextField.getText().equals(placeholderText)) { + searchTextField.setText(""); + searchTextField.getTextEditor().setForeground(JBColor.BLACK); + } + } + + @Override + public void focusLost(FocusEvent e) { + if (searchTextField.getText().isEmpty()) { + searchTextField.getTextEditor().setForeground(JBColor.GRAY); + searchTextField.setText(placeholderText); + } + } + }); + } + + private void setSorter(TableRowSorter sorter) { + this.searchTextField.addDocumentListener(new DocumentListener() { + @Override + public void insertUpdate(DocumentEvent e) { + String text = searchTextField.getText(); + if (text.trim().length() == 0 || searchTextField.getText().equals(placeholderText)) { + sorter.setRowFilter(null); + } else { + sorter.setRowFilter(RowFilter.regexFilter(text)); + } + } + + @Override + public void removeUpdate(DocumentEvent e) { + String text = searchTextField.getText(); + if (text.trim().length() == 0 || searchTextField.getText().equals(placeholderText)) { + sorter.setRowFilter(null); + } else { + sorter.setRowFilter(RowFilter.regexFilter(text)); + } + } + + @Override + public void changedUpdate(DocumentEvent e) { + + } + }); + } + } + + + @Nullable + @Override + protected JComponent createCenterPanel() { + return tabsPane; + } + + private JBTable createSubViewTable(TableModel tableModel, int fileNameIndex, int nameColumnIndex, int scoreColumnIndex, int modifiedScoreColumnIndex, int rankColumnIndex) { + JBTable table = new JBTable(); + table.setAutoCreateRowSorter(true); + + table.getColumnModel().getColumn(nameColumnIndex).setPreferredWidth(80); + table.getColumnModel().getColumn(fileNameIndex).setPreferredWidth(115); + table.getColumnModel().getColumn(scoreColumnIndex).setPreferredWidth(5); + table.getColumnModel().getColumn(modifiedScoreColumnIndex).setPreferredWidth(80); + table.getColumnModel().getColumn(rankColumnIndex).setPreferredWidth(5); + + return table; + } + + private JBScrollPane createTableScrollPane(JTable table) { + JPanel mainPanel = createSearchField(table); + + JBScrollPane scrollPane = new JBScrollPane(mainPanel); + scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); + scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); + return scrollPane; + } + + private JPanel createSearchField(JTable table) { + JPanel mainPanel = new JPanel(); + mainPanel.setLayout(new BorderLayout()); + if (!(table.getModel().getClass().toString()).equals(TreeTableModel.class.toString())) { + final TableRowSorter sorter = new TableRowSorter<>(table.getModel()); + table.setRowSorter(sorter); + table.getRowSorter().toggleSortOrder(2); + table.getRowSorter().toggleSortOrder(2); + + JPanel headerPanel = new JPanel(); + headerPanel.setLayout(new BoxLayout(headerPanel, BoxLayout.Y_AXIS)); + + String placeholderText = ""; + + if ((table.getModel().getClass().toString()).equals(ClassTableModel.class.toString())) { + placeholderText = Resources.get("titles", "class_placeholder"); + } else if ((table.getModel().getClass().toString()).equals(MethodTableModel.class.toString())) { + placeholderText = Resources.get("titles", "method_placeholder"); + } else if ((table.getModel().getClass().toString()).equals(StatementTableModel.class.toString())) { + placeholderText = Resources.get("titles", "statement_placeholder"); + } + String finalPlaceholderText = placeholderText; + + SearchField searchField = new SearchField(finalPlaceholderText); + searchField.setSorter(sorter); + + headerPanel.add(searchField.searchTextField); + headerPanel.add(table.getTableHeader()); + mainPanel.add(headerPanel, BorderLayout.PAGE_START); + } else { + mainPanel.add(table.getTableHeader(), BorderLayout.PAGE_START); + } + + mainPanel.add(table, BorderLayout.CENTER); + return mainPanel; + } + + private void closeWindow() { + //refresh(); + flService.setViewTestTableDialogOpened(false); + close(0); + } + + @Override + protected @NotNull Action[] createActions() { + Action close = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + closeWindow(); + } + }; + + close.putValue(Action.NAME, "Close"); + return new Action[] {close}; + } +} \ No newline at end of file diff --git a/src/main/java/ui/viewResultTableModels/TestTableModel.java b/src/main/java/ui/viewResultTableModels/TestTableModel.java new file mode 100644 index 0000000..336dc41 --- /dev/null +++ b/src/main/java/ui/viewResultTableModels/TestTableModel.java @@ -0,0 +1,51 @@ +package ui.viewResultTableModels; + +import models.bean.*; + +import javax.swing.table.AbstractTableModel; +import java.util.ArrayList; +import java.util.Map; + +public class TestTableModel extends AbstractTableModel { + + private final ArrayList tableDataList = new ArrayList<>(); + + public TestTableModel(ViewTestData testData) { + parseData(testData); + } + private void parseData(ViewTestData testData) { + for (Map.Entry entry : testData.getTests().entrySet()) { + String testname = entry.getKey(); + ArrayList values = entry.getValue(); + + if (values.size() < 2) { + continue; + } + + String result = values.get(0); + String heuristic = values.get(1); + + TableData tableData = new TableData(); + tableData.setTestName(testname); + tableData.setTestResult(result); + tableData.setTestHeuristic(heuristic); + + this.tableDataList.add(tableData); + } + } + + @Override + public int getRowCount() { + return 0; + } + + @Override + public int getColumnCount() { + return 0; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + return null; + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index d361181..8b33144 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -15,7 +15,7 @@ Visualization - + Settings From e014a6c0f28e8c1763ecf4eb1e8538ab42d281e7 Mon Sep 17 00:00:00 2001 From: Vandlik Viktor Date: Thu, 17 Apr 2025 10:46:51 +0200 Subject: [PATCH 08/13] test call chains --- src/main/java/models/bean/ViewTestData.java | 6 +-- src/main/java/services/FlServiceImpl.java | 2 +- src/main/java/ui/ViewTest.java | 26 ++++++++-- .../listener/AbstractTableMouseListener.java | 10 ++++ .../listener/CallChainTableMouseListener.java | 45 ++++++++++++++++ .../viewResultTableModels/TestTableModel.java | 52 +++++++++++++++++-- 6 files changed, 130 insertions(+), 11 deletions(-) create mode 100644 src/main/java/ui/listener/CallChainTableMouseListener.java diff --git a/src/main/java/models/bean/ViewTestData.java b/src/main/java/models/bean/ViewTestData.java index ed3407e..d93d3d5 100644 --- a/src/main/java/models/bean/ViewTestData.java +++ b/src/main/java/models/bean/ViewTestData.java @@ -7,7 +7,7 @@ public class ViewTestData { //cc.json-t reprezentálja private static ViewTestData instance; - private HashMap tests; + private HashMap> tests; public static ViewTestData getInstance() { if (instance == null) { @@ -23,11 +23,11 @@ public static ViewTestData getInstance(String relativePath) { return instance; } - public HashMap getTests() { + public HashMap> getTests() { return tests; } - public void setTests(HashMap tests) { + public void setTests(HashMap> tests) { this.tests = tests; } } diff --git a/src/main/java/services/FlServiceImpl.java b/src/main/java/services/FlServiceImpl.java index a17712f..d6c5f57 100644 --- a/src/main/java/services/FlServiceImpl.java +++ b/src/main/java/services/FlServiceImpl.java @@ -399,6 +399,7 @@ public ViewTestData parseViewTestDataJSON(ArrayList lines) { ViewTestData viewTestData = ViewTestData.getInstance(); String json = String.join(" ", lines); JSONObject jsonObject = new JSONObject(json); + HashMap> hash= new HashMap<>(); for (String testname : jsonObject.keySet()) { JSONArray arr = jsonObject.getJSONArray(testname); @@ -412,7 +413,6 @@ public ViewTestData parseViewTestDataJSON(ArrayList lines) { list.add(heuristic); testResult.setList(list); - HashMap hash= new HashMap<>(); hash.put(testResult.getTestname(), testResult.getList()); viewTestData.setTests(hash); diff --git a/src/main/java/ui/ViewTest.java b/src/main/java/ui/ViewTest.java index b8f7ffd..62f8005 100644 --- a/src/main/java/ui/ViewTest.java +++ b/src/main/java/ui/ViewTest.java @@ -5,12 +5,16 @@ import com.intellij.ui.SearchTextField; import com.intellij.ui.components.JBScrollPane; import com.intellij.ui.table.JBTable; +import models.bean.TestData; import models.bean.ViewTestData; import modules.PluginModule; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import services.FlServiceImpl; import services.Resources; +import ui.listener.CallChainTableMouseListener; +import ui.listener.ClassTableMouseListener; +import ui.listener.TreeViewTableMouseListener; import ui.viewResultTableModels.*; import javax.swing.*; @@ -21,13 +25,14 @@ import java.awt.*; import java.awt.event.*; +import static javax.swing.ListSelectionModel.SINGLE_SELECTION; + public class ViewTest extends DialogWrapper { - private final FlServiceImpl flService = null; - private final ViewTestData viewTestData = null; + private final FlServiceImpl flService; + private final ViewTestData viewTestData; private TestTableModel testViewTableModel; private JTable testViewTable; - private JTable treeViewTable; private JTabbedPane tabsPane; public ViewTest() { @@ -59,6 +64,9 @@ public ViewTest() { setTitle(title); + flService = new FlServiceImpl(); + viewTestData = ViewTestData.getInstance(); + testViewTableModel = new TestTableModel(viewTestData); setModal(false); getWindow().addWindowListener(new WindowAdapter() { @@ -140,6 +148,18 @@ public void changedUpdate(DocumentEvent e) { @Nullable @Override protected JComponent createCenterPanel() { + this.testViewTable = new JBTable(testViewTableModel); + + testViewTable.addMouseListener(new CallChainTableMouseListener(testViewTable,viewTestData)); + //testViewTable.setSelectionMode(SINGLE_SELECTION); + //testViewTable.setAutoCreateRowSorter(true); + testViewTable.getColumnModel().getColumn(TestTableModel.TESTNAME_COLUMN_INDEX).setPreferredWidth(250); + testViewTable.getColumnModel().getColumn(TestTableModel.RESULT_COLUMN_INDEX).setPreferredWidth(75); + testViewTable.getColumnModel().getColumn(TestTableModel.HEURISTIC_COLUMN_INDEX).setPreferredWidth(75); + tabsPane.addTab(Resources.get("titles", "tree_pane"), createTableScrollPane(testViewTable)); + tabsPane.setPreferredSize(new Dimension(500, 500)); + tabsPane.setLocation(600,300); + pack(); return tabsPane; } diff --git a/src/main/java/ui/listener/AbstractTableMouseListener.java b/src/main/java/ui/listener/AbstractTableMouseListener.java index 719c6eb..b3c87ff 100644 --- a/src/main/java/ui/listener/AbstractTableMouseListener.java +++ b/src/main/java/ui/listener/AbstractTableMouseListener.java @@ -4,6 +4,7 @@ import com.intellij.openapi.wm.ToolWindowManager; import com.intellij.ui.components.JBTabbedPane; import models.bean.TestData; +import models.bean.ViewTestData; import models.bean.context.Context; import modules.PluginModule; import modules.ProjectModule; @@ -17,18 +18,27 @@ public abstract class AbstractTableMouseListener extends MouseInputAdapter { protected final JTable resultTable; protected final TestData testData; + protected final ViewTestData viewTestData; protected final TreeTableModel tableModel; public AbstractTableMouseListener(JTable resultTable, TestData testData) { this.resultTable = resultTable; this.testData = testData; this.tableModel = null; + this.viewTestData = null; } + public AbstractTableMouseListener(JTable resultTable, ViewTestData viewTestData) { + this.resultTable = resultTable; + this.viewTestData = viewTestData; + this.testData = null; + this.tableModel = null; + } public AbstractTableMouseListener(JTable resultTable, TreeTableModel tableModel) { this.resultTable = resultTable; this.tableModel = tableModel; this.testData = null; + this.viewTestData = null; } protected void updateIndicatorPanel(String path, String name, int lineNumber){ diff --git a/src/main/java/ui/listener/CallChainTableMouseListener.java b/src/main/java/ui/listener/CallChainTableMouseListener.java new file mode 100644 index 0000000..d1d4d29 --- /dev/null +++ b/src/main/java/ui/listener/CallChainTableMouseListener.java @@ -0,0 +1,45 @@ +package ui.listener; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.LogicalPosition; +import com.intellij.openapi.editor.ScrollType; +import com.intellij.openapi.fileEditor.FileEditorManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.vfs.LocalFileSystem; +import com.intellij.openapi.vfs.VirtualFile; +import models.bean.ClassTestData; +import models.bean.TestData; +import models.bean.ViewTestData; +import modules.ProjectModule; +import ui.CallGraphView; +import ui.viewResultTableModels.ClassTableModel; +import ui.viewResultTableModels.TestTableModel; + +import javax.swing.*; +import java.awt.event.MouseEvent; +import java.io.File; +import java.util.List; +import java.util.stream.Collectors; +public class CallChainTableMouseListener extends AbstractTableMouseListener{ + + public CallChainTableMouseListener(JTable resultTable, ViewTestData viewTestData) { + super(resultTable, viewTestData); + } + + @Override + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) { + int row = resultTable.rowAtPoint(e.getPoint()); + int column = resultTable.columnAtPoint(e.getPoint()); + + if (row >= 0 && column >= 0) { + Object value = resultTable.getValueAt(row, column); + String filename = value != null ? value + "_call_chain.html" : ""; + System.out.println(filename); + new CallGraphView(filename, ProjectModule.getProject()).show(); + } + } + } + +} + diff --git a/src/main/java/ui/viewResultTableModels/TestTableModel.java b/src/main/java/ui/viewResultTableModels/TestTableModel.java index 336dc41..c98d274 100644 --- a/src/main/java/ui/viewResultTableModels/TestTableModel.java +++ b/src/main/java/ui/viewResultTableModels/TestTableModel.java @@ -1,7 +1,10 @@ package ui.viewResultTableModels; import models.bean.*; +import org.apache.commons.collections.bag.SynchronizedSortedBag; +import org.jetbrains.annotations.Nls; +import javax.swing.*; import javax.swing.table.AbstractTableModel; import java.util.ArrayList; import java.util.Map; @@ -10,11 +13,17 @@ public class TestTableModel extends AbstractTableModel { private final ArrayList tableDataList = new ArrayList<>(); + private static final String[] columnNames = {"Test Name", "Result", "Heuristic"}; + + public static final int TESTNAME_COLUMN_INDEX = 0; + public static final int RESULT_COLUMN_INDEX = 1; + public static final int HEURISTIC_COLUMN_INDEX = 2; + public TestTableModel(ViewTestData testData) { parseData(testData); } private void parseData(ViewTestData testData) { - for (Map.Entry entry : testData.getTests().entrySet()) { + for (Map.Entry> entry : testData.getTests().entrySet()) { String testname = entry.getKey(); ArrayList values = entry.getValue(); @@ -36,16 +45,51 @@ private void parseData(ViewTestData testData) { @Override public int getRowCount() { - return 0; + int count = 0; + for (TableData tableData : tableDataList) { + if (!tableData.isHide()) count++; + } + return count; } @Override public int getColumnCount() { - return 0; + return columnNames.length; + } + + @Nls + @Override + public String getColumnName(int columnIndex) { + return columnNames[columnIndex]; + } + + @Override + public Class getColumnClass(int columnIndex) { + switch (columnIndex) { + case TESTNAME_COLUMN_INDEX: + return String.class; + case RESULT_COLUMN_INDEX: + return String.class; + case HEURISTIC_COLUMN_INDEX: + return String.class; + default: + return Object.class; + } } @Override public Object getValueAt(int rowIndex, int columnIndex) { - return null; + TableData tableDataAtRowIndex = tableDataList.get(rowIndex); + switch (columnIndex) { + case TESTNAME_COLUMN_INDEX: + return tableDataAtRowIndex.getTestName(); + + case RESULT_COLUMN_INDEX: + return tableDataAtRowIndex.getTestResult(); + case HEURISTIC_COLUMN_INDEX: + return tableDataAtRowIndex.getTestHeuristic(); + default: + return ""; + } } } From 3e6f24adc042a0cf3f6291ffdf9a90a379a60d85 Mon Sep 17 00:00:00 2001 From: Vandlik Viktor Date: Fri, 18 Apr 2025 08:17:21 +0200 Subject: [PATCH 09/13] method call chains --- src/main/java/actions/PluginCallGraph.java | 4 +++- .../listener/CallChainTableMouseListener.java | 8 +++++--- .../ui/listener/MethodTableMouseListener.java | 19 +++++++++++++++++++ 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/main/java/actions/PluginCallGraph.java b/src/main/java/actions/PluginCallGraph.java index f02fd12..69d3332 100644 --- a/src/main/java/actions/PluginCallGraph.java +++ b/src/main/java/actions/PluginCallGraph.java @@ -95,7 +95,9 @@ public void actionPerformed(@NotNull AnActionEvent e) { "\nThe file is located at " + ProjectModule.getProjectPath() + File.separator + "static_call_graph.html", "Call Graph is ready", JOptionPane.PLAIN_MESSAGE); */ //new PopUpView("static_call_graph.html").show(); - new CallGraphView("callchains.html", e.getProject()).show(); + String path = "/html/"; + String filename = "callchains.html"; + new CallGraphView(path + filename, e.getProject()).show(); } else { Messages.showMessageDialog( e.getProject(), diff --git a/src/main/java/ui/listener/CallChainTableMouseListener.java b/src/main/java/ui/listener/CallChainTableMouseListener.java index d1d4d29..711f5be 100644 --- a/src/main/java/ui/listener/CallChainTableMouseListener.java +++ b/src/main/java/ui/listener/CallChainTableMouseListener.java @@ -28,15 +28,17 @@ public CallChainTableMouseListener(JTable resultTable, ViewTestData viewTestData @Override public void mouseClicked(MouseEvent e) { + String path = "/html/tests/"; if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) { int row = resultTable.rowAtPoint(e.getPoint()); int column = resultTable.columnAtPoint(e.getPoint()); if (row >= 0 && column >= 0) { Object value = resultTable.getValueAt(row, column); - String filename = value != null ? value + "_call_chain.html" : ""; - System.out.println(filename); - new CallGraphView(filename, ProjectModule.getProject()).show(); + String filename = value != null ? path + value + "_call_chain.html" : ""; + if (!filename.isEmpty()){ + new CallGraphView(filename, ProjectModule.getProject()).show(); + } } } } diff --git a/src/main/java/ui/listener/MethodTableMouseListener.java b/src/main/java/ui/listener/MethodTableMouseListener.java index d40a861..4eb5504 100644 --- a/src/main/java/ui/listener/MethodTableMouseListener.java +++ b/src/main/java/ui/listener/MethodTableMouseListener.java @@ -14,6 +14,7 @@ import models.bean.MethodTestData; import models.bean.TestData; import modules.ProjectModule; +import ui.CallGraphView; import ui.viewResultTableModels.MethodTableModel; import javax.swing.*; @@ -31,6 +32,8 @@ public MethodTableMouseListener(JTable resultTable, TestData testData) { @Override public void mouseClicked(MouseEvent e) { int selectedRow = resultTable.getSelectedRow(); + int row = resultTable.rowAtPoint(e.getPoint()); + int column = resultTable.columnAtPoint(e.getPoint()); if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) { String fileName = ((String) resultTable.getValueAt(resultTable.getSelectedRow(), MethodTableModel.FILE_NAME_COLUMN_INDEX)); @@ -63,6 +66,22 @@ public void mouseClicked(MouseEvent e) { MethodTableModel.FILE_NAME_COLUMN_INDEX).toString(), name, selected.getLine()); + + Object value = resultTable.getValueAt(row, column); + if (value != null) { + String methodValue = value.toString(); + + String fileNameOnly = resultTable.getValueAt(row, column - 1).toString(); + String fileBaseName = fileNameOnly.replace(".py", ""); + + String methodFormatted = methodValue.replace("\\", "_").replace("/", "_"); + String fullMethodName = fileBaseName + "." + methodFormatted; + + String filename = "/html/methods/" + fullMethodName + "_call_chain.html"; + System.out.println(filename); + + new CallGraphView(filename, ProjectModule.getProject()).show(); + } } } From c961988e7191de3b6eaed49f313df62aa04839ca Mon Sep 17 00:00:00 2001 From: Vandlik Viktor Date: Fri, 18 Apr 2025 11:40:53 +0200 Subject: [PATCH 10/13] test_call_graph_title --- src/main/java/ui/ViewTest.java | 6 +++--- src/main/java/ui/listener/MethodTableMouseListener.java | 1 - src/main/resources/titles.properties | 1 + 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/ui/ViewTest.java b/src/main/java/ui/ViewTest.java index 62f8005..c66909c 100644 --- a/src/main/java/ui/ViewTest.java +++ b/src/main/java/ui/ViewTest.java @@ -151,12 +151,12 @@ protected JComponent createCenterPanel() { this.testViewTable = new JBTable(testViewTableModel); testViewTable.addMouseListener(new CallChainTableMouseListener(testViewTable,viewTestData)); - //testViewTable.setSelectionMode(SINGLE_SELECTION); - //testViewTable.setAutoCreateRowSorter(true); + testViewTable.setSelectionMode(SINGLE_SELECTION); + testViewTable.setAutoCreateRowSorter(true); testViewTable.getColumnModel().getColumn(TestTableModel.TESTNAME_COLUMN_INDEX).setPreferredWidth(250); testViewTable.getColumnModel().getColumn(TestTableModel.RESULT_COLUMN_INDEX).setPreferredWidth(75); testViewTable.getColumnModel().getColumn(TestTableModel.HEURISTIC_COLUMN_INDEX).setPreferredWidth(75); - tabsPane.addTab(Resources.get("titles", "tree_pane"), createTableScrollPane(testViewTable)); + tabsPane.addTab(Resources.get("titles", "test_call_graph_title"), createTableScrollPane(testViewTable)); tabsPane.setPreferredSize(new Dimension(500, 500)); tabsPane.setLocation(600,300); pack(); diff --git a/src/main/java/ui/listener/MethodTableMouseListener.java b/src/main/java/ui/listener/MethodTableMouseListener.java index 4eb5504..9b88a56 100644 --- a/src/main/java/ui/listener/MethodTableMouseListener.java +++ b/src/main/java/ui/listener/MethodTableMouseListener.java @@ -78,7 +78,6 @@ public void mouseClicked(MouseEvent e) { String fullMethodName = fileBaseName + "." + methodFormatted; String filename = "/html/methods/" + fullMethodName + "_call_chain.html"; - System.out.println(filename); new CallGraphView(filename, ProjectModule.getProject()).show(); } diff --git a/src/main/resources/titles.properties b/src/main/resources/titles.properties index ffe2e66..cd06cf0 100644 --- a/src/main/resources/titles.properties +++ b/src/main/resources/titles.properties @@ -2,6 +2,7 @@ statement_options=Statement Options advanced_options=Settings call_graph_title=Call Graph View +test_call_graph_title=Test Call Graph View tree_pane=Hierarchical Tree class_pane=Class method_pane=Method From 95788240185573016d501ac28217e5f77c489517 Mon Sep 17 00:00:00 2001 From: Vandlik Viktor Date: Fri, 18 Apr 2025 12:30:31 +0200 Subject: [PATCH 11/13] right click added --- .../listener/CallChainTableMouseListener.java | 16 +++++++------ .../ui/listener/MethodTableMouseListener.java | 23 +++++++++++-------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/main/java/ui/listener/CallChainTableMouseListener.java b/src/main/java/ui/listener/CallChainTableMouseListener.java index 711f5be..3224db0 100644 --- a/src/main/java/ui/listener/CallChainTableMouseListener.java +++ b/src/main/java/ui/listener/CallChainTableMouseListener.java @@ -13,6 +13,7 @@ import modules.ProjectModule; import ui.CallGraphView; import ui.viewResultTableModels.ClassTableModel; +import ui.viewResultTableModels.MethodTableModel; import ui.viewResultTableModels.TestTableModel; import javax.swing.*; @@ -29,15 +30,16 @@ public CallChainTableMouseListener(JTable resultTable, ViewTestData viewTestData @Override public void mouseClicked(MouseEvent e) { String path = "/html/tests/"; - if (e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1) { + if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON3 || e.getClickCount() == 2 && e.getButton() == MouseEvent.BUTTON1 ) { int row = resultTable.rowAtPoint(e.getPoint()); int column = resultTable.columnAtPoint(e.getPoint()); - - if (row >= 0 && column >= 0) { - Object value = resultTable.getValueAt(row, column); - String filename = value != null ? path + value + "_call_chain.html" : ""; - if (!filename.isEmpty()){ - new CallGraphView(filename, ProjectModule.getProject()).show(); + if (column == TestTableModel.TESTNAME_COLUMN_INDEX){ + if (row >= 0) { + Object value = resultTable.getValueAt(row, column); + String filename = value != null ? path + value + "_call_chain.html" : ""; + if (!filename.isEmpty()){ + new CallGraphView(filename, ProjectModule.getProject()).show(); + } } } } diff --git a/src/main/java/ui/listener/MethodTableMouseListener.java b/src/main/java/ui/listener/MethodTableMouseListener.java index 9b88a56..06b31d5 100644 --- a/src/main/java/ui/listener/MethodTableMouseListener.java +++ b/src/main/java/ui/listener/MethodTableMouseListener.java @@ -66,20 +66,23 @@ public void mouseClicked(MouseEvent e) { MethodTableModel.FILE_NAME_COLUMN_INDEX).toString(), name, selected.getLine()); + } + if (e.getClickCount() == 1 && e.getButton() == MouseEvent.BUTTON3){ + if (column == MethodTableModel.NAME_COLUMN_INDEX){ + Object value = resultTable.getValueAt(row, column); + if (value != null) { + String methodValue = value.toString(); - Object value = resultTable.getValueAt(row, column); - if (value != null) { - String methodValue = value.toString(); - - String fileNameOnly = resultTable.getValueAt(row, column - 1).toString(); - String fileBaseName = fileNameOnly.replace(".py", ""); + String fileNameOnly = resultTable.getValueAt(row, 0).toString(); + String fileBaseName = fileNameOnly.replace(".py", ""); - String methodFormatted = methodValue.replace("\\", "_").replace("/", "_"); - String fullMethodName = fileBaseName + "." + methodFormatted; + String methodFormatted = methodValue.replace("\\", "_").replace("/", "_"); + String fullMethodName = fileBaseName + "." + methodFormatted; - String filename = "/html/methods/" + fullMethodName + "_call_chain.html"; + String filename = "/html/methods/" + fullMethodName + "_call_chain.html"; - new CallGraphView(filename, ProjectModule.getProject()).show(); + new CallGraphView(filename, ProjectModule.getProject()).show(); + } } } } From 7dc9286f833fa0f07877fb5c7a201758e6ee4c86 Mon Sep 17 00:00:00 2001 From: Vandlik Viktor Date: Fri, 18 Apr 2025 16:56:43 +0200 Subject: [PATCH 12/13] smt modified --- src/main/python/faultloc/Spectra.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/python/faultloc/Spectra.py b/src/main/python/faultloc/Spectra.py index d958d8d..09e8757 100644 --- a/src/main/python/faultloc/Spectra.py +++ b/src/main/python/faultloc/Spectra.py @@ -59,7 +59,7 @@ def heuristic_analyzer(self,test): if all([len(elem) == 1 for elem in chains]) and 0 < chain_lengths <= 1: return "put" - if all([len(elem) <= 2 for elem in chains]) and chain_lengths > 0: + if all([len(elem) <= 1 for elem in chains]) and chain_lengths > 0: return "smt" if chain_lengths == 1: From a611019eaa79292810affae532cec6e2ee15348c Mon Sep 17 00:00:00 2001 From: Vandlik Viktor Date: Wed, 7 May 2025 10:14:52 +0200 Subject: [PATCH 13/13] graph -> chain --- src/main/resources/titles.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/titles.properties b/src/main/resources/titles.properties index cd06cf0..870d3f4 100644 --- a/src/main/resources/titles.properties +++ b/src/main/resources/titles.properties @@ -1,8 +1,8 @@ #Titles of windows and tab panes in the ui statement_options=Statement Options advanced_options=Settings -call_graph_title=Call Graph View -test_call_graph_title=Test Call Graph View +call_graph_title=Call Chain View +test_call_graph_title=Test Call Chain View tree_pane=Hierarchical Tree class_pane=Class method_pane=Method