package hudson.plugins.testng.results;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.Serializable;
import java.util.*;
import hudson.model.Run;
import hudson.plugins.testng.PluginImpl;
import org.kohsuke.stapler.export.Exported;
/**
* Represents all the results gathered for a single build (or a single suite,
* while parsing the test results)
*
* @author nullin
* @author farshidce
*/
@SuppressFBWarnings(value="SE_BAD_FIELD", justification="ArrayList is Serializable")
public class TestNGResult extends BaseResult implements Serializable {
private static final long serialVersionUID = -3491974223665601995L;
private List<TestNGTestResult> testList = new ArrayList<TestNGTestResult>();
private List<MethodResult> passedTests = new ArrayList<MethodResult>();
private List<MethodResult> failedTests = new ArrayList<MethodResult>();
private List<MethodResult> skippedTests = new ArrayList<MethodResult>();
private List<MethodResult> failedConfigurationMethods = new ArrayList<MethodResult>();
private List<MethodResult> skippedConfigurationMethods = new ArrayList<MethodResult>();
private long startTime;
private long endTime;
private int passCount;
private int failCount;
private int skipCount;
private int failedConfigCount;
private int skippedConfigCount;
private Map<String, PackageResult> packageMap = new HashMap<String, PackageResult>();
/**
* @param name input name is ignored
* @deprecated don't use this constructor
*/
public TestNGResult(String name) {
super(PluginImpl.URL);
}
public TestNGResult() {
super(PluginImpl.URL);
}
@Override
public String getTitle() {
return getDisplayName();
}
@Override
public List<MethodResult> getFailedTests() {
return failedTests;
}
@Override
public List<MethodResult> getPassedTests() {
return passedTests;
}
@Override
public List<MethodResult> getSkippedTests() {
return skippedTests;
}
public List<MethodResult> getFailedConfigs() {
return failedConfigurationMethods;
}
public List<MethodResult> getSkippedConfigs() {
return skippedConfigurationMethods;
}
/**
* Gets the total number of passed tests.
*/
public int getPassCount() {
return passCount;
}
/**
* Gets the total number of failed tests.
*/
@Exported
public int getFailCount() {
return failCount;
}
/**
* Gets the total number of skipped tests.
*/
@Exported
public int getSkipCount() {
return skipCount;
}
public List<TestNGTestResult> getTestList() {
return testList;
}
@Exported(name = "total")
public int getTotalCount() {
return super.getTotalCount();
}
@Exported
@Override
public float getDuration() {
return (float) (endTime - startTime) / 1000f;
}
@Exported(name = "fail-config")
public int getFailedConfigCount() {
return failedConfigCount;
}
@Exported(name = "skip-config")
public int getSkippedConfigCount() {
return skippedConfigCount;
}
@Exported(name = "package")
public Collection<PackageResult> getPackageList() {
return packageMap.values();
}
public Map<String, PackageResult> getPackageMap() {
return packageMap;
}
public Set<String> getPackageNames() {
return packageMap.keySet();
}
/**
* Adds only the {@code <test>}s that already aren't part of the list.
*
* @param testList
*/
//TODO: whats going on here? why unique?
public void addUniqueTests(List<TestNGTestResult> testList) {
Set<TestNGTestResult> tmpSet = new HashSet<TestNGTestResult>(this.testList);
tmpSet.addAll(testList);
this.testList = new ArrayList<TestNGTestResult>(tmpSet);
}
public void setRun(Run<?, ?> run) {
this.run = run;
for (PackageResult pkg : packageMap.values()) {
pkg.setRun(run);
}
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
TestNGResult testngResult = (TestNGResult) o;
return run == null ? testngResult.run == null
: run.equals(testngResult.run);
}
@Override
public int hashCode() {
int result;
result = (run != null ? run.hashCode() : 0);
return result;
}
@Override
public String toString() {
return String.format("TestNGResult {" +
"totalTests=%d, " +
"failedTests=%d, skippedTests=%d, failedConfigs=%d, " +
"skippedConfigs=%d}", //name,
passCount + failCount + skipCount, failCount,
skipCount, failedConfigCount,
skippedConfigCount);
}
/**
* Updates the calculated fields
*/
@Override
public void tally() {
failedConfigCount = failedConfigurationMethods.size();
skippedConfigCount = skippedConfigurationMethods.size();
failCount = failedTests.size();
passCount = passedTests.size();
skipCount = skippedTests.size();
packageMap.clear();
for (TestNGTestResult _test : testList) {
for (ClassResult _class : _test.getClassList()) {
String pkg = _class.getPkgName();
if (packageMap.containsKey(pkg)) {
List<ClassResult> classResults = packageMap.get(pkg).getChildren();
if (!classResults.contains(_class)) {
classResults.add(_class);
}
} else {
PackageResult tpkg = new PackageResult(pkg);
tpkg.getChildren().add(_class);
tpkg.setParent(this);
packageMap.put(pkg, tpkg);
}
}
}
startTime = Long.MAX_VALUE;
endTime = 0;
for (PackageResult pkgResult : packageMap.values()) {
pkgResult.tally();
if (this.startTime > pkgResult.getStartTime()) {
startTime = pkgResult.getStartTime(); //cf. ClassResult#tally()
}
if (this.endTime < pkgResult.getEndTime()) {
endTime = pkgResult.getEndTime();
}
}
}
@Exported(visibility = 999)
public String getName() {
return name;
}
@Override
public BaseResult getParent() {
return null;
}
@Override
public String getDisplayName() {
return getName();
}
@Override
public Collection<PackageResult> getChildren() {
return packageMap.values();
}
@Override
public boolean hasChildren() {
return !packageMap.isEmpty();
}
}