class DynamicCallGraphMatrix():
    def __init__(self, pathdir):
        self.conf = Configuration(pathdir)
        self.loader = FileLoader()
        self.total_pass_test_cases = 0
        self.total_fail_test_cases = 0
        self.total_runtime_of_pass_test_cases = 0
        self.total_runtime_of_fail_test_cases = 0
        self.test_suite_activity_matrix_density = 0
        self.test_suite_matrix_diversity = 0
        self.test_suite_matrix_uniqueness = 0
        self.test_suite_matrix_ddu = 0
        self.test_suite_matrix_sparsity = 0
        self.test_suite_matrix_density = 0

        self.dynamic_call_graph_metrics_list = []
        self.dynamic_call_graph_metrics_math_data = []
        self.dynamic_call_graph_metrics_list_chart = []
        self.dynamic_call_graph_metrics_list_lang = []
        self.dynamic_call_graph_metrics_list_math = []
        self.dynamic_call_graph_metrics_list_time = []
        self.dynamic_call_graph_metrics_list_closure = []
        self.dynamic_call_graph_metrics_list_mockito = []

    def get_ranking_by_spectra(self, projectName, bug_version, spectraLineNum):
        if spectraLineNum == None:
            return
        #print('spectraLineNum>' + str(spectraLineNum))
        rankPath = os.path.join(
            self.conf.ROOT_PATH, 'suspiciousness_ranking/' + projectName +
            '_' + str(bug_version) + '.csv')
        with open(rankPath, 'r') as csvfile:
            readCSV = csv.reader(csvfile, delimiter=',')
            for lineno, row in enumerate(readCSV):
                if lineno == spectraLineNum:
                    #print(row)
                    return row[2]

    def get_featurenode_linenum_from_spectra(self, projectName, bug_version,
                                             faultMethodFeatureName):
        #print('project>' + projectName + ' id> ' + str(bug_version) + ' methodName> ' + faultMethodFeatureName)
        filepath = os.path.join(
            self.conf.ROOT_PATH,
            projectName + '/' + str(bug_version) + '/spectra')
        with open(filepath, 'r') as spectra:
            for num, line in enumerate(spectra, 1):
                if faultMethodFeatureName in line.strip():
                    return num

    def process_math_dynamic_metrics_from_call_graph(self):
        for subdir, dirs, files in sorted(
                os.walk(self.conf.MATH_CALL_GRPAH_PATH)):
            for file in sorted(files):
                filepath = os.path.join(subdir, file)
                print(filepath)
                buggy_version = re.findall('\d+', filepath)
                fname = file.replace(".dot", "")
                faultNodes = fname.strip()
                #print(faultNodes)
                #print('buggy_version> '+ str(buggy_version[0]) + ' dot file name: ' + fname)

                # load matrix file
                matrix_filepath = os.path.join(
                    self.conf.ROOT_PATH, self.conf.MATH_ID + '/' +
                    str(buggy_version[0]) + '/matrix')
                mat = self.loader.load_coverage_file(matrix_filepath)
                mat_arr = np.asarray(mat)
                #print(mat_arr.shape)
                pass_fail_col_arr = mat_arr[:, mat_arr.shape[1] - 1]
                test_case_result_col_arr = np.asarray(pass_fail_col_arr)
                unique_value, unique_counts = np.unique(
                    test_case_result_col_arr, return_counts=True)
                #print(unique_value)
                #print(unique_counts)

                total_test_case_coverage_by_dynamic_call_graph = 0
                # total test cases that cover/execute for this dynamic call graph
                getSpectraLineNum = self.get_featurenode_linenum_from_spectra(
                    self.conf.MATH_ID, buggy_version[0], faultNodes)
                #print(str(getSpectraLineNum))
                if getSpectraLineNum != None:
                    fault_node_feature_col_arr = mat_arr[:,
                                                         getSpectraLineNum - 1]
                    for t in range(0, len(fault_node_feature_col_arr)):
                        if fault_node_feature_col_arr[t] == 1:
                            total_test_case_coverage_by_dynamic_call_graph += 1

                cnt = 0
                diffu_feature_modified_list = []
                diffu_feature_added_list = []
                #faultNodeInDegList = []
                #if getSpectraLineNum != None:
                faultNodeInDegList = []
                faultNodeOutDegList = []
                faultClass_CBO = 0
                faultClass_RFC_List = []
                faultClass_RFC = 0

                # dot file edge calculation begin>
                node_split = faultNodes.split('#', 1)
                faultNodeClassName = node_split[0]
                file = open(filepath, 'r')  #READING DOT FILE
                with open(filepath, 'r') as file:
                    text = file.readlines()
                    for row in text:
                        #print(row)
                        line_split = row.split('->', 1)
                        #print(len(line_split))
                        if len(line_split) > 1:
                            sourceNode = line_split[0].strip().replace('"', '')
                            #sourceNode
                            #print(sourceNode)
                            dNode = line_split[1].strip().replace('"', '')
                            destNode = dNode.replace(";", "")
                            #print(destNode)
                            if sourceNode.strip() == faultNodes:
                                #print(sourceNode)
                                faultNodeOutDegList.append(destNode)
                            if destNode.strip() == faultNodes:
                                #print(destNode)
                                faultNodeInDegList.append(sourceNode)
                            # calculate CBO
                            if faultNodeClassName in sourceNode or faultNodeClassName in destNode:
                                faultClass_CBO += 1
                                #print(e.to_string())
                                if faultNodeClassName in sourceNode and faultNodeClassName in destNode:
                                    faultClass_CBO -= 1
                            #calculate RFC
                            if faultNodeClassName in sourceNode:
                                if sourceNode not in faultClass_RFC_List:
                                    faultClass_RFC_List.append(sourceNode)
                            if faultNodeClassName in destNode:
                                if destNode not in faultClass_RFC_List:
                                    faultClass_RFC_List.append(destNode)

                #ource(text)
                #graph = pydotplus.Graph(filepath)
                #print(graph.to_string())
                #edgeList = graph.get_edges()
                #print(edgeList)
                #nodeList = graph.get_nodes()
                #print(nodeList)

                outDegCount = len(faultNodeOutDegList)
                inDegCount = len(faultNodeInDegList)
                faultClass_RFC = len(faultClass_RFC_List) + outDegCount
                no_of_test_cases_covers_fault_node = 0
                no_of_test_cases_passes_for_fault_node = 0
                no_of_test_cases_fails_for_fault_node = 0
                print('OutDeg> ' + str(outDegCount) + ' InDeg> ' +
                      str(inDegCount) + ' CBO> ' + str(faultClass_CBO) +
                      ' RFC> ' + str(faultClass_RFC))
                if outDegCount != 0 and inDegCount != 0:
                    #print('OutDeg> ' + str(outDegCount) + ' InDeg> ' + str(inDegCount) + ' CBO> ' + str(faultClass_CBO)  + ' RFC> ' + str(faultClass_RFC))
                    # code for matrix file
                    getSpectraLineNum = self.get_featurenode_linenum_from_spectra(
                        self.conf.MATH_ID, buggy_version[0], faultNodes)
                    rank = self.get_ranking_by_spectra(self.conf.MATH_ID,
                                                       buggy_version[0],
                                                       getSpectraLineNum)
                    #print(str(getSpectraLineNum))
                    if getSpectraLineNum != None:
                        fault_node_feature_col_arr = mat_arr[:,
                                                             getSpectraLineNum -
                                                             1]
                        # fault node test coverage pass/fail info calculation
                        for t in range(0, len(fault_node_feature_col_arr)):
                            if fault_node_feature_col_arr[t] == 1:
                                no_of_test_cases_covers_fault_node += 1
                                if pass_fail_col_arr[t] == 1:
                                    no_of_test_cases_passes_for_fault_node += 1
                                else:
                                    no_of_test_cases_fails_for_fault_node += 1
                        #print('Total test cases for fn>', no_of_test_cases_covers_fault_node)
                        #print('pass for fn>', no_of_test_cases_passes_for_fault_node)
                        #print('fail for fn>', no_of_test_cases_fails_for_fault_node)
                    output_row = [
                        self.conf.MATH_ID,
                        # + '_' + str(buggy_version),
                        int(buggy_version[0]),
                        faultNodes,
                        rank,
                        inDegCount,
                        outDegCount,
                        inDegCount + outDegCount,
                        faultClass_CBO,
                        faultClass_RFC,
                        no_of_test_cases_covers_fault_node,
                        no_of_test_cases_passes_for_fault_node,
                        no_of_test_cases_fails_for_fault_node,
                        total_test_case_coverage_by_dynamic_call_graph,
                        "/".join(faultNodeInDegList),
                        "/".join(faultNodeOutDegList)
                    ]
                    diffu_feature_modified_list.append(output_row)
                else:
                    #print('OutDeg> ' + str(outDegCount) + ' InDeg> ' + str(inDegCount) + ' CBO> ' + str(faultClass_CBO) + ' RFC> ' + str(faultClass_RFC))
                    impl_action = 'Unknown'
                    output_row = [
                        self.conf.MATH_ID,
                        int(buggy_version[0]), impl_action, 9999, 0, 0, 0, 0,
                        0, 0, 0, 0, 0, '', ''
                    ]
                    diffu_feature_added_list.append(output_row)

                if len(diffu_feature_modified_list) > 0:
                    self.dynamic_call_graph_metrics_list_math.append(
                        diffu_feature_modified_list[0])
                else:
                    self.dynamic_call_graph_metrics_list_math.append(
                        diffu_feature_added_list[0])

        print(
            '============== Printing ' + self.conf.MATH_ID +
            ' Projects Dynamic Call Graph Metrics Features =================')
        output_sorted_list = sorted(self.dynamic_call_graph_metrics_list_math,
                                    key=itemgetter(1))
        self.dynamic_call_graph_metrics_math_data.extend(output_sorted_list)
        #print(output_sorted_list)
        print('============== Finished Printing ' + self.conf.MATH_ID +
              ' Projects Dynamic Call Graph Metrics Version ================')

    def print_math_dynamic_call_graph_metrics(self):
        result_arr = np.array(self.dynamic_call_graph_metrics_math_data)
        #print(result_arr.shape)
        with open(self.conf.ROOT_PATH + 'dynamic_call_graph_math_data.csv',
                  'w') as csvfile:
            # PassedTestRuntime, FailedTestRuntime,
            columnTitleRow = 'ProjectID, '\
                             'BugId, '\
                             'FaultNodeName, '\
                             'Rank, '\
                             'FaultNode_InDegree, '\
                             'FaultNode_OutDegree, '\
                             'FaultNodeDegreeCentrality, '\
                             'CBO, '\
                             'RFC, '\
                             'NoOfTestCasesExecuteFaultMethod, '\
                             'NoOfTestCasesPassesCoversFaultNode, '\
                             'NoOfTestCasesFailsCoversFaultNode, '\
                             'NoOfTestCasesExecutesDynamicCallGraph, '\
                             'InDegreeMethodCallsList, '\
                             'OutDegreeMethodCallsList\n'

            csvfile.write(columnTitleRow)
            for i in range(0, result_arr.shape[0]):
                row = (str(result_arr[i][0]) + ', ' + str(result_arr[i][1]) +
                       ', ' + str(result_arr[i][2]) + ', ' +
                       str(result_arr[i][3]) + ', ' + str(result_arr[i][4]) +
                       ', ' + str(result_arr[i][5]) + ', ' +
                       str(result_arr[i][6]) + ', ' + str(result_arr[i][7]) +
                       ', ' + str(result_arr[i][8]) + ', ' +
                       str(result_arr[i][9]) + ', ' + str(result_arr[i][10]) +
                       ', ' + str(result_arr[i][11]) + ', ' +
                       str(result_arr[i][12]) + ', ' + str(result_arr[i][13]) +
                       ', ' + str(result_arr[i][14]) + '\n')
                csvfile.write(row)
            print('Math Dynamic Call Graph Metrics file is saved.')

    def process_dynamic_metrics_from_call_graph(self):
        for i in range(0, len(self.conf.CALL_GRAPH_PROJECTS_ID)):
            for subdir, dirs, files in sorted(
                    os.walk(self.conf.DYNAMIC_CALL_GRAPH_PROJECTS_PATH[i])):
                for file in sorted(files):
                    filepath = os.path.join(subdir, file)
                    print(filepath)
                    fn = file.replace(".dot", "")
                    buggy_version = int(fn)  #re.findall('\d+', filepath)
                    graph = pydotplus.graphviz.graph_from_dot_file(filepath)
                    edgeList = graph.get_edge_list()
                    nodeList = graph.get_node_list()
                    faultNodes = []

                    # load matrix file
                    matrix_filepath = os.path.join(
                        self.conf.ROOT_PATH,
                        self.conf.CALL_GRAPH_PROJECTS_ID[i] + '/' +
                        str(buggy_version) + '/matrix')
                    mat = self.loader.load_coverage_file(matrix_filepath)
                    mat_arr = np.asarray(mat)
                    #print(mat_arr.shape)
                    pass_fail_col_arr = mat_arr[:, mat_arr.shape[1] - 1]
                    test_case_result_col_arr = np.asarray(pass_fail_col_arr)
                    unique_value, unique_counts = np.unique(
                        test_case_result_col_arr, return_counts=True)
                    #print(unique_value)
                    #print(unique_counts)

                    total_test_case_coverage_by_dynamic_call_graph = 0
                    for n in nodeList:
                        #nodeName = n.get_name()
                        colorName = json.loads(
                            n.obj_dict['attributes']['fillcolor'])
                        nodeName = json.loads(n.get_name())
                        if colorName.strip() == "red":
                            faultNodes.append(json.loads(n.get_name()))

                        # total test cases that cover/execute for this dynamic call graph
                        getSpectraLineNum = self.get_featurenode_linenum_from_spectra(
                            self.conf.CALL_GRAPH_PROJECTS_ID[i], buggy_version,
                            nodeName)
                        #print(str(getSpectraLineNum))
                        if getSpectraLineNum != None:
                            fault_node_feature_col_arr = mat_arr[:,
                                                                 getSpectraLineNum
                                                                 - 1]
                            for t in range(0, len(fault_node_feature_col_arr)):
                                if fault_node_feature_col_arr[t] == 1:
                                    total_test_case_coverage_by_dynamic_call_graph += 1
                    #print(nodeList)
                    #print(faultNodes)
                    cnt = 0
                    diffu_feature_modified_list = []
                    diffu_feature_added_list = []
                    for node in range(0, len(faultNodes)):
                        faultNodeInDegList = []
                        faultNodeOutDegList = []
                        faultClass_CBO = 0
                        faultClass_RFC_List = []
                        faultClass_RFC = 0
                        for e in edgeList:
                            cnt += 1
                            dottedEdge = False
                            att = e.obj_dict['attributes']
                            node_split = faultNodes[node].split('#', 1)
                            faultNodeClassName = node_split[0]
                            sourceNode = json.loads(e.get_source())
                            destNode = json.loads(e.get_destination())
                            if len(att) > 0:
                                if att['style'] == 'dotted':
                                    dottedEdge = True
                                    # for RFC calculation
                                    if faultNodeClassName in sourceNode:
                                        if sourceNode not in faultClass_RFC_List:
                                            faultClass_RFC_List.append(
                                                sourceNode)
                                    if faultNodeClassName in destNode:
                                        if destNode not in faultClass_RFC_List:
                                            faultClass_RFC_List.append(
                                                destNode)
                            if dottedEdge != True:
                                # calculate in/out degree
                                if sourceNode.strip() == faultNodes[node]:
                                    faultNodeOutDegList.append(destNode)
                                if destNode.strip() == faultNodes[node]:
                                    faultNodeInDegList.append(sourceNode)
                                # calculate CBO
                                if faultNodeClassName in sourceNode or faultNodeClassName in destNode:
                                    faultClass_CBO += 1
                                    #print(e.to_string())
                                    if faultNodeClassName in sourceNode and faultNodeClassName in destNode:
                                        faultClass_CBO -= 1
                                #calculate RFC
                                if faultNodeClassName in sourceNode:
                                    if sourceNode not in faultClass_RFC_List:
                                        faultClass_RFC_List.append(sourceNode)
                                if faultNodeClassName in destNode:
                                    if destNode not in faultClass_RFC_List:
                                        faultClass_RFC_List.append(destNode)
                        outDegCount = len(faultNodeOutDegList)
                        inDegCount = len(faultNodeInDegList)
                        faultClass_RFC = len(faultClass_RFC_List) + outDegCount
                        #print(faultClass_CBO)

                        if outDegCount != 0 and inDegCount != 0:
                            print('OutDeg> ' + str(outDegCount) + ' InDeg> ' +
                                  str(inDegCount) + ' CBO> ' +
                                  str(faultClass_CBO) + ' RFC> ' +
                                  str(faultClass_RFC))
                            # code for matrix file
                            getSpectraLineNum = self.get_featurenode_linenum_from_spectra(
                                self.conf.CALL_GRAPH_PROJECTS_ID[i],
                                buggy_version, faultNodes[node])
                            #print(str(getSpectraLineNum))
                            if getSpectraLineNum != None:
                                fault_node_feature_col_arr = mat_arr[:,
                                                                     getSpectraLineNum
                                                                     - 1]
                                # fault node test coverage pass/fail info calculation
                                no_of_test_cases_covers_fault_node = 0
                                no_of_test_cases_passes_for_fault_node = 0
                                no_of_test_cases_fails_for_fault_node = 0
                                for t in range(
                                        0, len(fault_node_feature_col_arr)):
                                    if fault_node_feature_col_arr[t] == 1:
                                        no_of_test_cases_covers_fault_node += 1
                                        if pass_fail_col_arr[t] == 1:
                                            no_of_test_cases_passes_for_fault_node += 1
                                        else:
                                            no_of_test_cases_fails_for_fault_node += 1
                                #print('Total test cases for fn>', no_of_test_cases_covers_fault_node)
                                #print('pass for fn>', no_of_test_cases_passes_for_fault_node)
                                #print('fail for fn>', no_of_test_cases_fails_for_fault_node)

                            output_row = [
                                self.conf.CALL_GRAPH_PROJECTS_ID[i],
                                # + '_' + str(buggy_version),
                                buggy_version,
                                faultNodes[node],
                                inDegCount,
                                outDegCount,
                                inDegCount + outDegCount,
                                faultClass_CBO,
                                faultClass_RFC,
                                no_of_test_cases_covers_fault_node,
                                no_of_test_cases_passes_for_fault_node,
                                no_of_test_cases_fails_for_fault_node,
                                total_test_case_coverage_by_dynamic_call_graph,
                                "/".join(faultNodeInDegList),
                                "/".join(faultNodeOutDegList)
                            ]
                            diffu_feature_modified_list.append(output_row)
                        else:
                            #print('OutDeg> ' + str(outDegCount) + ' InDeg> ' + str(inDegCount) + ' CBO> ' + str(faultClass_CBO) + ' RFC> ' + str(faultClass_RFC))
                            impl_action = 'Unknown'
                            output_row = [
                                self.conf.CALL_GRAPH_PROJECTS_ID[i],
                                buggy_version, impl_action, 0, 0, 0, 0, 0, 0,
                                0, 0, 0, '', ''
                            ]
                            diffu_feature_added_list.append(output_row)

                    if len(diffu_feature_modified_list) > 0:
                        #lowRank = self.get_ranking(diffu_feature_modified_list[0][0], diffu_feature_modified_list[0][1], diffu_feature_modified_list[0][2])
                        spectraLineNum = self.get_featurenode_linenum_from_spectra(
                            self.conf.CALL_GRAPH_PROJECTS_ID[i],
                            diffu_feature_modified_list[0][1],
                            diffu_feature_modified_list[0][2])
                        lowRank = self.get_ranking_by_spectra(
                            self.conf.CALL_GRAPH_PROJECTS_ID[i],
                            diffu_feature_modified_list[0][1], spectraLineNum)
                        #print('lowRank> ', lowRank)
                        #low rank == highest suspicious value.
                        index = 0
                        #print('length> ' + str(len(diffu_feature_modified_list)))
                        if len(diffu_feature_modified_list) > 1:
                            for x in range(1,
                                           len(diffu_feature_modified_list)):
                                spectraLineNum = self.get_featurenode_linenum_from_spectra(
                                    self.conf.CALL_GRAPH_PROJECTS_ID[i],
                                    diffu_feature_modified_list[x][1],
                                    diffu_feature_modified_list[x][2])
                                curRank = self.get_ranking_by_spectra(
                                    self.conf.CALL_GRAPH_PROJECTS_ID[i],
                                    diffu_feature_modified_list[x][1],
                                    spectraLineNum)
                                #print('curRank> ', curRank)
                                if curRank < lowRank:
                                    lowRank = curRank
                                    index = x
                                    #print('survivedindex>', diffu_feature_modified_list[index][2])
                            #print(index)
                            #print('length> ' + str(len(diffu_feature_modified_list)))
                            resultarr = diffu_feature_modified_list[index]
                            diffu_feature_modified_list = []
                            diffu_feature_modified_list.append(resultarr)
                            #print('modified length>' + str(len(diffu_feature_modified_list)))
                            #print('modified arr>', diffu_feature_modified_list)

                        if self.conf.CALL_GRAPH_PROJECTS_ID[i] == 'Chart':
                            self.dynamic_call_graph_metrics_list_chart.append(
                                diffu_feature_modified_list[0])
                        elif self.conf.CALL_GRAPH_PROJECTS_ID[i] == 'Lang':
                            self.dynamic_call_graph_metrics_list_lang.append(
                                diffu_feature_modified_list[0])
                        elif self.conf.CALL_GRAPH_PROJECTS_ID[i] == 'Time':
                            self.dynamic_call_graph_metrics_list_time.append(
                                diffu_feature_modified_list[0])
                        else:
                            self.dynamic_call_graph_metrics_list_closure.append(
                                diffu_feature_modified_list[0])
                    else:
                        if self.conf.CALL_GRAPH_PROJECTS_ID[i] == 'Chart':
                            self.dynamic_call_graph_metrics_list_chart.append(
                                diffu_feature_added_list[0])
                        elif self.conf.CALL_GRAPH_PROJECTS_ID[i] == 'Lang':
                            self.dynamic_call_graph_metrics_list_lang.append(
                                diffu_feature_added_list[0])
                        elif self.conf.CALL_GRAPH_PROJECTS_ID[i] == 'Time':
                            self.dynamic_call_graph_metrics_list_time.append(
                                diffu_feature_added_list[0])
                        else:
                            self.dynamic_call_graph_metrics_list_closure.append(
                                diffu_feature_added_list[0])

            print(
                '============== Printing ' +
                self.conf.CALL_GRAPH_PROJECTS_ID[i] +
                ' Projects Dynamic Call Graph Metrics Features ================='
            )
            if self.conf.CALL_GRAPH_PROJECTS_ID[i] == 'Chart':
                output_sorted_list = sorted(
                    self.dynamic_call_graph_metrics_list_chart,
                    key=itemgetter(1))
                self.dynamic_call_graph_metrics_list.extend(output_sorted_list)
                #print(output_sorted_list)
            if self.conf.CALL_GRAPH_PROJECTS_ID[i] == 'Lang':
                output_sorted_list = sorted(
                    self.dynamic_call_graph_metrics_list_lang,
                    key=itemgetter(1))
                #print(output_sorted_list)
                self.dynamic_call_graph_metrics_list.extend(output_sorted_list)
            if self.conf.CALL_GRAPH_PROJECTS_ID[i] == 'Time':
                output_sorted_list = sorted(
                    self.dynamic_call_graph_metrics_list_time,
                    key=itemgetter(1))
                #print(output_sorted_list)
                self.dynamic_call_graph_metrics_list.extend(output_sorted_list)
            if self.conf.CALL_GRAPH_PROJECTS_ID[i] == 'Closure':
                output_sorted_list = sorted(
                    self.dynamic_call_graph_metrics_list_closure,
                    key=itemgetter(1))
                #print(output_sorted_list)
                self.dynamic_call_graph_metrics_list.extend(output_sorted_list)
            print(
                '============== Finished Printing ' +
                self.conf.CALL_GRAPH_PROJECTS_ID[i] +
                ' Projects Dynamic Call Graph Metrics Version ================'
            )

    def print_dynamic_call_graph_metrics(self):
        #print(len(self.dynamic_call_graph_metrics_list))
        #print(self.dynamic_call_graph_metrics_list)
        result_arr = np.array(self.dynamic_call_graph_metrics_list)
        #print(result_arr.shape)
        with open(self.conf.ROOT_PATH + 'dynamic_call_graph_metrics.csv',
                  'w') as csvfile:
            # PassedTestRuntime, FailedTestRuntime,
            columnTitleRow = 'ProjectID, '\
                             'BugId, '\
                             'FaultNodeName, '\
                             'FaultNode_InDegree, '\
                             'FaultNode_OutDegree, '\
                             'FaultNodeDegreeCentrality, '\
                             'CBO, '\
                             'RFC, '\
                             'NoOfTestCasesExecuteFaultMethod, '\
                             'NoOfTestCasesPassesCoversFaultNode, '\
                             'NoOfTestCasesFailsCoversFaultNode, '\
                             'NoOfTestCasesExecutesDynamicCallGraph, '\
                             'InDegreeMethodCallsList, '\
                             'OutDegreeMethodCallsList\n'

            csvfile.write(columnTitleRow)
            for i in range(0, result_arr.shape[0]):
                row = (str(result_arr[i][0]) + ', ' + str(result_arr[i][1]) +
                       ', ' + str(result_arr[i][2]) + ', ' +
                       str(result_arr[i][3]) + ', ' + str(result_arr[i][4]) +
                       ', ' + str(result_arr[i][5]) + ', ' +
                       str(result_arr[i][6]) + ', ' + str(result_arr[i][7]) +
                       ', ' + str(result_arr[i][8]) + ', ' +
                       str(result_arr[i][9]) + ', ' + str(result_arr[i][10]) +
                       ', ' + str(result_arr[i][11]) + ', ' +
                       str(result_arr[i][12]) + ', ' + str(result_arr[i][13]) +
                       '\n')
                csvfile.write(row)
            print('Dynamic Call Graph Metrics file is saved.')

    def process_dynamic_call_graph(self):
        #self.calculate_oo_metrics()
        self.process_dynamic_metrics_from_call_graph()
        self.print_dynamic_call_graph_metrics()
        self.process_math_dynamic_metrics_from_call_graph()
        self.print_math_dynamic_call_graph_metrics()
