blob: 967847975c91623579901897d679a204d27f7b73 [file] [log] [blame]
package org.testng.reporters;
import org.testng.IReporter;
import org.testng.IResultMap;
import org.testng.ISuite;
import org.testng.ISuiteResult;
import org.testng.ITestContext;
import org.testng.ITestNGMethod;
import org.testng.ITestResult;
import org.testng.Reporter;
import org.testng.log4testng.Logger;
import org.testng.xml.XmlSuite;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Collection;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
* Reported designed to render self-contained HTML top down view
* of a testing suite.
*
* @author Paul Mendelson
* @version $Revision: 3 $
*/
public class EmailableReporter implements IReporter
{
Logger logger=Logger.getLogger(EmailableReporter.class);
//~ Instance fields ------------------------------------------------------
private PrintWriter out;
int row;
//~ Methods --------------------------------------------------------------
/** Creates summary of the run */
public void generateReport(
List<XmlSuite> xml,
List<ISuite> suites,
String outdir)
{
try {
out=new PrintWriter(new FileWriter(new File(outdir,"emailable-report.html")));
} catch(IOException e) {
logger.error("output file",e);
return;
}
startHtml(out);
for(ISuite suite : suites) {
summarize(suite);
out.println("<a id=summary></a>");
Map<String,ISuiteResult> r=suite.getResults();
for(ISuiteResult r2 : r.values()) {
resultSummary(
r2.getTestContext().getFailedTests(),
"failed");
resultSummary(
r2.getTestContext().getPassedTests(),
"passed");
resultDetail(
r2.getTestContext().getFailedTests(),
"failed");
resultDetail(
r2.getTestContext().getPassedTests(),
"passed");
}
}
out.println("</body></html>");
out.close();
}
/**
* @param tests
*/
private void resultSummary(IResultMap tests,String style)
{
if(tests.getAllResults().size()>0) {
tableStart(style);
out.println(
"<tr><th>Class</th>"
+"<th>Method</th><th># of<br/>Scenarios</th><th>Time<br/>(Msecs)</th></tr>");
int row=0;
StringBuffer buff=new StringBuffer();
String lastc="";
int mq=0;
int cq=0;
for(ITestNGMethod method : getMethodSet(tests)) {
row+=1;
String cname=method.getTestClass().getName();
if(!cname.equalsIgnoreCase(lastc)) {
if(mq>0) {
cq+=1;
out.println(
"<tr"+(cq%2==0
? " class=\"stripe\""
: "")+">"+"<td rowspan=\""+mq+"\">"+lastc+buff);
}
mq=0;
buff.setLength(0);
lastc=cname;
}
Set<ITestResult> result_set=tests.getResults(method);
long end=Long.MIN_VALUE;
long start=Long.MAX_VALUE;
for(ITestResult ans : tests.getResults(method)) {
if(ans.getEndMillis()>end) {
end=ans.getEndMillis();
}
if(ans.getStartMillis()<start) {
start=ans.getStartMillis();
}
}
mq+=1;
if(mq>1) {
buff.append("<tr"+(cq%2==1
? " class=\"stripe\""
: "")+">");
}
buff.append(
"<td><a href=\"#m"+row+"\">"+qualifiedName(method)+"</a></td>"
+"<td class=\"numi\">"+result_set.size()+"</td><td class=\"numi\">"
+(end-start)+"</td></tr>");
}
if(mq>0) {
row+=1;
out.println(
"<tr"+(row%2==0
? " class=\"stripe\""
: "")+">"+"<td rowspan=\""+mq+"\">"+lastc+buff);
}
out.println("</table>");
}
}
private String qualifiedName(ITestNGMethod method) {
String addon="";
if(method.getGroups().length>0 && ! "basic".equalsIgnoreCase(method.getGroups()[0])) {
addon=" ("+method.getGroups()[0]+")";
}
return method.getMethodName()+addon;
}
private void resultDetail(IResultMap tests,String style)
{
if(tests.getAllResults().size()>0) {
int row=0;
StringBuffer buff=new StringBuffer();
for(ITestNGMethod method : getMethodSet(tests)) {
row+=1;
String cname=method.getTestClass().getName();
out.println(
"<a id=\"m"+row+"\"></a><h2>"+cname+":"+method.getMethodName()
+"</h2>");
// Set<ITestResult> result_set=tests.getResults(method);
// long end=Long.MIN_VALUE;
// long start=Long.MAX_VALUE;
int rq=0;
Set<ITestResult> result_set=tests.getResults(method);
for(ITestResult ans : result_set) {
rq+=1;
Object[] pset=ans.getParameters();
if(pset.length>0) {
if(rq==1) {
tableStart("param");
out.print("<tr>");
for(int x=1; x<=pset.length; x++) {
out.print(
"<th style=\"padding-left:1em;padding-right:1em\">Parameter #"+x
+"</th>");
}
out.println("</tr>");
}
out.print("<tr>");
for(Object p : pset) {
out.println(
"<td style=\"padding-left:.5em;padding-right:2em\">"+p+"</td>");
}
out.println("</tr>");
if(rq==result_set.size()) {
out.println("</table>");
}
}
List<String> msgs=Reporter.getOutput(ans);
if(msgs.size()>0) {
out.println("<div style=\"padding-left:3em\">");
for(String line : msgs) {
out.println(line+"<br/>");
}
out.println("</div>");
}
}
// mq+=1;
// if(mq>1)
// buff.append("<tr"+(row%2==1?" class=\"stripe\"":"")+">");
// buff.append("<td><a href=\"#"+method.getId()+">"+method.getMethodName()+"</a></td>"
// +"<td class=\"numi\">"+result_set.size()+"</td><td class=\"numi\">"
// +(end-start)
// +"</td></tr>");
// }
// if(mq>0) {
// row+=1;
// out.println("<tr"+(row%2==0?" class=\"stripe\"":"")+">"
// +"<td rowspan=\""+mq+"\">"+lastc+buff);
out.println("<p class=\"totop\"><a href=#top>back to summary</a></p>");
}
// out.println("</table>");
}
}
/**
* @param tests
* @return
*/
private Collection<ITestNGMethod> getMethodSet(IResultMap tests)
{
Set r=new TreeSet<ITestNGMethod>(new TestSorter<ITestNGMethod>());
r.addAll(tests.getAllMethods());
return r;
}
private void summarize(ISuite suite)
{
tableStart("param");
Map<String,ISuiteResult> r=suite.getResults();
for(ISuiteResult r2 : r.values()) {
ITestContext overview=r2.getTestContext();
tableRow(
"# of Tests passed",
getMethodSet(overview.getPassedTests()).size());
tableRow(
"# of Scenarios passed",
overview.getPassedTests().size());
tableRow(
"# failed",
overview.getFailedTests().size());
tableRow(
"# skipped",
overview.getSkippedTests().size());
NumberFormat formatter=new DecimalFormat("#,##0.0");
tableRow(
"Total Time",
formatter.format(
(overview.getEndDate().getTime()-overview.getStartDate().getTime())/1000.)
+" seconds");
tableRow(
"Included Groups",
overview.getIncludedGroups());
tableRow(
"Excluded Groups",
overview.getExcludedGroups());
}
out.println("</table>");
}
/**
*
*/
private void tableStart(String cssclass)
{
out.println(
"<table cellspacing=0 cellpadding=0"
+(
cssclass!=null
? " class=\""+cssclass+"\""
: " style=\"padding-bottom:2em\""
)+">");
row=0;
}
private void tableRow(String label,String val)
{
row+=1;
out.println(
"<tr"+(row%2==0
? " class=\"stripe\""
: "")+"><th style=\"text-align:left;padding-right:2em\">"+label
+"</th><td style=\"text-align:right\">"+val+"</td></tr>");
}
private void tableRow(String label,long val)
{
tableRow(
label,
String.valueOf(val));
}
private void tableRow(String label,String[] val)
{
StringBuffer b=new StringBuffer();
for(String v : val)
b.append(v+" ");
tableRow(
label,
b.toString().trim());
}
private void startHtml(PrintWriter out)
{
out.println("<html>");
out.println("<head>");
out.println("<title>TestNG: Unit Test</title>");
out.println("<style type=\"text/css\">");
out.println(
"table.info_table,table.param,table.passed,table.failed {margin-bottom:10px;border:1px solid #000099;border-collapse:collapse;empty-cells:show;}");
out.println(
"table.info_table td,table.info_table th,table.param td,table.param th,table.passed td,table.passed th,table.failed td,table.failed th {");
out.println("border:1px solid #000099;padding:.25em .5em .25em .5em");
out.println("}");
out.println("td.numi {");
out.println("text-align:right");
out.println("}");
out.println("table.passed td {background-color: #00AA00;}");
out.println("table.passed tr.stripe td {background-color: #33FF33;}");
out.println("table.failed td {background-color: #DD0000;}");
out.println("table.failed tr.stripe td {background-color: #FF3333;}");
out.println("tr.stripe td,tr.stripe th {background-color: #E6EBF9;}");
out.println(
"p.totop {font-size:85%;text-align:center;border-bottom:2px black solid}");
out.println("div.shootout {padding:2em;border:3px #4854A8 solid}");
out.println("</style>");
out.println("</head>");
out.println("<body>");
}
//~ Inner Classes --------------------------------------------------------
/**
* DOCUMENT ME!
*
* @author $author$
* @version $Revision: 3 $
*
* @param <T> DOCUMENT ME!
*/
private class TestSorter<T extends ITestNGMethod> implements Comparator
{
//~ Methods -------------------------------------------------------------
/**
* DOCUMENT ME!
*
* @param o1 DOCUMENT ME!
* @param o2 DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public int compare(Object o1,Object o2)
{
int r=
((T)o1).getTestClass().getName()
.compareTo(((T)o2).getTestClass().getName());
if(r==0) {
r=((T)o1).getMethodName().compareTo(((T)o2).getMethodName());
}
return r;
}
}
}