UNPKG

@syntest/search

Version:

The common core of the SynTest Framework

109 lines 5.03 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ApproachLevel = void 0; /* * Copyright 2020-2023 Delft University of Technology and SynTest contributors * * This file is part of SynTest Framework - SynTest Core. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ const cfg_1 = require("@syntest/cfg"); const diagnostics_1 = require("../../util/diagnostics"); class ApproachLevel { calculate(cfg, node, traces) { // Construct map with key as id covered and value as datapoint that covers that id const idsTraceMap = new Map(traces.filter((trace) => trace.hits > 0).map((trace) => [trace.id, trace])); // Construct set of all covered ids const coveredNodeIds = new Set(idsTraceMap.keys()); const { approachLevel, closestCoveredBranch, lastEdgeType, statementFraction, } = this._findClosestCoveredBranch(cfg, node.id, coveredNodeIds); // if closest node is not found, we return the distance to the root branch if (!closestCoveredBranch) { return { approachLevel: undefined, closestCoveredNode: undefined, closestCoveredBranchTrace: undefined, lastEdgeType: undefined, statementFraction: undefined, }; } // Retrieve trace based on ids covered by found closestCoveredBranch const closestCoveredBranchTrace = idsTraceMap.get(closestCoveredBranch.id); if (!closestCoveredBranchTrace) { throw new Error((0, diagnostics_1.cannotFindTraceThatIsCovered)()); } return { approachLevel, closestCoveredNode: closestCoveredBranch, closestCoveredBranchTrace, lastEdgeType: lastEdgeType, statementFraction: statementFraction, }; } // eslint-disable-next-line sonarjs/cognitive-complexity _findClosestCoveredBranch(cfg, from, targets) { const visitedNodeIdSet = new Set([from]); const searchQueue = [[from, 0]]; while (searchQueue.length > 0) { const current = searchQueue.shift(); const currentNodeId = current[0]; const currentDistance = current[1]; // get all neighbors of currently considered node const incomingEdges = cfg.getIncomingEdges(currentNodeId); for (const edge of incomingEdges) { // ignore if already visited node if (visitedNodeIdSet.has(edge.source)) { continue; } // return if one of targets nodes was found if (targets.has(edge.source)) { const sourceNode = cfg.getNodeById(edge.source); let statementCount = -1; for (let index = 0; index < sourceNode.statements.length; index++) { const statement = sourceNode.statements[index]; if (targets.has(statement.id)) { statementCount = index + 1; } } return { approachLevel: currentDistance, closestCoveredBranch: cfg.getNodeById(edge.source), lastEdgeType: edge.type === cfg_1.EdgeType.CONDITIONAL_TRUE, statementFraction: sourceNode.statements.length === 0 ? -1 : statementCount / sourceNode.statements.length, }; } // add element to queue and visited nodes to continue search visitedNodeIdSet.add(edge.source); if (edge.type === cfg_1.EdgeType.CONDITIONAL_TRUE || edge.type === cfg_1.EdgeType.CONDITIONAL_FALSE) { // If a node has more than one outgoing edge, it is a control node // Only control nodes are considered in the approach level searchQueue.push([edge.source, currentDistance + 1]); } else { searchQueue.push([edge.source, currentDistance]); } } } return { approachLevel: -1, closestCoveredBranch: undefined, lastEdgeType: undefined, statementFraction: undefined, }; } } exports.ApproachLevel = ApproachLevel; //# sourceMappingURL=ApproachLevel.js.map