Exemple #2
0
class TestSuiteMatrix():
    def __init__(self, pathdir):
        self.conf = Configuration(pathdir)
        self.loader = FileLoader()
        self.total_pass_test_cases = 0
        self.total_fail_test_cases = 0
        self.total_runtime_of_pass_test_cases = 0
        self.total_runtime_of_fail_test_cases = 0
        self.test_suite_activity_matrix_density = 0
        self.test_suite_matrix_diversity = 0
        self.test_suite_matrix_uniqueness = 0
        self.test_suite_matrix_ddu = 0
        self.test_suite_matrix_sparsity = 0
        self.test_suite_matrix_density = 0

        self.test_suite_list = []
        self.test_suite_list_chart = []
        self.test_suite_list_lang = []
        self.test_suite_list_math = []
        self.test_suite_list_time = []
        self.test_suite_list_closure = []
        self.test_suite_list_mockito = []

    # calculate below metrics according to test suite paper.
    # Paper Title: "A Test-suite Diagnosability Metric for Spectrum-based Fault Localization Approaches"
    # self.test_suite_matrix_density,
    # self.test_suite_matrix_sparsity,
    # self.test_suite_activity_matrix_density,
    # self.test_suite_matrix_diversity,
    # self.test_suite_matrix_uniqueness,
    # self.test_suite_matrix_ddu
    def calculate_test_suite_matrix_ddu(self, matrix):
        mat_arr = np.asarray(matrix)
        row = mat_arr.shape[0]
        col = mat_arr.shape[1] - 1  # excluding pass/fail column
        sum = 0
        sparsity_sum = 0
        for i in range(0, row):
            for j in range(0, col):
                if mat_arr[i][j] == 1:
                    sum += mat_arr[i][j]
                if mat_arr[i][j] == 0:
                    sparsity_sum += 1

        self.test_suite_matrix_density = sum / (row * col)
        #The number of zero-valued elements divided by the total number of elements is called the sparsity of the matrix
        #Conceptually, sparsity corresponds to systems that are loosely coupled.
        self.test_suite_matrix_sparsity = sparsity_sum / (row * col)
        # DDU metrics calculation
        # activity matrix density calculation
        self.test_suite_activity_matrix_density = 1 - abs(
            1 - 2 * self.test_suite_matrix_density)
        modified_matrix = np.delete(mat_arr, mat_arr.shape[1] - 1, 1)
        dt = np.dtype(
            (np.void,
             modified_matrix.dtype.itemsize * modified_matrix.shape[1]))
        contg_arr = np.ascontiguousarray(modified_matrix).view(dt)
        unq, cnt = np.unique(contg_arr, return_counts=True)

        # calculate matrix diversity and matrix uniqueness.
        no_of_test_share_similar_activity = 0
        for i in range(0, len(cnt)):
            no_of_test_share_similar_activity += cnt[i] * (cnt[i] - 1)

        if no_of_test_share_similar_activity == 0:
            self.test_suite_matrix_diversity = 1
        else:
            self.test_suite_matrix_diversity = 1 - no_of_test_share_similar_activity / (
                row * (row - 1))
        dt = np.dtype(
            (np.void,
             modified_matrix.dtype.itemsize * modified_matrix.shape[0]))
        data_f = np.asfortranarray(modified_matrix).view(dt)
        u, c = np.unique(data_f, return_counts=True)
        self.test_suite_matrix_uniqueness = len(c) / col

        # calculate matrix DDU
        self.test_suite_matrix_ddu = self.test_suite_activity_matrix_density * self.test_suite_matrix_diversity * self.test_suite_matrix_uniqueness

    def load_tests_matrix_file(self):
        print('---loading tests matrix file ---')
        for i in range(0, len(self.conf.PROJECTS_ID)):
            for subdir, dirs, files in sorted(
                    os.walk(self.conf.PROJECTS_DATA_PATH[i])):
                for file in sorted(files):
                    filepath = os.path.join(subdir, file)
                    #print(filepath)
                    '''
                    if file == 'tests':
                        tests_list = self.loader.load_tests_file(filepath)
                        tests_arr = np.asarray(tests_list)
                        #print(tests_arr[1][1])
                        pass_fail_col_arr = tests_arr[:, tests_arr.shape[1] - 2]
                        #print(pass_fail_col_arr)
                        pass_fail_time_ns_col_arr = tests_arr[:, tests_arr.shape[1] - 1]
                        #print(pass_fail_time_ns_col_arr)
                        pass_test_case_sec = 0.0
                        fail_test_case_sec = 0.0
                        for x in range(1, len(pass_fail_col_arr)):
                            get_ns = int(pass_fail_time_ns_col_arr[x])
                            if pass_fail_col_arr[x] == 'PASS':
                                pass_test_case_sec = pass_test_case_sec + float(get_ns/1000000000)
                            else:
                                fail_test_case_sec = fail_test_case_sec + float(get_ns/1000000000)
                        #print(pass_test_case_sec)
                        #print(fail_test_case_sec)
                        self.total_runtime_of_pass_test_cases = pass_test_case_sec
                        self.total_runtime_of_fail_test_cases = fail_test_case_sec'''

                    if file == 'matrix':
                        buggy_version = re.findall('\d+', filepath)
                        print('Processing: ' + filepath)
                        mat = self.loader.load_coverage_file(filepath)
                        mat_arr = np.asarray(mat)
                        #print(mat_arr.shape)
                        #print(mat_arr.shape[1])
                        pass_fail_col_arr = mat_arr[:, mat_arr.shape[1] - 1]
                        #print(pass_fail_col_arr)
                        test_case_arr = np.asarray(pass_fail_col_arr)
                        unique_value, unique_counts = np.unique(
                            test_case_arr, return_counts=True)
                        if len(unique_value) == 2:
                            self.total_pass_test_cases = unique_counts[1]
                            self.total_fail_test_cases = unique_counts[0]
                        else:
                            if unique_value[0] == 1:
                                self.total_pass_test_cases = unique_counts[0]
                            else:
                                self.total_fail_test_cases = unique_counts[0]

                        self.calculate_test_suite_matrix_ddu(mat_arr)
                        output_row = [
                            self.conf.PROJECTS_ID[i] + '_' + buggy_version[0],
                            int(buggy_version[0]), self.total_pass_test_cases,
                            self.total_fail_test_cases,
                            self.test_suite_matrix_density,
                            self.test_suite_matrix_sparsity,
                            self.test_suite_activity_matrix_density,
                            self.test_suite_matrix_diversity,
                            self.test_suite_matrix_uniqueness,
                            self.test_suite_matrix_ddu
                        ]

                        if self.conf.PROJECTS_ID[i] == 'Chart':
                            self.test_suite_list_chart.append(output_row)
                        elif self.conf.PROJECTS_ID[i] == 'Lang':
                            self.test_suite_list_lang.append(output_row)
                        elif self.conf.PROJECTS_ID[i] == 'Math':
                            self.test_suite_list_math.append(output_row)
                        elif self.conf.PROJECTS_ID[i] == 'Time':
                            self.test_suite_list_time.append(output_row)
                        elif self.conf.PROJECTS_ID[i] == 'Closure':
                            self.test_suite_list_closure.append(output_row)
                        else:
                            self.test_suite_list_mockito.append(output_row)

            print(
                '============== Printing ' + self.conf.PROJECTS_ID[i] +
                ' Projects Buggy Versions Test Suite Features ================='
            )
            if self.conf.PROJECTS_ID[i] == 'Chart':
                output_sorted_list = sorted(self.test_suite_list_chart,
                                            key=itemgetter(1))
                #print(output_sorted_list)
                self.test_suite_list.extend(output_sorted_list)
            if self.conf.PROJECTS_ID[i] == 'Lang':
                output_sorted_list = sorted(self.test_suite_list_lang,
                                            key=itemgetter(1))
                #print(output_sorted_list)
                self.test_suite_list.extend(output_sorted_list)
            if self.conf.PROJECTS_ID[i] == 'Math':
                output_sorted_list = sorted(self.test_suite_list_math,
                                            key=itemgetter(1))
                #print(output_sorted_list)
                self.test_suite_list.extend(output_sorted_list)
            if self.conf.PROJECTS_ID[i] == 'Time':
                output_sorted_list = sorted(self.test_suite_list_time,
                                            key=itemgetter(1))
                #print(output_sorted_list)
                self.test_suite_list.extend(output_sorted_list)
            if self.conf.PROJECTS_ID[i] == 'Closure':
                output_sorted_list = sorted(self.test_suite_list_closure,
                                            key=itemgetter(1))
                #print(output_sorted_list)
                self.test_suite_list.extend(output_sorted_list)
            if self.conf.PROJECTS_ID[i] == 'Mockito':
                output_sorted_list = sorted(self.test_suite_list_mockito,
                                            key=itemgetter(1))
                #print(output_sorted_list)
                self.test_suite_list.extend(output_sorted_list)
            print('============== Finished Printing ' +
                  self.conf.PROJECTS_ID[i] +
                  ' Projects Buggy Version ================')

    def print_test_suite_matrix_properties(self):
        result_arr = np.array(self.test_suite_list)
        with open(
                self.conf.ROOT_PATH + 'test_suite_matrix_characteristics.csv',
                'w') as csvfile:
            # PassedTestRuntime, FailedTestRuntime,
            columnTitleRow = "ProjectID_BugId, BugId, TotalPassTest, TotalFailTest, MatrixDensity, MatrixSparsity, ActiveMatrixDensity, MatrixDiversity, MatrixUniqueness, MatrixDDU\n"
            csvfile.write(columnTitleRow)
            for i in range(0, result_arr.shape[0]):
                row = str(result_arr[i][0]) + ", " + str(
                    result_arr[i][1]) + ", " + str(
                        result_arr[i][2]) + ", " + str(
                            result_arr[i][3]) + ", " + str(
                                result_arr[i][4]) + ", " + str(
                                    result_arr[i][5]) + ", " + str(
                                        result_arr[i][6]) + ", " + str(
                                            result_arr[i][7]) + ", " + str(
                                                result_arr[i][8]) + ", " + str(
                                                    result_arr[i][9]) + "\n"
                csvfile.write(row)
            print('Test Suite characteristics file is saved.')

    def process_test_suite_properties(self):
        print('---preparing test suite characteristics---')
        #self.test_method()
        self.load_tests_matrix_file()
        self.print_test_suite_matrix_properties()
