@syntest/core
Version:
The common core of the SynTest Framework
185 lines • 8.75 kB
JavaScript
"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.
*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SearchAlgorithm = void 0;
const UserInterface_1 = require("../../ui/UserInterface");
/**
* 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(eventManager, objectiveManager) {
this._eventManager = eventManager;
this._objectiveManager = objectiveManager;
this._listeners = [];
}
/**
* 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
*/
search(subject, budgetManager, terminationManager) {
return __awaiter(this, void 0, void 0, function* () {
// Load search subject into the objective manager
this._objectiveManager.load(subject);
// Start initialization budget tracking
budgetManager.initializationStarted();
(0, UserInterface_1.getUserInterface)().startProgressBar();
// Inform listeners that the search started
this._listeners.forEach((listener) => {
listener.searchStarted(this, budgetManager, terminationManager);
});
(0, UserInterface_1.getUserInterface)().updateProgressBar(this.progress("branch"), budgetManager.getBudget());
this._eventManager.emitEvent("onSearchInitializationStart");
// Initialize search process
yield this._initialize(budgetManager, terminationManager);
// Stop initialization budget tracking, inform the listeners, and start search budget tracking
budgetManager.initializationStopped();
this._eventManager.emitEvent("onSearchInitializationComplete");
this._listeners.forEach((listener) => listener.initializationDone(this, budgetManager, terminationManager));
(0, UserInterface_1.getUserInterface)().updateProgressBar(this.progress("branch"), budgetManager.getBudget());
budgetManager.searchStarted();
this._eventManager.emitEvent("onSearchStart");
// 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()) {
this._eventManager.emitEvent("onSearchIterationStart");
// Start next iteration of the search process
yield this._iterate(budgetManager, terminationManager);
// Inform the budget manager and listeners that an iteration happened
budgetManager.iteration(this);
this._eventManager.emitEvent("onSearchIterationComplete");
this._listeners.forEach((listener) => listener.iteration(this, budgetManager, terminationManager));
(0, UserInterface_1.getUserInterface)().updateProgressBar(this.progress("branch"), budgetManager.getBudget());
}
// Stop search budget tracking
budgetManager.searchStopped();
(0, UserInterface_1.getUserInterface)().stopProgressBar();
this._eventManager.emitEvent("onSearchComplete");
// Inform listeners that the search stopped
this._listeners.forEach((listener) => {
listener.searchStarted(this, budgetManager, terminationManager);
});
// Return the archive of covered objectives
return this._objectiveManager.getArchive();
});
}
/**
* Return the objective manager.
*/
getObjectiveManager() {
return this._objectiveManager;
}
getCovered(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 paths = key.getSubject().path.split("/");
const fileName = paths[paths.length - 1];
result
.getTraces()
.filter((element) => element.type.includes(objectiveType) || objectiveType === "mixed")
.filter((element) => element.path.includes(fileName))
.forEach((current) => {
total.add(current.id + "_" + current.branchType);
if (current.hits > 0)
covered.add(current.id + "_" + current.branchType);
});
}
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 paths = key.getSubject().path.split("/");
const fileName = paths[paths.length - 1];
result
.getTraces()
.filter((element) => element.type.includes(objectiveType) || objectiveType === "mixed")
.filter((element) => element.path.includes(fileName))
.forEach((current) => {
total.add(current.id + "_" + current.branchType);
if (current.hits > 0)
covered.add(current.id + "_" + current.branchType);
});
}
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 = Math.pow(10, 2);
return Math.round(progress * factor) / factor;
}
/**
* Add a search listener to monitor the search process.
*
* @param listener The listener to add
*/
addListener(listener) {
this._listeners.push(listener);
return this;
}
/**
* Remove a search listener from the search process.
*
* @param listener The listener to remove
*/
removeListener(listener) {
this._listeners.slice(this._listeners.indexOf(listener), 1);
return this;
}
}
exports.SearchAlgorithm = SearchAlgorithm;
//# sourceMappingURL=SearchAlgorithm.js.map