/**
* 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.setup;
import org.evosuite.PackageInfo;
import org.evosuite.Properties;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
/**
* <p>
* CallContext class.
* </p>
*
* @author Gordon Fraser
*/
/**
* TODO THIS IS APPROXIMATED call context computed at runtime DO NOT consider
* the method signature, but only the method name. Currently, callcontext with
* and without signature are considered equal
*
* @author mattia
*
*/
public class CallContext implements Serializable {
/**
*
*/
private static final long serialVersionUID = 8650619230188403356L;
private final List<Call> context;
private final int hcode;
public boolean isEmpty() {
return context.isEmpty();
}
/**
* <p>
* Constructor for CallContext.
* </p>
*
* @param stackTrace
* an array of {@link java.lang.StackTraceElement} objects.
*/
public CallContext(StackTraceElement[] stackTrace) {
addJUnitExcludes();
int startPos = stackTrace.length - 1;
int endPos = 0;
List<Call> context = new ArrayList<Call>();
// Stack traces may be empty, e.g. if an exception is thrown in a constructor call in a test
while (startPos >= 0 && shouldSkipEntry(stackTrace[startPos].getClassName())) {
startPos--;
}
while (endPos < stackTrace.length && shouldSkipEntry(stackTrace[endPos].getClassName())) {
endPos++;
}
for (int i = startPos; i >= endPos; i--) {
StackTraceElement element = stackTrace[i];
context.add(new Call(element.getClassName(), element.getMethodName()));
}
this.context=context;
hcode = this.context.hashCode();
}
/**
* Constructor for public methods
*
* @param className
* @param methodName
*/
public CallContext(String className, String methodName) {
addJUnitExcludes();
List<Call> context = new ArrayList<Call>();
context.add(new Call(className, methodName));
this.context=context;
hcode = this.context.hashCode();
}
public CallContext() {
addJUnitExcludes();
List<Call> context = new ArrayList<Call>();
this.context=context;
hcode = this.context.hashCode();
}
public CallContext(Collection<Call> contextt) {
addJUnitExcludes();
List<Call> context = new ArrayList<Call>();
context.addAll(contextt);
this.context=context;
hcode = this.context.hashCode();
}
public int size() {
return context.size();
}
private String[] excludedPackages = new String[] { "java", "sun", PackageInfo.getEvoSuitePackage() };
/**
* If we are using -measureCoverage then we need to also exclude the junit tests
*/
private void addJUnitExcludes() {
if(Properties.JUNIT.isEmpty())
return;
List<String> values = new ArrayList<>(Arrays.asList(excludedPackages));
values.add("org.junit");
for(String junitClass : Properties.JUNIT.split(":")) {
values.add(junitClass);
}
excludedPackages = new String[values.size()];
excludedPackages = values.toArray(excludedPackages);
}
private boolean shouldSkipEntry(String entry) {
for(String excludedPackage : excludedPackages) {
if (entry.startsWith(excludedPackage))
return true;
}
return false;
}
/**
* attach the className-methodname pair passed as parameter before the
* current context.
**/
@Deprecated
public CallContext getSuperContext(String className, String methodName) {
throw new IllegalStateException("YET TO IMPLEMENT, DEPRECATED");
}
/**
* <p>
* getRootClassName
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getRootClassName() {
return context.get(0).getClassName();
}
/**
* <p>
* getRootMethodName
* </p>
*
* @return a {@link java.lang.String} object.
*/
public String getRootMethodName() {
return context.get(0).getMethodName();
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
/** {@inheritDoc} */
@Override
public String toString() {
if(context == null)
return "";
StringBuilder builder = new StringBuilder();
for (Call call : context) {
builder.append(call.toString());
builder.append(" ");
}
String tmp = builder.toString();
return tmp.trim();
}
@Override
public int hashCode() {
return hcode;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
CallContext other = (CallContext) obj;
if (hcode == other.hcode)
return true;
return false;
}
public boolean oldMatches(CallContext other) {
if (context.size() != other.context.size())
return false;
if (other.hcode == hcode)
return true;
for (int i = 0; i < context.size(); i++) {
Call call1 = context.get(i);
Call call2 = other.context.get(i);
if (!call1.matches(call2)) {
return false;
}
}
return false;
}
//A empty context matches with everything.
public boolean matches(CallContext other) {
if (context.isEmpty()||other.context.isEmpty()|| other.hcode == hcode)
return true;
return false;
}
public List<Call> getContext() {
return context;
}
// ----------------
// CALL class
}