Exemple #3
0
class FaultLocalization():
    def __init__(self, pathdir):
        self.conf = Configuration(pathdir)
        self.loader = FileLoader()
        self.num_of_failed_test_cases_cover_statement_Ncf = 0
        self.num_of_failed_test_cases_not_cover_statement_Nuf = 0
        self.num_of_successful_test_cases_cover_statement_Ncs = 0
        self.num_of_successful_test_cases_Ns = 0
        self.num_of_failed_test_cases_Nf = 0
        self.suspicious_values = []
        self.distinct_values = []
        self.suspicious_path = os.path.join(self.conf.ROOT_PATH,
                                            'suspiciousness_ranking/')
        #print(self.suspicious_path)

        if os.path.isdir(self.suspicious_path):
            print(self.suspicious_path + ' directory exists...')
        else:
            print(self.suspicious_path + ' directory created...')
            self.conf.handle_dir(self.suspicious_path)

    def update_values(self):
        self.num_of_failed_test_cases_cover_statement_Ncf = 0
        self.num_of_failed_test_cases_not_cover_statement_Nuf = 0
        self.num_of_successful_test_cases_cover_statement_Ncs = 0
        self.num_of_successful_test_cases_Ns = 0
        self.num_of_failed_test_cases_Nf = 0

    def suspicious_matrix_by_dstar(self, mat_arr):
        mat = np.array(mat_arr)
        #print(mat.shape)
        #print(mat)
        col = mat.shape[1] - 1
        #print(col)
        self.update_values()
        del self.suspicious_values[:]

        for i in range(0, col):
            self.update_values()
            for j in range(0, mat.shape[0]):
                if mat[j][col] == 0:  # for fail test case
                    if mat[j][i] == 1:
                        self.num_of_failed_test_cases_cover_statement_Ncf += 1
                    if mat[j][i] == 0:
                        self.num_of_failed_test_cases_not_cover_statement_Nuf += 1

                if mat[j][col] == 1:  # for pass test case
                    if mat[j][i] == 1:
                        self.num_of_successful_test_cases_cover_statement_Ncs += 1

            #print(self.num_of_failed_test_cases_cover_statement_Ncf)
            #print(self.num_of_successful_test_cases_cover_statement_Ncs)
            sum = self.num_of_failed_test_cases_not_cover_statement_Nuf + self.num_of_successful_test_cases_cover_statement_Ncs
            #print(sum)
            if sum == 0:
                dstar_value = 0
            else:
                dstar_value = pow(
                    self.num_of_failed_test_cases_cover_statement_Ncf, 2) / sum
            #print('DStar value for ' + str(i) + ' th col value: ' + str(dstar_value))
            self.suspicious_values.append(dstar_value)

    def generate_ranking(self):
        susp_arr = np.array(self.suspicious_values)
        print('---processing ranking---')
        self.distinct_values = []
        dist_arr = np.unique(susp_arr)
        # dist_array needs to reverse for making descending order
        self.distinct_values = dist_arr[::-1]
        #print(self.distinct_values)
        #for x in range(distinct_values.shape[0]):

    def print_suspiciousness_ranking_table(self, filename):
        print('writing csv for :', filename)
        #print(self.suspicious_path)
        susp_arr = np.array(self.suspicious_values)
        filename = filename + '.csv'
        with open(self.suspicious_path + filename, 'w') as csvfile:
            columnTitleRow = "Method_Call_No,Suspiciousness,Ranking\n"
            csvfile.write(columnTitleRow)
            for i in range(0, susp_arr.shape[0]):
                for y in range(0, len(self.distinct_values)):
                    if susp_arr[i] == self.distinct_values[y]:
                        row = str(i + 1) + "," + str(
                            susp_arr[i]) + "," + str(y + 1) + "\n"
                        csvfile.write(row)
                        #print('DStar value for ' + str(i+1) + ' th col value: ' + str(susp_arr[i]) + ' Ranking - ' + str(y+1))

    def calculate_suspiciousness(self):
        for i in range(0, len(self.conf.PROJECTS_DATA_PATH)):
            for subdir, dirs, files in sorted(
                    os.walk(self.conf.PROJECTS_DATA_PATH[i])):
                for file in sorted(files):
                    filepath = os.path.join(subdir, file)

                    if file == 'matrix':
                        print(filepath)
                        mat = self.loader.load_coverage_file(filepath)
                        self.suspicious_matrix_by_dstar(mat)
                        self.generate_ranking()
                        buggy_version = re.findall('\d+', filepath)
                        filename = self.conf.PROJECTS_ID[
                            i] + '_' + buggy_version[0]
                        #print(filename)
                        self.print_suspiciousness_ranking_table(filename)
        #mat = self.load_matrix()
        #mat_arr = np.asarray(mat)
        print('---Suspicious Ranking of Matrix Done----')