UNPKG

@syntest/search

Version:

The common core of the SynTest Framework

164 lines 7.32 kB
"use strict"; /* * Copyright 2020-2021 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. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.SearchAlgorithm = void 0; const path = require("node:path"); const logging_1 = require("@syntest/logging"); /** * Abstract search algorithm to search for an optimal solution within the search space. * * The search algorithm is dependent on the encoding of the search space. * * @author Mitchell Olsthoorn */ class SearchAlgorithm { /** * Abstract constructor. * * @param eventManager The event manager * @param objectiveManager The objective manager * @protected */ constructor(objectiveManager) { SearchAlgorithm.LOGGER = (0, logging_1.getLogger)(SearchAlgorithm.name); this._population = []; this._objectiveManager = objectiveManager; } /** * Search the search space for an optimal solution until one of the termination conditions are met. * * @param subject The subject of the search * @param budgetManager The budget manager to track budget progress * @param terminationManager The termination trigger manager */ async search(subject, budgetManager, terminationManager) { SearchAlgorithm.LOGGER.info("Starting search"); // Load search subject into the objective manager this._objectiveManager.load(subject); // Start initialization budget tracking budgetManager.initializationStarted(); process.emit("searchInitializationStart", this, subject, budgetManager, terminationManager); // Initialize search process await this._initialize(budgetManager, terminationManager); // Stop initialization budget tracking, inform the listeners, and start search budget tracking budgetManager.initializationStopped(); process.emit("searchInitializationComplete", this, subject, budgetManager, terminationManager); budgetManager.searchStarted(); process.emit("searchStart", this, subject, budgetManager, terminationManager); // Start search until the budget has expired, a termination trigger has been triggered, or there are no more objectives while (this._objectiveManager.hasObjectives() && budgetManager.hasBudgetLeft() && !terminationManager.isTriggered()) { process.emit("searchIterationStart", this, subject, budgetManager, terminationManager); // Start next iteration of the search process await this._iterate(budgetManager, terminationManager); // Inform the budget manager and listeners that an iteration happened budgetManager.iteration(this); process.emit("searchIterationComplete", this, subject, budgetManager, terminationManager); } // Stop search budget tracking budgetManager.searchStopped(); process.emit("searchComplete", this, subject, budgetManager, terminationManager); // Finalize the population this._objectiveManager.finalize(this._population); // Return the archive of covered objectives return this._objectiveManager.getArchive(); } // eslint-disable-next-line sonarjs/cognitive-complexity calculateObjectivePerformance(objectives) { const objectivePerformace = new Map(); for (const encoding of this._population) { if (encoding.getExecutionResult() === undefined) { continue; } for (const objective of objectives) { const distance = encoding.getDistance(objective); if (distance === undefined) { continue; } if (objectivePerformace.has(objective)) { const smallestDistance = objectivePerformace.get(objective); if (distance < smallestDistance) { objectivePerformace.set(objective, distance); } } else { objectivePerformace.set(objective, distance); } } } return objectivePerformace; } /** * Return the objective manager. */ getObjectiveManager() { return this._objectiveManager; } getCovered(objectiveType = "mixed") { const covered = new Set(); for (const key of this._objectiveManager.getArchive().getObjectives()) { const test = this._objectiveManager.getArchive().getEncoding(key); const result = test.getExecutionResult(); // TODO this does not work when there are files with the same name in different directories!! const fileName = path.basename(key.getSubject().path); for (const current of result .getTraces() .filter((element) => element.type.includes(objectiveType) || objectiveType === "mixed") .filter((element) => element.path.includes(fileName))) { if (current.hits > 0) covered.add(current.id); } } return covered.size; } getUncovered(objectiveType = "mixed") { const total = new Set(); const covered = new Set(); for (const key of this._objectiveManager.getArchive().getObjectives()) { const test = this._objectiveManager.getArchive().getEncoding(key); const result = test.getExecutionResult(); // TODO this does not work when there are files with the same name in different directories!! const fileName = path.basename(key.getSubject().path); for (const current of result .getTraces() .filter((element) => element.type.includes(objectiveType) || objectiveType === "mixed") .filter((element) => element.path.includes(fileName))) { total.add(current.id); if (current.hits > 0) covered.add(current.id); } } return total.size - covered.size; } /** * The progress of the search process. */ progress(objectiveType = "mixed") { const numberOfCoveredObjectives = this.getCovered(objectiveType); const numberOfUncoveredObjectives = this.getUncovered(objectiveType); const progress = (numberOfCoveredObjectives / (numberOfCoveredObjectives + numberOfUncoveredObjectives)) * 100; const factor = 10 ** 2; return Math.round(progress * factor) / factor; } } exports.SearchAlgorithm = SearchAlgorithm; //# sourceMappingURL=SearchAlgorithm.js.map