1336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustpackage org.testng.reporters;
2336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
3336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport org.testng.ITestContext;
4336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport org.testng.ITestNGMethod;
5336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport org.testng.ITestResult;
6336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport org.testng.Reporter;
7336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport org.testng.TestListenerAdapter;
8336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustimport org.testng.internal.Utils;
9336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
100f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.io.Serializable;
110f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.util.Collection;
120f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.util.Collections;
130f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.util.Comparator;
140f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.util.Date;
150f7e671c94aeedee2fbc796b3318d44b0297b6cdnullinimport java.util.List;
160f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
17336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
18336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust/**
19336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust * This class implements an HTML reporter for individual tests.
20336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust *
21336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust * @author Cedric Beust, May 2, 2004
229a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm * @author <a href='mailto:the_mindstorm@evolva.ro'>Alexandru Popescu</a>
23336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust */
24336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beustpublic class TestHTMLReporter extends TestListenerAdapter {
259a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm  private static final Comparator<ITestResult> NAME_COMPARATOR= new NameComparator();
269a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm  private static final Comparator<ITestResult> CONFIGURATION_COMPARATOR= new ConfigurationComparator();
270f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
28336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private ITestContext m_testContext = null;
290f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
30336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  /////
31336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  // implements ITestListener
32336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  //
33336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  @Override
34336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  public void onStart(ITestContext context) {
35336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    m_testContext = context;
36336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
37336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
38336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  @Override
39336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  public void onFinish(ITestContext context) {
400f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    generateLog(m_testContext,
41336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                null /* host */,
429a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm                m_testContext.getOutputDirectory(),
439a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm                getConfigurationFailures(),
449a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm                getConfigurationSkips(),
450f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin                getPassedTests(),
46336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                getFailedTests(),
470f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin                getSkippedTests(),
48336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust                getFailedButWithinSuccessPercentageTests());
49336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
50336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  //
51336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  // implements ITestListener
52336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  /////
53336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
548199621f3dd6adcbc12e93c4ea5508cf9f4f9055the.mindstorm  private static String getOutputFile(ITestContext context) {
558199621f3dd6adcbc12e93c4ea5508cf9f4f9055the.mindstorm    return context.getName() + ".html";
56336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
570f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
580f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin  public static void generateTable(StringBuffer sb, String title,
599a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      Collection<ITestResult> tests, String cssClass, Comparator<ITestResult> comparator)
60336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  {
61336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    sb.append("<table width='100%' border='1' class='invocation-").append(cssClass).append("'>\n")
620f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      .append("<tr><td colspan='4' align='center'><b>").append(title).append("</b></td></tr>\n")
63336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("<tr>")
64336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("<td><b>Test method</b></td>\n")
65336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("<td width=\"30%\"><b>Exception</b></td>\n")
6637d27f306eb39607b1ce933ee2fe3a1e2353c452Cédric Beust      .append("<td width=\"10%\"><b>Time (seconds)</b></td>\n")
6737d27f306eb39607b1ce933ee2fe3a1e2353c452Cédric Beust      .append("<td><b>Instance</b></td>\n")
68336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("</tr>\n");
690f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
70336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    if (tests instanceof List) {
719a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      Collections.sort((List<ITestResult>) tests, comparator);
72336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
73336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
74336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    // User output?
75336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    String id = "";
76336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    Throwable tw = null;
770f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
78336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    for (ITestResult tr : tests) {
79336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      sb.append("<tr>\n");
80336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
81336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      // Test method
82336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      ITestNGMethod method = tr.getMethod();
83336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
8432e304902c91abaa7bab596065cfc10d75fcaf53Cédric Beust      String name = method.getMethodName();
85b1b620551c4ac0ab75d30158ec482e65cda30823Cédric Beust      sb.append("<td title='").append(tr.getTestClass().getName()).append(".")
8632e304902c91abaa7bab596065cfc10d75fcaf53Cédric Beust        .append(name)
87b1b620551c4ac0ab75d30158ec482e65cda30823Cédric Beust        .append("()'>")
8832e304902c91abaa7bab596065cfc10d75fcaf53Cédric Beust        .append("<b>").append(name).append("</b>");
890f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
9037ac2350e62621bb857a4a77048e7e9d20ac14c5nullin      // Test class
9137ac2350e62621bb857a4a77048e7e9d20ac14c5nullin      String testClass = tr.getTestClass().getName();
9237ac2350e62621bb857a4a77048e7e9d20ac14c5nullin      if (testClass != null) {
9337ac2350e62621bb857a4a77048e7e9d20ac14c5nullin        sb.append("<br>").append("Test class: " + testClass);
940f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
9537ac2350e62621bb857a4a77048e7e9d20ac14c5nullin        // Test name
9637ac2350e62621bb857a4a77048e7e9d20ac14c5nullin        String testName = tr.getTestName();
9737ac2350e62621bb857a4a77048e7e9d20ac14c5nullin        if (testName != null) {
9837ac2350e62621bb857a4a77048e7e9d20ac14c5nullin          sb.append(" (").append(testName).append(")");
9937ac2350e62621bb857a4a77048e7e9d20ac14c5nullin        }
1009f2367a1c4b17a5b38fb6fa209b717fb42d4faccCédric Beust      }
1010f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
102336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      // Method description
103336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      if (! Utils.isStringEmpty(method.getDescription())) {
10437ac2350e62621bb857a4a77048e7e9d20ac14c5nullin        sb.append("<br>").append("Test method: ").append(method.getDescription());
105336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
1060f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
107336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      Object[] parameters = tr.getParameters();
108336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      if (parameters != null && parameters.length > 0) {
1099f2367a1c4b17a5b38fb6fa209b717fb42d4faccCédric Beust        sb.append("<br>Parameters: ");
110336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        for (int j = 0; j < parameters.length; j++) {
1110f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin          if (j > 0) {
1120f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin            sb.append(", ");
1130f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin          }
114336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          sb.append(parameters[j] == null ? "null" : parameters[j].toString());
115336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        }
116336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
117336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
118336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      //
119336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      // Output from the method, created by the user calling Reporter.log()
120336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      //
121336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      {
122336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        List<String> output = Reporter.getOutput(tr);
123336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        if (null != output && output.size() > 0) {
124336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          sb.append("<br/>");
125336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          // Method name
126336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          String divId = "Output-" + tr.hashCode();
127336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          sb.append("\n<a href=\"#").append(divId).append("\"")
128a124a51edf8709b78bc35762c62fba8d4c7ecb28the.mindstorm            .append(" onClick='toggleBox(\"").append(divId).append("\", this, \"Show output\", \"Hide output\");'>")
129336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust            .append("Show output</a>\n")
130336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust            .append("\n<a href=\"#").append(divId).append("\"")
131336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust            .append(" onClick=\"toggleAllBoxes();\">Show all outputs</a>\n")
132336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust            ;
1330f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
134336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          // Method output
135336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          sb.append("<div class='log' id=\"").append(divId).append("\">\n");
136336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          for (String s : output) {
137336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust            sb.append(s).append("<br/>\n");
138336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          }
139336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust          sb.append("</div>\n");
140336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        }
141336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
1420f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
143336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      sb.append("</td>\n");
144b1b620551c4ac0ab75d30158ec482e65cda30823Cédric Beust
1450f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
146336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      // Exception
147336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      tw = tr.getThrowable();
148336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      String stackTrace = "";
149336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      String fullStackTrace = "";
1500f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
151336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      id = "stack-trace" + tr.hashCode();
152336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      sb.append("<td>");
1530f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
154336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      if (null != tw) {
155336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        String[] stackTraces = Utils.stackTrace(tw, true);
156139b3297a77335e3fda59b783b72117fc7dcf8aethe.mindstorm        fullStackTrace = stackTraces[1];
157139b3297a77335e3fda59b783b72117fc7dcf8aethe.mindstorm        stackTrace = "<div><pre>" + stackTraces[0]  + "</pre></div>";
1580f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
159336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        sb.append(stackTrace);
160336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        // JavaScript link
161336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        sb.append("<a href='#' onClick='toggleBox(\"")
162a124a51edf8709b78bc35762c62fba8d4c7ecb28the.mindstorm        .append(id).append("\", this, \"Click to show all stack frames\", \"Click to hide stack frames\")'>")
163336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("Click to show all stack frames").append("</a>\n")
164336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<div class='stack-trace' id='" + id + "'>")
165336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("<pre>" + fullStackTrace + "</pre>")
166336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        .append("</div>")
167336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        ;
168336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      }
1690f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
17037d27f306eb39607b1ce933ee2fe3a1e2353c452Cédric Beust      sb.append("</td>\n");
17137d27f306eb39607b1ce933ee2fe3a1e2353c452Cédric Beust
17237d27f306eb39607b1ce933ee2fe3a1e2353c452Cédric Beust      // Time
17337d27f306eb39607b1ce933ee2fe3a1e2353c452Cédric Beust      long time = (tr.getEndMillis() - tr.getStartMillis()) / 1000;
1740b2ac5eab08098da2c2b63d4a3f87ba72ad5d6a1nullin      String strTime = Long.toString(time);
17537d27f306eb39607b1ce933ee2fe3a1e2353c452Cédric Beust      sb.append("<td>").append(strTime).append("</td>\n");
17637d27f306eb39607b1ce933ee2fe3a1e2353c452Cédric Beust
17737d27f306eb39607b1ce933ee2fe3a1e2353c452Cédric Beust      // Instance
17837d27f306eb39607b1ce933ee2fe3a1e2353c452Cédric Beust      Object instance = tr.getInstance();
17937d27f306eb39607b1ce933ee2fe3a1e2353c452Cédric Beust      sb.append("<td>").append(instance).append("</td>");
18037d27f306eb39607b1ce933ee2fe3a1e2353c452Cédric Beust
18137d27f306eb39607b1ce933ee2fe3a1e2353c452Cédric Beust      sb.append("</tr>\n");
182336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
1830f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
184336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    sb.append("</table><p>\n");
185336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
186336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
1870f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
188336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private static String arrayToString(String[] array) {
189336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    StringBuffer result = new StringBuffer("");
1900f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    for (String element : array) {
1910f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      result.append(element).append(" ");
192336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
1930f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
194336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    return result.toString();
195336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
1960f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
197336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private static String HEAD =
198336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    "\n<style type=\"text/css\">\n" +
199336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    ".log { display: none;} \n" +
200336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    ".stack-trace { display: none;} \n" +
201336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    "</style>\n" +
202336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    "<script type=\"text/javascript\">\n" +
203336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "<!--\n" +
204336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "function flip(e) {\n" +
205336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "  current = e.style.display;\n" +
206336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "  if (current == 'block') {\n" +
207336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "    e.style.display = 'none';\n" +
208a124a51edf8709b78bc35762c62fba8d4c7ecb28the.mindstorm      "    return 0;\n" +
209336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "  }\n" +
210336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "  else {\n" +
211336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "    e.style.display = 'block';\n" +
212a124a51edf8709b78bc35762c62fba8d4c7ecb28the.mindstorm      "    return 1;\n" +
213336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "  }\n" +
214336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "}\n" +
215336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "\n" +
216a124a51edf8709b78bc35762c62fba8d4c7ecb28the.mindstorm      "function toggleBox(szDivId, elem, msg1, msg2)\n" +
217336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "{\n" +
218a124a51edf8709b78bc35762c62fba8d4c7ecb28the.mindstorm      "  var res = -1;" +
219336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "  if (document.getElementById) {\n" +
220a124a51edf8709b78bc35762c62fba8d4c7ecb28the.mindstorm      "    res = flip(document.getElementById(szDivId));\n" +
221336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "  }\n" +
222336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "  else if (document.all) {\n" +
223336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "    // this is the way old msie versions work\n" +
224a124a51edf8709b78bc35762c62fba8d4c7ecb28the.mindstorm      "    res = flip(document.all[szDivId]);\n" +
225a124a51edf8709b78bc35762c62fba8d4c7ecb28the.mindstorm      "  }\n" +
226a124a51edf8709b78bc35762c62fba8d4c7ecb28the.mindstorm      "  if(elem) {\n" +
2270f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      "    if(res == 0) elem.innerHTML = msg1; else elem.innerHTML = msg2;\n" +
228336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "  }\n" +
229336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "\n" +
230336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "}\n" +
231336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "\n" +
232336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "function toggleAllBoxes() {\n" +
233336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "  if (document.getElementsByTagName) {\n" +
234336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "    d = document.getElementsByTagName('div');\n" +
235336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "    for (i = 0; i < d.length; i++) {\n" +
236336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "      if (d[i].className == 'log') {\n" +
237336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "        flip(d[i]);\n" +
238336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "      }\n" +
239336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "    }\n" +
240336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "  }\n" +
241336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "}\n" +
242336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "\n" +
243336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "// -->\n" +
244336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "</script>\n" +
245336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      "\n";
2460f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
2470f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin  public static void generateLog(ITestContext testContext,
2489a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      String host,
2499a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      String outputDirectory,
2509a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      Collection<ITestResult> failedConfs,
2519a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      Collection<ITestResult> skippedConfs,
2520f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      Collection<ITestResult> passedTests,
2539a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      Collection<ITestResult> failedTests,
2540f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin      Collection<ITestResult> skippedTests,
2559a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      Collection<ITestResult> percentageTests)
256336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  {
257336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    StringBuffer sb = new StringBuffer();
258336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    sb.append("<html>\n<head>\n")
259336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("<title>TestNG:  ").append(testContext.getName()).append("</title>\n")
260336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append(HtmlHelper.getCssString())
261336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append(HEAD)
262336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("</head>\n")
263336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      .append("<body>\n");
2640f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
265336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    Date startDate = testContext.getStartDate();
266336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    Date endDate = testContext.getEndDate();
267336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    long duration = (endDate.getTime() - startDate.getTime()) / 1000;
2680f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin    int passed =
269336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      testContext.getPassedTests().size() +
270336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      testContext.getFailedButWithinSuccessPercentageTests().size();
271336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    int failed = testContext.getFailedTests().size();
272336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    int skipped = testContext.getSkippedTests().size();
273336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    String hostLine = Utils.isStringEmpty(host) ? "" : "<tr><td>Remote host:</td><td>" + host
274336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust        + "</td>\n</tr>";
2750f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
276336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    sb
277336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("<h2 align='center'>").append(testContext.getName()).append("</h2>")
278336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("<table border='1' align=\"center\">\n")
279336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("<tr>\n")
280336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust//    .append("<td>Property file:</td><td>").append(m_testRunner.getPropertyFileName()).append("</td>\n")
281336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust//    .append("</tr><tr>\n")
282336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("<td>Tests passed/Failed/Skipped:</td><td>").append(passed).append("/").append(failed).append("/").append(skipped).append("</td>\n")
283336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("</tr><tr>\n")
284336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("<td>Started on:</td><td>").append(testContext.getStartDate().toString()).append("</td>\n")
285336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("</tr>\n")
286336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append(hostLine)
28708ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm    .append("<tr><td>Total time:</td><td>").append(duration).append(" seconds (").append(endDate.getTime() - startDate.getTime())
28808ebf81679fb5175f8090732f52ade4f9a099f1ethe.mindstorm      .append(" ms)</td>\n")
289336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("</tr><tr>\n")
290336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("<td>Included groups:</td><td>").append(arrayToString(testContext.getIncludedGroups())).append("</td>\n")
291336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("</tr><tr>\n")
292336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("<td>Excluded groups:</td><td>").append(arrayToString(testContext.getExcludedGroups())).append("</td>\n")
293336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("</tr>\n")
294336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    .append("</table><p/>\n")
295336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    ;
2960f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
29701864456a039f32dd36028e4b26c63c10d03a5aaCédric Beust    sb.append("<small><i>(Hover the method name to see the test class name)</i></small><p/>\n");
2989a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm    if (failedConfs.size() > 0) {
2999a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      generateTable(sb, "FAILED CONFIGURATIONS", failedConfs, "failed", CONFIGURATION_COMPARATOR);
3009a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm    }
3019a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm    if (skippedConfs.size() > 0) {
3029a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      generateTable(sb, "SKIPPED CONFIGURATIONS", skippedConfs, "skipped", CONFIGURATION_COMPARATOR);
3039a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm    }
304336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    if (failedTests.size() > 0) {
3059a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      generateTable(sb, "FAILED TESTS", failedTests, "failed", NAME_COMPARATOR);
306336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
307336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    if (percentageTests.size() > 0) {
308336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust      generateTable(sb, "FAILED TESTS BUT WITHIN SUCCESS PERCENTAGE",
3099a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm          percentageTests, "percent", NAME_COMPARATOR);
310336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
311336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    if (passedTests.size() > 0) {
3129a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      generateTable(sb, "PASSED TESTS", passedTests, "passed", NAME_COMPARATOR);
313336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
314336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    if (skippedTests.size() > 0) {
3159a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      generateTable(sb, "SKIPPED TESTS", skippedTests, "skipped", NAME_COMPARATOR);
316336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    }
3170f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
318336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    sb.append("</body>\n</html>");
3190f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
3208199621f3dd6adcbc12e93c4ea5508cf9f4f9055the.mindstorm    Utils.writeFile(outputDirectory, getOutputFile(testContext), sb.toString());
321336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
322336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust
323336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  private static void ppp(String s) {
324336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust    System.out.println("[TestHTMLReporter] " + s);
325336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust  }
3260f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
3271963187da6a45f898e62e4e922faac6b9382b4e4nullin  private static class NameComparator implements Comparator<ITestResult>, Serializable {
3281963187da6a45f898e62e4e922faac6b9382b4e4nullin    private static final long serialVersionUID = 381775815838366907L;
3299a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm    public int compare(ITestResult o1, ITestResult o2) {
3306c8ca81bdb931a7dedab1d30b60fb7381ac3f868Cédric Beust      String c1 = o1.getMethod().getMethodName();
3316c8ca81bdb931a7dedab1d30b60fb7381ac3f868Cédric Beust      String c2 = o2.getMethod().getMethodName();
3329a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      return c1.compareTo(c2);
3339a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm    }
3340f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
3359a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm  }
3360f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
3371963187da6a45f898e62e4e922faac6b9382b4e4nullin  private static class ConfigurationComparator implements Comparator<ITestResult>, Serializable {
3381963187da6a45f898e62e4e922faac6b9382b4e4nullin    private static final long serialVersionUID = 5558550850685483455L;
3391963187da6a45f898e62e4e922faac6b9382b4e4nullin
3409a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm    public int compare(ITestResult o1, ITestResult o2) {
3419a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      ITestNGMethod tm1= o1.getMethod();
3429a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      ITestNGMethod tm2= o2.getMethod();
3439a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      return annotationValue(tm2) - annotationValue(tm1);
3449a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm    }
3450f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
3469a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm    private static int annotationValue(ITestNGMethod method) {
3479a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      if(method.isBeforeSuiteConfiguration()) {
3489a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm        return 10;
3499a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      }
3509a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      if(method.isBeforeTestConfiguration()) {
3519a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm        return 9;
3529a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      }
3539a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      if(method.isBeforeClassConfiguration()) {
3549a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm        return 8;
3559a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      }
3569a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      if(method.isBeforeGroupsConfiguration()) {
3579a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm        return 7;
3589a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      }
3599a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      if(method.isBeforeMethodConfiguration()) {
3609a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm        return 6;
3619a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      }
3629a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      if(method.isAfterMethodConfiguration()) {
3639a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm        return 5;
3649a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      }
3659a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      if(method.isAfterGroupsConfiguration()) {
3669a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm        return 4;
3679a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      }
3689a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      if(method.isAfterClassConfiguration()) {
3699a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm        return 3;
3709a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      }
3719a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      if(method.isAfterTestConfiguration()) {
3729a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm        return 2;
3739a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      }
3749a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      if(method.isAfterSuiteConfiguration()) {
3759a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm        return 1;
3769a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      }
3770f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
3789a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm      return 0;
3799a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm    }
3809a1482542f224166248c1821ddeb70c7dbc5415athe.mindstorm  }
3810f7e671c94aeedee2fbc796b3318d44b0297b6cdnullin
382336f0ef401e9f564b8dc99d601ac80e8891ac2c1Cédric Beust}
383