1336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustpackage org.testng.reporters;
2336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
33e72adb9019ffef6cd2308b85608207b71188407Stefan Birknerimport static org.testng.internal.Utils.isStringNotEmpty;
43e72adb9019ffef6cd2308b85608207b71188407Stefan Birkner
5fb4edb8bc045e09d28cd1ebdbcf6af3bfc19cc68Cédric Beustimport org.testng.IInvokedMethod;
60f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beustimport org.testng.IReporter;
70f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beustimport org.testng.ISuite;
80f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beustimport org.testng.ISuiteResult;
90f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beustimport org.testng.ITestClass;
100f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beustimport org.testng.ITestContext;
110f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beustimport org.testng.ITestNGMethod;
120f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beustimport org.testng.Reporter;
130f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beustimport org.testng.collections.Maps;
140f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beustimport org.testng.internal.Utils;
150f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beustimport org.testng.xml.XmlSuite;
160f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beust
17a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachterimport java.io.BufferedWriter;
180f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.io.File;
190f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.io.IOException;
200f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.lang.reflect.Method;
210f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.text.SimpleDateFormat;
220f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.util.Arrays;
230f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.util.Collection;
240f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.util.Collections;
250f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.util.Comparator;
260f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.util.List;
270f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.util.Map;
280f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
29336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust/**
30336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust * This class implements an HTML reporter for suites.
310f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin *
32336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust * @author cbeust
339a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm * @author <a href='mailto:the_mindstorm@evolva.ro'>Alexandru Popescu</a>
34336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust */
35336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustpublic class SuiteHTMLReporter implements IReporter {
36336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  public static final String METHODS_CHRONOLOGICAL = "methods.html";
37336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  public static final String METHODS_ALPHABETICAL = "methods-alphabetical.html";
38336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  public static final String GROUPS = "groups.html";
39336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  public static final String CLASSES = "classes.html";
40336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  public static final String REPORTER_OUTPUT = "reporter-output.html";
41336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  public static final String METHODS_NOT_RUN = "methods-not-run.html";
42336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  public static final String TESTNG_XML = "testng.xml.html";
430f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
440f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beust  private Map<String, ITestClass> m_classes = Maps.newHashMap();
45336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private String m_outputDirectory;
460f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
47c33bf0fc7a27ee9279aeeb60233489a3f83477d0Cédric Beust  @Override
48336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) {
49c33bf0fc7a27ee9279aeeb60233489a3f83477d0Cédric Beust    m_outputDirectory = generateOutputDirectoryName(outputDirectory + File.separator + "old");
500f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
51336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    try {
52336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      HtmlHelper.generateStylesheet(outputDirectory);
53336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    } catch (IOException e) {
54336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      //  TODO Propagate the exception properly.
55336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      e.printStackTrace();
56336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
570f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
58d46142454fa19e07df3851321c2d35df0f52a7daRyan Schmitt    for (ISuite suite : suites) {
590f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
60336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      //
61336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      // Generate the various reports
62336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      //
6331f6566ce35497e9324201e8a3f6f79265df2e79Cédric Beust      XmlSuite xmlSuite = suite.getXmlSuite();
640f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      if (xmlSuite.getTests().size() == 0) {
650f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        continue;
660f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      }
67336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      generateTableOfContents(xmlSuite, suite);
68336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      generateSuites(xmlSuite, suite);
69336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      generateIndex(xmlSuite, suite);
70336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      generateMain(xmlSuite, suite);
71336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      generateMethodsAndGroups(xmlSuite, suite);
72336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      generateMethodsChronologically(xmlSuite, suite, METHODS_CHRONOLOGICAL, false);
73336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      generateMethodsChronologically(xmlSuite, suite, METHODS_ALPHABETICAL, true);
74336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      generateClasses(xmlSuite, suite);
75336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      generateReporterOutput(xmlSuite, suite);
76336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      generateExcludedMethodsReport(xmlSuite, suite);
77336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      generateXmlFile(xmlSuite, suite);
78336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
79336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
80336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    generateIndex(suites);
81336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
820f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
8376a81bfc80b19f3530d574d1f3bf4f496fb89c51Cédric Beust  /**
8476a81bfc80b19f3530d574d1f3bf4f496fb89c51Cédric Beust   * Overridable by subclasses to create different directory names (e.g. with timestamps).
8576a81bfc80b19f3530d574d1f3bf4f496fb89c51Cédric Beust   * @param outputDirectory the output directory specified by the user
8676a81bfc80b19f3530d574d1f3bf4f496fb89c51Cédric Beust   */
8776a81bfc80b19f3530d574d1f3bf4f496fb89c51Cédric Beust  protected String generateOutputDirectoryName(String outputDirectory) {
8876a81bfc80b19f3530d574d1f3bf4f496fb89c51Cédric Beust    return outputDirectory;
8976a81bfc80b19f3530d574d1f3bf4f496fb89c51Cédric Beust  }
9076a81bfc80b19f3530d574d1f3bf4f496fb89c51Cédric Beust
91336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private void generateXmlFile(XmlSuite xmlSuite, ISuite suite) {
920b2ac5eab08098da2c2b63d4a3f87ba72ad5d6a1nullin    String content = xmlSuite.toXml().replaceAll("<", "&lt;").replaceAll(">", "&gt;")
93336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          .replaceAll(" ", "&nbsp;").replaceAll("\n", "<br/>");
940f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
95336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    StringBuffer sb = new StringBuffer("<html>");
960f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
977ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    sb.append("<head><title>").append("testng.xml for ")
987ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      .append(xmlSuite.getName()).append("</title></head><body><tt>")
99336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append(content)
100336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("</tt></body></html>");
1010f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
102975d9acab06f8de7ef2791ebe784c6d1c6b4e6d9the.mindstorm    Utils.writeFile(getOutputDirectory(xmlSuite), TESTNG_XML, sb.toString());
103336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
104336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
105336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  /**
106336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   * Generate the main index.html file that lists all the suites
107336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   * and their result
108336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   */
109336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private void generateIndex(List<ISuite> suites) {
110336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    StringBuffer sb = new StringBuffer();
111336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    String title = "Test results";
112336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    sb.append("<html>\n<head><title>" + title + "</title>")
113336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append(HtmlHelper.getCssString("."))
114336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("</head><body>\n")
115336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("<h2><p align='center'>").append(title).append("</p></h2>\n")
1167ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      .append("<table border='1' width='100%' class='main-page'>")
117336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("<tr><th>Suite</th><th>Passed</th><th>Failed</th><th>Skipped</th><th>testng.xml</th></tr>\n");
1180f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
119124444cdff2e318bce603521a44633524543619athe.mindstorm    int totalFailedTests = 0;
120124444cdff2e318bce603521a44633524543619athe.mindstorm    int totalPassedTests = 0;
121124444cdff2e318bce603521a44633524543619athe.mindstorm    int totalSkippedTests = 0;
1220f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
123124444cdff2e318bce603521a44633524543619athe.mindstorm    StringBuffer suiteBuf= new StringBuffer();
124336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    for (ISuite suite : suites) {
1250f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      if (suite.getResults().size() == 0) {
1260f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        continue;
1270f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      }
1280f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
129336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      String name = suite.getName();
1300f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
131124444cdff2e318bce603521a44633524543619athe.mindstorm      int failedTests= 0;
132124444cdff2e318bce603521a44633524543619athe.mindstorm      int passedTests= 0;
133124444cdff2e318bce603521a44633524543619athe.mindstorm      int skippedTests= 0;
1340f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
135336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      Map<String, ISuiteResult> results = suite.getResults();
1361963187da6a45f898e62e4e922faac6b9382b4e4nullin      for (ISuiteResult result : results.values()) {
137336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        ITestContext context = result.getTestContext();
138336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        failedTests += context.getFailedTests().size();
139124444cdff2e318bce603521a44633524543619athe.mindstorm        totalFailedTests += context.getFailedTests().size();
140336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        passedTests += context.getPassedTests().size();
141124444cdff2e318bce603521a44633524543619athe.mindstorm        totalPassedTests += context.getPassedTests().size();
142336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        skippedTests += context.getSkippedTests().size();
143124444cdff2e318bce603521a44633524543619athe.mindstorm        totalSkippedTests += context.getSkippedTests().size();
144336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
1450f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
1460f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      String cls = failedTests > 0 ? "invocation-failed"
1477ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust          : (passedTests > 0  ? "invocation-passed" : "invocation-failed");
148124444cdff2e318bce603521a44633524543619athe.mindstorm      suiteBuf.append("<tr align='center' class='").append(cls).append("'>")
149336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<td><a href='").append(name).append("/index.html'>")
150336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append(name).append("</a></td>\n");
151124444cdff2e318bce603521a44633524543619athe.mindstorm      suiteBuf.append("<td>" + passedTests + "</td>")
152336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<td>" + failedTests + "</td>")
153336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<td>" + skippedTests + "</td>")
154336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<td><a href='").append(name).append("/").append(TESTNG_XML).append("'>Link").append("</a></td>")
155336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("</tr>");
1560f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
157336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
1580f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
1590f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    String cls= totalFailedTests > 0 ? "invocation-failed"
1607ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust        : (totalPassedTests > 0 ? "invocation-passed" : "invocation-failed");
161124444cdff2e318bce603521a44633524543619athe.mindstorm    sb.append("<tr align='center' class='").append(cls).append("'>")
162e9d9e161c61fe97ca84146830000aae3b694ed56the.mindstorm      .append("<td><em>Total</em></td>")
163e9d9e161c61fe97ca84146830000aae3b694ed56the.mindstorm      .append("<td><em>").append(totalPassedTests).append("</em></td>")
164e9d9e161c61fe97ca84146830000aae3b694ed56the.mindstorm      .append("<td><em>").append(totalFailedTests).append("</em></td>")
165e9d9e161c61fe97ca84146830000aae3b694ed56the.mindstorm      .append("<td><em>").append(totalSkippedTests).append("</em></td>")
166124444cdff2e318bce603521a44633524543619athe.mindstorm      .append("<td>&nbsp;</td>")
167124444cdff2e318bce603521a44633524543619athe.mindstorm      .append("</tr>\n");
168124444cdff2e318bce603521a44633524543619athe.mindstorm    sb.append(suiteBuf);
169124444cdff2e318bce603521a44633524543619athe.mindstorm    sb.append("</table>").append("</body></html>\n");
1700f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
1718199621f3dd6adcbc12e93c4ea5508cf9f4f9055the.mindstorm    Utils.writeFile(m_outputDirectory, "index.html", sb.toString());
172336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
173336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
174336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private void generateExcludedMethodsReport(XmlSuite xmlSuite, ISuite suite) {
1750f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      Collection<ITestNGMethod> excluded = suite.getExcludedMethods();
17601864456a039f32dd36028e4b26c63c10d03a5aaCédric Beust      StringBuffer sb2 = new StringBuffer("<h2>Methods that were not run</h2><table>\n");
177336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      for (ITestNGMethod method : excluded) {
178336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        Method m = method.getMethod();
179336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        if (m != null) {
180336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          sb2.append("<tr><td>")
1815a7f440cd13a7b3bc12ef68e7237a519bb4e1a37the.mindstorm          .append(m.getDeclaringClass().getName() + "." + m.getName());
1823e72adb9019ffef6cd2308b85608207b71188407Stefan Birkner          String description = method.getDescription();
1833e72adb9019ffef6cd2308b85608207b71188407Stefan Birkner          if(isStringNotEmpty(description)) {
1843e72adb9019ffef6cd2308b85608207b71188407Stefan Birkner            sb2.append("<br/>").append(SP2).append("<i>").append(description).append("</i>");
1855a7f440cd13a7b3bc12ef68e7237a519bb4e1a37the.mindstorm          }
1865a7f440cd13a7b3bc12ef68e7237a519bb4e1a37the.mindstorm          sb2.append("</td></tr>\n");
187336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        }
188336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
189336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      sb2.append("</table>");
1900f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
191975d9acab06f8de7ef2791ebe784c6d1c6b4e6d9the.mindstorm      Utils.writeFile(getOutputDirectory(xmlSuite), METHODS_NOT_RUN, sb2.toString());
192336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
193336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
194336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private void generateReporterOutput(XmlSuite xmlSuite, ISuite suite) {
195336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    StringBuffer sb = new StringBuffer();
1960f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
197336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    //
198336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    // Reporter output
199336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    //
200336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    sb.append("<h2>Reporter output</h2>")
201336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("<table>");
202336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    List<String> output = Reporter.getOutput();
203336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    for (String line : output) {
204336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      sb.append("<tr><td>").append(line).append("</td></tr>\n");
205336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
2060f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
207336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    sb.append("</table>");
2080f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
2090f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    Utils.writeFile(getOutputDirectory(xmlSuite), REPORTER_OUTPUT, sb.toString());
210336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
2110f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
212336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private void generateClasses(XmlSuite xmlSuite, ISuite suite) {
213336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    StringBuffer sb = new StringBuffer();
2147ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    sb.append("<table border='1'>\n")
2157ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    .append("<tr>\n")
2167ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    .append("<th>Class name</th>\n")
2177ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    .append("<th>Method name</th>\n")
2187ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    .append("<th>Groups</th>\n")
2197ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    .append("</tr>")
2207ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    ;
221336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    for (ITestClass tc : m_classes.values()) {
2220f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      sb.append(generateClass(tc));
223336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
2240f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
2257ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    sb.append("</table>\n");
2260f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
2270f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    Utils.writeFile(getOutputDirectory(xmlSuite), CLASSES, sb.toString());
228336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
2290f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
230336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private final static String SP = "&nbsp;";
231336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private final static String SP2 = SP + SP + SP + SP;
232336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private final static String SP3 = SP2 + SP2;
233336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private final static String SP4 = SP3 + SP3;
2340f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
235336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private String generateClass(ITestClass cls) {
236336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    StringBuffer sb = new StringBuffer();
2370f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
2387ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    sb.append("<tr>\n")
2397ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      .append("<td>").append(cls.getRealClass().getName()).append("</td>\n")
2407ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      .append("<td>&nbsp;</td>")
2417ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      .append("<td>&nbsp;</td>")
2427ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      .append("</tr>\n")
2437ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      ;
2440f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
2457ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    String[] tags = new String[] {
2467ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust        "@Test",
2477ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust        "@BeforeClass",
2487ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust        "@BeforeMethod",
2497ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust        "@AfterMethod",
2507ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust        "@AfterClass"
2517ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    };
2527ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    ITestNGMethod[][] methods = new ITestNGMethod[][] {
2537ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      cls.getTestMethods(),
2547ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      cls.getBeforeClassMethods(),
2557ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      cls.getBeforeTestMethods(),
2567ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      cls.getAfterTestMethods(),
2577ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      cls.getAfterClassMethods()
2587ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    };
2590f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
2607ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    for (int i = 0; i < tags.length; i++) {
2617ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      sb.append("<tr>\n")
2627ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      .append("<td align='center' colspan='3'>").append(tags[i]).append("</td>\n")
2637ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      .append("</tr>\n")
2647ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      .append(dumpMethods(methods[i]))
2657ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      ;
2667ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    }
2677ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//    sb.append("<hr width='100%'/>")
2687ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//    .append("<h3>").append(cls.getRealClass().getName()).append("</h3>\n");
2697ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//
2707ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//    sb.append("<div>").append(SP3).append("Test methods\n")
2717ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//      .append(dumpMethods(cls.getTestMethods())).append("</div>\n")
2720f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin//      .append("<div>").append(SP3).append("@BeforeClass\n")
2737ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//      .append(dumpMethods(cls.getBeforeClassMethods())).append("</div>\n")
2740f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin//      .append("<div>").append(SP3).append("@BeforeMethod\n")
2757ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//      .append(dumpMethods(cls.getBeforeTestMethods())).append("</div>\n")
2760f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin//      .append("<div>").append(SP3).append("@AfterMethod\n")
2777ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//      .append(dumpMethods(cls.getAfterTestMethods())).append("</div>\n")
2780f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin//      .append("<div>").append(SP3).append("@AfterClass\n")
2797ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//      .append(dumpMethods(cls.getAfterClassMethods())).append("</div>\n")
2807ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//     ;
2810f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
282336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    String result = sb.toString();
283336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    return result;
284336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
2850f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
286336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private String dumpMethods(ITestNGMethod[] testMethods) {
2878c794e046efae93dc1053eac4c978a3f2dfa2510gkorland    StringBuffer sb = new StringBuffer();
288336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    if(null == testMethods || testMethods.length == 0) {
289336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      return "";
290336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
2910f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
2927ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust    for (ITestNGMethod m : testMethods) {
2937ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      sb.append("<tr>\n");
2947ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      sb.append("<td>&nbsp;</td>\n")
2957ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust        .append("<td>").append(m.getMethodName()).append("</td>\n")
2967ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust        ;
2977ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      String[] groups = m.getGroups();
2987ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      if (groups != null && groups.length > 0) {
2997ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust        sb.append("<td>");
3007ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust        for (String g : groups) {
3017ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust          sb.append(g).append(" ");
3027ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust        }
3037ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust        sb.append("</td>\n");
3047ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      }
3057ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      else {
3067ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust        sb.append("<td>&nbsp;</td>");
3077ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      }
3087ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust      sb.append("</tr>\n");
3090f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    }
3100f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
3117ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//    StringBuffer sb = new StringBuffer("<br/>");  //"<table bgcolor=\"#c0c0c0\"/>");
3127ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//    for (ITestNGMethod tm : testMethods) {
3137ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//      sb
3147ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//      .append(SP4).append(tm.getMethodName()).append("()\n")
3157ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//      .append(dumpGroups(tm.getGroups()))
3167ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//      .append("<br/>");
3177ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//      ;
3187ae4d3305466d7663609eba37fd5d4bb23ca047fCédric Beust//    }
3190f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
3200f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
321336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    String result = sb.toString();
322336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    return result;
323336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
3240f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
325336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private String dumpGroups(String[] groups) {
326336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    StringBuffer sb = new StringBuffer();
3270f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
328336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    if (null != groups && groups.length > 0) {
329336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      sb.append(SP4).append("<em>[");
3300f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
331336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      for (String g : groups) {
332336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        sb.append(g).append(" ");
333336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
3340f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
335336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      sb.append("]</em><br/>\n");
336336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
3370f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
338336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    String result = sb.toString();
339336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    return result;
340336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
3410f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
342336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  /**
343336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   * Generate information about the methods that were run
344336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   */
345336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  public static final String AFTER= "&lt;&lt;";
346336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  public static final String BEFORE = "&gt;&gt;";
347336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private void generateMethodsChronologically(XmlSuite xmlSuite, ISuite suite,
3480f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      String outputFileName, boolean alphabetical)
349336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  {
350e353be223c97f152cb3eb1b6df65200eeed7021fUli Schlachter    try (BufferedWriter bw = Utils.openWriter(getOutputDirectory(xmlSuite), outputFileName)) {
351a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter      bw.append("<h2>Methods run, sorted chronologically</h2>");
352a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter      bw.append("<h3>" + BEFORE + " means before, " + AFTER + " means after</h3><p/>");
353a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter
354a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter      long startDate = -1;
355a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter      bw.append("<br/><em>").append(suite.getName()).append("</em><p/>");
356a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter      bw.append("<small><i>(Hover the method name to see the test class name)</i></small><p/>\n");
357a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter
358a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter      Collection<IInvokedMethod> invokedMethods = suite.getAllInvokedMethods();
359a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter      if (alphabetical) {
360a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	@SuppressWarnings({"unchecked"})
361a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	Comparator<? super ITestNGMethod>  alphabeticalComparator = new Comparator(){
362a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  @Override
363a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  public int compare(Object o1, Object o2) {
364a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    IInvokedMethod m1 = (IInvokedMethod) o1;
365a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    IInvokedMethod m2 = (IInvokedMethod) o2;
366a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    return m1.getTestMethod().getMethodName().compareTo(m2.getTestMethod().getMethodName());
367a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  }
368a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	};
369a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	Collections.sort((List) invokedMethods, alphabeticalComparator);
370a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter      }
3710f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
372a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter      SimpleDateFormat format = new SimpleDateFormat("yy/MM/dd HH:mm:ss");
373a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter      boolean addedHeader = false;
374a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter      for (IInvokedMethod iim : invokedMethods) {
375a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	ITestNGMethod tm = iim.getTestMethod();
376a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	if (!addedHeader) {
377a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  bw.append("<table border=\"1\">\n")
378a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    .append("<tr>")
379a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    .append("<th>Time</th>")
380a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    .append("<th>Delta (ms)</th>")
381a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    .append("<th>Suite<br>configuration</th>")
382a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    .append("<th>Test<br>configuration</th>")
383a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    .append("<th>Class<br>configuration</th>")
384a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    .append("<th>Groups<br>configuration</th>")
385a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    .append("<th>Method<br>configuration</th>")
386a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    .append("<th>Test<br>method</th>")
387a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    .append("<th>Thread</th>")
388a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    .append("<th>Instances</th>")
389a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	    .append("</tr>\n");
390a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  addedHeader = true;
391a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	}
392a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	String methodName = tm.toString();
393a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean bc = tm.isBeforeClassConfiguration();
394a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean ac = tm.isAfterClassConfiguration();
395a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean bt = tm.isBeforeTestConfiguration();
396a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean at = tm.isAfterTestConfiguration();
397a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean bs = tm.isBeforeSuiteConfiguration();
398a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean as = tm.isAfterSuiteConfiguration();
399a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean bg = tm.isBeforeGroupsConfiguration();
400a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean ag = tm.isAfterGroupsConfiguration();
401a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean setUp = tm.isBeforeMethodConfiguration();
402a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean tearDown = tm.isAfterMethodConfiguration();
403a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean isClassConfiguration = bc || ac;
404a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean isGroupsConfiguration = bg || ag;
405a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean isTestConfiguration = bt || at;
406a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean isSuiteConfiguration = bs || as;
407a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	boolean isSetupOrTearDown = setUp || tearDown;
408a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	String configurationClassMethod = isClassConfiguration ? (bc ? BEFORE : AFTER) + methodName : SP;
409a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	String configurationTestMethod = isTestConfiguration ? (bt ? BEFORE : AFTER) + methodName : SP;
410a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	String configurationGroupsMethod = isGroupsConfiguration ? (bg ? BEFORE : AFTER) + methodName : SP;
411a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	String configurationSuiteMethod = isSuiteConfiguration ? (bs ? BEFORE : AFTER) + methodName : SP;
412a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	String setUpOrTearDownMethod = isSetupOrTearDown ? (setUp ? BEFORE : AFTER) + methodName : SP;
413a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	String testMethod = tm.isTest() ? methodName : SP;
414a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter
415a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	StringBuffer instances = new StringBuffer();
416a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	for (long o : tm.getInstanceHashCodes()) {
417a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  instances.append(o).append(" ");
418a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	}
419a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter
420a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	if (startDate == -1) {
421a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  startDate = iim.getDate();
422a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	}
423a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	String date = format.format(iim.getDate());
424a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	bw.append("<tr bgcolor=\"" + createColor(tm) + "\">")
425a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  .append("  <td>").append(date).append("</td> ")
426a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  .append("  <td>").append(Long.toString(iim.getDate() - startDate)).append("</td> ")
427a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  .append(td(configurationSuiteMethod))
428a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  .append(td(configurationTestMethod))
429a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  .append(td(configurationClassMethod))
430a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  .append(td(configurationGroupsMethod))
431a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  .append(td(setUpOrTearDownMethod))
432a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  .append(td(testMethod))
433a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  .append("  <td>").append(tm.getId()).append("</td> ")
434a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  .append("  <td>").append(instances).append("</td> ")
435a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  .append("</tr>\n")
436a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter	  ;
437336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
438a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter      bw.append("</table>\n");
439a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter    } catch (IOException e) {
440a9c69ddb24b95d680bdaab61c6c614bf58d73cb5Uli Schlachter      Utils.log("[SuiteHTMLReporter]", 1, "Error writing to " + outputFileName + ": " + e.getMessage());
441336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
442336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
443336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
444336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  /**
445336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   * Generate a HTML color based on the class of the method
446336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   */
447336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private String createColor(ITestNGMethod tm) {
448336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    // real class can be null if this client is remote (not serializable)
449336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    long color = tm.getRealClass() != null ? tm.getRealClass().hashCode() & 0xffffff: 0xffffff;
450336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    long[] rgb = {
451336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        ((color & 0xff0000) >> 16) & 0xff,
452336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        ((color & 0x00ff00) >> 8) & 0xff,
453336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        color & 0xff
454336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    };
455336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    // Not too dark
456336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    for (int i = 0; i < rgb.length; i++) {
4570f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      if (rgb[i] < 0x60) {
4580f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        rgb[i] += 0x60;
4590f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      }
460336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
461336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    long adjustedColor = (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];
462336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    String result = Long.toHexString(adjustedColor);
4630f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
464336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    return result;
465336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
466336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
467336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private String td(String s) {
468336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    StringBuffer result = new StringBuffer();
469336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    String prefix = "";
4700f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
471336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    if (s.startsWith(BEFORE)) {
472336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      prefix = BEFORE;
473336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
474336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    else if (s.startsWith(AFTER)) {
475336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      prefix = AFTER;
476336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
4770f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
478336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    if (! s.equals(SP)) {
479336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      result.append("<td title=\"").append(s).append("\">");
480336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      int open = s.lastIndexOf("(");
481336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      int start = s.substring(0, open).lastIndexOf(".");
482975d9acab06f8de7ef2791ebe784c6d1c6b4e6d9the.mindstorm//      int end = s.lastIndexOf(")");
483336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      if (start >= 0) {
484336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        result.append(prefix + s.substring(start + 1, open));
485336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
486336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      else {
487336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        result.append(prefix + s);
488336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
489336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      result.append("</td> \n");
490336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
491336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    else {
492336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      result.append("<td>").append(SP).append("</td>");
493336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
4940f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
495336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    return result.toString();
496336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
4970f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
498336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private void ppp(String s) {
499336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    System.out.println("[SuiteHTMLReporter] " + s);
500336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
5010f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
502336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  /**
503336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   * Generate information about methods and groups
504336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   */
505336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private void generateMethodsAndGroups(XmlSuite xmlSuite, ISuite suite) {
506336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    StringBuffer sb = new StringBuffer();
5070f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
508336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    Map<String, Collection<ITestNGMethod>> groups = suite.getMethodsByGroups();
5090f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
510336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    sb.append("<h2>Groups used for this test run</h2>");
511336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    if (groups.size() > 0) {
512336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      sb.append("<table border=\"1\">\n")
513336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<tr> <td align=\"center\"><b>Group name</b></td>")
514336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<td align=\"center\"><b>Methods</b></td></tr>");
515336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
516336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      String[] groupNames = groups.keySet().toArray(new String[groups.size()]);
517336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      Arrays.sort(groupNames);
518336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      for (String group : groupNames) {
519336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        Collection<ITestNGMethod> methods = groups.get(group);
520336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        sb.append("<tr><td>").append(group).append("</td>");
521336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        StringBuffer methodNames = new StringBuffer();
5220f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beust        Map<ITestNGMethod, ITestNGMethod> uniqueMethods = Maps.newHashMap();
523336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        for (ITestNGMethod tm : methods) {
524336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          uniqueMethods.put(tm, tm);
525336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        }
526336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        for (ITestNGMethod tm : uniqueMethods.values()) {
527336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          methodNames.append(tm.toString()).append("<br/>");
528336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        }
529336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        sb.append("<td>" + methodNames.toString() + "</td></tr>\n");
530336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
5310f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
532336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      sb.append("</table>\n");
533336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
5340f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    Utils.writeFile(getOutputDirectory(xmlSuite), GROUPS, sb.toString());
535336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
5360f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
537336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private void generateIndex(XmlSuite xmlSuite, ISuite sr) {
538336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    StringBuffer index = new StringBuffer()
539336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("<html><head><title>Results for " + sr.getName() + "</title></head>\n")
540336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("<frameset cols=\"26%,74%\">\n")
541336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("<frame src=\"toc.html\" name=\"navFrame\">\n")
542336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("<frame src=\"main.html\" name=\"mainFrame\">\n")
543336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("</frameset>\n")
544336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("</html>\n")
545336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    ;
5460f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
5470f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    Utils.writeFile(getOutputDirectory(xmlSuite), "index.html", index.toString());
548336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
5490f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
550336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private String makeTitle(ISuite suite) {
551336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    return "Results for<br/><em>" + suite.getName() + "</em>";
552336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
5530f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
554336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private void generateMain(XmlSuite xmlSuite, ISuite sr) {
555336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    StringBuffer index = new StringBuffer()
556336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("<html><head><title>Results for " + sr.getName() + "</title></head>\n")
557336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("<body>Select a result on the left-hand pane.</body>")
558336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("</html>\n")
559336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    ;
5600f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
5610f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    Utils.writeFile(getOutputDirectory(xmlSuite), "main.html", index.toString());
5620f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin  }
5630f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
564336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  /**
5650f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin   *
566336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust   */
567336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private void generateTableOfContents(XmlSuite xmlSuite, ISuite suite) {
568336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    StringBuffer tableOfContents = new StringBuffer();
5690f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
570336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    //
571336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    // Generate methods and groups hyperlinks
572336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    //
573336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    Map<String, ISuiteResult> suiteResults = suite.getResults();
574336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    int groupCount = suite.getMethodsByGroups().size();
575336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    int methodCount = 0;
576336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    for (ISuiteResult sr : suiteResults.values()) {
577336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      ITestNGMethod[] methods = sr.getTestContext().getAllTestMethods();
578336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      methodCount += Utils.calculateInvokedMethodCount(methods);
5790f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
580336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      // Collect testClasses
581336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      for (ITestNGMethod tm : methods) {
582336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        ITestClass tc = tm.getTestClass();
583336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        m_classes.put(tc.getRealClass().getName(), tc);
584336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
585336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
5860f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
587336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    String name = "Results for " + suite.getName();
588336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    tableOfContents
589336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<html>\n")
590336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<head>\n")
591336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<title>" + name + "</title>\n")
592336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append(HtmlHelper.getCssString())
593336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("</head>\n")
594336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        ;
595336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    tableOfContents
596336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<body>\n")
597336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<h3><p align=\"center\">" + makeTitle(suite) + "</p></h3>\n")
598336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<table border='1' width='100%'>\n")
599336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<tr valign='top'>\n")
600336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          .append("<td>")
601336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust            .append(suiteResults.size()).append(" ").append(pluralize(suiteResults.size(), "test"))
602336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          .append("</td>\n")
603336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          .append("<td>")
604336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust              .append("<a target='mainFrame' href='").append(CLASSES).append("'>")
605336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust              .append(m_classes.size() + " " + pluralize(m_classes.size(), "class"))
606336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust              .append("</a>")
607336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          .append("</td>\n")
608336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          .append("<td>" + methodCount + " " + pluralize(methodCount, "method") + ":<br/>\n")
609336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust            .append("&nbsp;&nbsp;<a target='mainFrame' href='").append(METHODS_CHRONOLOGICAL).append("'>").append("chronological</a><br/>\n")
610336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust            .append("&nbsp;&nbsp;<a target='mainFrame' href='").append(METHODS_ALPHABETICAL).append("\'>").append("alphabetical</a><br/>\n")
6115a7f440cd13a7b3bc12ef68e7237a519bb4e1a37the.mindstorm            .append("&nbsp;&nbsp;<a target='mainFrame' href='").append(METHODS_NOT_RUN).append("'>not run (" + suite.getExcludedMethods().size() + ")</a>")
612336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          .append("</td>\n")
613336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("</tr>\n")
614336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
615336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<tr>\n")
616336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<td><a target='mainFrame' href='").append(GROUPS).append("'>").append(groupCount + pluralize(groupCount, " group") + "</a></td>\n")
617336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<td><a target='mainFrame' href='").append(REPORTER_OUTPUT).append("'>reporter output</a></td>\n")
618336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<td><a target='mainFrame' href='").append(TESTNG_XML).append("'>testng.xml</a></td>\n")
619336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("</tr>")
620336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("</table>");
6210f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
622336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      //
623336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      // Generate results for individual tests
624336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      //
6250f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
626336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      // Order the results so we can show the failures first, then the skip and
627336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      // finally the successes
6280f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beust      Map<String, ISuiteResult> redResults = Maps.newHashMap();
6290f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beust      Map<String, ISuiteResult> yellowResults = Maps.newHashMap();
6300f6db64c011bc71dcdb432d7d27730b04f5ef2c1Cédric Beust      Map<String, ISuiteResult> greenResults = Maps.newHashMap();
6310f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
6321963187da6a45f898e62e4e922faac6b9382b4e4nullin      for (Map.Entry<String, ISuiteResult> entry : suiteResults.entrySet()) {
6331963187da6a45f898e62e4e922faac6b9382b4e4nullin        String suiteName = entry.getKey();
6341963187da6a45f898e62e4e922faac6b9382b4e4nullin        ISuiteResult sr = entry.getValue();
635336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        ITestContext tc = sr.getTestContext();
6360f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin        int failed = tc.getFailedTests().size();
637336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        int skipped = tc.getSkippedTests().size();
63808ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm        int passed = tc.getPassedTests().size();
6390f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
64008ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm        if (failed > 0) {
64108ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm          redResults.put(suiteName, sr);
64208ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm        }
64308ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm        else if (skipped > 0) {
64408ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm          yellowResults.put(suiteName, sr);
64508ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm        }
64608ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm        else if (passed > 0) {
64708ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm          greenResults.put(suiteName, sr);
64808ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm        }
64908ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm        else {
65008ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm          redResults.put(suiteName, sr);
65108ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm        }
652336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
6530f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
6540f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
655336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      ISuiteResult[][] results = new ISuiteResult[][] {
656336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        sortResults(redResults.values()), sortResults(yellowResults.values()), sortResults(greenResults.values())
657336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      };
6580f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
65908ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm      String[] colors = {"failed", "skipped", "passed"};
660336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      for (int i = 0; i < colors.length; i++) {
661336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        ISuiteResult[] r = results[i];
662336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        for (ISuiteResult sr: r) {
663336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          String suiteName = sr.getTestContext().getName();
664336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          generateSuiteResult(suiteName, sr, colors[i], tableOfContents, m_outputDirectory);
665336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        }
666336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
6670f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
668336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    tableOfContents.append("</body></html>");
669975d9acab06f8de7ef2791ebe784c6d1c6b4e6d9the.mindstorm    Utils.writeFile(getOutputDirectory(xmlSuite), "toc.html", tableOfContents.toString());
670336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
6710f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
672336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private String pluralize(int count, String singular) {
673336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    return count > 1 ? (singular.endsWith("s") ? singular + "es" : singular + "s") : singular;
674336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
675336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
676336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private String getOutputDirectory(XmlSuite xmlSuite) {
677336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    return m_outputDirectory + File.separatorChar + xmlSuite.getName();
678336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
679336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
680336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private ISuiteResult[] sortResults(Collection<ISuiteResult> r) {
681336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    ISuiteResult[] result = r.toArray(new ISuiteResult[r.size()]);
682336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    Arrays.sort(result);
683336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    return result;
684336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
685336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
6860f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin  private void generateSuiteResult(String suiteName,
6870f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin                                   ISuiteResult sr,
6880f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin                                   String cssClass,
6890f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin                                   StringBuffer tableOfContents,
690336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                                   String outputDirectory)
691336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  {
692336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    ITestContext tc = sr.getTestContext();
693336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    int passed = tc.getPassedTests().size();
6940f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    int failed = tc.getFailedTests().size();
695336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    int skipped = tc.getSkippedTests().size();
696336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    String baseFile = tc.getName();
697336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    tableOfContents
698336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("\n<table width='100%' class='test-").append(cssClass).append("'>\n")
699336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("<tr><td>\n")
700336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("<table style='width: 100%'><tr>")
701336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("<td valign='top'>")
702336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append(suiteName).append(" (").append(passed).append("/").append(failed).append("/").append(skipped).append(")")
703336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("</td>")
704336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("<td valign='top' align='right'>\n")
705336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("  <a href='" + baseFile + ".html' target='mainFrame'>Results</a>\n")
706336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust//      .append("  <a href=\"" + baseFile + ".out\" target=\"mainFrame\"\">Output</a>\n")
707336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust//      .append("&nbsp;&nbsp;<a href=\"file://" + baseFile + ".properties\" target=\"mainFrame\"\">Property file</a><br>\n")
708336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("</td>")
709336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("</tr></table>\n")
710336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("</td></tr><p/>\n")
711336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      ;
7120f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
713336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    tableOfContents.append("</table>\n");
714336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
7150f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
716f0a15dd5b96f3d02be7cc50ad01bb2d0005f0c69cquezel  /**
717f0a15dd5b96f3d02be7cc50ad01bb2d0005f0c69cquezel   * Writes a property file for each suite result.
718f0a15dd5b96f3d02be7cc50ad01bb2d0005f0c69cquezel   *
719f0a15dd5b96f3d02be7cc50ad01bb2d0005f0c69cquezel   * @param xmlSuite
720f0a15dd5b96f3d02be7cc50ad01bb2d0005f0c69cquezel   * @param suite
721f0a15dd5b96f3d02be7cc50ad01bb2d0005f0c69cquezel   */
722336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private void generateSuites(XmlSuite xmlSuite, ISuite suite) {
723336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    Map<String, ISuiteResult> suiteResults = suite.getResults();
724336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
7251963187da6a45f898e62e4e922faac6b9382b4e4nullin    for (ISuiteResult sr : suiteResults.values()) {
726336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      ITestContext testContext = sr.getTestContext();
727336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      StringBuffer sb = new StringBuffer();
7280f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
7291963187da6a45f898e62e4e922faac6b9382b4e4nullin      for (ISuiteResult suiteResult : suiteResults.values()) {
730336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        sb.append(suiteResult.toString());
731336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
732975d9acab06f8de7ef2791ebe784c6d1c6b4e6d9the.mindstorm      Utils.writeFile(getOutputDirectory(xmlSuite), testContext.getName() + ".properties", sb.toString());
7330f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    }
734336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
735336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust}
736