/**
* Copyright (C) 2010-2017 Gordon Fraser, Andrea Arcuri and EvoSuite
* contributors
*
* This file is part of EvoSuite.
*
* EvoSuite is free software: you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 3.0 of the License, or
* (at your option) any later version.
*
* EvoSuite is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with EvoSuite. If not, see <http://www.gnu.org/licenses/>.
*/
package org.evosuite.statistics;
import org.evosuite.Properties;
import org.evosuite.TimeController;
import org.evosuite.testsuite.TestSuiteChromosome;
import java.util.ArrayList;
import java.util.List;
/**
* Creates an output variable that represents a sequence of values extracted from
* a test suite
*
* @author gordon
*
* @param <T>
*/
public abstract class SequenceOutputVariableFactory<T extends Number> {
protected RuntimeVariable variable;
protected List<Long> timeStamps = new ArrayList<Long>();
protected List<T> values = new ArrayList<T>();
private long startTime = 0L;
public SequenceOutputVariableFactory(RuntimeVariable variable) {
this.variable = variable;
}
public void setStartTime(long time) {
this.startTime = time;
}
protected abstract T getValue(TestSuiteChromosome individual);
public void update(TestSuiteChromosome individual) {
timeStamps.add(System.currentTimeMillis() - startTime);
values.add(getValue(individual));
}
public List<String> getVariableNames() {
List<String> variables = new ArrayList<String>();
for(String suffix : getTimelineHeaderSuffixes()) {
variables.add(variable.name() + suffix);
}
return variables;
}
public List<OutputVariable<T>> getOutputVariables() {
List<OutputVariable<T>> variables = new ArrayList<OutputVariable<T>>();
for(String variableName : getVariableNames()) {
OutputVariable<T> variable = new OutputVariable<T>(variableName, getTimeLineValue(variableName));
variables.add(variable);
}
return variables;
}
@SuppressWarnings("unchecked")
private T getTimeLineValue(String name) {
long interval = Properties.TIMELINE_INTERVAL;
int index = Integer.parseInt( (name.split("_T"))[1] );
long preferredTime = interval * index;
/*
* No data. Is it even possible? Maybe if population is too large,
* and budget was not enough to get even first generation
*/
if(timeStamps.isEmpty()){
return (T) Integer.valueOf(0); // FIXXME - what else?
}
for(int i=0; i<timeStamps.size(); i++){
/*
* find the first stamp that is after the time we would like to
* get coverage from
*/
long stamp = timeStamps.get(i);
if(stamp < preferredTime){
continue;
}
if(i==0){
/*
* it is the first element, so not much to do, we just use it as value
*/
return values.get(i);
}
/*
* If we do not want to interpolate, return last observed value
*/
if (! Properties.TIMELINE_INTERPOLATION) {
return values.get(i-1);
}
/*
* Now we interpolate the coverage, as usually we don't have the value for exact time we want
*/
long timeDelta = timeStamps.get(i) - timeStamps.get(i-1);
if(timeDelta > 0 ){
double covDelta = values.get(i).doubleValue() - values.get(i-1).doubleValue();
double ratio = covDelta / timeDelta;
long diff = preferredTime - timeStamps.get(i-1);
Double cov = values.get(i-1).doubleValue() + (diff * ratio);
return (T)cov; // TODO...type
}
}
/*
* No time stamp was higher. This might happen if coverage is 100% and we stop search.
* So just return last value seen
*/
return values.get(values.size()-1);
}
private String[] getTimelineHeaderSuffixes(){
int numberOfIntervals = calculateNumberOfIntervals();
String[] suffixes = new String[numberOfIntervals];
for(int i=0; i<suffixes.length; i++){
/*
* NOTE: we start from T1 and not T0 because, by definition, coverage
* at T0 is equal to T0, and no point in showing it in a graph
*/
suffixes[i] = "_T"+(i+1);
}
return suffixes;
}
private int calculateNumberOfIntervals() {
long interval = Properties.TIMELINE_INTERVAL;
/*
* We cannot just look at the obtained history, because the search might
* have finished earlier, eg if 100% coverage
*/
long totalTime = TimeController.getSearchBudgetInSeconds() * 1000l;
int numberOfIntervals = (int) (totalTime / interval);
return numberOfIntervals;
}
}